[med-svn] [htqc] 01/02: Imported Upstream version 1.92.1

Andreas Tille tille at debian.org
Mon Jun 22 12:47:09 UTC 2015


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

tille pushed a commit to branch master
in repository htqc.

commit a7a13894f85680a5446880bafd8d6636eddd9d17
Author: Andreas Tille <tille at debian.org>
Date:   Mon Jun 22 14:33:33 2015 +0200

    Imported Upstream version 1.92.1
---
 CMakeLists.txt                                     |   57 +
 Changes.md                                         |  597 +++++
 FindHTIO2.cmake                                    |   39 +
 INSTALL.md                                         |   59 +
 README-convert.md                                  |   63 +
 README-demul.md                                    |   38 +
 README-filter.md                                   |   26 +
 README-htio.md                                     |  124 +
 README-lane-tile.md                                |   34 +
 README-overlap.md                                  |   38 +
 README-primer-trim.md                              |   80 +
 README-rename.md                                   |   22 +
 README-sample.md                                   |   30 +
 README-stat.md                                     |   35 +
 README-trim.md                                     |   29 +
 README.md                                          |  151 ++
 src/CMakeLists.txt                                 |  101 +
 src/ht2-convert.cpp                                |  238 ++
 src/ht2-demul.cpp                                  |  438 ++++
 src/ht2-filter.cpp                                 |  340 +++
 src/ht2-lane-tile.cpp                              |  163 ++
 src/ht2-overlap.cpp                                |  255 ++
 src/ht2-primer-trim.cpp                            |  690 ++++++
 src/ht2-rename.cpp                                 |  114 +
 src/ht2-sample.cpp                                 |  404 ++++
 src/ht2-stat-draw.pl                               |  520 ++++
 src/ht2-stat.cpp                                   |  759 ++++++
 src/ht2-trim.cpp                                   |  280 +++
 src/ht_config.h.in                                 |    8 +
 src/htio2/Cast.cpp                                 |  353 +++
 src/htio2/Cast.h                                   |  103 +
 src/htio2/Enum.cpp                                 |   12 +
 src/htio2/Enum.h                                   |   58 +
 src/htio2/Error.cpp                                |   71 +
 src/htio2/Error.h                                  |   63 +
 src/htio2/FastaIO.cpp                              |  177 ++
 src/htio2/FastaIO.h                                |  104 +
 src/htio2/FastqIO.cpp                              |  126 +
 src/htio2/FastqIO.h                                |   95 +
 src/htio2/FastqSeq.cpp                             |   42 +
 src/htio2/FastqSeq.h                               |   66 +
 src/htio2/FileHandle.cpp                           |   30 +
 src/htio2/FileHandle.h                             |   94 +
 src/htio2/FormatUtil.cpp                           |   75 +
 src/htio2/FormatUtil.h                             |   22 +
 src/htio2/GzipFileHandle.cpp                       |  112 +
 src/htio2/GzipFileHandle.h                         |   88 +
 src/htio2/HeaderUtil.cpp                           |  216 ++
 src/htio2/HeaderUtil.h                             |   72 +
 src/htio2/JUCE-3.0.8/AppConfig.h                   |   51 +
 src/htio2/JUCE-3.0.8/CMakeLists.txt                |    0
 src/htio2/JUCE-3.0.8/JuceHeader.h                  |   19 +
 src/htio2/JUCE-3.0.8/ReadMe.txt                    |   12 +
 .../juce_core/containers/juce_AbstractFifo.cpp     |  235 ++
 .../juce_core/containers/juce_AbstractFifo.h       |  220 ++
 .../modules/juce_core/containers/juce_Array.h      | 1113 +++++++++
 .../containers/juce_ArrayAllocationBase.h          |  138 ++
 .../juce_core/containers/juce_DynamicObject.cpp    |  133 +
 .../juce_core/containers/juce_DynamicObject.h      |  139 ++
 .../juce_core/containers/juce_ElementComparator.h  |  195 ++
 .../modules/juce_core/containers/juce_HashMap.h    |  455 ++++
 .../juce_core/containers/juce_LinkedListPointer.h  |  371 +++
 .../juce_core/containers/juce_NamedValueSet.cpp    |  271 +++
 .../juce_core/containers/juce_NamedValueSet.h      |  145 ++
 .../modules/juce_core/containers/juce_OwnedArray.h |  897 +++++++
 .../juce_core/containers/juce_PropertySet.cpp      |  219 ++
 .../juce_core/containers/juce_PropertySet.h        |  211 ++
 .../containers/juce_ReferenceCountedArray.h        |  897 +++++++
 .../juce_core/containers/juce_ScopedValueSetter.h  |  100 +
 .../modules/juce_core/containers/juce_SortedSet.h  |  494 ++++
 .../modules/juce_core/containers/juce_SparseSet.h  |  298 +++
 .../modules/juce_core/containers/juce_Variant.cpp  |  780 ++++++
 .../modules/juce_core/containers/juce_Variant.h    |  327 +++
 .../juce_core/files/juce_DirectoryIterator.cpp     |  159 ++
 .../juce_core/files/juce_DirectoryIterator.h       |  159 ++
 .../modules/juce_core/files/juce_File.cpp          | 1086 +++++++++
 .../JUCE-3.0.8/modules/juce_core/files/juce_File.h |  973 ++++++++
 .../modules/juce_core/files/juce_FileFilter.cpp    |   41 +
 .../modules/juce_core/files/juce_FileFilter.h      |   77 +
 .../juce_core/files/juce_FileInputStream.cpp       |   84 +
 .../modules/juce_core/files/juce_FileInputStream.h |   96 +
 .../juce_core/files/juce_FileOutputStream.cpp      |  134 ++
 .../juce_core/files/juce_FileOutputStream.h        |  116 +
 .../juce_core/files/juce_FileSearchPath.cpp        |  172 ++
 .../modules/juce_core/files/juce_FileSearchPath.h  |  165 ++
 .../juce_core/files/juce_MemoryMappedFile.h        |  115 +
 .../modules/juce_core/files/juce_TemporaryFile.cpp |  117 +
 .../modules/juce_core/files/juce_TemporaryFile.h   |  169 ++
 .../juce_core/files/juce_WildcardFileFilter.cpp    |   77 +
 .../juce_core/files/juce_WildcardFileFilter.h      |   86 +
 .../modules/juce_core/javascript/juce_JSON.cpp     |  643 +++++
 .../modules/juce_core/javascript/juce_JSON.h       |  136 ++
 .../juce_core/javascript/juce_Javascript.cpp       | 1710 +++++++++++++
 .../modules/juce_core/javascript/juce_Javascript.h |  105 +
 .../JUCE-3.0.8/modules/juce_core/juce_core.cpp     |  226 ++
 src/htio2/JUCE-3.0.8/modules/juce_core/juce_core.h |  286 +++
 .../JUCE-3.0.8/modules/juce_core/juce_core.mm      |   29 +
 .../JUCE-3.0.8/modules/juce_core/juce_module_info  |   38 +
 .../modules/juce_core/logging/juce_FileLogger.cpp  |  134 ++
 .../modules/juce_core/logging/juce_FileLogger.h    |  135 ++
 .../modules/juce_core/logging/juce_Logger.cpp      |   63 +
 .../modules/juce_core/logging/juce_Logger.h        |   97 +
 .../modules/juce_core/maths/juce_BigInteger.cpp    | 1014 ++++++++
 .../modules/juce_core/maths/juce_BigInteger.h      |  334 +++
 .../modules/juce_core/maths/juce_Expression.cpp    | 1183 +++++++++
 .../modules/juce_core/maths/juce_Expression.h      |  270 +++
 .../modules/juce_core/maths/juce_MathsFunctions.h  |  549 +++++
 .../modules/juce_core/maths/juce_Random.cpp        |  189 ++
 .../modules/juce_core/maths/juce_Random.h          |  143 ++
 .../modules/juce_core/maths/juce_Range.h           |  304 +++
 .../modules/juce_core/memory/juce_Atomic.h         |  399 +++
 .../modules/juce_core/memory/juce_ByteOrder.h      |  196 ++
 .../juce_core/memory/juce_ContainerDeletePolicy.h  |   53 +
 .../modules/juce_core/memory/juce_HeapBlock.h      |  308 +++
 .../juce_core/memory/juce_LeakedObjectDetector.h   |  146 ++
 .../modules/juce_core/memory/juce_Memory.h         |  126 +
 .../modules/juce_core/memory/juce_MemoryBlock.cpp  |  416 ++++
 .../modules/juce_core/memory/juce_MemoryBlock.h    |  253 ++
 .../juce_core/memory/juce_OptionalScopedPointer.h  |  186 ++
 .../juce_core/memory/juce_ReferenceCountedObject.h |  415 ++++
 .../modules/juce_core/memory/juce_ScopedPointer.h  |  253 ++
 .../juce_core/memory/juce_SharedResourcePointer.h  |  152 ++
 .../modules/juce_core/memory/juce_Singleton.h      |  292 +++
 .../modules/juce_core/memory/juce_WeakReference.h  |  212 ++
 .../modules/juce_core/misc/juce_Result.cpp         |   83 +
 .../modules/juce_core/misc/juce_Result.h           |  125 +
 .../modules/juce_core/misc/juce_Uuid.cpp           |  117 +
 .../JUCE-3.0.8/modules/juce_core/misc/juce_Uuid.h  |  121 +
 .../modules/juce_core/misc/juce_WindowsRegistry.h  |  141 ++
 .../juce_core/native/java/JuceAppActivity.java     |  746 ++++++
 .../juce_core/native/juce_BasicNativeHeaders.h     |  223 ++
 .../juce_core/native/juce_android_Files.cpp        |  104 +
 .../juce_core/native/juce_android_JNIHelpers.h     |  428 ++++
 .../modules/juce_core/native/juce_android_Misc.cpp |   32 +
 .../juce_core/native/juce_android_Network.cpp      |  181 ++
 .../juce_core/native/juce_android_SystemStats.cpp  |  315 +++
 .../juce_core/native/juce_android_Threads.cpp      |   76 +
 .../juce_core/native/juce_linux_CommonFile.cpp     |  153 ++
 .../modules/juce_core/native/juce_linux_Files.cpp  |  241 ++
 .../juce_core/native/juce_linux_Network.cpp        |  444 ++++
 .../juce_core/native/juce_linux_SystemStats.cpp    |  191 ++
 .../juce_core/native/juce_linux_Threads.cpp        |   90 +
 .../modules/juce_core/native/juce_mac_Files.mm     |  498 ++++
 .../modules/juce_core/native/juce_mac_Network.mm   |  445 ++++
 .../modules/juce_core/native/juce_mac_Strings.mm   |   96 +
 .../juce_core/native/juce_mac_SystemStats.mm       |  306 +++
 .../modules/juce_core/native/juce_mac_Threads.mm   |   97 +
 .../juce_core/native/juce_osx_ObjCHelpers.h        |  169 ++
 .../juce_core/native/juce_posix_NamedPipe.cpp      |  224 ++
 .../juce_core/native/juce_posix_SharedCode.h       | 1301 ++++++++++
 .../juce_core/native/juce_win32_ComSmartPtr.h      |  170 ++
 .../modules/juce_core/native/juce_win32_Files.cpp  |  999 ++++++++
 .../juce_core/native/juce_win32_Network.cpp        |  486 ++++
 .../juce_core/native/juce_win32_Registry.cpp       |  227 ++
 .../juce_core/native/juce_win32_SystemStats.cpp    |  459 ++++
 .../juce_core/native/juce_win32_Threads.cpp        |  625 +++++
 .../modules/juce_core/network/juce_IPAddress.cpp   |  149 ++
 .../modules/juce_core/network/juce_IPAddress.h     |   82 +
 .../modules/juce_core/network/juce_MACAddress.cpp  |   78 +
 .../modules/juce_core/network/juce_MACAddress.h    |   82 +
 .../modules/juce_core/network/juce_NamedPipe.cpp   |   66 +
 .../modules/juce_core/network/juce_NamedPipe.h     |  104 +
 .../modules/juce_core/network/juce_Socket.cpp      |  593 +++++
 .../modules/juce_core/network/juce_Socket.h        |  305 +++
 .../modules/juce_core/network/juce_URL.cpp         |  497 ++++
 .../modules/juce_core/network/juce_URL.h           |  375 +++
 .../juce_core/streams/juce_BufferedInputStream.cpp |  198 ++
 .../juce_core/streams/juce_BufferedInputStream.h   |   92 +
 .../juce_core/streams/juce_FileInputSource.cpp     |   56 +
 .../juce_core/streams/juce_FileInputSource.h       |   66 +
 .../modules/juce_core/streams/juce_InputSource.h   |   78 +
 .../modules/juce_core/streams/juce_InputStream.cpp |  236 ++
 .../modules/juce_core/streams/juce_InputStream.h   |  266 ++
 .../juce_core/streams/juce_MemoryInputStream.cpp   |  159 ++
 .../juce_core/streams/juce_MemoryInputStream.h     |   97 +
 .../juce_core/streams/juce_MemoryOutputStream.cpp  |  214 ++
 .../juce_core/streams/juce_MemoryOutputStream.h    |  139 ++
 .../juce_core/streams/juce_OutputStream.cpp        |  351 +++
 .../modules/juce_core/streams/juce_OutputStream.h  |  278 +++
 .../juce_core/streams/juce_SubregionStream.cpp     |   82 +
 .../juce_core/streams/juce_SubregionStream.h       |   88 +
 .../modules/juce_core/system/juce_PlatformDefs.h   |  388 +++
 .../modules/juce_core/system/juce_StandardHeader.h |  157 ++
 .../modules/juce_core/system/juce_SystemStats.cpp  |  183 ++
 .../modules/juce_core/system/juce_SystemStats.h    |  195 ++
 .../modules/juce_core/system/juce_TargetPlatform.h |  201 ++
 .../juce_core/text/juce_CharPointer_ASCII.h        |  387 +++
 .../juce_core/text/juce_CharPointer_UTF16.h        |  525 ++++
 .../juce_core/text/juce_CharPointer_UTF32.h        |  378 +++
 .../modules/juce_core/text/juce_CharPointer_UTF8.h |  572 +++++
 .../juce_core/text/juce_CharacterFunctions.cpp     |  154 ++
 .../juce_core/text/juce_CharacterFunctions.h       |  629 +++++
 .../modules/juce_core/text/juce_Identifier.cpp     |   70 +
 .../modules/juce_core/text/juce_Identifier.h       |  120 +
 .../juce_core/text/juce_LocalisedStrings.cpp       |  209 ++
 .../modules/juce_core/text/juce_LocalisedStrings.h |  247 ++
 .../modules/juce_core/text/juce_NewLine.h          |   86 +
 .../modules/juce_core/text/juce_String.cpp         | 2543 ++++++++++++++++++++
 .../modules/juce_core/text/juce_String.h           | 1370 +++++++++++
 .../modules/juce_core/text/juce_StringArray.cpp    |  485 ++++
 .../modules/juce_core/text/juce_StringArray.h      |  421 ++++
 .../juce_core/text/juce_StringPairArray.cpp        |  147 ++
 .../modules/juce_core/text/juce_StringPairArray.h  |  157 ++
 .../modules/juce_core/text/juce_StringPool.cpp     |  166 ++
 .../modules/juce_core/text/juce_StringPool.h       |   94 +
 .../modules/juce_core/text/juce_StringRef.h        |  138 ++
 .../modules/juce_core/text/juce_TextDiff.cpp       |  247 ++
 .../modules/juce_core/text/juce_TextDiff.h         |   80 +
 .../juce_core/threads/juce_ChildProcess.cpp        |  113 +
 .../modules/juce_core/threads/juce_ChildProcess.h  |  119 +
 .../juce_core/threads/juce_CriticalSection.h       |  266 ++
 .../juce_core/threads/juce_DynamicLibrary.h        |   85 +
 .../juce_core/threads/juce_HighResolutionTimer.cpp |   36 +
 .../juce_core/threads/juce_HighResolutionTimer.h   |  109 +
 .../juce_core/threads/juce_InterProcessLock.h      |  128 +
 .../modules/juce_core/threads/juce_Process.h       |  153 ++
 .../juce_core/threads/juce_ReadWriteLock.cpp       |  150 ++
 .../modules/juce_core/threads/juce_ReadWriteLock.h |  152 ++
 .../modules/juce_core/threads/juce_ScopedLock.h    |  237 ++
 .../juce_core/threads/juce_ScopedReadLock.h        |   90 +
 .../juce_core/threads/juce_ScopedWriteLock.h       |   90 +
 .../modules/juce_core/threads/juce_SpinLock.h      |   91 +
 .../modules/juce_core/threads/juce_Thread.cpp      |  371 +++
 .../modules/juce_core/threads/juce_Thread.h        |  289 +++
 .../juce_core/threads/juce_ThreadLocalValue.h      |  198 ++
 .../modules/juce_core/threads/juce_ThreadPool.cpp  |  384 +++
 .../modules/juce_core/threads/juce_ThreadPool.h    |  321 +++
 .../juce_core/threads/juce_TimeSliceThread.cpp     |  171 ++
 .../juce_core/threads/juce_TimeSliceThread.h       |  149 ++
 .../modules/juce_core/threads/juce_WaitableEvent.h |  118 +
 .../juce_core/time/juce_PerformanceCounter.cpp     |  132 +
 .../juce_core/time/juce_PerformanceCounter.h       |  127 +
 .../modules/juce_core/time/juce_RelativeTime.cpp   |  139 ++
 .../modules/juce_core/time/juce_RelativeTime.h     |  184 ++
 .../modules/juce_core/time/juce_Time.cpp           |  469 ++++
 .../JUCE-3.0.8/modules/juce_core/time/juce_Time.h  |  404 ++++
 .../modules/juce_core/unit_tests/juce_UnitTest.cpp |  260 ++
 .../modules/juce_core/unit_tests/juce_UnitTest.h   |  311 +++
 .../modules/juce_core/xml/juce_XmlDocument.cpp     |  891 +++++++
 .../modules/juce_core/xml/juce_XmlDocument.h       |  181 ++
 .../modules/juce_core/xml/juce_XmlElement.cpp      |  888 +++++++
 .../modules/juce_core/xml/juce_XmlElement.h        |  763 ++++++
 .../zip/juce_GZIPCompressorOutputStream.cpp        |  213 ++
 .../zip/juce_GZIPCompressorOutputStream.h          |  101 +
 .../zip/juce_GZIPDecompressorInputStream.cpp       |  288 +++
 .../zip/juce_GZIPDecompressorInputStream.h         |   97 +
 .../modules/juce_core/zip/juce_ZipFile.cpp         |  608 +++++
 .../modules/juce_core/zip/juce_ZipFile.h           |  259 ++
 .../JUCE-3.0.8/modules/juce_core/zip/zlib/README   |  125 +
 .../modules/juce_core/zip/zlib/adler32.c           |  143 ++
 .../modules/juce_core/zip/zlib/compress.c          |   70 +
 .../JUCE-3.0.8/modules/juce_core/zip/zlib/crc32.c  |  407 ++++
 .../JUCE-3.0.8/modules/juce_core/zip/zlib/crc32.h  |  441 ++++
 .../modules/juce_core/zip/zlib/deflate.c           | 1679 +++++++++++++
 .../modules/juce_core/zip/zlib/deflate.h           |  333 +++
 .../modules/juce_core/zip/zlib/infback.c           |  611 +++++
 .../modules/juce_core/zip/zlib/inffast.c           |  316 +++
 .../modules/juce_core/zip/zlib/inffast.h           |   11 +
 .../modules/juce_core/zip/zlib/inffixed.h          |   94 +
 .../modules/juce_core/zip/zlib/inflate.c           | 1339 +++++++++++
 .../modules/juce_core/zip/zlib/inflate.h           |  121 +
 .../modules/juce_core/zip/zlib/inftrees.c          |  328 +++
 .../modules/juce_core/zip/zlib/inftrees.h          |   61 +
 .../JUCE-3.0.8/modules/juce_core/zip/zlib/trees.c  | 1191 +++++++++
 .../JUCE-3.0.8/modules/juce_core/zip/zlib/trees.h  |  127 +
 .../modules/juce_core/zip/zlib/uncompr.c           |   60 +
 .../JUCE-3.0.8/modules/juce_core/zip/zlib/zconf.h  |  345 +++
 .../modules/juce_core/zip/zlib/zconf.in.h          |  332 +++
 .../JUCE-3.0.8/modules/juce_core/zip/zlib/zlib.h   | 1358 +++++++++++
 .../JUCE-3.0.8/modules/juce_core/zip/zlib/zutil.c  |  311 +++
 .../JUCE-3.0.8/modules/juce_core/zip/zlib/zutil.h  |  271 +++
 src/htio2/Kmer.cpp                                 |  436 ++++
 src/htio2/Kmer.h                                   |  553 +++++
 src/htio2/MT19937.cpp                              |  270 +++
 src/htio2/MT19937.h                                |   97 +
 src/htio2/OptionParser.cpp                         |  609 +++++
 src/htio2/OptionParser.h                           |  231 ++
 src/htio2/PairedEndIO.cpp                          |  206 ++
 src/htio2/PairedEndIO.h                            |  133 +
 src/htio2/PlainFileHandle.cpp                      |  117 +
 src/htio2/PlainFileHandle.h                        |   86 +
 src/htio2/QualityUtil.cpp                          |  149 ++
 src/htio2/QualityUtil.h                            |  150 ++
 src/htio2/RefCounted.cpp                           |   12 +
 src/htio2/RefCounted.h                             |  156 ++
 src/htio2/RingBuffer.h                             |   95 +
 src/htio2/SeqIO.cpp                                |   99 +
 src/htio2/SeqIO.h                                  |  139 ++
 src/htio2/SimpleSeq.cpp                            |   89 +
 src/htio2/SimpleSeq.h                              |   87 +
 src/htio2/StringUtil.cpp                           |   34 +
 src/htio2/StringUtil.h                             |   55 +
 src/htio2/Version.cpp                              |   18 +
 src/htio2/Version.h                                |   18 +
 src/htio2/config.h.in                              |    8 +
 src/htqc/App.cpp                                   |   41 +
 src/htqc/App.h                                     |   14 +
 src/htqc/BaseQualCounter.cpp                       |  112 +
 src/htqc/BaseQualCounter.h                         |  112 +
 src/htqc/Common.cpp                                |   96 +
 src/htqc/Common.h                                  |   63 +
 src/htqc/FastqStat.cpp                             |  184 ++
 src/htqc/FastqStat.h                               |   63 +
 src/htqc/MicroAssembler.cpp                        |  289 +++
 src/htqc/MicroAssembler.h                          |   63 +
 src/htqc/MultiSeqFile.cpp                          |  122 +
 src/htqc/MultiSeqFile.h                            |   75 +
 src/htqc/Options.cpp                               |  337 +++
 src/htqc/Options.h                                 |  121 +
 src/htqc/Primer.cpp                                |  127 +
 src/htqc/Primer.h                                  |   47 +
 t/CMakeLists.txt                                   |  275 +++
 t/TestConfig.h.in                                  |    6 +
 t/TestFramework.cpp                                |  164 ++
 t/TestFramework.h                                  |  155 ++
 t/barcodes.tab                                     |   66 +
 t/double_1.fastq                                   |    8 +
 t/double_2.fastq                                   |    8 +
 t/double_ovlp.fastq                                |  Bin 0 -> 787 bytes
 t/filt.fastq.gz                                    |  Bin 0 -> 14014 bytes
 t/filt_1.fastq.gz                                  |  Bin 0 -> 6195 bytes
 t/filt_2.fastq.gz                                  |  Bin 0 -> 6375 bytes
 t/filt_fail.fastq.gz                               |  Bin 0 -> 8023 bytes
 t/filt_fail_1.fastq.gz                             |  Bin 0 -> 3168 bytes
 t/filt_fail_2.fastq.gz                             |  Bin 0 -> 3110 bytes
 t/filt_fail_s.fastq.gz                             |  Bin 0 -> 2292 bytes
 t/filt_s.fastq.gz                                  |  Bin 0 -> 2140 bytes
 t/option_parser.cpp                                |   54 +
 t/primers.fasta                                    |   13 +
 t/single_1.fastq                                   |    4 +
 t/single_2.fastq                                   |    4 +
 t/t_cast.cpp                                       |   80 +
 t/t_fasta_io.cpp                                   |   72 +
 t/t_fastq_io.cpp                                   |   72 +
 t/t_gzip_file_handle.cpp                           |   56 +
 t/t_header_util.cpp                                |   37 +
 t/t_ht_convert.cpp                                 |   17 +
 t/t_ht_demul.cpp                                   |  126 +
 t/t_ht_filter.cpp                                  |  101 +
 t/t_ht_lane_tile.cpp                               |   38 +
 t/t_ht_overlap.cpp                                 |   11 +
 t/t_ht_rename.cpp                                  |   37 +
 t/t_ht_sample.cpp                                  |   81 +
 t/t_ht_trim.cpp                                    |   24 +
 t/t_kmer_aa.cpp                                    |   60 +
 t/t_kmer_nt4_16.cpp                                |   96 +
 t/t_kmer_nt4_32.cpp                                |  109 +
 t/t_kmer_nt4_64.cpp                                |  173 ++
 t/t_kmer_nt5_16.cpp                                |   96 +
 t/t_kmer_nt5_32.cpp                                |  100 +
 t/t_kmer_nt5_64.cpp                                |  162 ++
 t/t_mt19937.cpp                                    |  167 ++
 t/t_multi_seq_file_pe.cpp                          |  141 ++
 t/t_multi_seq_file_se.cpp                          |   52 +
 t/t_plain_file_handle.cpp                          |   64 +
 t/t_ref_counted.cpp                                |   42 +
 t/t_ring_buffer.cpp                                |   67 +
 t/t_simple_seq.cpp                                 |   49 +
 t/t_string.cpp                                     |   58 +
 t/t_text_file_equal.cpp                            |   14 +
 t/test1.fasta                                      |  400 +++
 t/test1.fastq                                      |  400 +++
 t/test1.fastq.gz                                   |  Bin 0 -> 10941 bytes
 t/test2.fasta                                      |  400 +++
 t/test2.fastq                                      |  400 +++
 t/test2.fastq.gz                                   |  Bin 0 -> 10969 bytes
 t/test_interleave.fastq.gz                         |  Bin 0 -> 21549 bytes
 t/test_novlp_1.fastq.gz                            |  Bin 0 -> 2694 bytes
 t/test_novlp_2.fastq.gz                            |  Bin 0 -> 2829 bytes
 t/test_ovlp.fastq.gz                               |  Bin 0 -> 11933 bytes
 t/trim_1.fastq.gz                                  |  Bin 0 -> 10733 bytes
 t/trim_2.fastq.gz                                  |  Bin 0 -> 10768 bytes
 t/trim_both.fastq.gz                               |  Bin 0 -> 10733 bytes
 t/trim_head.fastq.gz                               |  Bin 0 -> 10874 bytes
 t/trim_tail.fastq.gz                               |  Bin 0 -> 10812 bytes
 375 files changed, 85726 insertions(+)

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..73d0f1a
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,57 @@
+#     HTQC - a high-throughput sequencing quality control toolkit
+#
+#     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.
+#
+#     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/>.
+
+cmake_minimum_required(VERSION 2.8)
+project(htqc)
+
+if (CMAKE_BUILD_TYPE STREQUAL "")
+  # CMake defaults to leaving CMAKE_BUILD_TYPE empty. This screws up
+  # differentiation between debug and release builds.
+  set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build, options are: None (CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE)
+endif ()
+
+list(APPEND CMAKE_CXX_FLAGS "-std=c++11")
+#set(CMAKE_EXE_LINKER_FLAGS_DEBUG ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=address)
+
+set(CPACK_PACKAGE_VERSION_MAJOR 1)
+set(CPACK_PACKAGE_VERSION_MINOR 92)
+set(CPACK_PACKAGE_VERSION_PATCH 1)
+set(CPACK_GENERATOR TGZ)
+set(CPACK_SOURCE_GENERATOR TGZ)
+set(CPACK_SOURCE_IGNORE_FILES ${CPACK_SOURCE_IGNORE_FILES} ".kdev4" "~" "build" "nbproject" "test_data" "CMakeLists.txt.user*")
+
+include(CPack)
+
+find_package(ZLIB)
+message(STATUS "  Zlib inc dir  : ${ZLIB_INCLUDE_DIRS}")
+message(STATUS "  Zlib libraries: ${ZLIB_LIBRARIES}")
+
+include(GNUInstallDirs)
+message(STATUS "GNU install dirs")
+message(STATUS "  bin: ${CMAKE_INSTALL_BINDIR}")
+message(STATUS "  lib: ${CMAKE_INSTALL_LIBDIR}")
+message(STATUS "  inc: ${CMAKE_INSTALL_INCLUDEDIR}")
+
+include_directories(
+    ${CMAKE_SOURCE_DIR}/src
+    ${CMAKE_SOURCE_DIR}/src
+    ${CMAKE_BINARY_DIR}/src
+    ${ZLIB_INCLUDE_DIRS}
+)
+
+set(juce_dep_libs pthread rt dl)
+
+add_subdirectory(src)
+add_subdirectory(t)
diff --git a/Changes.md b/Changes.md
new file mode 100644
index 0000000..49aa0bc
--- /dev/null
+++ b/Changes.md
@@ -0,0 +1,597 @@
+Changes
+=======
+
+1.92.1
+======
+
+  - ht2-overlap:
+
+    Fixed a severe bug that overlapping part in result sequence all come from
+    read 1, and probably using incorrect position.
+
+1.92.0
+======
+
+  - Use *JUCE* library to provide utility functions, and removed dependency on
+    *boost* whose CMake finder module is problematic. The *JUCE* stuffs are put
+    inside `htio2::juce` namespace.
+
+  - htio2 library
+
+    Added string manipulation functions in `StringUtil.h`: `split`, `join`,
+    `to_upper_case` and `to_lower_case`.
+
+    Added a command line option parser facility in `OptionParser.h`.
+
+    Replaced boost::intrusive_ptr by self-written pointer type. The Smart
+    pointer types for each class is defined inside the class. For example,
+    `FooBarPtr` are redefined to `FooBar::Ptr`.
+
+    Removed dependency on regular expression engine. Header format is guessed
+    using manually-written parser.
+
+    Modify the prefix of header file guardian macros from `HTIO_` to `HTIO2_`.
+
+  - all programs
+
+    Using `htio2::OptionParser` to parse command line options, which replaces
+    `boost::program_options`. Some option names are slightly modified.
+
+    Set default quality encoding from casava1.8 to unknown, which let the
+    program to guess sequence quality encoding.
+
+  - ht2-demul
+
+    Fixed a severe bug that when working with paired-end reads, read 1 is
+    written to both output.
+
+    Added unit test for read end validation.
+
+  - ht-stat
+
+    Fixed a bug that when working with very few amount of paired-end reads, the
+    QQ plot sampling would fall into endless cycle.
+
+    Use lock-free ring buffers to pass information between threads.
+
+  - ht2-sample
+
+    Now get accurate amount of results, instead of approximate amount.
+
+    Can directly specify number, or specify fraction of total.
+
+    Can write the indices of selected reads (or read pairs) into a file.
+
+1.91.0
+======
+  - use GNUInstallDirs to provide correct install location.
+
+  - finished ht2-filter and ht2-lane-tile.
+
+  - use markdown format for all documents.
+
+1.90.1
+======
+
+  - all programs:
+
+    The "--gzip/-z" option no longer exists. Compression is deduced by input
+    file name.
+
+  - ht2-filter and ht2-lane-tile-pick
+
+    Filter by length and quality at one time: pick those sequence whose length
+    of high quality bases is longer than length cutoff. The function of tile
+    filter is separated to ht2-lane-tile-pick.
+
+1.90.0
+======
+
+This is the pre-release of version 2.
+
+  - htio library
+
+    Header files are placed in htio2/ directory.
+
+    Added a new "RefCounted" base class which provides refcount. All
+    refcounted classes use Boost's intrusive_ptr class to provide a default
+    implementation for smart pointer.
+
+    Added a new "PairedEndIO" class which read/write paired-end reads, and
+    process issues such as interleaved / reverted mate pairs.
+
+    Moved all sequence format utilities into "SeqFormat.h", and added
+    functions to guess sequence format by file name or content.
+
+    Added write_seq(const FastqSeq&) to SeqIO base class.
+
+    Removed "HTIO_" prefix from all enums.
+
+    Tidy header file inclusion to increase compile speed.
+
+    Kmer utilities now support different memory size of Kmer type via template
+    specialization. Default specializations includes 64, 32 and 16 bit unsigned
+    integers.
+
+    Fixed errors of seek with SEEK_CUR and SEEK_END for the file handle classes.
+
+  - all programs
+
+    Allow interleaved input/output for paired-end reads.
+    
+    Use output file prefix instead of file name, so that all programs have same
+    behaviour.
+
+  - ht2-convert
+
+    a new program that converts sequence format, quality encoding, etc..
+
+  - ht2-overlap
+
+    the previous ht-asm program renamed to ht2-overlap to clarify its function.
+
+  - ht2-primer-trim
+
+    Supports multiple output by different primer set.
+
+    Do check reverse-complement strand by default, and use "--no-revcom" option
+    to disable this behaviour.
+
+    Added "--no-trim" option to not trim the primer sequence from reads, and
+    only pick the primer-containing reads.
+
+0.90.8
+======
+
+  - ht-demul
+
+    ".gz" suffix will be added for gzipped output files.
+
+0.90.7
+======
+
+  - ht-qual-recode
+
+    a new program for changing the encoding of sequence quality.
+
+  - GZipFileHandle.h and SeqIO.h
+
+    fixed an error that may cause conflicting type declaration of "gzFile", on
+    some version of zlib.
+
+0.90.6
+======
+
+  - ht-demul
+
+    fixed a bug that the program crashes if the output directory is not exist.
+
+    fixed a bug that the barcode file is not properly parsed.
+
+  - htio library
+
+    documentation for all functions.
+
+    FindHTIO1.cmake.
+
+    README_htio for simple tutorial on htio library.
+
+    two new functions for kmer generation. The length of whole input string is
+    treated as kmer size.
+
+0.90.5
+======
+
+  - htio library
+
+    removed #include in header files as much as possible. This would help to
+    increase compile speed.
+
+  - improved quality encode guessing strategy.
+
+  - guess encoding and header format from front 500 sequences.
+
+0.90.4
+======
+
+  - ht-primer-trim
+
+    changed default cutoff for allowed tail missing from 3 to 5.
+
+  - ht-asm
+
+    fixed an error which would cause segfault on specific inputs.
+
+  - added README for each program.
+
+  - source code
+
+    moved all C++ sources into a subdirectory so that the main directory would
+    have a clean look.
+
+0.90.3
+======
+
+  - htio library
+
+    fixed an bug on tell() of PlainFileHandle and GzipFileHandle.
+
+    fixed an bug on EncodedSeq revcom.
+
+    allowing FastaIO to read and write FastqSeq.
+
+0.90.2
+======
+
+  - htio library
+
+    added functions htio::SeqIO::New(), that automatically guess sequence format
+    from file content, and create handle for it.
+
+    fixed an error on FileHandle that seek() will disturb the file offset.
+
+    fixed an error on FastaIO that seek() will disturb the file offset. Now it
+    is ensured after reading one sequence, the offset is at the start of the
+    next sequence's header line.
+
+0.90.1
+======
+
+  - htio library
+
+    added operators on EncodedSeq and KmerList.
+
+  - fixed a bug that ht-primer-trim won't be installed.
+
+0.90.0
+======
+
+  - htio library
+
+    the include directory and library name now renamed to "htio1", with revised
+    API and ABI.
+
+    add functions for guess quality encoding and header format.
+
+    headers will be installed to PREFIX/include/htio1, and library is renamed to
+    libhtio1
+
+    quality range of CASAVA_1_8 changed to 0 - 41.
+
+    line reader can recognize CR, LF and CRLF.
+
+  - all programs
+
+    automatically guess quality encoding and header format.
+
+  - ht-asm
+
+    the old "ht-join" program now renamed to "ht-asm".
+
+  - ht-demul
+
+    a new program to demultiplex reads by barcode. Barcodes are got from the
+    FASTQ header.
+
+  - ht-primer-trim
+
+    a new program to remove primer sequence from reads.
+
+  - ht-stat
+
+    fixed a bug that the program crashes when the number of threads is more than
+    the number of input sequences.
+
+  - ht-stat-draw.pl
+
+    refined the output of lane-tile plots.
+
+    as GNUplot has issues on SVG heatmap, change default output format to PNG.
+
+    removed default font face setting from 'Arial' to '*', in avoid that some
+    machines don't have that font.
+
+0.15.1
+======
+
+  - revised CMakeLists.txt
+
+    might fix some bugs caused by library locating.
+
+  - ht-rename
+
+    by default, don't keep reads description (contents after first continuous
+    blank).
+
+0.15.0
+======
+
+  - all programs
+
+    use Boost instead of Glib.
+
+  - ht-rename
+
+    a new program to generate simple sequence IDs by batch.
+
+  - ht-stat
+
+    don't need to specify maximum read length.
+
+  - ht-filter
+
+    now won't accept zero-length sequences when filtering by quality.
+
+0.14.1
+======
+
+  - ht-stat
+
+    fixed a severe error that the program stucks at the third input file, due to
+    inappropriate queue access.
+
+0.14.0
+======
+
+  - ht-trim
+
+    require several continuous residues of good quality. If you want to fall
+    back to old behavior, set word size to 1.
+
+  - all programs
+
+    show help when run without any parameters.
+
+    check suffix for output file names and prefixes.
+
+0.13.2
+======
+
+  - all programs
+
+    add ".gz" suffix for output file names when using gzipped input and output.
+
+    user must specify "--single" or "--paired" explicitly, instead of single
+    mode by default.
+
+  - ht-join
+
+    specify output prefix for unjoined sequences using one single option "-u".
+
+0.13.1
+======
+
+  - HTIO library
+
+    fixed an error in FastqIO, that the program aborts when sequence has ID only
+    and has no description.
+
+  - added unit tests.
+
+  - README and program help
+
+    corrected some disaccording descriptions due to the upgrade from 0.12.X to
+    0.13.X.
+
+0.13.0
+======
+
+  - HTIO library
+
+    major API change.
+
+    added documentation.
+
+  - ht-stat
+
+    fixed a severe error that if multiple input files are given, the program
+    halts after finishing the first file.
+
+  - ht-filter
+
+    combines ht_length_filter, ht_tile_filter, ht_qual_filter into one program.
+
+  - all programs
+
+    use "-" instead of "_" in program names, so all programs are named "ht-xxx"
+    instead of "ht_xxx"
+
+    use single option "-o" to specify output prefix, instead of using "-a" "-b"
+    "-s" separately.
+
+0.12.1
+======
+
+  - ht_join
+
+    write unjoined sequences to user specified files (options -U -V).
+
+0.12.0
+======
+
+  - source code
+
+    IO classes and FASTQ sequence classes are moved to a new library named HTIO.
+
+  - ht_qual_filter, ht_length_filter, ht_sample
+
+    output for single-end mode now use "--out-s" instead of "--out-a".
+
+  - ht_stat_draw.pl
+
+    help document now provides correct usage.
+
+  - added reference in README.
+
+0.11.1
+======
+
+  - ht_stat
+
+    fixed a bug that parameters are not correctly printed to info file.
+
+  - ht_join
+
+    fixed a bug that quality on assembled sequence tail was not generated
+    correctly.
+
+    write more information to output sequence header.
+
+    aligning bases must both have good quality to be considered identical. This
+    will make the alignment more stringent.
+
+  - all programs
+
+    print parameters on log.
+
+    print log on STDOUT instead of STDERR.
+
+0.11.0
+======
+
+  - ht_join
+
+    a new program that joins paired-end reads into single sequences.
+
+  - all programs
+
+    use '--quiet' instead of '--verbose'. Thus all programs will by default
+    print information, unless you explicitly let them quiet.
+
+  - source code
+
+    checked if the GPL v3 license exists in all source files.
+
+    the command line option objects that have enumerative string values now use
+    G_OPTION_ARG_CALLBACK type, so that main functions of related programs don't
+    need to parse these options by themselves.
+
+0.10.2
+======
+
+  - all programs
+
+    support read/write gzipped sequences.
+
+    exit with error message when failed to open a file.
+
+  - source code
+
+    modified file layout; move everything to "htqc" namespace.
+
+    use C style stdio to read sequences instead of C++ stream.
+
+0.10.1
+======
+
+  - ht_stat
+
+    refined thread usage.
+
+    fixed an error that the program behaved weirdly if there are too few input
+    reads.
+
+  - ht_length_filter, ht_qual_filter, ht_sample
+
+    If the program did not work in paired-end mode ("--paired" or "-p"), but
+    output files were provided for the other end ("--out-b" or "-b") or the
+    unpaired ("--out-single" or "-s"), these programs will claim that.
+
+  - all programs
+
+    common option objects are compiled into a library. This is for the ease of
+    development, and does not affect user experience.
+
+0.10.0
+======
+
+  - all programs
+
+    able to take multiple input files. Command-line options are modified
+    accordingly.
+
+  - ht_stat, ht_tile_filter
+
+    control FASTQ quality encoding and header format using separate options
+    ("--encode" and "--header-format").
+
+  - ht_stat
+
+    creates separate files for text reports instead of one big file, and "--out"
+    option now specifies an output folder containing these files.
+
+  - ht_trim
+
+    this program replaces ht_tail_filter, and it can trim reads from both head
+    and tail.
+
+  - refined README and program help.
+
+0.9.7
+=====
+
+  - ht_stat
+
+    fixed the bug when -l is longer than actual read size, -65535 was given in
+    some charts.
+
+  - added a new program named "ht_sample" to pick sample from reads.
+
+  - FASTQ parser
+
+    modified '+' line validation.
+
+0.9.6
+=====
+
+  - ht_stat
+
+    threaded
+
+  - re-organize source code
+
+  - solved warnings about const char*
+
+0.9.5
+=====
+
+  - ht_stat
+
+    calculate Pearson correlation and print in QQ plot
+
+  - ht_stat.pl
+
+    changed line color for distribution of read quality and read length.
+
+0.9.4
+=====
+
+  - ht_stat_draw.pl
+
+    allow users to select picture format
+
+  - print logs on stderr
+
+0.9.3
+=====
+
+  - in addition of cycle quality heat map, add a box graph
+
+  - correct descriptions of program helps
+
+0.9.2
+=====
+
+  - a new perl script for rendering ht_stat outputs using gnuplot
+
+  - added '-v' or '--version' command-line switch to show program version
+
+0.9.1
+=====
+
+  - filled bugs in regexp for illumina header
+
+0.9.0
+=====
+
+  - initial release
diff --git a/FindHTIO2.cmake b/FindHTIO2.cmake
new file mode 100644
index 0000000..e2b86ac
--- /dev/null
+++ b/FindHTIO2.cmake
@@ -0,0 +1,39 @@
+include(FindPackageHandleStandardArgs)
+include(GNUInstallDirs)
+
+set(HTIO2_ROOT "" CACHE PATH "Additional HTIO2 search path")
+
+# find HTIO2 config header
+find_file(htio2_config_h htio2/config.h
+    PATHS ${HTIO2_ROOT}
+    PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR})
+
+#message(STATUS "  config header: ${htio2_config_h}")
+
+# parse version
+if(htio2_config_h)
+    file(STRINGS ${htio2_config_h} line_major REGEX "VERSION_MAJOR")
+    file(STRINGS ${htio2_config_h} line_minor REGEX "VERSION_MINOR")
+    file(STRINGS ${htio2_config_h} line_patch REGEX "VERSION_PATCH")
+
+    string(REGEX REPLACE "^.*VERSION_MAJOR +([0-9]+).*$" "\\1" HTIO2_VERSION_MAJOR "${line_major}")
+    string(REGEX REPLACE "^.*VERSION_MINOR +([0-9]+).*$" "\\1" HTIO2_VERSION_MINOR "${line_minor}")
+    string(REGEX REPLACE "^.*VERSION_PATCH +([0-9]+).*$" "\\1" HTIO2_VERSION_PATCH "${line_patch}")
+    set(HTIO2_VERSION_STRING "${HTIO2_VERSION_MAJOR}.${HTIO2_VERSION_MINOR}.${HTIO2_VERSION_PATCH}")
+    get_filename_component(HTIO2_INCLUDE_DIRS ${htio2_config_h} PATH CACHE)
+endif()
+
+# find HTIO2 library
+find_library(htio2_archive htio2
+    PATHS ${HTIO2_ROOT}
+    PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR})
+
+if(htio2_archive)
+    set(HTIO2_LIBRARIES ${htio2_archive} CACHE STRING "HTIO2 library")
+endif()
+
+#message(STATUS "  library: ${htio2_archive}")
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(HTIO2
+    REQUIRED_VARS htio2_config_h htio2_archive
+    VERSION_VAR HTIO2_VERSION_STRING)
diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 0000000..034e837
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,59 @@
+HTQC installation guide
+=======================
+
+CMake
+-----
+
+HTQC uses CMake to generate platform-specific build files. You must have CMake
+to build HTQC. To test whether you have CMake on your system, run:
+  $ cmake -h
+
+It should print help information if CMake has been properly installed.
+
+If you don't have a CMake in your system, please use your Unix system's package
+management system, or download CMake from their website: http://www.cmake.org/
+
+Simple install
+--------------
+
+Goto the source code directory:
+
+    $ cd (where_you_put_the_code)/htqc-X.X.X-Source
+
+In the source code dir, create a place to conatin build results:
+
+    $ mkdir build
+    $ cd build
+
+* Now we are in (where_you_put_the_code)/htqc-X.X.X-Source/build.
+* Please make sure the file "CMakeLists.txt" exists in the upper directory of
+  "build" directory.
+
+Run cmake to generate makefile:
+
+    $ cmake ..
+
+* ".." indicates the upper directory is the root of project
+* the file "Makefile" should be generated in current directory
+
+Build and install
+
+    $ make
+    $ su
+    $ make install
+
+Customized install
+------------------
+
+If you can't get system-wide permission to copy programs to "/usr/local/bin",
+you can install the program only for yourself. To do this, run cmake by
+specifying install prefix to a directory under your control:
+
+    $ cmake -DCMAKE_INSTALL_PREFIX=~ ../
+    $ make
+    $ make install
+
+It will install the programs to "~/bin" and libraries to "~/lib", which you
+have permissions to create files.
+
+For more options, please refer to the handbook of CMake.
diff --git a/README-convert.md b/README-convert.md
new file mode 100644
index 0000000..fc9d19d
--- /dev/null
+++ b/README-convert.md
@@ -0,0 +1,63 @@
+ht2-convert - convert reads storage format
+==========================================
+
+Introduction
+------------
+
+The program `ht2-convert` can convert several aspects for FASTQ format
+sequences, including:
+
+  - quality encode
+  - paired-end interleaving
+  - strand
+
+### Paired-end Interleaving
+
+There are two common ways to store paired-end files. One way is to store them in
+separate file pairs, each containing one end:
+
+    File 1:      File 2:
+    r1_1         r1_2
+    r2_1         r2_2
+    r3_1         r3_2
+
+and the other way is to store them in one file, which is called **interleaving**:
+
+    File:
+    r1_1
+    r1_2
+    r2_1
+    r2_2
+    r3_1
+    r3_2
+
+### Strand
+
+In most common cases, paired-end sequences has following layout:
+
+    >>>> read 1 >>>>
+    =========================== sequence ===========================
+                                                    <<<< read 2 <<<<
+
+However, for long insertion size libraries, the paired-end sequences may have
+this layout:
+
+                                                >>>> read 1 >>>>
+    =========================== sequence ===========================
+        <<<< read 2 <<<<
+
+-----
+Usage
+-----
+
+Separate interleaved file:
+
+    $ ht2-convert -P --pe-itlv -i input.fastq -o output
+
+files "output_1.fastq" and "output_2.fastq" will be generated.
+
+Combine file pairs into interleaved file:
+
+    $ ht2-convert -P --out-pe-itlv -i input_1.fastq input_2.fastq -o output
+
+the file "output.fastq" will be generated.
diff --git a/README-demul.md b/README-demul.md
new file mode 100644
index 0000000..df4893c
--- /dev/null
+++ b/README-demul.md
@@ -0,0 +1,38 @@
+ht2-demul - separate sequences by lane ID and barcode sequence
+=============================================================
+
+Introduction
+------------
+
+Many high-throughput sequencing platforms allow multiple samples being sequenced
+together, and distinguish the samples using known short oligonucleotides
+(usually named "index" or "barcode). Therefore, it is necessary to separate
+reads from different samples after you get the raw sequencing data, and this
+operation is called **demultiplexing**.
+
+The program `ht2-demul` separates reads from different samples using barcode
+sequences stored in FASTQ header line.
+
+Input and output
+----------------
+
+The input sequences can be single-end or paired-end. The sequence header must be
+CASAVA 1.8 format, because prior to CASAVA version 1.8, the barcode
+sequence is not stored in the headers.
+
+The barcode file should be a tab-delimited plain text with 3 columns, which are:
+
+  - project name
+  - sample name
+  - barcode sequence
+
+Demultiplexed reads are firstly grouped into folders according to project name,
+then by files according to sample name, so it is better to not include spaces in
+your project name and sample name.
+
+Usage
+-----
+
+Results are written to directory "output":
+
+    $ ht2-demul --paired-end --barcode barcodes.tab -i IN_1.fastq IN_2.fastq -o output
diff --git a/README-filter.md b/README-filter.md
new file mode 100644
index 0000000..424b2a5
--- /dev/null
+++ b/README-filter.md
@@ -0,0 +1,26 @@
+ht2-filter - filter reads by different criteria
+===============================================
+
+Introduction
+------------
+
+The program `ht2-filter` filters sequences according to the length of high
+quality bases.
+
+Input and output
+----------------
+
+Both single-end and paired-end reads are accepted. When paired-end reads is
+processed, the number of input files should be even, and the files of read 1
+should be given on front, then follwing the files of read 2.
+
+When input reads are paired-end and only one end is accepted, it will be
+written to a separate file (OutputPrefix_s.fastq).
+
+Usage
+-----
+
+The accepted reads will be stored in file OUT_1.fastq and OUT_2.fastq, and the
+one-end-accepted reads will be stored in file OUT_s.fastq.
+
+    $ ht2-filter --paired-end -i IN_1.fastq IN_2.fastq -o OUT
diff --git a/README-htio.md b/README-htio.md
new file mode 100644
index 0000000..586a244
--- /dev/null
+++ b/README-htio.md
@@ -0,0 +1,124 @@
+HTIO - high-throughput sequence processing library
+==================================================
+
+Introduction
+------------
+
+HTIO is a library for processing high-throughput sequences. It contains
+functions for FASTA/FASTQ file read/write, quality score decoding, FASTQ header
+parsing, k-mer generation etc..
+
+Synopsis
+--------
+
+    #include <htio2/FastqIO.h>
+    #include <htio2/FastqSeq.h>
+    //......
+
+Usage
+-----
+
+To use HTIO library, you need to include corresponding header files in your
+source code:
+
+    #include <htio2/FastqIO.h>
+    #include <htio2/FastqSeq.h>
+    #include <htio2/Kmer.h>
+    //......
+
+To compile your program, you need to include the directory containing HTIO
+header files, and link with HTIO library:
+
+    $ g++ -o my_program -I MY/HEADER/PREFIX my_program.cpp MY/PATH/TO/libhtio2.a
+
+By default, HTIO headers are installed to `/usr/local/include`, and the static
+libraries are installed to `/usr/local/lib` (or `/usr/local/lib64` for 64-bit
+*Fedora* systems). So you probably don't need to specify the `-I` option:
+
+    $ g++ -o my_program my_program.cpp /usr/local/lib/libhtio1.a
+
+Examples
+--------
+
+Convert sequences from FASTQ to FASTA:
+
+    #include <htio1/FastqIO.h>
+    #include <htio1/FastaIO.h>
+    #include <htio1/FastqSeq.h>
+
+    int main(int argc, char** argv)
+    {
+        // create file handles
+        htio::FastqIO fh_in(argv[1], htio::HTIO_READ);
+        htio::FastaIO fh_out(argv[2], htio::HTIO_WRITE);
+
+        // read and write sequences
+        htio::FastqSeq seq;
+        while (fh_in.next_seq(seq))
+            fh_out.write_seq(seq);
+    }
+
+Show positions where qualitiy is lower than 20:
+
+    #include <htio1/FastqIO.h>
+    #include <htio1/FastqSeq.h>
+    #include <htio1/QualityUtil.h>
+    #include <iostream>
+
+    int main(int argc, char** argv)
+    {
+        // create file handles
+        htio::FastqIO fh_in(argv[1], htio::HTIO_READ);
+
+        // read sequences
+        htio::FastqSeq seq;
+        while (fh_in.next_seq(seq))
+        {
+            std::cout << seq.id << std::endl;
+
+            // decode quality
+            std::vector<int16_t> quality_dec;
+            htio::decode_quality(seq.quality, quality_dec);
+
+            // show quality
+            for (size_t i=0; i<quality_dec.size(); i++)
+            {
+                if (quality_dec[i]<20)
+                    std::cout << i+1 << ": " << quality_dec[i] << std::endl;
+            }
+        }
+    }
+
+Generate k-mers:
+
+    #include <htio1/FastqIO.h>
+    #include <htio1/FastqSeq.h>
+    #include <htio1/Kmer.h>
+    #include <iostream>
+
+    int main(int argc, char** argv)
+    {
+        // create file handles
+        htio::FastqIO fh_in(argv[1], htio::HTIO_READ);
+
+        // read sequences
+        htio::FastqSeq seq;
+        while (fh_in.next_seq(seq))
+        {
+            // convert atgcn to 01234
+            htio::EncodedSeq enc_seq;
+            htio::encode_nt(seq.seq, enc_seq);
+
+            // generate kmers, using a word size of six
+            htio::KmerList kmers;
+            htio::gen_kmer_nt(enc_seq, kmers, 6);
+
+            // summarize occurred position
+            htio::KmerPosMap kmer_pos;
+            htio::summ_kmer_pos(kmers, kmer_pos);
+
+            // show kmer and position
+            for (htio::KmerPosMap::iterator it = kmer_pos.begin(); it != kmer_pos.end(); it++)
+                std::cout << "kmer " << htio::decode_kmer_nt(it->first, 6) << " at " << it->second+1 << std::endl;
+        }
+    }
diff --git a/README-lane-tile.md b/README-lane-tile.md
new file mode 100644
index 0000000..b065fca
--- /dev/null
+++ b/README-lane-tile.md
@@ -0,0 +1,34 @@
+ht2-lane-tile - remove reads from specific lane/tile
+====================================================
+
+Introduction
+------------
+
+Tiles are rectangular areas in an Illumina sequencing chip. Sometimes, specific
+tiles may produce very few amount of acceptable reads, and some people think it
+is better to reject all reads from those tiles. Thus we provide this program to
+reject reads from specific tiles.
+
+Input and Output
+----------------
+
+This program do not distinguish single-end and paired-end inputs. Paired-end
+inputs can be processed by apply the program on each file.
+
+Usage
+-----
+
+Reject sequences from tile 2 and 3:
+
+    $ ht2-lane-tile -T 2 3 -i input.fastq -o output
+
+If your input file contains reads from multiple lanes, and you only wish to
+reject sequences from a specific lane-tile, you can specify lane number. For
+example, you want to reject tile 2 and 3 in lane 5:
+
+    $ ht2-lane-tile -L 5 -T 2 3 -i input.fastq -o output
+
+If you also want to get those rejected reads, specify the output prefix with
+`-u` option:
+
+    $ ht2-lane-tile -L 5 -T 2 3 -i input.fastq -o output -u rejected
diff --git a/README-overlap.md b/README-overlap.md
new file mode 100644
index 0000000..e9e3220
--- /dev/null
+++ b/README-overlap.md
@@ -0,0 +1,38 @@
+ht2-overlap - assemble overlapping read pairs
+=============================================
+
+Introduction
+------------
+
+Merge 3'-overlapping paired-end reads into single sequences.
+
+Input and output
+----------------
+
+Input should be paired-end reads. If read ends are stored in file pairs, all
+files of read 1 should be given firstly, then follwing all files of read 2.
+
+The assembled reads are written into one file. The non-assembled reads are
+written into file specified by "-u" option.
+
+Usage
+-----
+
+Default run:
+
+    $ ht2-overlap -i IN_1.fastq IN_2.fastq -o overlap
+
+If you also need those non-assembled reads, provide a file prefix using "-u"
+option:
+
+    $ ht2-overlap -i IN_1.fastq IN_2.fastq -o overlap -u non_overlap
+
+Files `non_overlap_1.fastq` and `non_overlap_2.fastq` will be generated.
+
+Assume your input reads are separated into multiple volumes. You can specify
+those input files via file globbing:
+
+    $ ls
+    IN_vol1_1.fastq    IN_vol2_1.fastq    IN_vol3_1.fastq
+    IN_vol1_2.fastq    IN_vol2_2.fastq    IN_vol3_2.fastq
+    $ht2-overlap -i IN_*_1.fastq IN_*_2.fastq -o overlap -u non_overlap
diff --git a/README-primer-trim.md b/README-primer-trim.md
new file mode 100644
index 0000000..2b230d6
--- /dev/null
+++ b/README-primer-trim.md
@@ -0,0 +1,80 @@
+ht2-primer-trim - find and remove primers from reads
+===================================================
+
+Introduction
+------------
+
+`ht2-primer-trim` removes primer sequences from reads. This task is common for
+sequencing on PCR-amplified products, such as 16S, ITS, and other phylogenetic
+marker sequences.
+
+Input and Output
+----------------
+
+The program accepts single- and paired-end input reads. The primer sequences
+should be given in one FASTA file. The ID of 5' primers should begin with
+"left", and 3' ones begin with "right". Output targets should be given by
+description. Multiplexed primers are accepted.
+
+Only the reads with primers are trimmed and written to output. User
+can specify a file prefix for those reads failed to found primers.
+
+For example:
+
+    >left1 16S
+    XXXXXXXXXXXXXXX
+    >left2 16S
+    XXXXXXXXXXXXXXX
+    >left3 ITS
+    XXXXXXXXXXXXXXX
+    >left4 ITS
+    XXXXXXXXXXXXXXX
+    >right1 16S
+    XXXXXXXXXXXXXXX
+    >right2 ITS
+    XXXXXXXXXXXXXXX
+
+  - if a sequence matches with left1 and right1, or left2 and right1, it will be
+    written to `OUT_DIR/16S.fastq`;
+
+  - if a sequences matches with left3 and right2, or left4 and right2, it will
+    be written to `OUT/ITS.fastq`;
+
+  - if a sequence matches with left1 and right2, or only match with one primer,
+    or don't match with any primers, it will be discarded, or written to the
+    file for failed sequences (if specified by user).
+
+Primer Matching Strategy
+------------------------
+
+When processing single-end reads, primers are attempted to be aligned in
+pattern below:
+
+    >>>> left primer >>>>
+    >>>>>>>>>>>>>>>>>>>>>>>>>> read >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+                                            <<<< right primer <<<<
+
+If reverse-complement check is specified, the primers are
+also to be aligned in the pattern below:
+
+    >>>> right primer >>>>
+    >>>>>>>>>>>>>>>>>>>>>>>>>> read >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+                                             <<<< left primer <<<<
+
+When processing paired-end reads, primers are attempted to be aligned in
+pattern below:
+
+    >>>> left primer >>>>
+    >>>>>>>>>>>>>>>>>>>>>>>>>> read 1 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+    >>>> right primer >>>>
+    >>>>>>>>>>>>>>>>>>>>>>>>>> read 2 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+If the reverse-complement check is specified, the primers are
+also to be aligned in the pattern below:
+
+    >>>> right primer >>>>
+    >>>>>>>>>>>>>>>>>>>>>>>>>> read 1 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+    >>>> left primer >>>>
+    >>>>>>>>>>>>>>>>>>>>>>>>>> read 2 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
diff --git a/README-rename.md b/README-rename.md
new file mode 100644
index 0000000..22f6d6b
--- /dev/null
+++ b/README-rename.md
@@ -0,0 +1,22 @@
+ht2-rename - generate simple sequence IDs by batch
+==================================================
+
+Introduction
+------------
+
+The original sequence ID usually contains detailed information and is very long.
+ht2-rename generates short ID by auto-incremented numbers and user-defined
+prefix|suffix.
+
+Input and Output
+----------------
+
+The program don't distinguish single-end and paired-end inputs. If the input
+sequences are paired-end in separate fils, just run the program on each file.
+
+Usage
+-----
+
+Generates IDs like PRE_1_SUFF, PRE_2_SUFF, PRE_3_SUFF...:
+
+    $ ht2-rename -i in_1.fastq -o renamed_1.fastq --prefix PRE_ --suffix _SUFF
diff --git a/README-sample.md b/README-sample.md
new file mode 100644
index 0000000..764c47a
--- /dev/null
+++ b/README-sample.md
@@ -0,0 +1,30 @@
+ht2-sample - randomly pick some reads
+====================================
+
+Introduction
+------------
+
+Sometimes you may want to randomly pick a fraction of sequences. ht2-sample
+picks a given fraction of sequences randomly.
+
+Note: the fraction is not exact. For example, if you have 1000 sequences and
+specified to pick 1/10 of them, you will **NOT** get exactly 100 sequences.
+This is a compromise to get better run-time performance.
+
+Input and output
+----------------
+
+This program accepts both single-end and paired-end reads. When paired-end reads
+is processed, the number of input files should be even, and the files of read 1
+should be given on front, then follwing the files of read 2.
+
+Usage
+-----
+
+Pick 1/100 of sequences, output will be written to sample.fastq:
+
+  $ ht2-sample -S -i in.fastq -o sample -r 100
+
+For paired-end, output will be written to sample_1.fastq and sample_2.fastq:
+
+  $ ht2-sample -P -i in_1.fastq in_2.fastq -o sample -r 100
diff --git a/README-stat.md b/README-stat.md
new file mode 100644
index 0000000..b6a63cd
--- /dev/null
+++ b/README-stat.md
@@ -0,0 +1,35 @@
+ht2-stat - summarize sequencing reads quality
+=============================================
+
+Introduction
+------------
+
+`ht2-stat` produces sequence assessment in following aspects:
+
+  - quality by cycle
+  - quality by lane/tile
+  - base composition by cycle
+  - quality histogram
+  - length histogram
+  - quality QQ plot for paired-end reads
+
+Input and output
+----------------
+
+The program accepts both single-end and paired-end reads. When paired-end reads
+is processed, the number of input files should be even, and the files of read
+1 should be given on front, then follwing the files of read 2.
+
+Results are written to a directory in plain-text tab-delimited format. If input
+is paired-end, the results for each end are placed in separated files.
+
+Usage
+-----
+
+Output files are placed in "qual_stat" folder:
+
+    $ ht2-stat -S -i in.fastq -o qual_stat
+
+For paired-end reads:
+
+    $ ht2-stat -P -i in_1.fastq in_2.fastq -o qual_stat
diff --git a/README-trim.md b/README-trim.md
new file mode 100644
index 0000000..c11abc6
--- /dev/null
+++ b/README-trim.md
@@ -0,0 +1,29 @@
+ht2-trim - remove bad residues from sequence start/end
+=====================================================
+
+Introduction
+------------
+
+The quality of sequencing reads from Illumina platform usually drops along
+length. ht2-trim can remove low-quality part from the start and the end of reads.
+
+The trim stops at the first *N* continuous bases in which qualities are all higher
+than *Q*. (N=5 and Q=20 by default).
+
+Input and output
+----------------
+
+The program don't distinguish single-end and paired-end inputs. If you need to
+process paired-end reads stored in separate file pairs, just run the program on
+each file.
+
+Usage
+-----
+
+Trim from both side:
+
+    $ ht2-trim -i in.fastq -o out.fastq
+
+Only trim from end, keep start:
+
+    $ ht2-trim --trim-side head -i in.fastq -o out.fastq
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6bb8be9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,151 @@
+HTQC - a high-throughput sequencing quality control toolkit
+===========================================================
+
+Introduction
+------------
+
+HTQC is a read quality control toolkit for high-throughput sequencing. It
+contain a program for quality statistics, and several programs for quality
+filtration.
+
+Currently, only Illumina sequencing platform is supported.
+
+System requirements
+-------------------
+
+- **Zlib** is required for build and run the programs.
+- **Perl** and **Chart::Clicker** are required to run "ht2-stat-draw.pl", which
+  renders the output tables of "ht2-stat" to charts.
+
+If you build HTQC from source:
+
+- The C++ compiler must have well-support on C++11. This means at least you need
+  GCC 4.8, clang 3.3 or MSVC 2010. Preferably, you should use GCC 4.9, clang 3.5
+  or MSVC 2013.
+
+- CMake is used for cross-platform build configuration.
+
+If your system don't have those softwares installed, please refer to your OS's
+package management system. For example: *yum* for Fedora; *apt-get*, *aptitude*
+and *synaptics* for Debian; *pacman* for Arch. Or you can visit their official
+website:
+
+-
+-
+- http://www.cmake.org
+
+Install
+-------
+
+See "INSTALL" document.
+
+List of Programs
+----------------
+
+- ht2-demul
+
+  separate reads into individual files by barcode sequence.
+
+- ht2-filter
+
+  filter reads by quality / length / tile ID.
+
+- ht2-overlap
+
+  concatenate paired-end reads into single sequences.
+
+- ht2-primer-trim
+
+  remove primer sequences from reads.
+
+- ht2-rename
+
+  give sequences short name using auto-increased number and user-specified
+  prefix & suffix.
+
+- ht2-sample
+
+  randomly pick some sequences.
+
+- ht2-stat
+
+  generate reads quality statistics report.
+
+- ht2-stat-draw.pl
+
+  draw charts from ht2-stat output.
+
+- ht2-trim
+
+  trim reads from start and/or end by quality.
+
+For detailed descriptions, see individual README-XXX files for each program.
+Run a program with "-h" or "--help" will show command-line options.
+
+Typical usage
+-------------
+
+First of all, to know whether the sequencing reads are good:
+
+    $ ht2-stat -P -i reads_R1_* reads_R2_* -o report_dir
+    $ ht2-stat-draw.pl --dir report_dir
+
+Suppose it shows tile 5 and 14 is bad. Remove reads from these tiles:
+
+    $ ht2-lane-tile -i reads_R1_* --tile 5 14 -o tile_tidy_1
+    $ ht2-lane-tile -i reads_R2_* --tile 5 14 -o tile_tidy_2
+
+Trim low-quality tails:
+
+    $ ht2-trim -i tile_tidy_1.fastq -o trim_1.fastq
+    $ ht2-trim -i tile_tidy_2.fastq -o trim_2.fastq
+
+Remove reads that are too short:
+
+    $ ht2-filter -i trim_1.fastq trim_2.fastq -o filt
+
+Maybe you want to concatenate paired-ends to longer sequences:
+
+    $ ht2-overlap -i filt_1.fastq filt_2.fastq -o overlap -u non_overlap
+
+Single-end or pair-end
+----------------------
+
+Some programs handle single-end and paired-end reads differently. For those
+programs, outputs files are specified by a prefix, and multiple files will
+generated. For "ht2-filter", when one end of a paired-end is rejected but the
+other end is accepted, it is stored to "PREFIX_s.fastq".
+
+Programs like "ht2-trim" don't distinguish between paired-end or single-end
+mode. It only accepts one input file and one output file. You should run them
+twice for paired-end reads, one time for the file of each end.
+
+Reference
+---------
+
+We would be really appreciated if you cite our article:
+
+Yang X, Liu D, Liu F, Wu J, Zou J, Xiao X, Zhao F, Zhu B.
+HTQC: a fast quality control toolkit for Illumina sequencing data.
+BMC Bioinformatics. 2013 Jan 31;14:33
+
+Acknowledgements
+----------------
+
+JUCE core library is used for part of the base system. It is a light-weighted
+library whose source can be contained and compiled with our project. Thanks for
+the developers of JUCE! It's great!!!
+
+Contact
+-------
+
+If you have any questions or find any bugs, please email us:
+
+developer:
+
+- Xi Yang: jiandingzhe at 163.com, yangx at im.ac.cn
+- Di Liu: liud at im.ac.cn
+
+corresponding author:
+
+- Baoli Zhu: zhubaoli at im.ac.cn
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..a3bb0fc
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,101 @@
+configure_file(ht_config.h.in ht_config.h @ONLY)
+configure_file(htio2/config.h.in htio2/config.h @ONLY)
+
+file(GLOB HTIO_SOURCE_FILES htio2/*.cpp)
+file(GLOB HTQC_SOURCE_FILES htqc/*.cpp)
+file(GLOB JUCE_SOURCE_FILES htio2/JUCE-3.0.8/modules/*/*.cpp)
+
+add_library(htio2 STATIC ${HTIO_SOURCE_FILES} ${JUCE_SOURCE_FILES})
+
+add_library(ht_common STATIC ${HTQC_SOURCE_FILES})
+
+add_executable(ht2-convert ht2-convert.cpp)
+target_link_libraries(ht2-convert
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+
+add_executable(ht2-demul ht2-demul.cpp)
+target_link_libraries(ht2-demul
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+
+add_executable(ht2-stat ht2-stat.cpp
+    htqc/BaseQualCounter.cpp
+    htqc/FastqStat.cpp
+)
+target_link_libraries(ht2-stat
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+
+add_executable(ht2-trim ht2-trim.cpp)
+target_link_libraries(ht2-trim
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+
+add_executable(ht2-filter ht2-filter.cpp)
+target_link_libraries(ht2-filter
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+
+add_executable(ht2-rename ht2-rename.cpp)
+target_link_libraries(ht2-rename
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+
+add_executable(ht2-sample ht2-sample.cpp)
+target_link_libraries(ht2-sample
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+
+add_executable(ht2-overlap ht2-overlap.cpp)
+target_link_libraries(ht2-overlap
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+
+add_executable(ht2-primer-trim ht2-primer-trim.cpp)
+target_link_libraries(ht2-primer-trim
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+
+add_executable(ht2-lane-tile ht2-lane-tile.cpp)
+target_link_libraries(ht2-lane-tile
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+
+install(TARGETS ht2-demul ht2-primer-trim ht2-convert ht2-stat ht2-trim ht2-filter ht2-sample ht2-overlap ht2-rename htio2
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+install(PROGRAMS ht2-stat-draw.pl DESTINATION bin)
+install(FILES ${CMAKE_BINARY_DIR}/src/htio2/config.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/htio2)
+install(DIRECTORY htio2/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/htio2 FILES_MATCHING PATTERN "*.h")
diff --git a/src/ht2-convert.cpp b/src/ht2-convert.cpp
new file mode 100644
index 0000000..3110e6a
--- /dev/null
+++ b/src/ht2-convert.cpp
@@ -0,0 +1,238 @@
+#include <htio2/PairedEndIO.h>
+#include <htio2/QualityUtil.h>
+#include "htio2/Cast.h"
+#include "htio2/SeqIO.h"
+
+#define USE_prefix_out
+#define USE_se_pe
+#define USE_encode
+#define USE_header_format
+#include <htqc/Options.h>
+#include <htqc/App.h>
+#include <htqc/MultiSeqFile.h>
+
+using namespace std;
+using namespace htqc;
+
+bool OPT_out_pe_itlv;
+htio2::Option OPT_out_pe_itlv_ENTRY("out-pe-itlv", '\0', OPTION_GROUP_FORMAT,
+                                    &OPT_out_pe_itlv, htio2::Option::FLAG_NONE,
+                                    "Output paired-end reads will be stored in interleaved format.");
+
+string OPT_out_pe_strand("FR");
+htio2::Option OPT_out_pe_strand_ENTRY("out-pe-strand", '\0', OPTION_GROUP_FORMAT,
+                                      &OPT_out_pe_strand, htio2::Option::FLAG_NONE,
+                                      "The strand of paired-end reads for output. \"F\" for forward, \"R\" for reverse. 1st character for read 1, 2nd character for read 2.",
+                                      "FF|FR|RF|RR");
+
+htio2::QualityEncode OPT_out_encode;
+htio2::Option OPT_out_encode_ENTRY("out-encode", '\0', OPTION_GROUP_FORMAT,
+                                   &OPT_out_encode, htio2::Option::FLAG_NONE,
+                                   "Output quality score encode.", "STRING");
+
+htio2::Strand OPT_out_pe_strand1()
+{
+    return _cast_strand_chr(OPT_out_pe_strand[0]);
+}
+
+htio2::Strand OPT_out_pe_strand2()
+{
+    return _cast_strand_chr(OPT_out_pe_strand[1]);
+}
+
+void parse_options(int argc, char** argv)
+{
+    htio2::OptionParser option_parser;
+    option_parser.add_option(OPT_files_in_ENTRY);
+    option_parser.add_option(OPT_prefix_out_ENTRY);
+    option_parser.add_option(OPT_se_ENTRY);
+    option_parser.add_option(OPT_pe_ENTRY);
+
+    option_parser.add_option(OPT_encode_ENTRY);
+    option_parser.add_option(OPT_pe_itlv_ENTRY);
+    option_parser.add_option(OPT_pe_strand_ENTRY);
+
+    option_parser.add_option(OPT_out_encode_ENTRY);
+    option_parser.add_option(OPT_out_pe_itlv_ENTRY);
+    option_parser.add_option(OPT_out_pe_strand_ENTRY);
+
+    option_parser.add_option(OPT_quiet_ENTRY);
+    option_parser.add_option(OPT_help_ENTRY);
+    option_parser.add_option(OPT_version_ENTRY);
+
+    option_parser.parse_options(argc, argv);
+
+    if (OPT_help)
+    {
+        cout << endl
+            << argv[0] << " - convert paired-end reads from interleaved format to file pairs, or reverse"<< endl
+            << endl
+            << option_parser.format_document();
+        exit(EXIT_SUCCESS);
+    }
+    if (OPT_version) htqc::show_version_and_exit();
+}
+
+void validate_options()
+{
+    ensure_files_in();
+    ensure_prefix_out();
+    ensure_se_pe();
+    ensure_encode();
+    ensure_header_format();
+
+    if (OPT_pe)
+    {
+        if (OPT_out_pe_strand == "unknown")
+            OPT_out_pe_strand = _OPT_pe_strand;
+
+        if (OPT_out_pe_strand.length() != 2
+            || !check_strand_chr(OPT_out_pe_strand[0])
+            || !check_strand_chr(OPT_out_pe_strand[1]))
+        {
+            cerr << "ERROR: invalid paired-end strand: " << OPT_out_pe_strand << endl
+                << "Valid values: FF/FR/RF/RR (lower case allowed)." << endl;
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    if (OPT_out_encode == htio2::ENCODE_UNKNOWN)
+        OPT_out_encode = OPT_encode;
+}
+
+void show_options()
+{
+    show_se_pe();
+    show_files_in();
+    show_encode();
+    show_prefix_out();
+    cout << "# output encode: " << htio2::to_string(OPT_out_encode) << endl;
+    if (OPT_pe)
+    {
+        cout << "# output strand: " << OPT_out_pe_strand << endl;
+        if (OPT_out_pe_itlv)
+            cout << "# output is interleaved" << endl;
+    }
+}
+
+void do_se()
+{
+    // output file name
+    string file_out;
+    add_fastq_suffix_se(OPT_prefix_out, OPT_compress, file_out);
+    check_output_overwrite(OPT_files_in, file_out);
+
+    // io handles
+    htqc::MultiSeqFileSE fh_in(OPT_files_in, OPT_compress);
+    htio2::SeqIO::Ptr fh_out(htio2::SeqIO::New(file_out, htio2::WRITE, OPT_compress));
+
+    // traverse sequences
+    htio2::FastqSeq seq;
+    vector<int16_t> qual;
+
+    size_t n_seq = 0;
+
+    while (fh_in.next_seq(seq))
+    {
+        n_seq++;
+        if (OPT_encode != OPT_out_encode)
+        {
+            htio2::decode_quality(seq.quality, qual, OPT_encode);
+            htio2::encode_quality(qual, seq.quality, OPT_out_encode);
+        }
+        fh_out->write_seq(seq);
+        if (!OPT_quiet && n_seq % LOG_BLOCK == 0)
+            cout << "  " << n_seq << " processed" << endl;
+    }
+
+    if (!OPT_quiet)
+        cout << "  " << n_seq << " processed" << endl;
+}
+
+void do_pe()
+{
+    htqc::MultiSeqFilePE* fh_in;
+    htio2::PairedEndIO* fh_out;
+
+    htio2::Strand strand_in1 = OPT_pe_strand1();
+    htio2::Strand strand_in2 = OPT_pe_strand2();
+
+    if (OPT_pe_itlv)
+    {
+        fh_in = new htqc::MultiSeqFilePE(OPT_files_in,
+                                         strand_in1, strand_in2,
+                                         OPT_compress);
+    }
+    else
+    {
+        vector<string> files1;
+        vector<string> files2;
+        separate_paired_files(OPT_files_in, files1, files2);
+        fh_in = new htqc::MultiSeqFilePE(files1, files2,
+                                         strand_in1, strand_in2,
+                                         OPT_compress);
+    }
+
+    if (OPT_out_pe_itlv)
+    {
+        string file_out;
+        add_fastq_suffix_se(OPT_prefix_out, OPT_compress, file_out);
+        check_output_overwrite(OPT_files_in, file_out);
+        fh_out = new htio2::PairedEndIO(file_out,
+                                       htio2::WRITE,
+                                       OPT_out_pe_strand1(), OPT_out_pe_strand2(),
+                                       OPT_compress);
+    }
+    else
+    {
+        string file_out1;
+        string file_out2;
+        add_fastq_suffix_pe(OPT_prefix_out, OPT_compress, file_out1, file_out2);
+        check_output_overwrite(OPT_files_in, file_out1);
+        check_output_overwrite(OPT_files_in, file_out2);
+        fh_out = new htio2::PairedEndIO(file_out1, file_out2,
+                                       htio2::WRITE,
+                                       OPT_out_pe_strand1(), OPT_out_pe_strand2(),
+                                       OPT_compress);
+    }
+
+    htio2::FastqSeq seq1;
+    htio2::FastqSeq seq2;
+    vector<int16_t> qual1;
+    vector<int16_t> qual2;
+
+    size_t n_seq = 0;
+
+    while (fh_in->next_pair(seq1, seq2, strand_in1, strand_in2))
+    {
+        n_seq++;
+        if (OPT_encode != OPT_out_encode)
+        {
+            htio2::decode_quality(seq1.quality, qual1, OPT_encode);
+            htio2::decode_quality(seq2.quality, qual2, OPT_encode);
+            htio2::encode_quality(qual1, seq1.quality, OPT_out_encode);
+            htio2::encode_quality(qual2, seq2.quality, OPT_out_encode);
+        }
+
+        fh_out->write_pair(seq1, seq2, strand_in1, strand_in2);
+        if (!OPT_quiet && n_seq % LOG_BLOCK == 0)
+            cout << "  " << n_seq << " pairs processed" << endl;
+    }
+
+    if (!OPT_quiet)
+        cout << "  " << n_seq << " pairs processed" << endl;
+
+    delete fh_in;
+    delete fh_out;
+}
+
+void execute()
+{
+    if (OPT_se)
+        do_se();
+    else if (OPT_pe)
+        do_pe();
+    else
+        throw runtime_error("neither single-end nor paired-end");
+}
+
diff --git a/src/ht2-demul.cpp b/src/ht2-demul.cpp
new file mode 100644
index 0000000..83a95dc
--- /dev/null
+++ b/src/ht2-demul.cpp
@@ -0,0 +1,438 @@
+#include "htio2/Cast.h"
+#include "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+#include "htio2/PairedEndIO.h"
+#include "htio2/PlainFileHandle.h"
+#include "htio2/HeaderUtil.h"
+
+#define USE_header_format
+#define USE_se_pe
+#include "htqc/Options.h"
+#include "htqc/App.h"
+#include "htqc/MultiSeqFile.h"
+
+#include "htio2/JUCE-3.0.8/JuceHeader.h"
+
+#include <set>
+
+// We don't care strand in this program, so simply let them identical.
+#define PE_STRAND_FILE htio2::STRAND_FWD, htio2::STRAND_FWD
+#define PE_STRAND_OBJ htio2::STRAND_FWD, htio2::STRAND_FWD
+
+using namespace std;
+using namespace htqc;
+using namespace htio2::juce;
+
+string OPT_dir_out;
+htio2::Option OPT_dir_out_ENTRY("out", 'o', OPTION_GROUP_IO,
+                                &OPT_dir_out, htio2::Option::FLAG_NONE,
+                                "Output directory.", "DIR");
+string OPT_file_barcode;
+htio2::Option OPT_file_barcode_ENTRY("barcode", '\0', OPTION_GROUP_IO,
+                                     &OPT_file_barcode, htio2::Option::FLAG_NONE,
+                                     "Tab-delimited file containing three columns which are project, sample and barcode. Output will be written to output_dir/project/sample_[12].fastq",
+                                     "FILE");
+
+int OPT_mismatch(0);
+htio2::Option OPT_mismatch_ENTRY("mismatch", '\0', "Algorithm Parameters",
+                                 &OPT_mismatch, htio2::Option::FLAG_NONE,
+                                 "Allowed number of barcode mismatch.", "INT");
+
+void parse_options(int argc, char** argv)
+{
+    htio2::OptionParser option_parser;
+    option_parser.add_option(OPT_files_in_ENTRY);
+    option_parser.add_option(OPT_dir_out_ENTRY);
+    option_parser.add_option(OPT_file_barcode_ENTRY);
+
+    option_parser.add_option(OPT_mismatch_ENTRY);
+
+    option_parser.add_option(OPT_se_ENTRY);
+    option_parser.add_option(OPT_pe_ENTRY);
+    option_parser.add_option(OPT_pe_itlv_ENTRY);
+    option_parser.add_option(OPT_pe_strand_ENTRY);
+    option_parser.add_option(OPT_header_format_ENTRY);
+    option_parser.add_option(OPT_header_sra_ENTRY);
+
+    option_parser.add_option(OPT_quiet_ENTRY);
+    option_parser.add_option(OPT_help_ENTRY);
+    option_parser.add_option(OPT_version_ENTRY);
+
+    option_parser.parse_options(argc, argv);
+
+    // show help
+    if (OPT_help)
+    {
+        cout << endl
+            << argv[0] << " - demultiplex reads by barcode"
+            << endl << endl
+            << option_parser.format_document();
+        exit(EXIT_SUCCESS);
+    }
+
+    if (OPT_version) show_version_and_exit();
+}
+
+void validate_options()
+{
+    ensure_files_in();
+    ensure_se_pe();
+
+    if (!OPT_dir_out.length())
+    {
+        cerr << "ERROR: output directory not specified" << endl;
+        exit(EXIT_FAILURE);
+    }
+
+    ensure_header_format();
+
+    if (OPT_header_format != htio2::HEADER_1_8)
+    {
+        cerr << "ERROR: only CASAVA 1.8 headers can be used for demultiplex" << endl
+            << "your header format is: " << htio2::to_string(OPT_header_format) << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+void show_options()
+{
+    show_se_pe();
+    show_files_in();
+    cout << "# output dir: " << OPT_dir_out << endl;
+    cout << "# barcode file: " << OPT_file_barcode << endl;
+    cout << "# barcode mismatch: " << OPT_mismatch << endl;
+    show_header_format();
+}
+
+void read_barcode(map<string, pair<string, string> > & barcodes)
+{
+    if (!OPT_quiet)
+        cout << "read barcode file" << endl;
+    barcodes.clear();
+
+    htio2::PlainFileHandle IN(OPT_file_barcode.c_str(), htio2::READ);
+    string buffer;
+
+    while (IN.read_line(buffer))
+    {
+        size_t tab1 = buffer.find_first_of('\t');
+        size_t tab2 = buffer.find_first_of('\t', tab1 + 1);
+        string proj(buffer.substr(0, tab1));
+        string sample(buffer.substr(tab1 + 1, tab2 - tab1 - 1));
+        string barcode(buffer.substr(tab2 + 1));
+
+        if (!barcodes.insert(make_pair(barcode, make_pair(proj, sample))).second)
+        {
+            cerr << "ERROR: duplicate barcode: " << barcode << endl;
+            exit(EXIT_FAILURE);
+        }
+    }
+}
+
+void gen_output_dir(const map<string, pair<string, string> > & barcodes)
+{
+    if (!OPT_quiet) cout << "create output directories" << endl;
+
+    File p_out(OPT_dir_out.c_str());
+
+    if (!p_out.isDirectory())
+    {
+        Result re = p_out.createDirectory();
+        if (re.failed())
+        {
+            fprintf(stderr, "ERROR: failed to create output directory \"%s\": %s\n",
+                    OPT_dir_out.c_str(), re.getErrorMessage().toRawUTF8());
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    set<string> projs;
+    for (map<string, pair<string, string> >::const_iterator it = barcodes.begin(); it != barcodes.end(); it++)
+    {
+        projs.insert(it->second.first);
+    }
+
+    for (set<string>::const_iterator it = projs.begin(); it != projs.end(); it++)
+    {
+        File p_out_proj = p_out.getChildFile(it->c_str());
+
+        // remove existing directory
+        if (p_out_proj.isDirectory())
+        {
+            if (!OPT_quiet)
+                printf("  remove existing dir \"%s\"\n", p_out_proj.getFullPathName().toRawUTF8());
+
+            if (!p_out_proj.deleteRecursively())
+            {
+                fprintf(stderr, "ERROR: failed to remove dir \"%s\"\n", p_out_proj.getFullPathName().toRawUTF8());
+                exit(EXIT_FAILURE);
+            }
+        }
+
+        // create new directory
+        if (!OPT_quiet)
+            cout << "  create output dir: " << p_out_proj.getFullPathName().toStdString() << endl;
+
+        Result re = p_out_proj.createDirectory();
+        if (re.failed())
+        {
+            fprintf(stderr, "ERROR: failed to create output directory \"%s\": %s\n",
+                    p_out_proj.getFullPathName().toRawUTF8(), re.getErrorMessage().toRawUTF8());
+            exit(EXIT_FAILURE);
+        }
+    }
+}
+
+bool check_barcode(const map<string, pair<string, string> > & barcodes,
+                   const string& barcode,
+                   string& proj,
+                   string& sample)
+{
+    map<string, pair<string, string> >::const_iterator it = barcodes.find(barcode);
+
+    if (it != barcodes.end())
+    {
+        proj = it->second.first;
+        sample = it->second.second;
+        return true;
+    }
+    else if (OPT_mismatch)
+    {
+        for (it = barcodes.begin(); it != barcodes.end(); it++)
+        {
+            const string& ref_barcode = it->first;
+            if (ref_barcode.length() != barcode.length()) continue;
+            size_t diff = 0;
+            for (size_t i = 0; i < ref_barcode.length(); i++)
+            {
+                if (ref_barcode[i] != barcode[i]) diff++;
+            }
+
+            if (diff <= OPT_mismatch)
+            {
+                proj = it->second.first;
+                sample = it->second.second;
+                return true;
+            }
+        }
+        return false;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+int64_t n_accept = 0;
+int64_t n_seq = 0;
+
+string gen_out_file_one(const string& proj, const string& sample)
+{
+    File prefix = File(OPT_dir_out).getChildFile(String(proj)).getChildFile(String(sample));
+    string file_out;
+    add_fastq_suffix_se(prefix.getFullPathName().toStdString(), OPT_compress, file_out);
+    check_output_overwrite(OPT_files_in, file_out);
+    return file_out;
+}
+
+void gen_out_file_pair(const string& proj, const string& sample, string& f1, string& f2)
+{
+    File prefix = File(OPT_dir_out).getChildFile(String(proj)).getChildFile(String(sample));
+    add_fastq_suffix_pe(prefix.getFullPathName().toStdString(), OPT_compress, f1, f2);
+    check_output_overwrite(OPT_files_in, f1);
+    check_output_overwrite(OPT_files_in, f2);
+}
+
+string gen_fail_file_one()
+{
+    File prefix = File(OPT_dir_out).getChildFile("demul_failed");
+    string file_out;
+    add_fastq_suffix_se(prefix.getFullPathName().toStdString(), OPT_compress, file_out);
+    check_output_overwrite(OPT_files_in, file_out);
+    return file_out;
+}
+
+void gen_fail_file_pair(string& f1, string& f2)
+{
+    File prefix = File(OPT_dir_out).getChildFile("demul_failed");
+    add_fastq_suffix_pe(prefix.getFullPathName().toStdString(), OPT_compress, f1, f2);
+    check_output_overwrite(OPT_files_in, f1);
+    check_output_overwrite(OPT_files_in, f2);
+}
+
+void do_se(const map<string, pair<string, string> > & barcodes)
+{
+    htio2::FastqSeq curr_seq;
+    htio2::HeaderParser parser(OPT_header_format, OPT_header_sra);
+    string proj;
+    string sample;
+
+    int64_t n_accept = 0;
+    int64_t n_seq = 0;
+
+    string file_fail = gen_fail_file_one();
+
+    htio2::FastqIO FAIL(file_fail, htio2::WRITE, OPT_compress);
+
+    for (size_t file_i = 0; file_i < OPT_files_in.size(); file_i++)
+    {
+        htio2::FastqIO IN(OPT_files_in[file_i], htio2::READ, OPT_compress);
+
+        while (IN.next_seq(curr_seq))
+        {
+            parser.parse(curr_seq.id, curr_seq.desc);
+
+            if (check_barcode(barcodes, parser.barcode, proj, sample))
+            {
+                string file_out = gen_out_file_one(proj, sample);
+                htio2::FastqIO OUT(file_out, htio2::APPEND, OPT_compress);
+                OUT.write_seq(curr_seq);
+                n_accept++;
+            }
+            else
+            {
+                FAIL.write_seq(curr_seq);
+            }
+
+            n_seq++;
+            if (!OPT_quiet && n_accept % LOG_BLOCK == 0)
+                cout << "  " << n_seq << " sequences, " << n_accept << " has barcode" << endl;
+        }
+    }
+
+    if (!OPT_quiet)
+        cout << "  " << n_seq << " sequences, " << n_accept << " has barcode" << endl;
+}
+
+void process_one_pe(const htio2::FastqSeq& seq1,
+                    const htio2::FastqSeq& seq2,
+                    htio2::PairedEndIO& fh_fail,
+                    const map<string, pair<string, string> > & barcodes,
+                    htio2::HeaderParser& parser1,
+                    htio2::HeaderParser& parser2)
+{
+    n_seq++;
+
+    string proj;
+    string sample;
+
+    parser1.parse(seq1.id, seq1.desc);
+    parser2.parse(seq2.id, seq2.desc);
+
+    if (parser1.barcode != parser2.barcode)
+    {
+        cerr << "ERROR: paired-end has conflict barcodes: " << endl
+            << parser1.barcode << endl
+            << parser2.barcode << endl;
+        exit(EXIT_FAILURE);
+    }
+
+    if (check_barcode(barcodes, parser1.barcode, proj, sample))
+    {
+        n_accept++;
+
+        if (OPT_pe_itlv)
+        {
+            string file_out = gen_out_file_one(proj, sample);
+            htio2::PairedEndIO fh_out(file_out,
+                                     htio2::APPEND,
+                                     PE_STRAND_FILE,
+                                     OPT_compress);
+            fh_out.write_pair(seq1, seq2, PE_STRAND_OBJ);
+        }
+        else
+        {
+            string f1;
+            string f2;
+            gen_out_file_pair(proj, sample, f1, f2);
+            htio2::PairedEndIO fh_out(f1,
+                                     f2,
+                                     htio2::APPEND,
+                                     PE_STRAND_FILE,
+                                     OPT_compress);
+            fh_out.write_pair(seq1, seq2, PE_STRAND_OBJ);
+        }
+    }
+    else
+    {
+        fh_fail.write_pair(seq1, seq2);
+    }
+
+    if (!OPT_quiet && n_accept % LOG_BLOCK == 0)
+        cout << "  " << n_seq << " paired-ends, " << n_accept << " has barcode" << endl;
+}
+
+void do_pe(const map<string, pair<string, string> > & barcodes)
+{
+    htio2::FastqSeq curr1;
+    htio2::FastqSeq curr2;
+    htio2::HeaderParser parser1(OPT_header_format, OPT_header_sra);
+    htio2::HeaderParser parser2(OPT_header_format, OPT_header_sra);
+
+    if (!OPT_quiet)
+        cout << "traverse input files" << endl;
+
+    if (OPT_pe_itlv)
+    {
+        // create handle for failed output
+        string file_fail = gen_fail_file_one();
+
+        htio2::PairedEndIO fh_fail(file_fail,
+                                   htio2::WRITE,
+                                   PE_STRAND_FILE,
+                                   OPT_compress);
+
+        // traverse input files
+        htqc::MultiSeqFilePE fh_in(OPT_files_in, PE_STRAND_FILE, OPT_compress);
+
+        while (fh_in.next_pair(curr1, curr2, PE_STRAND_OBJ))
+        {
+            process_one_pe(curr1, curr2, fh_fail, barcodes, parser1, parser2);
+        }
+    }
+    else
+    {
+        string file_fail1;
+        string file_fail2;
+        gen_fail_file_pair(file_fail1, file_fail2);
+
+        htio2::PairedEndIO fh_fail(file_fail1,
+                                   file_fail2,
+                                   htio2::WRITE,
+                                   PE_STRAND_FILE,
+                                   OPT_compress);
+
+        vector<string> files_in_a;
+        vector<string> files_in_b;
+        separate_paired_files(OPT_files_in, files_in_a, files_in_b);
+
+        // traverse input file pairs
+        htqc::MultiSeqFilePE fh_in(files_in_a,
+                                   files_in_b,
+                                   PE_STRAND_FILE,
+                                   OPT_compress);
+
+        while (fh_in.next_pair(curr1, curr2, PE_STRAND_OBJ))
+        {
+            process_one_pe(curr1, curr2, fh_fail, barcodes, parser1, parser2);
+        }
+    }
+
+    if (!OPT_quiet)
+        cout << "done: " << n_seq << " paired-ends, " << n_accept << " has barcode" << endl;
+}
+
+void execute()
+{
+    map<string, pair<string, string> > barcodes;
+
+    read_barcode(barcodes);
+    gen_output_dir(barcodes);
+
+    if (OPT_se)
+        do_se(barcodes);
+    else if (OPT_pe)
+        do_pe(barcodes);
+    else
+        throw runtime_error("neither single-end nor paired-end");
+}
diff --git a/src/ht2-filter.cpp b/src/ht2-filter.cpp
new file mode 100644
index 0000000..9e31db3
--- /dev/null
+++ b/src/ht2-filter.cpp
@@ -0,0 +1,340 @@
+#define USE_prefix_out
+#define USE_encode
+#define USE_mask
+#define USE_header_format
+#define USE_se_pe
+#include "htqc/Options.h"
+#include "htqc/App.h"
+#include "htqc/MultiSeqFile.h"
+
+#include "htio2/SeqIO.h"
+#include "htio2/PairedEndIO.h"
+#include "htio2/QualityUtil.h"
+
+// We don't care strand in this program, so simply let them identical.
+#define PE_STRAND_FILE htio2::STRAND_FWD, htio2::STRAND_FWD
+#define PE_STRAND_OBJ htio2::STRAND_FWD, htio2::STRAND_FWD
+
+using namespace std;
+using namespace htqc;
+
+string OPT_prefix_reject;
+htio2::Option OPT_prefix_reject_ENTRY("reject", 'u', OPTION_GROUP_IO,
+                                      &OPT_prefix_reject, htio2::Option::FLAG_NONE,
+                                      "Output file prefix for rejected sequences.", "FILE_PREFIX");
+
+size_t OPT_cut_len(80);
+htio2::Option OPT_cut_len_ENTRY("length", 'L', "Filter Options",
+                                &OPT_cut_len, htio2::Option::FLAG_NONE,
+                                "Cutoff for the length of high-quality base pairs.", "INT");
+
+int16_t OPT_cut_qual(20);
+htio2::Option OPT_cut_qual_ENTRY("quality", 'Q', "Filter Options",
+                                 &OPT_cut_qual, htio2::Option::FLAG_NONE,
+                                 "Cutoff for base pair quality.", "INT");
+
+void parse_options(int argc, char** argv)
+{
+    htio2::OptionParser opt_psr;
+
+    opt_psr.add_option(OPT_files_in_ENTRY);
+    opt_psr.add_option(OPT_prefix_out_ENTRY);
+    opt_psr.add_option(OPT_prefix_reject_ENTRY);
+
+    opt_psr.add_option(OPT_se_ENTRY);
+    opt_psr.add_option(OPT_pe_ENTRY);
+    opt_psr.add_option(OPT_pe_itlv_ENTRY);
+
+    opt_psr.add_option(OPT_cut_len_ENTRY);
+    opt_psr.add_option(OPT_cut_qual_ENTRY);
+
+    opt_psr.add_option(OPT_encode_ENTRY);
+    opt_psr.add_option(OPT_mask_ENTRY);
+
+    opt_psr.add_option(OPT_quiet_ENTRY);
+    opt_psr.add_option(OPT_help_ENTRY);
+    opt_psr.add_option(OPT_version_ENTRY);
+
+    opt_psr.parse_options(argc, argv);
+
+    // show help
+    if (OPT_help)
+    {
+        cout << endl
+             << argv[0] << " - filter sequences by length and quality"
+             << endl << endl
+             << opt_psr.format_document();
+        exit(EXIT_SUCCESS);
+    }
+
+    if (OPT_version) show_version_and_exit();
+}
+
+void validate_options()
+{
+    ensure_files_in();
+    ensure_prefix_out();
+    ensure_se_pe();
+    ensure_encode();
+
+    if (OPT_prefix_reject.length())
+        tidy_prefix_out(OPT_prefix_reject);
+
+    if (OPT_prefix_out == OPT_prefix_reject)
+    {
+        cerr << "conflict output prefix for accepted and rejected reads: \"" << OPT_prefix_reject << "\"" << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+void show_options()
+{
+    show_se_pe();
+    show_files_in();
+    show_prefix_out();
+
+    if (OPT_prefix_reject.length())
+        cout << "# file prefix for rejected reads: " << OPT_prefix_reject << endl;
+
+    cout << "# length cutoff: " << OPT_cut_len << endl;
+    cout << "# quality cutoff: " << OPT_cut_qual << endl;
+    show_encode();
+}
+
+bool validate_seq(const htio2::FastqSeq& seq)
+{
+    vector<int16_t> qual;
+    htio2::decode_quality(seq.quality, qual, OPT_encode);
+
+    size_t high_qual_len = 0;
+    for (size_t i = 0; i < seq.length(); i++)
+    {
+        if (qual[i] >= OPT_cut_qual)
+            high_qual_len++;
+    }
+
+    return (high_qual_len >= OPT_cut_len);
+}
+
+void filter_se()
+{
+    // input
+    htqc::MultiSeqFileSE fh_in(OPT_files_in, OPT_compress);
+
+    // output
+    string file_out;
+    add_fastq_suffix_se(OPT_prefix_out, OPT_compress, file_out);
+    check_output_overwrite(OPT_files_in, file_out);
+    htio2::SeqIO::Ptr fh_out(htio2::SeqIO::New(file_out, htio2::WRITE, OPT_compress));
+
+    // rejected
+    htio2::SeqIO::Ptr fh_fail;
+    if (OPT_prefix_reject.length())
+    {
+        string file_fail;
+        add_fastq_suffix_se(OPT_prefix_reject, OPT_compress, file_fail);
+        check_output_overwrite(OPT_files_in, file_fail);
+        fh_fail = htio2::SeqIO::New(file_fail, htio2::WRITE, OPT_compress);
+    }
+
+    // traverse input
+    htio2::FastqSeq curr_seq;
+    int64_t n_accept = 0;
+    int64_t n_seq = 0;
+
+    while (fh_in.next_seq(curr_seq))
+    {
+        n_seq++;
+
+        if (validate_seq(curr_seq))
+        {
+            fh_out->write_seq(curr_seq);
+            n_accept++;
+        }
+        else
+        {
+            if (OPT_prefix_reject.length())
+                fh_fail->write_seq(curr_seq);
+        }
+
+        if (!OPT_quiet && (n_seq % LOG_BLOCK == 0))
+            cout << "\t" << n_seq << " reads, " << n_accept << " accept" << endl;
+    }
+
+    if (!OPT_quiet)
+        cout << "\t" << n_seq << " reads, " << n_accept << " accept" << endl;
+}
+
+int64_t n_accept_pair = 0;
+int64_t n_accept_single = 0;
+int64_t n_pair = 0;
+
+void filter_one_pe(const htio2::FastqSeq& seq1,
+                   const htio2::FastqSeq& seq2,
+                   htio2::PairedEndIO* fh_out,
+                   htio2::SeqIO* fh_single,
+                   htio2::PairedEndIO* fh_fail_pair,
+                   htio2::SeqIO* fh_fail_single)
+{
+    n_pair++;
+
+    bool accept_a = validate_seq(seq1);
+    bool accept_b = validate_seq(seq2);
+
+    if (accept_a)
+    {
+        if (accept_b)
+        {
+            fh_out->write_pair(seq1, seq2, PE_STRAND_OBJ);
+            n_accept_pair++;
+        }
+        else
+        {
+            fh_single->write_seq(seq1);
+            if (OPT_prefix_reject.length())
+                fh_fail_single->write_seq(seq2);
+            n_accept_single++;
+        }
+    }
+    else
+    {
+        if (accept_b)
+        {
+            if(OPT_prefix_reject.length())
+                fh_fail_single->write_seq(seq1);
+            fh_single->write_seq(seq2);
+            n_accept_single++;
+        }
+        else
+        {
+            if (OPT_prefix_reject.length())
+                fh_fail_pair->write_pair(seq1, seq2, PE_STRAND_OBJ);
+        }
+    }
+
+    if (!OPT_quiet && (n_pair % LOG_BLOCK == 0))
+        cout << "\t" << n_pair << " pairs, " << n_accept_pair << " accept by pair, " << n_accept_single << " accept by single" << endl;
+}
+
+void filter_pe()
+{
+    // generate output file name for one-side-accepted reads
+    string file_out_s;
+    add_fastq_suffix_se(OPT_prefix_out + "_s", OPT_compress, file_out_s);
+    check_output_overwrite(OPT_files_in, file_out_s);
+
+    string file_fail_s;
+    if (OPT_prefix_reject.length())
+    {
+        add_fastq_suffix_se(OPT_prefix_reject + "_s", OPT_compress, file_fail_s);
+        check_output_overwrite(OPT_files_in, file_fail_s);
+    }
+
+    // tmp sequence
+    htio2::FastqSeq seq1;
+    htio2::FastqSeq seq2;
+
+    if (OPT_pe_itlv)
+    {
+        // input
+        htqc::MultiSeqFilePE fh_in(OPT_files_in,
+                                    PE_STRAND_FILE,
+                                    OPT_compress);
+
+        // output
+        string file_out_p;
+        add_fastq_suffix_se(OPT_prefix_out + "_p", OPT_compress, file_out_p);
+        check_output_overwrite(OPT_files_in, file_out_p);
+
+        htio2::PairedEndIO::Ptr fh_out_p(new htio2::PairedEndIO(file_out_p,
+                                                              htio2::WRITE,
+                                                              PE_STRAND_FILE,
+                                                              OPT_compress)
+                                       );
+
+        htio2::SeqIO::Ptr fh_out_s(htio2::SeqIO::New(file_out_s,
+                                                   htio2::WRITE,
+                                                   OPT_compress)
+                                 );
+
+        // fail
+        htio2::PairedEndIO::Ptr fh_fail_p;
+        htio2::SeqIO::Ptr fh_fail_s;
+
+        if (OPT_prefix_reject.length())
+        {
+            string file_fail_p;
+            add_fastq_suffix_se(OPT_prefix_reject + "_p", OPT_compress, file_fail_p);
+            check_output_overwrite(OPT_files_in, file_fail_p);
+
+            fh_fail_p = new htio2::PairedEndIO(file_fail_p, htio2::WRITE, PE_STRAND_FILE, OPT_compress);
+            fh_fail_s = htio2::SeqIO::New(file_fail_s, htio2::WRITE, OPT_compress);
+        }
+
+        // traverse input files
+        while (fh_in.next_pair(seq1, seq2, PE_STRAND_OBJ))
+            filter_one_pe(seq1, seq2, fh_out_p.get(), fh_out_s.get(), fh_fail_p.get(), fh_fail_s.get());
+    }
+    else
+    {
+        // input
+        vector<string> files_in_a;
+        vector<string> files_in_b;
+        separate_paired_files(OPT_files_in, files_in_a, files_in_b);
+        htqc::MultiSeqFilePE fh_in(files_in_a,
+                                    files_in_b,
+                                    PE_STRAND_FILE,
+                                    OPT_compress);
+
+
+        // output
+        string file_out_a;
+        string file_out_b;
+        add_fastq_suffix_pe(OPT_prefix_out, OPT_compress, file_out_a, file_out_b);
+        check_output_overwrite(OPT_files_in, file_out_a);
+        check_output_overwrite(OPT_files_in, file_out_b);
+
+        htio2::PairedEndIO::Ptr fh_out_p(new htio2::PairedEndIO(file_out_a,
+                                                              file_out_b,
+                                                              htio2::WRITE,
+                                                              PE_STRAND_FILE,
+                                                              OPT_compress)
+                                       );
+
+        htio2::SeqIO::Ptr fh_out_s(htio2::SeqIO::New(file_out_s,
+                                                   htio2::WRITE,
+                                                   OPT_compress)
+                                 );
+
+        // fail
+        htio2::PairedEndIO::Ptr fh_fail_p;
+        htio2::SeqIO::Ptr fh_fail_s;
+        if (OPT_prefix_reject.length())
+        {
+            string file_fail_a, file_fail_b;
+            add_fastq_suffix_pe(OPT_prefix_reject, OPT_compress, file_fail_a, file_fail_b);
+            check_output_overwrite(OPT_files_in, file_fail_a);
+            check_output_overwrite(OPT_files_in, file_fail_b);
+
+            fh_fail_p = new htio2::PairedEndIO(file_fail_a, file_fail_b, htio2::WRITE, PE_STRAND_FILE, OPT_compress);
+            fh_fail_s = htio2::SeqIO::New(file_fail_s, htio2::WRITE, OPT_compress);
+        }
+
+        // traverse input files
+        while (fh_in.next_pair(seq1, seq2, PE_STRAND_OBJ))
+            filter_one_pe(seq1, seq2, fh_out_p.get(), fh_out_s.get(), fh_fail_p.get(), fh_fail_s.get());
+    }
+
+    if (!OPT_quiet)
+        cout << "\t" << n_pair << " input, " << n_accept_pair << " accept by pair, " << n_accept_single << " accept by single" << endl;
+}
+
+void execute()
+{
+    if (OPT_se)
+        filter_se();
+    else if (OPT_pe)
+        filter_pe();
+    else
+        throw runtime_error("neither single-end nor paired-end");
+}
diff --git a/src/ht2-lane-tile.cpp b/src/ht2-lane-tile.cpp
new file mode 100644
index 0000000..392c3d5
--- /dev/null
+++ b/src/ht2-lane-tile.cpp
@@ -0,0 +1,163 @@
+#include "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+#include "htio2/HeaderUtil.h"
+
+#define USE_prefix_out
+#define USE_header_format
+#include "htqc/Options.h"
+#include "htqc/App.h"
+
+#include <set>
+
+using namespace std;
+using namespace htqc;
+
+typedef set<int16_t> IntSet;
+typedef vector<int16_t> IntList;
+
+IntList OPT_exclude_lane;
+htio2::Option OPT_exclude_lane_ENTRY("lane", 'L', "Filter Options",
+                                     &OPT_exclude_lane, htio2::Option::FLAG_MULTI_KEY, htio2::ValueLimit::Free(),
+                                     "Unwanted lanes.", "LANE1 [LANE2 ...]");
+
+IntList OPT_exclude_tile;
+htio2::Option OPT_exclude_tile_ENTRY("tile", 'T', "Filter Options",
+                                     &OPT_exclude_tile, htio2::Option::FLAG_MULTI_KEY, htio2::ValueLimit::Free(),
+                                     "Unwanted tiles.", "TILE1 [TILE2 ...]");
+
+string OPT_prefix_reject;
+htio2::Option OPT_prefix_reject_ENTRY("reject", 'u', OPTION_GROUP_IO,
+                                      &OPT_prefix_reject, htio2::Option::FLAG_NONE,
+                                      "File prefix for rejected sequences.", "FILE_PREFIX");
+
+
+void parse_options(int argc, char **argv)
+{
+    htio2::OptionParser opt_psr;
+
+    opt_psr.add_option(OPT_files_in_ENTRY);
+    opt_psr.add_option(OPT_prefix_out_ENTRY);
+    opt_psr.add_option(OPT_prefix_reject_ENTRY);
+
+    opt_psr.add_option(OPT_exclude_lane_ENTRY);
+    opt_psr.add_option(OPT_exclude_tile_ENTRY);
+
+    opt_psr.add_option(OPT_header_format_ENTRY);
+    opt_psr.add_option(OPT_header_sra_ENTRY);
+
+    opt_psr.add_option(OPT_quiet_ENTRY);
+    opt_psr.add_option(OPT_help_ENTRY);
+    opt_psr.add_option(OPT_version_ENTRY);
+
+    opt_psr.parse_options(argc, argv);
+
+    // show help
+    if (OPT_help)
+    {
+        cout << endl
+             << argv[0] << " - filter sequences from specific lane-tile"
+             << endl << endl
+             << opt_psr.format_document();
+        exit(EXIT_SUCCESS);
+    }
+
+    if (OPT_version) show_version_and_exit();
+}
+
+void validate_options()
+{
+    ensure_files_in();
+    ensure_prefix_out();
+    ensure_header_format();
+
+    tidy_prefix_out(OPT_prefix_reject);
+    if (OPT_prefix_out == OPT_prefix_reject)
+    {
+        cerr << "ERROR: conflict output prefix for accepted and rejected reads: " << OPT_prefix_out << endl;
+        exit(EXIT_FAILURE);
+    }
+
+    if (OPT_exclude_tile.size() == 0)
+    {
+        cerr << "ERROR: tiles to exclude not specified" << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+void show_options()
+{
+    show_files_in();
+    show_prefix_out();
+    cout << "# output prefix for rejected sequences: " << OPT_prefix_reject << endl;
+
+    cout << "# exclude lanes: " << endl
+         << "#   ";
+    for (size_t i = 0; i < OPT_exclude_lane.size(); i++)
+    {
+        if (i != 0) cout << ", ";
+        cout << OPT_exclude_lane[i];
+    }
+    cout << endl;
+
+    cout << "# wanted tiles: " << endl
+         << "#   ";
+    for (size_t i = 0; i < OPT_exclude_tile.size(); i++)
+    {
+        if (i != 0) cout << ", ";
+        cout << OPT_exclude_tile[i];
+    }
+    cout << endl;
+}
+
+void execute()
+{
+    string file_out;
+    add_fastq_suffix_se(OPT_prefix_out, OPT_compress, file_out);
+    check_output_overwrite(OPT_files_in, file_out);
+    htio2::FastqIO fh_out(file_out, htio2::WRITE, OPT_compress);
+
+    htio2::FastqIO::Ptr fh_reject;
+    if (OPT_prefix_reject.length())
+    {
+        string file_reject;
+        add_fastq_suffix_se(OPT_prefix_reject, OPT_compress, file_reject);
+        fh_reject = new htio2::FastqIO(file_reject, htio2::WRITE, OPT_compress);
+    }
+
+    IntSet lane_search(OPT_exclude_lane.begin(), OPT_exclude_lane.end());
+    IntSet tile_search(OPT_exclude_tile.begin(), OPT_exclude_tile.end());
+
+    htio2::HeaderParser header_parser(OPT_header_format, OPT_header_sra);
+
+    htio2::FastqSeq seq;
+    size_t n_process = 0;
+    size_t n_accept = 0;
+    for (size_t i_file = 0; i_file < OPT_files_in.size(); i_file++)
+    {
+        htio2::FastqIO fh_in(OPT_files_in[i_file], htio2::READ, OPT_compress);
+
+        while (fh_in.next_seq(seq))
+        {
+            n_process++;
+            header_parser.parse(seq.id, seq.desc);
+
+            if ((lane_search.empty() || lane_search.count(header_parser.lane)) &&
+                     tile_search.count(header_parser.tile))
+            {
+                if (fh_reject)
+                    fh_reject->write_seq(seq);
+            }
+            else
+            {
+                fh_out.write_seq(seq);
+                n_accept++;
+            }
+
+            if (!OPT_quiet and (n_process%LOG_BLOCK == 0))
+                cout << "  " << n_process << " reads, " << n_accept << " accept" << endl;
+        }
+    }
+
+    if (!OPT_quiet)
+        cout << "  " << n_process << " reads, " << n_accept << " accept" << endl;
+}
diff --git a/src/ht2-overlap.cpp b/src/ht2-overlap.cpp
new file mode 100644
index 0000000..b0c5400
--- /dev/null
+++ b/src/ht2-overlap.cpp
@@ -0,0 +1,255 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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 "htio2/FastqIO.h"
+#include "htio2/QualityUtil.h"
+
+#define USE_prefix_out
+#define USE_encode
+#define USE_se_pe
+#define USE_interleave
+#include "htqc/Options.h"
+#include "htqc/MicroAssembler.h"
+#include "htqc/App.h"
+#include "htqc/MultiSeqFile.h"
+
+// we need to process reads in fwd strand
+#define PE_STRAND_FILE OPT_pe_strand1(), OPT_pe_strand2()
+#define PE_STRAND_OBJ htio2::STRAND_FWD, htio2::STRAND_FWD
+
+using namespace std;
+using namespace htqc;
+
+string OPT_prefix_reject;
+htio2::Option OPT_prefix_reject_ENTRY("reject", 'u', OPTION_GROUP_IO,
+                                      &OPT_prefix_reject, htio2::Option::FLAG_NONE,
+                                      "Output file prefix for non-overlapping reads.",
+                                      "FILE_PREFIX");
+
+#define OPTION_GROUP_PARAM "Overlapping Parameters"
+size_t OPT_word_size = 7;
+htio2::Option OPT_word_size_ENTRY("word-size", 'W', OPTION_GROUP_PARAM,
+                                  &OPT_word_size, htio2::Option::FLAG_NONE,
+                                  "Alignment is initiated from identical bases of this length.",
+                                  "INT");
+
+int16_t OPT_conf_qual = 20;
+htio2::Option OPT_conf_qual_ENTRY("quality", 'Q', OPTION_GROUP_PARAM,
+                                  &OPT_conf_qual, htio2::Option::FLAG_NONE,
+                                  "Only the bases whose quality is higher than this are used for kmer generation and identity counting.",
+                                  "INT");
+
+size_t OPT_iden = 10;
+htio2::Option OPT_iden_ENTRY("match", 'M', OPTION_GROUP_PARAM,
+                             &OPT_iden, htio2::Option::FLAG_NONE,
+                             "Number of matched bases required for assembly.",
+                             "INT");
+
+int16_t OPT_qual_diff = 15;
+htio2::Option OPT_qual_diff_ENTRY("quality-diff", 'D', OPTION_GROUP_PARAM,
+                                  &OPT_qual_diff, htio2::Option::FLAG_NONE,
+                                  "Quality difference to accept mismatches.",
+                                  "INT");
+
+void parse_options(int argc, char** argv)
+{
+    // we are always processing PE
+    OPT_pe = true;
+
+    htio2::OptionParser opt_psr;
+
+    opt_psr.add_option(OPT_files_in_ENTRY);
+    opt_psr.add_option(OPT_prefix_out_ENTRY);
+    opt_psr.add_option(OPT_prefix_reject_ENTRY);
+
+    opt_psr.add_option(OPT_pe_itlv_ENTRY);
+    opt_psr.add_option(OPT_pe_strand_ENTRY);
+    opt_psr.add_option(OPT_encode_ENTRY);
+    opt_psr.add_option(OPT_mask_ENTRY);
+
+    opt_psr.add_option(OPT_word_size_ENTRY);
+    opt_psr.add_option(OPT_conf_qual_ENTRY);
+    opt_psr.add_option(OPT_iden_ENTRY);
+    opt_psr.add_option(OPT_qual_diff_ENTRY);
+
+    opt_psr.add_option(OPT_quiet_ENTRY);
+    opt_psr.add_option(OPT_help_ENTRY);
+    opt_psr.add_option(OPT_version_ENTRY);
+
+    opt_psr.parse_options(argc, argv);
+
+    //
+    // show help
+    //
+    if (OPT_help)
+    {
+        cout << endl
+             << argv[0] << " - assemble paired-ends into single sequences"
+             << endl << endl
+             << opt_psr.format_document();
+        exit(EXIT_SUCCESS);
+    }
+    if (OPT_version) show_version_and_exit();
+}
+
+void validate_options()
+{
+    ensure_files_in();
+    ensure_se_pe();
+    ensure_encode();
+    ensure_prefix_out();
+
+    tidy_prefix_out(OPT_prefix_reject);
+}
+
+void show_options()
+{
+    show_files_in();
+    show_prefix_out();
+    if (OPT_prefix_reject.length())
+        cout << "# file prefix for non-assembled reads: " << OPT_prefix_reject << endl;
+    show_encode();
+    cout << "# assembly parameters:" << endl;
+    cout << "#   kmer size: " << OPT_word_size << endl;
+    cout << "#   quality for confidental bases: " << OPT_conf_qual << endl;
+    cout << "#   quality difference for acceptable conflict bases: " << OPT_qual_diff << endl;
+    cout << "#   required number of identical bases: " << OPT_iden << endl;
+}
+
+size_t n_seq = 0;
+size_t n_asm = 0;
+
+void process_one(const htio2::FastqSeq& seq1,
+                 const htio2::FastqSeq& seq2,
+                 htio2::SeqIO& fh_asm,
+                 htio2::PairedEndIO* fh_nasm,
+                 htqc::MicroAssembler& assembler)
+{
+    n_seq++;
+
+    vector<int16_t> qual_a;
+    vector<int16_t> qual_b;
+    htio2::decode_quality(seq1.quality, qual_a, OPT_encode);
+    htio2::decode_quality(seq2.quality, qual_b, OPT_encode);
+
+    htio2::FastqSeq result;
+
+    bool re = assembler.assemble(seq1.seq, qual_a, seq2.seq, qual_b);
+
+    if (re)
+    {
+        result.id = seq1.id;
+        result.desc = assembler.result_desc;
+        result.seq = assembler.result_seq;
+        htio2::encode_quality(assembler.result_qual, result.quality, OPT_encode);
+        fh_asm.write_seq(result);
+        n_asm++;
+    }
+    else if (fh_nasm)
+    {
+        fh_nasm->write_pair(seq1, seq2, PE_STRAND_OBJ);
+    }
+
+    if (!OPT_quiet && n_seq % LOG_BLOCK == 0)
+        cout << "  " << n_seq << " pairs, " << n_asm << " assembled" << endl;
+}
+
+void execute()
+{
+    // output handle
+    string file_out;
+    add_fastq_suffix_se(OPT_prefix_out, OPT_compress, file_out);
+    check_output_overwrite(OPT_files_in, file_out);
+    htio2::SeqIO::Ptr o_merge(htio2::SeqIO::New(file_out, htio2::WRITE, OPT_compress));
+
+    // handle for non-overlap reads
+    htio2::PairedEndIO* o_fail = NULL;
+
+    if (OPT_prefix_reject.length())
+    {
+        if (OPT_pe_itlv)
+        {
+            // generate file name for non-overlap reads
+            string file_u;
+            add_fastq_suffix_se(OPT_prefix_reject, OPT_compress, file_u);
+            check_output_overwrite(OPT_files_in, file_u);
+
+            // create handle
+            o_fail = new htio2::PairedEndIO(file_u,
+                                            htio2::WRITE,
+                                            PE_STRAND_FILE,
+                                            OPT_compress);
+        }
+        else
+        {
+            // generate file name for non-overlap reads
+            string file_u1;
+            string file_u2;
+            add_fastq_suffix_pe(OPT_prefix_reject, OPT_compress, file_u1, file_u2);
+            check_output_overwrite(OPT_files_in, file_u1);
+            check_output_overwrite(OPT_files_in, file_u2);
+
+            // create handle
+            o_fail = new htio2::PairedEndIO(file_u1,
+                                            file_u2,
+                                            htio2::WRITE,
+                                            PE_STRAND_FILE,
+                                            OPT_compress);
+        }
+    }
+
+    // traverse input
+    MicroAssembler assembler(OPT_word_size,
+                             OPT_conf_qual,
+                             OPT_iden,
+                             OPT_qual_diff);
+
+    if (!OPT_quiet)
+        cout << "beginning assembly" << endl;
+
+    htio2::FastqSeq seq1;
+    htio2::FastqSeq seq2;
+
+    if (OPT_pe_itlv)
+    {
+        htqc::MultiSeqFilePE fh_in(OPT_files_in,
+                                    PE_STRAND_FILE,
+                                    OPT_compress);
+
+        while (fh_in.next_pair(seq1, seq2, PE_STRAND_OBJ))
+            process_one(seq1, seq2, *o_merge, o_fail, assembler);
+    }
+    else
+    {
+        vector<string> files_in_a;
+        vector<string> files_in_b;
+        separate_paired_files(OPT_files_in, files_in_a, files_in_b);
+
+        htqc::MultiSeqFilePE fh_in(files_in_a,
+                                    files_in_b,
+                                    PE_STRAND_FILE,
+                                    OPT_compress);
+
+        while (fh_in.next_pair(seq1, seq2, PE_STRAND_OBJ))
+            process_one(seq1, seq2, *o_merge, o_fail, assembler);
+    }
+
+    if (!OPT_quiet)
+        cout << "  " << n_seq << " pairs, " << n_asm << " assembled" << endl;
+
+    if (o_fail)
+        delete o_fail;
+}
diff --git a/src/ht2-primer-trim.cpp b/src/ht2-primer-trim.cpp
new file mode 100644
index 0000000..2a5fcb1
--- /dev/null
+++ b/src/ht2-primer-trim.cpp
@@ -0,0 +1,690 @@
+#include "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+#include "htio2/PairedEndIO.h"
+#include "htio2/Kmer.h"
+#include "htio2/FastaIO.h"
+#include "htio2/QualityUtil.h"
+
+#define USE_se_pe
+#define USE_encode
+#include "htqc/Options.h"
+#include "htqc/App.h"
+#include "htqc/Primer.h"
+#include "htqc/MultiSeqFile.h"
+
+#include "htio2/JUCE-3.0.8/JuceHeader.h"
+
+// we need paired-end reads in fwd-rev style
+#define PE_STRAND_FILE OPT_pe_strand1(), OPT_pe_strand2()
+#define PE_STRAND_OBJ htio2::STRAND_FWD, htio2::STRAND_REV
+
+using namespace std;
+using namespace htqc;
+using namespace htio2::juce;
+
+string OPT_dir_out;
+htio2::Option OPT_dir_out_ENTRY("out", 'o', OPTION_GROUP_IO,
+                                &OPT_dir_out, htio2::Option::FLAG_NONE,
+                                "Output directory.", "DIR");
+
+string OPT_file_primer;
+htio2::Option OPT_file_primer_ENTRY("primer", '\0', OPTION_GROUP_IO,
+                                    &OPT_file_primer, htio2::Option::FLAG_NONE,
+                                    "Primers in FASTA format. IDs of left primers should begin with \"left\", and IDs for right primers should begin with \"right\".",
+                                    "FILE");
+
+#define OPTION_GROUP_ALGO "Primer Trimming Parameters"
+bool OPT_no_revcom;
+htio2::Option OPT_no_revcom_ENTRY("no-revcom", '\0', OPTION_GROUP_ALGO,
+                                  &OPT_no_revcom, htio2::Option::FLAG_NONE,
+                                  "Do not check primers in reverse complement strand.");
+
+bool OPT_no_trim;
+htio2::Option OPT_no_trim_ENTRY("no-trim", '\0', OPTION_GROUP_ALGO,
+                                &OPT_no_trim, htio2::Option::FLAG_NONE,
+                                "Pick primer-containing reads and do not trim primer.");
+
+int OPT_mismatch_high = 3;
+htio2::Option OPT_mismatch_high_ENTRY("mismatch-high", '\0', OPTION_GROUP_ALGO,
+                                      &OPT_mismatch_high, htio2::Option::FLAG_NONE,
+                                      "Allowed number of mismatches on high-quality bases.",
+                                      "INT");
+
+int OPT_mismatch = 6;
+htio2::Option OPT_mismatch_ENTRY("mismatch", '\0', OPTION_GROUP_ALGO,
+                                 &OPT_mismatch, htio2::Option::FLAG_NONE,
+                                 "Allowed number of mismatches.",
+                                 "INT");
+
+int OPT_tail_miss = 5;
+htio2::Option OPT_tail_miss_ENTRY("tail-miss", '\0', OPTION_GROUP_ALGO,
+                                  &OPT_tail_miss, htio2::Option::FLAG_NONE,
+                                  "Allowed length of missing bases on primer 5'-end.",
+                                  "INT");
+
+int OPT_cut_qual = 10;
+htio2::Option OPT_cut_qual_ENTRY("cut-qual", '\0', OPTION_GROUP_ALGO,
+                                 &OPT_cut_qual, htio2::Option::FLAG_NONE,
+                                 "Quality cutoff.",
+                                 "INT");
+
+
+
+// primer data
+typedef map<string, PrimerGroup> AllPrimerType;
+AllPrimerType primers;
+
+void parse_options(int argc, char** argv)
+{
+    htio2::OptionParser opt_psr;
+    opt_psr.add_option(OPT_files_in_ENTRY);
+    opt_psr.add_option(OPT_dir_out_ENTRY);
+    opt_psr.add_option(OPT_file_primer_ENTRY);
+
+    opt_psr.add_option(OPT_se_ENTRY);
+    opt_psr.add_option(OPT_pe_ENTRY);
+    opt_psr.add_option(OPT_pe_itlv_ENTRY);
+    opt_psr.add_option(OPT_pe_strand_ENTRY);
+    opt_psr.add_option(OPT_encode_ENTRY);
+    opt_psr.add_option(OPT_mask_ENTRY);
+
+    opt_psr.add_option(OPT_no_revcom_ENTRY);
+    opt_psr.add_option(OPT_no_trim_ENTRY);
+    opt_psr.add_option(OPT_cut_qual_ENTRY);
+    opt_psr.add_option(OPT_tail_miss_ENTRY);
+    opt_psr.add_option(OPT_mismatch_ENTRY);
+    opt_psr.add_option(OPT_mismatch_high_ENTRY);
+
+    opt_psr.add_option(OPT_quiet_ENTRY);
+    opt_psr.add_option(OPT_help_ENTRY);
+    opt_psr.add_option(OPT_version_ENTRY);
+
+    opt_psr.parse_options(argc, argv);
+
+    // show help
+    if (OPT_help)
+    {
+        cout << endl
+             << argv[0] << " - remove primer sequence from reads"
+             << endl << endl
+             << opt_psr.format_document();
+        exit(EXIT_SUCCESS);
+    }
+
+    if (OPT_version)
+        show_version_and_exit();
+}
+
+void validate_options()
+{
+    ensure_files_in();
+    ensure_se_pe();
+    ensure_encode();
+
+    if (!OPT_dir_out.length())
+    {
+        cerr << "ERROR: output directory not specified!" << endl;
+        exit(EXIT_FAILURE);
+    }
+
+    if (!OPT_file_primer.length())
+    {
+        cerr << "ERROR: primer file not specified!" << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+void show_options()
+{
+    show_se_pe();
+    show_files_in();
+    cout << "# output dir: " << OPT_dir_out << endl;
+    cout << "# primers: " << OPT_file_primer << endl;
+    cout << "# allowed mismatch for high-quality bases: " << OPT_mismatch_high << endl;
+    cout << "# allowed mismatch: " << OPT_mismatch << endl;
+    cout << "# cutoff for low-quality bases: " << OPT_cut_qual << endl;
+    show_encode();
+}
+
+size_t kmer_size = 0;
+
+void read_primers()
+{
+    // first pass
+    // find minimum length
+    size_t min_len = 65535;
+    {
+        htio2::FastaIO IN(OPT_file_primer, htio2::READ);
+        htio2::SimpleSeq seq;
+
+        while (IN.next_seq(seq))
+        {
+            if (seq.seq.length() < min_len)
+                min_len = seq.seq.length();
+        }
+    }
+
+    // calculate kmer size
+    kmer_size = (min_len - OPT_mismatch_high) / (OPT_mismatch_high + 1);
+    if (kmer_size < 4) kmer_size = 4;
+    if (!OPT_quiet) cout << "  shortest primer: " << min_len << ", alignment kmer size: " << kmer_size << endl;
+
+    // read primers
+    htio2::FastaIO IN(OPT_file_primer, htio2::READ);
+    htio2::SimpleSeq seq;
+
+    if (!OPT_quiet)cout << "read primers" << endl;
+    while (IN.next_seq(seq))
+    {
+        if (!seq.desc.length())
+        {
+            cerr << "primer \"" << seq.id << "\" has no description" << endl;
+            exit(EXIT_FAILURE);
+        }
+
+        // find or create the corresponding primer group
+        AllPrimerType::iterator primer_map_i = primers.find(seq.desc);
+        if (primer_map_i == primers.end())
+            primer_map_i = primers.insert(make_pair(seq.desc, PrimerGroup(seq.desc))).first;
+        PrimerGroup& primer_group = primer_map_i->second;
+
+        // add primer to primer group
+        if (seq.id.find("left") == 0)
+            primer_group.primers_left.push_back(Primer(seq.id, seq.seq, kmer_size));
+        else if (seq.id.find("right") == 0)
+            primer_group.primers_right.push_back(Primer(seq.id, seq.seq, kmer_size));
+        else
+        {
+            cerr << "ERROR: primer file has sequence with invalid ID: " << seq.id << endl
+                 << "IDs must begin with \"left\" or \"right\"" << endl;
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    // check primer number
+    if (!OPT_quiet)
+        cout << "  " << primers.size() << " primer groups" << endl;
+
+    for (AllPrimerType::const_iterator i = primers.begin(); i != primers.end(); ++i)
+    {
+        const PrimerGroup& group = i->second;
+
+        if (!group.primers_left.size())
+        {
+            cerr << "ERROR: group " << group.name << " has no left primer" << endl;
+            exit (EXIT_FAILURE);
+        }
+
+        if (!group.primers_right.size())
+        {
+            cerr << "ERROR: group " << group.name << " has no right primer" << endl;
+            exit (EXIT_FAILURE);
+        }
+
+        if (!OPT_quiet)
+            cout << "    " << group.name << " left " << group.primers_left.size() << ", right " << group.primers_right.size() << endl;
+    }
+}
+
+
+
+#define LEFT_START_OK  primer_start <= OPT_tail_miss
+#define LEFT_END_OK primer_end + 1 == curr_primer_len
+#define RIGHT_START_OK  primer_start == 0
+#define RIGHT_END_OK curr_primer_len - primer_end - 1 <= OPT_tail_miss
+
+size_t n_seq = 0;
+size_t n_accept = 0;
+
+void trim_se()
+{
+    // create output file handles
+    map<string, htio2::SeqIO::Ptr> fh_out_map;
+    for (map<string, PrimerGroup>::const_iterator i = primers.begin(); i != primers.end(); i++)
+    {
+        const string& name = i->first;
+        File prefix_out = File(OPT_dir_out).getChildFile(String(name));
+        string file_out;
+        add_fastq_suffix_se(prefix_out.getFullPathName().toStdString(), OPT_compress, file_out);
+        check_output_overwrite(OPT_files_in, file_out);
+
+        htio2::SeqIO::Ptr fh_out(htio2::SeqIO::New(file_out, htio2::WRITE, OPT_compress));
+        fh_out_map.insert(make_pair(name, fh_out));
+    }
+
+    // create file handle for failed ones
+    htio2::SeqIO::Ptr fh_fail(0);
+    {
+        File prefix_fail = File(OPT_dir_out).getChildFile("PRIMER_FAIL");
+        string file_fail;
+        add_fastq_suffix_se(prefix_fail.getFullPathName().toStdString(), OPT_compress, file_fail);
+        check_output_overwrite(OPT_files_in, file_fail);
+        fh_fail = htio2::SeqIO::New(file_fail, htio2::WRITE, OPT_compress);
+    }
+
+    // traverse input
+    htio2::FastqSeq curr_seq;
+    htio2::EncodedSeq curr_enc;
+    KmerList curr_kmer;
+    vector<int16_t> curr_qual;
+
+    htqc::MultiSeqFileSE fh_in(OPT_files_in, OPT_compress);
+
+    while (fh_in.next_seq(curr_seq))
+    {
+        n_seq++;
+
+        // preprocess current read
+        htio2::encode_nt5(curr_seq.seq, curr_enc);
+        htio2::gen_kmer_nt5(curr_enc, curr_kmer, kmer_size);
+        htio2::decode_quality(curr_seq.quality, curr_qual, OPT_encode);
+
+        // traverse primer groups
+        bool matched = false;
+
+        for (AllPrimerType::const_iterator i = primers.begin(); i != primers.end(); i++)
+        {
+            const string& primer_group_name = i->first;
+            const PrimerGroup& primer_group = i->second;
+
+            PosT read_start = 0;
+            PosT read_end = 0;
+            PosT primer_start = 0;
+            PosT primer_end = 0;
+
+            bool left_fwd_ok = false;
+            bool right_fwd_ok = false;
+            bool left_rev_ok = false;
+            bool right_rev_ok = false;
+            PosT trim_fwd_from = 0;
+            PosT trim_fwd_to = 0;
+            PosT trim_rev_from = 0;
+            PosT trim_rev_to = 0;
+
+            //
+            // compare with primers
+            //
+
+            size_t num_left = primer_group.primers_left.size();
+            size_t num_right = primer_group.primers_right.size();
+
+            // left primer
+            for (size_t i = 0; i < num_left; i++)
+            {
+                const size_t curr_primer_len = primer_group.primers_left[i].length();
+                bool aligned = primer_group.primers_left[i].align_fwd(curr_seq.seq, curr_qual, curr_kmer,
+                                                                      OPT_cut_qual, OPT_mismatch_high, OPT_mismatch,
+                                                                      read_start, read_end, primer_start, primer_end);
+                if (aligned && LEFT_START_OK && LEFT_END_OK)
+                {
+                    left_fwd_ok = true;
+                    trim_fwd_from = read_end + 1;
+                    break;
+                }
+            }
+
+            // right primer revcom
+            for (size_t i = 0; i < num_right; i++)
+            {
+                const size_t curr_primer_len = primer_group.primers_right[i].length();
+                bool aligned = primer_group.primers_right[i].align_rev(curr_seq.seq, curr_qual, curr_kmer,
+                                                                       OPT_cut_qual, OPT_mismatch_high, OPT_mismatch,
+                                                                       read_start, read_end, primer_start, primer_end);
+                if (aligned && RIGHT_START_OK && RIGHT_END_OK)
+                {
+                    right_fwd_ok = true;
+                    trim_fwd_to = read_start - 1;
+                    break;
+                }
+            }
+
+            // compare with reverse complement strand
+            if (!OPT_no_revcom)
+            {
+                // right primer
+                for (size_t i = 0; i < num_right; i++)
+                {
+                    const size_t curr_primer_len = primer_group.primers_right[i].length();
+                    bool aligned = primer_group.primers_right[i].align_fwd(curr_seq.seq, curr_qual, curr_kmer,
+                                                                           OPT_cut_qual, OPT_mismatch_high, OPT_mismatch,
+                                                                           read_start, read_end, primer_start, primer_end);
+                    // aligned on left, using left rules
+                    if (aligned && LEFT_START_OK && LEFT_END_OK)
+                    {
+                        right_rev_ok = true;
+                        trim_rev_from = read_end + 1;
+                        break;
+                    }
+                }
+
+                // left primer revcom
+                for (size_t i = 0; i < num_left; i++)
+                {
+                    const size_t curr_primer_len = primer_group.primers_left[i].length();
+                    bool aligned = primer_group.primers_left[i].align_rev(curr_seq.seq, curr_qual, curr_kmer,
+                                                                          OPT_cut_qual, OPT_mismatch_high, OPT_mismatch,
+                                                                          read_start, read_end, primer_start, primer_end);
+                    // aligned on right, using right rules
+                    if (aligned && RIGHT_START_OK && RIGHT_END_OK)
+                    {
+                        left_rev_ok = true;
+                        trim_rev_to = read_start - 1;
+                        break;
+                    }
+                }
+            }
+
+            // write output
+            if ((!num_left || left_fwd_ok) && (!num_right || right_fwd_ok))
+            {
+                n_accept++;
+                matched = true;
+                if (OPT_no_trim)
+                {
+                    fh_out_map[primer_group_name]->write_seq(curr_seq);
+                }
+                else
+                {
+                    htio2::FastqSeq trimmed_seq;
+                    curr_seq.subseq(trimmed_seq, trim_fwd_from, trim_fwd_to - trim_fwd_from + 1);
+                    fh_out_map[primer_group_name]->write_seq(trimmed_seq);
+                }
+            }
+            else if ((!num_left || left_rev_ok) && (!num_right || right_rev_ok))
+            {
+                n_accept++;
+                matched = true;
+                if (OPT_no_trim)
+                {
+                    fh_out_map[primer_group_name]->write_seq(curr_seq);
+                }
+                else
+                {
+                    htio2::FastqSeq trimmed_seq;
+                    curr_seq.subseq(trimmed_seq, trim_rev_from, trim_rev_to - trim_rev_from + 1);
+                    fh_out_map[primer_group_name]->write_seq(trimmed_seq);
+                }
+            }
+
+            if (matched) break;
+        } // primer group cycle
+
+        if (!matched)
+            fh_fail->write_seq(curr_seq);
+
+        if (!OPT_quiet && n_seq % LOG_BLOCK == 0)
+            cout << "  " << n_seq << " reads, " << n_accept << " trimmed" << endl;
+    } // sequence cycle
+
+
+    if (!OPT_quiet)
+        cout << "done: " << n_seq << " reads, " << n_accept << " trimmed" << endl;
+}
+
+void do_one_pe(const htio2::FastqSeq& seq1,
+               const htio2::FastqSeq& seq2,
+               map<string, htio2::PairedEndIO::Ptr>& fh_out,
+               htio2::PairedEndIO* fh_fail)
+{
+    n_seq++;
+
+    static htio2::EncodedSeq enc1;
+    static htio2::EncodedSeq enc2;
+    static KmerList klist1;
+    static KmerList klist2;
+    static vector<int16_t> qlist1;
+    static vector<int16_t> qlist2;
+
+    PosT read_start = 0;
+    PosT read_end = 0;
+    PosT primer_start = 0;
+    PosT primer_end = 0;
+
+    bool left_fwd_ok = false;
+    bool right_fwd_ok = false;
+    bool left_rev_ok = false;
+    bool right_rev_ok = false;
+    PosT trim_fwd_r1 = 0;
+    PosT trim_fwd_r2 = 0;
+    PosT trim_rev_r1 = 0;
+    PosT trim_rev_r2 = 0;
+
+    // preprocess current read
+    htio2::encode_nt5(seq1.seq, enc1);
+    htio2::encode_nt5(seq2.seq, enc2);
+    htio2::gen_kmer_nt5(enc1, klist1, kmer_size);
+    htio2::gen_kmer_nt5(enc2, klist2, kmer_size);
+    htio2::decode_quality(seq1.quality, qlist1, OPT_encode);
+    htio2::decode_quality(seq2.quality, qlist2, OPT_encode);
+
+    // traverse primer groups
+    bool matched = false;
+    for (AllPrimerType::const_iterator i = primers.begin(); i != primers.end(); i++)
+    {
+        const string& primer_group_name = i->first;
+        const PrimerGroup& primer_group = i->second;
+
+        size_t n_primer_left = primer_group.primers_left.size();
+        size_t n_primer_right = primer_group.primers_right.size();
+
+        // left on read 1
+        for (size_t i = 0; i < n_primer_left; i++)
+        {
+            const size_t curr_primer_len = primer_group.primers_left[i].length();
+            bool aligned = primer_group.primers_left[i].align_fwd(seq1.seq, qlist1, klist1,
+                                                                  OPT_cut_qual, OPT_mismatch_high, OPT_mismatch,
+                                                                  read_start, read_end, primer_start, primer_end);
+
+            if (aligned && LEFT_START_OK && LEFT_END_OK)
+            {
+                left_fwd_ok = true;
+                trim_fwd_r1 = read_end + 1;
+                break;
+            }
+        }
+
+        // right on read 2
+        for (size_t i = 0; i < n_primer_right; i++)
+        {
+            const size_t curr_primer_len = primer_group.primers_right[i].length();
+            bool aligned = primer_group.primers_right[i].align_fwd(seq2.seq, qlist2, klist2,
+                                                                   OPT_cut_qual, OPT_mismatch_high, OPT_mismatch,
+                                                                   read_start, read_end, primer_start, primer_end);
+            if (aligned && LEFT_START_OK && LEFT_END_OK)
+            {
+                right_fwd_ok = true;
+                trim_fwd_r2 = read_end + 1;
+                break;
+            }
+        }
+
+        // revcom
+        if (!OPT_no_revcom)
+        {
+            // align right revcom on read 1
+            for (size_t i = 0; i < n_primer_right; i++)
+            {
+                const size_t curr_primer_len = primer_group.primers_right[i].length();
+                bool aligned = primer_group.primers_right[i].align_rev(seq1.seq, qlist1, klist1,
+                                                                       OPT_cut_qual, OPT_mismatch_high, OPT_mismatch,
+                                                                       read_start, read_end, primer_start, primer_end);
+                if (aligned && LEFT_START_OK && LEFT_END_OK)
+                {
+                    right_rev_ok = true;
+                    trim_rev_r1 = read_end + 1;
+                    break;
+                }
+            }
+
+            // align left revcom on read 2
+            for (size_t i = 0; i < n_primer_left; i++)
+            {
+                const size_t curr_primer_len = primer_group.primers_left[i].length();
+                bool aligned = primer_group.primers_left[i].align_rev(seq2.seq, qlist2, klist2,
+                                                                      OPT_cut_qual, OPT_mismatch_high, OPT_mismatch,
+                                                                      read_start, read_end, primer_start, primer_end);
+                if (aligned && LEFT_START_OK && LEFT_END_OK)
+                {
+                    left_rev_ok = true;
+                    trim_rev_r2 = read_end + 1;
+                    break;
+                }
+            }
+
+        }
+
+        // fwd ok
+        if ((!n_primer_left || left_fwd_ok)
+                &&
+                (!n_primer_right || right_fwd_ok))
+        {
+            n_accept++;
+            matched = true;
+            if (OPT_no_trim)
+            {
+                fh_out[primer_group_name]->write_pair(seq1, seq2, PE_STRAND_OBJ);
+            }
+            else
+            {
+                htio2::FastqSeq trimmed1;
+                htio2::FastqSeq trimmed2;
+                seq1.subseq(trimmed1, trim_fwd_r1);
+                seq2.subseq(trimmed2, trim_fwd_r2);
+                fh_out[primer_group_name]->write_pair(trimmed1, trimmed2, PE_STRAND_OBJ);
+            }
+        }
+        // revcom ok
+        else if ((!n_primer_left || left_rev_ok)
+                 &&
+                 (!n_primer_right || right_rev_ok))
+        {
+            n_accept++;
+            matched = true;
+            if (OPT_no_trim)
+            {
+                fh_out[primer_group_name]->write_pair(seq1, seq2, PE_STRAND_OBJ);
+            }
+            else
+            {
+                htio2::FastqSeq trimmed1;
+                htio2::FastqSeq trimmed2;
+                seq1.subseq(trimmed1, trim_rev_r1);
+                seq2.subseq(trimmed2, trim_rev_r2);
+                fh_out[primer_group_name]->write_pair(trimmed1, trimmed2, PE_STRAND_OBJ);
+            }
+        }
+
+        if (matched)
+            break;
+    }
+
+    if (!matched)
+        fh_fail->write_pair(seq1, seq2);
+
+    if (!OPT_quiet && n_seq % LOG_BLOCK == 0)
+        cout << "  " << n_seq << " pairs, " << n_accept << " trimmed" << endl;
+}
+
+void trim_pe()
+{
+    htio2::FastqSeq seq1;
+    htio2::FastqSeq seq2;
+
+    // output handles
+    map<string, htio2::PairedEndIO::Ptr> fh_out_map;
+    for (map<string, PrimerGroup>::const_iterator i = primers.begin(); i != primers.end(); i++)
+    {
+        const string& name = i->first;
+        File prefix_out = File(OPT_dir_out).getChildFile(String(name));
+
+        if (OPT_pe_itlv)
+        {
+            string file_out;
+            add_fastq_suffix_se(prefix_out.getFullPathName().toStdString(), OPT_compress, file_out);
+            check_output_overwrite(OPT_files_in, file_out);
+
+            htio2::PairedEndIO::Ptr fh(new htio2::PairedEndIO(file_out, htio2::WRITE, PE_STRAND_FILE, OPT_compress));
+            fh_out_map.insert(make_pair(name, fh));
+        }
+        else
+        {
+            string file_out1;
+            string file_out2;
+            add_fastq_suffix_pe(prefix_out.getFullPathName().toStdString(), OPT_compress, file_out1, file_out2);
+            check_output_overwrite(OPT_files_in, file_out1);
+            check_output_overwrite(OPT_files_in, file_out2);
+
+            htio2::PairedEndIO::Ptr fh(new htio2::PairedEndIO(file_out1, file_out2, htio2::WRITE, PE_STRAND_FILE, OPT_compress));
+            fh_out_map.insert(make_pair(name, fh));
+        }
+    }
+
+    // handle for negative reads
+    htio2::PairedEndIO::Ptr fh_fail;
+    {
+        File prefix_fail = File(OPT_dir_out).getChildFile("PRIMER_FAIL");
+        if (OPT_pe_itlv)
+        {
+            string file_fail;
+            add_fastq_suffix_se(prefix_fail.getFullPathName().toStdString(), OPT_compress, file_fail);
+            check_output_overwrite(OPT_files_in, file_fail);
+            fh_fail = new htio2::PairedEndIO(file_fail, htio2::WRITE, PE_STRAND_FILE, OPT_compress);
+        }
+        else
+        {
+            string file_fail1;
+            string file_fail2;
+            add_fastq_suffix_pe(prefix_fail.getFullPathName().toStdString(), OPT_compress, file_fail1, file_fail2);
+            check_output_overwrite(OPT_files_in, file_fail1);
+            check_output_overwrite(OPT_files_in, file_fail2);
+
+            fh_fail = new htio2::PairedEndIO(file_fail1, file_fail2, htio2::WRITE, PE_STRAND_FILE, OPT_compress);
+        }
+    }
+
+    // input handle
+    htqc::MultiSeqFilePE* fh_in;
+    if (OPT_pe_itlv)
+    {
+        fh_in = new htqc::MultiSeqFilePE(OPT_files_in, PE_STRAND_FILE, OPT_compress);
+    }
+    else
+    {
+        vector<string> files_in_a;
+        vector<string> files_in_b;
+        separate_paired_files(OPT_files_in, files_in_a, files_in_b);
+        fh_in = new htqc::MultiSeqFilePE(files_in_a, files_in_b, PE_STRAND_FILE, OPT_compress);
+    }
+
+    // traverse input file pairs
+    while (fh_in->next_pair(seq1, seq2, PE_STRAND_OBJ))
+        do_one_pe(seq1, seq2, fh_out_map, fh_fail.get());
+
+    delete fh_in;
+
+    if (!OPT_quiet)
+        cout << "done: " << n_seq << " pairs, " << n_accept << " trimmed" << endl;
+}
+
+void execute()
+{
+    read_primers();
+
+    File dir_out_obj(OPT_dir_out);
+    if (!dir_out_obj.isDirectory())
+    {
+        Result re = dir_out_obj.createDirectory();
+        if (re.failed())
+        {
+            fprintf(stderr, "ERROR: failed to create output directory \"%s\": %s\n",
+                    OPT_dir_out.c_str(), re.getErrorMessage().toRawUTF8());
+        }
+    }
+
+    if (OPT_se)
+        trim_se();
+    else if (OPT_pe)
+        trim_pe();
+    else
+        throw runtime_error("neither single-end nor paired-end");
+}
diff --git a/src/ht2-rename.cpp b/src/ht2-rename.cpp
new file mode 100644
index 0000000..c5b6606
--- /dev/null
+++ b/src/ht2-rename.cpp
@@ -0,0 +1,114 @@
+#include "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+
+#define USE_prefix_out
+#define USE_se_pe
+#include "htqc/Options.h"
+#include "htqc/App.h"
+#include "htqc/MultiSeqFile.h"
+
+#include <sstream>
+
+using namespace std;
+using namespace htqc;
+
+#define OPTION_GROUP_NAMING "Naming Options"
+
+string OPT_name_prefix;
+htio2::Option OPT_name_prefix_ENTRY("prefix", '\0', OPTION_GROUP_NAMING,
+                                    &OPT_name_prefix, htio2::Option::FLAG_NONE,
+                                    "Prefix for generated IDs.", "STRING");
+
+string OPT_name_suffix;
+htio2::Option OPT_name_suffix_ENTRY("suffix", '\0', OPTION_GROUP_NAMING,
+                                    &OPT_name_suffix, htio2::Option::FLAG_NONE,
+                                    "Suffix for generated IDs.", "STRING");
+
+bool keep_desc;
+htio2::Option OPT_keep_desc_ENTRY("keep-desc", '\0', OPTION_GROUP_NAMING,
+                                  &keep_desc, htio2::Option::FLAG_NONE,
+                                  "Keep description of the input sequences, which is the header content after first continuous blank.");
+
+void parse_options(int argc, char** argv)
+{
+    OPT_se = true;
+
+    htio2::OptionParser opt_psr;
+    opt_psr.add_option(OPT_files_in_ENTRY);
+    opt_psr.add_option(OPT_prefix_out_ENTRY);
+
+    opt_psr.add_option(OPT_name_prefix_ENTRY);
+    opt_psr.add_option(OPT_name_suffix_ENTRY);
+    opt_psr.add_option(OPT_keep_desc_ENTRY);
+
+    opt_psr.add_option(OPT_quiet_ENTRY);
+    opt_psr.add_option(OPT_help_ENTRY);
+    opt_psr.add_option(OPT_version_ENTRY);
+
+    opt_psr.parse_options(argc, argv);
+
+    //
+    // show help
+    //
+    if (OPT_help)
+    {
+        cout << endl
+            << argv[0] << " - generate simple sequence IDs by batch"
+            << endl << endl
+            << opt_psr.format_document();
+        exit(EXIT_SUCCESS);
+    }
+
+    if (OPT_version) show_version_and_exit();
+}
+
+void validate_options()
+{
+    ensure_files_in();
+    ensure_prefix_out();
+
+    if (OPT_name_prefix.length() == 0 && OPT_name_suffix.length() == 0)
+        cerr << "WARNING: neither prefix nor suffix was provided!" << endl;
+}
+
+void show_options()
+{
+    show_files_in();
+    show_prefix_out();
+    cout << "# ID format: " << OPT_name_prefix << "(NUMBER)" << OPT_name_suffix;
+    if (keep_desc) cout << " DESCRIPTION";
+    cout << endl;
+}
+
+void execute()
+{
+    // output handle
+    string file_out;
+    add_fastq_suffix_se(OPT_prefix_out, OPT_compress, file_out);
+    check_output_overwrite(OPT_files_in, file_out);
+    htio2::SeqIO::Ptr fh_out(htio2::SeqIO::New(file_out, htio2::WRITE, OPT_compress));
+
+    // traverse input files
+    if (!OPT_quiet) cout << "process sequences" << endl;
+    size_t num_seq = 0;
+    htio2::FastqSeq curr_seq;
+    htqc::MultiSeqFileSE fh_in(OPT_files_in, OPT_compress);
+
+    while (fh_in.next_seq(curr_seq))
+    {
+        num_seq++;
+        if (!OPT_quiet && num_seq % LOG_BLOCK == 0)
+            cout << "    " << num_seq << " sequences processed" << endl;
+
+        ostringstream id_new;
+        id_new << OPT_name_prefix << num_seq << OPT_name_suffix;
+
+        curr_seq.id = id_new.str();
+        if (!keep_desc)
+            curr_seq.desc = "";
+
+        fh_out->write_seq(curr_seq);
+    }
+
+    if (!OPT_quiet) cout << "  " << num_seq << " sequences processed" << endl;
+}
diff --git a/src/ht2-sample.cpp b/src/ht2-sample.cpp
new file mode 100644
index 0000000..7a48eff
--- /dev/null
+++ b/src/ht2-sample.cpp
@@ -0,0 +1,404 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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 "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+#include "htio2/PairedEndIO.h"
+
+#define USE_prefix_out
+#define USE_se_pe
+#define USE_interleave
+#include "htqc/Options.h"
+#include "htqc/App.h"
+#include "htqc/MultiSeqFile.h"
+#include "htio2/MT19937.h"
+
+#include <set>
+#include <iostream>
+#include <fstream>
+
+// We don't care strand in this program, so simply let FILE and OBJ to be identical.
+#define PE_STRAND_FILE htio2::STRAND_FWD, htio2::STRAND_FWD
+#define PE_STRAND_OBJ  htio2::STRAND_FWD, htio2::STRAND_FWD
+
+using namespace std;
+using namespace htqc;
+using namespace htio2::juce;
+
+#define OPTION_GROUP_SAMPLING "Sampling Parameters"
+
+double OPT_rate = 0;
+htio2::Option OPT_rate_ENTRY("rate", 'r', OPTION_GROUP_SAMPLING,
+                             &OPT_rate, htio2::Option::FLAG_NONE,
+                             "1/rate of total reads will be picked.", "NUMBER");
+
+size_t OPT_num = 0;
+htio2::Option OPT_num_ENTRY("num", 'n', OPTION_GROUP_SAMPLING,
+                            &OPT_num, htio2::Option::FLAG_NONE,
+                            "Number of reads to be picked.", "INT");
+
+int64_t OPT_seed = 0;
+htio2::Option OPT_seed_ENTRY("seed", '\0', OPTION_GROUP_SAMPLING,
+                             &OPT_seed, htio2::Option::FLAG_NONE,
+                             "Seed for random number generator. 0 to use system-random seed.", "INT");
+
+string OPT_file_out_id;
+htio2::Option OPT_file_out_id_ENTRY("out-id", '\0', OPTION_GROUP_IO,
+                                    &OPT_file_out_id, htio2::Option::FLAG_NONE,
+                                    "Write the indices of picked reads to a file. The indices are 0-based.", "FILE");
+
+
+
+void parse_options(int argc, char** argv)
+{
+    htio2::OptionParser opt_psr;
+
+    opt_psr.add_option(OPT_files_in_ENTRY);
+    opt_psr.add_option(OPT_prefix_out_ENTRY);
+    opt_psr.add_option(OPT_file_out_id_ENTRY);
+
+    opt_psr.add_option(OPT_se_ENTRY);
+    opt_psr.add_option(OPT_pe_ENTRY);
+    opt_psr.add_option(OPT_pe_itlv_ENTRY);
+
+    opt_psr.add_option(OPT_rate_ENTRY);
+    opt_psr.add_option(OPT_num_ENTRY);
+    opt_psr.add_option(OPT_seed_ENTRY);
+
+    opt_psr.add_option(OPT_quiet_ENTRY);
+    opt_psr.add_option(OPT_help_ENTRY);
+    opt_psr.add_option(OPT_version_ENTRY);
+
+    opt_psr.parse_options(argc, argv);
+
+    //
+    // show help
+    //
+    if (OPT_help)
+    {
+        cout << endl
+             << argv[0] << " - randomly pick some reads"
+             << endl << endl
+             << opt_psr.format_document();
+        exit(EXIT_SUCCESS);
+    }
+
+    if (OPT_version) show_version_and_exit();
+}
+
+void validate_options()
+{
+    ensure_files_in();
+    ensure_se_pe();
+    ensure_prefix_out();
+
+    if (OPT_rate == 0)
+    {
+        if (OPT_num == 0)
+        {
+            cerr << "ERROR: neither sampling rate nor sampling amount is specified." << endl
+                 << "ERROR: you must specify how much to be sampled." << endl;
+            exit(EXIT_FAILURE);
+        }
+    }
+    else
+    {
+        if (OPT_num)
+        {
+            cerr << "ERROR: both sampling rate and sampling amount is specified." << endl
+                 << "ERROR: you must specify only one of them." << endl;
+            exit(EXIT_FAILURE);
+        }
+        if (OPT_rate <= 1)
+        {
+            cerr << "ERROR: invalid sampling rate: " << OPT_rate << endl
+                 << "ERROR: sampling rate must larger than 1" << endl;
+            exit(EXIT_FAILURE);
+        }
+    }
+}
+
+void show_options()
+{
+    show_se_pe();
+    show_files_in();
+    show_prefix_out();
+    if (OPT_file_out_id.size())
+        cout << "# output file for used indices: " << OPT_file_out_id << endl;
+
+    if (OPT_rate > 0)
+        cout << "# fraction to be picked: 1/" << OPT_rate << endl;
+    if (OPT_num > 0)
+        cout << "# amount to be picked: " << OPT_num << endl;
+    if (OPT_seed)
+        cout << "# user random seed: " << OPT_seed << endl;
+}
+
+int64_t n_accept = 0;
+int64_t n_input = 0;
+
+int64_t count_se()
+{
+    htqc::MultiSeqFileSE fh_in(OPT_files_in, OPT_compress);
+    htio2::FastqSeq seq;
+    int64_t n = 0;
+
+    while (fh_in.next_seq(seq))
+        n++;
+
+    if (n < 0)
+    {
+        fprintf(stderr, "ERROR: sequence amount overflow!\n");
+        exit(EXIT_FAILURE);
+    }
+    return n;
+}
+
+int64_t count_pe()
+{
+    htqc::MultiSeqFilePE* fh = nullptr;
+    if (OPT_pe_itlv)
+    {
+        fh = new htqc::MultiSeqFilePE(OPT_files_in,
+                                      PE_STRAND_FILE,
+                                      OPT_compress);
+    }
+    else
+    {
+        vector<string> files_in_a;
+        vector<string> files_in_b;
+        separate_paired_files(OPT_files_in, files_in_a, files_in_b);
+        fh = new htqc::MultiSeqFilePE(files_in_a,
+                                      files_in_b,
+                                      PE_STRAND_FILE,
+                                      OPT_compress);
+    }
+
+    htio2::FastqSeq seq1;
+    htio2::FastqSeq seq2;
+    int64_t n = 0;
+
+    while (fh->next_pair(seq1, seq2, PE_STRAND_OBJ))
+        n++;
+
+    if (n < 0)
+    {
+        fprintf(stderr, "ERROR: sequence amount overflow!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    delete fh;
+    return n;
+}
+
+
+
+void shuffle_vector(vector<int64_t>& data, htio2::MT19937& prng)
+{
+    for (size_t i1 = 0; i1 < data.size(); i1++)
+    {
+        uint64_t i2 = prng.next_uint64_in_range(data.size());
+        printf("  switch %lu %lu\n", i1, i2);
+        int64_t tmp = data[i1];
+        data[i1] = data[i2];
+        data[i2] = tmp;
+    }
+}
+
+void rand_pick(int64_t num, set<int64_t>& wanted, htio2::MT19937& prng)
+{
+    vector<int64_t> indices(num);
+    for (int64_t i = 0; i < num; i++)
+        indices[i] = i;
+
+    // shuffle
+    shuffle_vector(indices, prng);
+
+    // do pick
+    size_t n_pick = 0;
+    if (OPT_num)
+        n_pick = OPT_num;
+    else
+        n_pick = indices.size() / OPT_rate;
+
+    for (int i = 0; i < n_pick; i++)
+    {
+        if (!wanted.insert(indices[i]).second)
+            abort();
+    }
+}
+
+void filter_se(const set<int64_t>& wanted)
+{
+    // output handle
+    string file_out;
+    add_fastq_suffix_se(OPT_prefix_out, OPT_compress, file_out);
+    check_output_overwrite(OPT_files_in, file_out);
+
+    htio2::SeqIO::Ptr OUT(htio2::SeqIO::New(file_out,
+                                          htio2::WRITE,
+                                          OPT_compress));
+
+    // input handle
+    htqc::MultiSeqFileSE fh_in(OPT_files_in, OPT_compress);
+
+    // traverse input sequences
+    htio2::FastqSeq curr_seq;
+    int64_t id = 0;
+
+    while (fh_in.next_seq(curr_seq))
+    {
+        n_input++;
+
+        if (wanted.count(id++))
+        {
+            OUT->write_seq(curr_seq);
+            n_accept++;
+        }
+
+        if (!OPT_quiet && (n_input % LOG_BLOCK == 0))
+            cout << "\t" << n_input << " reads, " << n_accept << " accept" << endl;
+    }
+
+
+
+    if (!OPT_quiet)
+        cout << "  " << n_input << " reads, " << n_accept << " accept" << endl;
+}
+
+void filter_pe(const set<int64_t>& wanted)
+{
+    htio2::PairedEndIO* fh_out = NULL;
+    htqc::MultiSeqFilePE* fh_in = NULL;
+
+    if (OPT_pe_itlv)
+    {
+        string file_out;
+        add_fastq_suffix_se(OPT_prefix_out, OPT_compress, file_out);
+        check_output_overwrite(OPT_files_in, file_out);
+
+        fh_out = new htio2::PairedEndIO(file_out,
+                                        htio2::WRITE,
+                                        PE_STRAND_FILE,
+                                        OPT_compress);
+
+        fh_in = new htqc::MultiSeqFilePE(OPT_files_in,
+                                         PE_STRAND_FILE,
+                                         OPT_compress);
+    }
+    else
+    {
+        string file_out_a;
+        string file_out_b;
+        add_fastq_suffix_pe(OPT_prefix_out, OPT_compress, file_out_a, file_out_b);
+        check_output_overwrite(OPT_files_in, file_out_a);
+        check_output_overwrite(OPT_files_in, file_out_b);
+
+        fh_out = new htio2::PairedEndIO(file_out_a,
+                                        file_out_b,
+                                        htio2::WRITE,
+                                        PE_STRAND_FILE,
+                                        OPT_compress);
+
+        vector<string> files_in_a;
+        vector<string> files_in_b;
+        separate_paired_files(OPT_files_in, files_in_a, files_in_b);
+
+        fh_in = new htqc::MultiSeqFilePE(files_in_a,
+                                          files_in_b,
+                                          PE_STRAND_FILE,
+                                          OPT_compress);
+    }
+
+    // traverse sequences
+    htio2::FastqSeq curr_seq_a;
+    htio2::FastqSeq curr_seq_b;
+    int64_t id = 0;
+
+    while (fh_in->next_pair(curr_seq_a, curr_seq_b, PE_STRAND_OBJ))
+    {
+        n_input++;
+
+        if (wanted.count(id++))
+        {
+            fh_out->write_pair(curr_seq_a, curr_seq_b, PE_STRAND_OBJ);
+            n_accept++;
+        }
+
+        if (!OPT_quiet && (n_input % LOG_BLOCK == 0))
+            cout << "\t" << n_input << " pairs, " << n_accept << " picked" << endl;
+    }
+
+    delete fh_in;
+    delete fh_out;
+
+    if (!OPT_quiet)
+        cout << "  " << n_input << " pairs, " << n_accept << " picked" << endl;
+}
+
+void execute()
+{
+    // init PRNG
+    htio2::MT19937 prng;
+    if (OPT_seed != 0)
+        prng.set_seed(OPT_seed);
+
+    // first pass
+    // get sequence num
+    if (!OPT_quiet)
+        printf("count input sequences\n");
+
+    int64_t num = 0;
+    if (OPT_se)
+        num = count_se();
+    else if (OPT_pe)
+        num = count_pe();
+    else
+        abort();
+
+    if (!OPT_quiet)
+        printf("  %ld total\n", num);
+
+    // generate a table of wanted indices
+    if (!OPT_quiet)
+        printf("randomly generate wanted index table\n");
+    set<int64_t> wanted;
+    rand_pick(num, wanted, prng);
+
+    if (!OPT_quiet)
+        printf("  %lu indices\n", wanted.size());
+
+    // second pass
+    // pick wanted sequences
+    if (OPT_se)
+        filter_se(wanted);
+    else if (OPT_pe)
+        filter_pe(wanted);
+    else
+        abort();
+
+    // write a list of used indices
+    if (OPT_file_out_id.length())
+    {
+        if (!OPT_quiet)
+            printf("write used indices to file \"%s\"\n", OPT_file_out_id.c_str());
+
+        ofstream fh_out_id(OPT_file_out_id.c_str());
+        for (int64_t id : wanted)
+        {
+            fh_out_id << id << endl;
+        }
+    }
+}
diff --git a/src/ht2-stat-draw.pl b/src/ht2-stat-draw.pl
new file mode 100755
index 0000000..c706d15
--- /dev/null
+++ b/src/ht2-stat-draw.pl
@@ -0,0 +1,520 @@
+#!/usr/bin/perl
+
+#     HTQC - a high-throughput sequencing quality control toolkit
+#
+#     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.
+#
+#     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/>.
+
+use strict;
+use warnings;
+use File::Path;
+use File::Spec::Functions;
+use Chart::Clicker;
+use Getopt::Long;
+
+# output file name base
+my $CYC_QUAL_1       = 'cycle_quality_1';
+my $CYC_QUAL_2       = 'cycle_quality_2';
+my $CYC_QUAL_1_BOX   = 'cycle_quality_1.box';
+my $CYC_QUAL_2_BOX   = 'cycle_quality_2.box';
+my $READS_QUAL       = 'reads_quality';
+my $LANE_TILE_QUAL_1 = 'lane_tile_quality_1';
+my $LANE_TILE_QUAL_2 = 'lane_tile_quality_2';
+my $CYC_COMP_1       = 'cycle_composition_1';
+my $CYC_COMP_2       = 'cycle_composition_2';
+my $UMASK_LEN        = 'reads_length';
+my $QUAL_QQ          = 'quality_QQ';
+
+my $dir_data;
+my $WIDTH    = 600;
+my $HEIGHT   = 400;
+my $SZ_TITLE = 12;
+my $SZ_TEXT  = 9;
+my $FORMAT   = 'pdf';
+
+GetOptions(
+    'dir=s'        => \$dir_data,
+    'format=s'     => \$FORMAT,
+    'width=s'      => \$WIDTH,
+    'height=s'     => \$HEIGHT,
+    'title-size=s' => \$SZ_TITLE,
+    'text-size=s'  => \$SZ_TEXT,
+    'help'         => \&show_help
+);
+
+#
+# validate dir
+#
+die "data directory not specified" if !defined $dir_data;
+die "data directory not exist" if !-d $dir_data;
+
+my $file_info = catfile $dir_data, 'info.tab';
+die "info file not exist" if !-f $file_info;
+
+#
+# get info
+#
+open INFO, '<', $file_info or die "failed to open info file '$file_info': $!";
+my $PAIRED;
+my $LENGTH;
+my $QUAL_FROM;
+my $QUAL_TO;
+my $MASK;
+
+while (<INFO>) {
+    chomp;
+    my ( $key, $value ) = split /\t/;
+    if ( $key eq 'paired' ) {
+        $PAIRED = $value eq 'T' ? 1 : 0;
+    }
+    elsif ( $key eq 'length' ) {
+        $LENGTH = $value;
+    }
+    elsif ( $key eq 'quality range' ) {
+        $value =~ /^(\d+)-(\d+)$/
+          or die "failed to parse quality range: '$value'";
+        $QUAL_FROM = $1;
+        $QUAL_TO   = $2;
+    }
+    elsif ( $key eq 'mask' ) {
+        $MASK = $value eq 'T' ? 1 : 0;
+    }
+}
+
+close INFO;
+
+#
+# test the existence of gnuplot
+#
+my $HAS_GNUPLOT = 1;
+`gnuplot -V`;
+if ( $? != 0 ) {
+    print STDERR <<INFO_GNUPLOT_NOTFOUND;
+Gnuplot is not found in your system. Plot scripts are generated but are not
+rendered.
+Please install Gnuplot using the package management system of your Unix
+distribution, or visit Gnuplot website: http://sourceforge.net/projects/gnuplot
+INFO_GNUPLOT_NOTFOUND
+    $HAS_GNUPLOT = 0;
+}
+
+#
+# write gnuplot scripts
+#
+plot_cycle_quality_heatmap( $CYC_QUAL_1, 1 );
+plot_cycle_quality_heatmap( $CYC_QUAL_2, 2 ) if $PAIRED;
+
+plot_cycle_quality_box( $CYC_QUAL_1_BOX, 1 );
+plot_cycle_quality_box( $CYC_QUAL_2_BOX, 2 ) if $PAIRED;
+
+plot_reads_quality($READS_QUAL);
+
+plot_lane_tile_quality( $LANE_TILE_QUAL_1, 1 );
+plot_lane_tile_quality( $LANE_TILE_QUAL_2, 2 ) if $PAIRED;
+
+plot_cycle_composition( $CYC_COMP_1, 1 );
+plot_cycle_composition( $CYC_COMP_2, 2 ) if $PAIRED;
+
+plot_reads_length($UMASK_LEN);
+
+plot_quality_qq($QUAL_QQ) if $PAIRED;
+
+#
+# subs
+#
+
+# gnuplot scripts
+sub plot_cycle_quality_heatmap {
+    my $base = shift;
+    my $side = shift;
+
+    my $file_tab   = catfile $dir_data, $base . '.tab';
+    my $file_plot  = catfile $dir_data, $base . '.gnuplot';
+    my $file_chart = catfile $dir_data, $base . '.' . $FORMAT;
+    my $file_dat   = catfile $dir_data, $base . '.dat';
+
+    # read table
+    # write data file for gnuplot
+    open my $h_tab, '<', $file_tab
+      or die "failed to open '$file_tab' for read: $!";
+    open my $h_dat, '>', $file_dat
+      or die "failed to open '$file_dat' for write: $!";
+
+    my @qual_list;
+
+    my $line = 0;
+    while (<$h_tab>) {
+        chomp;
+        if ( $line == 0 ) {
+            ( undef, @qual_list ) = split /\t/;
+        }
+        else {
+            my ( $cyc, @values ) = split /\t/;
+            for ( my $i = 0 ; $i < @values ; $i++ ) {
+                print $h_dat join( "\t", $cyc, $qual_list[$i], $values[$i] ),
+                  "\n";
+            }
+        }
+    }
+    continue { $line++ }
+
+    close $h_tab;
+    close $h_dat;
+
+    # write script
+    my $x_min = -0.5;
+    my $x_max = $LENGTH + 0.5;
+    my $y_min = $QUAL_FROM - 0.5;
+    my $y_max = $QUAL_TO + 0.5;
+
+    open my $h_plot, '>', $file_plot or die $!;
+    print $h_plot <<HEREDOC;
+set title "Cycle Quality of Reads $side" font "*,$SZ_TITLE"
+unset key
+set terminal $FORMAT size $WIDTH,$HEIGHT
+set output "$file_chart"
+set palette rgbformulae 21,22,23
+
+set cblabel "Num reads" font "*,$SZ_TEXT"
+set cbtics font "*,$SZ_TEXT"
+
+set xrange [$x_min:$x_max]
+set yrange [$y_min:$y_max]
+set xlabel "Cycle" font "*,$SZ_TEXT"
+set ylabel "Quality" font "*,$SZ_TEXT"
+set xtics font "*,$SZ_TEXT"
+set ytics font "*,$SZ_TEXT"
+
+plot '$file_dat' using 1:2:3 with image
+
+HEREDOC
+    close $h_plot;
+
+    # run gnuplot
+    if ($HAS_GNUPLOT) {
+        system( 'gnuplot', $file_plot ) == 0 or die "gnuplot failed";
+    }
+}
+
+sub plot_cycle_quality_box {
+    my $base = shift;
+    my $side = shift;
+
+    my $file_tab   = catfile $dir_data, $base . '.tab';
+    my $file_plot  = catfile $dir_data, $base . '.gnuplot';
+    my $file_chart = catfile $dir_data, $base . '.' . $FORMAT;
+
+    # write script
+    my $x_min = -0.5;
+    my $x_max = $LENGTH + 0.5;
+    my $y_min = $QUAL_FROM - 0.5;
+    my $y_max = $QUAL_TO + 0.5;
+
+    open my $h_plot, '>', $file_plot or die $!;
+    print $h_plot <<HEREDOC;
+set title "Cycle Quality of Reads $side" font "*,$SZ_TITLE"
+unset key
+set terminal $FORMAT size $WIDTH,$HEIGHT
+set output "$file_chart"
+
+set xrange [$x_min:$x_max]
+set yrange [$y_min:$y_max]
+set xlabel "Cycle" font "*,$SZ_TEXT"
+set ylabel "Quality" font "*,$SZ_TEXT"
+set xtics font "*,$SZ_TEXT"
+set ytics font "*,$SZ_TEXT"
+
+set boxwidth 0.8 relative
+
+plot '$file_tab' using 1:3:2:6:5 with candlesticks lc rgbcolor '#00007f',\\
+     '$file_tab' using 1:7 with lines lc rgbcolor 'red'
+
+HEREDOC
+    close $h_plot;
+
+    # run gnuplot
+    if ($HAS_GNUPLOT) {
+        system( 'gnuplot', $file_plot ) == 0 or die "gnuplot failed";
+    }
+}
+
+sub plot_reads_quality {
+    my $base = shift;
+
+    my $file_tab   = catfile $dir_data, $base . '.tab';
+    my $file_plot  = catfile $dir_data, $base . '.gnuplot';
+    my $file_chart = catfile $dir_data, $base . '.' . $FORMAT;
+
+    # write script
+    open my $h_plot, '>', $file_plot or die $!;
+    print $h_plot <<HEREDOC;
+set title "Reads Quality" font "*,$SZ_TITLE"
+set terminal $FORMAT size $WIDTH,$HEIGHT
+
+set key font "*,$SZ_TEXT"
+
+set xlabel "Quality" font "*,$SZ_TEXT"
+set ylabel "Num reads" font "*,$SZ_TEXT"
+set xtics font "*,$SZ_TEXT"
+set ytics font "*,$SZ_TEXT"
+
+set output "$file_chart"
+
+HEREDOC
+
+    print $h_plot
+"plot '$file_tab' using 1:2 lc rgbcolor '#ff0000' title 'read 1 quality' with lines,\\\n";
+    print $h_plot
+"     '$file_tab' using 1:3 lc rgbcolor '#7f0000' title 'read 1 quality accum' with lines";
+
+    if ($PAIRED) {
+        print $h_plot ",\\\n";
+        print $h_plot
+"     '$file_tab' using 1:4 lc rgbcolor '#0000ff' title 'read 2 quality' with lines,\\\n";
+        print $h_plot
+"     '$file_tab' using 1:5 lc rgbcolor '#00007f' title 'read 2 quality accum' with lines\n";
+    }
+    else {
+        print $h_plot "\n";
+    }
+
+    close $h_plot;
+
+    # run gnuplot
+    if ($HAS_GNUPLOT) {
+        system( 'gnuplot', $file_plot ) == 0 or die "gnuplot failed";
+    }
+}
+
+sub plot_lane_tile_quality {
+    my $base = shift;
+    my $side = shift;
+
+    my $file_tab   = catfile $dir_data, $base . '.tab';
+    my $file_plot  = catfile $dir_data, $base . '.gnuplot';
+    my $file_chart = catfile $dir_data, $base . '.' . $FORMAT;
+    my $file_dat   = catfile $dir_data, $base . '.dat';
+
+    # read ticks
+    # create dat file
+    my @titles;
+    my @ticks_list;
+
+    open my $h_tab, '<', $file_tab
+      or die "failed to open '$file_tab' for read: $!";
+    open my $h_dat, '>', $file_dat
+      or die "failed to open '$file_dat' for write: $!";
+    my $n = 0;
+    while (<$h_tab>) {
+        chomp;
+        if ( $n == 0 ) {
+            ( undef, @titles ) = split /\t/;
+        }
+        else {
+            my ( $lane, $tile, @data ) = split /\t/;
+            push @ticks_list, "\"lane $lane tile $tile\" $n";
+            print $h_dat join( "\t", $n, @data ), "\n";
+        }
+    }
+    continue { $n++ }
+    close $h_tab;
+    close $h_dat;
+
+    my $ticks_str = join ', ', @ticks_list;
+
+    # write script
+    open my $h_plot, '>', $file_plot or die $!;
+    print $h_plot <<HEREDOC;
+set title "Lane-Tile Quality for Reads $side" font "*,$SZ_TITLE"
+set terminal $FORMAT size $WIDTH,$HEIGHT
+
+set key outside font "*,$SZ_TEXT"
+
+set xlabel "Tiles" font "*,$SZ_TEXT"
+set ylabel "Num reads" font "*,$SZ_TEXT"
+set xtics rotate 90 ($ticks_str) font "*,$SZ_TEXT"
+set ytics font "*,$SZ_TEXT"
+
+set style fill solid
+set output "$file_chart"
+plot '$file_dat' using 1:(\$5+\$4+\$3+\$2):(1) with boxes lc rgbcolor "blue" title "quality > 30", \\
+     '$file_dat' using 1:(\$4+\$3+\$2):(1) with boxes lc rgbcolor "green" title "20 < quality < 30", \\
+     '$file_dat' using 1:(\$3+\$2):(1) with boxes lc rgbcolor "red" title "10 < quality < 20", \\
+     '$file_dat' using 1:2:(1) with boxes lc rgbcolor "black" title "quality < 10"
+HEREDOC
+
+    close $h_plot;
+
+    # run gnuplot
+    if ($HAS_GNUPLOT) {
+        system( 'gnuplot', $file_plot ) == 0 or die "gnuplot failed";
+    }
+}
+
+sub plot_cycle_composition {
+    my $base = shift;
+    my $side = shift;
+
+    my $file_tab   = catfile $dir_data, $base . '.tab';
+    my $file_plot  = catfile $dir_data, $base . '.gnuplot';
+    my $file_chart = catfile $dir_data, $base . '.' . $FORMAT;
+
+    my $x_min = -0.5;
+    my $x_max = $LENGTH + 0.5;
+
+    open my $h_plot, '>', $file_plot or die $!;
+    print $h_plot <<heredoc;
+set title "Cycle Composition for Read $side" font "*,$SZ_TITLE"
+set terminal $FORMAT size $WIDTH,$HEIGHT
+set style fill solid
+
+set key outside font "*,$SZ_TEXT"
+
+set xrange [$x_min:$x_max]
+set xlabel "Cycle" font "*,$SZ_TEXT"
+set ylabel "Num reads" font "*,$SZ_TEXT"
+set xtics font "*,$SZ_TEXT"
+set ytics font "*,$SZ_TEXT"
+
+set output "$file_chart"
+heredoc
+    print $h_plot "plot";
+
+    if ($MASK) {
+        print $h_plot <<heredoc;
+'$file_tab' using 1:(\$7+\$6+\$5+\$4+\$3+\$2) with boxes lc rgbcolor "yellow" title "MASK", \\
+heredoc
+    }
+
+    print $h_plot <<heredoc;
+'$file_tab' using 1:(\$6+\$5+\$4+\$3+\$2) with boxes lc rgbcolor "grey" title "N", \\
+     '$file_tab' using 1:(\$5+\$4+\$3+\$2) with boxes lc rgbcolor "black" title "C", \\
+     '$file_tab' using 1:(\$4+\$3+\$2) with boxes lc rgbcolor "blue" title "G", \\
+     '$file_tab' using 1:(\$3+\$2) with boxes lc rgbcolor "red" title "T", \\
+     '$file_tab' using 1:2 with boxes lc rgbcolor "green" title "A"
+heredoc
+    close $h_plot;
+
+    # run gnuplot
+    if ($HAS_GNUPLOT) {
+        system( 'gnuplot', $file_plot ) == 0 or die "gnuplot failed";
+    }
+}
+
+sub plot_reads_length {
+    my $base = shift;
+
+    my $file_tab   = catfile $dir_data, $base . '.tab';
+    my $file_plot  = catfile $dir_data, $base . '.gnuplot';
+    my $file_chart = catfile $dir_data, $base . '.' . $FORMAT;
+
+    open my $h_plot, '>', $file_plot or die $!;
+    print $h_plot <<heredoc;
+set title "Reads Length" font "*,$SZ_TITLE"
+set terminal $FORMAT size $WIDTH,$HEIGHT
+
+set key font "*,$SZ_TEXT"
+
+set xlabel "Length" font "*,$SZ_TEXT"
+set ylabel "Num reads" font "*,$SZ_TEXT"
+set xtics font "*,$SZ_TEXT"
+set ytics font "*,$SZ_TEXT"
+
+set output "$file_chart"
+heredoc
+    print $h_plot
+"plot '$file_tab' using 1:2  lc rgbcolor '#ff0000' title 'read 1 length' with lines,\\\n";
+    print $h_plot
+"     '$file_tab' using 1:3  lc rgbcolor '#7f0000' title 'read 1 length accum' with lines";
+    if ($PAIRED) {
+        print $h_plot ",\\\n";
+        print $h_plot
+"     '$file_tab' using 1:4 lc rgbcolor '#0000ff' title 'read 2 length' with lines,\\\n";
+        print $h_plot
+"     '$file_tab' using 1:5 lc rgbcolor '#00007f' title 'read 2 length accum' with lines\n";
+    }
+    else {
+        print $h_plot "\n";
+    }
+    close $h_plot;
+
+    # run gnuplot
+    if ($HAS_GNUPLOT) {
+        system( 'gnuplot', $file_plot ) == 0 or die "gnuplot failed";
+    }
+}
+
+sub plot_quality_qq {
+    my $base = shift;
+
+    my $file_tab   = catfile $dir_data, $base . '.tab';
+    my $file_plot  = catfile $dir_data, $base . '.gnuplot';
+    my $file_chart = catfile $dir_data, $base . '.' . $FORMAT;
+
+    my $label_x = $QUAL_FROM + 3;
+    my $label_y = $QUAL_TO - 3;
+
+    # get pearson r value
+    open my $h_tab, '<', $file_tab
+      or die "failed to open '$file_tab' for read: $!";
+    my $tab_header = <$h_tab>;
+    chomp $tab_header;
+    $tab_header =~ /# pearson correlation: (\S+)/
+      or die "failed to parse pearson correlation from '$tab_header'";
+    my $pearson_text = $1;
+    close $h_tab;
+
+    # write gnuplot script
+    open my $h_plot, '>', $file_plot or die $!;
+    print $h_plot <<heredoc;
+set title "Read Pair Quality QQ plot" font "*,$SZ_TITLE"
+set terminal $FORMAT size $WIDTH,$HEIGHT
+set output "$file_chart"
+unset key
+
+set xrange [$QUAL_FROM:$QUAL_TO]
+set yrange [$QUAL_FROM:$QUAL_TO]
+set xtics font "*,$SZ_TEXT"
+set ytics font "*,$SZ_TEXT"
+
+set label 'r = $pearson_text' at $label_x,$label_y font "*,$SZ_TEXT"
+plot '$file_tab' with lines
+
+heredoc
+    close $h_plot;
+
+    # run gnuplot
+    if ($HAS_GNUPLOT) {
+        system( 'gnuplot', $file_plot ) == 0 or die "gnuplot failed";
+    }
+}
+
+# help document
+sub show_help {
+    print <<heredoc;
+$0 - render ht_stat outputs
+
+Usage:
+  ht_stat_draw.pl --dir STAT_DIR
+
+Options:
+--dir         the output directory of ht_stat.
+--format      picture format. [$FORMAT]
+--width       picture width. [$WIDTH]
+--height      picture height. [$HEIGHT]
+--title-size  font size for picture titles. [$SZ_TITLE]
+--text-size   font size for axis ticks, legends, etc.. [$SZ_TEXT]
+--help        show help
+heredoc
+    exit(0);
+}
diff --git a/src/ht2-stat.cpp b/src/ht2-stat.cpp
new file mode 100644
index 0000000..5db8e12
--- /dev/null
+++ b/src/ht2-stat.cpp
@@ -0,0 +1,759 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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 <vector>
+#include <map>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <stdexcept>
+#include <algorithm>
+#include <cmath>
+#include <queue>
+
+#include <cstdio>
+
+#include "htio2/Cast.h"
+#include "htio2/FastqIO.h"
+#include "htio2/QualityUtil.h"
+#include "htio2/HeaderUtil.h"
+
+#define USE_se_pe
+#define USE_encode
+#define USE_header_format
+#define USE_mask
+
+#include "htio2/RingBuffer.h"
+#include "htqc/Options.h"
+#include "htqc/BaseQualCounter.h"
+#include "htqc/FastqStat.h"
+#include "htqc/App.h"
+#include "htqc/MultiSeqFile.h"
+
+// We don't care strand in this program, so simply let them identical.
+#define PE_STRAND_FILE htio2::STRAND_FWD, htio2::STRAND_FWD
+#define PE_STRAND_OBJ htio2::STRAND_FWD, htio2::STRAND_FWD
+
+using namespace std;
+using namespace htqc;
+using namespace htio2::juce;
+
+//
+// thread devices
+//
+struct StatWorker;
+vector<StatWorker*> WORKERS;
+
+queue<ssize_t> IDX_FREE;
+queue<ssize_t> IDX_FILLED;
+
+// list of reads, one for each thread
+vector<htio2::FastqSeq> READ_BUFFER_1;
+vector<htio2::FastqSeq> READ_BUFFER_2;
+
+size_t N_PROCESSED = 0;
+
+//
+// command-line arguments
+//
+int OPT_num_threads = 2;
+htio2::Option OPT_num_threads_ENTRY("threads", 't', OPTION_GROUP_MISC,
+                                    &OPT_num_threads, htio2::Option::FLAG_NONE,
+                                    "Number of worker threads.", "INT");
+
+string OPT_dir_out;
+htio2::Option OPT_dir_out_ENTRY("out", 'o', OPTION_GROUP_IO,
+                                &OPT_dir_out, htio2::Option::FLAG_NONE,
+                                "Output directory.", "DIR");
+
+//
+// thread body
+//
+
+struct StatWorker: public Thread
+{
+
+    StatWorker(int thread_id)
+        : Thread(String(thread_id))
+        , todo(OPT_num_threads * 2)
+        , done(OPT_num_threads * 2)
+        , stat_a(OPT_mask, OPT_encode, OPT_header_format, OPT_header_sra)
+        , stat_b(OPT_mask, OPT_encode, OPT_header_format, OPT_header_sra)
+    {
+    }
+
+    virtual void run()
+    {
+        while (1)
+        {
+            ssize_t i = numeric_limits<ssize_t>::min();
+
+            // get indices of the todo read
+            todo.pop_sync(i);
+
+            // exit when get the signal
+            if (i == -1) return;
+
+
+            // process fetched ones
+            if (OPT_se)
+            {
+                stat_a.record_seq(READ_BUFFER_1[i]);
+            }
+            else
+            {
+                stat_a.record_seq(READ_BUFFER_1[i]);
+                stat_b.record_seq(READ_BUFFER_2[i]);
+            }
+
+            // push back processed read slot
+            done.push_sync(i);
+        }
+    }
+
+    htio2::RingBuffer<ssize_t> todo;
+    htio2::RingBuffer<ssize_t> done;
+    FastqStat stat_a;
+    FastqStat stat_b;
+};
+
+//
+// functions
+//
+
+void write_cycle_quality_table(const File& file, const FastqStat& stat)
+{
+    ofstream OUT(file.getFullPathName().toRawUTF8());
+
+    // write header
+    OUT << "#cycle";
+    for (int q = stat.qual_from; q <= stat.qual_to; q++)
+        OUT << "\t" << q;
+    OUT << endl;
+
+    // write qualities for each cycle
+    for (int i = 0; i < stat.observed_max_len; i++)
+    {
+        const BaseQualCounter& quals = stat.base_qual_counter[i];
+        OUT << i + 1;
+        for (int q = stat.qual_from; q <= stat.qual_to; q++)
+            OUT << "\t" << quals.get_num(q);
+        OUT << endl;
+    }
+}
+
+void write_cycle_composition(const File& file, const FastqStat& stat, bool qual_mask)
+{
+    ofstream OUT(file.getFullPathName().toRawUTF8());
+
+    // write header
+    OUT << "cycle" << "\t" << "A" << "\t" << "T" << "\t" << "G" << "\t" << "C" << "\t" << "N";
+    if (qual_mask) OUT << "\t" << "mask";
+    OUT << endl;
+
+    // write composition for each cycle
+    for (int i = 0; i < stat.observed_max_len; i++)
+    {
+        const BaseCounter& counter = stat.base_compo_counter[i];
+        OUT << i + 1 << "\t"
+            << counter.a << "\t"
+            << counter.t << "\t"
+            << counter.g << "\t"
+            << counter.c << "\t"
+            << counter.n << "\t";
+        if (qual_mask) OUT << counter.mask;
+        OUT << endl;
+    }
+}
+
+void write_se_seq_quality(const File& file, const FastqStat& stat)
+{
+    ofstream OUT(file.getFullPathName().toRawUTF8());
+
+    // write header
+    OUT << "#quality\tread 1 num\tread 1 accumulate" << endl;
+
+    int q = stat.qual_from;
+    int val_a = 0;
+    int sum_a = 0;
+
+    while (1)
+    {
+        if (q > stat.qual_to) break;
+
+        val_a = stat.read_qual_counter.get_num(q);
+        sum_a += val_a;
+        OUT << q << "\t" << val_a << "\t" << sum_a << endl;
+
+        q++;
+    }
+
+}
+
+void write_pe_seq_quality(const File& file, const FastqStat& stat_a, const FastqStat& stat_b)
+{
+    ofstream OUT(file.getFullPathName().toRawUTF8());
+
+    // write header
+    OUT << "#quality\tread 1 num\tread 1 accumulate\tread 2 num\tread 2 accumulate" << endl;
+
+    int q = stat_a.qual_from;
+    int val_a = 0;
+    int sum_a = 0;
+    int val_b = 0;
+    int sum_b = 0;
+
+    while (1)
+    {
+        if (q > stat_a.qual_to) break;
+
+        val_a = stat_a.read_qual_counter.get_num(q);
+        val_b = stat_b.read_qual_counter.get_num(q);
+        sum_a += val_a;
+        sum_b += val_b;
+
+        OUT << q << "\t" << val_a << "\t" << sum_a << "\t" << val_b << "\t" << sum_b << endl;
+
+        q++;
+    }
+}
+
+void write_se_seq_length(const File& file, const FastqStat& stat)
+{
+    ofstream OUT(file.getFullPathName().toRawUTF8());
+
+    // write header
+    OUT << "#length" << "\t" << "read 1 num" << "\t" << "read 1 accumulate" << endl;
+
+    {
+        int i = 1;
+        int val_a = 0;
+        int sum_a = 0;
+
+        while (1)
+        {
+            if (i > stat.observed_max_len) break;
+
+            val_a = stat.read_len_counter[i];
+            sum_a += val_a;
+            OUT << i << "\t" << val_a << "\t" << sum_a << endl;
+
+            i++;
+        }
+    }
+}
+
+void write_pe_seq_length(const File& file, const FastqStat& stat_a, const FastqStat& stat_b)
+{
+    ofstream OUT(file.getFullPathName().toRawUTF8());
+
+    // write header
+    if (stat_a.observed_max_len != stat_b.observed_max_len)
+    {
+        cerr << "ERROR: store has inequal length: " << stat_a.observed_max_len << " and " << stat_b.observed_max_len << endl;
+        exit(EXIT_FAILURE);
+    }
+
+    size_t length = stat_a.observed_max_len;
+
+    OUT << "#length" << "\t" << "read 1 num" << "\t" << "read 1 accumulate" << "\t" << "read 2 num" << "\t" << "read 2 accumulate" << endl;
+
+    {
+        int i = 1;
+        int val_a = 0;
+        int sum_a = 0;
+        int val_b = 0;
+        int sum_b = 0;
+
+        while (1)
+        {
+            if (i > length) break;
+
+            val_a = stat_a.read_len_counter[i];
+            val_b = stat_b.read_len_counter[i];
+            sum_a += val_a;
+            sum_b += val_b;
+
+            OUT << i << "\t" << val_a << "\t" << sum_a << "\t" << val_b << "\t" << sum_b << endl;
+
+            i++;
+        }
+    }
+}
+
+void write_lane_tile_quality(const File& file, const FastqStat& stat)
+{
+    ofstream OUT(file.getFullPathName().toRawUTF8());
+
+    // write header
+    OUT << "#lane\ttile\tqual<10\t10<qual<20\t20<qual<30\tqual>30" << endl;
+
+    // write content
+    for (
+         map< int, map<int, TileQualCounter> >::const_iterator it_lane = stat.tile_read_qual_counter.begin();
+         it_lane != stat.tile_read_qual_counter.end();
+         it_lane++
+         )
+    {
+        const map<int, TileQualCounter>* lane_quals = &(it_lane->second);
+
+        for (
+             map<int, TileQualCounter>::const_iterator it_tile = lane_quals->begin();
+             it_tile != lane_quals->end();
+             it_tile++
+             )
+        {
+            const TileQualCounter* tile_quals = &(it_tile->second);
+            OUT << it_lane->first << "\t"
+                << it_tile->first << "\t"
+                << tile_quals->num_reads_10 << "\t"
+                << tile_quals->num_reads_10_20 << "\t"
+                << tile_quals->num_reads_20_30 << "\t"
+                << tile_quals->num_reads_30 << endl;
+        }
+    }
+}
+
+void write_qq(const File& file, const FastqStat& stat_a, const FastqStat& stat_b)
+{
+    ofstream OUT(file.getFullPathName().toRawUTF8());
+
+    // calculate pearson correlation
+    const size_t n = stat_a.read_quals.size();
+
+    double sum_xy(0);
+    double sum_x(0);
+    double sum_y(0);
+    double sum_xx(0);
+    double sum_yy(0);
+
+    for (size_t i = 0; i < n; i++)
+    {
+        float x = stat_a.read_quals[i];
+        float y = stat_b.read_quals[i];
+        sum_xy += x*y;
+        sum_x += x;
+        sum_y += y;
+        sum_xx += x*x;
+        sum_yy += y*y;
+    }
+
+    double pearson =
+            (
+                n * sum_xy - sum_x * sum_y
+                ) / (
+                sqrt(n * sum_xx - sum_x * sum_x) * sqrt(n * sum_yy - sum_y * sum_y)
+                );
+
+    vector<float> quals_a_sorted = stat_a.read_quals;
+    vector<float> quals_b_sorted = stat_b.read_quals;
+
+    sort(quals_a_sorted.begin(), quals_a_sorted.end());
+    sort(quals_b_sorted.begin(), quals_b_sorted.end());
+    int num_seq = stat_a.read_quals.size();
+    int step = (num_seq < 200 ? 1 : num_seq / 200);
+
+    OUT << "# pearson correlation: " << pearson << endl;
+
+    // write data
+    for (int i = 0; i < num_seq; i += step)
+    {
+        OUT << quals_a_sorted[i] << "\t" << quals_b_sorted[i] << endl;
+    }
+}
+
+//
+// main
+//
+
+void parse_options(int argc, char** argv)
+{
+    htio2::OptionParser opt_psr;
+    opt_psr.add_option(OPT_files_in_ENTRY);
+    opt_psr.add_option(OPT_dir_out_ENTRY);
+
+    opt_psr.add_option(OPT_se_ENTRY);
+    opt_psr.add_option(OPT_pe_ENTRY);
+    opt_psr.add_option(OPT_pe_itlv_ENTRY);
+    opt_psr.add_option(OPT_pe_strand_ENTRY);
+    opt_psr.add_option(OPT_encode_ENTRY);
+    opt_psr.add_option(OPT_mask_ENTRY);
+    opt_psr.add_option(OPT_header_format_ENTRY);
+    opt_psr.add_option(OPT_header_sra_ENTRY);
+
+    opt_psr.add_option(OPT_num_threads_ENTRY);
+    opt_psr.add_option(OPT_quiet_ENTRY);
+    opt_psr.add_option(OPT_help_ENTRY);
+    opt_psr.add_option(OPT_version_ENTRY);
+
+    opt_psr.parse_options(argc, argv);
+
+    //
+    // show help
+    //
+    if (OPT_help)
+    {
+        cout << endl
+             << argv[0] << " - summarize sequencing reads quality"
+             << endl << endl
+             << opt_psr.format_document();
+        exit(EXIT_SUCCESS);
+    }
+
+    if (OPT_version) show_version_and_exit();
+}
+
+void validate_options()
+{
+    ensure_files_in();
+    ensure_se_pe();
+
+    ensure_encode();
+    ensure_header_format();
+
+    if ((OPT_encode == htio2::ENCODE_SOLEXA) && OPT_mask)
+    {
+        cerr << "ERROR: solexa mode cannot be used together with mask" << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+void show_options()
+{
+    show_se_pe();
+    show_files_in();
+    cout << "# output directory: " << OPT_dir_out << endl;
+    show_encode();
+    show_header_format();
+    show_mask();
+}
+
+void send_all_filled_slots()
+{
+    while (IDX_FILLED.size())
+    {
+        // get a filled slot
+        ssize_t slot_i = IDX_FILLED.front();
+        IDX_FILLED.pop();
+
+        // send this slot to a worker
+        bool slot_sent = false;
+        while (!slot_sent)
+        {
+            for (int i_worker = 0; i_worker < OPT_num_threads; i_worker++)
+            {
+                slot_sent = WORKERS[i_worker]->todo.push(slot_i);
+                if (slot_sent) break;
+            }
+        }
+
+        // log
+        N_PROCESSED++;
+        if (!OPT_quiet && (N_PROCESSED % LOG_BLOCK == 0))
+            cout << "\t" << N_PROCESSED << " reads done" << endl;
+    }
+}
+
+void fetch_empty_slots()
+{
+    for (int i_worker = 0; i_worker < OPT_num_threads; i_worker++)
+    {
+        ssize_t slot_i;
+        if (WORKERS[i_worker]->done.pop(slot_i))
+        {
+            IDX_FREE.push(slot_i);
+        }
+        if (WORKERS[i_worker]->done.pop(slot_i))
+        {
+            IDX_FREE.push(slot_i);
+        }
+    }
+}
+
+void do_single()
+{
+    htio2::FastqSeq curr;
+
+    htqc::MultiSeqFileSE fh_in(OPT_files_in, OPT_compress);
+
+    bool fh_re = false;
+
+    for (;;)
+    {
+        while (IDX_FREE.size())
+        {
+            ssize_t slot_i = IDX_FREE.front();
+            IDX_FREE.pop();
+
+            fh_re = fh_in.next_seq(READ_BUFFER_1[slot_i]);
+            if (!fh_re)
+                break;
+
+            IDX_FILLED.push(slot_i);
+        }
+
+        // send all filled slots to worker
+        send_all_filled_slots();
+
+        // return if finished
+        if (!fh_re)
+            break;
+
+        // try to fetch some empty slots
+        fetch_empty_slots();
+    }
+
+    if (!OPT_quiet)
+        cout << "\t" << N_PROCESSED << " done" << endl;
+}
+
+
+void do_paired()
+{
+    htqc::MultiSeqFilePE::Ptr fh_in;
+
+    if (OPT_pe_itlv)
+    {
+        fh_in = new htqc::MultiSeqFilePE(OPT_files_in,
+                                          PE_STRAND_FILE,
+                                          OPT_compress);
+    }
+    else
+    {
+        vector<string> files_in_a;
+        vector<string> files_in_b;
+        separate_paired_files(OPT_files_in, files_in_a, files_in_b);
+
+        fh_in = new htqc::MultiSeqFilePE(files_in_a,
+                                          files_in_b,
+                                          PE_STRAND_FILE,
+                                          OPT_compress);
+    }
+
+    htio2::FastqSeq seq1;
+    htio2::FastqSeq seq2;
+
+    bool fh_re = false;
+
+    for (;;)
+    {
+        // read from file
+        while (IDX_FREE.size())
+        {
+            ssize_t slot_i = IDX_FREE.front();
+            IDX_FREE.pop();
+
+            fh_re = fh_in->next_pair(READ_BUFFER_1[slot_i], READ_BUFFER_2[slot_i], PE_STRAND_OBJ);
+            if (!fh_re)
+                break;
+
+            IDX_FILLED.push(slot_i);
+        }
+
+        // send all filled slots to worker
+        send_all_filled_slots();
+
+        // return if finished
+        if (!fh_re)
+            break;
+
+        // try to read empty slots
+        fetch_empty_slots();
+    }
+
+    if (!OPT_quiet)
+        cout << "\t" << N_PROCESSED << " pairs done" << endl;
+}
+
+void execute()
+{
+    // create output directory
+    File dir_out(OPT_dir_out);
+    if (!dir_out.isDirectory())
+    {
+        Result re = dir_out.createDirectory();
+        if (re.failed())
+        {
+            fprintf(stderr, "ERROR: failed to create output directory \"%s\": %s\n",
+                    OPT_dir_out.c_str(), re.getErrorMessage().toRawUTF8());
+        }
+    }
+
+    //
+    // create thread communication utilities
+    //
+    READ_BUFFER_1.resize(OPT_num_threads*2);
+    READ_BUFFER_2.resize(OPT_num_threads*2);
+
+    // mark all slots as ready to use
+    for (ssize_t i = 0; i < OPT_num_threads*2; i++)
+    {
+        IDX_FREE.push(i);
+    }
+
+    // create threads
+    for (int i = 0; i < OPT_num_threads; i++)
+    {
+        WORKERS.push_back(new StatWorker(i));
+        WORKERS.back()->startThread();
+    }
+
+    //
+    // traverse input
+    //
+    if (OPT_se)
+        do_single();
+    else if (OPT_pe)
+        do_paired();
+    else
+        throw runtime_error("neither single-end nor paired-end");
+
+    // send stop signal
+    for (int i = 0; i < OPT_num_threads; i++)
+    {
+        WORKERS[i]->todo.push_sync(-1);
+    }
+
+    // join threads
+    // reduce statistic results from all threads into one
+    FastqStat stat_a(OPT_mask, OPT_encode, OPT_header_format, OPT_header_sra);
+    FastqStat stat_b(OPT_mask, OPT_encode, OPT_header_format, OPT_header_sra);
+
+    if (!OPT_quiet) cout << "join threads" << endl;
+    for (int i = 0; i < OPT_num_threads; i++)
+    {
+        StatWorker* worker = WORKERS[i];
+        if (!OPT_quiet) cout << "  thread " << i << endl;
+        worker->waitForThreadToExit(-1);
+
+        if (worker->stat_a.observed_max_len < stat_a.observed_max_len)
+            worker->stat_a.try_expand_store(stat_a.observed_max_len);
+        stat_a += worker->stat_a;
+
+        if (!OPT_se)
+        {
+            if (worker->stat_b.observed_max_len < stat_b.observed_max_len)
+                worker->stat_b.try_expand_store(stat_b.observed_max_len);
+            stat_b += worker->stat_b;
+        }
+
+        delete WORKERS[i];
+    }
+
+    if (!OPT_se)
+    {
+        if (stat_a.observed_max_len > stat_b.observed_max_len)
+            stat_b.try_expand_store(stat_a.observed_max_len);
+        else
+            stat_a.try_expand_store(stat_b.observed_max_len);
+    }
+
+    //
+    // write result
+    //
+    if (!OPT_quiet) cout << "write result" << endl;
+
+    // reads info
+    File file_info = dir_out.getChildFile("info.tab");
+    ofstream INFO(file_info.getFullPathName().toRawUTF8());
+    INFO << "amount" << "\t" << N_PROCESSED << (OPT_se ? "" : "x2") << endl
+         << "encode" << "\t" << htio2::to_string(OPT_encode) << endl
+         << "paired" << "\t" << bool_to_string(OPT_pe) << endl
+         << "length" << "\t" << stat_a.observed_max_len << endl
+         << "mask" << "\t" << bool_to_string(OPT_mask) << endl
+         << "quality range" << "\t" << stat_a.qual_from << '-' << stat_a.qual_to << endl;
+
+    // cycle quality
+    File file_cycle_qual_1 = dir_out.getChildFile("cycle_quality_1.tab");
+    if (!OPT_quiet)
+        cout << "  " << file_cycle_qual_1.getFullPathName().toStdString() << endl;
+
+    write_cycle_quality_table(file_cycle_qual_1, stat_a);
+
+    if (!OPT_se)
+    {
+        File file_cyc_qual_2 = dir_out.getChildFile("cycle_quality_2.tab");
+        if (!OPT_quiet)
+            cout << "  " << file_cyc_qual_2.getFullPathName().toStdString() << endl;
+
+        write_cycle_quality_table(file_cyc_qual_2, stat_b);
+    }
+
+    // read quality
+    File file_read_qual = dir_out.getChildFile("reads_quality.tab");
+    if (!OPT_quiet) cout << "  " << file_read_qual.getFullPathName().toStdString() << endl;
+
+    if (!OPT_se)
+    {
+        write_pe_seq_quality(file_read_qual, stat_a, stat_b);
+    }
+    else
+    {
+        write_se_seq_quality(file_read_qual, stat_a);
+    }
+
+    // lane and tile quality
+    File file_lane_tile_qual_1 = dir_out.getChildFile("lane_tile_quality_1.tab");
+    if (!OPT_quiet)
+        cout << "  " << file_lane_tile_qual_1.getFullPathName().toStdString() << endl;
+    write_lane_tile_quality(file_lane_tile_qual_1, stat_a);
+
+    if (!OPT_se)
+    {
+        File file_lane_tile_qual_2 = dir_out.getChildFile("lane_tile_quality_2.tab");
+        if (!OPT_quiet)
+            cout << "  " << file_lane_tile_qual_2.getFullPathName().toStdString() << endl;
+        write_lane_tile_quality(file_lane_tile_qual_2, stat_b);
+    }
+
+    // cycle composition
+    File file_cycle_comp_1 = dir_out.getChildFile("cycle_composition_1.tab");
+    if (!OPT_quiet)
+        cout << "  " << file_cycle_comp_1.getFullPathName().toStdString() << endl;
+    write_cycle_composition(file_cycle_comp_1, stat_a, OPT_mask);
+
+    if (!OPT_se)
+    {
+        File file_cycle_comp_2 = dir_out.getChildFile("cycle_composition_2.tab");
+        if (!OPT_quiet) cout << "  " << file_cycle_comp_2.getFullPathName().toStdString() << endl;
+        write_cycle_composition(file_cycle_comp_2, stat_b, OPT_mask);
+    }
+
+    // read length
+    File file_read_length = dir_out.getChildFile("reads_length.tab");
+    if (!OPT_quiet) cout << "  " << file_read_length.getFullPathName().toStdString() << endl;
+
+    if (!OPT_se)
+    {
+        write_pe_seq_length(file_read_length, stat_a, stat_b);
+    }
+    else
+    {
+        write_se_seq_length(file_read_length, stat_a);
+    }
+
+    // QQ plot
+    if (!OPT_se)
+    {
+        File file_qual_qq = dir_out.getChildFile("quality_QQ.tab");
+        if (!OPT_quiet) cout << "  " << file_qual_qq.getFullPathName().toStdString() << endl;
+        write_qq(file_qual_qq, stat_a, stat_b);
+    }
+
+    if (!OPT_quiet)
+        printf("all table written\n");
+}
+
diff --git a/src/ht2-trim.cpp b/src/ht2-trim.cpp
new file mode 100644
index 0000000..e3a15dc
--- /dev/null
+++ b/src/ht2-trim.cpp
@@ -0,0 +1,280 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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 "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+#include "htio2/QualityUtil.h"
+
+#define USE_prefix_out
+#define USE_encode
+#define USE_se_pe
+#include "htqc/Options.h"
+#include "htqc/App.h"
+#include "htqc/MultiSeqFile.h"
+
+using namespace std;
+using namespace htqc;
+
+//
+// type definitions
+//
+
+enum TrimSide
+{
+    TRIM_FROM_HEAD = 1,
+    TRIM_FROM_TAIL = 1 << 1
+};
+
+string trim_side_to_string(TrimSide side)
+{
+    if (side == TRIM_FROM_HEAD)
+        return "head";
+    else if (side == TRIM_FROM_TAIL)
+        return "tail";
+    else if (side == (TRIM_FROM_HEAD | TRIM_FROM_TAIL))
+        return "both";
+    else
+    {
+        cerr << "ERROR: invalid side enum value: " << int(side) << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+//
+// command line options
+//
+#define DEFAULT_KMER_SIZE 5
+#define DEFAULT_QUAL_CUT 20
+
+#define OPTION_GROUP_TRIM "Trimming Options"
+
+unsigned char OPT_trim_side = TRIM_FROM_HEAD | TRIM_FROM_TAIL;
+string OPT_trim_side_STR("both");
+htio2::Option OPT_trim_side_ENTRY("side", 'S', OPTION_GROUP_TRIM,
+                                  &OPT_trim_side_STR, htio2::Option::FLAG_NONE,
+                                  "Trim is performed on which side.", "head|tail|both");
+
+size_t OPT_word_size = DEFAULT_KMER_SIZE;
+htio2::Option OPT_word_size_ENTRY("word-size", 'W', OPTION_GROUP_TRIM,
+                                  &OPT_word_size, htio2::Option::FLAG_NONE,
+                                  "Number of continuous high quality bases.", "INT");
+
+int OPT_qual_cut = DEFAULT_QUAL_CUT;
+htio2::Option OPT_qual_cut_ENTRY("quality", 'Q', OPTION_GROUP_TRIM,
+                                 &OPT_qual_cut, htio2::Option::FLAG_NONE,
+                                 "Quality cutoff.", "INT");
+
+//
+// subs
+//
+
+void parse_options(int argc, char** argv)
+{
+    // we are always processing single-end
+    OPT_se = true;
+
+    htio2::OptionParser opt_psr;
+
+    opt_psr.add_option(OPT_files_in_ENTRY);
+    opt_psr.add_option(OPT_prefix_out_ENTRY);
+
+    opt_psr.add_option(OPT_trim_side_ENTRY);
+    opt_psr.add_option(OPT_qual_cut_ENTRY);
+    opt_psr.add_option(OPT_word_size_ENTRY);
+
+    opt_psr.add_option(OPT_encode_ENTRY);
+    opt_psr.add_option(OPT_mask_ENTRY);
+
+    opt_psr.add_option(OPT_quiet_ENTRY);
+    opt_psr.add_option(OPT_help_ENTRY);
+    opt_psr.add_option(OPT_version_ENTRY);
+
+    opt_psr.parse_options(argc, argv);
+
+    //
+    // show help
+    //
+    if (OPT_help)
+    {
+        cout << endl
+            << argv[0] << " - remove bad bases from reads head or tail"
+            << endl << endl
+            << opt_psr.format_document();
+        exit(EXIT_SUCCESS);
+    }
+
+    if (OPT_version) show_version_and_exit();
+}
+
+void validate_options()
+{
+    ensure_files_in();
+    ensure_prefix_out();
+
+    if (OPT_word_size < 1 || OPT_word_size > 16)
+    {
+        cerr << "ERROR: invalid kmer size: " << OPT_word_size << ", must between 1 - 16" << endl;
+        exit(EXIT_FAILURE);
+    }
+
+    if (OPT_trim_side_STR == "head")
+        OPT_trim_side = TRIM_FROM_HEAD;
+    else if (OPT_trim_side_STR == "tail")
+        OPT_trim_side = TRIM_FROM_TAIL;
+    else if (OPT_trim_side_STR == "both")
+        OPT_trim_side = TRIM_FROM_HEAD | TRIM_FROM_TAIL;
+    else
+    {
+        cerr << "ERROR: invalid trim side: " << OPT_trim_side_STR << ", must be head|tail|both" << endl;
+        exit(EXIT_FAILURE);
+    }
+
+    ensure_encode();
+}
+
+void show_options()
+{
+    show_files_in();
+    show_prefix_out();
+    cout << "# trim side: " << OPT_trim_side_STR << endl;
+    cout << "# word size: " << OPT_word_size << endl;
+    cout << "# quality cutoff: " << OPT_qual_cut << endl;
+    cout << "# encode: " << to_string(OPT_encode) << endl;
+}
+
+string to_str(uint16_t kmer)
+{
+    string re;
+    for (size_t i = 0; i < OPT_word_size; i++)
+    {
+        if (kmer & (1 << i))
+            re.push_back('1');
+        else
+            re.push_back('0');
+    }
+    return re;
+}
+
+void execute()
+{
+    // output
+    string file_out;
+    add_fastq_suffix_se(OPT_prefix_out, OPT_compress, file_out);
+    check_output_overwrite(OPT_files_in, file_out);
+    htio2::SeqIO::Ptr fh_out(htio2::SeqIO::New(file_out, htio2::WRITE, OPT_compress));
+
+
+    // generate kmer that is perfect
+    uint16_t perfect = 0;
+    for (size_t i = 0; i < OPT_word_size; i++)
+        perfect |= 1 << i;
+
+    //
+    // traverse input
+    //
+    size_t n = 0;
+    htio2::FastqSeq curr_seq;
+    htio2::FastqSeq curr_seq_sub;
+
+    htqc::MultiSeqFileSE fh_in(OPT_files_in, OPT_compress);
+
+    while (fh_in.next_seq(curr_seq))
+    {
+        n++;
+
+        ssize_t len = curr_seq.length();
+        ssize_t i_start = 0;
+        ssize_t i_end = len - 1;
+
+        // sequence must be long enough
+        if (len < OPT_word_size * 2)
+        {
+            i_end = i_start - 1;
+            goto TRIM_DONE;
+        }
+
+        // trim from head
+        if (OPT_trim_side & TRIM_FROM_HEAD)
+        {
+            // the first kmer
+            uint16_t kmer = 0;
+            for (size_t i = 0; i < OPT_word_size; i++)
+            {
+                int32_t qual = htio2::decode_quality(curr_seq.quality[i], OPT_encode);
+                bool curr_ok = (OPT_qual_cut <= qual);
+                kmer |= curr_ok << i;
+            }
+
+            // traverse all remaining kmers
+            if (kmer != perfect)
+            {
+                while (true)
+                {
+                    if (i_start == len - OPT_word_size) break;
+                    i_start++;
+
+                    int32_t qual = htio2::decode_quality(curr_seq.quality[i_start + OPT_word_size - 1], OPT_encode);
+                    bool curr_ok = (OPT_qual_cut <= qual);
+                    kmer >>= 1;
+                    kmer |= curr_ok << (OPT_word_size - 1);
+                    kmer &= perfect;
+                    if (kmer == perfect) break;
+                }
+            }
+        }
+
+        // trim from tail
+        if (OPT_trim_side & TRIM_FROM_TAIL)
+        {
+            // the last kmer
+            uint16_t kmer = 0;
+            for (size_t i = 0; i < OPT_word_size; i++)
+            {
+                int32_t qual = htio2::decode_quality(curr_seq.quality[len - OPT_word_size + i], OPT_encode);
+                bool curr_ok = (OPT_qual_cut <= qual);
+                kmer |= curr_ok << i;
+            }
+
+            // traverse all remaining kmers
+            if (kmer != perfect)
+            {
+                while (true)
+                {
+                    if (i_end == i_start - 1) break;
+                    i_end--;
+                    int qual = htio2::decode_quality(curr_seq.quality[i_end - OPT_word_size + 1], OPT_encode);
+                    bool curr_ok = (OPT_qual_cut <= qual);
+                    kmer <<= 1;
+                    kmer |= curr_ok;
+                    kmer &= perfect;
+                    if (kmer == perfect) break;
+                }
+            }
+        }
+
+        // write output
+TRIM_DONE:
+        int trim_len = i_end - i_start + 1;
+        curr_seq.subseq(curr_seq_sub, i_start, trim_len);
+        fh_out->write_seq(curr_seq_sub);
+
+        if (!OPT_quiet && (n % LOG_BLOCK == 0))
+            cout << "  " << n << " reads" << endl;
+    }
+
+
+    if (!OPT_quiet)
+        cout << "  " << n << " reads" << endl;
+}
diff --git a/src/ht_config.h.in b/src/ht_config.h.in
new file mode 100644
index 0000000..dff234e
--- /dev/null
+++ b/src/ht_config.h.in
@@ -0,0 +1,8 @@
+#ifndef HT_CONFIG_H
+#define HT_CONFIG_H
+
+#define HTQC_VERSION_MAJOR @CPACK_PACKAGE_VERSION_MAJOR@
+#define HTQC_VERSION_MINOR @CPACK_PACKAGE_VERSION_MINOR@
+#define HTQC_VERSION_PATCH @CPACK_PACKAGE_VERSION_PATCH@
+
+#endif // HT_CONFIG_H
\ No newline at end of file
diff --git a/src/htio2/Cast.cpp b/src/htio2/Cast.cpp
new file mode 100644
index 0000000..07a5561
--- /dev/null
+++ b/src/htio2/Cast.cpp
@@ -0,0 +1,353 @@
+#include "htio2/Cast.h"
+#include "htio2/StringUtil.h"
+
+#include <stdlib.h>
+
+using namespace std;
+
+namespace htio2
+{
+
+string _prepare_input_(const std::string& input)
+{
+    size_t i_begin = input.find_first_not_of(" \t");
+    return to_lower_case(input.substr(i_begin));
+}
+
+template <>
+bool from_string<bool>(const std::string& input, bool& output)
+{
+    string input_lc = _prepare_input_(input);
+
+    if (input_lc == "yes" || input_lc == "true" || input_lc == "y" || input_lc == "t" || input_lc == "1")
+    {
+        output = true;
+        return true;
+    }
+    else if (input_lc == "no" || input_lc == "false" || input_lc == "n" || input_lc == "f" || input_lc == "0")
+    {
+        output = false;
+        return true;
+    }
+    else
+        return false;
+}
+
+// cast to signed integers
+#define FROM_STRING_INT_IMPL(_out_type_, _func_) \
+    char* p_end = 0;\
+    _out_type_ tmp = _func_(input.c_str(), &p_end, 0);\
+    if (p_end != input.c_str())\
+    {\
+        output = tmp;\
+        return true;\
+    }\
+    else\
+        return false;\
+
+#define FROM_STRING_FLOAT_IMPL(_out_type_, _func_)\
+    char* p_end = 0;\
+    _out_type_ tmp = _func_(input.c_str(), &p_end);\
+    if (p_end != input.c_str())\
+    {\
+        output = tmp;\
+        return true;\
+    }\
+    else\
+        return false;\
+
+template <>
+bool from_string<short>(const std::string& input, short& output)
+{
+    FROM_STRING_INT_IMPL(short, strtol);
+}
+
+template <>
+bool from_string<int>(const std::string& input, int& output)
+{
+    FROM_STRING_INT_IMPL(int, strtol);
+}
+
+template <>
+bool from_string<long>(const std::string& input, long& output)
+{
+    FROM_STRING_INT_IMPL(long, strtol);
+}
+
+template <>
+bool from_string<long long>(const std::string& input, long long& output)
+{
+    FROM_STRING_INT_IMPL(long long, strtoll);
+}
+
+// cast to unsigned integers
+template <>
+bool from_string<unsigned short>(const std::string& input, unsigned short& output)
+{
+    FROM_STRING_INT_IMPL(unsigned short, strtoul);
+}
+
+template <>
+bool from_string<unsigned int>(const std::string& input, unsigned int& output)
+{
+    FROM_STRING_INT_IMPL(unsigned int, strtoul);
+}
+
+template <>
+bool from_string<unsigned long>(const std::string& input, unsigned long& output)
+{
+    FROM_STRING_INT_IMPL(unsigned long, strtoul);
+}
+
+template <>
+bool from_string<unsigned long long>(const std::string& input, unsigned long long& output)
+{
+    FROM_STRING_INT_IMPL(unsigned long long, strtoull);
+}
+
+// cast to floating points
+template <>
+bool from_string<float>(const std::string& input, float& output)
+{
+    FROM_STRING_FLOAT_IMPL(float, strtof);
+}
+
+template <>
+bool from_string<double>(const std::string& input, double& output)
+{
+    FROM_STRING_FLOAT_IMPL(double, strtod);
+}
+
+template <>
+bool from_string<long double>(const std::string& input, long double& output)
+{
+    FROM_STRING_FLOAT_IMPL(long double, strtold);
+}
+
+// cast to HTIO enum types
+template<>
+bool from_string<Strand>(const std::string& input, Strand& output)
+{
+    string input_lc = _prepare_input_(input);
+
+    if (input_lc == "forward" || input_lc == "fwd" || input_lc == "1")
+    {
+        output = STRAND_FWD;
+        return true;
+    }
+    else if (input_lc == "reverse" || input_lc == "rev" || input_lc == "-1")
+    {
+        output = STRAND_REV;
+        return true;
+    }
+    else if (input_lc == "unknown" || input_lc == "0")
+    {
+        output = STRAND_UNKNOWN;
+        return true;
+    }
+    else
+        return false;
+}
+
+template<>
+bool from_string<SeqFormat>(const std::string& input, SeqFormat& output)
+{
+    string input_lc = _prepare_input_(input);
+
+    if (input_lc == "fastq" || input_lc == "fq")
+    {
+        output = FORMAT_FASTQ;
+        return true;
+    }
+    else if (input_lc == "fasta" || input_lc == "fas" || input_lc == "fa" || input_lc == "fna")
+    {
+        output = FORMAT_FASTA;
+        return true;
+    }
+    else
+        return false;
+}
+
+template<>
+bool from_string<HeaderFormat>(const std::string& input, HeaderFormat& output)
+{
+    string input_lc = _prepare_input_(input);
+
+    if (input_lc == "pri_casava1.8")
+    {
+        output = HEADER_PRI_1_8;
+        return true;
+    }
+    else if (input_lc == "casava1.8")
+    {
+        output = HEADER_1_8;
+        return true;
+    }
+    else if (input_lc == "unknown")
+    {
+        output = HEADER_UNKNOWN;
+        return true;
+    }
+    else
+        return false;
+}
+
+template<>
+bool from_string<QualityEncode>(const std::string& input, QualityEncode& output)
+{
+    string input_lc = _prepare_input_(input);
+
+    if (input_lc == "sanger")
+    {
+        output = ENCODE_SANGER;
+        return true;
+    }
+    else if (input_lc == "solexa")
+    {
+        output = ENCODE_SOLEXA;
+        return true;
+    }
+    else if (input_lc == "illumina")
+    {
+        output = ENCODE_ILLUMINA;
+        return true;
+    }
+    else if (input_lc == "casava1.8")
+    {
+        output = ENCODE_CASAVA_1_8;
+        return true;
+    }
+    else if (input_lc == "unknown")
+    {
+        output = ENCODE_UNKNOWN;
+        return true;
+    }
+    else
+        return false;
+}
+
+template<>
+bool from_string<CompressFormat>(const std::string& input, CompressFormat& output)
+{
+    string input_lc = _prepare_input_(input);
+
+    if (input_lc == "plain")
+    {
+        output = COMPRESS_PLAIN;
+        return true;
+    }
+    else if (input_lc == "gzip" || input_lc == "gz")
+    {
+        output = COMPRESS_GZIP;
+        return true;
+    }
+    else if (input_lc == "lzma" || input_lc == "xz")
+    {
+        output = COMPRESS_LZMA;
+        return true;
+    }
+    else if (input_lc == "bz2" || input_lc == "bzip2")
+    {
+        output = COMPRESS_BZIP2;
+        return true;
+    }
+    else if (input_lc == "unknown")
+    {
+        output = COMPRESS_UNKNOWN;
+        return true;
+    }
+    else
+        return false;
+}
+
+// stringify HTIO enum types
+template<>
+std::string to_string<Strand>(Strand arg)
+{
+    switch (arg)
+    {
+    case STRAND_UNKNOWN:
+        return "unknown";
+    case STRAND_FWD:
+        return "forward";
+    case STRAND_REV:
+        return "reverse";
+    default:
+        abort();
+    }
+}
+
+template<>
+std::string to_string<SeqFormat>(SeqFormat arg)
+{
+    switch (arg)
+    {
+    case FORMAT_UNKNOWN:
+        return "unknown";
+    case FORMAT_FASTQ:
+        return "fastq";
+    case FORMAT_FASTA:
+        return "fasta";
+    default:
+        abort();
+    }
+}
+
+template<>
+std::string to_string<HeaderFormat>(HeaderFormat arg)
+{
+    switch (arg)
+    {
+    case HEADER_UNKNOWN:
+        return "unknown";
+    case HEADER_PRI_1_8:
+        return "pri_casava1.8";
+    case HEADER_1_8:
+        return "casava1.8";
+    default:
+        abort();
+    }
+}
+
+template<>
+std::string to_string<QualityEncode>(QualityEncode arg)
+{
+    switch (arg)
+    {
+    case ENCODE_UNKNOWN:
+        return "unknown";
+    case ENCODE_SANGER:
+        return "sanger";
+    case ENCODE_SOLEXA:
+        return "solexa";
+    case ENCODE_ILLUMINA:
+        return "illumina";
+    case ENCODE_CASAVA_1_8:
+        return "casava1.8";
+    default:
+        abort();
+    }
+}
+
+template<>
+std::string to_string<CompressFormat>(CompressFormat arg)
+{
+    switch (arg)
+    {
+    case COMPRESS_PLAIN:
+        return "plain";
+    case COMPRESS_GZIP:
+        return "gzip";
+    case COMPRESS_LZMA:
+        return "lzma";
+    case COMPRESS_BZIP2:
+        return "bzip2";
+    case COMPRESS_UNKNOWN:
+        return "unknown";
+    default:
+        abort();
+    }
+}
+
+
+} // namespace htio2
diff --git a/src/htio2/Cast.h b/src/htio2/Cast.h
new file mode 100644
index 0000000..bb715a3
--- /dev/null
+++ b/src/htio2/Cast.h
@@ -0,0 +1,103 @@
+#ifndef HTIO2_CAST_H
+#define HTIO2_CAST_H
+
+#include <sstream>
+
+#include "htio2/Enum.h"
+
+namespace htio2
+{
+
+template <typename T>
+bool from_string(const std::string& input, T& output);
+
+template <>
+inline bool from_string<std::string>(const std::string& input, std::string& output)
+{
+    output = input;
+    return true;
+}
+
+template <>
+bool from_string<bool>(const std::string& input, bool& output);
+
+// cast to signed integers
+template <>
+bool from_string<short>(const std::string& input, short& output);
+
+template <>
+bool from_string<int>(const std::string& input, int& output);
+
+template <>
+bool from_string<long>(const std::string& input, long& output);
+
+template <>
+bool from_string<long long>(const std::string& input, long long& output);
+
+// cast to unsigned integers
+template <>
+bool from_string<unsigned short>(const std::string& input, unsigned short& output);
+
+template <>
+bool from_string<unsigned int>(const std::string& input, unsigned int& output);
+
+template <>
+bool from_string<unsigned long>(const std::string& input, unsigned long& output);
+
+template <>
+bool from_string<unsigned long long>(const std::string& input, unsigned long long& output);
+
+// cast to floating points
+template <>
+bool from_string<float>(const std::string& input, float& output);
+
+template <>
+bool from_string<double>(const std::string& input, double& output);
+
+template <>
+bool from_string<long double>(const std::string& input, long double& output);
+
+// cast to HTIO enum types
+template<>
+bool from_string<Strand>(const std::string& input, Strand& output);
+
+template<>
+bool from_string<SeqFormat>(const std::string& input, SeqFormat& output);
+
+template<>
+bool from_string<HeaderFormat>(const std::string& input, HeaderFormat& output);
+
+template<>
+bool from_string<QualityEncode>(const std::string& input, QualityEncode& output);
+
+template<>
+bool from_string<CompressFormat>(const std::string& input, CompressFormat& output);
+
+// stringify primitive types
+template <typename T>
+std::string to_string(T input)
+{
+    std::ostringstream result;
+    result << input;
+    return result.str();
+}
+
+// stringify HTIO enum types
+template<>
+std::string to_string<Strand>(Strand input);
+
+template<>
+std::string to_string<SeqFormat>(SeqFormat input);
+
+template<>
+std::string to_string<HeaderFormat>(HeaderFormat input);
+
+template<>
+std::string to_string<QualityEncode>(QualityEncode input);
+
+template<>
+std::string to_string<CompressFormat>(CompressFormat input);
+
+} // namespace htio2
+
+#endif // HTIO2_CAST_H
diff --git a/src/htio2/Enum.cpp b/src/htio2/Enum.cpp
new file mode 100644
index 0000000..1504bff
--- /dev/null
+++ b/src/htio2/Enum.cpp
@@ -0,0 +1,12 @@
+#include "htio2/Enum.h"
+#include <cstdlib>
+#include <stdexcept>
+
+using namespace std;
+
+namespace htio2
+{
+
+
+
+} // namespace htio2
diff --git a/src/htio2/Enum.h b/src/htio2/Enum.h
new file mode 100644
index 0000000..75aae05
--- /dev/null
+++ b/src/htio2/Enum.h
@@ -0,0 +1,58 @@
+#ifndef HTIO2_ENUMS_H
+#define	HTIO2_ENUMS_H
+
+#include <string>
+
+namespace htio2
+{
+
+typedef enum
+{
+    STRAND_UNKNOWN = 0,
+    STRAND_FWD = 1,
+    STRAND_REV = 2,
+} Strand;
+
+typedef enum
+{
+    HEADER_UNKNOWN = 0,
+    HEADER_PRI_1_8 = 1, ///< header format prior to CASAVA 1.8
+    HEADER_1_8 = 2, ///< header format by CASAVA 1.8
+} HeaderFormat;
+
+typedef enum
+{
+    ENCODE_UNKNOWN = 0,
+    ENCODE_SANGER = 1, ///< 0 to 93 using ASCII 33 to 126
+    ENCODE_SOLEXA = 2, ///< -5 to 62 using ASCII 59 to 126
+    ENCODE_ILLUMINA = 3, ///< 0 to 62 using ASCII 64 to 126
+    ENCODE_CASAVA_1_8 = 4, ///< 2 to 40 using ASCII 35 to 73
+} QualityEncode;
+
+typedef enum
+{
+    FORMAT_UNKNOWN = 0,
+    FORMAT_FASTQ = 1,
+    FORMAT_FASTA = 2,
+} SeqFormat;
+
+typedef enum
+{
+    COMPRESS_UNKNOWN = 0,
+    COMPRESS_PLAIN = 1,
+    COMPRESS_GZIP = 2,
+    COMPRESS_BZIP2 = 3,
+    COMPRESS_LZMA = 4,
+} CompressFormat;
+
+typedef enum
+{
+    READ,
+    WRITE,
+    APPEND
+} IOMode;
+
+} // namespace htio2
+
+#endif	/* HTIO2_ENUMS_H */
+
diff --git a/src/htio2/Error.cpp b/src/htio2/Error.cpp
new file mode 100644
index 0000000..7831a32
--- /dev/null
+++ b/src/htio2/Error.cpp
@@ -0,0 +1,71 @@
+#include "htio2/Error.h"
+#include <sstream>
+#include "htio2/Cast.h"
+
+namespace htio2
+{
+
+InvalidQualityEncode::InvalidQualityEncode(QualityEncode encode)
+: std::invalid_argument(to_string(encode))
+{ }
+
+InvalidQualityEncode::~InvalidQualityEncode() throw ()
+{ }
+
+InvalidHeaderFormat::InvalidHeaderFormat(HeaderFormat format)
+: std::invalid_argument(to_string(format))
+{ }
+
+InvalidHeaderFormat::~InvalidHeaderFormat() throw ()
+{ }
+
+InvalidCompressFormat::InvalidCompressFormat(CompressFormat comp)
+: std::invalid_argument(to_string(comp))
+{ }
+
+InvalidCompressFormat::~InvalidCompressFormat() throw ()
+{ }
+
+InvalidSeqFormat::InvalidSeqFormat(SeqFormat format)
+: std::invalid_argument(to_string(format))
+{ }
+
+InvalidSeqFormat::~InvalidSeqFormat() throw ()
+{ }
+
+InvalidRevcom::InvalidRevcom(const std::string& seq)
+: std::invalid_argument(seq)
+{ }
+
+InvalidRevcom::~InvalidRevcom() throw ()
+{ }
+
+std::string _format_file_message(const std::string& content, size_t offset)
+{
+    std::ostringstream buffer;
+    buffer << "invalid file content at offset " << offset << ": " << content;
+    return buffer.str();
+}
+
+InvalidFileContent::InvalidFileContent(const std::string& content, size_t offset)
+: std::runtime_error(_format_file_message(content, offset))
+{ }
+
+InvalidFileContent::~InvalidFileContent() throw ()
+{ }
+
+std::string _format_kmer_message_(size_t size, size_t limit)
+{
+    std::ostringstream buffer;
+    buffer << "kmer size " << size << " exceeds limit " << limit;
+    return buffer.str();
+}
+
+InvalidKmerSize::InvalidKmerSize(size_t size, size_t limit)
+    : std::runtime_error(_format_kmer_message_(size, limit))
+{ }
+
+InvalidKmerSize::~InvalidKmerSize() throw()
+{ }
+
+} // namespace htio2
diff --git a/src/htio2/Error.h b/src/htio2/Error.h
new file mode 100644
index 0000000..ec53e7d
--- /dev/null
+++ b/src/htio2/Error.h
@@ -0,0 +1,63 @@
+#ifndef HTIO2_ERROR_H
+#define	HTIO2_ERROR_H
+
+#include <stdexcept>
+
+#include "htio2/Enum.h"
+
+namespace htio2
+{
+
+class InvalidQualityEncode : public std::invalid_argument
+{
+public:
+    InvalidQualityEncode(QualityEncode encode);
+    virtual ~InvalidQualityEncode() throw ();
+};
+
+class InvalidHeaderFormat : public std::invalid_argument
+{
+public:
+    InvalidHeaderFormat(HeaderFormat format);
+    virtual ~InvalidHeaderFormat() throw ();
+};
+
+class InvalidCompressFormat : public std::invalid_argument
+{
+public:
+    InvalidCompressFormat(CompressFormat comp);
+    virtual ~InvalidCompressFormat() throw ();
+};
+
+class InvalidSeqFormat : public std::invalid_argument
+{
+public:
+    InvalidSeqFormat(SeqFormat format);
+    virtual ~InvalidSeqFormat() throw ();
+};
+
+class InvalidRevcom : public std::invalid_argument
+{
+public:
+    InvalidRevcom(const std::string& seq);
+    virtual ~InvalidRevcom() throw ();
+};
+
+class InvalidFileContent : public std::runtime_error
+{
+public:
+    InvalidFileContent(const std::string& content, size_t offset);
+    virtual ~InvalidFileContent() throw ();
+};
+
+class InvalidKmerSize: public std::runtime_error
+{
+public:
+    InvalidKmerSize(size_t size, size_t limit);
+    virtual ~InvalidKmerSize() throw();
+};
+
+} // namespace htio2
+
+#endif	/* HTIO2_ERROR_H */
+
diff --git a/src/htio2/FastaIO.cpp b/src/htio2/FastaIO.cpp
new file mode 100644
index 0000000..b4bc9b2
--- /dev/null
+++ b/src/htio2/FastaIO.cpp
@@ -0,0 +1,177 @@
+/*
+ * File:   FastaParser.cpp
+ * Author: yangxi
+ *
+ * Created on December 19, 2012, 11:24 AM
+ */
+
+#include "htio2/FastaIO.h"
+#include "htio2/SimpleSeq.h"
+#include "htio2/Error.h"
+#include "htio2/FileHandle.h"
+#include "htio2/FastqSeq.h"
+
+using namespace std;
+
+namespace htio2
+{
+
+FastaIO::FastaIO(const std::string& filename, IOMode mode, CompressFormat comp) : SeqIO(filename, mode, comp)
+{
+    init_buffer();
+}
+
+FastaIO::FastaIO(FileHandle* handle) : SeqIO(handle)
+{
+    init_buffer();
+}
+
+FastaIO::FastaIO(FILE* handle, bool auto_close) : SeqIO(handle, auto_close)
+{
+    init_buffer();
+}
+
+FastaIO::FastaIO(gzFile handle, bool auto_close) : SeqIO(handle, auto_close)
+{
+    init_buffer();
+}
+
+FastaIO::~FastaIO()
+{
+}
+
+void FastaIO::seek(off_t offset, int whence)
+{
+    if (whence == SEEK_SET)
+    {
+        handle_offset = offset;
+        handle->seek(offset, SEEK_SET);
+    }
+    else if (whence == SEEK_CUR)
+    {
+        handle->seek(handle_offset, SEEK_SET);
+        handle->seek(offset, SEEK_CUR);
+        handle_offset += offset;
+    }
+    else if (whence == SEEK_END)
+    {
+        handle->seek(0, SEEK_END);
+        handle_offset = handle->tell() + offset;
+        handle->seek(offset, SEEK_END);
+    }
+    else
+        throw runtime_error("invalid seek whence");
+
+    handle->read_line(buffer);
+}
+
+off_t FastaIO::tell() const
+{
+    return handle_offset;
+}
+
+bool FastaIO::next_seq(SimpleSeq& result)
+{
+    result.id.clear();
+    result.desc.clear();
+    result.seq.clear();
+
+    //
+    // parse header line
+    // the header line should already be read to buffer
+    //
+    if (!buffer.length()) return false;
+
+    // find the position of first space
+    size_t i_id_end = buffer.find_first_of(" \t");
+
+    if (i_id_end != string::npos)
+    {
+        // assign ID
+        result.id.assign(buffer, 1, i_id_end - 1);
+
+        // find the position of desc
+        size_t i_desc_begin = buffer.find_first_not_of(" \t", i_id_end);
+        if (i_desc_begin != string::npos)
+        {
+            result.desc.assign(buffer, i_desc_begin, string::npos);
+        }
+    }
+    else
+    {
+        // no space, the whole line after ">" is ID
+        result.id.assign(buffer, 1, string::npos);
+    }
+
+    //
+    // get sequence
+    //
+    while (1)
+    {
+        // read a line
+        handle_offset = handle->tell();
+        if (!handle->read_line(buffer)) break;
+
+        // break if we met next record
+        if (buffer[0] == '>')
+        {
+            // ensure the position is at the start of header line
+            break;
+        }
+
+        // store current line to sequence, removing spaces and tabs
+        const size_t buffer_len = buffer.length();
+        for (size_t i = 0; i < buffer_len; i++)
+        {
+            switch (buffer[i])
+            {
+            case ' ':
+            case '\t':
+                break;
+            default:
+                result.seq.push_back(buffer[i]);
+            }
+        }
+    }
+
+    return true;
+}
+
+bool FastaIO::next_seq(FastqSeq& result)
+{
+    bool re = this->next_seq(static_cast<SimpleSeq&> (result));
+    result.quality.resize(result.seq.length(), 33 + 40);
+    return re;
+}
+
+void FastaIO::write_seq(const SimpleSeq& seq)
+{
+    handle->write_line(string(">") + seq.id + " " + seq.desc);
+    for (int i = 0; i < seq.seq.length(); i += 60)
+        handle->write_line(seq.seq.substr(i, 60));
+    handle_offset = handle->tell();
+}
+
+void FastaIO::write_seq(const FastqSeq& seq)
+{
+    write_seq(static_cast<const SimpleSeq&> (seq));
+}
+
+void FastaIO::init_buffer()
+{
+    while (1)
+    {
+        handle_offset = handle->tell();
+        if (!handle->read_line(buffer)) break;
+
+        if (buffer.length())
+        {
+            if (buffer[0] == '>')
+                break;
+            else
+                throw InvalidFileContent(buffer, handle->tell());
+        }
+    }
+}
+
+} //namespace htio2
diff --git a/src/htio2/FastaIO.h b/src/htio2/FastaIO.h
new file mode 100644
index 0000000..dcbb26e
--- /dev/null
+++ b/src/htio2/FastaIO.h
@@ -0,0 +1,104 @@
+/*
+ * File:   FastaParser.h
+ * Author: yangxi
+ *
+ * Created on December 19, 2012, 11:24 AM
+ */
+
+#ifndef HTIO2_FASTA_IO_H
+#define	HTIO2_FASTA_IO_H
+
+#include "htio2/SeqIO.h"
+
+namespace htio2
+{
+
+class FastaIO;
+
+class FastaIO : public SeqIO
+{
+public:
+    typedef htio2::SmartPtr<FastaIO> Ptr;
+    typedef htio2::SmartPtr<const FastaIO> ConstPtr;
+public:
+    /**
+     * create sequence IO object by file name
+     * @param file file to open
+     * @param mode read/write/append
+     * @param comp compress format. COMPRESS_UNKNOWN for automatically guess.
+     */
+    FastaIO(const std::string& file, IOMode mode, CompressFormat comp = COMPRESS_UNKNOWN);
+
+    /**
+     * create sequence IO object from HTIO file handle object
+     * @param handle
+     */
+    FastaIO(FileHandle* handle);
+
+    /**
+     * create sequence IO object from C standard file handle
+     * @param handle
+     * @param auto_close if set to true, the underlying handle will be closed when sequence IO object is destroyed
+     */
+    FastaIO(FILE* handle, bool auto_close = true);
+
+    /**
+     * create sequence IO object from Zlib file handle
+     * @param handle
+     * @param auto_close if set to true, the underlying handle will be closed when sequence IO object is destroyed
+     */
+    FastaIO(gzFile handle, bool auto_close = true);
+    virtual ~FastaIO();
+
+    /**
+     * Seek to a file offset.
+     * It must be ensured that the offset is always on the beginning of a FASTA entry.
+     * The offset can be different with the wrapped FileHandle's offset.
+     * See implementation of next_seq() for detail.
+     * @param offset
+     * @param whence 0 for absolute, 1 for relative
+     */
+    virtual void seek(off_t offset, int whence = SEEK_SET) override;
+
+    /**
+     * get the current file offset
+     * The offset can be different with the wrapped FileHandle's offset.
+     * See implementation of next_seq() for detail.
+     * @return file offset that is on the beginning of a FASTA entry.
+     */
+    virtual off_t tell() const override;
+
+    /**
+     * read one sequence
+     * @param result
+     * @return true if got a seq, false if reached end of file
+     */
+    virtual bool next_seq(SimpleSeq& result) override;
+
+    /**
+     * Read one sequence with quality. The qualities are set to 33+40.
+     * @param result
+     * @return true if got a seq, false if reached end of file
+     */
+    virtual bool next_seq(FastqSeq& result) override;
+
+    /**
+     * write one sequence
+     * @param seq the sequence to be written
+     */
+    virtual void write_seq(const SimpleSeq& seq) override;
+
+    virtual void write_seq(const FastqSeq& seq) override;
+protected:
+    /**
+     * The FastaIO guarantee that it won't seek while reading and writing.
+     * However, it could know the position of a record after the header line was read.
+     * Thus we need these facilities to record the file offset before the header line.
+     */
+    off_t handle_offset;
+    void init_buffer();
+};
+} // namespace htio2
+
+#endif	/* HTIO2_FASTA_IO_H */
+
diff --git a/src/htio2/FastqIO.cpp b/src/htio2/FastqIO.cpp
new file mode 100644
index 0000000..a000d5f
--- /dev/null
+++ b/src/htio2/FastqIO.cpp
@@ -0,0 +1,126 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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 "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+#include "htio2/Error.h"
+#include "htio2/FileHandle.h"
+#include <zlib.h>
+
+using namespace std;
+
+namespace htio2
+{
+
+FastqIO::FastqIO(const string& file, IOMode mode, CompressFormat comp) : SeqIO(file, mode, comp)
+{
+}
+
+FastqIO::FastqIO(FileHandle* handle) : SeqIO(handle)
+{
+}
+
+FastqIO::FastqIO(FILE* handle, bool auto_close) : SeqIO(handle, auto_close)
+{
+}
+
+FastqIO::FastqIO(gzFile handle, bool auto_close) : SeqIO(handle, auto_close)
+{
+}
+
+FastqIO::~FastqIO()
+{
+}
+
+bool FastqIO::next_seq(FastqSeq& output)
+{
+    return read_one_seq(output.id, output.desc, output.seq, output.quality);
+}
+
+bool FastqIO::next_seq(SimpleSeq& output)
+{
+    static std::string null;
+    return read_one_seq(output.id, output.desc, output.seq, null);
+}
+
+void FastqIO::write_seq(const FastqSeq& seq)
+{
+    handle->write_line("@" + seq.id + " " + seq.desc);
+    handle->write_line(seq.seq);
+    handle->write_line("+");
+    handle->write_line(seq.quality);
+}
+
+void FastqIO::write_seq(const SimpleSeq& seq)
+{
+    handle->write_line("@" + seq.id + " " + seq.desc);
+    handle->write_line(seq.seq);
+    handle->write_line("+");
+    handle->write_line(std::string(seq.length(), 'I'));
+}
+
+bool FastqIO::read_one_seq(std::string& id, std::string& desc, std::string& seq, std::string& qual)
+{
+    int32_t line_got = 0;
+
+    while (1)
+    {
+        bool re = handle->read_line(buffer);
+
+
+        if (!re) break;
+
+        if (line_got == 0)
+        {
+            if (buffer.length() == 0) continue;
+            line_got++;
+
+            size_t first_space = buffer.find_first_of(" \t");
+            size_t desc_begin = buffer.find_first_not_of(" \t", first_space);
+            id.assign(buffer, 1, first_space - 1);
+
+            if (desc_begin == string::npos)
+                desc = "";
+            else
+                desc.assign(buffer, desc_begin, string::npos);
+        }
+        else if (line_got == 1)
+        {
+            line_got++;
+            seq = buffer;
+        }
+        else if (line_got == 2)
+        {
+            line_got++;
+            if (buffer[0] != '+')
+                throw InvalidFileContent(buffer, handle->tell());
+        }
+        else if (line_got == 3)
+        {
+            line_got++;
+            qual = buffer;
+            if (seq.length() != buffer.length())
+                throw InvalidFileContent(buffer, handle->tell());
+            break;
+        }
+    }
+
+    if ((line_got != 4) && (line_got != 0))
+        throw InvalidFileContent("incomplete FASTQ record", handle->tell());
+
+    return line_got > 0;
+}
+
+} // namespace htio2
diff --git a/src/htio2/FastqIO.h b/src/htio2/FastqIO.h
new file mode 100644
index 0000000..3877f1b
--- /dev/null
+++ b/src/htio2/FastqIO.h
@@ -0,0 +1,95 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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/>.
+
+#ifndef HTIO2_FASTQ_IO_H
+#define HTIO2_FASTQ_IO_H
+
+#include "htio2/SeqIO.h"
+
+namespace htio2
+{
+
+class FastqSeq;
+class FastqIO;
+
+class FastqIO : public SeqIO
+{
+public:
+    typedef SmartPtr<FastqIO> Ptr;
+    typedef SmartPtr<const FastqIO> ConstPtr;
+
+public:
+    /**
+     * create sequence IO object by file name
+     * @param file file to open
+     * @param mode read/write/append
+     * @param comp compress format. COMPRESS_UNKNOWN for automatically guess.
+     */
+    FastqIO(const std::string& file, IOMode mode, CompressFormat comp = COMPRESS_UNKNOWN);
+
+    /**
+     * create sequence IO object from HTIO file handle object
+     * @param handle
+     */
+    FastqIO(FileHandle* handle);
+
+    /**
+     * create sequence IO object from C file handle
+     * @param handle
+     * @param auto_close if set to true, close the handle when sequence IO object is destroyed
+     */
+    FastqIO(FILE* handle, bool auto_close = true);
+
+    /**
+     * create sequence IO object from Zlib file handle
+     * @param handle
+     * @param auto_close if set to true, close the handle when sequence IO object is destroyed
+     */
+    FastqIO(gzFile handle, bool auto_close = true);
+    virtual ~FastqIO();
+
+    /**
+     * read one sequence.
+     * @param output
+     * @return true if got a seq, false if reached end of file
+     */
+    virtual bool next_seq(FastqSeq& output);
+
+    /**
+     * read one sequence with quality
+     * @param output
+     * @return true if got a seq, false if reached end of file
+     */
+    virtual bool next_seq(SimpleSeq& output);
+
+    /**
+     * write one sequence
+     * @param seq seq to write
+     */
+    virtual void write_seq(const FastqSeq& seq);
+
+    /**
+     * Write one sequence. Quality will be filled with 'I'
+     * @param output
+     */
+    virtual void write_seq(const SimpleSeq& seq);
+
+private:
+    bool read_one_seq(std::string& id, std::string& desc, std::string& seq, std::string& qual);
+};
+
+} // namespace htio2
+
+#endif // HTIO2_FASTQ_IO_H
diff --git a/src/htio2/FastqSeq.cpp b/src/htio2/FastqSeq.cpp
new file mode 100644
index 0000000..1e1f5b8
--- /dev/null
+++ b/src/htio2/FastqSeq.cpp
@@ -0,0 +1,42 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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 "htio2/FastqSeq.h"
+
+using namespace std;
+
+namespace htio2
+{
+
+FastqSeq::FastqSeq()
+{
+}
+
+FastqSeq::~FastqSeq()
+{
+}
+
+void FastqSeq::revcom(FastqSeq& result) const
+{
+    SimpleSeq::revcom(result);
+    result.quality.assign(quality.rbegin(), quality.rend());
+}
+
+void FastqSeq::subseq(FastqSeq& result, size_t start, size_t length) const
+{
+    SimpleSeq::subseq(result, start, length);
+    result.quality.assign(quality, start, length);
+}
+
+} // namespace htio2
diff --git a/src/htio2/FastqSeq.h b/src/htio2/FastqSeq.h
new file mode 100644
index 0000000..b1d8c0d
--- /dev/null
+++ b/src/htio2/FastqSeq.h
@@ -0,0 +1,66 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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/>.
+
+#ifndef HTIO2_FASTQ_SEQ_H
+#define	HTIO2_FASTQ_SEQ_H
+
+#include <htio2/SimpleSeq.h>
+
+namespace htio2
+{
+
+/**
+ * @brief sequence with ASCII quality
+ */
+class FastqSeq : public SimpleSeq
+{
+public:
+    typedef SmartPtr<FastqSeq> Ptr;
+    typedef SmartPtr<const FastqSeq> ConstPtr;
+
+public:
+    /**
+     * create an empty sequence object
+     */
+    FastqSeq();
+
+    virtual ~FastqSeq();
+
+    /**
+     * generate reverse complement sequence
+     * @param result
+     */
+    void revcom(FastqSeq& result) const;
+
+
+    /**
+     * Get part of the sequence. The quality is truncated correspondingly.
+     * @param result store the sub-sequence
+     * @param start start of the sub-sequence. 0 for the first base
+     * @param length length of the sub-sequence. std::string::npos to get everyting until the end.
+     */
+    void subseq(FastqSeq& result, size_t start, size_t length = std::string::npos) const;
+
+    /**
+     * Stringified quality score. If you want quality in numbers, see function
+     * "decode_quality" in header "QualityUtil.h".
+     */
+    std::string quality;
+};
+
+} // namespace htio2
+
+#endif	/* HTIO2_FASTQ_SEQ_H */
+
diff --git a/src/htio2/FileHandle.cpp b/src/htio2/FileHandle.cpp
new file mode 100644
index 0000000..2a7e7cd
--- /dev/null
+++ b/src/htio2/FileHandle.cpp
@@ -0,0 +1,30 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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 "htio2/FileHandle.h"
+
+namespace htio2
+{
+
+FileHandle::FileHandle()
+{
+
+}
+
+FileHandle::~FileHandle()
+{
+}
+
+} // namespace htio2
diff --git a/src/htio2/FileHandle.h b/src/htio2/FileHandle.h
new file mode 100644
index 0000000..68f1a93
--- /dev/null
+++ b/src/htio2/FileHandle.h
@@ -0,0 +1,94 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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/>.
+
+#ifndef HTIO2_FILE_HANDLE_H
+#define	HTIO2_FILE_HANDLE_H
+
+#include <string>
+
+#include "htio2/RefCounted.h"
+#include "htio2/Enum.h"
+
+namespace htio2
+{
+
+#define LINE_END_CR 13
+#define LINE_END_LF 10
+
+inline const char* get_io_mode_str(IOMode mode)
+{
+    switch (mode)
+    {
+    case READ:
+        return "rb";
+    case WRITE:
+        return "wb";
+    case APPEND:
+        return "ab";
+    default:
+        return 0;
+    }
+}
+
+/**
+ * An abstract base class for file handles.
+ */
+class FileHandle : public RefCounted
+{
+public:
+    typedef SmartPtr<FileHandle> Ptr;
+    typedef SmartPtr<const FileHandle> ConstPtr;
+
+public:
+    FileHandle();
+    virtual ~FileHandle();
+
+    /**
+     * Read one line. The end-of-line character can be CR, LF and CRLF.
+     * @param buffer
+     * @return true if get a line, false if reached end of file.
+     */
+    virtual bool read_line(std::string& buffer) = 0;
+
+    /**
+     * Write one line. The end-of-line character is decided by the system.
+     * @param content the content to be written
+     */
+    virtual void write_line(const std::string& content) = 0;
+
+    /**
+     * Seek to a file offset.
+     * The offset can be different with the wrapped FILE* or gzFile's offset.
+     * See implementation of read_line() for detail.
+     * @param offset
+     * @param whence 0 for absolute, 1 for relative
+     */
+    virtual void seek(off_t offset, int whence = SEEK_SET) = 0;
+
+    /**
+     * Get the current file offset.
+     * The offset can be different with the wrapped FILE* or gzFile's offset.
+     * See implementation of read_line() for detail.
+     * @return offset
+     */
+    virtual off_t tell() const = 0;
+
+private:
+};
+
+} // namespace htio2
+
+#endif	/* HTIO2_FILE_HANDLE_H */
+
diff --git a/src/htio2/FormatUtil.cpp b/src/htio2/FormatUtil.cpp
new file mode 100644
index 0000000..215050c
--- /dev/null
+++ b/src/htio2/FormatUtil.cpp
@@ -0,0 +1,75 @@
+#include "htio2/FormatUtil.h"
+
+#include "htio2/Error.h"
+#include "htio2/PlainFileHandle.h"
+#include "htio2/GzipFileHandle.h"
+
+using namespace std;
+
+namespace htio2
+{
+
+CompressFormat guess_compress_by_name(const std::string& file)
+{
+    if (file.rfind(".gz") != std::string::npos) return COMPRESS_GZIP;
+    else return COMPRESS_PLAIN;
+}
+
+SeqFormat guess_format_by_name_and_content(const std::string& file, CompressFormat comp)
+{
+    SeqFormat re = guess_format_by_name(file);
+    if (re == FORMAT_UNKNOWN)
+    {
+        FileHandle* handle = 0;
+        if (comp == COMPRESS_GZIP)
+            handle = new GzipFileHandle(file.c_str(), READ);
+        else if (comp == COMPRESS_PLAIN)
+            handle = new PlainFileHandle(file.c_str(), READ);
+        else
+            throw InvalidCompressFormat(comp);
+
+        re = guess_format_by_content(*handle);
+        delete handle;
+    }
+    return re;
+}
+
+SeqFormat guess_format_by_name(const std::string& file)
+{
+    if (file.rfind(".fastq") != string::npos ||
+        file.rfind(".fq") != string::npos)
+    {
+        return FORMAT_FASTQ;
+    }
+    else if (file.rfind(".fasta") != string::npos ||
+             file.rfind(".fas") != string::npos ||
+             file.rfind(".fa") != string::npos ||
+             file.rfind(".faa") != string::npos ||
+             file.rfind(".fna") != string::npos)
+    {
+        return FORMAT_FASTA;
+    }
+    else
+    {
+        return FORMAT_UNKNOWN;
+    }
+}
+
+SeqFormat guess_format_by_content(FileHandle& handle)
+{
+    // read first line, guess format
+    string line;
+    handle.read_line(line);
+
+    SeqFormat format;
+    if (line[0] == '>')
+        format = FORMAT_FASTA;
+    else if (line[0] == '@')
+        format = FORMAT_FASTQ;
+    else
+        format = FORMAT_UNKNOWN;
+
+    return format;
+}
+
+} // namespace htio2
diff --git a/src/htio2/FormatUtil.h b/src/htio2/FormatUtil.h
new file mode 100644
index 0000000..7846ffd
--- /dev/null
+++ b/src/htio2/FormatUtil.h
@@ -0,0 +1,22 @@
+#ifndef HTIO2_FORMAT_UTIL_H
+#define	HTIO2_FORMAT_UTIL_H
+
+#include <string>
+#include <htio2/Enum.h>
+
+namespace htio2
+{
+
+class FileHandle;
+
+CompressFormat guess_compress_by_name(const std::string& file);
+
+SeqFormat guess_format_by_name_and_content(const std::string& file, CompressFormat comp);
+SeqFormat guess_format_by_name(const std::string& file);
+SeqFormat guess_format_by_content(FileHandle& handle);
+
+
+} // namespace htio2
+
+#endif	/* HTIO2_FORMAT_UTIL_H */
+
diff --git a/src/htio2/GzipFileHandle.cpp b/src/htio2/GzipFileHandle.cpp
new file mode 100644
index 0000000..7ae16ab
--- /dev/null
+++ b/src/htio2/GzipFileHandle.cpp
@@ -0,0 +1,112 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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 "htio2/GzipFileHandle.h"
+#include "htio2/Error.h"
+
+#include <cstring>
+#include <cerrno>
+#include <cstdio>
+#include <zlib.h>
+
+using namespace std;
+
+namespace htio2
+{
+
+GzipFileHandle::GzipFileHandle(const string& file, IOMode mode) : auto_close(true)
+{
+    handle = gzopen(file.c_str(), get_io_mode_str(mode));
+    if (handle == 0)
+    {
+        const char* msg = strerror(errno);
+        throw runtime_error(string(msg));
+    }
+    offset = gztell(handle);
+    curr_chr = gzgetc(handle);
+}
+
+GzipFileHandle::GzipFileHandle(gzFile handle, bool auto_close) : auto_close(auto_close)
+{
+    offset = gztell(handle);
+    curr_chr = gzgetc(handle);
+}
+
+GzipFileHandle::~GzipFileHandle()
+{
+    if (auto_close) gzclose(handle);
+}
+
+bool GzipFileHandle::read_line(std::string& buffer)
+{
+    buffer.clear();
+    if (curr_chr == EOF) return false;
+
+    while (1)
+    {
+        switch (curr_chr)
+        {
+        case EOF:
+            goto END;
+        case LINE_END_CR:
+            curr_chr = gzgetc(handle);
+            if (curr_chr == LINE_END_LF) curr_chr = gzgetc(handle);
+            goto END;
+        case LINE_END_LF:
+            curr_chr = gzgetc(handle);
+            goto END;
+        default:
+            buffer.push_back(curr_chr);
+            curr_chr = gzgetc(handle);
+        }
+    }
+
+END:
+    offset = gztell(handle) - 1;
+    return true;
+}
+
+void GzipFileHandle::write_line(const std::string& content)
+{
+    gzwrite(handle, content.data(), content.size());
+    gzputc(handle, '\n');
+    offset = gztell(handle);
+}
+
+void GzipFileHandle::seek(off_t offset, int whence)
+{
+    if (whence == SEEK_SET)
+    {
+        this->offset = offset;
+        gzseek(handle, offset, SEEK_SET);
+    }
+    else if (whence == SEEK_CUR)
+    {
+        gzseek(handle, this->offset, SEEK_SET);
+        gzseek(handle, offset, SEEK_CUR);
+        this->offset += offset;
+    }
+    else
+        throw runtime_error("invalid seek whence");
+
+    curr_chr = gzgetc(handle);
+}
+
+off_t GzipFileHandle::tell() const
+{
+    return offset;
+}
+
+} // namespace htio2
diff --git a/src/htio2/GzipFileHandle.h b/src/htio2/GzipFileHandle.h
new file mode 100644
index 0000000..4905fb2
--- /dev/null
+++ b/src/htio2/GzipFileHandle.h
@@ -0,0 +1,88 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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/>.
+
+#ifndef HTIO2_GZIP_FILE_HANDLE_H
+#define	HTIO2_GZIP_FILE_HANDLE_H
+
+#include "htio2/FileHandle.h"
+#include <zlib.h>
+
+namespace htio2
+{
+
+class GzipFileHandle : public FileHandle
+{
+    friend class ::TestFramework;
+public:
+    typedef SmartPtr<GzipFileHandle> Ptr;
+    typedef SmartPtr<const GzipFileHandle> ConstPtr;
+
+public:
+    /**
+     * create by file name and mode
+     * @param file file name
+     * @param mode "rb" for read, "wb" for write
+     */
+    GzipFileHandle(const std::string& file, IOMode mode);
+
+    /**
+     * create from Zlib file handle
+     * @param handle
+     * @param auto_close if set to true, the underlying gzFile will be closed when the object is destroyed
+     */
+    GzipFileHandle(gzFile handle, bool auto_close = true);
+
+    virtual ~GzipFileHandle();
+
+    /**
+     * Read one line. The end-of-line character can be CR, LF and CRLF.
+     * @param buffer
+     * @return true if get a line, false if reached end of file.
+     */
+    virtual bool read_line(std::string& buffer);
+
+    /**
+     * Write one line. The end-of-line character is decided by the system.
+     * @param content
+     */
+    virtual void write_line(const std::string& content);
+
+    /**
+     * Seek to a file offset.
+     * The offset can be different with the wrapped FILE* or gzFile's offset.
+     * See implementation of read_line() for detail.
+     * @param offset
+     * @param whence SEEK_SET or 0 for absolute, SEEK_CUR or 1 for relative. Note: SEEK_END is not supported by zlib.
+     */
+    virtual void seek(off_t offset, int whence = SEEK_SET);
+
+    /**
+     * Get the current file offset.
+     * The offset can be different with the wrapped FILE* or gzFile's offset.
+     * See implementation of read_line() for detail.
+     * @return offset
+     */
+    virtual off_t tell() const;
+private:
+    gzFile handle;
+    bool auto_close;
+    off_t offset;
+    char curr_chr;
+};
+
+} // namespace htio2
+
+#endif	/* HTIO2_GZIP_FILE_HANDLE_H */
+
diff --git a/src/htio2/HeaderUtil.cpp b/src/htio2/HeaderUtil.cpp
new file mode 100644
index 0000000..24b29a7
--- /dev/null
+++ b/src/htio2/HeaderUtil.cpp
@@ -0,0 +1,216 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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 "htio2/HeaderUtil.h"
+#include "htio2/Cast.h"
+#include "htio2/FastqIO.h"
+#include "htio2/SimpleSeq.h"
+#include "htio2/FastqSeq.h"
+#include "htio2/Error.h"
+
+#include "JUCE-3.0.8/JuceHeader.h"
+
+using namespace std;
+using namespace htio2::juce;
+
+namespace htio2
+{
+
+void guess_header_format(const std::string& header,
+                         HeaderFormat& format,
+                         bool& with_ncbi_additive)
+{
+//    printf("header: %s\n", header.c_str());
+    string header_use;
+    if (header[0] == '@') header_use.assign(header, 1, string::npos);
+    else header_use = header;
+
+    StringArray fields;
+    fields.addTokens(String(header_use), " \t");
+
+    // check the existance of NCBI additive part
+    if (fields.size() >= 2 &&
+            fields.strings.getFirst().startsWith("SRR") &&
+            fields.strings.getLast().startsWith("length="))
+    {
+//        printf("  with NCBI\n");
+        with_ncbi_additive = true;
+        fields.remove(0);
+        fields.remove(fields.size()-1);
+    }
+    else
+    {
+        with_ncbi_additive = false;
+    }
+
+    // check header format
+    if (fields.size() >= 1)
+    {
+//        printf("  check %s\n", fields[0].toRawUTF8());
+        StringArray tokens_f1;
+        tokens_f1.addTokens(fields[0], ":", "");
+//        printf("  %d tokens\n", tokens_f1.size());
+
+        int lane = -1;
+        int tile = -1;
+        int x = -1;
+        int y = -1;
+
+        if (tokens_f1.size() == 5 &&
+                from_string<int>(tokens_f1[1].toStdString(), lane) &&
+                from_string<int>(tokens_f1[2].toStdString(), tile) &&
+                from_string<int>(tokens_f1[3].toStdString(), x) &&
+                from_string<int>(tokens_f1[4].toStdString(), y))
+        {
+            format = HEADER_PRI_1_8;
+        }
+        else if (tokens_f1.size() == 7 &&
+                 from_string<int>(tokens_f1[3].toStdString(), lane) &&
+                 from_string<int>(tokens_f1[4].toStdString(), tile) &&
+                 from_string<int>(tokens_f1[5].toStdString(), x) &&
+                 from_string<int>(tokens_f1[6].toStdString(), y))
+        {
+            format = HEADER_1_8;
+        }
+        else
+        {
+            format = HEADER_UNKNOWN;
+        }
+    }
+    else
+    {
+        format = HEADER_UNKNOWN;
+    }
+}
+
+size_t guess_header_format(FastqIO& stream, size_t num_to_guess, HeaderFormat& format, bool& with_ncbi_additive)
+{
+    FastqSeq seq;
+    HeaderFormat tmp_format = HEADER_UNKNOWN;
+    bool tmp_ncbi_flag = false;
+
+    size_t num_seq = 0;
+    off_t orig_offset = stream.tell();
+
+    for (; num_seq < num_to_guess; num_seq++)
+    {
+        if (!stream.next_seq(seq)) break;
+        HeaderFormat curr_format;
+        bool curr_ncbi_flag;
+        guess_header_format(seq.id + " " + seq.desc, curr_format, curr_ncbi_flag);
+
+        if (tmp_format == HEADER_UNKNOWN)
+        {
+            tmp_format = curr_format;
+            tmp_ncbi_flag = curr_ncbi_flag;
+        }
+        else
+        {
+            if (tmp_format != curr_format || tmp_ncbi_flag != curr_ncbi_flag)
+            {
+                stream.seek(orig_offset, 0);
+                throw runtime_error("FASTQ content has mixed header format");
+            }
+        }
+    }
+
+    stream.seek(orig_offset, 0);
+    format = tmp_format;
+    with_ncbi_additive = tmp_ncbi_flag;
+    return num_seq;
+}
+
+HeaderParser::HeaderParser(HeaderFormat h_format, bool with_ncbi_additive)
+: format(h_format)
+, with_ncbi_additive(with_ncbi_additive)
+{
+    if (h_format == HEADER_1_8)
+        lane_colon_pos = 3;
+    else if (h_format == HEADER_PRI_1_8)
+        lane_colon_pos = 1;
+    else
+        lane_colon_pos = -1;
+}
+
+void HeaderParser::parse(const string& id, const string& desc)
+{
+    if (lane_colon_pos == -1)
+    {
+        lane = 0;
+        tile = 0;
+        barcode.clear();
+        return;
+    }
+
+    string id_tidy;
+    string desc_tidy;
+    if (with_ncbi_additive)
+    {
+        size_t prefix_end = id.find_first_of(" \t");
+        size_t suffix_begin = desc.find_last_of(" \t");
+        if (prefix_end == string::npos || suffix_begin == string::npos)
+            throw runtime_error("failed to locate NCBI SRA additive in header: " + id + " " + desc);
+
+        size_t tidy_begin = id.find_first_not_of(" \t", prefix_end + 1);
+        size_t tidy_end = desc.find_last_not_of(" \t", suffix_begin - 1);
+
+        id_tidy.assign(id, tidy_begin, string::npos);
+        desc_tidy.assign(desc, 0, tidy_end + 1);
+    }
+    else
+    {
+        id_tidy = id;
+        desc_tidy = desc;
+    }
+
+    //
+    // parse lane and tile
+    //
+    int32_t lane_i_begin = -1;
+    int32_t num_colon = 0;
+
+    for (size_t i = 0; i < id_tidy.size(); i++)
+    {
+        if (id_tidy[i] == ':') num_colon++;
+
+        if (num_colon == lane_colon_pos)
+        {
+            lane_i_begin = i + 1;
+            break;
+        }
+    }
+
+    if (sscanf(id_tidy.c_str() + lane_i_begin, "%d:%d:", &lane, &tile) != 2)
+        throw runtime_error("failed to parse lane and tile in header: " + id_tidy);
+
+    //
+    // parse barcode
+    //
+    if (format == HEADER_1_8)
+    {
+        size_t pos = desc_tidy.find_last_of(':');
+        barcode.assign(desc_tidy, pos + 1, string::npos);
+    }
+    else if (format == HEADER_PRI_1_8)
+    {
+        barcode = "";
+    }
+    else
+    {
+        barcode = "";
+    }
+}
+
+} // namespace htio2
diff --git a/src/htio2/HeaderUtil.h b/src/htio2/HeaderUtil.h
new file mode 100644
index 0000000..b4fb2bd
--- /dev/null
+++ b/src/htio2/HeaderUtil.h
@@ -0,0 +1,72 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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/>.
+
+#ifndef HTIO2_HEADER_UTIL_H
+#define HTIO2_HEADER_UTIL_H
+
+#include "htio2/Enum.h"
+
+namespace htio2
+{
+
+/**
+ * Guess header format from one header.
+ * @param header
+ * @param format header format of the input header
+ * @param with_ncbi_additive will be set to true if the header has information added by NCBI SRA
+ */
+void guess_header_format(const std::string& header, HeaderFormat& format, bool& with_ncbi_additive);
+
+
+class FastqIO;
+
+/**
+ * Guess header format from several input sequences.
+ * @param stream sequences to guess are read from this stream.
+ * @param num_to_guess the amount of sequences to be guessed.
+ * @param format header format of input sequences.
+ * @param with_ncbi_additive will be set to true if the header has information added by NCBI SRA.
+ * @return number of sequences that are actually used to guess.
+ */
+size_t guess_header_format(FastqIO& stream, size_t num_to_guess, HeaderFormat& format, bool& with_ncbi_additive);
+
+class HeaderParser
+{
+public:
+    /**
+     * create a FASTQ header parser
+     * @param h_format the header format
+     * @param with_ncbi_additive whether the header would contain NCBI SRA additional contents.
+     */
+    HeaderParser(HeaderFormat h_format, bool with_ncbi_additive);
+
+    /**
+     * Parse a FASTQ header. The results are stored on the members of HeaderParser object.
+     * @param id the content of FASTQ header before the first block of continuous space
+     * @param desc the content of FASTQ header after the first block of continuous space
+     */
+    void parse(const std::string& id, const std::string& desc);
+
+    HeaderFormat format;
+    bool with_ncbi_additive;
+    int lane_colon_pos;
+    int lane;
+    int tile;
+    std::string barcode;
+};
+
+} // namespace htio2
+
+#endif // HTIO2_HEADER_UTIL_H
diff --git a/src/htio2/JUCE-3.0.8/AppConfig.h b/src/htio2/JUCE-3.0.8/AppConfig.h
new file mode 100644
index 0000000..8eabb6c
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/AppConfig.h
@@ -0,0 +1,51 @@
+/*
+
+    IMPORTANT! This file is auto-generated each time you save your
+    project - if you alter its contents, your changes may be overwritten!
+
+    There's a section below where you can add your own custom code safely, and the
+    Introjucer will preserve the contents of that block, but the best way to change
+    any of these definitions is by using the Introjucer's project settings.
+
+    Any commented-out settings will assume their default values.
+
+*/
+
+#ifndef __JUCE_APPCONFIG_YGTDMY__
+#define __JUCE_APPCONFIG_YGTDMY__
+
+//==============================================================================
+// [BEGIN_USER_CODE_SECTION]
+
+// (You can add your own code in this section, and the Introjucer will not overwrite it)
+
+// [END_USER_CODE_SECTION]
+
+//==============================================================================
+#define JUCE_MODULE_AVAILABLE_juce_core      1
+
+//==============================================================================
+// juce_core flags:
+
+#ifndef    JUCE_FORCE_DEBUG
+ //#define JUCE_FORCE_DEBUG
+#endif
+
+#ifndef    JUCE_LOG_ASSERTIONS
+ //#define JUCE_LOG_ASSERTIONS
+#endif
+
+#ifndef    JUCE_CHECK_MEMORY_LEAKS
+ //#define JUCE_CHECK_MEMORY_LEAKS
+#endif
+
+#ifndef    JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
+ //#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
+#endif
+
+#ifndef    JUCE_INCLUDE_ZLIB_CODE
+ //#define JUCE_INCLUDE_ZLIB_CODE
+#endif
+
+
+#endif  // __JUCE_APPCONFIG_YGTDMY__
diff --git a/src/htio2/JUCE-3.0.8/CMakeLists.txt b/src/htio2/JUCE-3.0.8/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
diff --git a/src/htio2/JUCE-3.0.8/JuceHeader.h b/src/htio2/JUCE-3.0.8/JuceHeader.h
new file mode 100644
index 0000000..9f7a1ed
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/JuceHeader.h
@@ -0,0 +1,19 @@
+/*
+
+    IMPORTANT! This file is auto-generated each time you save your
+    project - if you alter its contents, your changes may be overwritten!
+
+    This is the header file that your files should include in order to get all the
+    JUCE library headers. You should avoid including the JUCE headers directly in
+    your own source files, because that wouldn't pick up the correct configuration
+    options for your app.
+
+*/
+
+#ifndef __JUCE_HEADER_H__
+#define __JUCE_HEADER_H__
+
+#include "AppConfig.h"
+#include "modules/juce_core/juce_core.h"
+
+#endif   // __JUCE_HEADER_H__
diff --git a/src/htio2/JUCE-3.0.8/ReadMe.txt b/src/htio2/JUCE-3.0.8/ReadMe.txt
new file mode 100644
index 0000000..f6c3564
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/ReadMe.txt
@@ -0,0 +1,12 @@
+
+ Important Note!!
+ ================
+
+The purpose of this folder is to contain files that are auto-generated by the Introjucer,
+and ALL files in this folder will be mercilessly DELETED and completely re-written whenever
+the Introjucer saves your project.
+
+Therefore, it's a bad idea to make any manual changes to the files in here, or to
+put any of your own files in here if you don't want to lose them. (Of course you may choose
+to add the folder's contents to your version-control system so that you can re-merge your own
+modifications after the Introjucer has saved its changes).
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_AbstractFifo.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_AbstractFifo.cpp
new file mode 100644
index 0000000..65b1615
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_AbstractFifo.cpp
@@ -0,0 +1,235 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+AbstractFifo::AbstractFifo (const int capacity) noexcept
+    : bufferSize (capacity)
+{
+    jassert (bufferSize > 0);
+}
+
+AbstractFifo::~AbstractFifo() {}
+
+int AbstractFifo::getTotalSize() const noexcept           { return bufferSize; }
+int AbstractFifo::getFreeSpace() const noexcept           { return bufferSize - getNumReady() - 1; }
+
+int AbstractFifo::getNumReady() const noexcept
+{
+    const int vs = validStart.get();
+    const int ve = validEnd.get();
+    return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
+}
+
+void AbstractFifo::reset() noexcept
+{
+    validEnd = 0;
+    validStart = 0;
+}
+
+void AbstractFifo::setTotalSize (int newSize) noexcept
+{
+    jassert (newSize > 0);
+    reset();
+    bufferSize = newSize;
+}
+
+//==============================================================================
+void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
+{
+    const int vs = validStart.get();
+    const int ve = validEnd.value;
+
+    const int freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
+    numToWrite = jmin (numToWrite, freeSpace - 1);
+
+    if (numToWrite <= 0)
+    {
+        startIndex1 = 0;
+        startIndex2 = 0;
+        blockSize1 = 0;
+        blockSize2 = 0;
+    }
+    else
+    {
+        startIndex1 = ve;
+        startIndex2 = 0;
+        blockSize1 = jmin (bufferSize - ve, numToWrite);
+        numToWrite -= blockSize1;
+        blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, vs);
+    }
+}
+
+void AbstractFifo::finishedWrite (int numWritten) noexcept
+{
+    jassert (numWritten >= 0 && numWritten < bufferSize);
+    int newEnd = validEnd.value + numWritten;
+    if (newEnd >= bufferSize)
+        newEnd -= bufferSize;
+
+    validEnd = newEnd;
+}
+
+void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
+{
+    const int vs = validStart.value;
+    const int ve = validEnd.get();
+
+    const int numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
+    numWanted = jmin (numWanted, numReady);
+
+    if (numWanted <= 0)
+    {
+        startIndex1 = 0;
+        startIndex2 = 0;
+        blockSize1 = 0;
+        blockSize2 = 0;
+    }
+    else
+    {
+        startIndex1 = vs;
+        startIndex2 = 0;
+        blockSize1 = jmin (bufferSize - vs, numWanted);
+        numWanted -= blockSize1;
+        blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, ve);
+    }
+}
+
+void AbstractFifo::finishedRead (int numRead) noexcept
+{
+    jassert (numRead >= 0 && numRead <= bufferSize);
+
+    int newStart = validStart.value + numRead;
+    if (newStart >= bufferSize)
+        newStart -= bufferSize;
+
+    validStart = newStart;
+}
+
+//==============================================================================
+//==============================================================================
+#if JUCE_UNIT_TESTS
+
+class AbstractFifoTests  : public UnitTest
+{
+public:
+    AbstractFifoTests() : UnitTest ("Abstract Fifo") {}
+
+    class WriteThread  : public Thread
+    {
+    public:
+        WriteThread (AbstractFifo& f, int* b, Random rng)
+            : Thread ("fifo writer"), fifo (f), buffer (b), random (rng)
+        {
+            startThread();
+        }
+
+        ~WriteThread()
+        {
+            stopThread (5000);
+        }
+
+        void run()
+        {
+            int n = 0;
+
+            while (! threadShouldExit())
+            {
+                int num = random.nextInt (2000) + 1;
+
+                int start1, size1, start2, size2;
+                fifo.prepareToWrite (num, start1, size1, start2, size2);
+
+                jassert (size1 >= 0 && size2 >= 0);
+                jassert (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()));
+                jassert (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize()));
+
+                for (int i = 0; i < size1; ++i)
+                    buffer [start1 + i] = n++;
+
+                for (int i = 0; i < size2; ++i)
+                    buffer [start2 + i] = n++;
+
+                fifo.finishedWrite (size1 + size2);
+            }
+        }
+
+    private:
+        AbstractFifo& fifo;
+        int* buffer;
+        Random random;
+    };
+
+    void runTest()
+    {
+        beginTest ("AbstractFifo");
+
+        int buffer [5000];
+        AbstractFifo fifo (numElementsInArray (buffer));
+
+        WriteThread writer (fifo, buffer, getRandom());
+
+        int n = 0;
+        Random r = getRandom();
+        r.combineSeed (12345);
+
+        for (int count = 100000; --count >= 0;)
+        {
+            int num = r.nextInt (6000) + 1;
+
+            int start1, size1, start2, size2;
+            fifo.prepareToRead (num, start1, size1, start2, size2);
+
+            if (! (size1 >= 0 && size2 >= 0)
+                    && (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()))
+                    && (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize())))
+            {
+                expect (false, "prepareToRead returned -ve values");
+                break;
+            }
+
+            bool failed = false;
+
+            for (int i = 0; i < size1; ++i)
+                failed = (buffer [start1 + i] != n++) || failed;
+
+            for (int i = 0; i < size2; ++i)
+                failed = (buffer [start2 + i] != n++) || failed;
+
+            if (failed)
+            {
+                expect (false, "read values were incorrect");
+                break;
+            }
+
+            fifo.finishedRead (size1 + size2);
+        }
+    }
+};
+
+static AbstractFifoTests fifoUnitTests;
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_AbstractFifo.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_AbstractFifo.h
new file mode 100644
index 0000000..02feac7
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_AbstractFifo.h
@@ -0,0 +1,220 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_ABSTRACTFIFO_H_INCLUDED
+#define JUCE_ABSTRACTFIFO_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Encapsulates the logic required to implement a lock-free FIFO.
+
+    This class handles the logic needed when building a single-reader, single-writer FIFO.
+
+    It doesn't actually hold any data itself, but your FIFO class can use one of these to manage
+    its position and status when reading or writing to it.
+
+    To use it, you can call prepareToWrite() to determine the position within your own buffer that
+    an incoming block of data should be stored, and prepareToRead() to find out when the next
+    outgoing block should be read from.
+
+    e.g.
+    @code
+    class MyFifo
+    {
+    public:
+        MyFifo()  : abstractFifo (1024)
+        {
+        }
+
+        void addToFifo (const int* someData, int numItems)
+        {
+            int start1, size1, start2, size2;
+            abstractFifo.prepareToWrite (numItems, start1, size1, start2, size2);
+
+            if (size1 > 0)
+                copySomeData (myBuffer + start1, someData, size1);
+
+            if (size2 > 0)
+                copySomeData (myBuffer + start2, someData + size1, size2);
+
+            abstractFifo.finishedWrite (size1 + size2);
+        }
+
+        void readFromFifo (int* someData, int numItems)
+        {
+            int start1, size1, start2, size2;
+            abstractFifo.prepareToRead (numSamples, start1, size1, start2, size2);
+
+            if (size1 > 0)
+                copySomeData (someData, myBuffer + start1, size1);
+
+            if (size2 > 0)
+                copySomeData (someData + size1, myBuffer + start2, size2);
+
+            abstractFifo.finishedRead (size1 + size2);
+        }
+
+    private:
+        AbstractFifo abstractFifo;
+        int myBuffer [1024];
+    };
+    @endcode
+*/
+class JUCE_API  AbstractFifo
+{
+public:
+    //==============================================================================
+    /** Creates a FIFO to manage a buffer with the specified capacity. */
+    AbstractFifo (int capacity) noexcept;
+
+    /** Destructor */
+    ~AbstractFifo();
+
+    //==============================================================================
+    /** Returns the total size of the buffer being managed. */
+    int getTotalSize() const noexcept;
+
+    /** Returns the number of items that can currently be added to the buffer without it overflowing. */
+    int getFreeSpace() const noexcept;
+
+    /** Returns the number of items that can currently be read from the buffer. */
+    int getNumReady() const noexcept;
+
+    /** Clears the buffer positions, so that it appears empty. */
+    void reset() noexcept;
+
+    /** Changes the buffer's total size.
+        Note that this isn't thread-safe, so don't call it if there's any danger that it
+        might overlap with a call to any other method in this class!
+    */
+    void setTotalSize (int newSize) noexcept;
+
+    //==============================================================================
+    /** Returns the location within the buffer at which an incoming block of data should be written.
+
+        Because the section of data that you want to add to the buffer may overlap the end
+        and wrap around to the start, two blocks within your buffer are returned, and you
+        should copy your data into the first one, with any remaining data spilling over into
+        the second.
+
+        If the number of items you ask for is too large to fit within the buffer's free space, then
+        blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you
+        may decide to keep waiting and re-trying the method until there's enough space available.
+
+        After calling this method, if you choose to write your data into the blocks returned, you
+        must call finishedWrite() to tell the FIFO how much data you actually added.
+
+        e.g.
+        @code
+        void addToFifo (const int* someData, int numItems)
+        {
+            int start1, size1, start2, size2;
+            prepareToWrite (numItems, start1, size1, start2, size2);
+
+            if (size1 > 0)
+                copySomeData (myBuffer + start1, someData, size1);
+
+            if (size2 > 0)
+                copySomeData (myBuffer + start2, someData + size1, size2);
+
+            finishedWrite (size1 + size2);
+        }
+        @endcode
+
+        @param numToWrite       indicates how many items you'd like to add to the buffer
+        @param startIndex1      on exit, this will contain the start index in your buffer at which your data should be written
+        @param blockSize1       on exit, this indicates how many items can be written to the block starting at startIndex1
+        @param startIndex2      on exit, this will contain the start index in your buffer at which any data that didn't fit into
+                                the first block should be written
+        @param blockSize2       on exit, this indicates how many items can be written to the block starting at startIndex2
+        @see finishedWrite
+    */
+    void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
+
+    /** Called after writing from the FIFO, to indicate that this many items have been added.
+        @see prepareToWrite
+    */
+    void finishedWrite (int numWritten) noexcept;
+
+    /** Returns the location within the buffer from which the next block of data should be read.
+
+        Because the section of data that you want to read from the buffer may overlap the end
+        and wrap around to the start, two blocks within your buffer are returned, and you
+        should read from both of them.
+
+        If the number of items you ask for is greater than the amount of data available, then
+        blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you
+        may decide to keep waiting and re-trying the method until there's enough data available.
+
+        After calling this method, if you choose to read the data, you must call finishedRead() to
+        tell the FIFO how much data you have consumed.
+
+        e.g.
+        @code
+        void readFromFifo (int* someData, int numItems)
+        {
+            int start1, size1, start2, size2;
+            prepareToRead (numSamples, start1, size1, start2, size2);
+
+            if (size1 > 0)
+                copySomeData (someData, myBuffer + start1, size1);
+
+            if (size2 > 0)
+                copySomeData (someData + size1, myBuffer + start2, size2);
+
+            finishedRead (size1 + size2);
+        }
+        @endcode
+
+        @param numWanted        indicates how many items you'd like to add to the buffer
+        @param startIndex1      on exit, this will contain the start index in your buffer at which your data should be written
+        @param blockSize1       on exit, this indicates how many items can be written to the block starting at startIndex1
+        @param startIndex2      on exit, this will contain the start index in your buffer at which any data that didn't fit into
+                                the first block should be written
+        @param blockSize2       on exit, this indicates how many items can be written to the block starting at startIndex2
+        @see finishedRead
+    */
+    void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
+
+    /** Called after reading from the FIFO, to indicate that this many items have now been consumed.
+        @see prepareToRead
+    */
+    void finishedRead (int numRead) noexcept;
+
+
+private:
+    //==============================================================================
+    int bufferSize;
+    Atomic <int> validStart, validEnd;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo)
+};
+
+
+#endif   // JUCE_ABSTRACTFIFO_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_Array.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_Array.h
new file mode 100644
index 0000000..375576a
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_Array.h
@@ -0,0 +1,1113 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_ARRAY_H_INCLUDED
+#define JUCE_ARRAY_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Holds a resizable array of primitive or copy-by-value objects.
+
+    Examples of arrays are: Array<int>, Array<Rectangle> or Array<MyClass*>
+
+    The Array class can be used to hold simple, non-polymorphic objects as well as primitive types - to
+    do so, the class must fulfil these requirements:
+    - it must have a copy constructor and assignment operator
+    - it must be able to be relocated in memory by a memcpy without this causing any problems - so
+      objects whose functionality relies on external pointers or references to themselves can not be used.
+
+    You can of course have an array of pointers to any kind of object, e.g. Array<MyClass*>, but if
+    you do this, the array doesn't take any ownership of the objects - see the OwnedArray class or the
+    ReferenceCountedArray class for more powerful ways of holding lists of objects.
+
+    For holding lists of strings, you can use Array\<String\>, but it's usually better to use the
+    specialised class StringArray, which provides more useful functions.
+
+    To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
+    TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
+
+    @see OwnedArray, ReferenceCountedArray, StringArray, CriticalSection
+*/
+template <typename ElementType,
+          typename TypeOfCriticalSectionToUse = DummyCriticalSection,
+          int minimumAllocatedSize = 0>
+class Array
+{
+private:
+    typedef PARAMETER_TYPE (ElementType) ParameterType;
+
+public:
+    //==============================================================================
+    /** Creates an empty array. */
+    Array() noexcept
+       : numUsed (0)
+    {
+    }
+
+    /** Creates a copy of another array.
+        @param other    the array to copy
+    */
+    Array (const Array<ElementType, TypeOfCriticalSectionToUse>& other)
+    {
+        const ScopedLockType lock (other.getLock());
+        numUsed = other.numUsed;
+        data.setAllocatedSize (other.numUsed);
+
+        for (int i = 0; i < numUsed; ++i)
+            new (data.elements + i) ElementType (other.data.elements[i]);
+    }
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    Array (Array<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
+        : data (static_cast<ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&&> (other.data)),
+          numUsed (other.numUsed)
+    {
+        other.numUsed = 0;
+    }
+   #endif
+
+    /** Initalises from a null-terminated C array of values.
+
+        @param values   the array to copy from
+    */
+    template <typename TypeToCreateFrom>
+    explicit Array (const TypeToCreateFrom* values)
+       : numUsed (0)
+    {
+        while (*values != TypeToCreateFrom())
+            add (*values++);
+    }
+
+    /** Initalises from a C array of values.
+
+        @param values       the array to copy from
+        @param numValues    the number of values in the array
+    */
+    template <typename TypeToCreateFrom>
+    Array (const TypeToCreateFrom* values, int numValues)
+       : numUsed (numValues)
+    {
+        data.setAllocatedSize (numValues);
+
+        for (int i = 0; i < numValues; ++i)
+            new (data.elements + i) ElementType (values[i]);
+    }
+
+    /** Destructor. */
+    ~Array()
+    {
+        deleteAllElements();
+    }
+
+    /** Copies another array.
+        @param other    the array to copy
+    */
+    Array& operator= (const Array& other)
+    {
+        if (this != &other)
+        {
+            Array<ElementType, TypeOfCriticalSectionToUse> otherCopy (other);
+            swapWith (otherCopy);
+        }
+
+        return *this;
+    }
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    Array& operator= (Array&& other) noexcept
+    {
+        const ScopedLockType lock (getLock());
+        deleteAllElements();
+        data = static_cast<ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&&> (other.data);
+        numUsed = other.numUsed;
+        other.numUsed = 0;
+        return *this;
+    }
+   #endif
+
+    //==============================================================================
+    /** Compares this array to another one.
+        Two arrays are considered equal if they both contain the same set of
+        elements, in the same order.
+        @param other    the other array to compare with
+    */
+    template <class OtherArrayType>
+    bool operator== (const OtherArrayType& other) const
+    {
+        const ScopedLockType lock (getLock());
+        const typename OtherArrayType::ScopedLockType lock2 (other.getLock());
+
+        if (numUsed != other.numUsed)
+            return false;
+
+        for (int i = numUsed; --i >= 0;)
+            if (! (data.elements [i] == other.data.elements [i]))
+                return false;
+
+        return true;
+    }
+
+    /** Compares this array to another one.
+        Two arrays are considered equal if they both contain the same set of
+        elements, in the same order.
+        @param other    the other array to compare with
+    */
+    template <class OtherArrayType>
+    bool operator!= (const OtherArrayType& other) const
+    {
+        return ! operator== (other);
+    }
+
+    //==============================================================================
+    /** Removes all elements from the array.
+        This will remove all the elements, and free any storage that the array is
+        using. To clear the array without freeing the storage, use the clearQuick()
+        method instead.
+
+        @see clearQuick
+    */
+    void clear()
+    {
+        const ScopedLockType lock (getLock());
+        deleteAllElements();
+        data.setAllocatedSize (0);
+        numUsed = 0;
+    }
+
+    /** Removes all elements from the array without freeing the array's allocated storage.
+        @see clear
+    */
+    void clearQuick()
+    {
+        const ScopedLockType lock (getLock());
+        deleteAllElements();
+        numUsed = 0;
+    }
+
+    //==============================================================================
+    /** Returns the current number of elements in the array.
+    */
+    inline int size() const noexcept
+    {
+        return numUsed;
+    }
+
+    /** Returns one of the elements in the array.
+        If the index passed in is beyond the range of valid elements, this
+        will return a default value.
+
+        If you're certain that the index will always be a valid element, you
+        can call getUnchecked() instead, which is faster.
+
+        @param index    the index of the element being requested (0 is the first element in the array)
+        @see getUnchecked, getFirst, getLast
+    */
+    ElementType operator[] (const int index) const
+    {
+        const ScopedLockType lock (getLock());
+
+        if (isPositiveAndBelow (index, numUsed))
+        {
+            jassert (data.elements != nullptr);
+            return data.elements [index];
+        }
+
+        return ElementType();
+    }
+
+    /** Returns one of the elements in the array, without checking the index passed in.
+
+        Unlike the operator[] method, this will try to return an element without
+        checking that the index is within the bounds of the array, so should only
+        be used when you're confident that it will always be a valid index.
+
+        @param index    the index of the element being requested (0 is the first element in the array)
+        @see operator[], getFirst, getLast
+    */
+    inline ElementType getUnchecked (const int index) const
+    {
+        const ScopedLockType lock (getLock());
+        jassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
+        return data.elements [index];
+    }
+
+    /** Returns a direct reference to one of the elements in the array, without checking the index passed in.
+
+        This is like getUnchecked, but returns a direct reference to the element, so that
+        you can alter it directly. Obviously this can be dangerous, so only use it when
+        absolutely necessary.
+
+        @param index    the index of the element being requested (0 is the first element in the array)
+        @see operator[], getFirst, getLast
+    */
+    inline ElementType& getReference (const int index) const noexcept
+    {
+        const ScopedLockType lock (getLock());
+        jassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
+        return data.elements [index];
+    }
+
+    /** Returns the first element in the array, or a default value if the array is empty.
+
+        @see operator[], getUnchecked, getLast
+    */
+    inline ElementType getFirst() const
+    {
+        const ScopedLockType lock (getLock());
+
+        if (numUsed > 0)
+        {
+            jassert (data.elements != nullptr);
+            return data.elements[0];
+        }
+
+        return ElementType();
+    }
+
+    /** Returns the last element in the array, or a default value if the array is empty.
+
+        @see operator[], getUnchecked, getFirst
+    */
+    inline ElementType getLast() const
+    {
+        const ScopedLockType lock (getLock());
+
+        if (numUsed > 0)
+        {
+            jassert (data.elements != nullptr);
+            return data.elements[numUsed - 1];
+        }
+
+        return ElementType();
+    }
+
+    /** Returns a pointer to the actual array data.
+        This pointer will only be valid until the next time a non-const method
+        is called on the array.
+    */
+    inline ElementType* getRawDataPointer() noexcept
+    {
+        return data.elements;
+    }
+
+    //==============================================================================
+    /** Returns a pointer to the first element in the array.
+        This method is provided for compatibility with standard C++ iteration mechanisms.
+    */
+    inline ElementType* begin() const noexcept
+    {
+        return data.elements;
+    }
+
+    /** Returns a pointer to the element which follows the last element in the array.
+        This method is provided for compatibility with standard C++ iteration mechanisms.
+    */
+    inline ElementType* end() const noexcept
+    {
+       #if JUCE_DEBUG
+        if (data.elements == nullptr || numUsed <= 0) // (to keep static analysers happy)
+            return data.elements;
+       #endif
+
+        return data.elements + numUsed;
+    }
+
+    //==============================================================================
+    /** Finds the index of the first element which matches the value passed in.
+
+        This will search the array for the given object, and return the index
+        of its first occurrence. If the object isn't found, the method will return -1.
+
+        @param elementToLookFor   the value or object to look for
+        @returns                  the index of the object, or -1 if it's not found
+    */
+    int indexOf (ParameterType elementToLookFor) const
+    {
+        const ScopedLockType lock (getLock());
+        const ElementType* e = data.elements.getData();
+        const ElementType* const end_ = e + numUsed;
+
+        for (; e != end_; ++e)
+            if (elementToLookFor == *e)
+                return static_cast <int> (e - data.elements.getData());
+
+        return -1;
+    }
+
+    /** Returns true if the array contains at least one occurrence of an object.
+
+        @param elementToLookFor     the value or object to look for
+        @returns                    true if the item is found
+    */
+    bool contains (ParameterType elementToLookFor) const
+    {
+        const ScopedLockType lock (getLock());
+        const ElementType* e = data.elements.getData();
+        const ElementType* const end_ = e + numUsed;
+
+        for (; e != end_; ++e)
+            if (elementToLookFor == *e)
+                return true;
+
+        return false;
+    }
+
+    //==============================================================================
+    /** Appends a new element at the end of the array.
+
+        @param newElement       the new object to add to the array
+        @see set, insert, addIfNotAlreadyThere, addSorted, addUsingDefaultSort, addArray
+    */
+    void add (const ElementType& newElement)
+    {
+        const ScopedLockType lock (getLock());
+        data.ensureAllocatedSize (numUsed + 1);
+        new (data.elements + numUsed++) ElementType (newElement);
+    }
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    /** Appends a new element at the end of the array.
+
+        @param newElement       the new object to add to the array
+        @see set, insert, addIfNotAlreadyThere, addSorted, addUsingDefaultSort, addArray
+    */
+    void add (ElementType&& newElement)
+    {
+        const ScopedLockType lock (getLock());
+        data.ensureAllocatedSize (numUsed + 1);
+        new (data.elements + numUsed++) ElementType (static_cast<ElementType&&> (newElement));
+    }
+   #endif
+
+    /** Inserts a new element into the array at a given position.
+
+        If the index is less than 0 or greater than the size of the array, the
+        element will be added to the end of the array.
+        Otherwise, it will be inserted into the array, moving all the later elements
+        along to make room.
+
+        @param indexToInsertAt    the index at which the new element should be
+                                  inserted (pass in -1 to add it to the end)
+        @param newElement         the new object to add to the array
+        @see add, addSorted, addUsingDefaultSort, set
+    */
+    void insert (int indexToInsertAt, ParameterType newElement)
+    {
+        const ScopedLockType lock (getLock());
+        data.ensureAllocatedSize (numUsed + 1);
+        jassert (data.elements != nullptr);
+
+        if (isPositiveAndBelow (indexToInsertAt, numUsed))
+        {
+            ElementType* const insertPos = data.elements + indexToInsertAt;
+            const int numberToMove = numUsed - indexToInsertAt;
+
+            if (numberToMove > 0)
+                memmove (insertPos + 1, insertPos, ((size_t) numberToMove) * sizeof (ElementType));
+
+            new (insertPos) ElementType (newElement);
+            ++numUsed;
+        }
+        else
+        {
+            new (data.elements + numUsed++) ElementType (newElement);
+        }
+    }
+
+    /** Inserts multiple copies of an element into the array at a given position.
+
+        If the index is less than 0 or greater than the size of the array, the
+        element will be added to the end of the array.
+        Otherwise, it will be inserted into the array, moving all the later elements
+        along to make room.
+
+        @param indexToInsertAt    the index at which the new element should be inserted
+        @param newElement         the new object to add to the array
+        @param numberOfTimesToInsertIt  how many copies of the value to insert
+        @see insert, add, addSorted, set
+    */
+    void insertMultiple (int indexToInsertAt, ParameterType newElement,
+                         int numberOfTimesToInsertIt)
+    {
+        if (numberOfTimesToInsertIt > 0)
+        {
+            const ScopedLockType lock (getLock());
+            data.ensureAllocatedSize (numUsed + numberOfTimesToInsertIt);
+            ElementType* insertPos;
+
+            if (isPositiveAndBelow (indexToInsertAt, numUsed))
+            {
+                insertPos = data.elements + indexToInsertAt;
+                const int numberToMove = numUsed - indexToInsertAt;
+                memmove (insertPos + numberOfTimesToInsertIt, insertPos, ((size_t) numberToMove) * sizeof (ElementType));
+            }
+            else
+            {
+                insertPos = data.elements + numUsed;
+            }
+
+            numUsed += numberOfTimesToInsertIt;
+
+            while (--numberOfTimesToInsertIt >= 0)
+                new (insertPos++) ElementType (newElement);
+        }
+    }
+
+    /** Inserts an array of values into this array at a given position.
+
+        If the index is less than 0 or greater than the size of the array, the
+        new elements will be added to the end of the array.
+        Otherwise, they will be inserted into the array, moving all the later elements
+        along to make room.
+
+        @param indexToInsertAt      the index at which the first new element should be inserted
+        @param newElements          the new values to add to the array
+        @param numberOfElements     how many items are in the array
+        @see insert, add, addSorted, set
+    */
+    void insertArray (int indexToInsertAt,
+                      const ElementType* newElements,
+                      int numberOfElements)
+    {
+        if (numberOfElements > 0)
+        {
+            const ScopedLockType lock (getLock());
+            data.ensureAllocatedSize (numUsed + numberOfElements);
+            ElementType* insertPos = data.elements;
+
+            if (isPositiveAndBelow (indexToInsertAt, numUsed))
+            {
+                insertPos += indexToInsertAt;
+                const int numberToMove = numUsed - indexToInsertAt;
+                memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ElementType));
+            }
+            else
+            {
+                insertPos += numUsed;
+            }
+
+            numUsed += numberOfElements;
+
+            while (--numberOfElements >= 0)
+                new (insertPos++) ElementType (*newElements++);
+        }
+    }
+
+    /** Appends a new element at the end of the array as long as the array doesn't
+        already contain it.
+
+        If the array already contains an element that matches the one passed in, nothing
+        will be done.
+
+        @param newElement   the new object to add to the array
+    */
+    void addIfNotAlreadyThere (ParameterType newElement)
+    {
+        const ScopedLockType lock (getLock());
+
+        if (! contains (newElement))
+            add (newElement);
+    }
+
+    /** Replaces an element with a new value.
+
+        If the index is less than zero, this method does nothing.
+        If the index is beyond the end of the array, the item is added to the end of the array.
+
+        @param indexToChange    the index whose value you want to change
+        @param newValue         the new value to set for this index.
+        @see add, insert
+    */
+    void set (const int indexToChange, ParameterType newValue)
+    {
+        jassert (indexToChange >= 0);
+        const ScopedLockType lock (getLock());
+
+        if (isPositiveAndBelow (indexToChange, numUsed))
+        {
+            jassert (data.elements != nullptr);
+            data.elements [indexToChange] = newValue;
+        }
+        else if (indexToChange >= 0)
+        {
+            data.ensureAllocatedSize (numUsed + 1);
+            new (data.elements + numUsed++) ElementType (newValue);
+        }
+    }
+
+    /** Replaces an element with a new value without doing any bounds-checking.
+
+        This just sets a value directly in the array's internal storage, so you'd
+        better make sure it's in range!
+
+        @param indexToChange    the index whose value you want to change
+        @param newValue         the new value to set for this index.
+        @see set, getUnchecked
+    */
+    void setUnchecked (const int indexToChange, ParameterType newValue)
+    {
+        const ScopedLockType lock (getLock());
+        jassert (isPositiveAndBelow (indexToChange, numUsed));
+        data.elements [indexToChange] = newValue;
+    }
+
+    /** Adds elements from an array to the end of this array.
+
+        @param elementsToAdd        an array of some kind of object from which elements
+                                    can be constructed.
+        @param numElementsToAdd     how many elements are in this other array
+        @see add
+    */
+    template <typename Type>
+    void addArray (const Type* elementsToAdd, int numElementsToAdd)
+    {
+        const ScopedLockType lock (getLock());
+
+        if (numElementsToAdd > 0)
+        {
+            data.ensureAllocatedSize (numUsed + numElementsToAdd);
+
+            while (--numElementsToAdd >= 0)
+            {
+                new (data.elements + numUsed) ElementType (*elementsToAdd++);
+                ++numUsed;
+            }
+        }
+    }
+
+    /** Adds elements from a null-terminated array of pointers to the end of this array.
+
+        @param elementsToAdd    an array of pointers to some kind of object from which elements
+                                can be constructed. This array must be terminated by a nullptr
+        @see addArray
+    */
+    template <typename Type>
+    void addNullTerminatedArray (const Type* const* elementsToAdd)
+    {
+        int num = 0;
+        for (const Type* const* e = elementsToAdd; *e != nullptr; ++e)
+            ++num;
+
+        addArray (elementsToAdd, num);
+    }
+
+    /** This swaps the contents of this array with those of another array.
+
+        If you need to exchange two arrays, this is vastly quicker than using copy-by-value
+        because it just swaps their internal pointers.
+    */
+    template <class OtherArrayType>
+    void swapWith (OtherArrayType& otherArray) noexcept
+    {
+        const ScopedLockType lock1 (getLock());
+        const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
+        data.swapWith (otherArray.data);
+        std::swap (numUsed, otherArray.numUsed);
+    }
+
+    /** Adds elements from another array to the end of this array.
+
+        @param arrayToAddFrom       the array from which to copy the elements
+        @param startIndex           the first element of the other array to start copying from
+        @param numElementsToAdd     how many elements to add from the other array. If this
+                                    value is negative or greater than the number of available elements,
+                                    all available elements will be copied.
+        @see add
+    */
+    template <class OtherArrayType>
+    void addArray (const OtherArrayType& arrayToAddFrom,
+                   int startIndex = 0,
+                   int numElementsToAdd = -1)
+    {
+        const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
+
+        {
+            const ScopedLockType lock2 (getLock());
+
+            if (startIndex < 0)
+            {
+                jassertfalse;
+                startIndex = 0;
+            }
+
+            if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
+                numElementsToAdd = arrayToAddFrom.size() - startIndex;
+
+            while (--numElementsToAdd >= 0)
+                add (arrayToAddFrom.getUnchecked (startIndex++));
+        }
+    }
+
+    /** This will enlarge or shrink the array to the given number of elements, by adding
+        or removing items from its end.
+
+        If the array is smaller than the given target size, empty elements will be appended
+        until its size is as specified. If its size is larger than the target, items will be
+        removed from its end to shorten it.
+    */
+    void resize (const int targetNumItems)
+    {
+        jassert (targetNumItems >= 0);
+
+        const int numToAdd = targetNumItems - numUsed;
+        if (numToAdd > 0)
+            insertMultiple (numUsed, ElementType(), numToAdd);
+        else if (numToAdd < 0)
+            removeRange (targetNumItems, -numToAdd);
+    }
+
+    /** Inserts a new element into the array, assuming that the array is sorted.
+
+        This will use a comparator to find the position at which the new element
+        should go. If the array isn't sorted, the behaviour of this
+        method will be unpredictable.
+
+        @param comparator   the comparator to use to compare the elements - see the sort()
+                            method for details about the form this object should take
+        @param newElement   the new element to insert to the array
+        @returns the index at which the new item was added
+        @see addUsingDefaultSort, add, sort
+    */
+    template <class ElementComparator>
+    int addSorted (ElementComparator& comparator, ParameterType newElement)
+    {
+        const ScopedLockType lock (getLock());
+        const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newElement, 0, numUsed);
+        insert (index, newElement);
+        return index;
+    }
+
+    /** Inserts a new element into the array, assuming that the array is sorted.
+
+        This will use the DefaultElementComparator class for sorting, so your ElementType
+        must be suitable for use with that class. If the array isn't sorted, the behaviour of this
+        method will be unpredictable.
+
+        @param newElement   the new element to insert to the array
+        @see addSorted, sort
+    */
+    void addUsingDefaultSort (ParameterType newElement)
+    {
+        DefaultElementComparator <ElementType> comparator;
+        addSorted (comparator, newElement);
+    }
+
+    /** Finds the index of an element in the array, assuming that the array is sorted.
+
+        This will use a comparator to do a binary-chop to find the index of the given
+        element, if it exists. If the array isn't sorted, the behaviour of this
+        method will be unpredictable.
+
+        @param comparator           the comparator to use to compare the elements - see the sort()
+                                    method for details about the form this object should take
+        @param elementToLookFor     the element to search for
+        @returns                    the index of the element, or -1 if it's not found
+        @see addSorted, sort
+    */
+    template <typename ElementComparator, typename TargetValueType>
+    int indexOfSorted (ElementComparator& comparator, TargetValueType elementToLookFor) const
+    {
+        (void) comparator;  // if you pass in an object with a static compareElements() method, this
+                            // avoids getting warning messages about the parameter being unused
+
+        const ScopedLockType lock (getLock());
+
+        for (int s = 0, e = numUsed;;)
+        {
+            if (s >= e)
+                return -1;
+
+            if (comparator.compareElements (elementToLookFor, data.elements [s]) == 0)
+                return s;
+
+            const int halfway = (s + e) / 2;
+            if (halfway == s)
+                return -1;
+
+            if (comparator.compareElements (elementToLookFor, data.elements [halfway]) >= 0)
+                s = halfway;
+            else
+                e = halfway;
+        }
+    }
+
+    //==============================================================================
+    /** Removes an element from the array.
+
+        This will remove the element at a given index, and move back
+        all the subsequent elements to close the gap.
+        If the index passed in is out-of-range, nothing will happen.
+
+        @param indexToRemove    the index of the element to remove
+        @returns                the element that has been removed
+        @see removeFirstMatchingValue, removeAllInstancesOf, removeRange
+    */
+    ElementType remove (const int indexToRemove)
+    {
+        const ScopedLockType lock (getLock());
+
+        if (isPositiveAndBelow (indexToRemove, numUsed))
+        {
+            jassert (data.elements != nullptr);
+            ElementType removed (data.elements[indexToRemove]);
+            removeInternal (indexToRemove);
+            return removed;
+        }
+
+        return ElementType();
+    }
+
+    /** Removes an item from the array.
+
+        This will remove the first occurrence of the given element from the array.
+        If the item isn't found, no action is taken.
+
+        @param valueToRemove   the object to try to remove
+        @see remove, removeRange
+    */
+    void removeFirstMatchingValue (ParameterType valueToRemove)
+    {
+        const ScopedLockType lock (getLock());
+        ElementType* const e = data.elements;
+
+        for (int i = 0; i < numUsed; ++i)
+        {
+            if (valueToRemove == e[i])
+            {
+                removeInternal (i);
+                break;
+            }
+        }
+    }
+
+    /** Removes an item from the array.
+
+        This will remove the first occurrence of the given element from the array.
+        If the item isn't found, no action is taken.
+
+        @param valueToRemove   the object to try to remove
+        @see remove, removeRange
+    */
+    void removeAllInstancesOf (ParameterType valueToRemove)
+    {
+        const ScopedLockType lock (getLock());
+
+        for (int i = numUsed; --i >= 0;)
+            if (valueToRemove == data.elements[i])
+                removeInternal (i);
+    }
+
+    /** Removes a range of elements from the array.
+
+        This will remove a set of elements, starting from the given index,
+        and move subsequent elements down to close the gap.
+
+        If the range extends beyond the bounds of the array, it will
+        be safely clipped to the size of the array.
+
+        @param startIndex       the index of the first element to remove
+        @param numberToRemove   how many elements should be removed
+        @see remove, removeFirstMatchingValue, removeAllInstancesOf
+    */
+    void removeRange (int startIndex, int numberToRemove)
+    {
+        const ScopedLockType lock (getLock());
+        const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove);
+        startIndex = jlimit (0, numUsed, startIndex);
+
+        if (endIndex > startIndex)
+        {
+            ElementType* const e = data.elements + startIndex;
+
+            numberToRemove = endIndex - startIndex;
+            for (int i = 0; i < numberToRemove; ++i)
+                e[i].~ElementType();
+
+            const int numToShift = numUsed - endIndex;
+            if (numToShift > 0)
+                memmove (e, e + numberToRemove, ((size_t) numToShift) * sizeof (ElementType));
+
+            numUsed -= numberToRemove;
+            minimiseStorageAfterRemoval();
+        }
+    }
+
+    /** Removes the last n elements from the array.
+
+        @param howManyToRemove   how many elements to remove from the end of the array
+        @see remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange
+    */
+    void removeLast (int howManyToRemove = 1)
+    {
+        const ScopedLockType lock (getLock());
+
+        if (howManyToRemove > numUsed)
+            howManyToRemove = numUsed;
+
+        for (int i = 1; i <= howManyToRemove; ++i)
+            data.elements [numUsed - i].~ElementType();
+
+        numUsed -= howManyToRemove;
+        minimiseStorageAfterRemoval();
+    }
+
+    /** Removes any elements which are also in another array.
+
+        @param otherArray   the other array in which to look for elements to remove
+        @see removeValuesNotIn, remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange
+    */
+    template <class OtherArrayType>
+    void removeValuesIn (const OtherArrayType& otherArray)
+    {
+        const typename OtherArrayType::ScopedLockType lock1 (otherArray.getLock());
+        const ScopedLockType lock2 (getLock());
+
+        if (this == &otherArray)
+        {
+            clear();
+        }
+        else
+        {
+            if (otherArray.size() > 0)
+            {
+                for (int i = numUsed; --i >= 0;)
+                    if (otherArray.contains (data.elements [i]))
+                        removeInternal (i);
+            }
+        }
+    }
+
+    /** Removes any elements which are not found in another array.
+
+        Only elements which occur in this other array will be retained.
+
+        @param otherArray    the array in which to look for elements NOT to remove
+        @see removeValuesIn, remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange
+    */
+    template <class OtherArrayType>
+    void removeValuesNotIn (const OtherArrayType& otherArray)
+    {
+        const typename OtherArrayType::ScopedLockType lock1 (otherArray.getLock());
+        const ScopedLockType lock2 (getLock());
+
+        if (this != &otherArray)
+        {
+            if (otherArray.size() <= 0)
+            {
+                clear();
+            }
+            else
+            {
+                for (int i = numUsed; --i >= 0;)
+                    if (! otherArray.contains (data.elements [i]))
+                        removeInternal (i);
+            }
+        }
+    }
+
+    /** Swaps over two elements in the array.
+
+        This swaps over the elements found at the two indexes passed in.
+        If either index is out-of-range, this method will do nothing.
+
+        @param index1   index of one of the elements to swap
+        @param index2   index of the other element to swap
+    */
+    void swap (const int index1,
+               const int index2)
+    {
+        const ScopedLockType lock (getLock());
+
+        if (isPositiveAndBelow (index1, numUsed)
+             && isPositiveAndBelow (index2, numUsed))
+        {
+            std::swap (data.elements [index1],
+                       data.elements [index2]);
+        }
+    }
+
+    /** Moves one of the values to a different position.
+
+        This will move the value to a specified index, shuffling along
+        any intervening elements as required.
+
+        So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
+        move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
+
+        @param currentIndex     the index of the value to be moved. If this isn't a
+                                valid index, then nothing will be done
+        @param newIndex         the index at which you'd like this value to end up. If this
+                                is less than zero, the value will be moved to the end
+                                of the array
+    */
+    void move (const int currentIndex, int newIndex) noexcept
+    {
+        if (currentIndex != newIndex)
+        {
+            const ScopedLockType lock (getLock());
+
+            if (isPositiveAndBelow (currentIndex, numUsed))
+            {
+                if (! isPositiveAndBelow (newIndex, numUsed))
+                    newIndex = numUsed - 1;
+
+                char tempCopy [sizeof (ElementType)];
+                memcpy (tempCopy, data.elements + currentIndex, sizeof (ElementType));
+
+                if (newIndex > currentIndex)
+                {
+                    memmove (data.elements + currentIndex,
+                             data.elements + currentIndex + 1,
+                             sizeof (ElementType) * (size_t) (newIndex - currentIndex));
+                }
+                else
+                {
+                    memmove (data.elements + newIndex + 1,
+                             data.elements + newIndex,
+                             sizeof (ElementType) * (size_t) (currentIndex - newIndex));
+                }
+
+                memcpy (data.elements + newIndex, tempCopy, sizeof (ElementType));
+            }
+        }
+    }
+
+    //==============================================================================
+    /** Reduces the amount of storage being used by the array.
+
+        Arrays typically allocate slightly more storage than they need, and after
+        removing elements, they may have quite a lot of unused space allocated.
+        This method will reduce the amount of allocated storage to a minimum.
+    */
+    void minimiseStorageOverheads()
+    {
+        const ScopedLockType lock (getLock());
+        data.shrinkToNoMoreThan (numUsed);
+    }
+
+    /** Increases the array's internal storage to hold a minimum number of elements.
+
+        Calling this before adding a large known number of elements means that
+        the array won't have to keep dynamically resizing itself as the elements
+        are added, and it'll therefore be more efficient.
+    */
+    void ensureStorageAllocated (const int minNumElements)
+    {
+        const ScopedLockType lock (getLock());
+        data.ensureAllocatedSize (minNumElements);
+    }
+
+    //==============================================================================
+    /** Sorts the elements in the array.
+
+        This will use a comparator object to sort the elements into order. The object
+        passed must have a method of the form:
+        @code
+        int compareElements (ElementType first, ElementType second);
+        @endcode
+
+        ..and this method must return:
+          - a value of < 0 if the first comes before the second
+          - a value of 0 if the two objects are equivalent
+          - a value of > 0 if the second comes before the first
+
+        To improve performance, the compareElements() method can be declared as static or const.
+
+        @param comparator   the comparator to use for comparing elements.
+        @param retainOrderOfEquivalentItems     if this is true, then items
+                            which the comparator says are equivalent will be
+                            kept in the order in which they currently appear
+                            in the array. This is slower to perform, but may
+                            be important in some cases. If it's false, a faster
+                            algorithm is used, but equivalent elements may be
+                            rearranged.
+
+        @see addSorted, indexOfSorted, sortArray
+    */
+    template <class ElementComparator>
+    void sort (ElementComparator& comparator,
+               const bool retainOrderOfEquivalentItems = false) const
+    {
+        const ScopedLockType lock (getLock());
+        (void) comparator;  // if you pass in an object with a static compareElements() method, this
+                            // avoids getting warning messages about the parameter being unused
+        sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
+    }
+
+    //==============================================================================
+    /** Returns the CriticalSection that locks this array.
+        To lock, you can call getLock().enter() and getLock().exit(), or preferably use
+        an object of ScopedLockType as an RAII lock for it.
+    */
+    inline const TypeOfCriticalSectionToUse& getLock() const noexcept      { return data; }
+
+    /** Returns the type of scoped lock to use for locking this array */
+    typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
+
+
+    //==============================================================================
+   #ifndef DOXYGEN
+    // Note that the swapWithArray method has been replaced by a more flexible templated version,
+    // and renamed "swapWith" to be more consistent with the names used in other classes.
+    JUCE_DEPRECATED_WITH_BODY (void swapWithArray (Array& other) noexcept, { swapWith (other); })
+   #endif
+
+private:
+    //==============================================================================
+    ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse> data;
+    int numUsed;
+
+    void removeInternal (const int indexToRemove)
+    {
+        --numUsed;
+        ElementType* const e = data.elements + indexToRemove;
+        e->~ElementType();
+        const int numberToShift = numUsed - indexToRemove;
+
+        if (numberToShift > 0)
+            memmove (e, e + 1, ((size_t) numberToShift) * sizeof (ElementType));
+
+        minimiseStorageAfterRemoval();
+    }
+
+    inline void deleteAllElements() noexcept
+    {
+        for (int i = 0; i < numUsed; ++i)
+            data.elements[i].~ElementType();
+    }
+
+    void minimiseStorageAfterRemoval()
+    {
+        if (data.numAllocated > jmax (minimumAllocatedSize, numUsed * 2))
+            data.shrinkToNoMoreThan (jmax (numUsed, jmax (minimumAllocatedSize, 64 / (int) sizeof (ElementType))));
+    }
+};
+
+
+#endif   // JUCE_ARRAY_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ArrayAllocationBase.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ArrayAllocationBase.h
new file mode 100644
index 0000000..cfbe464
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ArrayAllocationBase.h
@@ -0,0 +1,138 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_ARRAYALLOCATIONBASE_H_INCLUDED
+#define JUCE_ARRAYALLOCATIONBASE_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Implements some basic array storage allocation functions.
+
+    This class isn't really for public use - it's used by the other
+    array classes, but might come in handy for some purposes.
+
+    It inherits from a critical section class to allow the arrays to use
+    the "empty base class optimisation" pattern to reduce their footprint.
+
+    @see Array, OwnedArray, ReferenceCountedArray
+*/
+template <class ElementType, class TypeOfCriticalSectionToUse>
+class ArrayAllocationBase  : public TypeOfCriticalSectionToUse
+{
+public:
+    //==============================================================================
+    /** Creates an empty array. */
+    ArrayAllocationBase() noexcept
+        : numAllocated (0)
+    {
+    }
+
+    /** Destructor. */
+    ~ArrayAllocationBase() noexcept
+    {
+    }
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    ArrayAllocationBase (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
+        : elements (static_cast <HeapBlock <ElementType>&&> (other.elements)),
+          numAllocated (other.numAllocated)
+    {
+    }
+
+    ArrayAllocationBase& operator= (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
+    {
+        elements = static_cast <HeapBlock <ElementType>&&> (other.elements);
+        numAllocated = other.numAllocated;
+        return *this;
+    }
+   #endif
+
+    //==============================================================================
+    /** Changes the amount of storage allocated.
+
+        This will retain any data currently held in the array, and either add or
+        remove extra space at the end.
+
+        @param numElements  the number of elements that are needed
+    */
+    void setAllocatedSize (const int numElements)
+    {
+        if (numAllocated != numElements)
+        {
+            if (numElements > 0)
+                elements.realloc ((size_t) numElements);
+            else
+                elements.free();
+
+            numAllocated = numElements;
+        }
+    }
+
+    /** Increases the amount of storage allocated if it is less than a given amount.
+
+        This will retain any data currently held in the array, but will add
+        extra space at the end to make sure there it's at least as big as the size
+        passed in. If it's already bigger, no action is taken.
+
+        @param minNumElements  the minimum number of elements that are needed
+    */
+    void ensureAllocatedSize (const int minNumElements)
+    {
+        if (minNumElements > numAllocated)
+            setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
+
+        jassert (numAllocated <= 0 || elements != nullptr);
+    }
+
+    /** Minimises the amount of storage allocated so that it's no more than
+        the given number of elements.
+    */
+    void shrinkToNoMoreThan (const int maxNumElements)
+    {
+        if (maxNumElements < numAllocated)
+            setAllocatedSize (maxNumElements);
+    }
+
+    /** Swap the contents of two objects. */
+    void swapWith (ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse>& other) noexcept
+    {
+        elements.swapWith (other.elements);
+        std::swap (numAllocated, other.numAllocated);
+    }
+
+    //==============================================================================
+    HeapBlock <ElementType> elements;
+    int numAllocated;
+
+private:
+    JUCE_DECLARE_NON_COPYABLE (ArrayAllocationBase)
+};
+
+
+#endif   // JUCE_ARRAYALLOCATIONBASE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_DynamicObject.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_DynamicObject.cpp
new file mode 100644
index 0000000..38f5c5f
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_DynamicObject.cpp
@@ -0,0 +1,133 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+DynamicObject::DynamicObject()
+{
+}
+
+DynamicObject::DynamicObject (const DynamicObject& other)
+   : ReferenceCountedObject(), properties (other.properties)
+{
+}
+
+DynamicObject::~DynamicObject()
+{
+}
+
+bool DynamicObject::hasProperty (const Identifier& propertyName) const
+{
+    const var* const v = properties.getVarPointer (propertyName);
+    return v != nullptr && ! v->isMethod();
+}
+
+var DynamicObject::getProperty (const Identifier& propertyName) const
+{
+    return properties [propertyName];
+}
+
+void DynamicObject::setProperty (const Identifier& propertyName, const var& newValue)
+{
+    properties.set (propertyName, newValue);
+}
+
+void DynamicObject::removeProperty (const Identifier& propertyName)
+{
+    properties.remove (propertyName);
+}
+
+bool DynamicObject::hasMethod (const Identifier& methodName) const
+{
+    return getProperty (methodName).isMethod();
+}
+
+var DynamicObject::invokeMethod (Identifier method, const var::NativeFunctionArgs& args)
+{
+    if (var::NativeFunction function = properties [method].getNativeFunction())
+        return function (args);
+
+    return var();
+}
+
+void DynamicObject::setMethod (Identifier name, var::NativeFunction function)
+{
+    properties.set (name, var (function));
+}
+
+void DynamicObject::clear()
+{
+    properties.clear();
+}
+
+void DynamicObject::cloneAllProperties()
+{
+    for (int i = properties.size(); --i >= 0;)
+        if (var* v = properties.getVarPointerAt (i))
+            *v = v->clone();
+}
+
+DynamicObject::Ptr DynamicObject::clone()
+{
+    Ptr d (new DynamicObject (*this));
+    d->cloneAllProperties();
+    return d;
+}
+
+void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const bool allOnOneLine)
+{
+    out << '{';
+    if (! allOnOneLine)
+        out << newLine;
+
+    const int numValues = properties.size();
+
+    for (int i = 0; i < numValues; ++i)
+    {
+        if (! allOnOneLine)
+            JSONFormatter::writeSpaces (out, indentLevel + JSONFormatter::indentSize);
+
+        out << '"';
+        JSONFormatter::writeString (out, properties.getName (i));
+        out << "\": ";
+        JSONFormatter::write (out, properties.getValueAt (i), indentLevel + JSONFormatter::indentSize, allOnOneLine);
+
+        if (i < numValues - 1)
+        {
+            if (allOnOneLine)
+                out << ", ";
+            else
+                out << ',' << newLine;
+        }
+        else if (! allOnOneLine)
+            out << newLine;
+    }
+
+    if (! allOnOneLine)
+        JSONFormatter::writeSpaces (out, indentLevel);
+
+    out << '}';
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_DynamicObject.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_DynamicObject.h
new file mode 100644
index 0000000..5c624a4
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_DynamicObject.h
@@ -0,0 +1,139 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_DYNAMICOBJECT_H_INCLUDED
+#define JUCE_DYNAMICOBJECT_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Represents a dynamically implemented object.
+
+    This class is primarily intended for wrapping scripting language objects,
+    but could be used for other purposes.
+
+    An instance of a DynamicObject can be used to store named properties, and
+    by subclassing hasMethod() and invokeMethod(), you can give your object
+    methods.
+*/
+class JUCE_API  DynamicObject  : public ReferenceCountedObject
+{
+public:
+    //==============================================================================
+    DynamicObject();
+    DynamicObject (const DynamicObject&);
+    ~DynamicObject();
+
+    typedef ReferenceCountedObjectPtr<DynamicObject> Ptr;
+
+    //==============================================================================
+    /** Returns true if the object has a property with this name.
+        Note that if the property is actually a method, this will return false.
+    */
+    virtual bool hasProperty (const Identifier& propertyName) const;
+
+    /** Returns a named property.
+        This returns var::null if no such property exists.
+    */
+    virtual var getProperty (const Identifier& propertyName) const;
+
+    /** Sets a named property. */
+    virtual void setProperty (const Identifier& propertyName, const var& newValue);
+
+    /** Removes a named property. */
+    virtual void removeProperty (const Identifier& propertyName);
+
+    //==============================================================================
+    /** Checks whether this object has the specified method.
+
+        The default implementation of this just checks whether there's a property
+        with this name that's actually a method, but this can be overridden for
+        building objects with dynamic invocation.
+    */
+    virtual bool hasMethod (const Identifier& methodName) const;
+
+    /** Invokes a named method on this object.
+
+        The default implementation looks up the named property, and if it's a method
+        call, then it invokes it.
+
+        This method is virtual to allow more dynamic invocation to used for objects
+        where the methods may not already be set as properies.
+    */
+    virtual var invokeMethod (Identifier methodName,
+                              const var::NativeFunctionArgs& args);
+
+    /** Adds a method to the class.
+
+        This is basically the same as calling setProperty (methodName, (var::NativeFunction) myFunction), but
+        helps to avoid accidentally invoking the wrong type of var constructor. It also makes
+        the code easier to read,
+    */
+    void setMethod (Identifier methodName, var::NativeFunction function);
+
+    //==============================================================================
+    /** Removes all properties and methods from the object. */
+    void clear();
+
+    /** Returns the NamedValueSet that holds the object's properties. */
+    NamedValueSet& getProperties() noexcept     { return properties; }
+
+    /** Calls var::clone() on all the properties that this object contains. */
+    void cloneAllProperties();
+
+    //==============================================================================
+    /** Returns a clone of this object.
+        The default implementation of this method just returns a new DynamicObject
+        with a (deep) copy of all of its properties. Subclasses can override this to
+        implement their own custom copy routines.
+    */
+    virtual Ptr clone();
+
+    //==============================================================================
+    /** Writes this object to a text stream in JSON format.
+        This method is used by JSON::toString and JSON::writeToStream, and you should
+        never need to call it directly, but it's virtual so that custom object types
+        can stringify themselves appropriately.
+    */
+    virtual void writeAsJSON (OutputStream&, int indentLevel, bool allOnOneLine);
+
+private:
+    //==============================================================================
+    NamedValueSet properties;
+
+   #if JUCE_CATCH_DEPRECATED_CODE_MISUSE
+    // These methods have been deprecated - use var::invoke instead
+    virtual void invokeMethod (const Identifier&, const var*, int) {}
+   #endif
+
+    JUCE_LEAK_DETECTOR (DynamicObject)
+};
+
+
+
+#endif   // JUCE_DYNAMICOBJECT_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ElementComparator.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ElementComparator.h
new file mode 100644
index 0000000..01dc5b7
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ElementComparator.h
@@ -0,0 +1,195 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_ELEMENTCOMPARATOR_H_INCLUDED
+#define JUCE_ELEMENTCOMPARATOR_H_INCLUDED
+
+#ifndef DOXYGEN
+
+/** This is an internal helper class which converts a juce ElementComparator style
+    class (using a "compareElements" method) into a class that's compatible with
+    std::sort (i.e. using an operator() to compare the elements)
+*/
+template <typename ElementComparator>
+struct SortFunctionConverter
+{
+    SortFunctionConverter (ElementComparator& e) : comparator (e) {}
+
+    template <typename Type>
+    bool operator() (Type a, Type b)  { return comparator.compareElements (a, b) < 0; }
+
+private:
+    ElementComparator& comparator;
+    SortFunctionConverter& operator= (const SortFunctionConverter&) JUCE_DELETED_FUNCTION;
+};
+
+#endif
+
+
+//==============================================================================
+/**
+    Sorts a range of elements in an array.
+
+    The comparator object that is passed-in must define a public method with the following
+    signature:
+    @code
+    int compareElements (ElementType first, ElementType second);
+    @endcode
+
+    ..and this method must return:
+      - a value of < 0 if the first comes before the second
+      - a value of 0 if the two objects are equivalent
+      - a value of > 0 if the second comes before the first
+
+    To improve performance, the compareElements() method can be declared as static or const.
+
+    @param comparator       an object which defines a compareElements() method
+    @param array            the array to sort
+    @param firstElement     the index of the first element of the range to be sorted
+    @param lastElement      the index of the last element in the range that needs
+                            sorting (this is inclusive)
+    @param retainOrderOfEquivalentItems     if true, the order of items that the
+                            comparator deems the same will be maintained - this will be
+                            a slower algorithm than if they are allowed to be moved around.
+
+    @see sortArrayRetainingOrder
+*/
+template <class ElementType, class ElementComparator>
+static void sortArray (ElementComparator& comparator,
+                       ElementType* const array,
+                       int firstElement,
+                       int lastElement,
+                       const bool retainOrderOfEquivalentItems)
+{
+    SortFunctionConverter<ElementComparator> converter (comparator);
+
+    if (retainOrderOfEquivalentItems)
+        std::stable_sort (array + firstElement, array + lastElement + 1, converter);
+    else
+        std::sort        (array + firstElement, array + lastElement + 1, converter);
+}
+
+
+//==============================================================================
+/**
+    Searches a sorted array of elements, looking for the index at which a specified value
+    should be inserted for it to be in the correct order.
+
+    The comparator object that is passed-in must define a public method with the following
+    signature:
+    @code
+    int compareElements (ElementType first, ElementType second);
+    @endcode
+
+    ..and this method must return:
+      - a value of < 0 if the first comes before the second
+      - a value of 0 if the two objects are equivalent
+      - a value of > 0 if the second comes before the first
+
+    To improve performance, the compareElements() method can be declared as static or const.
+
+    @param comparator       an object which defines a compareElements() method
+    @param array            the array to search
+    @param newElement       the value that is going to be inserted
+    @param firstElement     the index of the first element to search
+    @param lastElement      the index of the last element in the range (this is non-inclusive)
+*/
+template <class ElementType, class ElementComparator>
+static int findInsertIndexInSortedArray (ElementComparator& comparator,
+                                         ElementType* const array,
+                                         const ElementType newElement,
+                                         int firstElement,
+                                         int lastElement)
+{
+    jassert (firstElement <= lastElement);
+
+    (void) comparator;  // if you pass in an object with a static compareElements() method, this
+                        // avoids getting warning messages about the parameter being unused
+
+    while (firstElement < lastElement)
+    {
+        if (comparator.compareElements (newElement, array [firstElement]) == 0)
+        {
+            ++firstElement;
+            break;
+        }
+        else
+        {
+            const int halfway = (firstElement + lastElement) >> 1;
+
+            if (halfway == firstElement)
+            {
+                if (comparator.compareElements (newElement, array [halfway]) >= 0)
+                    ++firstElement;
+
+                break;
+            }
+            else if (comparator.compareElements (newElement, array [halfway]) >= 0)
+            {
+                firstElement = halfway;
+            }
+            else
+            {
+                lastElement = halfway;
+            }
+        }
+    }
+
+    return firstElement;
+}
+
+//==============================================================================
+/**
+    A simple ElementComparator class that can be used to sort an array of
+    objects that support the '<' operator.
+
+    This will work for primitive types and objects that implement operator<().
+
+    Example: @code
+    Array <int> myArray;
+    DefaultElementComparator<int> sorter;
+    myArray.sort (sorter);
+    @endcode
+
+    @see ElementComparator
+*/
+template <class ElementType>
+class DefaultElementComparator
+{
+private:
+    typedef PARAMETER_TYPE (ElementType) ParameterType;
+
+public:
+    static int compareElements (ParameterType first, ParameterType second)
+    {
+        return (first < second) ? -1 : ((second < first) ? 1 : 0);
+    }
+};
+
+
+#endif   // JUCE_ELEMENTCOMPARATOR_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_HashMap.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_HashMap.h
new file mode 100644
index 0000000..07d02b4
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_HashMap.h
@@ -0,0 +1,455 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_HASHMAP_H_INCLUDED
+#define JUCE_HASHMAP_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A simple class to generate hash functions for some primitive types, intended for
+    use with the HashMap class.
+    @see HashMap
+*/
+struct DefaultHashFunctions
+{
+    /** Generates a simple hash from an integer. */
+    int generateHash (const int key, const int upperLimit) const noexcept        { return std::abs (key) % upperLimit; }
+    /** Generates a simple hash from an int64. */
+    int generateHash (const int64 key, const int upperLimit) const noexcept      { return std::abs ((int) key) % upperLimit; }
+    /** Generates a simple hash from a string. */
+    int generateHash (const String& key, const int upperLimit) const noexcept    { return (int) (((uint32) key.hashCode()) % (uint32) upperLimit); }
+    /** Generates a simple hash from a variant. */
+    int generateHash (const var& key, const int upperLimit) const noexcept       { return generateHash (key.toString(), upperLimit); }
+};
+
+
+//==============================================================================
+/**
+    Holds a set of mappings between some key/value pairs.
+
+    The types of the key and value objects are set as template parameters.
+    You can also specify a class to supply a hash function that converts a key value
+    into an hashed integer. This class must have the form:
+
+    @code
+    struct MyHashGenerator
+    {
+        int generateHash (MyKeyType key, int upperLimit) const
+        {
+            // The function must return a value 0 <= x < upperLimit
+            return someFunctionOfMyKeyType (key) % upperLimit;
+        }
+    };
+    @endcode
+
+    Like the Array class, the key and value types are expected to be copy-by-value
+    types, so if you define them to be pointer types, this class won't delete the
+    objects that they point to.
+
+    If you don't supply a class for the HashFunctionType template parameter, the
+    default one provides some simple mappings for strings and ints.
+
+    @code
+    HashMap<int, String> hash;
+    hash.set (1, "item1");
+    hash.set (2, "item2");
+
+    DBG (hash [1]); // prints "item1"
+    DBG (hash [2]); // prints "item2"
+
+    // This iterates the map, printing all of its key -> value pairs..
+    for (HashMap<int, String>::Iterator i (hash); i.next();)
+        DBG (i.getKey() << " -> " << i.getValue());
+    @endcode
+
+    @tparam HashFunctionType The class of hash function, which must be copy-constructible.
+    @see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
+*/
+template <typename KeyType,
+          typename ValueType,
+          class HashFunctionType = DefaultHashFunctions,
+          class TypeOfCriticalSectionToUse = DummyCriticalSection>
+class HashMap
+{
+private:
+    typedef PARAMETER_TYPE (KeyType)   KeyTypeParameter;
+    typedef PARAMETER_TYPE (ValueType) ValueTypeParameter;
+
+public:
+    //==============================================================================
+    /** Creates an empty hash-map.
+
+        @param numberOfSlots Specifies the number of hash entries the map will use. This will be
+                            the "upperLimit" parameter that is passed to your generateHash()
+                            function. The number of hash slots will grow automatically if necessary,
+                            or it can be remapped manually using remapTable().
+        @param hashFunction An instance of HashFunctionType, which will be copied and
+                            stored to use with the HashMap. This parameter can be omitted
+                            if HashFunctionType has a default constructor.
+    */
+    explicit HashMap (int numberOfSlots = defaultHashTableSize,
+                      HashFunctionType hashFunction = HashFunctionType())
+       : hashFunctionToUse (hashFunction), totalNumItems (0)
+    {
+        hashSlots.insertMultiple (0, nullptr, numberOfSlots);
+    }
+
+    /** Destructor. */
+    ~HashMap()
+    {
+        clear();
+    }
+
+    //==============================================================================
+    /** Removes all values from the map.
+        Note that this will clear the content, but won't affect the number of slots (see
+        remapTable and getNumSlots).
+    */
+    void clear()
+    {
+        const ScopedLockType sl (getLock());
+
+        for (int i = hashSlots.size(); --i >= 0;)
+        {
+            HashEntry* h = hashSlots.getUnchecked(i);
+
+            while (h != nullptr)
+            {
+                const ScopedPointer<HashEntry> deleter (h);
+                h = h->nextEntry;
+            }
+
+            hashSlots.set (i, nullptr);
+        }
+
+        totalNumItems = 0;
+    }
+
+    //==============================================================================
+    /** Returns the current number of items in the map. */
+    inline int size() const noexcept
+    {
+        return totalNumItems;
+    }
+
+    /** Returns the value corresponding to a given key.
+        If the map doesn't contain the key, a default instance of the value type is returned.
+        @param keyToLookFor    the key of the item being requested
+    */
+    inline ValueType operator[] (KeyTypeParameter keyToLookFor) const
+    {
+        const ScopedLockType sl (getLock());
+
+        for (const HashEntry* entry = hashSlots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
+            if (entry->key == keyToLookFor)
+                return entry->value;
+
+        return ValueType();
+    }
+
+    //==============================================================================
+    /** Returns true if the map contains an item with the specied key. */
+    bool contains (KeyTypeParameter keyToLookFor) const
+    {
+        const ScopedLockType sl (getLock());
+
+        for (const HashEntry* entry = hashSlots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
+            if (entry->key == keyToLookFor)
+                return true;
+
+        return false;
+    }
+
+    /** Returns true if the hash contains at least one occurrence of a given value. */
+    bool containsValue (ValueTypeParameter valueToLookFor) const
+    {
+        const ScopedLockType sl (getLock());
+
+        for (int i = getNumSlots(); --i >= 0;)
+            for (const HashEntry* entry = hashSlots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
+                if (entry->value == valueToLookFor)
+                    return true;
+
+        return false;
+    }
+
+    //==============================================================================
+    /** Adds or replaces an element in the hash-map.
+        If there's already an item with the given key, this will replace its value. Otherwise, a new item
+        will be added to the map.
+    */
+    void set (KeyTypeParameter newKey, ValueTypeParameter newValue)
+    {
+        const ScopedLockType sl (getLock());
+        const int hashIndex = generateHashFor (newKey);
+
+        HashEntry* const firstEntry = hashSlots.getUnchecked (hashIndex);
+
+        for (HashEntry* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
+        {
+            if (entry->key == newKey)
+            {
+                entry->value = newValue;
+                return;
+            }
+        }
+
+        hashSlots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
+        ++totalNumItems;
+
+        if (totalNumItems > (getNumSlots() * 3) / 2)
+            remapTable (getNumSlots() * 2);
+    }
+
+    /** Removes an item with the given key. */
+    void remove (KeyTypeParameter keyToRemove)
+    {
+        const ScopedLockType sl (getLock());
+        const int hashIndex = generateHashFor (keyToRemove);
+        HashEntry* entry = hashSlots.getUnchecked (hashIndex);
+        HashEntry* previous = nullptr;
+
+        while (entry != nullptr)
+        {
+            if (entry->key == keyToRemove)
+            {
+                const ScopedPointer<HashEntry> deleter (entry);
+
+                entry = entry->nextEntry;
+
+                if (previous != nullptr)
+                    previous->nextEntry = entry;
+                else
+                    hashSlots.set (hashIndex, entry);
+
+                --totalNumItems;
+            }
+            else
+            {
+                previous = entry;
+                entry = entry->nextEntry;
+            }
+        }
+    }
+
+    /** Removes all items with the given value. */
+    void removeValue (ValueTypeParameter valueToRemove)
+    {
+        const ScopedLockType sl (getLock());
+
+        for (int i = getNumSlots(); --i >= 0;)
+        {
+            HashEntry* entry = hashSlots.getUnchecked(i);
+            HashEntry* previous = nullptr;
+
+            while (entry != nullptr)
+            {
+                if (entry->value == valueToRemove)
+                {
+                    const ScopedPointer<HashEntry> deleter (entry);
+
+                    entry = entry->nextEntry;
+
+                    if (previous != nullptr)
+                        previous->nextEntry = entry;
+                    else
+                        hashSlots.set (i, entry);
+
+                    --totalNumItems;
+                }
+                else
+                {
+                    previous = entry;
+                    entry = entry->nextEntry;
+                }
+            }
+        }
+    }
+
+    /** Remaps the hash-map to use a different number of slots for its hash function.
+        Each slot corresponds to a single hash-code, and each one can contain multiple items.
+        @see getNumSlots()
+    */
+    void remapTable (int newNumberOfSlots)
+    {
+        HashMap newTable (newNumberOfSlots);
+
+        for (int i = getNumSlots(); --i >= 0;)
+            for (const HashEntry* entry = hashSlots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
+                newTable.set (entry->key, entry->value);
+
+        swapWith (newTable);
+    }
+
+    /** Returns the number of slots which are available for hashing.
+        Each slot corresponds to a single hash-code, and each one can contain multiple items.
+        @see getNumSlots()
+    */
+    inline int getNumSlots() const noexcept
+    {
+        return hashSlots.size();
+    }
+
+    //==============================================================================
+    /** Efficiently swaps the contents of two hash-maps. */
+    template <class OtherHashMapType>
+    void swapWith (OtherHashMapType& otherHashMap) noexcept
+    {
+        const ScopedLockType lock1 (getLock());
+        const typename OtherHashMapType::ScopedLockType lock2 (otherHashMap.getLock());
+
+        hashSlots.swapWith (otherHashMap.hashSlots);
+        std::swap (totalNumItems, otherHashMap.totalNumItems);
+    }
+
+    //==============================================================================
+    /** Returns the CriticalSection that locks this structure.
+        To lock, you can call getLock().enter() and getLock().exit(), or preferably use
+        an object of ScopedLockType as an RAII lock for it.
+    */
+    inline const TypeOfCriticalSectionToUse& getLock() const noexcept      { return lock; }
+
+    /** Returns the type of scoped lock to use for locking this array */
+    typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
+
+private:
+    //==============================================================================
+    class HashEntry
+    {
+    public:
+        HashEntry (KeyTypeParameter k, ValueTypeParameter val, HashEntry* const next)
+            : key (k), value (val), nextEntry (next)
+        {}
+
+        const KeyType key;
+        ValueType value;
+        HashEntry* nextEntry;
+
+        JUCE_DECLARE_NON_COPYABLE (HashEntry)
+    };
+
+public:
+    //==============================================================================
+    /** Iterates over the items in a HashMap.
+
+        To use it, repeatedly call next() until it returns false, e.g.
+        @code
+        HashMap <String, String> myMap;
+
+        HashMap<String, String>::Iterator i (myMap);
+
+        while (i.next())
+        {
+            DBG (i.getKey() << " -> " << i.getValue());
+        }
+        @endcode
+
+        The order in which items are iterated bears no resemblence to the order in which
+        they were originally added!
+
+        Obviously as soon as you call any non-const methods on the original hash-map, any
+        iterators that were created beforehand will cease to be valid, and should not be used.
+
+        @see HashMap
+    */
+    class Iterator
+    {
+    public:
+        //==============================================================================
+        Iterator (const HashMap& hashMapToIterate)
+            : hashMap (hashMapToIterate), entry (nullptr), index (0)
+        {}
+
+        /** Moves to the next item, if one is available.
+            When this returns true, you can get the item's key and value using getKey() and
+            getValue(). If it returns false, the iteration has finished and you should stop.
+        */
+        bool next()
+        {
+            if (entry != nullptr)
+                entry = entry->nextEntry;
+
+            while (entry == nullptr)
+            {
+                if (index >= hashMap.getNumSlots())
+                    return false;
+
+                entry = hashMap.hashSlots.getUnchecked (index++);
+            }
+
+            return true;
+        }
+
+        /** Returns the current item's key.
+            This should only be called when a call to next() has just returned true.
+        */
+        KeyType getKey() const
+        {
+            return entry != nullptr ? entry->key : KeyType();
+        }
+
+        /** Returns the current item's value.
+            This should only be called when a call to next() has just returned true.
+        */
+        ValueType getValue() const
+        {
+            return entry != nullptr ? entry->value : ValueType();
+        }
+
+    private:
+        //==============================================================================
+        const HashMap& hashMap;
+        HashEntry* entry;
+        int index;
+
+        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Iterator)
+    };
+
+private:
+    //==============================================================================
+    enum { defaultHashTableSize = 101 };
+    friend class Iterator;
+
+    HashFunctionType hashFunctionToUse;
+    Array<HashEntry*> hashSlots;
+    int totalNumItems;
+    TypeOfCriticalSectionToUse lock;
+
+    int generateHashFor (KeyTypeParameter key) const
+    {
+        const int hash = hashFunctionToUse.generateHash (key, getNumSlots());
+        jassert (isPositiveAndBelow (hash, getNumSlots())); // your hash function is generating out-of-range numbers!
+        return hash;
+    }
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HashMap)
+};
+
+
+#endif   // JUCE_HASHMAP_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_LinkedListPointer.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_LinkedListPointer.h
new file mode 100644
index 0000000..a27e521
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_LinkedListPointer.h
@@ -0,0 +1,371 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_LINKEDLISTPOINTER_H_INCLUDED
+#define JUCE_LINKEDLISTPOINTER_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Helps to manipulate singly-linked lists of objects.
+
+    For objects that are designed to contain a pointer to the subsequent item in the
+    list, this class contains methods to deal with the list. To use it, the ObjectType
+    class that it points to must contain a LinkedListPointer called nextListItem, e.g.
+
+    @code
+    struct MyObject
+    {
+        int x, y, z;
+
+        // A linkable object must contain a member with this name and type, which must be
+        // accessible by the LinkedListPointer class. (This doesn't mean it has to be public -
+        // you could make your class a friend of a LinkedListPointer<MyObject> instead).
+        LinkedListPointer<MyObject> nextListItem;
+    };
+
+    LinkedListPointer<MyObject> myList;
+    myList.append (new MyObject());
+    myList.append (new MyObject());
+
+    int numItems = myList.size(); // returns 2
+    MyObject* lastInList = myList.getLast();
+    @endcode
+*/
+template <class ObjectType>
+class LinkedListPointer
+{
+public:
+    //==============================================================================
+    /** Creates a null pointer to an empty list. */
+    LinkedListPointer() noexcept
+        : item (nullptr)
+    {
+    }
+
+    /** Creates a pointer to a list whose head is the item provided. */
+    explicit LinkedListPointer (ObjectType* const headItem) noexcept
+        : item (headItem)
+    {
+    }
+
+    /** Sets this pointer to point to a new list. */
+    LinkedListPointer& operator= (ObjectType* const newItem) noexcept
+    {
+        item = newItem;
+        return *this;
+    }
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    LinkedListPointer (LinkedListPointer&& other) noexcept
+        : item (other.item)
+    {
+        other.item = nullptr;
+    }
+
+    LinkedListPointer& operator= (LinkedListPointer&& other) noexcept
+    {
+        jassert (this != &other); // hopefully the compiler should make this situation impossible!
+
+        item = other.item;
+        other.item = nullptr;
+        return *this;
+    }
+   #endif
+
+    //==============================================================================
+    /** Returns the item which this pointer points to. */
+    inline operator ObjectType*() const noexcept
+    {
+        return item;
+    }
+
+    /** Returns the item which this pointer points to. */
+    inline ObjectType* get() const noexcept
+    {
+        return item;
+    }
+
+    /** Returns the last item in the list which this pointer points to.
+        This will iterate the list and return the last item found. Obviously the speed
+        of this operation will be proportional to the size of the list. If the list is
+        empty the return value will be this object.
+        If you're planning on appending a number of items to your list, it's much more
+        efficient to use the Appender class than to repeatedly call getLast() to find the end.
+    */
+    LinkedListPointer& getLast() noexcept
+    {
+        LinkedListPointer* l = this;
+
+        while (l->item != nullptr)
+            l = &(l->item->nextListItem);
+
+        return *l;
+    }
+
+    /** Returns the number of items in the list.
+        Obviously with a simple linked list, getting the size involves iterating the list, so
+        this can be a lengthy operation - be careful when using this method in your code.
+    */
+    int size() const noexcept
+    {
+        int total = 0;
+
+        for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
+            ++total;
+
+        return total;
+    }
+
+    /** Returns the item at a given index in the list.
+        Since the only way to find an item is to iterate the list, this operation can obviously
+        be slow, depending on its size, so you should be careful when using this in algorithms.
+    */
+    LinkedListPointer& operator[] (int index) noexcept
+    {
+        LinkedListPointer* l = this;
+
+        while (--index >= 0 && l->item != nullptr)
+            l = &(l->item->nextListItem);
+
+        return *l;
+    }
+
+    /** Returns the item at a given index in the list.
+        Since the only way to find an item is to iterate the list, this operation can obviously
+        be slow, depending on its size, so you should be careful when using this in algorithms.
+    */
+    const LinkedListPointer& operator[] (int index) const noexcept
+    {
+        const LinkedListPointer* l = this;
+
+        while (--index >= 0 && l->item != nullptr)
+            l = &(l->item->nextListItem);
+
+        return *l;
+    }
+
+    /** Returns true if the list contains the given item. */
+    bool contains (const ObjectType* const itemToLookFor) const noexcept
+    {
+        for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
+            if (itemToLookFor == i)
+                return true;
+
+        return false;
+    }
+
+    //==============================================================================
+    /** Inserts an item into the list, placing it before the item that this pointer
+        currently points to.
+    */
+    void insertNext (ObjectType* const newItem)
+    {
+        jassert (newItem != nullptr);
+        jassert (newItem->nextListItem == nullptr);
+        newItem->nextListItem = item;
+        item = newItem;
+    }
+
+    /** Inserts an item at a numeric index in the list.
+        Obviously this will involve iterating the list to find the item at the given index,
+        so be careful about the impact this may have on execution time.
+    */
+    void insertAtIndex (int index, ObjectType* newItem)
+    {
+        jassert (newItem != nullptr);
+        LinkedListPointer* l = this;
+
+        while (index != 0 && l->item != nullptr)
+        {
+            l = &(l->item->nextListItem);
+            --index;
+        }
+
+        l->insertNext (newItem);
+    }
+
+    /** Replaces the object that this pointer points to, appending the rest of the list to
+        the new object, and returning the old one.
+    */
+    ObjectType* replaceNext (ObjectType* const newItem) noexcept
+    {
+        jassert (newItem != nullptr);
+        jassert (newItem->nextListItem == nullptr);
+
+        ObjectType* const oldItem = item;
+        item = newItem;
+        item->nextListItem = oldItem->nextListItem.item;
+        oldItem->nextListItem.item = nullptr;
+        return oldItem;
+    }
+
+    /** Adds an item to the end of the list.
+
+        This operation involves iterating the whole list, so can be slow - if you need to
+        append a number of items to your list, it's much more efficient to use the Appender
+        class than to repeatedly call append().
+    */
+    void append (ObjectType* const newItem)
+    {
+        getLast().item = newItem;
+    }
+
+    /** Creates copies of all the items in another list and adds them to this one.
+        This will use the ObjectType's copy constructor to try to create copies of each
+        item in the other list, and appends them to this list.
+    */
+    void addCopyOfList (const LinkedListPointer& other)
+    {
+        LinkedListPointer* insertPoint = this;
+
+        for (ObjectType* i = other.item; i != nullptr; i = i->nextListItem)
+        {
+            insertPoint->insertNext (new ObjectType (*i));
+            insertPoint = &(insertPoint->item->nextListItem);
+        }
+    }
+
+    /** Removes the head item from the list.
+        This won't delete the object that is removed, but returns it, so the caller can
+        delete it if necessary.
+    */
+    ObjectType* removeNext() noexcept
+    {
+        ObjectType* const oldItem = item;
+
+        if (oldItem != nullptr)
+        {
+            item = oldItem->nextListItem;
+            oldItem->nextListItem.item = nullptr;
+        }
+
+        return oldItem;
+    }
+
+    /** Removes a specific item from the list.
+        Note that this will not delete the item, it simply unlinks it from the list.
+    */
+    void remove (ObjectType* const itemToRemove)
+    {
+        if (LinkedListPointer* const l = findPointerTo (itemToRemove))
+            l->removeNext();
+    }
+
+    /** Iterates the list, calling the delete operator on all of its elements and
+        leaving this pointer empty.
+    */
+    void deleteAll()
+    {
+        while (item != nullptr)
+        {
+            ObjectType* const oldItem = item;
+            item = oldItem->nextListItem;
+            delete oldItem;
+        }
+    }
+
+    /** Finds a pointer to a given item.
+        If the item is found in the list, this returns the pointer that points to it. If
+        the item isn't found, this returns null.
+    */
+    LinkedListPointer* findPointerTo (ObjectType* const itemToLookFor) noexcept
+    {
+        LinkedListPointer* l = this;
+
+        while (l->item != nullptr)
+        {
+            if (l->item == itemToLookFor)
+                return l;
+
+            l = &(l->item->nextListItem);
+        }
+
+        return nullptr;
+    }
+
+    /** Copies the items in the list to an array.
+        The destArray must contain enough elements to hold the entire list - no checks are
+        made for this!
+    */
+    void copyToArray (ObjectType** destArray) const noexcept
+    {
+        jassert (destArray != nullptr);
+
+        for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
+            *destArray++ = i;
+    }
+
+    /** Swaps this pointer with another one */
+    void swapWith (LinkedListPointer& other) noexcept
+    {
+        std::swap (item, other.item);
+    }
+
+    //==============================================================================
+    /**
+        Allows efficient repeated insertions into a list.
+
+        You can create an Appender object which points to the last element in your
+        list, and then repeatedly call Appender::append() to add items to the end
+        of the list in O(1) time.
+    */
+    class Appender
+    {
+    public:
+        /** Creates an appender which will add items to the given list.
+        */
+        Appender (LinkedListPointer& endOfListPointer) noexcept
+            : endOfList (&endOfListPointer)
+        {
+            // This can only be used to add to the end of a list.
+            jassert (endOfListPointer.item == nullptr);
+        }
+
+        /** Appends an item to the list. */
+        void append (ObjectType* const newItem) noexcept
+        {
+            *endOfList = newItem;
+            endOfList = &(newItem->nextListItem);
+        }
+
+    private:
+        LinkedListPointer* endOfList;
+
+        JUCE_DECLARE_NON_COPYABLE (Appender)
+    };
+
+private:
+    //==============================================================================
+    ObjectType* item;
+
+    JUCE_DECLARE_NON_COPYABLE (LinkedListPointer)
+};
+
+
+#endif   // JUCE_LINKEDLISTPOINTER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_NamedValueSet.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_NamedValueSet.cpp
new file mode 100644
index 0000000..c4e198d
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_NamedValueSet.cpp
@@ -0,0 +1,271 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+struct NamedValueSet::NamedValue
+{
+    NamedValue() noexcept {}
+    NamedValue (Identifier n, const var& v)  : name (n), value (v) {}
+    NamedValue (const NamedValue& other) : name (other.name), value (other.value) {}
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    NamedValue (NamedValue&& other) noexcept
+        : name (static_cast<Identifier&&> (other.name)),
+          value (static_cast<var&&> (other.value))
+    {
+    }
+
+    NamedValue (Identifier n, var&& v)  : name (n), value (static_cast<var&&> (v))
+    {
+    }
+
+    NamedValue& operator= (NamedValue&& other) noexcept
+    {
+        name = static_cast<Identifier&&> (other.name);
+        value = static_cast<var&&> (other.value);
+        return *this;
+    }
+   #endif
+
+    bool operator== (const NamedValue& other) const noexcept   { return name == other.name && value == other.value; }
+    bool operator!= (const NamedValue& other) const noexcept   { return ! operator== (other); }
+
+    Identifier name;
+    var value;
+};
+
+//==============================================================================
+NamedValueSet::NamedValueSet() noexcept
+{
+}
+
+NamedValueSet::NamedValueSet (const NamedValueSet& other)
+   : values (other.values)
+{
+}
+
+NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other)
+{
+    clear();
+    values = other.values;
+    return *this;
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+NamedValueSet::NamedValueSet (NamedValueSet&& other) noexcept
+    : values (static_cast <Array<NamedValue>&&> (other.values))
+{
+}
+
+NamedValueSet& NamedValueSet::operator= (NamedValueSet&& other) noexcept
+{
+    other.values.swapWith (values);
+    return *this;
+}
+#endif
+
+NamedValueSet::~NamedValueSet()
+{
+    clear();
+}
+
+void NamedValueSet::clear()
+{
+    values.clear();
+}
+
+bool NamedValueSet::operator== (const NamedValueSet& other) const
+{
+    return values == other.values;
+}
+
+bool NamedValueSet::operator!= (const NamedValueSet& other) const
+{
+    return ! operator== (other);
+}
+
+int NamedValueSet::size() const noexcept
+{
+    return values.size();
+}
+
+const var& NamedValueSet::operator[] (const Identifier& name) const
+{
+    if (const var* v = getVarPointer (name))
+        return *v;
+
+    return var::null;
+}
+
+var NamedValueSet::getWithDefault (const Identifier& name, const var& defaultReturnValue) const
+{
+    if (const var* const v = getVarPointer (name))
+        return *v;
+
+    return defaultReturnValue;
+}
+
+var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept
+{
+    for (NamedValue* e = values.end(), *i = values.begin(); i != e; ++i)
+        if (i->name == name)
+            return &(i->value);
+
+    return nullptr;
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+bool NamedValueSet::set (Identifier name, var&& newValue)
+{
+    if (var* const v = getVarPointer (name))
+    {
+        if (v->equalsWithSameType (newValue))
+            return false;
+
+        *v = static_cast<var&&> (newValue);
+        return true;
+    }
+
+    values.add (NamedValue (name, static_cast<var&&> (newValue)));
+    return true;
+}
+#endif
+
+bool NamedValueSet::set (Identifier name, const var& newValue)
+{
+    if (var* const v = getVarPointer (name))
+    {
+        if (v->equalsWithSameType (newValue))
+            return false;
+
+        *v = newValue;
+        return true;
+    }
+
+    values.add (NamedValue (name, newValue));
+    return true;
+}
+
+bool NamedValueSet::contains (const Identifier& name) const
+{
+    return getVarPointer (name) != nullptr;
+}
+
+int NamedValueSet::indexOf (const Identifier& name) const noexcept
+{
+    const int numValues = values.size();
+
+    for (int i = 0; i < numValues; ++i)
+        if (values.getReference(i).name == name)
+            return i;
+
+    return -1;
+}
+
+bool NamedValueSet::remove (const Identifier& name)
+{
+    const int numValues = values.size();
+
+    for (int i = 0; i < numValues; ++i)
+    {
+        if (values.getReference(i).name == name)
+        {
+            values.remove (i);
+            return true;
+        }
+    }
+
+    return false;
+}
+
+Identifier NamedValueSet::getName (const int index) const noexcept
+{
+    if (isPositiveAndBelow (index, values.size()))
+        return values.getReference (index).name;
+
+    jassertfalse;
+    return Identifier();
+}
+
+const var& NamedValueSet::getValueAt (const int index) const noexcept
+{
+    if (isPositiveAndBelow (index, values.size()))
+        return values.getReference (index).value;
+
+    jassertfalse;
+    return var::null;
+}
+
+var* NamedValueSet::getVarPointerAt (int index) const noexcept
+{
+    if (isPositiveAndBelow (index, values.size()))
+        return &(values.getReference (index).value);
+
+    return nullptr;
+}
+
+void NamedValueSet::setFromXmlAttributes (const XmlElement& xml)
+{
+    values.clearQuick();
+
+    for (const XmlElement::XmlAttributeNode* att = xml.attributes; att != nullptr; att = att->nextListItem)
+    {
+        if (att->name.toString().startsWith ("base64:"))
+        {
+            MemoryBlock mb;
+
+            if (mb.fromBase64Encoding (att->value))
+            {
+                values.add (NamedValue (att->name.toString().substring (7), var (mb)));
+                continue;
+            }
+        }
+
+        values.add (NamedValue (att->name, var (att->value)));
+    }
+}
+
+void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const
+{
+    for (NamedValue* e = values.end(), *i = values.begin(); i != e; ++i)
+    {
+        if (const MemoryBlock* mb = i->value.getBinaryData())
+        {
+            xml.setAttribute ("base64:" + i->name.toString(), mb->toBase64Encoding());
+        }
+        else
+        {
+            // These types can't be stored as XML!
+            jassert (! i->value.isObject());
+            jassert (! i->value.isMethod());
+            jassert (! i->value.isArray());
+
+            xml.setAttribute (i->name.toString(),
+                              i->value.toString());
+        }
+    }
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_NamedValueSet.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_NamedValueSet.h
new file mode 100644
index 0000000..0216326
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_NamedValueSet.h
@@ -0,0 +1,145 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_NAMEDVALUESET_H_INCLUDED
+#define JUCE_NAMEDVALUESET_H_INCLUDED
+
+
+//==============================================================================
+/** Holds a set of named var objects.
+
+    This can be used as a basic structure to hold a set of var object, which can
+    be retrieved by using their identifier.
+*/
+class JUCE_API  NamedValueSet
+{
+public:
+    /** Creates an empty set. */
+    NamedValueSet() noexcept;
+
+    /** Creates a copy of another set. */
+    NamedValueSet (const NamedValueSet&);
+
+    /** Replaces this set with a copy of another set. */
+    NamedValueSet& operator= (const NamedValueSet&);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    NamedValueSet (NamedValueSet&&) noexcept;
+    NamedValueSet& operator= (NamedValueSet&&) noexcept;
+   #endif
+
+    /** Destructor. */
+    ~NamedValueSet();
+
+    bool operator== (const NamedValueSet&) const;
+    bool operator!= (const NamedValueSet&) const;
+
+    //==============================================================================
+    /** Returns the total number of values that the set contains. */
+    int size() const noexcept;
+
+    /** Returns the value of a named item.
+        If the name isn't found, this will return a void variant.
+        @see getProperty
+    */
+    const var& operator[] (const Identifier& name) const;
+
+    /** Tries to return the named value, but if no such value is found, this will
+        instead return the supplied default value.
+    */
+    var getWithDefault (const Identifier& name, const var& defaultReturnValue) const;
+
+    /** Changes or adds a named value.
+        @returns    true if a value was changed or added; false if the
+                    value was already set the value passed-in.
+    */
+    bool set (Identifier name, const var& newValue);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    /** Changes or adds a named value.
+        @returns    true if a value was changed or added; false if the
+                    value was already set the value passed-in.
+    */
+    bool set (Identifier name, var&& newValue);
+   #endif
+
+    /** Returns true if the set contains an item with the specified name. */
+    bool contains (const Identifier& name) const;
+
+    /** Removes a value from the set.
+        @returns    true if a value was removed; false if there was no value
+                    with the name that was given.
+    */
+    bool remove (const Identifier& name);
+
+    /** Returns the name of the value at a given index.
+        The index must be between 0 and size() - 1.
+    */
+    Identifier getName (int index) const noexcept;
+
+    /** Returns a pointer to the var that holds a named value, or null if there is
+        no value with this name.
+
+        Do not use this method unless you really need access to the internal var object
+        for some reason - for normal reading and writing always prefer operator[]() and set().
+    */
+    var* getVarPointer (const Identifier& name) const noexcept;
+
+    /** Returns the value of the item at a given index.
+        The index must be between 0 and size() - 1.
+    */
+    const var& getValueAt (int index) const noexcept;
+
+    /** Returns the value of the item at a given index.
+        The index must be between 0 and size() - 1, or this will return a nullptr
+    */
+    var* getVarPointerAt (int index) const noexcept;
+
+    /** Returns the index of the given name, or -1 if it's not found. */
+    int indexOf (const Identifier& name) const noexcept;
+
+    /** Removes all values. */
+    void clear();
+
+    //==============================================================================
+    /** Sets properties to the values of all of an XML element's attributes. */
+    void setFromXmlAttributes (const XmlElement& xml);
+
+    /** Sets attributes in an XML element corresponding to each of this object's
+        properties.
+    */
+    void copyToXmlAttributes (XmlElement& xml) const;
+
+private:
+    //==============================================================================
+    struct NamedValue;
+    Array<NamedValue> values;
+};
+
+
+#endif   // JUCE_NAMEDVALUESET_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_OwnedArray.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_OwnedArray.h
new file mode 100644
index 0000000..a116df8
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_OwnedArray.h
@@ -0,0 +1,897 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_OWNEDARRAY_H_INCLUDED
+#define JUCE_OWNEDARRAY_H_INCLUDED
+
+
+//==============================================================================
+/** An array designed for holding objects.
+
+    This holds a list of pointers to objects, and will automatically
+    delete the objects when they are removed from the array, or when the
+    array is itself deleted.
+
+    Declare it in the form:  OwnedArray<MyObjectClass>
+
+    ..and then add new objects, e.g.   myOwnedArray.add (new MyObjectClass());
+
+    After adding objects, they are 'owned' by the array and will be deleted when
+    removed or replaced.
+
+    To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
+    TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
+
+    @see Array, ReferenceCountedArray, StringArray, CriticalSection
+*/
+template <class ObjectClass,
+          class TypeOfCriticalSectionToUse = DummyCriticalSection>
+
+class OwnedArray
+{
+public:
+    //==============================================================================
+    /** Creates an empty array. */
+    OwnedArray() noexcept
+        : numUsed (0)
+    {
+    }
+
+    /** Deletes the array and also deletes any objects inside it.
+
+        To get rid of the array without deleting its objects, use its
+        clear (false) method before deleting it.
+    */
+    ~OwnedArray()
+    {
+        deleteAllObjects();
+    }
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    OwnedArray (OwnedArray&& other) noexcept
+        : data (static_cast <ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data)),
+          numUsed (other.numUsed)
+    {
+        other.numUsed = 0;
+    }
+
+    OwnedArray& operator= (OwnedArray&& other) noexcept
+    {
+        const ScopedLockType lock (getLock());
+        deleteAllObjects();
+
+        data = static_cast <ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data);
+        numUsed = other.numUsed;
+        other.numUsed = 0;
+        return *this;
+    }
+   #endif
+
+    //==============================================================================
+    /** Clears the array, optionally deleting the objects inside it first. */
+    void clear (bool deleteObjects = true)
+    {
+        const ScopedLockType lock (getLock());
+
+        if (deleteObjects)
+            deleteAllObjects();
+
+        data.setAllocatedSize (0);
+        numUsed = 0;
+    }
+
+    //==============================================================================
+    /** Clears the array, optionally deleting the objects inside it first. */
+    void clearQuick (bool deleteObjects)
+    {
+        const ScopedLockType lock (getLock());
+
+        if (deleteObjects)
+            deleteAllObjects();
+
+        numUsed = 0;
+    }
+
+    //==============================================================================
+    /** Returns the number of items currently in the array.
+        @see operator[]
+    */
+    inline int size() const noexcept
+    {
+        return numUsed;
+    }
+
+    /** Returns a pointer to the object at this index in the array.
+
+        If the index is out-of-range, this will return a null pointer, (and
+        it could be null anyway, because it's ok for the array to hold null
+        pointers as well as objects).
+
+        @see getUnchecked
+    */
+    inline ObjectClass* operator[] (const int index) const noexcept
+    {
+        const ScopedLockType lock (getLock());
+        if (isPositiveAndBelow (index, numUsed))
+        {
+            jassert (data.elements != nullptr);
+            return data.elements [index];
+        }
+
+        return nullptr;
+    }
+
+    /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range.
+
+        This is a faster and less safe version of operator[] which doesn't check the index passed in, so
+        it can be used when you're sure the index is always going to be legal.
+    */
+    inline ObjectClass* getUnchecked (const int index) const noexcept
+    {
+        const ScopedLockType lock (getLock());
+        jassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
+        return data.elements [index];
+    }
+
+    /** Returns a pointer to the first object in the array.
+
+        This will return a null pointer if the array's empty.
+        @see getLast
+    */
+    inline ObjectClass* getFirst() const noexcept
+    {
+        const ScopedLockType lock (getLock());
+
+        if (numUsed > 0)
+        {
+            jassert (data.elements != nullptr);
+            return data.elements [0];
+        }
+
+        return nullptr;
+    }
+
+    /** Returns a pointer to the last object in the array.
+
+        This will return a null pointer if the array's empty.
+        @see getFirst
+    */
+    inline ObjectClass* getLast() const noexcept
+    {
+        const ScopedLockType lock (getLock());
+
+        if (numUsed > 0)
+        {
+            jassert (data.elements != nullptr);
+            return data.elements [numUsed - 1];
+        }
+
+        return nullptr;
+    }
+
+    /** Returns a pointer to the actual array data.
+        This pointer will only be valid until the next time a non-const method
+        is called on the array.
+    */
+    inline ObjectClass** getRawDataPointer() noexcept
+    {
+        return data.elements;
+    }
+
+    //==============================================================================
+    /** Returns a pointer to the first element in the array.
+        This method is provided for compatibility with standard C++ iteration mechanisms.
+    */
+    inline ObjectClass** begin() const noexcept
+    {
+        return data.elements;
+    }
+
+    /** Returns a pointer to the element which follows the last element in the array.
+        This method is provided for compatibility with standard C++ iteration mechanisms.
+    */
+    inline ObjectClass** end() const noexcept
+    {
+       #if JUCE_DEBUG
+        if (data.elements == nullptr || numUsed <= 0) // (to keep static analysers happy)
+            return data.elements;
+       #endif
+
+        return data.elements + numUsed;
+    }
+
+    //==============================================================================
+    /** Finds the index of an object which might be in the array.
+
+        @param objectToLookFor    the object to look for
+        @returns                  the index at which the object was found, or -1 if it's not found
+    */
+    int indexOf (const ObjectClass* objectToLookFor) const noexcept
+    {
+        const ScopedLockType lock (getLock());
+        ObjectClass* const* e = data.elements.getData();
+        ObjectClass* const* const end_ = e + numUsed;
+
+        for (; e != end_; ++e)
+            if (objectToLookFor == *e)
+                return static_cast <int> (e - data.elements.getData());
+
+        return -1;
+    }
+
+    /** Returns true if the array contains a specified object.
+
+        @param objectToLookFor      the object to look for
+        @returns                    true if the object is in the array
+    */
+    bool contains (const ObjectClass* objectToLookFor) const noexcept
+    {
+        const ScopedLockType lock (getLock());
+        ObjectClass* const* e = data.elements.getData();
+        ObjectClass* const* const end_ = e + numUsed;
+
+        for (; e != end_; ++e)
+            if (objectToLookFor == *e)
+                return true;
+
+        return false;
+    }
+
+    //==============================================================================
+    /** Appends a new object to the end of the array.
+
+        Note that the this object will be deleted by the OwnedArray when it
+        is removed, so be careful not to delete it somewhere else.
+
+        Also be careful not to add the same object to the array more than once,
+        as this will obviously cause deletion of dangling pointers.
+
+        @param newObject    the new object to add to the array
+        @returns            the new object that was added
+        @see set, insert, addIfNotAlreadyThere, addSorted
+    */
+    ObjectClass* add (ObjectClass* newObject) noexcept
+    {
+        const ScopedLockType lock (getLock());
+        data.ensureAllocatedSize (numUsed + 1);
+        jassert (data.elements != nullptr);
+        data.elements [numUsed++] = newObject;
+        return newObject;
+    }
+
+    /** Inserts a new object into the array at the given index.
+
+        Note that the this object will be deleted by the OwnedArray when it
+        is removed, so be careful not to delete it somewhere else.
+
+        If the index is less than 0 or greater than the size of the array, the
+        element will be added to the end of the array.
+        Otherwise, it will be inserted into the array, moving all the later elements
+        along to make room.
+
+        Be careful not to add the same object to the array more than once,
+        as this will obviously cause deletion of dangling pointers.
+
+        @param indexToInsertAt      the index at which the new element should be inserted
+        @param newObject            the new object to add to the array
+        @returns                    the new object that was added
+        @see add, addSorted, addIfNotAlreadyThere, set
+    */
+    ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject) noexcept
+    {
+        if (indexToInsertAt < 0)
+            return add (newObject);
+
+        const ScopedLockType lock (getLock());
+
+        if (indexToInsertAt > numUsed)
+            indexToInsertAt = numUsed;
+
+        data.ensureAllocatedSize (numUsed + 1);
+        jassert (data.elements != nullptr);
+
+        ObjectClass** const e = data.elements + indexToInsertAt;
+        const int numToMove = numUsed - indexToInsertAt;
+
+        if (numToMove > 0)
+            memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
+
+        *e = newObject;
+        ++numUsed;
+        return newObject;
+    }
+
+    /** Inserts an array of values into this array at a given position.
+
+        If the index is less than 0 or greater than the size of the array, the
+        new elements will be added to the end of the array.
+        Otherwise, they will be inserted into the array, moving all the later elements
+        along to make room.
+
+        @param indexToInsertAt      the index at which the first new element should be inserted
+        @param newObjects           the new values to add to the array
+        @param numberOfElements     how many items are in the array
+        @see insert, add, addSorted, set
+    */
+    void insertArray (int indexToInsertAt,
+                      ObjectClass* const* newObjects,
+                      int numberOfElements)
+    {
+        if (numberOfElements > 0)
+        {
+            const ScopedLockType lock (getLock());
+            data.ensureAllocatedSize (numUsed + numberOfElements);
+            ObjectClass** insertPos = data.elements;
+
+            if (isPositiveAndBelow (indexToInsertAt, numUsed))
+            {
+                insertPos += indexToInsertAt;
+                const size_t numberToMove = (size_t) (numUsed - indexToInsertAt);
+                memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ObjectClass*));
+            }
+            else
+            {
+                insertPos += numUsed;
+            }
+
+            numUsed += numberOfElements;
+
+            while (--numberOfElements >= 0)
+                *insertPos++ = *newObjects++;
+        }
+    }
+
+    /** Appends a new object at the end of the array as long as the array doesn't
+        already contain it.
+
+        If the array already contains a matching object, nothing will be done.
+
+        @param newObject   the new object to add to the array
+        @returns           the new object that was added
+    */
+    ObjectClass* addIfNotAlreadyThere (ObjectClass* newObject) noexcept
+    {
+        const ScopedLockType lock (getLock());
+
+        if (! contains (newObject))
+            add (newObject);
+
+        return newObject;
+    }
+
+    /** Replaces an object in the array with a different one.
+
+        If the index is less than zero, this method does nothing.
+        If the index is beyond the end of the array, the new object is added to the end of the array.
+
+        Be careful not to add the same object to the array more than once,
+        as this will obviously cause deletion of dangling pointers.
+
+        @param indexToChange        the index whose value you want to change
+        @param newObject            the new value to set for this index.
+        @param deleteOldElement     whether to delete the object that's being replaced with the new one
+        @see add, insert, remove
+    */
+    ObjectClass* set (int indexToChange, ObjectClass* newObject, bool deleteOldElement = true)
+    {
+        if (indexToChange >= 0)
+        {
+            ScopedPointer<ObjectClass> toDelete;
+
+            {
+                const ScopedLockType lock (getLock());
+
+                if (indexToChange < numUsed)
+                {
+                    if (deleteOldElement)
+                    {
+                        toDelete = data.elements [indexToChange];
+
+                        if (toDelete == newObject)
+                            toDelete.release();
+                    }
+
+                    data.elements [indexToChange] = newObject;
+                }
+                else
+                {
+                    data.ensureAllocatedSize (numUsed + 1);
+                    data.elements [numUsed++] = newObject;
+                }
+            }
+        }
+        else
+        {
+            jassertfalse; // you're trying to set an object at a negative index, which doesn't have
+                          // any effect - but since the object is not being added, it may be leaking..
+        }
+
+        return newObject;
+    }
+
+    /** Adds elements from another array to the end of this array.
+
+        @param arrayToAddFrom       the array from which to copy the elements
+        @param startIndex           the first element of the other array to start copying from
+        @param numElementsToAdd     how many elements to add from the other array. If this
+                                    value is negative or greater than the number of available elements,
+                                    all available elements will be copied.
+        @see add
+    */
+    template <class OtherArrayType>
+    void addArray (const OtherArrayType& arrayToAddFrom,
+                   int startIndex = 0,
+                   int numElementsToAdd = -1)
+    {
+        const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
+        const ScopedLockType lock2 (getLock());
+
+        if (startIndex < 0)
+        {
+            jassertfalse;
+            startIndex = 0;
+        }
+
+        if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
+            numElementsToAdd = arrayToAddFrom.size() - startIndex;
+
+        data.ensureAllocatedSize (numUsed + numElementsToAdd);
+        jassert (numElementsToAdd <= 0 || data.elements != nullptr);
+
+        while (--numElementsToAdd >= 0)
+        {
+            data.elements [numUsed] = arrayToAddFrom.getUnchecked (startIndex++);
+            ++numUsed;
+        }
+    }
+
+    /** Adds copies of the elements in another array to the end of this array.
+
+        The other array must be either an OwnedArray of a compatible type of object, or an Array
+        containing pointers to the same kind of object. The objects involved must provide
+        a copy constructor, and this will be used to create new copies of each element, and
+        add them to this array.
+
+        @param arrayToAddFrom       the array from which to copy the elements
+        @param startIndex           the first element of the other array to start copying from
+        @param numElementsToAdd     how many elements to add from the other array. If this
+                                    value is negative or greater than the number of available elements,
+                                    all available elements will be copied.
+        @see add
+    */
+    template <class OtherArrayType>
+    void addCopiesOf (const OtherArrayType& arrayToAddFrom,
+                      int startIndex = 0,
+                      int numElementsToAdd = -1)
+    {
+        const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
+        const ScopedLockType lock2 (getLock());
+
+        if (startIndex < 0)
+        {
+            jassertfalse;
+            startIndex = 0;
+        }
+
+        if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
+            numElementsToAdd = arrayToAddFrom.size() - startIndex;
+
+        data.ensureAllocatedSize (numUsed + numElementsToAdd);
+        jassert (numElementsToAdd <= 0 || data.elements != nullptr);
+
+        while (--numElementsToAdd >= 0)
+            data.elements [numUsed++] = createCopyIfNotNull (arrayToAddFrom.getUnchecked (startIndex++));
+    }
+
+    /** Inserts a new object into the array assuming that the array is sorted.
+
+        This will use a comparator to find the position at which the new object
+        should go. If the array isn't sorted, the behaviour of this
+        method will be unpredictable.
+
+        @param comparator   the comparator to use to compare the elements - see the sort method
+                            for details about this object's structure
+        @param newObject    the new object to insert to the array
+        @returns the index at which the new object was added
+        @see add, sort, indexOfSorted
+    */
+    template <class ElementComparator>
+    int addSorted (ElementComparator& comparator, ObjectClass* const newObject) noexcept
+    {
+        (void) comparator;  // if you pass in an object with a static compareElements() method, this
+                            // avoids getting warning messages about the parameter being unused
+        const ScopedLockType lock (getLock());
+        const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
+        insert (index, newObject);
+        return index;
+    }
+
+    /** Finds the index of an object in the array, assuming that the array is sorted.
+
+        This will use a comparator to do a binary-chop to find the index of the given
+        element, if it exists. If the array isn't sorted, the behaviour of this
+        method will be unpredictable.
+
+        @param comparator           the comparator to use to compare the elements - see the sort()
+                                    method for details about the form this object should take
+        @param objectToLookFor      the object to search for
+        @returns                    the index of the element, or -1 if it's not found
+        @see addSorted, sort
+    */
+    template <typename ElementComparator>
+    int indexOfSorted (ElementComparator& comparator, const ObjectClass* const objectToLookFor) const noexcept
+    {
+        (void) comparator;
+        const ScopedLockType lock (getLock());
+        int s = 0, e = numUsed;
+
+        while (s < e)
+        {
+            if (comparator.compareElements (objectToLookFor, data.elements [s]) == 0)
+                return s;
+
+            const int halfway = (s + e) / 2;
+            if (halfway == s)
+                break;
+
+            if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0)
+                s = halfway;
+            else
+                e = halfway;
+        }
+
+        return -1;
+    }
+
+    //==============================================================================
+    /** Removes an object from the array.
+
+        This will remove the object at a given index (optionally also
+        deleting it) and move back all the subsequent objects to close the gap.
+        If the index passed in is out-of-range, nothing will happen.
+
+        @param indexToRemove    the index of the element to remove
+        @param deleteObject     whether to delete the object that is removed
+        @see removeObject, removeRange
+    */
+    void remove (int indexToRemove, bool deleteObject = true)
+    {
+        ScopedPointer<ObjectClass> toDelete;
+
+        {
+            const ScopedLockType lock (getLock());
+
+            if (isPositiveAndBelow (indexToRemove, numUsed))
+            {
+                ObjectClass** const e = data.elements + indexToRemove;
+
+                if (deleteObject)
+                    toDelete = *e;
+
+                --numUsed;
+                const int numToShift = numUsed - indexToRemove;
+
+                if (numToShift > 0)
+                    memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numToShift);
+            }
+        }
+
+        if ((numUsed << 1) < data.numAllocated)
+            minimiseStorageOverheads();
+    }
+
+    /** Removes and returns an object from the array without deleting it.
+
+        This will remove the object at a given index and return it, moving back all
+        the subsequent objects to close the gap. If the index passed in is out-of-range,
+        nothing will happen.
+
+        @param indexToRemove    the index of the element to remove
+        @see remove, removeObject, removeRange
+    */
+    ObjectClass* removeAndReturn (int indexToRemove)
+    {
+        ObjectClass* removedItem = nullptr;
+        const ScopedLockType lock (getLock());
+
+        if (isPositiveAndBelow (indexToRemove, numUsed))
+        {
+            ObjectClass** const e = data.elements + indexToRemove;
+            removedItem = *e;
+
+            --numUsed;
+            const int numToShift = numUsed - indexToRemove;
+
+            if (numToShift > 0)
+                memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numToShift);
+
+            if ((numUsed << 1) < data.numAllocated)
+                minimiseStorageOverheads();
+        }
+
+        return removedItem;
+    }
+
+    /** Removes a specified object from the array.
+
+        If the item isn't found, no action is taken.
+
+        @param objectToRemove   the object to try to remove
+        @param deleteObject     whether to delete the object (if it's found)
+        @see remove, removeRange
+    */
+    void removeObject (const ObjectClass* objectToRemove, bool deleteObject = true)
+    {
+        const ScopedLockType lock (getLock());
+        ObjectClass** const e = data.elements.getData();
+
+        for (int i = 0; i < numUsed; ++i)
+        {
+            if (objectToRemove == e[i])
+            {
+                remove (i, deleteObject);
+                break;
+            }
+        }
+    }
+
+    /** Removes a range of objects from the array.
+
+        This will remove a set of objects, starting from the given index,
+        and move any subsequent elements down to close the gap.
+
+        If the range extends beyond the bounds of the array, it will
+        be safely clipped to the size of the array.
+
+        @param startIndex       the index of the first object to remove
+        @param numberToRemove   how many objects should be removed
+        @param deleteObjects    whether to delete the objects that get removed
+        @see remove, removeObject
+    */
+    void removeRange (int startIndex, int numberToRemove, bool deleteObjects = true)
+    {
+        const ScopedLockType lock (getLock());
+        const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove);
+        startIndex = jlimit (0, numUsed, startIndex);
+
+        if (endIndex > startIndex)
+        {
+            if (deleteObjects)
+            {
+                for (int i = startIndex; i < endIndex; ++i)
+                {
+                    ContainerDeletePolicy<ObjectClass>::destroy (data.elements [i]);
+                    data.elements [i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
+                }
+            }
+
+            const int rangeSize = endIndex - startIndex;
+            ObjectClass** e = data.elements + startIndex;
+            int numToShift = numUsed - endIndex;
+            numUsed -= rangeSize;
+
+            while (--numToShift >= 0)
+            {
+                *e = e [rangeSize];
+                ++e;
+            }
+
+            if ((numUsed << 1) < data.numAllocated)
+                minimiseStorageOverheads();
+        }
+    }
+
+    /** Removes the last n objects from the array.
+
+        @param howManyToRemove   how many objects to remove from the end of the array
+        @param deleteObjects     whether to also delete the objects that are removed
+        @see remove, removeObject, removeRange
+    */
+    void removeLast (int howManyToRemove = 1,
+                     bool deleteObjects = true)
+    {
+        const ScopedLockType lock (getLock());
+
+        if (howManyToRemove >= numUsed)
+            clear (deleteObjects);
+        else
+            removeRange (numUsed - howManyToRemove, howManyToRemove, deleteObjects);
+    }
+
+    /** Swaps a pair of objects in the array.
+
+        If either of the indexes passed in is out-of-range, nothing will happen,
+        otherwise the two objects at these positions will be exchanged.
+    */
+    void swap (int index1,
+               int index2) noexcept
+    {
+        const ScopedLockType lock (getLock());
+
+        if (isPositiveAndBelow (index1, numUsed)
+             && isPositiveAndBelow (index2, numUsed))
+        {
+            std::swap (data.elements [index1],
+                       data.elements [index2]);
+        }
+    }
+
+    /** Moves one of the objects to a different position.
+
+        This will move the object to a specified index, shuffling along
+        any intervening elements as required.
+
+        So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
+        move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
+
+        @param currentIndex     the index of the object to be moved. If this isn't a
+                                valid index, then nothing will be done
+        @param newIndex         the index at which you'd like this object to end up. If this
+                                is less than zero, it will be moved to the end of the array
+    */
+    void move (int currentIndex, int newIndex) noexcept
+    {
+        if (currentIndex != newIndex)
+        {
+            const ScopedLockType lock (getLock());
+
+            if (isPositiveAndBelow (currentIndex, numUsed))
+            {
+                if (! isPositiveAndBelow (newIndex, numUsed))
+                    newIndex = numUsed - 1;
+
+                ObjectClass* const value = data.elements [currentIndex];
+
+                if (newIndex > currentIndex)
+                {
+                    memmove (data.elements + currentIndex,
+                             data.elements + currentIndex + 1,
+                             sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
+                }
+                else
+                {
+                    memmove (data.elements + newIndex + 1,
+                             data.elements + newIndex,
+                             sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
+                }
+
+                data.elements [newIndex] = value;
+            }
+        }
+    }
+
+    /** This swaps the contents of this array with those of another array.
+
+        If you need to exchange two arrays, this is vastly quicker than using copy-by-value
+        because it just swaps their internal pointers.
+    */
+    template <class OtherArrayType>
+    void swapWith (OtherArrayType& otherArray) noexcept
+    {
+        const ScopedLockType lock1 (getLock());
+        const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
+        data.swapWith (otherArray.data);
+        std::swap (numUsed, otherArray.numUsed);
+    }
+
+    //==============================================================================
+    /** Reduces the amount of storage being used by the array.
+
+        Arrays typically allocate slightly more storage than they need, and after
+        removing elements, they may have quite a lot of unused space allocated.
+        This method will reduce the amount of allocated storage to a minimum.
+    */
+    void minimiseStorageOverheads() noexcept
+    {
+        const ScopedLockType lock (getLock());
+        data.shrinkToNoMoreThan (numUsed);
+    }
+
+    /** Increases the array's internal storage to hold a minimum number of elements.
+
+        Calling this before adding a large known number of elements means that
+        the array won't have to keep dynamically resizing itself as the elements
+        are added, and it'll therefore be more efficient.
+    */
+    void ensureStorageAllocated (const int minNumElements) noexcept
+    {
+        const ScopedLockType lock (getLock());
+        data.ensureAllocatedSize (minNumElements);
+    }
+
+    //==============================================================================
+    /** Sorts the elements in the array.
+
+        This will use a comparator object to sort the elements into order. The object
+        passed must have a method of the form:
+        @code
+        int compareElements (ElementType first, ElementType second);
+        @endcode
+
+        ..and this method must return:
+          - a value of < 0 if the first comes before the second
+          - a value of 0 if the two objects are equivalent
+          - a value of > 0 if the second comes before the first
+
+        To improve performance, the compareElements() method can be declared as static or const.
+
+        @param comparator   the comparator to use for comparing elements.
+        @param retainOrderOfEquivalentItems     if this is true, then items
+                            which the comparator says are equivalent will be
+                            kept in the order in which they currently appear
+                            in the array. This is slower to perform, but may
+                            be important in some cases. If it's false, a faster
+                            algorithm is used, but equivalent elements may be
+                            rearranged.
+        @see sortArray, indexOfSorted
+    */
+    template <class ElementComparator>
+    void sort (ElementComparator& comparator,
+               bool retainOrderOfEquivalentItems = false) const noexcept
+    {
+        (void) comparator;  // if you pass in an object with a static compareElements() method, this
+                            // avoids getting warning messages about the parameter being unused
+
+        const ScopedLockType lock (getLock());
+        sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
+    }
+
+    //==============================================================================
+    /** Returns the CriticalSection that locks this array.
+        To lock, you can call getLock().enter() and getLock().exit(), or preferably use
+        an object of ScopedLockType as an RAII lock for it.
+    */
+    inline const TypeOfCriticalSectionToUse& getLock() const noexcept      { return data; }
+
+    /** Returns the type of scoped lock to use for locking this array */
+    typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
+
+
+    //==============================================================================
+   #ifndef DOXYGEN
+    // Note that the swapWithArray method has been replaced by a more flexible templated version,
+    // and renamed "swapWith" to be more consistent with the names used in other classes.
+    JUCE_DEPRECATED_WITH_BODY (void swapWithArray (OwnedArray& other) noexcept, { swapWith (other); })
+   #endif
+
+private:
+    //==============================================================================
+    ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
+    int numUsed;
+
+    void deleteAllObjects()
+    {
+        while (numUsed > 0)
+            ContainerDeletePolicy<ObjectClass>::destroy (data.elements [--numUsed]);
+    }
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OwnedArray)
+};
+
+
+#endif   // JUCE_OWNEDARRAY_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_PropertySet.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_PropertySet.cpp
new file mode 100644
index 0000000..6b02baf
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_PropertySet.cpp
@@ -0,0 +1,219 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+PropertySet::PropertySet (const bool ignoreCaseOfKeyNames)
+    : properties (ignoreCaseOfKeyNames),
+      fallbackProperties (nullptr),
+      ignoreCaseOfKeys (ignoreCaseOfKeyNames)
+{
+}
+
+PropertySet::PropertySet (const PropertySet& other)
+    : properties (other.properties),
+      fallbackProperties (other.fallbackProperties),
+      ignoreCaseOfKeys (other.ignoreCaseOfKeys)
+{
+}
+
+PropertySet& PropertySet::operator= (const PropertySet& other)
+{
+    properties = other.properties;
+    fallbackProperties = other.fallbackProperties;
+    ignoreCaseOfKeys = other.ignoreCaseOfKeys;
+
+    propertyChanged();
+    return *this;
+}
+
+PropertySet::~PropertySet()
+{
+}
+
+void PropertySet::clear()
+{
+    const ScopedLock sl (lock);
+
+    if (properties.size() > 0)
+    {
+        properties.clear();
+        propertyChanged();
+    }
+}
+
+String PropertySet::getValue (StringRef keyName, const String& defaultValue) const noexcept
+{
+    const ScopedLock sl (lock);
+
+    const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
+
+    if (index >= 0)
+        return properties.getAllValues() [index];
+
+    return fallbackProperties != nullptr ? fallbackProperties->getValue (keyName, defaultValue)
+                                         : defaultValue;
+}
+
+int PropertySet::getIntValue (StringRef keyName, const int defaultValue) const noexcept
+{
+    const ScopedLock sl (lock);
+    const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
+
+    if (index >= 0)
+        return properties.getAllValues() [index].getIntValue();
+
+    return fallbackProperties != nullptr ? fallbackProperties->getIntValue (keyName, defaultValue)
+                                         : defaultValue;
+}
+
+double PropertySet::getDoubleValue (StringRef keyName, const double defaultValue) const noexcept
+{
+    const ScopedLock sl (lock);
+    const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
+
+    if (index >= 0)
+        return properties.getAllValues()[index].getDoubleValue();
+
+    return fallbackProperties != nullptr ? fallbackProperties->getDoubleValue (keyName, defaultValue)
+                                         : defaultValue;
+}
+
+bool PropertySet::getBoolValue (StringRef keyName, const bool defaultValue) const noexcept
+{
+    const ScopedLock sl (lock);
+    const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
+
+    if (index >= 0)
+        return properties.getAllValues() [index].getIntValue() != 0;
+
+    return fallbackProperties != nullptr ? fallbackProperties->getBoolValue (keyName, defaultValue)
+                                         : defaultValue;
+}
+
+XmlElement* PropertySet::getXmlValue (StringRef keyName) const
+{
+    return XmlDocument::parse (getValue (keyName));
+}
+
+void PropertySet::setValue (const String& keyName, const var& v)
+{
+    jassert (keyName.isNotEmpty()); // shouldn't use an empty key name!
+
+    if (keyName.isNotEmpty())
+    {
+        const String value (v.toString());
+        const ScopedLock sl (lock);
+
+        const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
+
+        if (index < 0 || properties.getAllValues() [index] != value)
+        {
+            properties.set (keyName, value);
+            propertyChanged();
+        }
+    }
+}
+
+void PropertySet::removeValue (StringRef keyName)
+{
+    if (keyName.isNotEmpty())
+    {
+        const ScopedLock sl (lock);
+        const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
+
+        if (index >= 0)
+        {
+            properties.remove (keyName);
+            propertyChanged();
+        }
+    }
+}
+
+void PropertySet::setValue (const String& keyName, const XmlElement* const xml)
+{
+    setValue (keyName, xml == nullptr ? var()
+                                      : var (xml->createDocument ("", true)));
+}
+
+bool PropertySet::containsKey (StringRef keyName) const noexcept
+{
+    const ScopedLock sl (lock);
+    return properties.getAllKeys().contains (keyName, ignoreCaseOfKeys);
+}
+
+void PropertySet::addAllPropertiesFrom (const PropertySet& source)
+{
+    const ScopedLock sl (source.getLock());
+
+    for (int i = 0; i < source.properties.size(); ++i)
+        setValue (source.properties.getAllKeys() [i],
+                  source.properties.getAllValues() [i]);
+}
+
+void PropertySet::setFallbackPropertySet (PropertySet* fallbackProperties_) noexcept
+{
+    const ScopedLock sl (lock);
+    fallbackProperties = fallbackProperties_;
+}
+
+XmlElement* PropertySet::createXml (const String& nodeName) const
+{
+    const ScopedLock sl (lock);
+    XmlElement* const xml = new XmlElement (nodeName);
+
+    for (int i = 0; i < properties.getAllKeys().size(); ++i)
+    {
+        XmlElement* const e = xml->createNewChildElement ("VALUE");
+        e->setAttribute ("name", properties.getAllKeys()[i]);
+        e->setAttribute ("val", properties.getAllValues()[i]);
+    }
+
+    return xml;
+}
+
+void PropertySet::restoreFromXml (const XmlElement& xml)
+{
+    const ScopedLock sl (lock);
+    clear();
+
+    forEachXmlChildElementWithTagName (xml, e, "VALUE")
+    {
+        if (e->hasAttribute ("name")
+             && e->hasAttribute ("val"))
+        {
+            properties.set (e->getStringAttribute ("name"),
+                            e->getStringAttribute ("val"));
+        }
+    }
+
+    if (properties.size() > 0)
+        propertyChanged();
+}
+
+void PropertySet::propertyChanged()
+{
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_PropertySet.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_PropertySet.h
new file mode 100644
index 0000000..2a4ecb1
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_PropertySet.h
@@ -0,0 +1,211 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_PROPERTYSET_H_INCLUDED
+#define JUCE_PROPERTYSET_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A set of named property values, which can be strings, integers, floating point, etc.
+
+    Effectively, this just wraps a StringPairArray in an interface that makes it easier
+    to load and save types other than strings.
+
+    See the PropertiesFile class for a subclass of this, which automatically broadcasts change
+    messages and saves/loads the list from a file.
+*/
+class JUCE_API  PropertySet
+{
+public:
+    //==============================================================================
+    /** Creates an empty PropertySet.
+        @param ignoreCaseOfKeyNames   if true, the names of properties are compared in a
+                                      case-insensitive way
+    */
+    PropertySet (bool ignoreCaseOfKeyNames = false);
+
+    /** Creates a copy of another PropertySet. */
+    PropertySet (const PropertySet& other);
+
+    /** Copies another PropertySet over this one. */
+    PropertySet& operator= (const PropertySet& other);
+
+    /** Destructor. */
+    virtual ~PropertySet();
+
+    //==============================================================================
+    /** Returns one of the properties as a string.
+
+        If the value isn't found in this set, then this will look for it in a fallback
+        property set (if you've specified one with the setFallbackPropertySet() method),
+        and if it can't find one there, it'll return the default value passed-in.
+
+        @param keyName              the name of the property to retrieve
+        @param defaultReturnValue   a value to return if the named property doesn't actually exist
+    */
+    String getValue (StringRef keyName, const String& defaultReturnValue = String()) const noexcept;
+
+    /** Returns one of the properties as an integer.
+
+        If the value isn't found in this set, then this will look for it in a fallback
+        property set (if you've specified one with the setFallbackPropertySet() method),
+        and if it can't find one there, it'll return the default value passed-in.
+
+        @param keyName              the name of the property to retrieve
+        @param defaultReturnValue   a value to return if the named property doesn't actually exist
+    */
+    int getIntValue (StringRef keyName, int defaultReturnValue = 0) const noexcept;
+
+    /** Returns one of the properties as an double.
+
+        If the value isn't found in this set, then this will look for it in a fallback
+        property set (if you've specified one with the setFallbackPropertySet() method),
+        and if it can't find one there, it'll return the default value passed-in.
+
+        @param keyName              the name of the property to retrieve
+        @param defaultReturnValue   a value to return if the named property doesn't actually exist
+    */
+    double getDoubleValue (StringRef keyName, double defaultReturnValue = 0.0) const noexcept;
+
+    /** Returns one of the properties as an boolean.
+
+        The result will be true if the string found for this key name can be parsed as a non-zero
+        integer.
+
+        If the value isn't found in this set, then this will look for it in a fallback
+        property set (if you've specified one with the setFallbackPropertySet() method),
+        and if it can't find one there, it'll return the default value passed-in.
+
+        @param keyName              the name of the property to retrieve
+        @param defaultReturnValue   a value to return if the named property doesn't actually exist
+    */
+    bool getBoolValue (StringRef keyName, bool defaultReturnValue = false) const noexcept;
+
+    /** Returns one of the properties as an XML element.
+
+        The result will a new XMLElement object that the caller must delete. If may return nullptr
+        if the key isn't found, or if the entry contains an string that isn't valid XML.
+
+        If the value isn't found in this set, then this will look for it in a fallback
+        property set (if you've specified one with the setFallbackPropertySet() method),
+        and if it can't find one there, it'll return the default value passed-in.
+
+        @param keyName              the name of the property to retrieve
+    */
+    XmlElement* getXmlValue (StringRef keyName) const;
+
+    //==============================================================================
+    /** Sets a named property.
+
+        @param keyName      the name of the property to set. (This mustn't be an empty string)
+        @param value        the new value to set it to
+    */
+    void setValue (const String& keyName, const var& value);
+
+    /** Sets a named property to an XML element.
+
+        @param keyName      the name of the property to set. (This mustn't be an empty string)
+        @param xml          the new element to set it to. If this is zero, the value will be set to
+                            an empty string
+        @see getXmlValue
+    */
+    void setValue (const String& keyName, const XmlElement* xml);
+
+    /** This copies all the values from a source PropertySet to this one.
+        This won't remove any existing settings, it just adds any that it finds in the source set.
+    */
+    void addAllPropertiesFrom (const PropertySet& source);
+
+    //==============================================================================
+    /** Deletes a property.
+        @param keyName      the name of the property to delete. (This mustn't be an empty string)
+    */
+    void removeValue (StringRef keyName);
+
+    /** Returns true if the properies include the given key. */
+    bool containsKey (StringRef keyName) const noexcept;
+
+    /** Removes all values. */
+    void clear();
+
+    //==============================================================================
+    /** Returns the keys/value pair array containing all the properties. */
+    StringPairArray& getAllProperties() noexcept                        { return properties; }
+
+    /** Returns the lock used when reading or writing to this set */
+    const CriticalSection& getLock() const noexcept                     { return lock; }
+
+    //==============================================================================
+    /** Returns an XML element which encapsulates all the items in this property set.
+        The string parameter is the tag name that should be used for the node.
+        @see restoreFromXml
+    */
+    XmlElement* createXml (const String& nodeName) const;
+
+    /** Reloads a set of properties that were previously stored as XML.
+        The node passed in must have been created by the createXml() method.
+        @see createXml
+    */
+    void restoreFromXml (const XmlElement& xml);
+
+    //==============================================================================
+    /** Sets up a second PopertySet that will be used to look up any values that aren't
+        set in this one.
+
+        If you set this up to be a pointer to a second property set, then whenever one
+        of the getValue() methods fails to find an entry in this set, it will look up that
+        value in the fallback set, and if it finds it, it will return that.
+
+        Make sure that you don't delete the fallback set while it's still being used by
+        another set! To remove the fallback set, just call this method with a null pointer.
+
+        @see getFallbackPropertySet
+    */
+    void setFallbackPropertySet (PropertySet* fallbackProperties) noexcept;
+
+    /** Returns the fallback property set.
+        @see setFallbackPropertySet
+    */
+    PropertySet* getFallbackPropertySet() const noexcept                { return fallbackProperties; }
+
+protected:
+    /** Subclasses can override this to be told when one of the properies has been changed. */
+    virtual void propertyChanged();
+
+private:
+    StringPairArray properties;
+    PropertySet* fallbackProperties;
+    CriticalSection lock;
+    bool ignoreCaseOfKeys;
+
+    JUCE_LEAK_DETECTOR (PropertySet)
+};
+
+
+#endif   // JUCE_PROPERTYSET_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ReferenceCountedArray.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ReferenceCountedArray.h
new file mode 100644
index 0000000..d33343d
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ReferenceCountedArray.h
@@ -0,0 +1,897 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_REFERENCECOUNTEDARRAY_H_INCLUDED
+#define JUCE_REFERENCECOUNTEDARRAY_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Holds a list of objects derived from ReferenceCountedObject, or which implement basic
+    reference-count handling methods.
+
+    The template parameter specifies the class of the object you want to point to - the easiest
+    way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
+    or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
+    class by implementing a set of mathods called incReferenceCount(), decReferenceCount(), and
+    decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
+    should behave.
+
+    A ReferenceCountedArray holds objects derived from ReferenceCountedObject,
+    and takes care of incrementing and decrementing their ref counts when they
+    are added and removed from the array.
+
+    To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
+    TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
+
+    @see Array, OwnedArray, StringArray
+*/
+template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSection>
+class ReferenceCountedArray
+{
+public:
+    typedef ReferenceCountedObjectPtr<ObjectClass> ObjectClassPtr;
+
+    //==============================================================================
+    /** Creates an empty array.
+        @see ReferenceCountedObject, Array, OwnedArray
+    */
+    ReferenceCountedArray() noexcept
+        : numUsed (0)
+    {
+    }
+
+    /** Creates a copy of another array */
+    ReferenceCountedArray (const ReferenceCountedArray& other) noexcept
+    {
+        const ScopedLockType lock (other.getLock());
+        numUsed = other.size();
+        data.setAllocatedSize (numUsed);
+        memcpy (data.elements, other.getRawDataPointer(), (size_t) numUsed * sizeof (ObjectClass*));
+
+        for (int i = numUsed; --i >= 0;)
+            if (ObjectClass* o = data.elements[i])
+                o->incReferenceCount();
+    }
+
+    /** Creates a copy of another array */
+    template <class OtherObjectClass, class OtherCriticalSection>
+    ReferenceCountedArray (const ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>& other) noexcept
+    {
+        const typename ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>::ScopedLockType lock (other.getLock());
+        numUsed = other.size();
+        data.setAllocatedSize (numUsed);
+        memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*));
+
+        for (int i = numUsed; --i >= 0;)
+            if (ObjectClass* o = data.elements[i])
+                o->incReferenceCount();
+    }
+
+    /** Copies another array into this one.
+        Any existing objects in this array will first be released.
+    */
+    ReferenceCountedArray& operator= (const ReferenceCountedArray& other) noexcept
+    {
+        ReferenceCountedArray otherCopy (other);
+        swapWith (otherCopy);
+        return *this;
+    }
+
+    /** Copies another array into this one.
+        Any existing objects in this array will first be released.
+    */
+    template <class OtherObjectClass>
+    ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& operator= (const ReferenceCountedArray<OtherObjectClass, TypeOfCriticalSectionToUse>& other) noexcept
+    {
+        ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse> otherCopy (other);
+        swapWith (otherCopy);
+        return *this;
+    }
+
+    /** Destructor.
+        Any objects in the array will be released, and may be deleted if not referenced from elsewhere.
+    */
+    ~ReferenceCountedArray()
+    {
+        clear();
+    }
+
+    //==============================================================================
+    /** Removes all objects from the array.
+
+        Any objects in the array that are not referenced from elsewhere will be deleted.
+    */
+    void clear()
+    {
+        const ScopedLockType lock (getLock());
+
+        while (numUsed > 0)
+            if (ObjectClass* o = data.elements [--numUsed])
+                releaseObject (o);
+
+        jassert (numUsed == 0);
+        data.setAllocatedSize (0);
+    }
+
+    /** Returns the current number of objects in the array. */
+    inline int size() const noexcept
+    {
+        return numUsed;
+    }
+
+    /** Returns a pointer to the object at this index in the array.
+
+        If the index is out-of-range, this will return a null pointer, (and
+        it could be null anyway, because it's ok for the array to hold null
+        pointers as well as objects).
+
+        @see getUnchecked
+    */
+    inline ObjectClassPtr operator[] (const int index) const noexcept
+    {
+        return getObjectPointer (index);
+    }
+
+    /** Returns a pointer to the object at this index in the array, without checking
+        whether the index is in-range.
+
+        This is a faster and less safe version of operator[] which doesn't check the index passed in, so
+        it can be used when you're sure the index is always going to be legal.
+    */
+    inline ObjectClassPtr getUnchecked (const int index) const noexcept
+    {
+        return getObjectPointerUnchecked (index);
+    }
+
+    /** Returns a raw pointer to the object at this index in the array.
+
+        If the index is out-of-range, this will return a null pointer, (and
+        it could be null anyway, because it's ok for the array to hold null
+        pointers as well as objects).
+
+        @see getUnchecked
+    */
+    inline ObjectClass* getObjectPointer (const int index) const noexcept
+    {
+        const ScopedLockType lock (getLock());
+
+        if (isPositiveAndBelow (index, numUsed))
+        {
+            jassert (data.elements != nullptr);
+            return data.elements [index];
+        }
+
+        return ObjectClassPtr();
+    }
+
+    /** Returns a raw pointer to the object at this index in the array, without checking
+        whether the index is in-range.
+    */
+    inline ObjectClass* getObjectPointerUnchecked (const int index) const noexcept
+    {
+        const ScopedLockType lock (getLock());
+        jassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
+        return data.elements [index];
+    }
+
+    /** Returns a pointer to the first object in the array.
+
+        This will return a null pointer if the array's empty.
+        @see getLast
+    */
+    inline ObjectClassPtr getFirst() const noexcept
+    {
+        const ScopedLockType lock (getLock());
+
+        if (numUsed > 0)
+        {
+            jassert (data.elements != nullptr);
+            return data.elements [0];
+        }
+
+        return ObjectClassPtr();
+    }
+
+    /** Returns a pointer to the last object in the array.
+
+        This will return a null pointer if the array's empty.
+        @see getFirst
+    */
+    inline ObjectClassPtr getLast() const noexcept
+    {
+        const ScopedLockType lock (getLock());
+
+        if (numUsed > 0)
+        {
+            jassert (data.elements != nullptr);
+            return data.elements [numUsed - 1];
+        }
+
+        return ObjectClassPtr();
+    }
+
+    /** Returns a pointer to the actual array data.
+        This pointer will only be valid until the next time a non-const method
+        is called on the array.
+    */
+    inline ObjectClass** getRawDataPointer() const noexcept
+    {
+        return data.elements;
+    }
+
+    //==============================================================================
+    /** Returns a pointer to the first element in the array.
+        This method is provided for compatibility with standard C++ iteration mechanisms.
+    */
+    inline ObjectClass** begin() const noexcept
+    {
+        return data.elements;
+    }
+
+    /** Returns a pointer to the element which follows the last element in the array.
+        This method is provided for compatibility with standard C++ iteration mechanisms.
+    */
+    inline ObjectClass** end() const noexcept
+    {
+        return data.elements + numUsed;
+    }
+
+    //==============================================================================
+    /** Finds the index of the first occurrence of an object in the array.
+
+        @param objectToLookFor    the object to look for
+        @returns                  the index at which the object was found, or -1 if it's not found
+    */
+    int indexOf (const ObjectClass* const objectToLookFor) const noexcept
+    {
+        const ScopedLockType lock (getLock());
+        ObjectClass** e = data.elements.getData();
+        ObjectClass** const endPointer = e + numUsed;
+
+        while (e != endPointer)
+        {
+            if (objectToLookFor == *e)
+                return static_cast <int> (e - data.elements.getData());
+
+            ++e;
+        }
+
+        return -1;
+    }
+
+    /** Returns true if the array contains a specified object.
+
+        @param objectToLookFor      the object to look for
+        @returns                    true if the object is in the array
+    */
+    bool contains (const ObjectClass* const objectToLookFor) const noexcept
+    {
+        const ScopedLockType lock (getLock());
+        ObjectClass** e = data.elements.getData();
+        ObjectClass** const endPointer = e + numUsed;
+
+        while (e != endPointer)
+        {
+            if (objectToLookFor == *e)
+                return true;
+
+            ++e;
+        }
+
+        return false;
+    }
+
+    /** Appends a new object to the end of the array.
+
+        This will increase the new object's reference count.
+
+        @param newObject       the new object to add to the array
+        @see set, insert, addIfNotAlreadyThere, addSorted, addArray
+    */
+    ObjectClass* add (ObjectClass* const newObject) noexcept
+    {
+        const ScopedLockType lock (getLock());
+        data.ensureAllocatedSize (numUsed + 1);
+        jassert (data.elements != nullptr);
+        data.elements [numUsed++] = newObject;
+
+        if (newObject != nullptr)
+            newObject->incReferenceCount();
+
+        return newObject;
+    }
+
+    /** Inserts a new object into the array at the given index.
+
+        If the index is less than 0 or greater than the size of the array, the
+        element will be added to the end of the array.
+        Otherwise, it will be inserted into the array, moving all the later elements
+        along to make room.
+
+        This will increase the new object's reference count.
+
+        @param indexToInsertAt      the index at which the new element should be inserted
+        @param newObject            the new object to add to the array
+        @see add, addSorted, addIfNotAlreadyThere, set
+    */
+    ObjectClass* insert (int indexToInsertAt,
+                         ObjectClass* const newObject) noexcept
+    {
+        if (indexToInsertAt < 0)
+            return add (newObject);
+
+        const ScopedLockType lock (getLock());
+
+        if (indexToInsertAt > numUsed)
+            indexToInsertAt = numUsed;
+
+        data.ensureAllocatedSize (numUsed + 1);
+        jassert (data.elements != nullptr);
+
+        ObjectClass** const e = data.elements + indexToInsertAt;
+        const int numToMove = numUsed - indexToInsertAt;
+
+        if (numToMove > 0)
+            memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
+
+        *e = newObject;
+
+        if (newObject != nullptr)
+            newObject->incReferenceCount();
+
+        ++numUsed;
+
+        return newObject;
+    }
+
+    /** Appends a new object at the end of the array as long as the array doesn't
+        already contain it.
+
+        If the array already contains a matching object, nothing will be done.
+
+        @param newObject   the new object to add to the array
+    */
+    void addIfNotAlreadyThere (ObjectClass* const newObject) noexcept
+    {
+        const ScopedLockType lock (getLock());
+        if (! contains (newObject))
+            add (newObject);
+    }
+
+    /** Replaces an object in the array with a different one.
+
+        If the index is less than zero, this method does nothing.
+        If the index is beyond the end of the array, the new object is added to the end of the array.
+
+        The object being added has its reference count increased, and if it's replacing
+        another object, then that one has its reference count decreased, and may be deleted.
+
+        @param indexToChange        the index whose value you want to change
+        @param newObject            the new value to set for this index.
+        @see add, insert, remove
+    */
+    void set (const int indexToChange,
+              ObjectClass* const newObject)
+    {
+        if (indexToChange >= 0)
+        {
+            const ScopedLockType lock (getLock());
+
+            if (newObject != nullptr)
+                newObject->incReferenceCount();
+
+            if (indexToChange < numUsed)
+            {
+                if (ObjectClass* o = data.elements [indexToChange])
+                    releaseObject (o);
+
+                data.elements [indexToChange] = newObject;
+            }
+            else
+            {
+                data.ensureAllocatedSize (numUsed + 1);
+                jassert (data.elements != nullptr);
+                data.elements [numUsed++] = newObject;
+            }
+        }
+    }
+
+    /** Adds elements from another array to the end of this array.
+
+        @param arrayToAddFrom       the array from which to copy the elements
+        @param startIndex           the first element of the other array to start copying from
+        @param numElementsToAdd     how many elements to add from the other array. If this
+                                    value is negative or greater than the number of available elements,
+                                    all available elements will be copied.
+        @see add
+    */
+    void addArray (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& arrayToAddFrom,
+                   int startIndex = 0,
+                   int numElementsToAdd = -1) noexcept
+    {
+        const ScopedLockType lock1 (arrayToAddFrom.getLock());
+
+        {
+            const ScopedLockType lock2 (getLock());
+
+            if (startIndex < 0)
+            {
+                jassertfalse;
+                startIndex = 0;
+            }
+
+            if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
+                numElementsToAdd = arrayToAddFrom.size() - startIndex;
+
+            if (numElementsToAdd > 0)
+            {
+                data.ensureAllocatedSize (numUsed + numElementsToAdd);
+
+                while (--numElementsToAdd >= 0)
+                    add (arrayToAddFrom.getUnchecked (startIndex++));
+            }
+        }
+    }
+
+    /** Inserts a new object into the array assuming that the array is sorted.
+
+        This will use a comparator to find the position at which the new object
+        should go. If the array isn't sorted, the behaviour of this
+        method will be unpredictable.
+
+        @param comparator   the comparator object to use to compare the elements - see the
+                            sort() method for details about this object's form
+        @param newObject    the new object to insert to the array
+        @returns the index at which the new object was added
+        @see add, sort
+    */
+    template <class ElementComparator>
+    int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
+    {
+        const ScopedLockType lock (getLock());
+        const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
+        insert (index, newObject);
+        return index;
+    }
+
+    /** Inserts or replaces an object in the array, assuming it is sorted.
+
+        This is similar to addSorted, but if a matching element already exists, then it will be
+        replaced by the new one, rather than the new one being added as well.
+    */
+    template <class ElementComparator>
+    void addOrReplaceSorted (ElementComparator& comparator,
+                             ObjectClass* newObject) noexcept
+    {
+        const ScopedLockType lock (getLock());
+        const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
+
+        if (index > 0 && comparator.compareElements (newObject, data.elements [index - 1]) == 0)
+            set (index - 1, newObject); // replace an existing object that matches
+        else
+            insert (index, newObject);  // no match, so insert the new one
+    }
+
+    /** Finds the index of an object in the array, assuming that the array is sorted.
+
+        This will use a comparator to do a binary-chop to find the index of the given
+        element, if it exists. If the array isn't sorted, the behaviour of this
+        method will be unpredictable.
+
+        @param comparator           the comparator to use to compare the elements - see the sort()
+                                    method for details about the form this object should take
+        @param objectToLookFor      the object to search for
+        @returns                    the index of the element, or -1 if it's not found
+        @see addSorted, sort
+    */
+    template <class ElementComparator>
+    int indexOfSorted (ElementComparator& comparator,
+                       const ObjectClass* const objectToLookFor) const noexcept
+    {
+        (void) comparator;
+        const ScopedLockType lock (getLock());
+        int s = 0, e = numUsed;
+
+        while (s < e)
+        {
+            if (comparator.compareElements (objectToLookFor, data.elements [s]) == 0)
+                return s;
+
+            const int halfway = (s + e) / 2;
+            if (halfway == s)
+                break;
+
+            if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0)
+                s = halfway;
+            else
+                e = halfway;
+        }
+
+        return -1;
+    }
+
+    //==============================================================================
+    /** Removes an object from the array.
+
+        This will remove the object at a given index and move back all the
+        subsequent objects to close the gap.
+
+        If the index passed in is out-of-range, nothing will happen.
+
+        The object that is removed will have its reference count decreased,
+        and may be deleted if not referenced from elsewhere.
+
+        @param indexToRemove    the index of the element to remove
+        @see removeObject, removeRange
+    */
+    void remove (const int indexToRemove)
+    {
+        const ScopedLockType lock (getLock());
+
+        if (isPositiveAndBelow (indexToRemove, numUsed))
+        {
+            ObjectClass** const e = data.elements + indexToRemove;
+
+            if (ObjectClass* o = *e)
+                releaseObject (o);
+
+            --numUsed;
+            const int numberToShift = numUsed - indexToRemove;
+
+            if (numberToShift > 0)
+                memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
+
+            if ((numUsed << 1) < data.numAllocated)
+                minimiseStorageOverheads();
+        }
+    }
+
+    /** Removes and returns an object from the array.
+
+        This will remove the object at a given index and return it, moving back all
+        the subsequent objects to close the gap. If the index passed in is out-of-range,
+        nothing will happen and a null pointer will be returned.
+
+        @param indexToRemove    the index of the element to remove
+        @see remove, removeObject, removeRange
+    */
+    ObjectClassPtr removeAndReturn (const int indexToRemove)
+    {
+        ObjectClassPtr removedItem;
+        const ScopedLockType lock (getLock());
+
+        if (isPositiveAndBelow (indexToRemove, numUsed))
+        {
+            ObjectClass** const e = data.elements + indexToRemove;
+
+            if (ObjectClass* o = *e)
+            {
+                removedItem = o;
+                releaseObject (o);
+            }
+
+            --numUsed;
+            const int numberToShift = numUsed - indexToRemove;
+
+            if (numberToShift > 0)
+                memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
+
+            if ((numUsed << 1) < data.numAllocated)
+                minimiseStorageOverheads();
+        }
+
+        return removedItem;
+    }
+
+    /** Removes the first occurrence of a specified object from the array.
+
+        If the item isn't found, no action is taken. If it is found, it is
+        removed and has its reference count decreased.
+
+        @param objectToRemove   the object to try to remove
+        @see remove, removeRange
+    */
+    void removeObject (ObjectClass* const objectToRemove)
+    {
+        const ScopedLockType lock (getLock());
+        remove (indexOf (objectToRemove));
+    }
+
+    /** Removes a range of objects from the array.
+
+        This will remove a set of objects, starting from the given index,
+        and move any subsequent elements down to close the gap.
+
+        If the range extends beyond the bounds of the array, it will
+        be safely clipped to the size of the array.
+
+        The objects that are removed will have their reference counts decreased,
+        and may be deleted if not referenced from elsewhere.
+
+        @param startIndex       the index of the first object to remove
+        @param numberToRemove   how many objects should be removed
+        @see remove, removeObject
+    */
+    void removeRange (const int startIndex,
+                      const int numberToRemove)
+    {
+        const ScopedLockType lock (getLock());
+
+        const int start    = jlimit (0, numUsed, startIndex);
+        const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove);
+
+        if (endIndex > start)
+        {
+            int i;
+            for (i = start; i < endIndex; ++i)
+            {
+                if (ObjectClass* o = data.elements[i])
+                {
+                    releaseObject (o);
+                    data.elements[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
+                }
+            }
+
+            const int rangeSize = endIndex - start;
+            ObjectClass** e = data.elements + start;
+            i = numUsed - endIndex;
+            numUsed -= rangeSize;
+
+            while (--i >= 0)
+            {
+                *e = e [rangeSize];
+                ++e;
+            }
+
+            if ((numUsed << 1) < data.numAllocated)
+                minimiseStorageOverheads();
+        }
+    }
+
+    /** Removes the last n objects from the array.
+
+        The objects that are removed will have their reference counts decreased,
+        and may be deleted if not referenced from elsewhere.
+
+        @param howManyToRemove   how many objects to remove from the end of the array
+        @see remove, removeObject, removeRange
+    */
+    void removeLast (int howManyToRemove = 1)
+    {
+        const ScopedLockType lock (getLock());
+
+        if (howManyToRemove > numUsed)
+            howManyToRemove = numUsed;
+
+        while (--howManyToRemove >= 0)
+            remove (numUsed - 1);
+    }
+
+    /** Swaps a pair of objects in the array.
+
+        If either of the indexes passed in is out-of-range, nothing will happen,
+        otherwise the two objects at these positions will be exchanged.
+    */
+    void swap (const int index1,
+               const int index2) noexcept
+    {
+        const ScopedLockType lock (getLock());
+
+        if (isPositiveAndBelow (index1, numUsed)
+             && isPositiveAndBelow (index2, numUsed))
+        {
+            std::swap (data.elements [index1],
+                       data.elements [index2]);
+        }
+    }
+
+    /** Moves one of the objects to a different position.
+
+        This will move the object to a specified index, shuffling along
+        any intervening elements as required.
+
+        So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
+        move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
+
+        @param currentIndex     the index of the object to be moved. If this isn't a
+                                valid index, then nothing will be done
+        @param newIndex         the index at which you'd like this object to end up. If this
+                                is less than zero, it will be moved to the end of the array
+    */
+    void move (const int currentIndex,
+               int newIndex) noexcept
+    {
+        if (currentIndex != newIndex)
+        {
+            const ScopedLockType lock (getLock());
+
+            if (isPositiveAndBelow (currentIndex, numUsed))
+            {
+                if (! isPositiveAndBelow (newIndex, numUsed))
+                    newIndex = numUsed - 1;
+
+                ObjectClass* const value = data.elements [currentIndex];
+
+                if (newIndex > currentIndex)
+                {
+                    memmove (data.elements + currentIndex,
+                             data.elements + currentIndex + 1,
+                             sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
+                }
+                else
+                {
+                    memmove (data.elements + newIndex + 1,
+                             data.elements + newIndex,
+                             sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
+                }
+
+                data.elements [newIndex] = value;
+            }
+        }
+    }
+
+    //==============================================================================
+    /** This swaps the contents of this array with those of another array.
+
+        If you need to exchange two arrays, this is vastly quicker than using copy-by-value
+        because it just swaps their internal pointers.
+    */
+    template <class OtherArrayType>
+    void swapWith (OtherArrayType& otherArray) noexcept
+    {
+        const ScopedLockType lock1 (getLock());
+        const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
+        data.swapWith (otherArray.data);
+        std::swap (numUsed, otherArray.numUsed);
+    }
+
+    //==============================================================================
+    /** Compares this array to another one.
+
+        @returns true only if the other array contains the same objects in the same order
+    */
+    bool operator== (const ReferenceCountedArray& other) const noexcept
+    {
+        const ScopedLockType lock2 (other.getLock());
+        const ScopedLockType lock1 (getLock());
+
+        if (numUsed != other.numUsed)
+            return false;
+
+        for (int i = numUsed; --i >= 0;)
+            if (data.elements [i] != other.data.elements [i])
+                return false;
+
+        return true;
+    }
+
+    /** Compares this array to another one.
+
+        @see operator==
+    */
+    bool operator!= (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) const noexcept
+    {
+        return ! operator== (other);
+    }
+
+    //==============================================================================
+    /** Sorts the elements in the array.
+
+        This will use a comparator object to sort the elements into order. The object
+        passed must have a method of the form:
+        @code
+        int compareElements (ElementType first, ElementType second);
+        @endcode
+
+        ..and this method must return:
+          - a value of < 0 if the first comes before the second
+          - a value of 0 if the two objects are equivalent
+          - a value of > 0 if the second comes before the first
+
+        To improve performance, the compareElements() method can be declared as static or const.
+
+        @param comparator   the comparator to use for comparing elements.
+        @param retainOrderOfEquivalentItems     if this is true, then items
+                            which the comparator says are equivalent will be
+                            kept in the order in which they currently appear
+                            in the array. This is slower to perform, but may
+                            be important in some cases. If it's false, a faster
+                            algorithm is used, but equivalent elements may be
+                            rearranged.
+
+        @see sortArray
+    */
+    template <class ElementComparator>
+    void sort (ElementComparator& comparator,
+               const bool retainOrderOfEquivalentItems = false) const noexcept
+    {
+        (void) comparator;  // if you pass in an object with a static compareElements() method, this
+                            // avoids getting warning messages about the parameter being unused
+
+        const ScopedLockType lock (getLock());
+        sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
+    }
+
+    //==============================================================================
+    /** Reduces the amount of storage being used by the array.
+
+        Arrays typically allocate slightly more storage than they need, and after
+        removing elements, they may have quite a lot of unused space allocated.
+        This method will reduce the amount of allocated storage to a minimum.
+    */
+    void minimiseStorageOverheads() noexcept
+    {
+        const ScopedLockType lock (getLock());
+        data.shrinkToNoMoreThan (numUsed);
+    }
+
+    /** Increases the array's internal storage to hold a minimum number of elements.
+
+        Calling this before adding a large known number of elements means that
+        the array won't have to keep dynamically resizing itself as the elements
+        are added, and it'll therefore be more efficient.
+    */
+    void ensureStorageAllocated (const int minNumElements)
+    {
+        const ScopedLockType lock (getLock());
+        data.ensureAllocatedSize (minNumElements);
+    }
+
+    //==============================================================================
+    /** Returns the CriticalSection that locks this array.
+        To lock, you can call getLock().enter() and getLock().exit(), or preferably use
+        an object of ScopedLockType as an RAII lock for it.
+    */
+    inline const TypeOfCriticalSectionToUse& getLock() const noexcept      { return data; }
+
+    /** Returns the type of scoped lock to use for locking this array */
+    typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
+
+
+    //==============================================================================
+   #ifndef DOXYGEN
+    // Note that the swapWithArray method has been replaced by a more flexible templated version,
+    // and renamed "swapWith" to be more consistent with the names used in other classes.
+    JUCE_DEPRECATED_WITH_BODY (void swapWithArray (ReferenceCountedArray& other) noexcept, { swapWith (other); })
+   #endif
+
+private:
+    //==============================================================================
+    ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
+    int numUsed;
+
+    static void releaseObject (ObjectClass* o)
+    {
+        if (o->decReferenceCountWithoutDeleting())
+            ContainerDeletePolicy<ObjectClass>::destroy (o);
+    }
+};
+
+
+#endif   // JUCE_REFERENCECOUNTEDARRAY_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ScopedValueSetter.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ScopedValueSetter.h
new file mode 100644
index 0000000..13b871e
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_ScopedValueSetter.h
@@ -0,0 +1,100 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SCOPEDVALUESETTER_H_INCLUDED
+#define JUCE_SCOPEDVALUESETTER_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Helper class providing an RAII-based mechanism for temporarily setting and
+    then re-setting a value.
+
+    E.g. @code
+    int x = 1;
+
+    {
+        ScopedValueSetter setter (x, 2);
+
+        // x is now 2
+    }
+
+    // x is now 1 again
+
+    {
+        ScopedValueSetter setter (x, 3, 4);
+
+        // x is now 3
+    }
+
+    // x is now 4
+    @endcode
+
+*/
+template <typename ValueType>
+class ScopedValueSetter
+{
+public:
+    /** Creates a ScopedValueSetter that will immediately change the specified value to the
+        given new value, and will then reset it to its original value when this object is deleted.
+    */
+    ScopedValueSetter (ValueType& valueToSet,
+                       ValueType newValue)
+        : value (valueToSet),
+          originalValue (valueToSet)
+    {
+        valueToSet = newValue;
+    }
+
+    /** Creates a ScopedValueSetter that will immediately change the specified value to the
+        given new value, and will then reset it to be valueWhenDeleted when this object is deleted.
+    */
+    ScopedValueSetter (ValueType& valueToSet,
+                       ValueType newValue,
+                       ValueType valueWhenDeleted)
+        : value (valueToSet),
+          originalValue (valueWhenDeleted)
+    {
+        valueToSet = newValue;
+    }
+
+    ~ScopedValueSetter()
+    {
+        value = originalValue;
+    }
+
+private:
+    //==============================================================================
+    ValueType& value;
+    const ValueType originalValue;
+
+    JUCE_DECLARE_NON_COPYABLE (ScopedValueSetter)
+};
+
+
+#endif   // JUCE_SCOPEDVALUESETTER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_SortedSet.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_SortedSet.h
new file mode 100644
index 0000000..62fd923
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_SortedSet.h
@@ -0,0 +1,494 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SORTEDSET_H_INCLUDED
+#define JUCE_SORTEDSET_H_INCLUDED
+
+#if JUCE_MSVC
+ #pragma warning (push)
+ #pragma warning (disable: 4512)
+#endif
+
+//==============================================================================
+/**
+    Holds a set of unique primitive objects, such as ints or doubles.
+
+    A set can only hold one item with a given value, so if for example it's a
+    set of integers, attempting to add the same integer twice will do nothing
+    the second time.
+
+    Internally, the list of items is kept sorted (which means that whatever
+    kind of primitive type is used must support the ==, <, >, <= and >= operators
+    to determine the order), and searching the set for known values is very fast
+    because it uses a binary-chop method.
+
+    Note that if you're using a class or struct as the element type, it must be
+    capable of being copied or moved with a straightforward memcpy, rather than
+    needing construction and destruction code.
+
+    To make all the set's methods thread-safe, pass in "CriticalSection" as the templated
+    TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
+
+    @see Array, OwnedArray, ReferenceCountedArray, StringArray, CriticalSection
+*/
+template <class ElementType, class TypeOfCriticalSectionToUse = DummyCriticalSection>
+class SortedSet
+{
+public:
+    //==============================================================================
+    /** Creates an empty set. */
+    SortedSet() noexcept
+    {
+    }
+
+    /** Creates a copy of another set.
+        @param other    the set to copy
+    */
+    SortedSet (const SortedSet& other)
+        : data (other.data)
+    {
+    }
+
+    /** Destructor. */
+    ~SortedSet() noexcept
+    {
+    }
+
+    /** Copies another set over this one.
+        @param other    the set to copy
+    */
+    SortedSet& operator= (const SortedSet& other) noexcept
+    {
+        data = other.data;
+        return *this;
+    }
+
+    //==============================================================================
+    /** Compares this set to another one.
+        Two sets are considered equal if they both contain the same set of elements.
+        @param other    the other set to compare with
+    */
+    bool operator== (const SortedSet<ElementType>& other) const noexcept
+    {
+        return data == other.data;
+    }
+
+    /** Compares this set to another one.
+        Two sets are considered equal if they both contain the same set of elements.
+        @param other    the other set to compare with
+    */
+    bool operator!= (const SortedSet<ElementType>& other) const noexcept
+    {
+        return ! operator== (other);
+    }
+
+    //==============================================================================
+    /** Removes all elements from the set.
+
+        This will remove all the elements, and free any storage that the set is
+        using. To clear it without freeing the storage, use the clearQuick()
+        method instead.
+
+        @see clearQuick
+    */
+    void clear() noexcept
+    {
+        data.clear();
+    }
+
+    /** Removes all elements from the set without freeing the array's allocated storage.
+        @see clear
+    */
+    void clearQuick() noexcept
+    {
+        data.clearQuick();
+    }
+
+    //==============================================================================
+    /** Returns the current number of elements in the set. */
+    inline int size() const noexcept
+    {
+        return data.size();
+    }
+
+    /** Returns one of the elements in the set.
+
+        If the index passed in is beyond the range of valid elements, this
+        will return zero.
+
+        If you're certain that the index will always be a valid element, you
+        can call getUnchecked() instead, which is faster.
+
+        @param index    the index of the element being requested (0 is the first element in the set)
+        @see getUnchecked, getFirst, getLast
+    */
+    inline ElementType operator[] (const int index) const noexcept
+    {
+        return data [index];
+    }
+
+    /** Returns one of the elements in the set, without checking the index passed in.
+        Unlike the operator[] method, this will try to return an element without
+        checking that the index is within the bounds of the set, so should only
+        be used when you're confident that it will always be a valid index.
+
+        @param index    the index of the element being requested (0 is the first element in the set)
+        @see operator[], getFirst, getLast
+    */
+    inline ElementType getUnchecked (const int index) const noexcept
+    {
+        return data.getUnchecked (index);
+    }
+
+    /** Returns a direct reference to one of the elements in the set, without checking the index passed in.
+
+        This is like getUnchecked, but returns a direct reference to the element, so that
+        you can alter it directly. Obviously this can be dangerous, so only use it when
+        absolutely necessary.
+
+        @param index    the index of the element being requested (0 is the first element in the array)
+    */
+    inline ElementType& getReference (const int index) const noexcept
+    {
+        return data.getReference (index);
+    }
+
+    /** Returns the first element in the set, or 0 if the set is empty.
+        @see operator[], getUnchecked, getLast
+    */
+    inline ElementType getFirst() const noexcept
+    {
+        return data.getFirst();
+    }
+
+    /** Returns the last element in the set, or 0 if the set is empty.
+        @see operator[], getUnchecked, getFirst
+    */
+    inline ElementType getLast() const noexcept
+    {
+        return data.getLast();
+    }
+
+    //==============================================================================
+    /** Returns a pointer to the first element in the set.
+        This method is provided for compatibility with standard C++ iteration mechanisms.
+    */
+    inline ElementType* begin() const noexcept
+    {
+        return data.begin();
+    }
+
+    /** Returns a pointer to the element which follows the last element in the set.
+        This method is provided for compatibility with standard C++ iteration mechanisms.
+    */
+    inline ElementType* end() const noexcept
+    {
+        return data.end();
+    }
+
+    //==============================================================================
+    /** Finds the index of the first element which matches the value passed in.
+
+        This will search the set for the given object, and return the index
+        of its first occurrence. If the object isn't found, the method will return -1.
+
+        @param elementToLookFor   the value or object to look for
+        @returns                  the index of the object, or -1 if it's not found
+    */
+    int indexOf (const ElementType& elementToLookFor) const noexcept
+    {
+        const ScopedLockType lock (data.getLock());
+
+        int s = 0;
+        int e = data.size();
+
+        for (;;)
+        {
+            if (s >= e)
+                return -1;
+
+            if (elementToLookFor == data.getReference (s))
+                return s;
+
+            const int halfway = (s + e) / 2;
+
+            if (halfway == s)
+                return -1;
+
+            if (elementToLookFor < data.getReference (halfway))
+                e = halfway;
+            else
+                s = halfway;
+        }
+    }
+
+    /** Returns true if the set contains at least one occurrence of an object.
+
+        @param elementToLookFor     the value or object to look for
+        @returns                    true if the item is found
+    */
+    bool contains (const ElementType& elementToLookFor) const noexcept
+    {
+        return indexOf (elementToLookFor) >= 0;
+    }
+
+    //==============================================================================
+    /** Adds a new element to the set, (as long as it's not already in there).
+
+        Note that if a matching element already exists, the new value will be assigned
+        to the existing one using operator=, so that if there are any differences between
+        the objects which were not recognised by the object's operator==, then the
+        set will always contain a copy of the most recently added one.
+
+        @param newElement   the new object to add to the set
+        @returns            true if the value was added, or false if it already existed
+        @see set, insert, addIfNotAlreadyThere, addSorted, addSet, addArray
+    */
+    bool add (const ElementType& newElement) noexcept
+    {
+        const ScopedLockType lock (getLock());
+
+        int s = 0;
+        int e = data.size();
+
+        while (s < e)
+        {
+            ElementType& elem = data.getReference (s);
+            if (newElement == elem)
+            {
+                elem = newElement; // force an update in case operator== permits differences.
+                return false;
+            }
+
+            const int halfway = (s + e) / 2;
+            const bool isBeforeHalfway = (newElement < data.getReference (halfway));
+
+            if (halfway == s)
+            {
+                if (! isBeforeHalfway)
+                    ++s;
+
+                break;
+            }
+
+            if (isBeforeHalfway)
+                e = halfway;
+            else
+                s = halfway;
+        }
+
+        data.insert (s, newElement);
+        return true;
+    }
+
+    /** Adds elements from an array to this set.
+
+        @param elementsToAdd        the array of elements to add
+        @param numElementsToAdd     how many elements are in this other array
+        @see add
+    */
+    void addArray (const ElementType* elementsToAdd,
+                   int numElementsToAdd) noexcept
+    {
+        const ScopedLockType lock (getLock());
+
+        while (--numElementsToAdd >= 0)
+            add (*elementsToAdd++);
+    }
+
+    /** Adds elements from another set to this one.
+
+        @param setToAddFrom         the set from which to copy the elements
+        @param startIndex           the first element of the other set to start copying from
+        @param numElementsToAdd     how many elements to add from the other set. If this
+                                    value is negative or greater than the number of available elements,
+                                    all available elements will be copied.
+        @see add
+    */
+    template <class OtherSetType>
+    void addSet (const OtherSetType& setToAddFrom,
+                 int startIndex = 0,
+                 int numElementsToAdd = -1) noexcept
+    {
+        const typename OtherSetType::ScopedLockType lock1 (setToAddFrom.getLock());
+
+        {
+            const ScopedLockType lock2 (getLock());
+            jassert (this != &setToAddFrom);
+
+            if (this != &setToAddFrom)
+            {
+                if (startIndex < 0)
+                {
+                    jassertfalse;
+                    startIndex = 0;
+                }
+
+                if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size())
+                    numElementsToAdd = setToAddFrom.size() - startIndex;
+
+                if (numElementsToAdd > 0)
+                    addArray (&setToAddFrom.data.getReference (startIndex), numElementsToAdd);
+            }
+        }
+    }
+
+    //==============================================================================
+    /** Removes an element from the set.
+
+        This will remove the element at a given index.
+        If the index passed in is out-of-range, nothing will happen.
+
+        @param indexToRemove    the index of the element to remove
+        @returns                the element that has been removed
+        @see removeValue, removeRange
+    */
+    ElementType remove (const int indexToRemove) noexcept
+    {
+        return data.remove (indexToRemove);
+    }
+
+    /** Removes an item from the set.
+
+        This will remove the given element from the set, if it's there.
+
+        @param valueToRemove   the object to try to remove
+        @see remove, removeRange
+    */
+    void removeValue (const ElementType valueToRemove) noexcept
+    {
+        const ScopedLockType lock (getLock());
+        data.remove (indexOf (valueToRemove));
+    }
+
+    /** Removes any elements which are also in another set.
+
+        @param otherSet   the other set in which to look for elements to remove
+        @see removeValuesNotIn, remove, removeValue, removeRange
+    */
+    template <class OtherSetType>
+    void removeValuesIn (const OtherSetType& otherSet) noexcept
+    {
+        const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
+        const ScopedLockType lock2 (getLock());
+
+        if (this == &otherSet)
+        {
+            clear();
+        }
+        else if (otherSet.size() > 0)
+        {
+            for (int i = data.size(); --i >= 0;)
+                if (otherSet.contains (data.getReference (i)))
+                    remove (i);
+        }
+    }
+
+    /** Removes any elements which are not found in another set.
+
+        Only elements which occur in this other set will be retained.
+
+        @param otherSet    the set in which to look for elements NOT to remove
+        @see removeValuesIn, remove, removeValue, removeRange
+    */
+    template <class OtherSetType>
+    void removeValuesNotIn (const OtherSetType& otherSet) noexcept
+    {
+        const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
+        const ScopedLockType lock2 (getLock());
+
+        if (this != &otherSet)
+        {
+            if (otherSet.size() <= 0)
+            {
+                clear();
+            }
+            else
+            {
+                for (int i = data.size(); --i >= 0;)
+                    if (! otherSet.contains (data.getReference (i)))
+                        remove (i);
+            }
+        }
+    }
+
+    /** This swaps the contents of this array with those of another array.
+
+        If you need to exchange two arrays, this is vastly quicker than using copy-by-value
+        because it just swaps their internal pointers.
+    */
+    template <class OtherSetType>
+    void swapWith (OtherSetType& otherSet) noexcept
+    {
+        data.swapWith (otherSet.data);
+    }
+
+    //==============================================================================
+    /** Reduces the amount of storage being used by the set.
+
+        Sets typically allocate slightly more storage than they need, and after
+        removing elements, they may have quite a lot of unused space allocated.
+        This method will reduce the amount of allocated storage to a minimum.
+    */
+    void minimiseStorageOverheads() noexcept
+    {
+        data.minimiseStorageOverheads();
+    }
+
+    /** Increases the set's internal storage to hold a minimum number of elements.
+
+        Calling this before adding a large known number of elements means that
+        the set won't have to keep dynamically resizing itself as the elements
+        are added, and it'll therefore be more efficient.
+    */
+    void ensureStorageAllocated (const int minNumElements)
+    {
+        data.ensureStorageAllocated (minNumElements);
+    }
+
+    //==============================================================================
+    /** Returns the CriticalSection that locks this array.
+        To lock, you can call getLock().enter() and getLock().exit(), or preferably use
+        an object of ScopedLockType as an RAII lock for it.
+    */
+    inline const TypeOfCriticalSectionToUse& getLock() const noexcept      { return data.getLock(); }
+
+    /** Returns the type of scoped lock to use for locking this array */
+    typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
+
+
+private:
+    //==============================================================================
+    Array<ElementType, TypeOfCriticalSectionToUse> data;
+};
+
+#if JUCE_MSVC
+ #pragma warning (pop)
+#endif
+
+#endif   // JUCE_SORTEDSET_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_SparseSet.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_SparseSet.h
new file mode 100644
index 0000000..86366fc
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_SparseSet.h
@@ -0,0 +1,298 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SPARSESET_H_INCLUDED
+#define JUCE_SPARSESET_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Holds a set of primitive values, storing them as a set of ranges.
+
+    This container acts like an array, but can efficiently hold large contiguous
+    ranges of values. It's quite a specialised class, mostly useful for things
+    like keeping the set of selected rows in a listbox.
+
+    The type used as a template parameter must be an integer type, such as int, short,
+    int64, etc.
+*/
+template <class Type>
+class SparseSet
+{
+public:
+    //==============================================================================
+    /** Creates a new empty set. */
+    SparseSet()
+    {
+    }
+
+    /** Creates a copy of another SparseSet. */
+    SparseSet (const SparseSet<Type>& other)
+        : values (other.values)
+    {
+    }
+
+    //==============================================================================
+    /** Clears the set. */
+    void clear()
+    {
+        values.clear();
+    }
+
+    /** Checks whether the set is empty.
+
+        This is much quicker than using (size() == 0).
+    */
+    bool isEmpty() const noexcept
+    {
+        return values.size() == 0;
+    }
+
+    /** Returns the number of values in the set.
+
+        Because of the way the data is stored, this method can take longer if there
+        are a lot of items in the set. Use isEmpty() for a quick test of whether there
+        are any items.
+    */
+    Type size() const
+    {
+        Type total (0);
+
+        for (int i = 0; i < values.size(); i += 2)
+            total += values.getUnchecked (i + 1) - values.getUnchecked (i);
+
+        return total;
+    }
+
+    /** Returns one of the values in the set.
+
+        @param index    the index of the value to retrieve, in the range 0 to (size() - 1).
+        @returns        the value at this index, or 0 if it's out-of-range
+    */
+    Type operator[] (Type index) const
+    {
+        for (int i = 0; i < values.size(); i += 2)
+        {
+            const Type start (values.getUnchecked (i));
+            const Type len (values.getUnchecked (i + 1) - start);
+
+            if (index < len)
+                return start + index;
+
+            index -= len;
+        }
+
+        return Type();
+    }
+
+    /** Checks whether a particular value is in the set. */
+    bool contains (const Type valueToLookFor) const
+    {
+        for (int i = 0; i < values.size(); ++i)
+            if (valueToLookFor < values.getUnchecked(i))
+                return (i & 1) != 0;
+
+        return false;
+    }
+
+    //==============================================================================
+    /** Returns the number of contiguous blocks of values.
+        @see getRange
+    */
+    int getNumRanges() const noexcept
+    {
+        return values.size() >> 1;
+    }
+
+    /** Returns one of the contiguous ranges of values stored.
+        @param rangeIndex   the index of the range to look up, between 0
+                            and (getNumRanges() - 1)
+        @see getTotalRange
+    */
+    const Range<Type> getRange (const int rangeIndex) const
+    {
+        if (isPositiveAndBelow (rangeIndex, getNumRanges()))
+            return Range<Type> (values.getUnchecked (rangeIndex << 1),
+                                values.getUnchecked ((rangeIndex << 1) + 1));
+
+        return Range<Type>();
+    }
+
+    /** Returns the range between the lowest and highest values in the set.
+        @see getRange
+    */
+    Range<Type> getTotalRange() const
+    {
+        if (values.size() > 0)
+        {
+            jassert ((values.size() & 1) == 0);
+            return Range<Type> (values.getUnchecked (0),
+                                values.getUnchecked (values.size() - 1));
+        }
+
+        return Range<Type>();
+    }
+
+    //==============================================================================
+    /** Adds a range of contiguous values to the set.
+        e.g. addRange (Range \<int\> (10, 14)) will add (10, 11, 12, 13) to the set.
+    */
+    void addRange (const Range<Type> range)
+    {
+        jassert (range.getLength() >= 0);
+        if (range.getLength() > 0)
+        {
+            removeRange (range);
+
+            values.addUsingDefaultSort (range.getStart());
+            values.addUsingDefaultSort (range.getEnd());
+
+            simplify();
+        }
+    }
+
+    /** Removes a range of values from the set.
+        e.g. removeRange (Range\<int\> (10, 14)) will remove (10, 11, 12, 13) from the set.
+    */
+    void removeRange (const Range<Type> rangeToRemove)
+    {
+        jassert (rangeToRemove.getLength() >= 0);
+
+        if (rangeToRemove.getLength() > 0
+             && values.size() > 0
+             && rangeToRemove.getStart() < values.getUnchecked (values.size() - 1)
+             && values.getUnchecked(0) < rangeToRemove.getEnd())
+        {
+            const bool onAtStart = contains (rangeToRemove.getStart() - 1);
+            const Type lastValue (jmin (rangeToRemove.getEnd(), values.getLast()));
+            const bool onAtEnd = contains (lastValue);
+
+            for (int i = values.size(); --i >= 0;)
+            {
+                if (values.getUnchecked(i) <= lastValue)
+                {
+                    while (values.getUnchecked(i) >= rangeToRemove.getStart())
+                    {
+                        values.remove (i);
+
+                        if (--i < 0)
+                            break;
+                    }
+
+                    break;
+                }
+            }
+
+            if (onAtStart)   values.addUsingDefaultSort (rangeToRemove.getStart());
+            if (onAtEnd)     values.addUsingDefaultSort (lastValue);
+
+            simplify();
+        }
+    }
+
+    /** Does an XOR of the values in a given range. */
+    void invertRange (const Range<Type> range)
+    {
+        SparseSet newItems;
+        newItems.addRange (range);
+
+        for (int i = getNumRanges(); --i >= 0;)
+            newItems.removeRange (getRange (i));
+
+        removeRange (range);
+
+        for (int i = newItems.getNumRanges(); --i >= 0;)
+            addRange (newItems.getRange(i));
+    }
+
+    /** Checks whether any part of a given range overlaps any part of this set. */
+    bool overlapsRange (const Range<Type> range)
+    {
+        if (range.getLength() > 0)
+        {
+            for (int i = getNumRanges(); --i >= 0;)
+            {
+                if (values.getUnchecked ((i << 1) + 1) <= range.getStart())
+                    return false;
+
+                if (values.getUnchecked (i << 1) < range.getEnd())
+                    return true;
+            }
+        }
+
+        return false;
+    }
+
+    /** Checks whether the whole of a given range is contained within this one. */
+    bool containsRange (const Range<Type> range)
+    {
+        if (range.getLength() > 0)
+        {
+            for (int i = getNumRanges(); --i >= 0;)
+            {
+                if (values.getUnchecked ((i << 1) + 1) <= range.getStart())
+                    return false;
+
+                if (values.getUnchecked (i << 1) <= range.getStart()
+                     && range.getEnd() <= values.getUnchecked ((i << 1) + 1))
+                    return true;
+            }
+        }
+
+        return false;
+    }
+
+    //==============================================================================
+    bool operator== (const SparseSet<Type>& other) noexcept
+    {
+        return values == other.values;
+    }
+
+    bool operator!= (const SparseSet<Type>& other) noexcept
+    {
+        return values != other.values;
+    }
+
+private:
+    //==============================================================================
+    // alternating start/end values of ranges of values that are present.
+    Array<Type, DummyCriticalSection> values;
+
+    void simplify()
+    {
+        jassert ((values.size() & 1) == 0);
+
+        for (int i = values.size(); --i > 0;)
+            if (values.getUnchecked(i) == values.getUnchecked (i - 1))
+                values.removeRange (--i, 2);
+    }
+};
+
+
+
+#endif   // JUCE_SPARSESET_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_Variant.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_Variant.cpp
new file mode 100644
index 0000000..db3f2f5
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_Variant.cpp
@@ -0,0 +1,780 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+enum VariantStreamMarkers
+{
+    varMarker_Int       = 1,
+    varMarker_BoolTrue  = 2,
+    varMarker_BoolFalse = 3,
+    varMarker_Double    = 4,
+    varMarker_String    = 5,
+    varMarker_Int64     = 6,
+    varMarker_Array     = 7,
+    varMarker_Binary    = 8,
+    varMarker_Undefined = 9
+};
+
+//==============================================================================
+class var::VariantType
+{
+public:
+    VariantType() noexcept {}
+    virtual ~VariantType() noexcept {}
+
+    virtual int toInt (const ValueUnion&) const noexcept                        { return 0; }
+    virtual int64 toInt64 (const ValueUnion&) const noexcept                    { return 0; }
+    virtual double toDouble (const ValueUnion&) const noexcept                  { return 0; }
+    virtual String toString (const ValueUnion&) const                           { return String::empty; }
+    virtual bool toBool (const ValueUnion&) const noexcept                      { return false; }
+    virtual ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; }
+    virtual Array<var>* toArray (const ValueUnion&) const noexcept              { return nullptr; }
+    virtual MemoryBlock* toBinary (const ValueUnion&) const noexcept            { return nullptr; }
+    virtual var clone (const var& original) const                               { return original; }
+
+    virtual bool isVoid() const noexcept      { return false; }
+    virtual bool isUndefined() const noexcept { return false; }
+    virtual bool isInt() const noexcept       { return false; }
+    virtual bool isInt64() const noexcept     { return false; }
+    virtual bool isBool() const noexcept      { return false; }
+    virtual bool isDouble() const noexcept    { return false; }
+    virtual bool isString() const noexcept    { return false; }
+    virtual bool isObject() const noexcept    { return false; }
+    virtual bool isArray() const noexcept     { return false; }
+    virtual bool isBinary() const noexcept    { return false; }
+    virtual bool isMethod() const noexcept    { return false; }
+
+    virtual void cleanUp (ValueUnion&) const noexcept {}
+    virtual void createCopy (ValueUnion& dest, const ValueUnion& source) const      { dest = source; }
+    virtual bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept = 0;
+    virtual void writeToStream (const ValueUnion& data, OutputStream& output) const = 0;
+};
+
+//==============================================================================
+class var::VariantType_Void  : public var::VariantType
+{
+public:
+    VariantType_Void() noexcept {}
+    static const VariantType_Void instance;
+
+    bool isVoid() const noexcept override   { return true; }
+    bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept override { return otherType.isVoid() || otherType.isUndefined(); }
+    void writeToStream (const ValueUnion&, OutputStream& output) const override   { output.writeCompressedInt (0); }
+};
+
+//==============================================================================
+class var::VariantType_Undefined  : public var::VariantType
+{
+public:
+    VariantType_Undefined() noexcept {}
+    static const VariantType_Undefined instance;
+
+    bool isUndefined() const noexcept override           { return true; }
+    String toString (const ValueUnion&) const override   { return "undefined"; }
+    bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept override { return otherType.isVoid() || otherType.isUndefined(); }
+
+    void writeToStream (const ValueUnion&, OutputStream& output) const override
+    {
+        output.writeCompressedInt (1);
+        output.writeByte (varMarker_Undefined);
+    }
+};
+
+//==============================================================================
+class var::VariantType_Int  : public var::VariantType
+{
+public:
+    VariantType_Int() noexcept {}
+    static const VariantType_Int instance;
+
+    int toInt (const ValueUnion& data) const noexcept override       { return data.intValue; };
+    int64 toInt64 (const ValueUnion& data) const noexcept override   { return (int64) data.intValue; };
+    double toDouble (const ValueUnion& data) const noexcept override { return (double) data.intValue; }
+    String toString (const ValueUnion& data) const override          { return String (data.intValue); }
+    bool toBool (const ValueUnion& data) const noexcept override     { return data.intValue != 0; }
+    bool isInt() const noexcept override                             { return true; }
+
+    bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
+    {
+        if (otherType.isDouble() || otherType.isInt64() || otherType.isString())
+            return otherType.equals (otherData, data, *this);
+
+        return otherType.toInt (otherData) == data.intValue;
+    }
+
+    void writeToStream (const ValueUnion& data, OutputStream& output) const override
+    {
+        output.writeCompressedInt (5);
+        output.writeByte (varMarker_Int);
+        output.writeInt (data.intValue);
+    }
+};
+
+//==============================================================================
+class var::VariantType_Int64  : public var::VariantType
+{
+public:
+    VariantType_Int64() noexcept {}
+    static const VariantType_Int64 instance;
+
+    int toInt (const ValueUnion& data) const noexcept override       { return (int) data.int64Value; };
+    int64 toInt64 (const ValueUnion& data) const noexcept override   { return data.int64Value; };
+    double toDouble (const ValueUnion& data) const noexcept override { return (double) data.int64Value; }
+    String toString (const ValueUnion& data) const override          { return String (data.int64Value); }
+    bool toBool (const ValueUnion& data) const noexcept override     { return data.int64Value != 0; }
+    bool isInt64() const noexcept override                           { return true; }
+
+    bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
+    {
+        if (otherType.isDouble() || otherType.isString())
+            return otherType.equals (otherData, data, *this);
+
+        return otherType.toInt64 (otherData) == data.int64Value;
+    }
+
+    void writeToStream (const ValueUnion& data, OutputStream& output) const override
+    {
+        output.writeCompressedInt (9);
+        output.writeByte (varMarker_Int64);
+        output.writeInt64 (data.int64Value);
+    }
+};
+
+//==============================================================================
+class var::VariantType_Double   : public var::VariantType
+{
+public:
+    VariantType_Double() noexcept {}
+    static const VariantType_Double instance;
+
+    int toInt (const ValueUnion& data) const noexcept override       { return (int) data.doubleValue; };
+    int64 toInt64 (const ValueUnion& data) const noexcept override   { return (int64) data.doubleValue; };
+    double toDouble (const ValueUnion& data) const noexcept override { return data.doubleValue; }
+    String toString (const ValueUnion& data) const override          { return String (data.doubleValue); }
+    bool toBool (const ValueUnion& data) const noexcept override     { return data.doubleValue != 0; }
+    bool isDouble() const noexcept override                          { return true; }
+
+    bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
+    {
+        return std::abs (otherType.toDouble (otherData) - data.doubleValue) < std::numeric_limits<double>::epsilon();
+    }
+
+    void writeToStream (const ValueUnion& data, OutputStream& output) const override
+    {
+        output.writeCompressedInt (9);
+        output.writeByte (varMarker_Double);
+        output.writeDouble (data.doubleValue);
+    }
+};
+
+//==============================================================================
+class var::VariantType_Bool   : public var::VariantType
+{
+public:
+    VariantType_Bool() noexcept {}
+    static const VariantType_Bool instance;
+
+    int toInt (const ValueUnion& data) const noexcept override       { return data.boolValue ? 1 : 0; };
+    int64 toInt64 (const ValueUnion& data) const noexcept override   { return data.boolValue ? 1 : 0; };
+    double toDouble (const ValueUnion& data) const noexcept override { return data.boolValue ? 1.0 : 0.0; }
+    String toString (const ValueUnion& data) const override          { return String::charToString (data.boolValue ? (juce_wchar) '1' : (juce_wchar) '0'); }
+    bool toBool (const ValueUnion& data) const noexcept override     { return data.boolValue; }
+    bool isBool() const noexcept override                            { return true; }
+
+    bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
+    {
+        return otherType.toBool (otherData) == data.boolValue;
+    }
+
+    void writeToStream (const ValueUnion& data, OutputStream& output) const override
+    {
+        output.writeCompressedInt (1);
+        output.writeByte (data.boolValue ? (char) varMarker_BoolTrue : (char) varMarker_BoolFalse);
+    }
+};
+
+//==============================================================================
+class var::VariantType_String   : public var::VariantType
+{
+public:
+    VariantType_String() noexcept {}
+    static const VariantType_String instance;
+
+    void cleanUp (ValueUnion& data) const noexcept override                       { getString (data)-> ~String(); }
+    void createCopy (ValueUnion& dest, const ValueUnion& source) const override   { new (dest.stringValue) String (*getString (source)); }
+
+    bool isString() const noexcept override                          { return true; }
+    int toInt (const ValueUnion& data) const noexcept override       { return getString (data)->getIntValue(); };
+    int64 toInt64 (const ValueUnion& data) const noexcept override   { return getString (data)->getLargeIntValue(); };
+    double toDouble (const ValueUnion& data) const noexcept override { return getString (data)->getDoubleValue(); }
+    String toString (const ValueUnion& data) const override          { return *getString (data); }
+    bool toBool (const ValueUnion& data) const noexcept override     { return getString (data)->getIntValue() != 0
+                                                                           || getString (data)->trim().equalsIgnoreCase ("true")
+                                                                           || getString (data)->trim().equalsIgnoreCase ("yes"); }
+
+    bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
+    {
+        return otherType.toString (otherData) == *getString (data);
+    }
+
+    void writeToStream (const ValueUnion& data, OutputStream& output) const override
+    {
+        const String* const s = getString (data);
+        const size_t len = s->getNumBytesAsUTF8() + 1;
+        HeapBlock<char> temp (len);
+        s->copyToUTF8 (temp, len);
+        output.writeCompressedInt ((int) (len + 1));
+        output.writeByte (varMarker_String);
+        output.write (temp, len);
+    }
+
+private:
+    static inline const String* getString (const ValueUnion& data) noexcept { return reinterpret_cast <const String*> (data.stringValue); }
+    static inline String* getString (ValueUnion& data) noexcept             { return reinterpret_cast <String*> (data.stringValue); }
+};
+
+//==============================================================================
+class var::VariantType_Object   : public var::VariantType
+{
+public:
+    VariantType_Object() noexcept {}
+    static const VariantType_Object instance;
+
+    void cleanUp (ValueUnion& data) const noexcept override   { if (data.objectValue != nullptr) data.objectValue->decReferenceCount(); }
+
+    void createCopy (ValueUnion& dest, const ValueUnion& source) const override
+    {
+        dest.objectValue = source.objectValue;
+        if (dest.objectValue != nullptr)
+            dest.objectValue->incReferenceCount();
+    }
+
+    String toString (const ValueUnion& data) const override                            { return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue); }
+    bool toBool (const ValueUnion& data) const noexcept override                       { return data.objectValue != 0; }
+    ReferenceCountedObject* toObject (const ValueUnion& data) const noexcept override  { return data.objectValue; }
+    bool isObject() const noexcept override                                            { return true; }
+
+    bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
+    {
+        return otherType.toObject (otherData) == data.objectValue;
+    }
+
+    var clone (const var& original) const override
+    {
+        if (DynamicObject* d = original.getDynamicObject())
+            return d->clone().get();
+
+        jassertfalse; // can only clone DynamicObjects!
+        return var();
+    }
+
+    void writeToStream (const ValueUnion&, OutputStream& output) const override
+    {
+        jassertfalse; // Can't write an object to a stream!
+        output.writeCompressedInt (0);
+    }
+};
+
+//==============================================================================
+class var::VariantType_Array   : public var::VariantType_Object
+{
+public:
+    VariantType_Array() noexcept {}
+    static const VariantType_Array instance;
+
+    String toString (const ValueUnion&) const override                           { return "[Array]"; }
+    ReferenceCountedObject* toObject (const ValueUnion&) const noexcept override { return nullptr; }
+    bool isArray() const noexcept override                                       { return true; }
+
+    Array<var>* toArray (const ValueUnion& data) const noexcept override
+    {
+        if (RefCountedArray* a = dynamic_cast<RefCountedArray*> (data.objectValue))
+            return &(a->array);
+
+        return nullptr;
+    }
+
+    bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
+    {
+        const Array<var>* const thisArray = toArray (data);
+        const Array<var>* const otherArray = otherType.toArray (otherData);
+        return thisArray == otherArray || (thisArray != nullptr && otherArray != nullptr && *otherArray == *thisArray);
+    }
+
+    var clone (const var& original) const override
+    {
+        Array<var> arrayCopy;
+
+        if (const Array<var>* array = toArray (original.value))
+            for (int i = 0; i < array->size(); ++i)
+                arrayCopy.add (array->getReference(i).clone());
+
+        return var (arrayCopy);
+    }
+
+    void writeToStream (const ValueUnion& data, OutputStream& output) const override
+    {
+        if (const Array<var>* array = toArray (data))
+        {
+            MemoryOutputStream buffer (512);
+            const int numItems = array->size();
+            buffer.writeCompressedInt (numItems);
+
+            for (int i = 0; i < numItems; ++i)
+                array->getReference(i).writeToStream (buffer);
+
+            output.writeCompressedInt (1 + (int) buffer.getDataSize());
+            output.writeByte (varMarker_Array);
+            output << buffer;
+        }
+    }
+
+    struct RefCountedArray  : public ReferenceCountedObject
+    {
+        RefCountedArray (const Array<var>& a)  : array (a)  { incReferenceCount(); }
+       #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+        RefCountedArray (Array<var>&& a)  : array (static_cast<Array<var>&&> (a)) { incReferenceCount(); }
+       #endif
+        Array<var> array;
+    };
+};
+
+//==============================================================================
+class var::VariantType_Binary   : public var::VariantType
+{
+public:
+    VariantType_Binary() noexcept {}
+
+    static const VariantType_Binary instance;
+
+    void cleanUp (ValueUnion& data) const noexcept override                      { delete data.binaryValue; }
+    void createCopy (ValueUnion& dest, const ValueUnion& source) const override  { dest.binaryValue = new MemoryBlock (*source.binaryValue); }
+
+    String toString (const ValueUnion& data) const override                      { return data.binaryValue->toBase64Encoding(); }
+    bool isBinary() const noexcept override                                      { return true; }
+    MemoryBlock* toBinary (const ValueUnion& data) const noexcept override       { return data.binaryValue; }
+
+    bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
+    {
+        const MemoryBlock* const otherBlock = otherType.toBinary (otherData);
+        return otherBlock != nullptr && *otherBlock == *data.binaryValue;
+    }
+
+    void writeToStream (const ValueUnion& data, OutputStream& output) const override
+    {
+        output.writeCompressedInt (1 + (int) data.binaryValue->getSize());
+        output.writeByte (varMarker_Binary);
+        output << *data.binaryValue;
+    }
+};
+
+//==============================================================================
+class var::VariantType_Method   : public var::VariantType
+{
+public:
+    VariantType_Method() noexcept {}
+    static const VariantType_Method instance;
+
+    String toString (const ValueUnion&) const override               { return "Method"; }
+    bool toBool (const ValueUnion& data) const noexcept override     { return data.methodValue != nullptr; }
+    bool isMethod() const noexcept override                          { return true; }
+
+    bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
+    {
+        return otherType.isMethod() && otherData.methodValue == data.methodValue;
+    }
+
+    void writeToStream (const ValueUnion&, OutputStream& output) const override
+    {
+        jassertfalse; // Can't write a method to a stream!
+        output.writeCompressedInt (0);
+    }
+};
+
+//==============================================================================
+const var::VariantType_Void         var::VariantType_Void::instance;
+const var::VariantType_Undefined    var::VariantType_Undefined::instance;
+const var::VariantType_Int          var::VariantType_Int::instance;
+const var::VariantType_Int64        var::VariantType_Int64::instance;
+const var::VariantType_Bool         var::VariantType_Bool::instance;
+const var::VariantType_Double       var::VariantType_Double::instance;
+const var::VariantType_String       var::VariantType_String::instance;
+const var::VariantType_Object       var::VariantType_Object::instance;
+const var::VariantType_Array        var::VariantType_Array::instance;
+const var::VariantType_Binary       var::VariantType_Binary::instance;
+const var::VariantType_Method       var::VariantType_Method::instance;
+
+
+//==============================================================================
+var::var() noexcept : type (&VariantType_Void::instance) {}
+var::var (const VariantType& t) noexcept  : type (&t) {}
+var::~var() noexcept  { type->cleanUp (value); }
+
+const var var::null;
+
+//==============================================================================
+var::var (const var& valueToCopy)  : type (valueToCopy.type)
+{
+    type->createCopy (value, valueToCopy.value);
+}
+
+var::var (const int v) noexcept       : type (&VariantType_Int::instance)    { value.intValue = v; }
+var::var (const int64 v) noexcept     : type (&VariantType_Int64::instance)  { value.int64Value = v; }
+var::var (const bool v) noexcept      : type (&VariantType_Bool::instance)   { value.boolValue = v; }
+var::var (const double v) noexcept    : type (&VariantType_Double::instance) { value.doubleValue = v; }
+var::var (NativeFunction m) noexcept  : type (&VariantType_Method::instance) { value.methodValue = m; }
+var::var (const Array<var>& v)        : type (&VariantType_Array::instance)  { value.objectValue = new VariantType_Array::RefCountedArray(v); }
+var::var (const String& v)            : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
+var::var (const char* const v)        : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
+var::var (const wchar_t* const v)     : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
+var::var (const void* v, size_t sz)   : type (&VariantType_Binary::instance) { value.binaryValue = new MemoryBlock (v, sz); }
+var::var (const MemoryBlock& v)       : type (&VariantType_Binary::instance) { value.binaryValue = new MemoryBlock (v); }
+
+var::var (ReferenceCountedObject* const object)  : type (&VariantType_Object::instance)
+{
+    value.objectValue = object;
+
+    if (object != nullptr)
+        object->incReferenceCount();
+}
+
+var var::undefined() noexcept           { return var (VariantType_Undefined::instance); }
+
+//==============================================================================
+bool var::isVoid() const noexcept       { return type->isVoid(); }
+bool var::isUndefined() const noexcept  { return type->isUndefined(); }
+bool var::isInt() const noexcept        { return type->isInt(); }
+bool var::isInt64() const noexcept      { return type->isInt64(); }
+bool var::isBool() const noexcept       { return type->isBool(); }
+bool var::isDouble() const noexcept     { return type->isDouble(); }
+bool var::isString() const noexcept     { return type->isString(); }
+bool var::isObject() const noexcept     { return type->isObject(); }
+bool var::isArray() const noexcept      { return type->isArray(); }
+bool var::isBinaryData() const noexcept { return type->isBinary(); }
+bool var::isMethod() const noexcept     { return type->isMethod(); }
+
+var::operator int() const noexcept                      { return type->toInt (value); }
+var::operator int64() const noexcept                    { return type->toInt64 (value); }
+var::operator bool() const noexcept                     { return type->toBool (value); }
+var::operator float() const noexcept                    { return (float) type->toDouble (value); }
+var::operator double() const noexcept                   { return type->toDouble (value); }
+String var::toString() const                            { return type->toString (value); }
+var::operator String() const                            { return type->toString (value); }
+ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); }
+Array<var>* var::getArray() const noexcept              { return type->toArray (value); }
+MemoryBlock* var::getBinaryData() const noexcept        { return type->toBinary (value); }
+DynamicObject* var::getDynamicObject() const noexcept   { return dynamic_cast <DynamicObject*> (getObject()); }
+
+//==============================================================================
+void var::swapWith (var& other) noexcept
+{
+    std::swap (type, other.type);
+    std::swap (value, other.value);
+}
+
+var& var::operator= (const var& v)               { type->cleanUp (value); type = v.type; type->createCopy (value, v.value); return *this; }
+var& var::operator= (const int v)                { type->cleanUp (value); type = &VariantType_Int::instance; value.intValue = v; return *this; }
+var& var::operator= (const int64 v)              { type->cleanUp (value); type = &VariantType_Int64::instance; value.int64Value = v; return *this; }
+var& var::operator= (const bool v)               { type->cleanUp (value); type = &VariantType_Bool::instance; value.boolValue = v; return *this; }
+var& var::operator= (const double v)             { type->cleanUp (value); type = &VariantType_Double::instance; value.doubleValue = v; return *this; }
+var& var::operator= (const char* const v)        { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
+var& var::operator= (const wchar_t* const v)     { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
+var& var::operator= (const String& v)            { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
+var& var::operator= (const Array<var>& v)        { var v2 (v); swapWith (v2); return *this; }
+var& var::operator= (ReferenceCountedObject* v)  { var v2 (v); swapWith (v2); return *this; }
+var& var::operator= (NativeFunction v)           { var v2 (v); swapWith (v2); return *this; }
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+var::var (var&& other) noexcept
+    : type (other.type),
+      value (other.value)
+{
+    other.type = &VariantType_Void::instance;
+}
+
+var& var::operator= (var&& other) noexcept
+{
+    swapWith (other);
+    return *this;
+}
+
+var::var (String&& v)  : type (&VariantType_String::instance)
+{
+    new (value.stringValue) String (static_cast<String&&> (v));
+}
+
+var::var (MemoryBlock&& v)  : type (&VariantType_Binary::instance)
+{
+    value.binaryValue = new MemoryBlock (static_cast<MemoryBlock&&> (v));
+}
+
+var::var (Array<var>&& v)  : type (&VariantType_Array::instance)
+{
+    value.objectValue = new VariantType_Array::RefCountedArray (static_cast<Array<var>&&> (v));
+}
+
+var& var::operator= (String&& v)
+{
+    type->cleanUp (value);
+    type = &VariantType_String::instance;
+    new (value.stringValue) String (static_cast<String&&> (v));
+    return *this;
+}
+#endif
+
+//==============================================================================
+bool var::equals (const var& other) const noexcept
+{
+    return type->equals (value, other.value, *other.type);
+}
+
+bool var::equalsWithSameType (const var& other) const noexcept
+{
+    return type == other.type && equals (other);
+}
+
+bool var::hasSameTypeAs (const var& other) const noexcept
+{
+    return type == other.type;
+}
+
+bool operator== (const var& v1, const var& v2) noexcept     { return v1.equals (v2); }
+bool operator!= (const var& v1, const var& v2) noexcept     { return ! v1.equals (v2); }
+bool operator== (const var& v1, const String& v2)           { return v1.toString() == v2; }
+bool operator!= (const var& v1, const String& v2)           { return v1.toString() != v2; }
+bool operator== (const var& v1, const char* const v2)       { return v1.toString() == v2; }
+bool operator!= (const var& v1, const char* const v2)       { return v1.toString() != v2; }
+
+//==============================================================================
+var var::clone() const noexcept
+{
+    return type->clone (*this);
+}
+
+//==============================================================================
+var var::operator[] (const Identifier propertyName) const
+{
+    if (DynamicObject* const o = getDynamicObject())
+        return o->getProperty (propertyName);
+
+    return var();
+}
+
+var var::operator[] (const char* const propertyName) const
+{
+    return operator[] (Identifier (propertyName));
+}
+
+var var::getProperty (const Identifier propertyName, const var& defaultReturnValue) const
+{
+    if (DynamicObject* const o = getDynamicObject())
+        return o->getProperties().getWithDefault (propertyName, defaultReturnValue);
+
+    return defaultReturnValue;
+}
+
+var::NativeFunction var::getNativeFunction() const
+{
+    return isMethod() ? value.methodValue : nullptr;
+}
+
+var var::invoke (Identifier method, const var* arguments, int numArguments) const
+{
+    if (DynamicObject* const o = getDynamicObject())
+        return o->invokeMethod (method, var::NativeFunctionArgs (*this, arguments, numArguments));
+
+    return var();
+}
+
+var var::call (const Identifier method) const
+{
+    return invoke (method, nullptr, 0);
+}
+
+var var::call (const Identifier method, const var& arg1) const
+{
+    return invoke (method, &arg1, 1);
+}
+
+var var::call (const Identifier method, const var& arg1, const var& arg2) const
+{
+    var args[] = { arg1, arg2 };
+    return invoke (method, args, 2);
+}
+
+var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3)
+{
+    var args[] = { arg1, arg2, arg3 };
+    return invoke (method, args, 3);
+}
+
+var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const
+{
+    var args[] = { arg1, arg2, arg3, arg4 };
+    return invoke (method, args, 4);
+}
+
+var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const
+{
+    var args[] = { arg1, arg2, arg3, arg4, arg5 };
+    return invoke (method, args, 5);
+}
+
+//==============================================================================
+int var::size() const
+{
+    if (const Array<var>* const array = getArray())
+        return array->size();
+
+    return 0;
+}
+
+const var& var::operator[] (int arrayIndex) const
+{
+    const Array<var>* const array = getArray();
+
+    // When using this method, the var must actually be an array, and the index
+    // must be in-range!
+    jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
+
+    return array->getReference (arrayIndex);
+}
+
+var& var::operator[] (int arrayIndex)
+{
+    const Array<var>* const array = getArray();
+
+    // When using this method, the var must actually be an array, and the index
+    // must be in-range!
+    jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
+
+    return array->getReference (arrayIndex);
+}
+
+Array<var>* var::convertToArray()
+{
+    if (Array<var>* array = getArray())
+        return array;
+
+    Array<var> tempVar;
+    if (! isVoid())
+        tempVar.add (*this);
+
+    *this = tempVar;
+    return getArray();
+}
+
+void var::append (const var& n)
+{
+    convertToArray()->add (n);
+}
+
+void var::remove (const int index)
+{
+    if (Array<var>* const array = getArray())
+        array->remove (index);
+}
+
+void var::insert (const int index, const var& n)
+{
+    convertToArray()->insert (index, n);
+}
+
+void var::resize (const int numArrayElementsWanted)
+{
+    convertToArray()->resize (numArrayElementsWanted);
+}
+
+int var::indexOf (const var& n) const
+{
+    if (const Array<var>* const array = getArray())
+        return array->indexOf (n);
+
+    return -1;
+}
+
+//==============================================================================
+void var::writeToStream (OutputStream& output) const
+{
+    type->writeToStream (value, output);
+}
+
+var var::readFromStream (InputStream& input)
+{
+    const int numBytes = input.readCompressedInt();
+
+    if (numBytes > 0)
+    {
+        switch (input.readByte())
+        {
+            case varMarker_Int:         return var (input.readInt());
+            case varMarker_Int64:       return var (input.readInt64());
+            case varMarker_BoolTrue:    return var (true);
+            case varMarker_BoolFalse:   return var (false);
+            case varMarker_Double:      return var (input.readDouble());
+            case varMarker_String:
+            {
+                MemoryOutputStream mo;
+                mo.writeFromInputStream (input, numBytes - 1);
+                return var (mo.toUTF8());
+            }
+
+            case varMarker_Binary:
+            {
+                MemoryBlock mb ((size_t) numBytes - 1);
+
+                if (numBytes > 1)
+                {
+                    const int numRead = input.read (mb.getData(), numBytes - 1);
+                    mb.setSize ((size_t) numRead);
+                }
+
+                return var (mb);
+            }
+
+            case varMarker_Array:
+            {
+                var v;
+                Array<var>* const destArray = v.convertToArray();
+
+                for (int i = input.readCompressedInt(); --i >= 0;)
+                    destArray->add (readFromStream (input));
+
+                return v;
+            }
+
+            default:
+                input.skipNextBytes (numBytes - 1); break;
+        }
+    }
+
+    return var();
+}
+
+var::NativeFunctionArgs::NativeFunctionArgs (const var& t, const var* args, int numArgs) noexcept
+    : thisObject (t), arguments (args), numArguments (numArgs)
+{}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_Variant.h b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_Variant.h
new file mode 100644
index 0000000..41a4884
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/containers/juce_Variant.h
@@ -0,0 +1,327 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_VARIANT_H_INCLUDED
+#define JUCE_VARIANT_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A variant class, that can be used to hold a range of primitive values.
+
+    A var object can hold a range of simple primitive values, strings, or
+    any kind of ReferenceCountedObject. The var class is intended to act like
+    the kind of values used in dynamic scripting languages.
+
+    You can save/load var objects either in a small, proprietary binary format
+    using writeToStream()/readFromStream(), or as JSON by using the JSON class.
+
+    @see JSON, DynamicObject
+*/
+class JUCE_API  var
+{
+public:
+    //==============================================================================
+    /** This structure is passed to a NativeFunction callback, and contains invocation
+        details about the function's arguments and context.
+    */
+    struct NativeFunctionArgs
+    {
+        NativeFunctionArgs (const var& thisObject, const var* args, int numArgs) noexcept;
+
+        const var& thisObject;
+        const var* arguments;
+        int numArguments;
+
+        JUCE_DECLARE_NON_COPYABLE (NativeFunctionArgs)
+    };
+
+    typedef var (*NativeFunction) (const NativeFunctionArgs&);
+    typedef Identifier identifier;
+
+    //==============================================================================
+    /** Creates a void variant. */
+    var() noexcept;
+
+    /** Destructor. */
+    ~var() noexcept;
+
+    /** A static var object that can be used where you need an empty variant object. */
+    static const var null;
+
+    var (const var& valueToCopy);
+    var (int value) noexcept;
+    var (int64 value) noexcept;
+    var (bool value) noexcept;
+    var (double value) noexcept;
+    var (const char* value);
+    var (const wchar_t* value);
+    var (const String& value);
+    var (const Array<var>& value);
+    var (ReferenceCountedObject* object);
+    var (NativeFunction method) noexcept;
+    var (const void* binaryData, size_t dataSize);
+    var (const MemoryBlock& binaryData);
+
+    var& operator= (const var& valueToCopy);
+    var& operator= (int value);
+    var& operator= (int64 value);
+    var& operator= (bool value);
+    var& operator= (double value);
+    var& operator= (const char* value);
+    var& operator= (const wchar_t* value);
+    var& operator= (const String& value);
+    var& operator= (const Array<var>& value);
+    var& operator= (ReferenceCountedObject* object);
+    var& operator= (NativeFunction method);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    var (var&& other) noexcept;
+    var (String&& value);
+    var (MemoryBlock&& binaryData);
+    var (Array<var>&& value);
+    var& operator= (var&& other) noexcept;
+    var& operator= (String&& value);
+   #endif
+
+    void swapWith (var& other) noexcept;
+
+    /** Returns a var object that can be used where you need the javascript "undefined" value. */
+    static var undefined() noexcept;
+
+    //==============================================================================
+    operator int() const noexcept;
+    operator int64() const noexcept;
+    operator bool() const noexcept;
+    operator float() const noexcept;
+    operator double() const noexcept;
+    operator String() const;
+    String toString() const;
+
+    /** If this variant holds an array, this provides access to it.
+        NOTE: Beware when you use this - the array pointer is only valid for the lifetime
+        of the variant that returned it, so be very careful not to call this method on temporary
+        var objects that are the return-value of a function, and which may go out of scope before
+        you use the array!
+    */
+    Array<var>* getArray() const noexcept;
+
+    /** If this variant holds a memory block, this provides access to it.
+        NOTE: Beware when you use this - the MemoryBlock pointer is only valid for the lifetime
+        of the variant that returned it, so be very careful not to call this method on temporary
+        var objects that are the return-value of a function, and which may go out of scope before
+        you use the MemoryBlock!
+    */
+    MemoryBlock* getBinaryData() const noexcept;
+
+    ReferenceCountedObject* getObject() const noexcept;
+    DynamicObject* getDynamicObject() const noexcept;
+
+    //==============================================================================
+    bool isVoid() const noexcept;
+    bool isUndefined() const noexcept;
+    bool isInt() const noexcept;
+    bool isInt64() const noexcept;
+    bool isBool() const noexcept;
+    bool isDouble() const noexcept;
+    bool isString() const noexcept;
+    bool isObject() const noexcept;
+    bool isArray() const noexcept;
+    bool isBinaryData() const noexcept;
+    bool isMethod() const noexcept;
+
+    /** Returns true if this var has the same value as the one supplied.
+        Note that this ignores the type, so a string var "123" and an integer var with the
+        value 123 are considered to be equal.
+        @see equalsWithSameType
+    */
+    bool equals (const var& other) const noexcept;
+
+    /** Returns true if this var has the same value and type as the one supplied.
+        This differs from equals() because e.g. "123" and 123 will be considered different.
+        @see equals
+    */
+    bool equalsWithSameType (const var& other) const noexcept;
+
+    /** Returns true if this var has the same type as the one supplied. */
+    bool hasSameTypeAs (const var& other) const noexcept;
+
+    /** Returns a deep copy of this object.
+        For simple types this just returns a copy, but if the object contains any arrays
+        or DynamicObjects, they will be cloned (recursively).
+    */
+    var clone() const noexcept;
+
+    //==============================================================================
+    /** If the var is an array, this returns the number of elements.
+        If the var isn't actually an array, this will return 0.
+    */
+    int size() const;
+
+    /** If the var is an array, this can be used to return one of its elements.
+        To call this method, you must make sure that the var is actually an array, and
+        that the index is a valid number. If these conditions aren't met, behaviour is
+        undefined.
+        For more control over the array's contents, you can call getArray() and manipulate
+        it directly as an Array\<var\>.
+    */
+    const var& operator[] (int arrayIndex) const;
+
+    /** If the var is an array, this can be used to return one of its elements.
+        To call this method, you must make sure that the var is actually an array, and
+        that the index is a valid number. If these conditions aren't met, behaviour is
+        undefined.
+        For more control over the array's contents, you can call getArray() and manipulate
+        it directly as an Array\<var\>.
+    */
+    var& operator[] (int arrayIndex);
+
+    /** Appends an element to the var, converting it to an array if it isn't already one.
+        If the var isn't an array, it will be converted to one, and if its value was non-void,
+        this value will be kept as the first element of the new array. The parameter value
+        will then be appended to it.
+        For more control over the array's contents, you can call getArray() and manipulate
+        it directly as an Array\<var\>.
+    */
+    void append (const var& valueToAppend);
+
+    /** Inserts an element to the var, converting it to an array if it isn't already one.
+        If the var isn't an array, it will be converted to one, and if its value was non-void,
+        this value will be kept as the first element of the new array. The parameter value
+        will then be inserted into it.
+        For more control over the array's contents, you can call getArray() and manipulate
+        it directly as an Array\<var\>.
+    */
+    void insert (int index, const var& value);
+
+    /** If the var is an array, this removes one of its elements.
+        If the index is out-of-range or the var isn't an array, nothing will be done.
+        For more control over the array's contents, you can call getArray() and manipulate
+        it directly as an Array\<var\>.
+    */
+    void remove (int index);
+
+    /** Treating the var as an array, this resizes it to contain the specified number of elements.
+        If the var isn't an array, it will be converted to one, and if its value was non-void,
+        this value will be kept as the first element of the new array before resizing.
+        For more control over the array's contents, you can call getArray() and manipulate
+        it directly as an Array\<var\>.
+    */
+    void resize (int numArrayElementsWanted);
+
+    /** If the var is an array, this searches it for the first occurrence of the specified value,
+        and returns its index.
+        If the var isn't an array, or if the value isn't found, this returns -1.
+    */
+    int indexOf (const var& value) const;
+
+    //==============================================================================
+    /** If this variant is an object, this returns one of its properties. */
+    var operator[] (Identifier propertyName) const;
+    /** If this variant is an object, this returns one of its properties. */
+    var operator[] (const char* propertyName) const;
+    /** If this variant is an object, this returns one of its properties, or a default
+        fallback value if the property is not set. */
+    var getProperty (Identifier propertyName, const var& defaultReturnValue) const;
+
+    /** Invokes a named method call with no arguments. */
+    var call (Identifier method) const;
+    /** Invokes a named method call with one argument. */
+    var call (Identifier method, const var& arg1) const;
+    /** Invokes a named method call with 2 arguments. */
+    var call (Identifier method, const var& arg1, const var& arg2) const;
+    /** Invokes a named method call with 3 arguments. */
+    var call (Identifier method, const var& arg1, const var& arg2, const var& arg3);
+    /** Invokes a named method call with 4 arguments. */
+    var call (Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const;
+    /** Invokes a named method call with 5 arguments. */
+    var call (Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const;
+    /** Invokes a named method call with a list of arguments. */
+    var invoke (Identifier method, const var* arguments, int numArguments) const;
+    /** If this object is a method, this returns the function pointer. */
+    NativeFunction getNativeFunction() const;
+
+    //==============================================================================
+    /** Writes a binary representation of this value to a stream.
+        The data can be read back later using readFromStream().
+        @see JSON
+    */
+    void writeToStream (OutputStream& output) const;
+
+    /** Reads back a stored binary representation of a value.
+        The data in the stream must have been written using writeToStream(), or this
+        will have unpredictable results.
+        @see JSON
+    */
+    static var readFromStream (InputStream& input);
+
+private:
+    //==============================================================================
+    class VariantType;            friend class VariantType;
+    class VariantType_Void;       friend class VariantType_Void;
+    class VariantType_Undefined;  friend class VariantType_Undefined;
+    class VariantType_Int;        friend class VariantType_Int;
+    class VariantType_Int64;      friend class VariantType_Int64;
+    class VariantType_Double;     friend class VariantType_Double;
+    class VariantType_Bool;       friend class VariantType_Bool;
+    class VariantType_String;     friend class VariantType_String;
+    class VariantType_Object;     friend class VariantType_Object;
+    class VariantType_Array;      friend class VariantType_Array;
+    class VariantType_Binary;     friend class VariantType_Binary;
+    class VariantType_Method;     friend class VariantType_Method;
+
+    union ValueUnion
+    {
+        int intValue;
+        int64 int64Value;
+        bool boolValue;
+        double doubleValue;
+        char stringValue [sizeof (String)];
+        ReferenceCountedObject* objectValue;
+        MemoryBlock* binaryValue;
+        NativeFunction methodValue;
+    };
+
+    const VariantType* type;
+    ValueUnion value;
+
+    Array<var>* convertToArray();
+    var (const VariantType&) noexcept;
+};
+
+/** Compares the values of two var objects, using the var::equals() comparison. */
+bool operator== (const var& v1, const var& v2) noexcept;
+/** Compares the values of two var objects, using the var::equals() comparison. */
+bool operator!= (const var& v1, const var& v2) noexcept;
+bool operator== (const var& v1, const String& v2);
+bool operator!= (const var& v1, const String& v2);
+bool operator== (const var& v1, const char* v2);
+bool operator!= (const var& v1, const char* v2);
+
+
+#endif   // JUCE_VARIANT_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_DirectoryIterator.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_DirectoryIterator.cpp
new file mode 100644
index 0000000..7d6dd4b
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_DirectoryIterator.cpp
@@ -0,0 +1,159 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+DirectoryIterator::DirectoryIterator (const File& directory, bool recursive,
+                                      const String& pattern, const int type)
+  : wildCards (parseWildcards (pattern)),
+    fileFinder (directory, (recursive || wildCards.size() > 1) ? "*" : pattern),
+    wildCard (pattern),
+    path (File::addTrailingSeparator (directory.getFullPathName())),
+    index (-1),
+    totalNumFiles (-1),
+    whatToLookFor (type),
+    isRecursive (recursive),
+    hasBeenAdvanced (false)
+{
+    // you have to specify the type of files you're looking for!
+    jassert ((type & (File::findFiles | File::findDirectories)) != 0);
+    jassert (type > 0 && type <= 7);
+}
+
+DirectoryIterator::~DirectoryIterator()
+{
+}
+
+StringArray DirectoryIterator::parseWildcards (const String& pattern)
+{
+    StringArray s;
+    s.addTokens (pattern, ";,", "\"'");
+    s.trim();
+    s.removeEmptyStrings();
+    return s;
+}
+
+bool DirectoryIterator::fileMatches (const StringArray& wildCards, const String& filename)
+{
+    for (int i = 0; i < wildCards.size(); ++i)
+        if (filename.matchesWildcard (wildCards[i], ! File::areFileNamesCaseSensitive()))
+            return true;
+
+    return false;
+}
+
+bool DirectoryIterator::next()
+{
+    return next (nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+}
+
+bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResult, int64* const fileSize,
+                              Time* const modTime, Time* const creationTime, bool* const isReadOnly)
+{
+    hasBeenAdvanced = true;
+
+    if (subIterator != nullptr)
+    {
+        if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly))
+            return true;
+
+        subIterator = nullptr;
+    }
+
+    String filename;
+    bool isDirectory, isHidden = false;
+
+    while (fileFinder.next (filename, &isDirectory,
+                            (isHiddenResult != nullptr || (whatToLookFor & File::ignoreHiddenFiles) != 0) ? &isHidden : nullptr,
+                            fileSize, modTime, creationTime, isReadOnly))
+    {
+        ++index;
+
+        if (! filename.containsOnly ("."))
+        {
+            bool matches = false;
+
+            if (isDirectory)
+            {
+                if (isRecursive && ((whatToLookFor & File::ignoreHiddenFiles) == 0 || ! isHidden))
+                    subIterator = new DirectoryIterator (File::createFileWithoutCheckingPath (path + filename),
+                                                         true, wildCard, whatToLookFor);
+
+                matches = (whatToLookFor & File::findDirectories) != 0;
+            }
+            else
+            {
+                matches = (whatToLookFor & File::findFiles) != 0;
+            }
+
+            // if we're not relying on the OS iterator to do the wildcard match, do it now..
+            if (matches && (isRecursive || wildCards.size() > 1))
+                matches = fileMatches (wildCards, filename);
+
+            if (matches && (whatToLookFor & File::ignoreHiddenFiles) != 0)
+                matches = ! isHidden;
+
+            if (matches)
+            {
+                currentFile = File::createFileWithoutCheckingPath (path + filename);
+                if (isHiddenResult != nullptr)     *isHiddenResult = isHidden;
+                if (isDirResult != nullptr)        *isDirResult = isDirectory;
+
+                return true;
+            }
+
+            if (subIterator != nullptr)
+                return next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly);
+        }
+    }
+
+    return false;
+}
+
+const File& DirectoryIterator::getFile() const
+{
+    if (subIterator != nullptr && subIterator->hasBeenAdvanced)
+        return subIterator->getFile();
+
+    // You need to call DirectoryIterator::next() before asking it for the file that it found!
+    jassert (hasBeenAdvanced);
+
+    return currentFile;
+}
+
+float DirectoryIterator::getEstimatedProgress() const
+{
+    if (totalNumFiles < 0)
+        totalNumFiles = File (path).getNumberOfChildFiles (File::findFilesAndDirectories);
+
+    if (totalNumFiles <= 0)
+        return 0.0f;
+
+    const float detailedIndex = (subIterator != nullptr) ? index + subIterator->getEstimatedProgress()
+                                                         : (float) index;
+
+    return detailedIndex / totalNumFiles;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_DirectoryIterator.h b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_DirectoryIterator.h
new file mode 100644
index 0000000..3ca2265
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_DirectoryIterator.h
@@ -0,0 +1,159 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_DIRECTORYITERATOR_H_INCLUDED
+#define JUCE_DIRECTORYITERATOR_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Searches through the files in a directory, returning each file that is found.
+
+    A DirectoryIterator will search through a directory and its subdirectories using
+    a wildcard filepattern match.
+
+    If you may be scanning a large number of files, it's usually smarter to use this
+    class than File::findChildFiles() because it allows you to stop at any time, rather
+    than having to wait for the entire scan to finish before getting the results.
+
+    It also provides an estimate of its progress, using a (highly inaccurate!) algorithm.
+*/
+class JUCE_API  DirectoryIterator
+{
+public:
+    //==============================================================================
+    /** Creates a DirectoryIterator for a given directory.
+
+        After creating one of these, call its next() method to get the
+        first file - e.g. @code
+
+        DirectoryIterator iter (File ("/animals/mooses"), true, "*.moose");
+
+        while (iter.next())
+        {
+            File theFileItFound (iter.getFile());
+
+            ... etc
+        }
+        @endcode
+
+        @param directory    the directory to search in
+        @param isRecursive  whether all the subdirectories should also be searched
+        @param wildCard     the file pattern to match. This may contain multiple patterns
+                            separated by a semi-colon or comma, e.g. "*.jpg;*.png"
+        @param whatToLookFor    a value from the File::TypesOfFileToFind enum, specifying
+                                whether to look for files, directories, or both.
+    */
+    DirectoryIterator (const File& directory,
+                       bool isRecursive,
+                       const String& wildCard = "*",
+                       int whatToLookFor = File::findFiles);
+
+    /** Destructor. */
+    ~DirectoryIterator();
+
+    /** Moves the iterator along to the next file.
+
+        @returns    true if a file was found (you can then use getFile() to see what it was) - or
+                    false if there are no more matching files.
+    */
+    bool next();
+
+    /** Moves the iterator along to the next file, and returns various properties of that file.
+
+        If you need to find out details about the file, it's more efficient to call this method than
+        to call the normal next() method and then find out the details afterwards.
+
+        All the parameters are optional, so pass null pointers for any items that you're not
+        interested in.
+
+        @returns    true if a file was found (you can then use getFile() to see what it was) - or
+                    false if there are no more matching files. If it returns false, then none of the
+                    parameters will be filled-in.
+    */
+    bool next (bool* isDirectory,
+               bool* isHidden,
+               int64* fileSize,
+               Time* modTime,
+               Time* creationTime,
+               bool* isReadOnly);
+
+    /** Returns the file that the iterator is currently pointing at.
+
+        The result of this call is only valid after a call to next() has returned true.
+    */
+    const File& getFile() const;
+
+    /** Returns a guess of how far through the search the iterator has got.
+
+        @returns    a value 0.0 to 1.0 to show the progress, although this won't be
+                    very accurate.
+    */
+    float getEstimatedProgress() const;
+
+private:
+    //==============================================================================
+    class NativeIterator
+    {
+    public:
+        NativeIterator (const File& directory, const String& wildCard);
+        ~NativeIterator();
+
+        bool next (String& filenameFound,
+                   bool* isDirectory, bool* isHidden, int64* fileSize,
+                   Time* modTime, Time* creationTime, bool* isReadOnly);
+
+        class Pimpl;
+
+    private:
+        friend class DirectoryIterator;
+        friend struct ContainerDeletePolicy<Pimpl>;
+        ScopedPointer<Pimpl> pimpl;
+
+        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeIterator)
+    };
+
+    friend struct ContainerDeletePolicy<NativeIterator::Pimpl>;
+    StringArray wildCards;
+    NativeIterator fileFinder;
+    String wildCard, path;
+    int index;
+    mutable int totalNumFiles;
+    const int whatToLookFor;
+    const bool isRecursive;
+    bool hasBeenAdvanced;
+    ScopedPointer<DirectoryIterator> subIterator;
+    File currentFile;
+
+    static StringArray parseWildcards (const String& pattern);
+    static bool fileMatches (const StringArray& wildCards, const String& filename);
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryIterator)
+};
+
+#endif   // JUCE_DIRECTORYITERATOR_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_File.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_File.cpp
new file mode 100644
index 0000000..d5c520a
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_File.cpp
@@ -0,0 +1,1086 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+File::File (const String& fullPathName)
+    : fullPath (parseAbsolutePath (fullPathName))
+{
+}
+
+File File::createFileWithoutCheckingPath (const String& path) noexcept
+{
+    File f;
+    f.fullPath = path;
+    return f;
+}
+
+File::File (const File& other)
+    : fullPath (other.fullPath)
+{
+}
+
+File& File::operator= (const String& newPath)
+{
+    fullPath = parseAbsolutePath (newPath);
+    return *this;
+}
+
+File& File::operator= (const File& other)
+{
+    fullPath = other.fullPath;
+    return *this;
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+File::File (File&& other) noexcept
+    : fullPath (static_cast <String&&> (other.fullPath))
+{
+}
+
+File& File::operator= (File&& other) noexcept
+{
+    fullPath = static_cast <String&&> (other.fullPath);
+    return *this;
+}
+#endif
+
+const File File::nonexistent;
+
+
+//==============================================================================
+String File::parseAbsolutePath (const String& p)
+{
+    if (p.isEmpty())
+        return String();
+
+#if JUCE_WINDOWS
+    // Windows..
+    String path (p.replaceCharacter ('/', '\\'));
+
+    if (path.startsWithChar (separator))
+    {
+        if (path[1] != separator)
+        {
+            /*  When you supply a raw string to the File object constructor, it must be an absolute path.
+                If you're trying to parse a string that may be either a relative path or an absolute path,
+                you MUST provide a context against which the partial path can be evaluated - you can do
+                this by simply using File::getChildFile() instead of the File constructor. E.g. saying
+                "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
+                path if that's what was supplied, or would evaluate a partial path relative to the CWD.
+            */
+            jassertfalse;
+
+            path = File::getCurrentWorkingDirectory().getFullPathName().substring (0, 2) + path;
+        }
+    }
+    else if (! path.containsChar (':'))
+    {
+        /*  When you supply a raw string to the File object constructor, it must be an absolute path.
+            If you're trying to parse a string that may be either a relative path or an absolute path,
+            you MUST provide a context against which the partial path can be evaluated - you can do
+            this by simply using File::getChildFile() instead of the File constructor. E.g. saying
+            "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
+            path if that's what was supplied, or would evaluate a partial path relative to the CWD.
+        */
+        jassertfalse;
+
+        return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName();
+    }
+#else
+    // Mac or Linux..
+
+    // Yes, I know it's legal for a unix pathname to contain a backslash, but this assertion is here
+    // to catch anyone who's trying to run code that was written on Windows with hard-coded path names.
+    // If that's why you've ended up here, use File::getChildFile() to build your paths instead.
+    jassert ((! p.containsChar ('\\')) || (p.indexOfChar ('/') >= 0 && p.indexOfChar ('/') < p.indexOfChar ('\\')));
+
+    String path (p);
+
+    if (path.startsWithChar ('~'))
+    {
+        if (path[1] == separator || path[1] == 0)
+        {
+            // expand a name of the form "~/abc"
+            path = File::getSpecialLocation (File::userHomeDirectory).getFullPathName()
+                    + path.substring (1);
+        }
+        else
+        {
+            // expand a name of type "~dave/abc"
+            const String userName (path.substring (1).upToFirstOccurrenceOf ("/", false, false));
+
+            if (struct passwd* const pw = getpwnam (userName.toUTF8()))
+                path = addTrailingSeparator (pw->pw_dir) + path.fromFirstOccurrenceOf ("/", false, false);
+        }
+    }
+    else if (! path.startsWithChar (separator))
+    {
+       #if JUCE_DEBUG || JUCE_LOG_ASSERTIONS
+        if (! (path.startsWith ("./") || path.startsWith ("../")))
+        {
+            /*  When you supply a raw string to the File object constructor, it must be an absolute path.
+                If you're trying to parse a string that may be either a relative path or an absolute path,
+                you MUST provide a context against which the partial path can be evaluated - you can do
+                this by simply using File::getChildFile() instead of the File constructor. E.g. saying
+                "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
+                path if that's what was supplied, or would evaluate a partial path relative to the CWD.
+            */
+            jassertfalse;
+
+           #if JUCE_LOG_ASSERTIONS
+            Logger::writeToLog ("Illegal absolute path: " + path);
+           #endif
+        }
+       #endif
+
+        return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName();
+    }
+#endif
+
+    while (path.endsWithChar (separator) && path != separatorString) // careful not to turn a single "/" into an empty string.
+        path = path.dropLastCharacters (1);
+
+    return path;
+}
+
+String File::addTrailingSeparator (const String& path)
+{
+    return path.endsWithChar (separator) ? path
+                                         : path + separator;
+}
+
+//==============================================================================
+#if JUCE_LINUX
+ #define NAMES_ARE_CASE_SENSITIVE 1
+#endif
+
+bool File::areFileNamesCaseSensitive()
+{
+   #if NAMES_ARE_CASE_SENSITIVE
+    return true;
+   #else
+    return false;
+   #endif
+}
+
+static int compareFilenames (const String& name1, const String& name2) noexcept
+{
+   #if NAMES_ARE_CASE_SENSITIVE
+    return name1.compare (name2);
+   #else
+    return name1.compareIgnoreCase (name2);
+   #endif
+}
+
+bool File::operator== (const File& other) const     { return compareFilenames (fullPath, other.fullPath) == 0; }
+bool File::operator!= (const File& other) const     { return compareFilenames (fullPath, other.fullPath) != 0; }
+bool File::operator<  (const File& other) const     { return compareFilenames (fullPath, other.fullPath) <  0; }
+bool File::operator>  (const File& other) const     { return compareFilenames (fullPath, other.fullPath) >  0; }
+
+//==============================================================================
+bool File::setReadOnly (const bool shouldBeReadOnly,
+                        const bool applyRecursively) const
+{
+    bool worked = true;
+
+    if (applyRecursively && isDirectory())
+    {
+        Array <File> subFiles;
+        findChildFiles (subFiles, File::findFilesAndDirectories, false);
+
+        for (int i = subFiles.size(); --i >= 0;)
+            worked = subFiles.getReference(i).setReadOnly (shouldBeReadOnly, true) && worked;
+    }
+
+    return setFileReadOnlyInternal (shouldBeReadOnly) && worked;
+}
+
+bool File::deleteRecursively() const
+{
+    bool worked = true;
+
+    if (isDirectory())
+    {
+        Array<File> subFiles;
+        findChildFiles (subFiles, File::findFilesAndDirectories, false);
+
+        for (int i = subFiles.size(); --i >= 0;)
+            worked = subFiles.getReference(i).deleteRecursively() && worked;
+    }
+
+    return deleteFile() && worked;
+}
+
+bool File::moveFileTo (const File& newFile) const
+{
+    if (newFile.fullPath == fullPath)
+        return true;
+
+    if (! exists())
+        return false;
+
+   #if ! NAMES_ARE_CASE_SENSITIVE
+    if (*this != newFile)
+   #endif
+        if (! newFile.deleteFile())
+            return false;
+
+    return moveInternal (newFile);
+}
+
+bool File::copyFileTo (const File& newFile) const
+{
+    return (*this == newFile)
+            || (exists() && newFile.deleteFile() && copyInternal (newFile));
+}
+
+bool File::copyDirectoryTo (const File& newDirectory) const
+{
+    if (isDirectory() && newDirectory.createDirectory())
+    {
+        Array<File> subFiles;
+        findChildFiles (subFiles, File::findFiles, false);
+
+        for (int i = 0; i < subFiles.size(); ++i)
+            if (! subFiles.getReference(i).copyFileTo (newDirectory.getChildFile (subFiles.getReference(i).getFileName())))
+                return false;
+
+        subFiles.clear();
+        findChildFiles (subFiles, File::findDirectories, false);
+
+        for (int i = 0; i < subFiles.size(); ++i)
+            if (! subFiles.getReference(i).copyDirectoryTo (newDirectory.getChildFile (subFiles.getReference(i).getFileName())))
+                return false;
+
+        return true;
+    }
+
+    return false;
+}
+
+//==============================================================================
+String File::getPathUpToLastSlash() const
+{
+    const int lastSlash = fullPath.lastIndexOfChar (separator);
+
+    if (lastSlash > 0)
+        return fullPath.substring (0, lastSlash);
+
+    if (lastSlash == 0)
+        return separatorString;
+
+    return fullPath;
+}
+
+File File::getParentDirectory() const
+{
+    File f;
+    f.fullPath = getPathUpToLastSlash();
+    return f;
+}
+
+//==============================================================================
+String File::getFileName() const
+{
+    return fullPath.substring (fullPath.lastIndexOfChar (separator) + 1);
+}
+
+String File::getFileNameWithoutExtension() const
+{
+    const int lastSlash = fullPath.lastIndexOfChar (separator) + 1;
+    const int lastDot   = fullPath.lastIndexOfChar ('.');
+
+    if (lastDot > lastSlash)
+        return fullPath.substring (lastSlash, lastDot);
+
+    return fullPath.substring (lastSlash);
+}
+
+bool File::isAChildOf (const File& potentialParent) const
+{
+    if (potentialParent.fullPath.isEmpty())
+        return false;
+
+    const String ourPath (getPathUpToLastSlash());
+
+    if (compareFilenames (potentialParent.fullPath, ourPath) == 0)
+        return true;
+
+    if (potentialParent.fullPath.length() >= ourPath.length())
+        return false;
+
+    return getParentDirectory().isAChildOf (potentialParent);
+}
+
+int   File::hashCode() const    { return fullPath.hashCode(); }
+int64 File::hashCode64() const  { return fullPath.hashCode64(); }
+
+//==============================================================================
+bool File::isAbsolutePath (StringRef path)
+{
+    return path.text[0] == separator
+           #if JUCE_WINDOWS
+            || (path.isNotEmpty() && path.text[1] == ':');
+           #else
+            || path.text[0] == '~';
+           #endif
+}
+
+File File::getChildFile (StringRef relativePath) const
+{
+    if (isAbsolutePath (relativePath))
+        return File (String (relativePath.text));
+
+    if (relativePath[0] != '.')
+        return File (addTrailingSeparator (fullPath) + relativePath);
+
+    String path (fullPath);
+
+    // It's relative, so remove any ../ or ./ bits at the start..
+   #if JUCE_WINDOWS
+    if (relativePath.text.indexOf ((juce_wchar) '/') >= 0)
+        return getChildFile (String (relativePath.text).replaceCharacter ('/', '\\'));
+   #endif
+
+    while (relativePath[0] == '.')
+    {
+        const juce_wchar secondChar = relativePath[1];
+
+        if (secondChar == '.')
+        {
+            const juce_wchar thirdChar = relativePath[2];
+
+            if (thirdChar == 0 || thirdChar == separator)
+            {
+                const int lastSlash = path.lastIndexOfChar (separator);
+                if (lastSlash >= 0)
+                    path = path.substring (0, lastSlash);
+
+                relativePath = relativePath.text + (thirdChar == 0 ? 2 : 3);
+            }
+            else
+            {
+                break;
+            }
+        }
+        else if (secondChar == separator)
+        {
+            relativePath = relativePath.text + 2;
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    return File (addTrailingSeparator (path) + relativePath);
+}
+
+File File::getSiblingFile (StringRef fileName) const
+{
+    return getParentDirectory().getChildFile (fileName);
+}
+
+//==============================================================================
+String File::descriptionOfSizeInBytes (const int64 bytes)
+{
+    const char* suffix;
+    double divisor = 0;
+
+    if (bytes == 1)                       { suffix = " byte"; }
+    else if (bytes < 1024)                { suffix = " bytes"; }
+    else if (bytes < 1024 * 1024)         { suffix = " KB"; divisor = 1024.0; }
+    else if (bytes < 1024 * 1024 * 1024)  { suffix = " MB"; divisor = 1024.0 * 1024.0; }
+    else                                  { suffix = " GB"; divisor = 1024.0 * 1024.0 * 1024.0; }
+
+    return (divisor > 0 ? String (bytes / divisor, 1) : String (bytes)) + suffix;
+}
+
+//==============================================================================
+Result File::create() const
+{
+    if (exists())
+        return Result::ok();
+
+    const File parentDir (getParentDirectory());
+
+    if (parentDir == *this)
+        return Result::fail ("Cannot create parent directory");
+
+    Result r (parentDir.createDirectory());
+
+    if (r.wasOk())
+    {
+        FileOutputStream fo (*this, 8);
+        r = fo.getStatus();
+    }
+
+    return r;
+}
+
+Result File::createDirectory() const
+{
+    if (isDirectory())
+        return Result::ok();
+
+    const File parentDir (getParentDirectory());
+
+    if (parentDir == *this)
+        return Result::fail ("Cannot create parent directory");
+
+    Result r (parentDir.createDirectory());
+
+    if (r.wasOk())
+        r = createDirectoryInternal (fullPath.trimCharactersAtEnd (separatorString));
+
+    return r;
+}
+
+//==============================================================================
+Time File::getLastModificationTime() const           { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (m); }
+Time File::getLastAccessTime() const                 { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (a); }
+Time File::getCreationTime() const                   { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (c); }
+
+bool File::setLastModificationTime (Time t) const    { return setFileTimesInternal (t.toMilliseconds(), 0, 0); }
+bool File::setLastAccessTime (Time t) const          { return setFileTimesInternal (0, t.toMilliseconds(), 0); }
+bool File::setCreationTime (Time t) const            { return setFileTimesInternal (0, 0, t.toMilliseconds()); }
+
+//==============================================================================
+bool File::loadFileAsData (MemoryBlock& destBlock) const
+{
+    if (! existsAsFile())
+        return false;
+
+    FileInputStream in (*this);
+    return in.openedOk() && getSize() == (int64) in.readIntoMemoryBlock (destBlock);
+}
+
+String File::loadFileAsString() const
+{
+    if (! existsAsFile())
+        return String();
+
+    FileInputStream in (*this);
+    return in.openedOk() ? in.readEntireStreamAsString()
+                         : String();
+}
+
+void File::readLines (StringArray& destLines) const
+{
+    destLines.addLines (loadFileAsString());
+}
+
+//==============================================================================
+int File::findChildFiles (Array<File>& results,
+                          const int whatToLookFor,
+                          const bool searchRecursively,
+                          const String& wildCardPattern) const
+{
+    int total = 0;
+
+    for (DirectoryIterator di (*this, searchRecursively, wildCardPattern, whatToLookFor); di.next();)
+    {
+        results.add (di.getFile());
+        ++total;
+    }
+
+    return total;
+}
+
+int File::getNumberOfChildFiles (const int whatToLookFor, const String& wildCardPattern) const
+{
+    int total = 0;
+
+    for (DirectoryIterator di (*this, false, wildCardPattern, whatToLookFor); di.next();)
+        ++total;
+
+    return total;
+}
+
+bool File::containsSubDirectories() const
+{
+    if (! isDirectory())
+        return false;
+
+    DirectoryIterator di (*this, false, "*", findDirectories);
+    return di.next();
+}
+
+//==============================================================================
+File File::getNonexistentChildFile (const String& suggestedPrefix,
+                                    const String& suffix,
+                                    bool putNumbersInBrackets) const
+{
+    File f (getChildFile (suggestedPrefix + suffix));
+
+    if (f.exists())
+    {
+        int number = 1;
+        String prefix (suggestedPrefix);
+
+        // remove any bracketed numbers that may already be on the end..
+        if (prefix.trim().endsWithChar (')'))
+        {
+            putNumbersInBrackets = true;
+
+            const int openBracks  = prefix.lastIndexOfChar ('(');
+            const int closeBracks = prefix.lastIndexOfChar (')');
+
+            if (openBracks > 0
+                 && closeBracks > openBracks
+                 && prefix.substring (openBracks + 1, closeBracks).containsOnly ("0123456789"))
+            {
+                number = prefix.substring (openBracks + 1, closeBracks).getIntValue();
+                prefix = prefix.substring (0, openBracks);
+            }
+        }
+
+        // also use brackets if it ends in a digit.
+        putNumbersInBrackets = putNumbersInBrackets
+                                 || CharacterFunctions::isDigit (prefix.getLastCharacter());
+
+        do
+        {
+            String newName (prefix);
+
+            if (putNumbersInBrackets)
+                newName << '(' << ++number << ')';
+            else
+                newName << ++number;
+
+            f = getChildFile (newName + suffix);
+
+        } while (f.exists());
+    }
+
+    return f;
+}
+
+File File::getNonexistentSibling (const bool putNumbersInBrackets) const
+{
+    if (! exists())
+        return *this;
+
+    return getParentDirectory().getNonexistentChildFile (getFileNameWithoutExtension(),
+                                                         getFileExtension(),
+                                                         putNumbersInBrackets);
+}
+
+//==============================================================================
+String File::getFileExtension() const
+{
+    const int indexOfDot = fullPath.lastIndexOfChar ('.');
+
+    if (indexOfDot > fullPath.lastIndexOfChar (separator))
+        return fullPath.substring (indexOfDot);
+
+    return String();
+}
+
+bool File::hasFileExtension (StringRef possibleSuffix) const
+{
+    if (possibleSuffix.isEmpty())
+        return fullPath.lastIndexOfChar ('.') <= fullPath.lastIndexOfChar (separator);
+
+    const int semicolon = possibleSuffix.text.indexOf ((juce_wchar) ';');
+
+    if (semicolon >= 0)
+        return hasFileExtension (String (possibleSuffix.text).substring (0, semicolon).trimEnd())
+                || hasFileExtension ((possibleSuffix.text + (semicolon + 1)).findEndOfWhitespace());
+
+    if (fullPath.endsWithIgnoreCase (possibleSuffix))
+    {
+        if (possibleSuffix.text[0] == '.')
+            return true;
+
+        const int dotPos = fullPath.length() - possibleSuffix.length() - 1;
+
+        if (dotPos >= 0)
+            return fullPath [dotPos] == '.';
+    }
+
+    return false;
+}
+
+File File::withFileExtension (StringRef newExtension) const
+{
+    if (fullPath.isEmpty())
+        return File();
+
+    String filePart (getFileName());
+
+    const int i = filePart.lastIndexOfChar ('.');
+    if (i >= 0)
+        filePart = filePart.substring (0, i);
+
+    if (newExtension.isNotEmpty() && newExtension.text[0] != '.')
+        filePart << '.';
+
+    return getSiblingFile (filePart + newExtension);
+}
+
+//==============================================================================
+bool File::startAsProcess (const String& parameters) const
+{
+    return exists() && Process::openDocument (fullPath, parameters);
+}
+
+//==============================================================================
+FileInputStream* File::createInputStream() const
+{
+    ScopedPointer<FileInputStream> fin (new FileInputStream (*this));
+
+    if (fin->openedOk())
+        return fin.release();
+
+    return nullptr;
+}
+
+FileOutputStream* File::createOutputStream (const size_t bufferSize) const
+{
+    ScopedPointer<FileOutputStream> out (new FileOutputStream (*this, bufferSize));
+
+    return out->failedToOpen() ? nullptr
+                               : out.release();
+}
+
+//==============================================================================
+bool File::appendData (const void* const dataToAppend,
+                       const size_t numberOfBytes) const
+{
+    jassert (((ssize_t) numberOfBytes) >= 0);
+
+    if (numberOfBytes == 0)
+        return true;
+
+    FileOutputStream out (*this, 8192);
+    return out.openedOk() && out.write (dataToAppend, numberOfBytes);
+}
+
+bool File::replaceWithData (const void* const dataToWrite,
+                            const size_t numberOfBytes) const
+{
+    if (numberOfBytes == 0)
+        return deleteFile();
+
+    TemporaryFile tempFile (*this, TemporaryFile::useHiddenFile);
+    tempFile.getFile().appendData (dataToWrite, numberOfBytes);
+    return tempFile.overwriteTargetFileWithTemporary();
+}
+
+bool File::appendText (const String& text,
+                       const bool asUnicode,
+                       const bool writeUnicodeHeaderBytes) const
+{
+    FileOutputStream out (*this);
+
+    if (out.failedToOpen())
+        return false;
+
+    out.writeText (text, asUnicode, writeUnicodeHeaderBytes);
+    return true;
+}
+
+bool File::replaceWithText (const String& textToWrite,
+                            const bool asUnicode,
+                            const bool writeUnicodeHeaderBytes) const
+{
+    TemporaryFile tempFile (*this, TemporaryFile::useHiddenFile);
+    tempFile.getFile().appendText (textToWrite, asUnicode, writeUnicodeHeaderBytes);
+    return tempFile.overwriteTargetFileWithTemporary();
+}
+
+bool File::hasIdenticalContentTo (const File& other) const
+{
+    if (other == *this)
+        return true;
+
+    if (getSize() == other.getSize() && existsAsFile() && other.existsAsFile())
+    {
+        FileInputStream in1 (*this), in2 (other);
+
+        if (in1.openedOk() && in2.openedOk())
+        {
+            const int bufferSize = 4096;
+            HeapBlock<char> buffer1 (bufferSize), buffer2 (bufferSize);
+
+            for (;;)
+            {
+                const int num1 = in1.read (buffer1, bufferSize);
+                const int num2 = in2.read (buffer2, bufferSize);
+
+                if (num1 != num2)
+                    break;
+
+                if (num1 <= 0)
+                    return true;
+
+                if (memcmp (buffer1, buffer2, (size_t) num1) != 0)
+                    break;
+            }
+        }
+    }
+
+    return false;
+}
+
+//==============================================================================
+String File::createLegalPathName (const String& original)
+{
+    String s (original);
+    String start;
+
+    if (s.isNotEmpty() && s[1] == ':')
+    {
+        start = s.substring (0, 2);
+        s = s.substring (2);
+    }
+
+    return start + s.removeCharacters ("\"#@,;:<>*^|?")
+                    .substring (0, 1024);
+}
+
+String File::createLegalFileName (const String& original)
+{
+    String s (original.removeCharacters ("\"#@,;:<>*^|?\\/"));
+
+    const int maxLength = 128; // only the length of the filename, not the whole path
+    const int len = s.length();
+
+    if (len > maxLength)
+    {
+        const int lastDot = s.lastIndexOfChar ('.');
+
+        if (lastDot > jmax (0, len - 12))
+        {
+            s = s.substring (0, maxLength - (len - lastDot))
+                 + s.substring (lastDot);
+        }
+        else
+        {
+            s = s.substring (0, maxLength);
+        }
+    }
+
+    return s;
+}
+
+//==============================================================================
+static int countNumberOfSeparators (String::CharPointerType s)
+{
+    int num = 0;
+
+    for (;;)
+    {
+        const juce_wchar c = s.getAndAdvance();
+
+        if (c == 0)
+            break;
+
+        if (c == File::separator)
+            ++num;
+    }
+
+    return num;
+}
+
+String File::getRelativePathFrom (const File& dir)  const
+{
+    String thisPath (fullPath);
+
+    while (thisPath.endsWithChar (separator))
+        thisPath = thisPath.dropLastCharacters (1);
+
+    String dirPath (addTrailingSeparator (dir.existsAsFile() ? dir.getParentDirectory().getFullPathName()
+                                                             : dir.fullPath));
+
+    int commonBitLength = 0;
+    String::CharPointerType thisPathAfterCommon (thisPath.getCharPointer());
+    String::CharPointerType dirPathAfterCommon  (dirPath.getCharPointer());
+
+    {
+        String::CharPointerType thisPathIter (thisPath.getCharPointer());
+        String::CharPointerType dirPathIter  (dirPath.getCharPointer());
+
+        for (int i = 0;;)
+        {
+            const juce_wchar c1 = thisPathIter.getAndAdvance();
+            const juce_wchar c2 = dirPathIter.getAndAdvance();
+
+           #if NAMES_ARE_CASE_SENSITIVE
+            if (c1 != c2
+           #else
+            if ((c1 != c2 && CharacterFunctions::toLowerCase (c1) != CharacterFunctions::toLowerCase (c2))
+           #endif
+                 || c1 == 0)
+                break;
+
+            ++i;
+
+            if (c1 == separator)
+            {
+                thisPathAfterCommon = thisPathIter;
+                dirPathAfterCommon  = dirPathIter;
+                commonBitLength = i;
+            }
+        }
+    }
+
+    // if the only common bit is the root, then just return the full path..
+    if (commonBitLength == 0 || (commonBitLength == 1 && thisPath[1] == separator))
+        return fullPath;
+
+    const int numUpDirectoriesNeeded = countNumberOfSeparators (dirPathAfterCommon);
+
+    if (numUpDirectoriesNeeded == 0)
+        return thisPathAfterCommon;
+
+   #if JUCE_WINDOWS
+    String s (String::repeatedString ("..\\", numUpDirectoriesNeeded));
+   #else
+    String s (String::repeatedString ("../",  numUpDirectoriesNeeded));
+   #endif
+    s.appendCharPointer (thisPathAfterCommon);
+    return s;
+}
+
+//==============================================================================
+File File::createTempFile (StringRef fileNameEnding)
+{
+    const File tempFile (getSpecialLocation (tempDirectory)
+                            .getChildFile ("temp_" + String::toHexString (Random::getSystemRandom().nextInt()))
+                            .withFileExtension (fileNameEnding));
+
+    if (tempFile.exists())
+        return createTempFile (fileNameEnding);
+
+    return tempFile;
+}
+
+//==============================================================================
+MemoryMappedFile::MemoryMappedFile (const File& file, MemoryMappedFile::AccessMode mode)
+    : address (nullptr), range (0, file.getSize()), fileHandle (0)
+{
+    openInternal (file, mode);
+}
+
+MemoryMappedFile::MemoryMappedFile (const File& file, const Range<int64>& fileRange, AccessMode mode)
+    : address (nullptr), range (fileRange.getIntersectionWith (Range<int64> (0, file.getSize()))), fileHandle (0)
+{
+    openInternal (file, mode);
+}
+
+
+//==============================================================================
+#if JUCE_UNIT_TESTS
+
+class FileTests  : public UnitTest
+{
+public:
+    FileTests() : UnitTest ("Files") {}
+
+    void runTest()
+    {
+        beginTest ("Reading");
+
+        const File home (File::getSpecialLocation (File::userHomeDirectory));
+        const File temp (File::getSpecialLocation (File::tempDirectory));
+
+        expect (! File::nonexistent.exists());
+        expect (home.isDirectory());
+        expect (home.exists());
+        expect (! home.existsAsFile());
+        expect (File::getSpecialLocation (File::userDocumentsDirectory).isDirectory());
+        expect (File::getSpecialLocation (File::userApplicationDataDirectory).isDirectory());
+        expect (File::getSpecialLocation (File::currentExecutableFile).exists());
+        expect (File::getSpecialLocation (File::currentApplicationFile).exists());
+        expect (File::getSpecialLocation (File::invokedExecutableFile).exists());
+        expect (home.getVolumeTotalSize() > 1024 * 1024);
+        expect (home.getBytesFreeOnVolume() > 0);
+        expect (! home.isHidden());
+        expect (home.isOnHardDisk());
+        expect (! home.isOnCDRomDrive());
+        expect (File::getCurrentWorkingDirectory().exists());
+        expect (home.setAsCurrentWorkingDirectory());
+        expect (File::getCurrentWorkingDirectory() == home);
+
+        {
+            Array<File> roots;
+            File::findFileSystemRoots (roots);
+            expect (roots.size() > 0);
+
+            int numRootsExisting = 0;
+            for (int i = 0; i < roots.size(); ++i)
+                if (roots[i].exists())
+                    ++numRootsExisting;
+
+            // (on windows, some of the drives may not contain media, so as long as at least one is ok..)
+            expect (numRootsExisting > 0);
+        }
+
+        beginTest ("Writing");
+
+        File demoFolder (temp.getChildFile ("Juce UnitTests Temp Folder.folder"));
+        expect (demoFolder.deleteRecursively());
+        expect (demoFolder.createDirectory());
+        expect (demoFolder.isDirectory());
+        expect (demoFolder.getParentDirectory() == temp);
+        expect (temp.isDirectory());
+
+        {
+            Array<File> files;
+            temp.findChildFiles (files, File::findFilesAndDirectories, false, "*");
+            expect (files.contains (demoFolder));
+        }
+
+        {
+            Array<File> files;
+            temp.findChildFiles (files, File::findDirectories, true, "*.folder");
+            expect (files.contains (demoFolder));
+        }
+
+        File tempFile (demoFolder.getNonexistentChildFile ("test", ".txt", false));
+
+        expect (tempFile.getFileExtension() == ".txt");
+        expect (tempFile.hasFileExtension (".txt"));
+        expect (tempFile.hasFileExtension ("txt"));
+        expect (tempFile.withFileExtension ("xyz").hasFileExtension (".xyz"));
+        expect (tempFile.withFileExtension ("xyz").hasFileExtension ("abc;xyz;foo"));
+        expect (tempFile.withFileExtension ("xyz").hasFileExtension ("xyz;foo"));
+        expect (! tempFile.withFileExtension ("h").hasFileExtension ("bar;foo;xx"));
+        expect (tempFile.getSiblingFile ("foo").isAChildOf (temp));
+        expect (tempFile.hasWriteAccess());
+
+        {
+            FileOutputStream fo (tempFile);
+            fo.write ("0123456789", 10);
+        }
+
+        expect (tempFile.exists());
+        expect (tempFile.getSize() == 10);
+        expect (std::abs ((int) (tempFile.getLastModificationTime().toMilliseconds() - Time::getCurrentTime().toMilliseconds())) < 3000);
+        expectEquals (tempFile.loadFileAsString(), String ("0123456789"));
+        expect (! demoFolder.containsSubDirectories());
+
+        expectEquals (tempFile.getRelativePathFrom (demoFolder.getParentDirectory()), demoFolder.getFileName() + File::separatorString + tempFile.getFileName());
+        expectEquals (demoFolder.getParentDirectory().getRelativePathFrom (tempFile), ".." + File::separatorString + ".." + File::separatorString + demoFolder.getParentDirectory().getFileName());
+
+        expect (demoFolder.getNumberOfChildFiles (File::findFiles) == 1);
+        expect (demoFolder.getNumberOfChildFiles (File::findFilesAndDirectories) == 1);
+        expect (demoFolder.getNumberOfChildFiles (File::findDirectories) == 0);
+        demoFolder.getNonexistentChildFile ("tempFolder", "", false).createDirectory();
+        expect (demoFolder.getNumberOfChildFiles (File::findDirectories) == 1);
+        expect (demoFolder.getNumberOfChildFiles (File::findFilesAndDirectories) == 2);
+        expect (demoFolder.containsSubDirectories());
+
+        expect (tempFile.hasWriteAccess());
+        tempFile.setReadOnly (true);
+        expect (! tempFile.hasWriteAccess());
+        tempFile.setReadOnly (false);
+        expect (tempFile.hasWriteAccess());
+
+        Time t (Time::getCurrentTime());
+        tempFile.setLastModificationTime (t);
+        Time t2 = tempFile.getLastModificationTime();
+        expect (std::abs ((int) (t2.toMilliseconds() - t.toMilliseconds())) <= 1000);
+
+        {
+            MemoryBlock mb;
+            tempFile.loadFileAsData (mb);
+            expect (mb.getSize() == 10);
+            expect (mb[0] == '0');
+        }
+
+        {
+            expect (tempFile.getSize() == 10);
+            FileOutputStream fo (tempFile);
+            expect (fo.openedOk());
+
+            expect (fo.setPosition  (7));
+            expect (fo.truncate().wasOk());
+            expect (tempFile.getSize() == 7);
+            fo.write ("789", 3);
+            fo.flush();
+            expect (tempFile.getSize() == 10);
+        }
+
+        beginTest ("Memory-mapped files");
+
+        {
+            MemoryMappedFile mmf (tempFile, MemoryMappedFile::readOnly);
+            expect (mmf.getSize() == 10);
+            expect (mmf.getData() != nullptr);
+            expect (memcmp (mmf.getData(), "0123456789", 10) == 0);
+        }
+
+        {
+            const File tempFile2 (tempFile.getNonexistentSibling (false));
+            expect (tempFile2.create());
+            expect (tempFile2.appendData ("xxxxxxxxxx", 10));
+
+            {
+                MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite);
+                expect (mmf.getSize() == 10);
+                expect (mmf.getData() != nullptr);
+                memcpy (mmf.getData(), "abcdefghij", 10);
+            }
+
+            {
+                MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite);
+                expect (mmf.getSize() == 10);
+                expect (mmf.getData() != nullptr);
+                expect (memcmp (mmf.getData(), "abcdefghij", 10) == 0);
+            }
+
+            expect (tempFile2.deleteFile());
+        }
+
+        beginTest ("More writing");
+
+        expect (tempFile.appendData ("abcdefghij", 10));
+        expect (tempFile.getSize() == 20);
+        expect (tempFile.replaceWithData ("abcdefghij", 10));
+        expect (tempFile.getSize() == 10);
+
+        File tempFile2 (tempFile.getNonexistentSibling (false));
+        expect (tempFile.copyFileTo (tempFile2));
+        expect (tempFile2.exists());
+        expect (tempFile2.hasIdenticalContentTo (tempFile));
+        expect (tempFile.deleteFile());
+        expect (! tempFile.exists());
+        expect (tempFile2.moveFileTo (tempFile));
+        expect (tempFile.exists());
+        expect (! tempFile2.exists());
+
+        expect (demoFolder.deleteRecursively());
+        expect (! demoFolder.exists());
+    }
+};
+
+static FileTests fileUnitTests;
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_File.h b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_File.h
new file mode 100644
index 0000000..57d970f
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_File.h
@@ -0,0 +1,973 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_FILE_H_INCLUDED
+#define JUCE_FILE_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Represents a local file or directory.
+
+    This class encapsulates the absolute pathname of a file or directory, and
+    has methods for finding out about the file and changing its properties.
+
+    To read or write to the file, there are methods for returning an input or
+    output stream.
+
+    @see FileInputStream, FileOutputStream
+*/
+class JUCE_API  File
+{
+public:
+    //==============================================================================
+    /** Creates an (invalid) file object.
+
+        The file is initially set to an empty path, so getFullPath() will return
+        an empty string, and comparing the file to File::nonexistent will return
+        true.
+
+        You can use its operator= method to point it at a proper file.
+    */
+    File() noexcept  {}
+
+    /** Creates a file from an absolute path.
+
+        If the path supplied is a relative path, it is taken to be relative
+        to the current working directory (see File::getCurrentWorkingDirectory()),
+        but this isn't a recommended way of creating a file, because you
+        never know what the CWD is going to be.
+
+        On the Mac/Linux, the path can include "~" notation for referring to
+        user home directories.
+    */
+    File (const String& absolutePath);
+
+    /** Creates a copy of another file object. */
+    File (const File&);
+
+    /** Destructor. */
+    ~File() noexcept  {}
+
+    /** Sets the file based on an absolute pathname.
+
+        If the path supplied is a relative path, it is taken to be relative
+        to the current working directory (see File::getCurrentWorkingDirectory()),
+        but this isn't a recommended way of creating a file, because you
+        never know what the CWD is going to be.
+
+        On the Mac/Linux, the path can include "~" notation for referring to
+        user home directories.
+    */
+    File& operator= (const String& newAbsolutePath);
+
+    /** Copies from another file object. */
+    File& operator= (const File& otherFile);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    File (File&&) noexcept;
+    File& operator= (File&&) noexcept;
+   #endif
+
+    //==============================================================================
+    /** This static constant is used for referring to an 'invalid' file. */
+    static const File nonexistent;
+
+    //==============================================================================
+    /** Checks whether the file actually exists.
+
+        @returns    true if the file exists, either as a file or a directory.
+        @see existsAsFile, isDirectory
+    */
+    bool exists() const;
+
+    /** Checks whether the file exists and is a file rather than a directory.
+
+        @returns    true only if this is a real file, false if it's a directory
+                    or doesn't exist
+        @see exists, isDirectory
+    */
+    bool existsAsFile() const;
+
+    /** Checks whether the file is a directory that exists.
+
+        @returns    true only if the file is a directory which actually exists, so
+                    false if it's a file or doesn't exist at all
+        @see exists, existsAsFile
+    */
+    bool isDirectory() const;
+
+    /** Returns the size of the file in bytes.
+
+        @returns    the number of bytes in the file, or 0 if it doesn't exist.
+    */
+    int64 getSize() const;
+
+    /** Utility function to convert a file size in bytes to a neat string description.
+
+        So for example 100 would return "100 bytes", 2000 would return "2 KB",
+        2000000 would produce "2 MB", etc.
+    */
+    static String descriptionOfSizeInBytes (int64 bytes);
+
+    //==============================================================================
+    /** Returns the complete, absolute path of this file.
+
+        This includes the filename and all its parent folders. On Windows it'll
+        also include the drive letter prefix; on Mac or Linux it'll be a complete
+        path starting from the root folder.
+
+        If you just want the file's name, you should use getFileName() or
+        getFileNameWithoutExtension().
+
+        @see getFileName, getRelativePathFrom
+    */
+    const String& getFullPathName() const noexcept          { return fullPath; }
+
+    /** Returns the last section of the pathname.
+
+        Returns just the final part of the path - e.g. if the whole path
+        is "/moose/fish/foo.txt" this will return "foo.txt".
+
+        For a directory, it returns the final part of the path - e.g. for the
+        directory "/moose/fish" it'll return "fish".
+
+        If the filename begins with a dot, it'll return the whole filename, e.g. for
+        "/moose/.fish", it'll return ".fish"
+
+        @see getFullPathName, getFileNameWithoutExtension
+    */
+    String getFileName() const;
+
+    /** Creates a relative path that refers to a file relatively to a given directory.
+
+        e.g. File ("/moose/foo.txt").getRelativePathFrom (File ("/moose/fish/haddock"))
+             would return "../../foo.txt".
+
+        If it's not possible to navigate from one file to the other, an absolute
+        path is returned. If the paths are invalid, an empty string may also be
+        returned.
+
+        @param directoryToBeRelativeTo  the directory which the resultant string will
+                                        be relative to. If this is actually a file rather than
+                                        a directory, its parent directory will be used instead.
+                                        If it doesn't exist, it's assumed to be a directory.
+        @see getChildFile, isAbsolutePath
+    */
+    String getRelativePathFrom (const File& directoryToBeRelativeTo) const;
+
+    //==============================================================================
+    /** Returns the file's extension.
+
+        Returns the file extension of this file, also including the dot.
+
+        e.g. "/moose/fish/foo.txt" would return ".txt"
+
+        @see hasFileExtension, withFileExtension, getFileNameWithoutExtension
+    */
+    String getFileExtension() const;
+
+    /** Checks whether the file has a given extension.
+
+        @param extensionToTest  the extension to look for - it doesn't matter whether or
+                                not this string has a dot at the start, so ".wav" and "wav"
+                                will have the same effect. To compare with multiple extensions, this
+                                parameter can contain multiple strings, separated by semi-colons -
+                                so, for example: hasFileExtension (".jpeg;png;gif") would return
+                                true if the file has any of those three extensions.
+
+        @see getFileExtension, withFileExtension, getFileNameWithoutExtension
+    */
+    bool hasFileExtension (StringRef extensionToTest) const;
+
+    /** Returns a version of this file with a different file extension.
+
+        e.g. File ("/moose/fish/foo.txt").withFileExtension ("html") returns "/moose/fish/foo.html"
+
+        @param newExtension     the new extension, either with or without a dot at the start (this
+                                doesn't make any difference). To get remove a file's extension altogether,
+                                pass an empty string into this function.
+
+        @see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension
+    */
+    File withFileExtension (StringRef newExtension) const;
+
+    /** Returns the last part of the filename, without its file extension.
+
+        e.g. for "/moose/fish/foo.txt" this will return "foo".
+
+        @see getFileName, getFileExtension, hasFileExtension, withFileExtension
+    */
+    String getFileNameWithoutExtension() const;
+
+    //==============================================================================
+    /** Returns a 32-bit hash-code that identifies this file.
+
+        This is based on the filename. Obviously it's possible, although unlikely, that
+        two files will have the same hash-code.
+    */
+    int hashCode() const;
+
+    /** Returns a 64-bit hash-code that identifies this file.
+
+        This is based on the filename. Obviously it's possible, although unlikely, that
+        two files will have the same hash-code.
+    */
+    int64 hashCode64() const;
+
+    //==============================================================================
+    /** Returns a file that represents a relative (or absolute) sub-path of the current one.
+
+        This will find a child file or directory of the current object.
+
+        e.g.
+            File ("/moose/fish").getChildFile ("foo.txt") will produce "/moose/fish/foo.txt".
+            File ("/moose/fish").getChildFile ("haddock/foo.txt") will produce "/moose/fish/haddock/foo.txt".
+            File ("/moose/fish").getChildFile ("../foo.txt") will produce "/moose/foo.txt".
+
+        If the string is actually an absolute path, it will be treated as such, e.g.
+            File ("/moose/fish").getChildFile ("/foo.txt") will produce "/foo.txt"
+
+        @see getSiblingFile, getParentDirectory, getRelativePathFrom, isAChildOf
+    */
+    File getChildFile (StringRef relativeOrAbsolutePath) const;
+
+    /** Returns a file which is in the same directory as this one.
+
+        This is equivalent to getParentDirectory().getChildFile (name).
+
+        @see getChildFile, getParentDirectory
+    */
+    File getSiblingFile (StringRef siblingFileName) const;
+
+    //==============================================================================
+    /** Returns the directory that contains this file or directory.
+
+        e.g. for "/moose/fish/foo.txt" this will return "/moose/fish".
+    */
+    File getParentDirectory() const;
+
+    /** Checks whether a file is somewhere inside a directory.
+
+        Returns true if this file is somewhere inside a subdirectory of the directory
+        that is passed in. Neither file actually has to exist, because the function
+        just checks the paths for similarities.
+
+        e.g. File ("/moose/fish/foo.txt").isAChildOf ("/moose") is true.
+             File ("/moose/fish/foo.txt").isAChildOf ("/moose/fish") is also true.
+    */
+    bool isAChildOf (const File& potentialParentDirectory) const;
+
+    //==============================================================================
+    /** Chooses a filename relative to this one that doesn't already exist.
+
+        If this file is a directory, this will return a child file of this
+        directory that doesn't exist, by adding numbers to a prefix and suffix until
+        it finds one that isn't already there.
+
+        If the prefix + the suffix doesn't exist, it won't bother adding a number.
+
+        e.g. File ("/moose/fish").getNonexistentChildFile ("foo", ".txt", true) might
+             return "/moose/fish/foo(2).txt" if there's already a file called "foo.txt".
+
+        @param prefix                   the string to use for the filename before the number
+        @param suffix                   the string to add to the filename after the number
+        @param putNumbersInBrackets     if true, this will create filenames in the
+                                        format "prefix(number)suffix", if false, it will leave the
+                                        brackets out.
+    */
+    File getNonexistentChildFile (const String& prefix,
+                                  const String& suffix,
+                                  bool putNumbersInBrackets = true) const;
+
+    /** Chooses a filename for a sibling file to this one that doesn't already exist.
+
+        If this file doesn't exist, this will just return itself, otherwise it
+        will return an appropriate sibling that doesn't exist, e.g. if a file
+        "/moose/fish/foo.txt" exists, this might return "/moose/fish/foo(2).txt".
+
+        @param putNumbersInBrackets     whether to add brackets around the numbers that
+                                        get appended to the new filename.
+    */
+    File getNonexistentSibling (bool putNumbersInBrackets = true) const;
+
+    //==============================================================================
+    /** Compares the pathnames for two files. */
+    bool operator== (const File&) const;
+    /** Compares the pathnames for two files. */
+    bool operator!= (const File&) const;
+    /** Compares the pathnames for two files. */
+    bool operator< (const File&) const;
+    /** Compares the pathnames for two files. */
+    bool operator> (const File&) const;
+
+    //==============================================================================
+    /** Checks whether a file can be created or written to.
+
+        @returns    true if it's possible to create and write to this file. If the file
+                    doesn't already exist, this will check its parent directory to
+                    see if writing is allowed.
+        @see setReadOnly
+    */
+    bool hasWriteAccess() const;
+
+    /** Changes the write-permission of a file or directory.
+
+        @param shouldBeReadOnly     whether to add or remove write-permission
+        @param applyRecursively     if the file is a directory and this is true, it will
+                                    recurse through all the subfolders changing the permissions
+                                    of all files
+        @returns    true if it manages to change the file's permissions.
+        @see hasWriteAccess
+    */
+    bool setReadOnly (bool shouldBeReadOnly,
+                      bool applyRecursively = false) const;
+
+    /** Returns true if this file is a hidden or system file.
+        The criteria for deciding whether a file is hidden are platform-dependent.
+    */
+    bool isHidden() const;
+
+    /** Returns true if this file is a link or alias that can be followed using getLinkedTarget(). */
+    bool isLink() const;
+
+    /** If this file is a link or alias, this returns the file that it points to.
+        If the file isn't actually link, it'll just return itself.
+    */
+    File getLinkedTarget() const;
+
+    /** Returns a unique identifier for the file, if one is available.
+
+        Depending on the OS and file-system, this may be a unix inode number or
+        a win32 file identifier, or 0 if it fails to find one. The number will
+        be unique on the filesystem, but not globally.
+    */
+    uint64 getFileIdentifier() const;
+
+    //==============================================================================
+    /** Returns the last modification time of this file.
+
+        @returns    the time, or an invalid time if the file doesn't exist.
+        @see setLastModificationTime, getLastAccessTime, getCreationTime
+    */
+    Time getLastModificationTime() const;
+
+    /** Returns the last time this file was accessed.
+
+        @returns    the time, or an invalid time if the file doesn't exist.
+        @see setLastAccessTime, getLastModificationTime, getCreationTime
+    */
+    Time getLastAccessTime() const;
+
+    /** Returns the time that this file was created.
+
+        @returns    the time, or an invalid time if the file doesn't exist.
+        @see getLastModificationTime, getLastAccessTime
+    */
+    Time getCreationTime() const;
+
+    /** Changes the modification time for this file.
+
+        @param newTime  the time to apply to the file
+        @returns true if it manages to change the file's time.
+        @see getLastModificationTime, setLastAccessTime, setCreationTime
+    */
+    bool setLastModificationTime (Time newTime) const;
+
+    /** Changes the last-access time for this file.
+
+        @param newTime  the time to apply to the file
+        @returns true if it manages to change the file's time.
+        @see getLastAccessTime, setLastModificationTime, setCreationTime
+    */
+    bool setLastAccessTime (Time newTime) const;
+
+    /** Changes the creation date for this file.
+
+        @param newTime  the time to apply to the file
+        @returns true if it manages to change the file's time.
+        @see getCreationTime, setLastModificationTime, setLastAccessTime
+    */
+    bool setCreationTime (Time newTime) const;
+
+    /** If possible, this will try to create a version string for the given file.
+
+        The OS may be able to look at the file and give a version for it - e.g. with
+        executables, bundles, dlls, etc. If no version is available, this will
+        return an empty string.
+    */
+    String getVersion() const;
+
+    //==============================================================================
+    /** Creates an empty file if it doesn't already exist.
+
+        If the file that this object refers to doesn't exist, this will create a file
+        of zero size.
+
+        If it already exists or is a directory, this method will do nothing.
+
+        @returns    true if the file has been created (or if it already existed).
+        @see createDirectory
+    */
+    Result create() const;
+
+    /** Creates a new directory for this filename.
+
+        This will try to create the file as a directory, and fill also create
+        any parent directories it needs in order to complete the operation.
+
+        @returns    a result to indicate whether the directory was created successfully, or
+                    an error message if it failed.
+        @see create
+    */
+    Result createDirectory() const;
+
+    /** Deletes a file.
+
+        If this file is actually a directory, it may not be deleted correctly if it
+        contains files. See deleteRecursively() as a better way of deleting directories.
+
+        @returns    true if the file has been successfully deleted (or if it didn't exist to
+                    begin with).
+        @see deleteRecursively
+    */
+    bool deleteFile() const;
+
+    /** Deletes a file or directory and all its subdirectories.
+
+        If this file is a directory, this will try to delete it and all its subfolders. If
+        it's just a file, it will just try to delete the file.
+
+        @returns    true if the file and all its subfolders have been successfully deleted
+                    (or if it didn't exist to begin with).
+        @see deleteFile
+    */
+    bool deleteRecursively() const;
+
+    /** Moves this file or folder to the trash.
+
+        @returns true if the operation succeeded. It could fail if the trash is full, or
+                 if the file is write-protected, so you should check the return value
+                 and act appropriately.
+    */
+    bool moveToTrash() const;
+
+    /** Moves or renames a file.
+
+        Tries to move a file to a different location.
+        If the target file already exists, this will attempt to delete it first, and
+        will fail if this can't be done.
+
+        Note that the destination file isn't the directory to put it in, it's the actual
+        filename that you want the new file to have.
+
+        @returns    true if the operation succeeds
+    */
+    bool moveFileTo (const File& targetLocation) const;
+
+    /** Copies a file.
+
+        Tries to copy a file to a different location.
+        If the target file already exists, this will attempt to delete it first, and
+        will fail if this can't be done.
+
+        @returns    true if the operation succeeds
+    */
+    bool copyFileTo (const File& targetLocation) const;
+
+    /** Copies a directory.
+
+        Tries to copy an entire directory, recursively.
+
+        If this file isn't a directory or if any target files can't be created, this
+        will return false.
+
+        @param newDirectory    the directory that this one should be copied to. Note that this
+                               is the name of the actual directory to create, not the directory
+                               into which the new one should be placed, so there must be enough
+                               write privileges to create it if it doesn't exist. Any files inside
+                               it will be overwritten by similarly named ones that are copied.
+    */
+    bool copyDirectoryTo (const File& newDirectory) const;
+
+    //==============================================================================
+    /** Used in file searching, to specify whether to return files, directories, or both.
+    */
+    enum TypesOfFileToFind
+    {
+        findDirectories             = 1,    /**< Use this flag to indicate that you want to find directories. */
+        findFiles                   = 2,    /**< Use this flag to indicate that you want to find files. */
+        findFilesAndDirectories     = 3,    /**< Use this flag to indicate that you want to find both files and directories. */
+        ignoreHiddenFiles           = 4     /**< Add this flag to avoid returning any hidden files in the results. */
+    };
+
+    /** Searches inside a directory for files matching a wildcard pattern.
+
+        Assuming that this file is a directory, this method will search it
+        for either files or subdirectories whose names match a filename pattern.
+
+        @param results                  an array to which File objects will be added for the
+                                        files that the search comes up with
+        @param whatToLookFor            a value from the TypesOfFileToFind enum, specifying whether to
+                                        return files, directories, or both. If the ignoreHiddenFiles flag
+                                        is also added to this value, hidden files won't be returned
+        @param searchRecursively        if true, all subdirectories will be recursed into to do
+                                        an exhaustive search
+        @param wildCardPattern          the filename pattern to search for, e.g. "*.txt"
+        @returns                        the number of results that have been found
+
+        @see getNumberOfChildFiles, DirectoryIterator
+    */
+    int findChildFiles (Array<File>& results,
+                        int whatToLookFor,
+                        bool searchRecursively,
+                        const String& wildCardPattern = "*") const;
+
+    /** Searches inside a directory and counts how many files match a wildcard pattern.
+
+        Assuming that this file is a directory, this method will search it
+        for either files or subdirectories whose names match a filename pattern,
+        and will return the number of matches found.
+
+        This isn't a recursive call, and will only search this directory, not
+        its children.
+
+        @param whatToLookFor    a value from the TypesOfFileToFind enum, specifying whether to
+                                count files, directories, or both. If the ignoreHiddenFiles flag
+                                is also added to this value, hidden files won't be counted
+        @param wildCardPattern  the filename pattern to search for, e.g. "*.txt"
+        @returns                the number of matches found
+        @see findChildFiles, DirectoryIterator
+    */
+    int getNumberOfChildFiles (int whatToLookFor,
+                               const String& wildCardPattern = "*") const;
+
+    /** Returns true if this file is a directory that contains one or more subdirectories.
+        @see isDirectory, findChildFiles
+    */
+    bool containsSubDirectories() const;
+
+    //==============================================================================
+    /** Creates a stream to read from this file.
+
+        @returns    a stream that will read from this file (initially positioned at the
+                    start of the file), or nullptr if the file can't be opened for some reason
+        @see createOutputStream, loadFileAsData
+    */
+    FileInputStream* createInputStream() const;
+
+    /** Creates a stream to write to this file.
+
+        If the file exists, the stream that is returned will be positioned ready for
+        writing at the end of the file, so you might want to use deleteFile() first
+        to write to an empty file.
+
+        @returns    a stream that will write to this file (initially positioned at the
+                    end of the file), or nullptr if the file can't be opened for some reason
+        @see createInputStream, appendData, appendText
+    */
+    FileOutputStream* createOutputStream (size_t bufferSize = 0x8000) const;
+
+    //==============================================================================
+    /** Loads a file's contents into memory as a block of binary data.
+
+        Of course, trying to load a very large file into memory will blow up, so
+        it's better to check first.
+
+        @param result   the data block to which the file's contents should be appended - note
+                        that if the memory block might already contain some data, you
+                        might want to clear it first
+        @returns        true if the file could all be read into memory
+    */
+    bool loadFileAsData (MemoryBlock& result) const;
+
+    /** Reads a file into memory as a string.
+
+        Attempts to load the entire file as a zero-terminated string.
+
+        This makes use of InputStream::readEntireStreamAsString, which can
+        read either UTF-16 or UTF-8 file formats.
+    */
+    String loadFileAsString() const;
+
+    /** Reads the contents of this file as text and splits it into lines, which are
+        appended to the given StringArray.
+    */
+    void readLines (StringArray& destLines) const;
+
+    //==============================================================================
+    /** Appends a block of binary data to the end of the file.
+
+        This will try to write the given buffer to the end of the file.
+
+        @returns false if it can't write to the file for some reason
+    */
+    bool appendData (const void* dataToAppend,
+                     size_t numberOfBytes) const;
+
+    /** Replaces this file's contents with a given block of data.
+
+        This will delete the file and replace it with the given data.
+
+        A nice feature of this method is that it's safe - instead of deleting
+        the file first and then re-writing it, it creates a new temporary file,
+        writes the data to that, and then moves the new file to replace the existing
+        file. This means that if the power gets pulled out or something crashes,
+        you're a lot less likely to end up with a corrupted or unfinished file..
+
+        Returns true if the operation succeeds, or false if it fails.
+
+        @see appendText
+    */
+    bool replaceWithData (const void* dataToWrite,
+                          size_t numberOfBytes) const;
+
+    /** Appends a string to the end of the file.
+
+        This will try to append a text string to the file, as either 16-bit unicode
+        or 8-bit characters in the default system encoding.
+
+        It can also write the 'ff fe' unicode header bytes before the text to indicate
+        the endianness of the file.
+
+        Any single \\n characters in the string are replaced with \\r\\n before it is written.
+
+        @see replaceWithText
+    */
+    bool appendText (const String& textToAppend,
+                     bool asUnicode = false,
+                     bool writeUnicodeHeaderBytes = false) const;
+
+    /** Replaces this file's contents with a given text string.
+
+        This will delete the file and replace it with the given text.
+
+        A nice feature of this method is that it's safe - instead of deleting
+        the file first and then re-writing it, it creates a new temporary file,
+        writes the text to that, and then moves the new file to replace the existing
+        file. This means that if the power gets pulled out or something crashes,
+        you're a lot less likely to end up with an empty file..
+
+        For an explanation of the parameters here, see the appendText() method.
+
+        Returns true if the operation succeeds, or false if it fails.
+
+        @see appendText
+    */
+    bool replaceWithText (const String& textToWrite,
+                          bool asUnicode = false,
+                          bool writeUnicodeHeaderBytes = false) const;
+
+    /** Attempts to scan the contents of this file and compare it to another file, returning
+        true if this is possible and they match byte-for-byte.
+    */
+    bool hasIdenticalContentTo (const File& other) const;
+
+    //==============================================================================
+    /** Creates a set of files to represent each file root.
+
+        e.g. on Windows this will create files for "c:\", "d:\" etc according
+        to which ones are available. On the Mac/Linux, this will probably
+        just add a single entry for "/".
+    */
+    static void findFileSystemRoots (Array<File>& results);
+
+    /** Finds the name of the drive on which this file lives.
+        @returns the volume label of the drive, or an empty string if this isn't possible
+    */
+    String getVolumeLabel() const;
+
+    /** Returns the serial number of the volume on which this file lives.
+        @returns the serial number, or zero if there's a problem doing this
+    */
+    int getVolumeSerialNumber() const;
+
+    /** Returns the number of bytes free on the drive that this file lives on.
+
+        @returns the number of bytes free, or 0 if there's a problem finding this out
+        @see getVolumeTotalSize
+    */
+    int64 getBytesFreeOnVolume() const;
+
+    /** Returns the total size of the drive that contains this file.
+
+        @returns the total number of bytes that the volume can hold
+        @see getBytesFreeOnVolume
+    */
+    int64 getVolumeTotalSize() const;
+
+    /** Returns true if this file is on a CD or DVD drive. */
+    bool isOnCDRomDrive() const;
+
+    /** Returns true if this file is on a hard disk.
+
+        This will fail if it's a network drive, but will still be true for
+        removable hard-disks.
+    */
+    bool isOnHardDisk() const;
+
+    /** Returns true if this file is on a removable disk drive.
+
+        This might be a usb-drive, a CD-rom, or maybe a network drive.
+    */
+    bool isOnRemovableDrive() const;
+
+    //==============================================================================
+    /** Launches the file as a process.
+
+        - if the file is executable, this will run it.
+
+        - if it's a document of some kind, it will launch the document with its
+        default viewer application.
+
+        - if it's a folder, it will be opened in Explorer, Finder, or equivalent.
+
+        @see revealToUser
+    */
+    bool startAsProcess (const String& parameters = String()) const;
+
+    /** Opens Finder, Explorer, or whatever the OS uses, to show the user this file's location.
+        @see startAsProcess
+    */
+    void revealToUser() const;
+
+    //==============================================================================
+    /** A set of types of location that can be passed to the getSpecialLocation() method.
+    */
+    enum SpecialLocationType
+    {
+        /** The user's home folder. This is the same as using File ("~"). */
+        userHomeDirectory,
+
+        /** The user's default documents folder. On Windows, this might be the user's
+            "My Documents" folder. On the Mac it'll be their "Documents" folder. Linux
+            doesn't tend to have one of these, so it might just return their home folder.
+        */
+        userDocumentsDirectory,
+
+        /** The folder that contains the user's desktop objects. */
+        userDesktopDirectory,
+
+        /** The most likely place where a user might store their music files. */
+        userMusicDirectory,
+
+        /** The most likely place where a user might store their movie files. */
+        userMoviesDirectory,
+
+        /** The most likely place where a user might store their picture files. */
+        userPicturesDirectory,
+
+        /** The folder in which applications store their persistent user-specific settings.
+            On Windows, this might be "\Documents and Settings\username\Application Data".
+            On the Mac, it might be "~/Library". If you're going to store your settings in here,
+            always create your own sub-folder to put them in, to avoid making a mess.
+        */
+        userApplicationDataDirectory,
+
+        /** An equivalent of the userApplicationDataDirectory folder that is shared by all users
+            of the computer, rather than just the current user.
+
+            On the Mac it'll be "/Library", on Windows, it could be something like
+            "\Documents and Settings\All Users\Application Data".
+
+            Depending on the setup, this folder may be read-only.
+        */
+        commonApplicationDataDirectory,
+
+        /** A place to put documents which are shared by all users of the machine.
+            On Windows this may be somewhere like "C:\Users\Public\Documents", on OSX it
+            will be something like "/Users/Shared". Other OSes may have no such concept
+            though, so be careful.
+        */
+        commonDocumentsDirectory,
+
+        /** The folder that should be used for temporary files.
+            Always delete them when you're finished, to keep the user's computer tidy!
+        */
+        tempDirectory,
+
+        /** Returns this application's executable file.
+
+            If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
+            host app.
+
+            On the mac this will return the unix binary, not the package folder - see
+            currentApplicationFile for that.
+
+            See also invokedExecutableFile, which is similar, but if the exe was launched from a
+            file link, invokedExecutableFile will return the name of the link.
+        */
+        currentExecutableFile,
+
+        /** Returns this application's location.
+
+            If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
+            host app.
+
+            On the mac this will return the package folder (if it's in one), not the unix binary
+            that's inside it - compare with currentExecutableFile.
+        */
+        currentApplicationFile,
+
+        /** Returns the file that was invoked to launch this executable.
+            This may differ from currentExecutableFile if the app was started from e.g. a link - this
+            will return the name of the link that was used, whereas currentExecutableFile will return
+            the actual location of the target executable.
+        */
+        invokedExecutableFile,
+
+        /** In a plugin, this will return the path of the host executable. */
+        hostApplicationPath,
+
+       #if JUCE_WINDOWS
+        /** On a Windows machine, returns the location of the Windows/System32 folder. */
+        windowsSystemDirectory,
+       #endif
+
+        /** The directory in which applications normally get installed.
+            So on windows, this would be something like "c:\program files", on the
+            Mac "/Applications", or "/usr" on linux.
+        */
+        globalApplicationsDirectory
+    };
+
+    /** Finds the location of a special type of file or directory, such as a home folder or
+        documents folder.
+
+        @see SpecialLocationType
+    */
+    static File JUCE_CALLTYPE getSpecialLocation (const SpecialLocationType type);
+
+    //==============================================================================
+    /** Returns a temporary file in the system's temp directory.
+        This will try to return the name of a non-existent temp file.
+        To get the temp folder, you can use getSpecialLocation (File::tempDirectory).
+    */
+    static File createTempFile (StringRef fileNameEnding);
+
+
+    //==============================================================================
+    /** Returns the current working directory.
+        @see setAsCurrentWorkingDirectory
+    */
+    static File getCurrentWorkingDirectory();
+
+    /** Sets the current working directory to be this file.
+
+        For this to work the file must point to a valid directory.
+
+        @returns true if the current directory has been changed.
+        @see getCurrentWorkingDirectory
+    */
+    bool setAsCurrentWorkingDirectory() const;
+
+    //==============================================================================
+    /** The system-specific file separator character.
+        On Windows, this will be '\', on Mac/Linux, it'll be '/'
+    */
+    static const juce_wchar separator;
+
+    /** The system-specific file separator character, as a string.
+        On Windows, this will be '\', on Mac/Linux, it'll be '/'
+    */
+    static const String separatorString;
+
+    //==============================================================================
+    /** Returns a version of a filename with any illegal characters removed.
+
+        This will return a copy of the given string after removing characters
+        that are not allowed in a legal filename, and possibly shortening the
+        string if it's too long.
+
+        Because this will remove slashes, don't use it on an absolute pathname - use
+        createLegalPathName() for that.
+
+        @see createLegalPathName
+    */
+    static String createLegalFileName (const String& fileNameToFix);
+
+    /** Returns a version of a path with any illegal characters removed.
+
+        Similar to createLegalFileName(), but this won't remove slashes, so can
+        be used on a complete pathname.
+
+        @see createLegalFileName
+    */
+    static String createLegalPathName (const String& pathNameToFix);
+
+    /** Indicates whether filenames are case-sensitive on the current operating system. */
+    static bool areFileNamesCaseSensitive();
+
+    /** Returns true if the string seems to be a fully-specified absolute path. */
+    static bool isAbsolutePath (StringRef path);
+
+    /** Creates a file that simply contains this string, without doing the sanity-checking
+        that the normal constructors do.
+
+        Best to avoid this unless you really know what you're doing.
+    */
+    static File createFileWithoutCheckingPath (const String& absolutePath) noexcept;
+
+    /** Adds a separator character to the end of a path if it doesn't already have one. */
+    static String addTrailingSeparator (const String& path);
+
+   #if JUCE_MAC || JUCE_IOS || DOXYGEN
+    //==============================================================================
+    /** OSX ONLY - Finds the OSType of a file from the its resources. */
+    OSType getMacOSType() const;
+
+    /** OSX ONLY - Returns true if this file is actually a bundle. */
+    bool isBundle() const;
+   #endif
+
+   #if JUCE_MAC || DOXYGEN
+    /** OSX ONLY - Adds this file to the OSX dock */
+    void addToDock() const;
+   #endif
+
+   #if JUCE_WINDOWS
+    /** Windows ONLY - Creates a win32 .LNK shortcut file that links to this file. */
+    bool createLink (const String& description, const File& linkFileToCreate) const;
+   #endif
+
+private:
+    //==============================================================================
+    String fullPath;
+
+    static String parseAbsolutePath (const String&);
+    String getPathUpToLastSlash() const;
+
+    Result createDirectoryInternal (const String&) const;
+    bool copyInternal (const File&) const;
+    bool moveInternal (const File&) const;
+    bool setFileTimesInternal (int64 m, int64 a, int64 c) const;
+    void getFileTimesInternal (int64& m, int64& a, int64& c) const;
+    bool setFileReadOnlyInternal (bool) const;
+};
+
+#endif   // JUCE_FILE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileFilter.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileFilter.cpp
new file mode 100644
index 0000000..bd0bdf8
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileFilter.cpp
@@ -0,0 +1,41 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+FileFilter::FileFilter (const String& filterDescription)
+    : description (filterDescription)
+{
+}
+
+FileFilter::~FileFilter()
+{
+}
+
+const String& FileFilter::getDescription() const noexcept
+{
+    return description;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileFilter.h b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileFilter.h
new file mode 100644
index 0000000..4c02415
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileFilter.h
@@ -0,0 +1,77 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_FILEFILTER_H_INCLUDED
+#define JUCE_FILEFILTER_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Interface for deciding which files are suitable for something.
+
+    For example, this is used by DirectoryContentsList to select which files
+    go into the list.
+
+    @see WildcardFileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
+*/
+class JUCE_API  FileFilter
+{
+public:
+    //==============================================================================
+    /** Creates a filter with the given description.
+
+        The description can be returned later with the getDescription() method.
+    */
+    FileFilter (const String& filterDescription);
+
+    /** Destructor. */
+    virtual ~FileFilter();
+
+    //==============================================================================
+    /** Returns the description that the filter was created with. */
+    const String& getDescription() const noexcept;
+
+    //==============================================================================
+    /** Should return true if this file is suitable for inclusion in whatever context
+        the object is being used.
+    */
+    virtual bool isFileSuitable (const File& file) const = 0;
+
+    /** Should return true if this directory is suitable for inclusion in whatever context
+        the object is being used.
+    */
+    virtual bool isDirectorySuitable (const File& file) const = 0;
+
+
+protected:
+    //==============================================================================
+    String description;
+};
+
+
+#endif   // JUCE_FILEFILTER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileInputStream.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileInputStream.cpp
new file mode 100644
index 0000000..801ccfa
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileInputStream.cpp
@@ -0,0 +1,84 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+int64 juce_fileSetPosition (void* handle, int64 pos);
+
+
+//==============================================================================
+FileInputStream::FileInputStream (const File& f)
+    : file (f),
+      fileHandle (nullptr),
+      currentPosition (0),
+      status (Result::ok())
+{
+    openHandle();
+}
+
+int64 FileInputStream::getTotalLength()
+{
+    // You should always check that a stream opened successfully before using it!
+    jassert (openedOk());
+
+    return file.getSize();
+}
+
+int FileInputStream::read (void* buffer, int bytesToRead)
+{
+    // You should always check that a stream opened successfully before using it!
+    jassert (openedOk());
+
+    // The buffer should never be null, and a negative size is probably a
+    // sign that something is broken!
+    jassert (buffer != nullptr && bytesToRead >= 0);
+
+    const size_t num = readInternal (buffer, (size_t) bytesToRead);
+    currentPosition += num;
+
+    return (int) num;
+}
+
+bool FileInputStream::isExhausted()
+{
+    return currentPosition >= getTotalLength();
+}
+
+int64 FileInputStream::getPosition()
+{
+    return currentPosition;
+}
+
+bool FileInputStream::setPosition (int64 pos)
+{
+    // You should always check that a stream opened successfully before using it!
+    jassert (openedOk());
+
+    if (pos != currentPosition)
+        currentPosition = juce_fileSetPosition (fileHandle, pos);
+
+    return currentPosition == pos;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileInputStream.h b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileInputStream.h
new file mode 100644
index 0000000..35963ba
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileInputStream.h
@@ -0,0 +1,96 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_FILEINPUTSTREAM_H_INCLUDED
+#define JUCE_FILEINPUTSTREAM_H_INCLUDED
+
+
+//==============================================================================
+/**
+    An input stream that reads from a local file.
+
+    @see InputStream, FileOutputStream, File::createInputStream
+*/
+class JUCE_API  FileInputStream  : public InputStream
+{
+public:
+    //==============================================================================
+    /** Creates a FileInputStream to read from the given file.
+
+        After creating a FileInputStream, you should use openedOk() or failedToOpen()
+        to make sure that it's OK before trying to read from it! If it failed, you
+        can call getStatus() to get more error information.
+    */
+    explicit FileInputStream (const File& fileToRead);
+
+    /** Destructor. */
+    ~FileInputStream();
+
+    //==============================================================================
+    /** Returns the file that this stream is reading from. */
+    const File& getFile() const noexcept                { return file; }
+
+    /** Returns the status of the file stream.
+        The result will be ok if the file opened successfully. If an error occurs while
+        opening or reading from the file, this will contain an error message.
+    */
+    const Result& getStatus() const noexcept            { return status; }
+
+    /** Returns true if the stream couldn't be opened for some reason.
+        @see getResult()
+    */
+    bool failedToOpen() const noexcept                  { return status.failed(); }
+
+    /** Returns true if the stream opened without problems.
+        @see getResult()
+    */
+    bool openedOk() const noexcept                      { return status.wasOk(); }
+
+
+    //==============================================================================
+    int64 getTotalLength() override;
+    int read (void*, int) override;
+    bool isExhausted() override;
+    int64 getPosition() override;
+    bool setPosition (int64) override;
+
+private:
+    //==============================================================================
+    const File file;
+    void* fileHandle;
+    int64 currentPosition;
+    Result status;
+
+    void openHandle();
+    size_t readInternal (void*, size_t);
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputStream)
+};
+
+
+#endif   // JUCE_FILEINPUTSTREAM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileOutputStream.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileOutputStream.cpp
new file mode 100644
index 0000000..961a8d1
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileOutputStream.cpp
@@ -0,0 +1,134 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+int64 juce_fileSetPosition (void* handle, int64 pos);
+
+//==============================================================================
+FileOutputStream::FileOutputStream (const File& f, const size_t bufferSizeToUse)
+    : file (f),
+      fileHandle (nullptr),
+      status (Result::ok()),
+      currentPosition (0),
+      bufferSize (bufferSizeToUse),
+      bytesInBuffer (0),
+      buffer (jmax (bufferSizeToUse, (size_t) 16))
+{
+    openHandle();
+}
+
+FileOutputStream::~FileOutputStream()
+{
+    flushBuffer();
+    closeHandle();
+}
+
+int64 FileOutputStream::getPosition()
+{
+    return currentPosition;
+}
+
+bool FileOutputStream::setPosition (int64 newPosition)
+{
+    if (newPosition != currentPosition)
+    {
+        flushBuffer();
+        currentPosition = juce_fileSetPosition (fileHandle, newPosition);
+    }
+
+    return newPosition == currentPosition;
+}
+
+bool FileOutputStream::flushBuffer()
+{
+    bool ok = true;
+
+    if (bytesInBuffer > 0)
+    {
+        ok = (writeInternal (buffer, bytesInBuffer) == (ssize_t) bytesInBuffer);
+        bytesInBuffer = 0;
+    }
+
+    return ok;
+}
+
+void FileOutputStream::flush()
+{
+    flushBuffer();
+    flushInternal();
+}
+
+bool FileOutputStream::write (const void* const src, const size_t numBytes)
+{
+    jassert (src != nullptr && ((ssize_t) numBytes) >= 0);
+
+    if (bytesInBuffer + numBytes < bufferSize)
+    {
+        memcpy (buffer + bytesInBuffer, src, numBytes);
+        bytesInBuffer += numBytes;
+        currentPosition += numBytes;
+    }
+    else
+    {
+        if (! flushBuffer())
+            return false;
+
+        if (numBytes < bufferSize)
+        {
+            memcpy (buffer + bytesInBuffer, src, numBytes);
+            bytesInBuffer += numBytes;
+            currentPosition += numBytes;
+        }
+        else
+        {
+            const ssize_t bytesWritten = writeInternal (src, numBytes);
+
+            if (bytesWritten < 0)
+                return false;
+
+            currentPosition += bytesWritten;
+            return bytesWritten == (ssize_t) numBytes;
+        }
+    }
+
+    return true;
+}
+
+bool FileOutputStream::writeRepeatedByte (uint8 byte, size_t numBytes)
+{
+    jassert (((ssize_t) numBytes) >= 0);
+
+    if (bytesInBuffer + numBytes < bufferSize)
+    {
+        memset (buffer + bytesInBuffer, byte, numBytes);
+        bytesInBuffer += numBytes;
+        currentPosition += numBytes;
+        return true;
+    }
+
+    return OutputStream::writeRepeatedByte (byte, numBytes);
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileOutputStream.h b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileOutputStream.h
new file mode 100644
index 0000000..f80705f
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileOutputStream.h
@@ -0,0 +1,116 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_FILEOUTPUTSTREAM_H_INCLUDED
+#define JUCE_FILEOUTPUTSTREAM_H_INCLUDED
+
+
+//==============================================================================
+/**
+    An output stream that writes into a local file.
+
+    @see OutputStream, FileInputStream, File::createOutputStream
+*/
+class JUCE_API  FileOutputStream  : public OutputStream
+{
+public:
+    //==============================================================================
+    /** Creates a FileOutputStream.
+
+        If the file doesn't exist, it will first be created. If the file can't be
+        created or opened, the failedToOpen() method will return
+        true.
+
+        If the file already exists when opened, the stream's write-postion will
+        be set to the end of the file. To overwrite an existing file,
+        use File::deleteFile() before opening the stream, or use setPosition(0)
+        after it's opened (although this won't truncate the file).
+
+        @see TemporaryFile
+    */
+    FileOutputStream (const File& fileToWriteTo,
+                      size_t bufferSizeToUse = 16384);
+
+    /** Destructor. */
+    ~FileOutputStream();
+
+    //==============================================================================
+    /** Returns the file that this stream is writing to.
+    */
+    const File& getFile() const                         { return file; }
+
+    /** Returns the status of the file stream.
+        The result will be ok if the file opened successfully. If an error occurs while
+        opening or writing to the file, this will contain an error message.
+    */
+    const Result& getStatus() const noexcept            { return status; }
+
+    /** Returns true if the stream couldn't be opened for some reason.
+        @see getResult()
+    */
+    bool failedToOpen() const noexcept                  { return status.failed(); }
+
+    /** Returns true if the stream opened without problems.
+        @see getResult()
+    */
+    bool openedOk() const noexcept                      { return status.wasOk(); }
+
+    /** Attempts to truncate the file to the current write position.
+        To truncate a file to a specific size, first use setPosition() to seek to the
+        appropriate location, and then call this method.
+    */
+    Result truncate();
+
+    //==============================================================================
+    void flush() override;
+    int64 getPosition() override;
+    bool setPosition (int64) override;
+    bool write (const void*, size_t) override;
+    bool writeRepeatedByte (uint8 byte, size_t numTimesToRepeat) override;
+
+
+private:
+    //==============================================================================
+    File file;
+    void* fileHandle;
+    Result status;
+    int64 currentPosition;
+    size_t bufferSize, bytesInBuffer;
+    HeapBlock <char> buffer;
+
+    void openHandle();
+    void closeHandle();
+    void flushInternal();
+    bool flushBuffer();
+    int64 setPositionInternal (int64);
+    ssize_t writeInternal (const void*, size_t);
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileOutputStream)
+};
+
+#endif   // JUCE_FILEOUTPUTSTREAM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileSearchPath.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileSearchPath.cpp
new file mode 100644
index 0000000..ce0af7e
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileSearchPath.cpp
@@ -0,0 +1,172 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+FileSearchPath::FileSearchPath() {}
+FileSearchPath::~FileSearchPath() {}
+
+FileSearchPath::FileSearchPath (const String& path)
+{
+    init (path);
+}
+
+FileSearchPath::FileSearchPath (const FileSearchPath& other)
+   : directories (other.directories)
+{
+}
+
+FileSearchPath& FileSearchPath::operator= (const FileSearchPath& other)
+{
+    directories = other.directories;
+    return *this;
+}
+
+FileSearchPath& FileSearchPath::operator= (const String& path)
+{
+    init (path);
+    return *this;
+}
+
+void FileSearchPath::init (const String& path)
+{
+    directories.clear();
+    directories.addTokens (path, ";", "\"");
+    directories.trim();
+    directories.removeEmptyStrings();
+
+    for (int i = directories.size(); --i >= 0;)
+        directories.set (i, directories[i].unquoted());
+}
+
+int FileSearchPath::getNumPaths() const
+{
+    return directories.size();
+}
+
+File FileSearchPath::operator[] (const int index) const
+{
+    return File (directories [index]);
+}
+
+String FileSearchPath::toString() const
+{
+    StringArray directories2 (directories);
+    for (int i = directories2.size(); --i >= 0;)
+        if (directories2[i].containsChar (';'))
+            directories2.set (i, directories2[i].quoted());
+
+    return directories2.joinIntoString (";");
+}
+
+void FileSearchPath::add (const File& dir, const int insertIndex)
+{
+    directories.insert (insertIndex, dir.getFullPathName());
+}
+
+void FileSearchPath::addIfNotAlreadyThere (const File& dir)
+{
+    for (int i = 0; i < directories.size(); ++i)
+        if (File (directories[i]) == dir)
+            return;
+
+    add (dir);
+}
+
+void FileSearchPath::remove (const int index)
+{
+    directories.remove (index);
+}
+
+void FileSearchPath::addPath (const FileSearchPath& other)
+{
+    for (int i = 0; i < other.getNumPaths(); ++i)
+        addIfNotAlreadyThere (other[i]);
+}
+
+void FileSearchPath::removeRedundantPaths()
+{
+    for (int i = directories.size(); --i >= 0;)
+    {
+        const File d1 (directories[i]);
+
+        for (int j = directories.size(); --j >= 0;)
+        {
+            const File d2 (directories[j]);
+
+            if ((i != j) && (d1.isAChildOf (d2) || d1 == d2))
+            {
+                directories.remove (i);
+                break;
+            }
+        }
+    }
+}
+
+void FileSearchPath::removeNonExistentPaths()
+{
+    for (int i = directories.size(); --i >= 0;)
+        if (! File (directories[i]).isDirectory())
+            directories.remove (i);
+}
+
+int FileSearchPath::findChildFiles (Array<File>& results,
+                                    const int whatToLookFor,
+                                    const bool searchRecursively,
+                                    const String& wildCardPattern) const
+{
+    int total = 0;
+
+    for (int i = 0; i < directories.size(); ++i)
+        total += operator[] (i).findChildFiles (results,
+                                                whatToLookFor,
+                                                searchRecursively,
+                                                wildCardPattern);
+
+    return total;
+}
+
+bool FileSearchPath::isFileInPath (const File& fileToCheck,
+                                   const bool checkRecursively) const
+{
+    for (int i = directories.size(); --i >= 0;)
+    {
+        const File d (directories[i]);
+
+        if (checkRecursively)
+        {
+            if (fileToCheck.isAChildOf (d))
+                return true;
+        }
+        else
+        {
+            if (fileToCheck.getParentDirectory() == d)
+                return true;
+        }
+    }
+
+    return false;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileSearchPath.h b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileSearchPath.h
new file mode 100644
index 0000000..51baf2e
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_FileSearchPath.h
@@ -0,0 +1,165 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_FILESEARCHPATH_H_INCLUDED
+#define JUCE_FILESEARCHPATH_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Represents a set of folders that make up a search path.
+
+    @see File
+*/
+class JUCE_API  FileSearchPath
+{
+public:
+    //==============================================================================
+    /** Creates an empty search path. */
+    FileSearchPath();
+
+    /** Creates a search path from a string of pathnames.
+
+        The path can be semicolon- or comma-separated, e.g.
+        "/foo/bar;/foo/moose;/fish/moose"
+
+        The separate folders are tokenised and added to the search path.
+    */
+    FileSearchPath (const String& path);
+
+    /** Creates a copy of another search path. */
+    FileSearchPath (const FileSearchPath&);
+
+    /** Copies another search path. */
+    FileSearchPath& operator= (const FileSearchPath&);
+
+    /** Destructor. */
+    ~FileSearchPath();
+
+    /** Uses a string containing a list of pathnames to re-initialise this list.
+
+        This search path is cleared and the semicolon- or comma-separated folders
+        in this string are added instead. e.g. "/foo/bar;/foo/moose;/fish/moose"
+    */
+    FileSearchPath& operator= (const String& path);
+
+    //==============================================================================
+    /** Returns the number of folders in this search path.
+        @see operator[]
+    */
+    int getNumPaths() const;
+
+    /** Returns one of the folders in this search path.
+        The file returned isn't guaranteed to actually be a valid directory.
+        @see getNumPaths
+    */
+    File operator[] (int index) const;
+
+    /** Returns the search path as a semicolon-separated list of directories. */
+    String toString() const;
+
+    //==============================================================================
+    /** Adds a new directory to the search path.
+
+        The new directory is added to the end of the list if the insertIndex parameter is
+        less than zero, otherwise it is inserted at the given index.
+    */
+    void add (const File& directoryToAdd,
+              int insertIndex = -1);
+
+    /** Adds a new directory to the search path if it's not already in there. */
+    void addIfNotAlreadyThere (const File& directoryToAdd);
+
+    /** Removes a directory from the search path. */
+    void remove (int indexToRemove);
+
+    /** Merges another search path into this one.
+        This will remove any duplicate directories.
+    */
+    void addPath (const FileSearchPath&);
+
+    /** Removes any directories that are actually subdirectories of one of the other directories in the search path.
+
+        If the search is intended to be recursive, there's no point having nested folders in the search
+        path, because they'll just get searched twice and you'll get duplicate results.
+
+        e.g. if the path is "c:\abc\de;c:\abc", this method will simplify it to "c:\abc"
+    */
+    void removeRedundantPaths();
+
+    /** Removes any directories that don't actually exist. */
+    void removeNonExistentPaths();
+
+    //==============================================================================
+    /** Searches the path for a wildcard.
+
+        This will search all the directories in the search path in order, adding any
+        matching files to the results array.
+
+        @param results                  an array to append the results to
+        @param whatToLookFor            a value from the File::TypesOfFileToFind enum, specifying whether to
+                                        return files, directories, or both.
+        @param searchRecursively        whether to recursively search the subdirectories too
+        @param wildCardPattern          a pattern to match against the filenames
+        @returns the number of files added to the array
+        @see File::findChildFiles
+    */
+    int findChildFiles (Array<File>& results,
+                        int whatToLookFor,
+                        bool searchRecursively,
+                        const String& wildCardPattern = "*") const;
+
+    //==============================================================================
+    /** Finds out whether a file is inside one of the path's directories.
+
+        This will return true if the specified file is a child of one of the
+        directories specified by this path. Note that this doesn't actually do any
+        searching or check that the files exist - it just looks at the pathnames
+        to work out whether the file would be inside a directory.
+
+        @param fileToCheck      the file to look for
+        @param checkRecursively if true, then this will return true if the file is inside a
+                                subfolder of one of the path's directories (at any depth). If false
+                                it will only return true if the file is actually a direct child
+                                of one of the directories.
+        @see File::isAChildOf
+
+    */
+    bool isFileInPath (const File& fileToCheck,
+                       bool checkRecursively) const;
+
+private:
+    //==============================================================================
+    StringArray directories;
+
+    void init (const String&);
+
+    JUCE_LEAK_DETECTOR (FileSearchPath)
+};
+
+#endif   // JUCE_FILESEARCHPATH_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_MemoryMappedFile.h b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_MemoryMappedFile.h
new file mode 100644
index 0000000..8a79185
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_MemoryMappedFile.h
@@ -0,0 +1,115 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_MEMORYMAPPEDFILE_H_INCLUDED
+#define JUCE_MEMORYMAPPEDFILE_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Maps a file into virtual memory for easy reading and/or writing.
+*/
+class JUCE_API  MemoryMappedFile
+{
+public:
+    /** The read/write flags used when opening a memory mapped file. */
+    enum AccessMode
+    {
+        readOnly,   /**< Indicates that the memory can only be read. */
+        readWrite   /**< Indicates that the memory can be read and written to - changes that are
+                         made will be flushed back to disk at the whim of the OS. */
+    };
+
+    /** Opens a file and maps it to an area of virtual memory.
+
+        The file should already exist, and should already be the size that you want to work with
+        when you call this. If the file is resized after being opened, the behaviour is undefined.
+
+        If the file exists and the operation succeeds, the getData() and getSize() methods will
+        return the location and size of the data that can be read or written. Note that the entire
+        file is not read into memory immediately - the OS simply creates a virtual mapping, which
+        will lazily pull the data into memory when blocks are accessed.
+
+        If the file can't be opened for some reason, the getData() method will return a null pointer.
+    */
+    MemoryMappedFile (const File& file, AccessMode mode);
+
+    /** Opens a section of a file and maps it to an area of virtual memory.
+
+        The file should already exist, and should already be the size that you want to work with
+        when you call this. If the file is resized after being opened, the behaviour is undefined.
+
+        If the file exists and the operation succeeds, the getData() and getSize() methods will
+        return the location and size of the data that can be read or written. Note that the entire
+        file is not read into memory immediately - the OS simply creates a virtual mapping, which
+        will lazily pull the data into memory when blocks are accessed.
+
+        If the file can't be opened for some reason, the getData() method will return a null pointer.
+
+        NOTE: the start of the actual range used may be rounded-down to a multiple of the OS's page-size,
+        so do not assume that the mapped memory will begin at exactly the position you requested - always
+        use getRange() to check the actual range that is being used.
+    */
+    MemoryMappedFile (const File& file,
+                      const Range<int64>& fileRange,
+                      AccessMode mode);
+
+    /** Destructor. */
+    ~MemoryMappedFile();
+
+    /** Returns the address at which this file has been mapped, or a null pointer if
+        the file couldn't be successfully mapped.
+    */
+    void* getData() const noexcept              { return address; }
+
+    /** Returns the number of bytes of data that are available for reading or writing.
+        This will normally be the size of the file.
+    */
+    size_t getSize() const noexcept             { return (size_t) range.getLength(); }
+
+    /** Returns the section of the file at which the mapped memory represents. */
+    Range<int64> getRange() const noexcept      { return range; }
+
+private:
+    //==============================================================================
+    void* address;
+    Range<int64> range;
+
+   #if JUCE_WINDOWS
+    void* fileHandle;
+   #else
+    int fileHandle;
+   #endif
+
+    void openInternal (const File&, AccessMode);
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedFile)
+};
+
+
+#endif   // JUCE_MEMORYMAPPEDFILE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_TemporaryFile.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_TemporaryFile.cpp
new file mode 100644
index 0000000..50475d5
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_TemporaryFile.cpp
@@ -0,0 +1,117 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+static File createTempFile (const File& parentDirectory, String name,
+                            const String& suffix, const int optionFlags)
+{
+    if ((optionFlags & TemporaryFile::useHiddenFile) != 0)
+        name = "." + name;
+
+    return parentDirectory.getNonexistentChildFile (name, suffix, (optionFlags & TemporaryFile::putNumbersInBrackets) != 0);
+}
+
+TemporaryFile::TemporaryFile (const String& suffix, const int optionFlags)
+    : temporaryFile (createTempFile (File::getSpecialLocation (File::tempDirectory),
+                                     "temp_" + String::toHexString (Random::getSystemRandom().nextInt()),
+                                     suffix, optionFlags))
+{
+}
+
+TemporaryFile::TemporaryFile (const File& target, const int optionFlags)
+    : temporaryFile (createTempFile (target.getParentDirectory(),
+                                     target.getFileNameWithoutExtension()
+                                       + "_temp" + String::toHexString (Random::getSystemRandom().nextInt()),
+                                     target.getFileExtension(), optionFlags)),
+      targetFile (target)
+{
+    // If you use this constructor, you need to give it a valid target file!
+    jassert (targetFile != File());
+}
+
+TemporaryFile::TemporaryFile (const File& target, const File& temporary)
+    : temporaryFile (temporary), targetFile (target)
+{
+}
+
+TemporaryFile::~TemporaryFile()
+{
+    if (! deleteTemporaryFile())
+    {
+        /* Failed to delete our temporary file! The most likely reason for this would be
+           that you've not closed an output stream that was being used to write to file.
+
+           If you find that something beyond your control is changing permissions on
+           your temporary files and preventing them from being deleted, you may want to
+           call TemporaryFile::deleteTemporaryFile() to detect those error cases and
+           handle them appropriately.
+        */
+        jassertfalse;
+    }
+}
+
+//==============================================================================
+bool TemporaryFile::overwriteTargetFileWithTemporary() const
+{
+    // This method only works if you created this object with the constructor
+    // that takes a target file!
+    jassert (targetFile != File());
+
+    if (temporaryFile.exists())
+    {
+        // Have a few attempts at overwriting the file before giving up..
+        for (int i = 5; --i >= 0;)
+        {
+            if (temporaryFile.moveFileTo (targetFile))
+                return true;
+
+            Thread::sleep (100);
+        }
+    }
+    else
+    {
+        // There's no temporary file to use. If your write failed, you should
+        // probably check, and not bother calling this method.
+        jassertfalse;
+    }
+
+    return false;
+}
+
+bool TemporaryFile::deleteTemporaryFile() const
+{
+    // Have a few attempts at deleting the file before giving up..
+    for (int i = 5; --i >= 0;)
+    {
+        if (temporaryFile.deleteFile())
+            return true;
+
+        Thread::sleep (50);
+    }
+
+    return false;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_TemporaryFile.h b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_TemporaryFile.h
new file mode 100644
index 0000000..04561a7
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_TemporaryFile.h
@@ -0,0 +1,169 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_TEMPORARYFILE_H_INCLUDED
+#define JUCE_TEMPORARYFILE_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Manages a temporary file, which will be deleted when this object is deleted.
+
+    This object is intended to be used as a stack based object, using its scope
+    to make sure the temporary file isn't left lying around.
+
+    For example:
+
+    @code
+    {
+        File myTargetFile ("~/myfile.txt");
+
+        // this will choose a file called something like "~/myfile_temp239348.txt"
+        // which definitely doesn't exist at the time the constructor is called.
+        TemporaryFile temp (myTargetFile);
+
+        // create a stream to the temporary file, and write some data to it...
+        ScopedPointer <FileOutputStream> out (temp.getFile().createOutputStream());
+
+        if (out != nullptr)
+        {
+            out->write ( ...etc )
+            out = nullptr; // (deletes the stream)
+
+            // ..now we've finished writing, this will rename the temp file to
+            // make it replace the target file we specified above.
+            bool succeeded = temp.overwriteTargetFileWithTemporary();
+        }
+
+        // ..and even if something went wrong and our overwrite failed,
+        // as the TemporaryFile object goes out of scope here, it'll make sure
+        // that the temp file gets deleted.
+    }
+    @endcode
+
+    @see File, FileOutputStream
+*/
+class JUCE_API  TemporaryFile
+{
+public:
+    //==============================================================================
+    enum OptionFlags
+    {
+        useHiddenFile = 1,          /**< Indicates that the temporary file should be hidden -
+                                         i.e. its name should start with a dot. */
+        putNumbersInBrackets = 2    /**< Indicates that when numbers are appended to make sure
+                                         the file is unique, they should go in brackets rather
+                                         than just being appended (see File::getNonexistentSibling() )*/
+    };
+
+    //==============================================================================
+    /** Creates a randomly-named temporary file in the default temp directory.
+
+        @param suffix       a file suffix to use for the file
+        @param optionFlags  a combination of the values listed in the OptionFlags enum
+        The file will not be created until you write to it. And remember that when
+        this object is deleted, the file will also be deleted!
+    */
+    TemporaryFile (const String& suffix = String(),
+                   int optionFlags = 0);
+
+    /** Creates a temporary file in the same directory as a specified file.
+
+        This is useful if you have a file that you want to overwrite, but don't
+        want to harm the original file if the write operation fails. You can
+        use this to create a temporary file next to the target file, then
+        write to the temporary file, and finally use overwriteTargetFileWithTemporary()
+        to replace the target file with the one you've just written.
+
+        This class won't create any files until you actually write to them. And remember
+        that when this object is deleted, the temporary file will also be deleted!
+
+        @param targetFile   the file that you intend to overwrite - the temporary
+                            file will be created in the same directory as this
+        @param optionFlags  a combination of the values listed in the OptionFlags enum
+    */
+    TemporaryFile (const File& targetFile,
+                   int optionFlags = 0);
+
+    /** Creates a temporary file using an explicit filename.
+        The other constructors are a better choice than this one, unless for some reason
+        you need to explicitly specify the temporary file you want to use.
+
+        @param targetFile    the file that you intend to overwrite
+        @param temporaryFile the temporary file to be used
+    */
+    TemporaryFile (const File& targetFile,
+                   const File& temporaryFile);
+
+    /** Destructor.
+
+        When this object is deleted it will make sure that its temporary file is
+        also deleted! If the operation fails, it'll throw an assertion in debug
+        mode.
+    */
+    ~TemporaryFile();
+
+    //==============================================================================
+    /** Returns the temporary file. */
+    const File& getFile() const noexcept                { return temporaryFile; }
+
+    /** Returns the target file that was specified in the constructor. */
+    const File& getTargetFile() const noexcept          { return targetFile; }
+
+    /** Tries to move the temporary file to overwrite the target file that was
+        specified in the constructor.
+
+        If you used the constructor that specified a target file, this will attempt
+        to replace that file with the temporary one.
+
+        Before calling this, make sure:
+        - that you've actually written to the temporary file
+        - that you've closed any open streams that you were using to write to it
+        - and that you don't have any streams open to the target file, which would
+          prevent it being overwritten
+
+        If the file move succeeds, this returns false, and the temporary file will
+        have disappeared. If it fails, the temporary file will probably still exist,
+        but will be deleted when this object is destroyed.
+    */
+    bool overwriteTargetFileWithTemporary() const;
+
+    /** Attempts to delete the temporary file, if it exists.
+        @returns true if the file is successfully deleted (or if it didn't exist).
+    */
+    bool deleteTemporaryFile() const;
+
+
+private:
+    //==============================================================================
+    const File temporaryFile, targetFile;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemporaryFile)
+};
+
+#endif   // JUCE_TEMPORARYFILE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_WildcardFileFilter.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_WildcardFileFilter.cpp
new file mode 100644
index 0000000..1fef455
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_WildcardFileFilter.cpp
@@ -0,0 +1,77 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns,
+                                        const String& directoryWildcardPatterns,
+                                        const String& desc)
+    : FileFilter (desc.isEmpty() ? fileWildcardPatterns
+                                 : (desc + " (" + fileWildcardPatterns + ")"))
+{
+    parse (fileWildcardPatterns, fileWildcards);
+    parse (directoryWildcardPatterns, directoryWildcards);
+}
+
+WildcardFileFilter::~WildcardFileFilter()
+{
+}
+
+bool WildcardFileFilter::isFileSuitable (const File& file) const
+{
+    return match (file, fileWildcards);
+}
+
+bool WildcardFileFilter::isDirectorySuitable (const File& file) const
+{
+    return match (file, directoryWildcards);
+}
+
+//==============================================================================
+void WildcardFileFilter::parse (const String& pattern, StringArray& result)
+{
+    result.addTokens (pattern.toLowerCase(), ";,", "\"'");
+
+    result.trim();
+    result.removeEmptyStrings();
+
+    // special case for *.*, because people use it to mean "any file", but it
+    // would actually ignore files with no extension.
+    for (int i = result.size(); --i >= 0;)
+        if (result[i] == "*.*")
+            result.set (i, "*");
+}
+
+bool WildcardFileFilter::match (const File& file, const StringArray& wildcards)
+{
+    const String filename (file.getFileName());
+
+    for (int i = wildcards.size(); --i >= 0;)
+        if (filename.matchesWildcard (wildcards[i], true))
+            return true;
+
+    return false;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_WildcardFileFilter.h b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_WildcardFileFilter.h
new file mode 100644
index 0000000..166ae4a
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/files/juce_WildcardFileFilter.h
@@ -0,0 +1,86 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_WILDCARDFILEFILTER_H_INCLUDED
+#define JUCE_WILDCARDFILEFILTER_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A type of FileFilter that works by wildcard pattern matching.
+
+    This filter only allows files that match one of the specified patterns, but
+    allows all directories through.
+
+    @see FileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
+*/
+class JUCE_API  WildcardFileFilter  : public FileFilter
+{
+public:
+    //==============================================================================
+    /**
+        Creates a wildcard filter for one or more patterns.
+
+        The wildcardPatterns parameter is a comma or semicolon-delimited set of
+        patterns, e.g. "*.wav;*.aiff" would look for files ending in either .wav
+        or .aiff.
+
+        Passing an empty string as a pattern will fail to match anything, so by leaving
+        either the file or directory pattern parameter empty means you can control
+        whether files or directories are found.
+
+        The description is a name to show the user in a list of possible patterns, so
+        for the wav/aiff example, your description might be "audio files".
+    */
+    WildcardFileFilter (const String& fileWildcardPatterns,
+                        const String& directoryWildcardPatterns,
+                        const String& description);
+
+    /** Destructor. */
+    ~WildcardFileFilter();
+
+    //==============================================================================
+    /** Returns true if the filename matches one of the patterns specified. */
+    bool isFileSuitable (const File& file) const;
+
+    /** This always returns true. */
+    bool isDirectorySuitable (const File& file) const;
+
+private:
+    //==============================================================================
+    StringArray fileWildcards, directoryWildcards;
+
+    static void parse (const String& pattern, StringArray& result);
+    static bool match (const File& file, const StringArray& wildcards);
+
+    JUCE_LEAK_DETECTOR (WildcardFileFilter)
+};
+
+
+
+#endif   // JUCE_WILDCARDFILEFILTER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_JSON.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_JSON.cpp
new file mode 100644
index 0000000..5a0f7f7
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_JSON.cpp
@@ -0,0 +1,643 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+class JSONParser
+{
+public:
+    static Result parseObjectOrArray (String::CharPointerType t, var& result)
+    {
+        t = t.findEndOfWhitespace();
+
+        switch (t.getAndAdvance())
+        {
+            case 0:      result = var(); return Result::ok();
+            case '{':    return parseObject (t, result);
+            case '[':    return parseArray  (t, result);
+        }
+
+        return createFail ("Expected '{' or '['", &t);
+    }
+
+    static Result parseString (const juce_wchar quoteChar, String::CharPointerType& t, var& result)
+    {
+        MemoryOutputStream buffer (256);
+
+        for (;;)
+        {
+            juce_wchar c = t.getAndAdvance();
+
+            if (c == quoteChar)
+                break;
+
+            if (c == '\\')
+            {
+                c = t.getAndAdvance();
+
+                switch (c)
+                {
+                    case '"':
+                    case '\'':
+                    case '\\':
+                    case '/':  break;
+
+                    case 'a':  c = '\a'; break;
+                    case 'b':  c = '\b'; break;
+                    case 'f':  c = '\f'; break;
+                    case 'n':  c = '\n'; break;
+                    case 'r':  c = '\r'; break;
+                    case 't':  c = '\t'; break;
+
+                    case 'u':
+                    {
+                        c = 0;
+
+                        for (int i = 4; --i >= 0;)
+                        {
+                            const int digitValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance());
+                            if (digitValue < 0)
+                                return createFail ("Syntax error in unicode escape sequence");
+
+                            c = (juce_wchar) ((c << 4) + digitValue);
+                        }
+
+                        break;
+                    }
+                }
+            }
+
+            if (c == 0)
+                return createFail ("Unexpected end-of-input in string constant");
+
+            buffer.appendUTF8Char (c);
+        }
+
+        result = buffer.toUTF8();
+        return Result::ok();
+    }
+
+    static Result parseAny (String::CharPointerType& t, var& result)
+    {
+        t = t.findEndOfWhitespace();
+        String::CharPointerType t2 (t);
+
+        switch (t2.getAndAdvance())
+        {
+            case '{':    t = t2; return parseObject (t, result);
+            case '[':    t = t2; return parseArray  (t, result);
+            case '"':    t = t2; return parseString ('"',  t, result);
+            case '\'':   t = t2; return parseString ('\'', t, result);
+
+            case '-':
+                t2 = t2.findEndOfWhitespace();
+                if (! CharacterFunctions::isDigit (*t2))
+                    break;
+
+                t = t2;
+                return parseNumber (t, result, true);
+
+            case '0': case '1': case '2': case '3': case '4':
+            case '5': case '6': case '7': case '8': case '9':
+                return parseNumber (t, result, false);
+
+            case 't':   // "true"
+                if (t2.getAndAdvance() == 'r' && t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'e')
+                {
+                    t = t2;
+                    result = var (true);
+                    return Result::ok();
+                }
+                break;
+
+            case 'f':   // "false"
+                if (t2.getAndAdvance() == 'a' && t2.getAndAdvance() == 'l'
+                      && t2.getAndAdvance() == 's' && t2.getAndAdvance() == 'e')
+                {
+                    t = t2;
+                    result = var (false);
+                    return Result::ok();
+                }
+                break;
+
+            case 'n':   // "null"
+                if (t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'l' && t2.getAndAdvance() == 'l')
+                {
+                    t = t2;
+                    result = var();
+                    return Result::ok();
+                }
+                break;
+
+            default:
+                break;
+        }
+
+        return createFail ("Syntax error", &t);
+    }
+
+private:
+    static Result createFail (const char* const message, const String::CharPointerType* location = nullptr)
+    {
+        String m (message);
+        if (location != nullptr)
+            m << ": \"" << String (*location, 20) << '"';
+
+        return Result::fail (m);
+    }
+
+    static Result parseNumber (String::CharPointerType& t, var& result, const bool isNegative)
+    {
+        String::CharPointerType oldT (t);
+
+        int64 intValue = t.getAndAdvance() - '0';
+        jassert (intValue >= 0 && intValue < 10);
+
+        for (;;)
+        {
+            String::CharPointerType previousChar (t);
+            const juce_wchar c = t.getAndAdvance();
+            const int digit = ((int) c) - '0';
+
+            if (isPositiveAndBelow (digit, 10))
+            {
+                intValue = intValue * 10 + digit;
+                continue;
+            }
+
+            if (c == 'e' || c == 'E' || c == '.')
+            {
+                t = oldT;
+                const double asDouble = CharacterFunctions::readDoubleValue (t);
+                result = isNegative ? -asDouble : asDouble;
+                return Result::ok();
+            }
+
+            if (CharacterFunctions::isWhitespace (c)
+                 || c == ',' || c == '}' || c == ']' || c == 0)
+            {
+                t = previousChar;
+                break;
+            }
+
+            return createFail ("Syntax error in number", &oldT);
+        }
+
+        const int64 correctedValue = isNegative ? -intValue : intValue;
+
+        if ((intValue >> 31) != 0)
+            result = correctedValue;
+        else
+            result = (int) correctedValue;
+
+        return Result::ok();
+    }
+
+    static Result parseObject (String::CharPointerType& t, var& result)
+    {
+        DynamicObject* const resultObject = new DynamicObject();
+        result = resultObject;
+        NamedValueSet& resultProperties = resultObject->getProperties();
+
+        for (;;)
+        {
+            t = t.findEndOfWhitespace();
+
+            String::CharPointerType oldT (t);
+            const juce_wchar c = t.getAndAdvance();
+
+            if (c == '}')
+                break;
+
+            if (c == 0)
+                return createFail ("Unexpected end-of-input in object declaration");
+
+            if (c == '"')
+            {
+                var propertyNameVar;
+                Result r (parseString ('"', t, propertyNameVar));
+
+                if (r.failed())
+                    return r;
+
+                const Identifier propertyName (propertyNameVar.toString());
+
+                if (propertyName.isValid())
+                {
+                    t = t.findEndOfWhitespace();
+                    oldT = t;
+
+                    const juce_wchar c2 = t.getAndAdvance();
+                    if (c2 != ':')
+                        return createFail ("Expected ':', but found", &oldT);
+
+                    resultProperties.set (propertyName, var());
+                    var* propertyValue = resultProperties.getVarPointer (propertyName);
+
+                    Result r2 (parseAny (t, *propertyValue));
+
+                    if (r2.failed())
+                        return r2;
+
+                    t = t.findEndOfWhitespace();
+                    oldT = t;
+
+                    const juce_wchar nextChar = t.getAndAdvance();
+
+                    if (nextChar == ',')
+                        continue;
+
+                    if (nextChar == '}')
+                        break;
+                }
+            }
+
+            return createFail ("Expected object member declaration, but found", &oldT);
+        }
+
+        return Result::ok();
+    }
+
+    static Result parseArray (String::CharPointerType& t, var& result)
+    {
+        result = var (Array<var>());
+        Array<var>* const destArray = result.getArray();
+
+        for (;;)
+        {
+            t = t.findEndOfWhitespace();
+
+            String::CharPointerType oldT (t);
+            const juce_wchar c = t.getAndAdvance();
+
+            if (c == ']')
+                break;
+
+            if (c == 0)
+                return createFail ("Unexpected end-of-input in array declaration");
+
+            t = oldT;
+            destArray->add (var());
+            Result r (parseAny (t, destArray->getReference (destArray->size() - 1)));
+
+            if (r.failed())
+                return r;
+
+            t = t.findEndOfWhitespace();
+            oldT = t;
+
+            const juce_wchar nextChar = t.getAndAdvance();
+
+            if (nextChar == ',')
+                continue;
+
+            if (nextChar == ']')
+                break;
+
+            return createFail ("Expected object array item, but found", &oldT);
+        }
+
+        return Result::ok();
+    }
+};
+
+//==============================================================================
+class JSONFormatter
+{
+public:
+    static void write (OutputStream& out, const var& v,
+                       const int indentLevel, const bool allOnOneLine)
+    {
+        if (v.isString())
+        {
+            out << '"';
+            writeString (out, v.toString().getCharPointer());
+            out << '"';
+        }
+        else if (v.isVoid())
+        {
+            out << "null";
+        }
+        else if (v.isUndefined())
+        {
+            out << "undefined";
+        }
+        else if (v.isBool())
+        {
+            out << (static_cast<bool> (v) ? "true" : "false");
+        }
+        else if (v.isArray())
+        {
+            writeArray (out, *v.getArray(), indentLevel, allOnOneLine);
+        }
+        else if (v.isObject())
+        {
+            if (DynamicObject* object = v.getDynamicObject())
+                object->writeAsJSON (out, indentLevel, allOnOneLine);
+            else
+                jassertfalse; // Only DynamicObjects can be converted to JSON!
+        }
+        else
+        {
+            // Can't convert these other types of object to JSON!
+            jassert (! (v.isMethod() || v.isBinaryData()));
+
+            out << v.toString();
+        }
+    }
+
+    static void writeEscapedChar (OutputStream& out, const unsigned short value)
+    {
+        out << "\\u" << String::toHexString ((int) value).paddedLeft ('0', 4);
+    }
+
+    static void writeString (OutputStream& out, String::CharPointerType t)
+    {
+        for (;;)
+        {
+            const juce_wchar c (t.getAndAdvance());
+
+            switch (c)
+            {
+                case 0:  return;
+
+                case '\"':  out << "\\\""; break;
+                case '\\':  out << "\\\\"; break;
+                case '\a':  out << "\\a";  break;
+                case '\b':  out << "\\b";  break;
+                case '\f':  out << "\\f";  break;
+                case '\t':  out << "\\t";  break;
+                case '\r':  out << "\\r";  break;
+                case '\n':  out << "\\n";  break;
+
+                default:
+                    if (c >= 32 && c < 127)
+                    {
+                        out << (char) c;
+                    }
+                    else
+                    {
+                        if (CharPointer_UTF16::getBytesRequiredFor (c) > 2)
+                        {
+                            CharPointer_UTF16::CharType chars[2];
+                            CharPointer_UTF16 utf16 (chars);
+                            utf16.write (c);
+
+                            for (int i = 0; i < 2; ++i)
+                                writeEscapedChar (out, (unsigned short) chars[i]);
+                        }
+                        else
+                        {
+                            writeEscapedChar (out, (unsigned short) c);
+                        }
+                    }
+
+                    break;
+            }
+        }
+    }
+
+    static void writeSpaces (OutputStream& out, int numSpaces)
+    {
+        out.writeRepeatedByte (' ', (size_t) numSpaces);
+    }
+
+    static void writeArray (OutputStream& out, const Array<var>& array,
+                            const int indentLevel, const bool allOnOneLine)
+    {
+        out << '[';
+
+        if (array.size() > 0)
+        {
+            if (! allOnOneLine)
+                out << newLine;
+
+            for (int i = 0; i < array.size(); ++i)
+            {
+                if (! allOnOneLine)
+                    writeSpaces (out, indentLevel + indentSize);
+
+                write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine);
+
+                if (i < array.size() - 1)
+                {
+                    if (allOnOneLine)
+                        out << ", ";
+                    else
+                        out << ',' << newLine;
+                }
+                else if (! allOnOneLine)
+                    out << newLine;
+            }
+
+            if (! allOnOneLine)
+                writeSpaces (out, indentLevel);
+        }
+
+        out << ']';
+    }
+
+    enum { indentSize = 2 };
+};
+
+//==============================================================================
+var JSON::parse (const String& text)
+{
+    var result;
+
+    if (! parse (text, result))
+        result = var();
+
+    return result;
+}
+
+var JSON::fromString (StringRef text)
+{
+    var result;
+
+    if (! JSONParser::parseAny (text.text, result))
+        result = var();
+
+    return result;
+}
+
+var JSON::parse (InputStream& input)
+{
+    return parse (input.readEntireStreamAsString());
+}
+
+var JSON::parse (const File& file)
+{
+    return parse (file.loadFileAsString());
+}
+
+Result JSON::parse (const String& text, var& result)
+{
+    return JSONParser::parseObjectOrArray (text.getCharPointer(), result);
+}
+
+String JSON::toString (const var& data, const bool allOnOneLine)
+{
+    MemoryOutputStream mo (1024);
+    JSONFormatter::write (mo, data, 0, allOnOneLine);
+    return mo.toUTF8();
+}
+
+void JSON::writeToStream (OutputStream& output, const var& data, const bool allOnOneLine)
+{
+    JSONFormatter::write (output, data, 0, allOnOneLine);
+}
+
+String JSON::escapeString (StringRef s)
+{
+    MemoryOutputStream mo;
+    JSONFormatter::writeString (mo, s.text);
+    return mo.toString();
+}
+
+Result JSON::parseQuotedString (String::CharPointerType& t, var& result)
+{
+    const juce_wchar quote = t.getAndAdvance();
+
+    if (quote == '"' || quote == '\'')
+        return JSONParser::parseString (quote, t, result);
+
+    return Result::fail ("Not a quoted string!");
+}
+
+//==============================================================================
+//==============================================================================
+#if JUCE_UNIT_TESTS
+
+class JSONTests  : public UnitTest
+{
+public:
+    JSONTests() : UnitTest ("JSON") {}
+
+    static String createRandomWideCharString (Random& r)
+    {
+        juce_wchar buffer[40] = { 0 };
+
+        for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
+        {
+            if (r.nextBool())
+            {
+                do
+                {
+                    buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
+                }
+                while (! CharPointer_UTF16::canRepresent (buffer[i]));
+            }
+            else
+                buffer[i] = (juce_wchar) (1 + r.nextInt (0xff));
+        }
+
+        return CharPointer_UTF32 (buffer);
+    }
+
+    static String createRandomIdentifier (Random& r)
+    {
+        char buffer[30] = { 0 };
+
+        for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
+        {
+            static const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:";
+            buffer[i] = chars [r.nextInt (sizeof (chars) - 1)];
+        }
+
+        return CharPointer_ASCII (buffer);
+    }
+
+    static var createRandomVar (Random& r, int depth)
+    {
+        switch (r.nextInt (depth > 3 ? 6 : 8))
+        {
+            case 0:     return var();
+            case 1:     return r.nextInt();
+            case 2:     return r.nextInt64();
+            case 3:     return r.nextBool();
+            case 4:     return r.nextDouble();
+            case 5:     return createRandomWideCharString (r);
+
+            case 6:
+            {
+                var v (createRandomVar (r, depth + 1));
+
+                for (int i = 1 + r.nextInt (30); --i >= 0;)
+                    v.append (createRandomVar (r, depth + 1));
+
+                return v;
+            }
+
+            case 7:
+            {
+                DynamicObject* o = new DynamicObject();
+
+                for (int i = r.nextInt (30); --i >= 0;)
+                    o->setProperty (createRandomIdentifier (r), createRandomVar (r, depth + 1));
+
+                return o;
+            }
+
+            default:
+                return var();
+        }
+    }
+
+    void runTest()
+    {
+        beginTest ("JSON");
+        Random r = getRandom();
+
+        expect (JSON::parse (String::empty) == var::null);
+        expect (JSON::parse ("{}").isObject());
+        expect (JSON::parse ("[]").isArray());
+        expect (JSON::parse ("[ 1234 ]")[0].isInt());
+        expect (JSON::parse ("[ 12345678901234 ]")[0].isInt64());
+        expect (JSON::parse ("[ 1.123e3 ]")[0].isDouble());
+        expect (JSON::parse ("[ -1234]")[0].isInt());
+        expect (JSON::parse ("[-12345678901234]")[0].isInt64());
+        expect (JSON::parse ("[-1.123e3]")[0].isDouble());
+
+        for (int i = 100; --i >= 0;)
+        {
+            var v;
+
+            if (i > 0)
+                v = createRandomVar (r, 0);
+
+            const bool oneLine = r.nextBool();
+            String asString (JSON::toString (v, oneLine));
+            var parsed = JSON::parse ("[" + asString + "]")[0];
+            String parsedString (JSON::toString (parsed, oneLine));
+            expect (asString.isNotEmpty() && parsedString == asString);
+        }
+    }
+};
+
+static JSONTests JSONUnitTests;
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_JSON.h b/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_JSON.h
new file mode 100644
index 0000000..7fb17ee
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_JSON.h
@@ -0,0 +1,136 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_JSON_H_INCLUDED
+#define JUCE_JSON_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Contains static methods for converting JSON-formatted text to and from var objects.
+
+    The var class is structurally compatible with JSON-formatted data, so these
+    functions allow you to parse JSON into a var object, and to convert a var
+    object to JSON-formatted text.
+
+    @see var
+*/
+class JUCE_API  JSON
+{
+public:
+    //==============================================================================
+    /** Parses a string of JSON-formatted text, and returns a result code containing
+        any parse errors.
+
+        This will return the parsed structure in the parsedResult parameter, and will
+        return a Result object to indicate whether parsing was successful, and if not,
+        it will contain an error message.
+
+        If you're not interested in the error message, you can use one of the other
+        shortcut parse methods, which simply return a var::null if the parsing fails.
+
+        Note that this will only parse valid JSON, which means that the item given must
+        be either an object or an array definition. If you want to also be able to parse
+        any kind of primitive JSON object, use the fromString() method.
+    */
+    static Result parse (const String& text, var& parsedResult);
+
+    /** Attempts to parse some JSON-formatted text, and returns the result as a var object.
+
+        If the parsing fails, this simply returns var::null - if you need to find out more
+        detail about the parse error, use the alternative parse() method which returns a Result.
+
+        Note that this will only parse valid JSON, which means that the item given must
+        be either an object or an array definition. If you want to also be able to parse
+        any kind of primitive JSON object, use the fromString() method.
+    */
+    static var parse (const String& text);
+
+    /** Attempts to parse some JSON-formatted text from a file, and returns the result
+        as a var object.
+
+        Note that this is just a short-cut for reading the entire file into a string and
+        parsing the result.
+
+        If the parsing fails, this simply returns var::null - if you need to find out more
+        detail about the parse error, use the alternative parse() method which returns a Result.
+    */
+    static var parse (const File& file);
+
+    /** Attempts to parse some JSON-formatted text from a stream, and returns the result
+        as a var object.
+
+        Note that this is just a short-cut for reading the entire stream into a string and
+        parsing the result.
+
+        If the parsing fails, this simply returns var::null - if you need to find out more
+        detail about the parse error, use the alternative parse() method which returns a Result.
+    */
+    static var parse (InputStream& input);
+
+    //==============================================================================
+    /** Returns a string which contains a JSON-formatted representation of the var object.
+        If allOnOneLine is true, the result will be compacted into a single line of text
+        with no carriage-returns. If false, it will be laid-out in a more human-readable format.
+        @see writeToStream
+    */
+    static String toString (const var& objectToFormat,
+                            bool allOnOneLine = false);
+
+    /** Parses a string that was created with the toString() method.
+        This is slightly different to the parse() methods because they will reject primitive
+        values and only accept array or object definitions, whereas this method will handle
+        either.
+    */
+    static var fromString (StringRef);
+
+    /** Writes a JSON-formatted representation of the var object to the given stream.
+        If allOnOneLine is true, the result will be compacted into a single line of text
+        with no carriage-returns. If false, it will be laid-out in a more human-readable format.
+        @see toString
+    */
+    static void writeToStream (OutputStream& output,
+                               const var& objectToFormat,
+                               bool allOnOneLine = false);
+
+    /** Returns a version of a string with any extended characters escaped. */
+    static String escapeString (StringRef);
+
+    /** Parses a quoted string-literal in JSON format, returning the un-escaped result in the
+        result parameter, and an error message in case the content was illegal.
+        This advances the text parameter, leaving it positioned after the closing quote.
+    */
+    static Result parseQuotedString (String::CharPointerType& text, var& result);
+
+private:
+    //==============================================================================
+    JSON() JUCE_DELETED_FUNCTION; // This class can't be instantiated - just use its static methods.
+};
+
+
+#endif   // JUCE_JSON_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_Javascript.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_Javascript.cpp
new file mode 100644
index 0000000..af99a84
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_Javascript.cpp
@@ -0,0 +1,1710 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#define JUCE_JS_OPERATORS(X) \
+    X(semicolon,     ";")        X(dot,          ".")       X(comma,        ",") \
+    X(openParen,     "(")        X(closeParen,   ")")       X(openBrace,    "{")    X(closeBrace, "}") \
+    X(openBracket,   "[")        X(closeBracket, "]")       X(colon,        ":")    X(question,   "?") \
+    X(typeEquals,    "===")      X(equals,       "==")      X(assign,       "=") \
+    X(typeNotEquals, "!==")      X(notEquals,    "!=")      X(logicalNot,   "!") \
+    X(plusEquals,    "+=")       X(plusplus,     "++")      X(plus,         "+") \
+    X(minusEquals,   "-=")       X(minusminus,   "--")      X(minus,        "-") \
+    X(timesEquals,   "*=")       X(times,        "*")       X(divideEquals, "/=")   X(divide,     "/") \
+    X(moduloEquals,  "%=")       X(modulo,       "%")       X(xorEquals,    "^=")   X(bitwiseXor, "^") \
+    X(andEquals,     "&=")       X(logicalAnd,   "&&")      X(bitwiseAnd,   "&") \
+    X(orEquals,      "|=")       X(logicalOr,    "||")      X(bitwiseOr,    "|") \
+    X(leftShiftEquals,    "<<=") X(lessThanOrEqual,  "<=")  X(leftShift,    "<<")   X(lessThan,   "<") \
+    X(rightShiftUnsigned, ">>>") X(rightShiftEquals, ">>=") X(rightShift,   ">>")   X(greaterThanOrEqual, ">=")  X(greaterThan,  ">")
+
+#define JUCE_JS_KEYWORDS(X) \
+    X(var,      "var")      X(if_,     "if")     X(else_,  "else")   X(do_,       "do")       X(null_,     "null") \
+    X(while_,   "while")    X(for_,    "for")    X(break_, "break")  X(continue_, "continue") X(undefined, "undefined") \
+    X(function, "function") X(return_, "return") X(true_,  "true")   X(false_,    "false")    X(new_,      "new")
+
+namespace TokenTypes
+{
+    #define JUCE_DECLARE_JS_TOKEN(name, str)  static const char* const name = str;
+    JUCE_JS_KEYWORDS  (JUCE_DECLARE_JS_TOKEN)
+    JUCE_JS_OPERATORS (JUCE_DECLARE_JS_TOKEN)
+    JUCE_DECLARE_JS_TOKEN (eof,        "$eof")
+    JUCE_DECLARE_JS_TOKEN (literal,    "$literal")
+    JUCE_DECLARE_JS_TOKEN (identifier, "$identifier")
+}
+
+#if JUCE_MSVC
+ #pragma warning (push)
+ #pragma warning (disable: 4702)
+#endif
+
+//==============================================================================
+struct JavascriptEngine::RootObject   : public DynamicObject
+{
+    RootObject()
+    {
+        setMethod ("exec",      exec);
+        setMethod ("eval",      eval);
+        setMethod ("trace",     trace);
+        setMethod ("charToInt", charToInt);
+        setMethod ("parseInt",  IntegerClass::parseInt);
+    }
+
+    Time timeout;
+
+    typedef const var::NativeFunctionArgs& Args;
+    typedef const char* TokenType;
+
+    void execute (const String& code)
+    {
+        ExpressionTreeBuilder tb (code);
+        ScopedPointer<BlockStatement> (tb.parseStatementList())->perform (Scope (nullptr, this, this), nullptr);
+    }
+
+    var evaluate (const String& code)
+    {
+        ExpressionTreeBuilder tb (code);
+        return ExpPtr (tb.parseExpression())->getResult (Scope (nullptr, this, this));
+    }
+
+    //==============================================================================
+    static bool areTypeEqual (const var& a, const var& b)
+    {
+        return a.hasSameTypeAs (b) && isFunction (a) == isFunction (b)
+                && (((a.isUndefined() || a.isVoid()) && (b.isUndefined() || b.isVoid())) || a == b);
+    }
+
+    static String getTokenName (TokenType t)         { return t[0] == '$' ? String (t + 1) : ("'" + String (t) + "'"); }
+    static bool isFunction (const var& v)            { return dynamic_cast<FunctionObject*> (v.getObject()) != nullptr; }
+    static bool isNumericOrUndefined (const var& v)  { return v.isInt() || v.isDouble() || v.isInt64() || v.isBool() || v.isUndefined(); }
+    static int64 getOctalValue (const String& s)     { BigInteger b; b.parseString (s, 8); return b.toInt64(); }
+    static Identifier getPrototypeIdentifier()       { static const Identifier i ("prototype"); return i; }
+
+    //==============================================================================
+    struct CodeLocation
+    {
+        CodeLocation (const String& code) noexcept        : program (code), location (program.getCharPointer()) {}
+        CodeLocation (const CodeLocation& other) noexcept : program (other.program), location (other.location) {}
+
+        void throwError (const String& message) const
+        {
+            int col = 1, line = 1;
+
+            for (String::CharPointerType i (program.getCharPointer()); i < location && ! i.isEmpty(); ++i)
+            {
+                ++col;
+                if (*i == '\n')  { col = 1; ++line; }
+            }
+
+            throw "Line " + String (line) + ", column " + String (col) + " : " + message;
+        }
+
+        String program;
+        String::CharPointerType location;
+    };
+
+    //==============================================================================
+    struct Scope
+    {
+        Scope (const Scope* p, RootObject* r, DynamicObject* s) noexcept : parent (p), root (r), scope (s) {}
+
+        const Scope* parent;
+        ReferenceCountedObjectPtr<RootObject> root;
+        DynamicObject::Ptr scope;
+
+        var findFunctionCall (const CodeLocation& location, const var& targetObject, Identifier functionName) const
+        {
+            if (DynamicObject* o = targetObject.getDynamicObject())
+            {
+                if (var* prop = o->getProperties().getVarPointer (functionName))
+                    return *prop;
+
+                for (DynamicObject* p = o->getProperty (getPrototypeIdentifier()).getDynamicObject(); p != nullptr;
+                     p = p->getProperty (getPrototypeIdentifier()).getDynamicObject())
+                {
+                    if (var* prop = p->getProperties().getVarPointer (functionName))
+                        return *prop;
+                }
+            }
+
+            if (targetObject.isString())
+                if (var* m = findRootClassProperty (StringClass::getClassName(), functionName))
+                    return *m;
+
+            if (targetObject.isArray())
+                if (var* m = findRootClassProperty (ArrayClass::getClassName(), functionName))
+                    return *m;
+
+            if (var* m = findRootClassProperty (ObjectClass::getClassName(), functionName))
+                return *m;
+
+            location.throwError ("Unknown function '" + functionName.toString() + "'");
+            return var();
+        }
+
+        var* findRootClassProperty (Identifier className, Identifier propName) const
+        {
+            if (DynamicObject* cls = root->getProperty (className).getDynamicObject())
+                return cls->getProperties().getVarPointer (propName);
+
+            return nullptr;
+        }
+
+        var findSymbolInParentScopes (Identifier name) const
+        {
+            if (var* v = scope->getProperties().getVarPointer (name))
+                return *v;
+
+            return parent != nullptr ? parent->findSymbolInParentScopes (name)
+                                     : var::undefined();
+        }
+
+        bool findAndInvokeMethod (Identifier function, const var::NativeFunctionArgs& args, var& result) const
+        {
+            const NamedValueSet& props = scope->getProperties();
+
+            DynamicObject* target = args.thisObject.getDynamicObject();
+
+            if (target == nullptr || target == scope)
+            {
+                if (const var* m = props.getVarPointer (function))
+                {
+                    if (FunctionObject* fo = dynamic_cast<FunctionObject*> (m->getObject()))
+                    {
+                        result = fo->invoke (*this, args);
+                        return true;
+                    }
+                }
+            }
+
+            for (int i = 0; i < props.size(); ++i)
+                if (DynamicObject* o = props.getValueAt (i).getDynamicObject())
+                    if (Scope (this, root, o).findAndInvokeMethod (function, args, result))
+                        return true;
+
+            return false;
+        }
+
+        void checkTimeOut (const CodeLocation& location) const
+        {
+            if (Time::getCurrentTime() > root->timeout)
+                location.throwError ("Execution timed-out");
+        }
+    };
+
+    //==============================================================================
+    struct Statement
+    {
+        Statement (const CodeLocation& l) noexcept : location (l) {}
+        virtual ~Statement() {}
+
+        enum ResultCode  { ok = 0, returnWasHit, breakWasHit, continueWasHit };
+        virtual ResultCode perform (const Scope&, var*) const  { return ok; }
+
+        CodeLocation location;
+        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Statement)
+    };
+
+    struct Expression  : public Statement
+    {
+        Expression (const CodeLocation& l) noexcept : Statement (l) {}
+
+        virtual var getResult (const Scope&) const            { return var::undefined(); }
+        virtual void assign (const Scope&, const var&) const  { location.throwError ("Cannot assign to this expression!"); }
+
+        ResultCode perform (const Scope& s, var*) const override  { getResult (s); return ok; }
+    };
+
+    typedef ScopedPointer<Expression> ExpPtr;
+
+    struct BlockStatement  : public Statement
+    {
+        BlockStatement (const CodeLocation& l) noexcept : Statement (l) {}
+
+        ResultCode perform (const Scope& s, var* returnedValue) const override
+        {
+            for (int i = 0; i < statements.size(); ++i)
+                if (ResultCode r = statements.getUnchecked(i)->perform (s, returnedValue))
+                    return r;
+
+            return ok;
+        }
+
+        OwnedArray<Statement> statements;
+    };
+
+    struct IfStatement  : public Statement
+    {
+        IfStatement (const CodeLocation& l) noexcept : Statement (l) {}
+
+        ResultCode perform (const Scope& s, var* returnedValue) const override
+        {
+            return (condition->getResult(s) ? trueBranch : falseBranch)->perform (s, returnedValue);
+        }
+
+        ExpPtr condition;
+        ScopedPointer<Statement> trueBranch, falseBranch;
+    };
+
+    struct VarStatement  : public Statement
+    {
+        VarStatement (const CodeLocation& l) noexcept : Statement (l) {}
+
+        ResultCode perform (const Scope& s, var*) const override
+        {
+            s.scope->setProperty (name, initialiser->getResult (s));
+            return ok;
+        }
+
+        Identifier name;
+        ExpPtr initialiser;
+    };
+
+    struct LoopStatement  : public Statement
+    {
+        LoopStatement (const CodeLocation& l, bool isDo) noexcept : Statement (l), isDoLoop (isDo) {}
+
+        ResultCode perform (const Scope& s, var* returnedValue) const override
+        {
+            initialiser->perform (s, nullptr);
+
+            while (isDoLoop || condition->getResult (s))
+            {
+                s.checkTimeOut (location);
+                ResultCode r = body->perform (s, returnedValue);
+
+                if (r == returnWasHit)   return r;
+                if (r == breakWasHit)    break;
+
+                iterator->perform (s, nullptr);
+
+                if (isDoLoop && r != continueWasHit && ! condition->getResult (s))
+                    break;
+            }
+
+            return ok;
+        }
+
+        ScopedPointer<Statement> initialiser, iterator, body;
+        ExpPtr condition;
+        bool isDoLoop;
+    };
+
+    struct ReturnStatement  : public Statement
+    {
+        ReturnStatement (const CodeLocation& l, Expression* v) noexcept : Statement (l), returnValue (v) {}
+
+        ResultCode perform (const Scope& s, var* ret) const override
+        {
+            if (ret != nullptr)  *ret = returnValue->getResult (s);
+            return returnWasHit;
+        }
+
+        ExpPtr returnValue;
+    };
+
+    struct BreakStatement  : public Statement
+    {
+        BreakStatement (const CodeLocation& l) noexcept : Statement (l) {}
+        ResultCode perform (const Scope&, var*) const override  { return breakWasHit; }
+    };
+
+    struct ContinueStatement  : public Statement
+    {
+        ContinueStatement (const CodeLocation& l) noexcept : Statement (l) {}
+        ResultCode perform (const Scope&, var*) const override  { return continueWasHit; }
+    };
+
+    struct LiteralValue  : public Expression
+    {
+        LiteralValue (const CodeLocation& l, const var& v) noexcept : Expression (l), value (v) {}
+        var getResult (const Scope&) const override   { return value; }
+        var value;
+    };
+
+    struct UnqualifiedName  : public Expression
+    {
+        UnqualifiedName (const CodeLocation& l, Identifier n) noexcept : Expression (l), name (n) {}
+
+        var getResult (const Scope& s) const override  { return s.findSymbolInParentScopes (name); }
+
+        void assign (const Scope& s, const var& newValue) const override
+        {
+            if (var* v = s.scope->getProperties().getVarPointer (name))
+                *v = newValue;
+            else
+                s.root->setProperty (name, newValue);
+        }
+
+        Identifier name;
+    };
+
+    struct DotOperator  : public Expression
+    {
+        DotOperator (const CodeLocation& l, ExpPtr& p, Identifier c) noexcept : Expression (l), parent (p), child (c) {}
+
+        var getResult (const Scope& s) const override
+        {
+            var p (parent->getResult (s));
+            static const Identifier lengthID ("length");
+
+            if (child == lengthID)
+            {
+                if (Array<var>* array = p.getArray())   return array->size();
+                if (p.isString())                       return p.toString().length();
+            }
+
+            if (DynamicObject* o = p.getDynamicObject())
+                if (var* v = o->getProperties().getVarPointer (child))
+                    return *v;
+
+            return var::undefined();
+        }
+
+        void assign (const Scope& s, const var& newValue) const override
+        {
+            if (DynamicObject* o = parent->getResult (s).getDynamicObject())
+                o->setProperty (child, newValue);
+            else
+                Expression::assign (s, newValue);
+        }
+
+        ExpPtr parent;
+        Identifier child;
+    };
+
+    struct ArraySubscript  : public Expression
+    {
+        ArraySubscript (const CodeLocation& l) noexcept : Expression (l) {}
+
+        var getResult (const Scope& s) const override
+        {
+            if (const Array<var>* array = object->getResult (s).getArray())
+                return (*array) [static_cast<int> (index->getResult (s))];
+
+            return var::undefined();
+        }
+
+        void assign (const Scope& s, const var& newValue) const override
+        {
+            if (Array<var>* array = object->getResult (s).getArray())
+            {
+                const int i = index->getResult (s);
+                while (array->size() < i)
+                    array->add (var::undefined());
+
+                array->set (i, newValue);
+                return;
+            }
+
+            Expression::assign (s, newValue);
+        }
+
+        ExpPtr object, index;
+    };
+
+    struct BinaryOperatorBase  : public Expression
+    {
+        BinaryOperatorBase (const CodeLocation& l, ExpPtr& a, ExpPtr& b, TokenType op) noexcept
+            : Expression (l), lhs (a), rhs (b), operation (op) {}
+
+        ExpPtr lhs, rhs;
+        TokenType operation;
+    };
+
+    struct BinaryOperator  : public BinaryOperatorBase
+    {
+        BinaryOperator (const CodeLocation& l, ExpPtr& a, ExpPtr& b, TokenType op) noexcept
+            : BinaryOperatorBase (l, a, b, op) {}
+
+        virtual var getWithUndefinedArg() const                           { return var::undefined(); }
+        virtual var getWithDoubles (double, double) const                 { return throwError ("Double"); }
+        virtual var getWithInts (int64, int64) const                      { return throwError ("Integer"); }
+        virtual var getWithArrayOrObject (const var& a, const var&) const { return throwError (a.isArray() ? "Array" : "Object"); }
+        virtual var getWithStrings (const String&, const String&) const   { return throwError ("String"); }
+
+        var getResult (const Scope& s) const override
+        {
+            var a (lhs->getResult (s)), b (rhs->getResult (s));
+
+            if ((a.isUndefined() || a.isVoid()) && (b.isUndefined() || b.isVoid()))
+                return getWithUndefinedArg();
+
+            if (isNumericOrUndefined (a) && isNumericOrUndefined (b))
+                return (a.isDouble() || b.isDouble()) ? getWithDoubles (a, b) : getWithInts (a, b);
+
+            if (a.isArray() || a.isObject())
+                return getWithArrayOrObject (a, b);
+
+            return getWithStrings (a.toString(), b.toString());
+        }
+
+        var throwError (const char* typeName) const
+            { location.throwError (getTokenName (operation) + " is not allowed on the " + typeName + " type"); return var(); }
+    };
+
+    struct EqualsOp  : public BinaryOperator
+    {
+        EqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::equals) {}
+        var getWithUndefinedArg() const override                               { return true; }
+        var getWithDoubles (double a, double b) const override                 { return a == b; }
+        var getWithInts (int64 a, int64 b) const override                      { return a == b; }
+        var getWithStrings (const String& a, const String& b) const override   { return a == b; }
+        var getWithArrayOrObject (const var& a, const var& b) const override   { return a == b; }
+    };
+
+    struct NotEqualsOp  : public BinaryOperator
+    {
+        NotEqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::notEquals) {}
+        var getWithUndefinedArg() const override                               { return false; }
+        var getWithDoubles (double a, double b) const override                 { return a != b; }
+        var getWithInts (int64 a, int64 b) const override                      { return a != b; }
+        var getWithStrings (const String& a, const String& b) const override   { return a != b; }
+        var getWithArrayOrObject (const var& a, const var& b) const override   { return a != b; }
+    };
+
+    struct LessThanOp  : public BinaryOperator
+    {
+        LessThanOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::lessThan) {}
+        var getWithDoubles (double a, double b) const override                 { return a < b; }
+        var getWithInts (int64 a, int64 b) const override                      { return a < b; }
+        var getWithStrings (const String& a, const String& b) const override   { return a < b; }
+    };
+
+    struct LessThanOrEqualOp  : public BinaryOperator
+    {
+        LessThanOrEqualOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::lessThanOrEqual) {}
+        var getWithDoubles (double a, double b) const override                 { return a <= b; }
+        var getWithInts (int64 a, int64 b) const override                      { return a <= b; }
+        var getWithStrings (const String& a, const String& b) const override   { return a <= b; }
+    };
+
+    struct GreaterThanOp  : public BinaryOperator
+    {
+        GreaterThanOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::greaterThan) {}
+        var getWithDoubles (double a, double b) const override                 { return a > b; }
+        var getWithInts (int64 a, int64 b) const override                      { return a > b; }
+        var getWithStrings (const String& a, const String& b) const override   { return a > b; }
+    };
+
+    struct GreaterThanOrEqualOp  : public BinaryOperator
+    {
+        GreaterThanOrEqualOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::greaterThanOrEqual) {}
+        var getWithDoubles (double a, double b) const override                 { return a >= b; }
+        var getWithInts (int64 a, int64 b) const override                      { return a >= b; }
+        var getWithStrings (const String& a, const String& b) const override   { return a >= b; }
+    };
+
+    struct AdditionOp  : public BinaryOperator
+    {
+        AdditionOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::plus) {}
+        var getWithDoubles (double a, double b) const override                 { return a + b; }
+        var getWithInts (int64 a, int64 b) const override                      { return a + b; }
+        var getWithStrings (const String& a, const String& b) const override   { return a + b; }
+    };
+
+    struct SubtractionOp  : public BinaryOperator
+    {
+        SubtractionOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::minus) {}
+        var getWithDoubles (double a, double b) const override { return a - b; }
+        var getWithInts (int64 a, int64 b) const override      { return a - b; }
+    };
+
+    struct MultiplyOp  : public BinaryOperator
+    {
+        MultiplyOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::times) {}
+        var getWithDoubles (double a, double b) const override { return a * b; }
+        var getWithInts (int64 a, int64 b) const override      { return a * b; }
+    };
+
+    struct DivideOp  : public BinaryOperator
+    {
+        DivideOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::divide) {}
+        var getWithDoubles (double a, double b) const override  { return b != 0 ? a / b : std::numeric_limits<double>::infinity(); }
+        var getWithInts (int64 a, int64 b) const override       { return b != 0 ? var (a / b) : var (std::numeric_limits<double>::infinity()); }
+    };
+
+    struct ModuloOp  : public BinaryOperator
+    {
+        ModuloOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::modulo) {}
+        var getWithInts (int64 a, int64 b) const override   { return b != 0 ? var (a % b) : var (std::numeric_limits<double>::infinity()); }
+    };
+
+    struct BitwiseOrOp  : public BinaryOperator
+    {
+        BitwiseOrOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::bitwiseOr) {}
+        var getWithInts (int64 a, int64 b) const override   { return a | b; }
+    };
+
+    struct BitwiseAndOp  : public BinaryOperator
+    {
+        BitwiseAndOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::bitwiseAnd) {}
+        var getWithInts (int64 a, int64 b) const override   { return a & b; }
+    };
+
+    struct BitwiseXorOp  : public BinaryOperator
+    {
+        BitwiseXorOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::bitwiseXor) {}
+        var getWithInts (int64 a, int64 b) const override   { return a ^ b; }
+    };
+
+    struct LeftShiftOp  : public BinaryOperator
+    {
+        LeftShiftOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::leftShift) {}
+        var getWithInts (int64 a, int64 b) const override   { return ((int) a) << (int) b; }
+    };
+
+    struct RightShiftOp  : public BinaryOperator
+    {
+        RightShiftOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::rightShift) {}
+        var getWithInts (int64 a, int64 b) const override   { return ((int) a) >> (int) b; }
+    };
+
+    struct RightShiftUnsignedOp  : public BinaryOperator
+    {
+        RightShiftUnsignedOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::rightShiftUnsigned) {}
+        var getWithInts (int64 a, int64 b) const override   { return (int) (((uint32) a) >> (int) b); }
+    };
+
+    struct LogicalAndOp  : public BinaryOperatorBase
+    {
+        LogicalAndOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::logicalAnd) {}
+        var getResult (const Scope& s) const override       { return lhs->getResult (s) && rhs->getResult (s); }
+    };
+
+    struct LogicalOrOp  : public BinaryOperatorBase
+    {
+        LogicalOrOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::logicalOr) {}
+        var getResult (const Scope& s) const override       { return lhs->getResult (s) || rhs->getResult (s); }
+    };
+
+    struct TypeEqualsOp  : public BinaryOperatorBase
+    {
+        TypeEqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::typeEquals) {}
+        var getResult (const Scope& s) const override       { return areTypeEqual (lhs->getResult (s), rhs->getResult (s)); }
+    };
+
+    struct TypeNotEqualsOp  : public BinaryOperatorBase
+    {
+        TypeNotEqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::typeNotEquals) {}
+        var getResult (const Scope& s) const override       { return ! areTypeEqual (lhs->getResult (s), rhs->getResult (s)); }
+    };
+
+    struct ConditionalOp  : public Expression
+    {
+        ConditionalOp (const CodeLocation& l) noexcept : Expression (l) {}
+
+        var getResult (const Scope& s) const override              { return (condition->getResult (s) ? trueBranch : falseBranch)->getResult (s); }
+        void assign (const Scope& s, const var& v) const override  { (condition->getResult (s) ? trueBranch : falseBranch)->assign (s, v); }
+
+        ExpPtr condition, trueBranch, falseBranch;
+    };
+
+    struct Assignment  : public Expression
+    {
+        Assignment (const CodeLocation& l, ExpPtr& dest, ExpPtr& source) noexcept : Expression (l), target (dest), newValue (source) {}
+
+        var getResult (const Scope& s) const override
+        {
+            var value (newValue->getResult (s));
+            target->assign (s, value);
+            return value;
+        }
+
+        ExpPtr target, newValue;
+    };
+
+    struct SelfAssignment  : public Expression
+    {
+        SelfAssignment (const CodeLocation& l, Expression* dest, Expression* source) noexcept
+            : Expression (l), target (dest), newValue (source) {}
+
+        var getResult (const Scope& s) const override
+        {
+            var value (newValue->getResult (s));
+            target->assign (s, value);
+            return value;
+        }
+
+        Expression* target; // Careful! this pointer aliases a sub-term of newValue!
+        ExpPtr newValue;
+        TokenType op;
+    };
+
+    struct PostAssignment  : public SelfAssignment
+    {
+        PostAssignment (const CodeLocation& l, Expression* dest, Expression* source) noexcept : SelfAssignment (l, dest, source) {}
+
+        var getResult (const Scope& s) const override
+        {
+            var oldValue (target->getResult (s));
+            target->assign (s, newValue->getResult (s));
+            return oldValue;
+        }
+    };
+
+    struct FunctionCall  : public Expression
+    {
+        FunctionCall (const CodeLocation& l) noexcept : Expression (l) {}
+
+        var getResult (const Scope& s) const override
+        {
+            if (DotOperator* dot = dynamic_cast<DotOperator*> (object.get()))
+            {
+                var thisObject (dot->parent->getResult (s));
+                return invokeFunction (s, s.findFunctionCall (location, thisObject, dot->child), thisObject);
+            }
+
+            var function (object->getResult (s));
+            return invokeFunction (s, function, var (s.scope));
+        }
+
+        var invokeFunction (const Scope& s, const var& function, const var& thisObject) const
+        {
+            s.checkTimeOut (location);
+
+            Array<var> argVars;
+            for (int i = 0; i < arguments.size(); ++i)
+                argVars.add (arguments.getUnchecked(i)->getResult (s));
+
+            const var::NativeFunctionArgs args (thisObject, argVars.begin(), argVars.size());
+
+            if (var::NativeFunction nativeFunction = function.getNativeFunction())
+                return nativeFunction (args);
+
+            if (FunctionObject* fo = dynamic_cast<FunctionObject*> (function.getObject()))
+                return fo->invoke (s, args);
+
+            location.throwError ("This expression is not a function!"); return var();
+        }
+
+        ExpPtr object;
+        OwnedArray<Expression> arguments;
+    };
+
+    struct NewOperator  : public FunctionCall
+    {
+        NewOperator (const CodeLocation& l) noexcept : FunctionCall (l) {}
+
+        var getResult (const Scope& s) const override
+        {
+            var classOrFunc = object->getResult (s);
+
+            const bool isFunc = isFunction (classOrFunc);
+            if (! (isFunc || classOrFunc.getDynamicObject() != nullptr))
+                return var::undefined();
+
+            DynamicObject::Ptr newObject (new DynamicObject());
+
+            if (isFunc)
+                invokeFunction (s, classOrFunc, newObject.get());
+            else
+                newObject->setProperty (getPrototypeIdentifier(), classOrFunc);
+
+            return newObject.get();
+        }
+    };
+
+    struct ObjectDeclaration  : public Expression
+    {
+        ObjectDeclaration (const CodeLocation& l) noexcept : Expression (l) {}
+
+        var getResult (const Scope& s) const override
+        {
+            DynamicObject::Ptr newObject (new DynamicObject());
+
+            for (int i = 0; i < names.size(); ++i)
+                newObject->setProperty (names.getUnchecked(i), initialisers.getUnchecked(i)->getResult (s));
+
+            return newObject.get();
+        }
+
+        Array<Identifier> names;
+        OwnedArray<Expression> initialisers;
+    };
+
+    struct ArrayDeclaration  : public Expression
+    {
+        ArrayDeclaration (const CodeLocation& l) noexcept : Expression (l) {}
+
+        var getResult (const Scope& s) const override
+        {
+            Array<var> a;
+
+            for (int i = 0; i < values.size(); ++i)
+                a.add (values.getUnchecked(i)->getResult (s));
+
+            return a;
+        }
+
+        OwnedArray<Expression> values;
+    };
+
+    //==============================================================================
+    struct FunctionObject  : public DynamicObject
+    {
+        FunctionObject() noexcept {}
+
+        FunctionObject (const FunctionObject& other)  : DynamicObject(), functionCode (other.functionCode)
+        {
+            ExpressionTreeBuilder tb (functionCode);
+            tb.parseFunctionParamsAndBody (*this);
+        }
+
+        DynamicObject::Ptr clone() override    { return new FunctionObject (*this); }
+
+        void writeAsJSON (OutputStream& out, int /*indentLevel*/, bool /*allOnOneLine*/) override
+        {
+            out << "function " << functionCode;
+        }
+
+        var invoke (const Scope& s, const var::NativeFunctionArgs& args) const
+        {
+            DynamicObject::Ptr functionRoot (new DynamicObject());
+
+            static const Identifier thisIdent ("this");
+            functionRoot->setProperty (thisIdent, args.thisObject);
+
+            for (int i = 0; i < parameters.size(); ++i)
+                functionRoot->setProperty (parameters.getReference(i),
+                                           i < args.numArguments ? args.arguments[i] : var::undefined());
+
+            var result;
+            body->perform (Scope (&s, s.root, functionRoot), &result);
+            return result;
+        }
+
+        String functionCode;
+        Array<Identifier> parameters;
+        ScopedPointer<Statement> body;
+    };
+
+    //==============================================================================
+    struct TokenIterator
+    {
+        TokenIterator (const String& code) : location (code), p (code.getCharPointer()) { skip(); }
+
+        void skip()
+        {
+            skipWhitespaceAndComments();
+            location.location = p;
+            currentType = matchNextToken();
+        }
+
+        void match (TokenType expected)
+        {
+            if (currentType != expected)
+                location.throwError ("Found " + getTokenName (currentType) + " when expecting " + getTokenName (expected));
+
+            skip();
+        }
+
+        bool matchIf (TokenType expected)                                 { if (currentType == expected)  { skip(); return true; } return false; }
+        bool matchesAny (TokenType t1, TokenType t2) const                { return currentType == t1 || currentType == t2; }
+        bool matchesAny (TokenType t1, TokenType t2, TokenType t3) const  { return matchesAny (t1, t2) || currentType == t3; }
+
+        CodeLocation location;
+        TokenType currentType;
+        var currentValue;
+
+    private:
+        String::CharPointerType p;
+
+        static bool isIdentifierStart (const juce_wchar c) noexcept   { return CharacterFunctions::isLetter (c)        || c == '_'; }
+        static bool isIdentifierBody  (const juce_wchar c) noexcept   { return CharacterFunctions::isLetterOrDigit (c) || c == '_'; }
+
+        TokenType matchNextToken()
+        {
+            if (isIdentifierStart (*p))
+            {
+                String::CharPointerType end (p);
+                while (isIdentifierBody (*++end)) {}
+
+                const size_t len = (size_t) (end - p);
+                #define JUCE_JS_COMPARE_KEYWORD(name, str) if (len == sizeof (str) - 1 && matchToken (TokenTypes::name, len)) return TokenTypes::name;
+                JUCE_JS_KEYWORDS (JUCE_JS_COMPARE_KEYWORD)
+
+                currentValue = String (p, end); p = end;
+                return TokenTypes::identifier;
+            }
+
+            if (p.isDigit())
+            {
+                if (parseHexLiteral() || parseFloatLiteral() || parseOctalLiteral() || parseDecimalLiteral())
+                    return TokenTypes::literal;
+
+                location.throwError ("Syntax error in numeric constant");
+            }
+
+            if (parseStringLiteral (*p) || (*p == '.' && parseFloatLiteral()))
+                return TokenTypes::literal;
+
+            #define JUCE_JS_COMPARE_OPERATOR(name, str) if (matchToken (TokenTypes::name, sizeof (str) - 1)) return TokenTypes::name;
+            JUCE_JS_OPERATORS (JUCE_JS_COMPARE_OPERATOR)
+
+            if (! p.isEmpty())
+                location.throwError ("Unexpected character '" + String::charToString (*p) + "' in source");
+
+            return TokenTypes::eof;
+        }
+
+        bool matchToken (TokenType name, const size_t len) noexcept
+        {
+            if (p.compareUpTo (CharPointer_ASCII (name), (int) len) != 0) return false;
+            p += (int) len;  return true;
+        }
+
+        void skipWhitespaceAndComments()
+        {
+            for (;;)
+            {
+                p = p.findEndOfWhitespace();
+
+                if (*p == '/')
+                {
+                    const juce_wchar c2 = p[1];
+
+                    if (c2 == '/')  { p = CharacterFunctions::find (p, (juce_wchar) '\n'); continue; }
+
+                    if (c2 == '*')
+                    {
+                        location.location = p;
+                        p = CharacterFunctions::find (p + 2, CharPointer_ASCII ("*/"));
+                        if (p.isEmpty()) location.throwError ("Unterminated '/*' comment");
+                        p += 2; continue;
+                    }
+                }
+
+                break;
+            }
+        }
+
+        bool parseStringLiteral (juce_wchar quoteType)
+        {
+            if (quoteType != '"' && quoteType != '\'')
+                return false;
+
+            Result r (JSON::parseQuotedString (p, currentValue));
+            if (r.failed()) location.throwError (r.getErrorMessage());
+            return true;
+        }
+
+        bool parseHexLiteral()
+        {
+            if (*p != '0' || (p[1] != 'x' && p[1] != 'X')) return false;
+
+            String::CharPointerType t (++p);
+            int64 v = CharacterFunctions::getHexDigitValue (*++t);
+            if (v < 0) return false;
+
+            for (;;)
+            {
+                const int digit = CharacterFunctions::getHexDigitValue (*++t);
+                if (digit < 0) break;
+                v = v * 16 + digit;
+            }
+
+            currentValue = v; p = t;
+            return true;
+        }
+
+        bool parseFloatLiteral()
+        {
+            int numDigits = 0;
+            String::CharPointerType t (p);
+            while (t.isDigit())  { ++t; ++numDigits; }
+
+            const bool hasPoint = (*t == '.');
+
+            if (hasPoint)
+                while ((++t).isDigit())  ++numDigits;
+
+            if (numDigits == 0)
+                return false;
+
+            juce_wchar c = *t;
+            const bool hasExponent = (c == 'e' || c == 'E');
+
+            if (hasExponent)
+            {
+                c = *++t;
+                if (c == '+' || c == '-')  ++t;
+                if (! t.isDigit()) return false;
+                while ((++t).isDigit()) {}
+            }
+
+            if (! (hasExponent || hasPoint)) return false;
+
+            currentValue = CharacterFunctions::getDoubleValue (p);  p = t;
+            return true;
+        }
+
+        bool parseOctalLiteral()
+        {
+            String::CharPointerType t (p);
+            int64 v = *t - '0';
+            if (v != 0) return false;  // first digit of octal must be 0
+
+            for (;;)
+            {
+                const int digit = (int) (*++t - '0');
+                if (isPositiveAndBelow (digit, 8))        v = v * 8 + digit;
+                else if (isPositiveAndBelow (digit, 10))  location.throwError ("Decimal digit in octal constant");
+                else break;
+            }
+
+            currentValue = v;  p = t;
+            return true;
+        }
+
+        bool parseDecimalLiteral()
+        {
+            int64 v = 0;
+
+            for (;; ++p)
+            {
+                const int digit = (int) (*p - '0');
+                if (isPositiveAndBelow (digit, 10))  v = v * 10 + digit;
+                else break;
+            }
+
+            currentValue = v;
+            return true;
+        }
+    };
+
+    //==============================================================================
+    struct ExpressionTreeBuilder  : private TokenIterator
+    {
+        ExpressionTreeBuilder (const String code)  : TokenIterator (code) {}
+
+        BlockStatement* parseStatementList()
+        {
+            ScopedPointer<BlockStatement> b (new BlockStatement (location));
+
+            while (currentType != TokenTypes::closeBrace && currentType != TokenTypes::eof)
+                b->statements.add (parseStatement());
+
+            return b.release();
+        }
+
+        void parseFunctionParamsAndBody (FunctionObject& fo)
+        {
+            match (TokenTypes::openParen);
+
+            while (currentType != TokenTypes::closeParen)
+            {
+                fo.parameters.add (currentValue.toString());
+                match (TokenTypes::identifier);
+
+                if (currentType != TokenTypes::closeParen)
+                    match (TokenTypes::comma);
+            }
+
+            match (TokenTypes::closeParen);
+            fo.body = parseBlock();
+        }
+
+        Expression* parseExpression()
+        {
+            ExpPtr lhs (parseLogicOperator());
+
+            if (matchIf (TokenTypes::question))          return parseTerneryOperator (lhs);
+            if (matchIf (TokenTypes::assign))            { ExpPtr rhs (parseExpression()); return new Assignment (location, lhs, rhs); }
+            if (matchIf (TokenTypes::plusEquals))        return parseInPlaceOpExpression<AdditionOp> (lhs);
+            if (matchIf (TokenTypes::minusEquals))       return parseInPlaceOpExpression<SubtractionOp> (lhs);
+            if (matchIf (TokenTypes::leftShiftEquals))   return parseInPlaceOpExpression<LeftShiftOp> (lhs);
+            if (matchIf (TokenTypes::rightShiftEquals))  return parseInPlaceOpExpression<RightShiftOp> (lhs);
+
+            return lhs.release();
+        }
+
+    private:
+        void throwError (const String& err) const  { location.throwError (err); }
+
+        template <typename OpType>
+        Expression* parseInPlaceOpExpression (ExpPtr& lhs)
+        {
+            ExpPtr rhs (parseExpression());
+            Expression* bareLHS = lhs; // careful - bare pointer is deliberately alised
+            return new SelfAssignment (location, bareLHS, new OpType (location, lhs, rhs));
+        }
+
+        BlockStatement* parseBlock()
+        {
+            match (TokenTypes::openBrace);
+            ScopedPointer<BlockStatement> b (parseStatementList());
+            match (TokenTypes::closeBrace);
+            return b.release();
+        }
+
+        Statement* parseStatement()
+        {
+            if (currentType == TokenTypes::openBrace)   return parseBlock();
+            if (matchIf (TokenTypes::var))              return parseVar();
+            if (matchIf (TokenTypes::if_))              return parseIf();
+            if (matchIf (TokenTypes::while_))           return parseDoOrWhileLoop (false);
+            if (matchIf (TokenTypes::do_))              return parseDoOrWhileLoop (true);
+            if (matchIf (TokenTypes::for_))             return parseForLoop();
+            if (matchIf (TokenTypes::return_))          return new ReturnStatement (location, matchIf (TokenTypes::semicolon) ? new Expression (location) : parseExpression());
+            if (matchIf (TokenTypes::break_))           return new BreakStatement (location);
+            if (matchIf (TokenTypes::continue_))        return new ContinueStatement (location);
+            if (matchIf (TokenTypes::function))         return parseFunction();
+            if (matchIf (TokenTypes::semicolon))        return new Statement (location);
+            if (matchIf (TokenTypes::plusplus))         return parsePreIncDec<AdditionOp>();
+            if (matchIf (TokenTypes::minusminus))       return parsePreIncDec<SubtractionOp>();
+
+            if (matchesAny (TokenTypes::openParen, TokenTypes::openBracket))
+                return matchEndOfStatement (parseFactor());
+
+            if (matchesAny (TokenTypes::identifier, TokenTypes::literal, TokenTypes::minus))
+                return matchEndOfStatement (parseExpression());
+
+            throwError ("Found " + getTokenName (currentType) + " when expecting a statement");
+            return nullptr;
+        }
+
+        Expression* matchEndOfStatement (Expression* ex)  { ExpPtr e (ex); if (currentType != TokenTypes::eof) match (TokenTypes::semicolon); return e.release(); }
+        Expression* matchCloseParen (Expression* ex)      { ExpPtr e (ex); match (TokenTypes::closeParen); return e.release(); }
+
+        Statement* parseIf()
+        {
+            ScopedPointer<IfStatement> s (new IfStatement (location));
+            match (TokenTypes::openParen);
+            s->condition = parseExpression();
+            match (TokenTypes::closeParen);
+            s->trueBranch = parseStatement();
+            s->falseBranch = matchIf (TokenTypes::else_) ? parseStatement() : new Statement (location);
+            return s.release();
+        }
+
+        Statement* parseVar()
+        {
+            ScopedPointer<VarStatement> s (new VarStatement (location));
+            s->name = parseIdentifier();
+            s->initialiser = matchIf (TokenTypes::assign) ? parseExpression() : new Expression (location);
+
+            if (matchIf (TokenTypes::comma))
+            {
+                ScopedPointer<BlockStatement> block (new BlockStatement (location));
+                block->statements.add (s.release());
+                block->statements.add (parseVar());
+                return block.release();
+            }
+
+            match (TokenTypes::semicolon);
+            return s.release();
+        }
+
+        Statement* parseFunction()
+        {
+            Identifier name;
+            var fn = parseFunctionDefinition (name);
+
+            if (name.isNull())
+                throwError ("Functions defined at statement-level must have a name");
+
+            ExpPtr nm (new UnqualifiedName (location, name)), value (new LiteralValue (location, fn));
+            return new Assignment (location, nm, value);
+        }
+
+        Statement* parseForLoop()
+        {
+            ScopedPointer<LoopStatement> s (new LoopStatement (location, false));
+            match (TokenTypes::openParen);
+            s->initialiser = parseStatement();
+
+            if (matchIf (TokenTypes::semicolon))
+                s->condition = new LiteralValue (location, true);
+            else
+            {
+                s->condition = parseExpression();
+                match (TokenTypes::semicolon);
+            }
+
+            s->iterator = parseExpression();
+            match (TokenTypes::closeParen);
+            s->body = parseStatement();
+            return s.release();
+        }
+
+        Statement* parseDoOrWhileLoop (bool isDoLoop)
+        {
+            ScopedPointer<LoopStatement> s (new LoopStatement (location, isDoLoop));
+            s->initialiser = new Statement (location);
+            s->iterator = new Statement (location);
+
+            if (isDoLoop)
+            {
+                s->body = parseBlock();
+                match (TokenTypes::while_);
+            }
+
+            match (TokenTypes::openParen);
+            s->condition = parseExpression();
+            match (TokenTypes::closeParen);
+
+            if (! isDoLoop)
+                s->body = parseStatement();
+
+            return s.release();
+        }
+
+        Identifier parseIdentifier()
+        {
+            Identifier i;
+            if (currentType == TokenTypes::identifier)
+                i = currentValue.toString();
+
+            match (TokenTypes::identifier);
+            return i;
+        }
+
+        var parseFunctionDefinition (Identifier& functionName)
+        {
+            const String::CharPointerType functionStart (location.location);
+
+            if (currentType == TokenTypes::identifier)
+                functionName = parseIdentifier();
+
+            ScopedPointer<FunctionObject> fo (new FunctionObject());
+            parseFunctionParamsAndBody (*fo);
+            fo->functionCode = String (functionStart, location.location);
+            return var (fo.release());
+        }
+
+        Expression* parseFunctionCall (FunctionCall* call, ExpPtr& function)
+        {
+            ScopedPointer<FunctionCall> s (call);
+            s->object = function;
+            match (TokenTypes::openParen);
+
+            while (currentType != TokenTypes::closeParen)
+            {
+                s->arguments.add (parseExpression());
+                if (currentType != TokenTypes::closeParen)
+                    match (TokenTypes::comma);
+            }
+
+            return matchCloseParen (s.release());
+        }
+
+        Expression* parseSuffixes (Expression* e)
+        {
+            ExpPtr input (e);
+
+            if (matchIf (TokenTypes::dot))
+                return parseSuffixes (new DotOperator (location, input, parseIdentifier()));
+
+            if (currentType == TokenTypes::openParen)
+                return parseSuffixes (parseFunctionCall (new FunctionCall (location), input));
+
+            if (matchIf (TokenTypes::openBracket))
+            {
+                ScopedPointer<ArraySubscript> s (new ArraySubscript (location));
+                s->object = input;
+                s->index = parseExpression();
+                match (TokenTypes::closeBracket);
+                return parseSuffixes (s.release());
+            }
+
+            if (matchIf (TokenTypes::plusplus))   return parsePostIncDec<AdditionOp> (input);
+            if (matchIf (TokenTypes::minusminus)) return parsePostIncDec<SubtractionOp> (input);
+
+            return input.release();
+        }
+
+        Expression* parseFactor()
+        {
+            if (currentType == TokenTypes::identifier)  return parseSuffixes (new UnqualifiedName (location, parseIdentifier()));
+            if (matchIf (TokenTypes::openParen))        return parseSuffixes (matchCloseParen (parseExpression()));
+            if (matchIf (TokenTypes::true_))            return parseSuffixes (new LiteralValue (location, (int) 1));
+            if (matchIf (TokenTypes::false_))           return parseSuffixes (new LiteralValue (location, (int) 0));
+            if (matchIf (TokenTypes::null_))            return parseSuffixes (new LiteralValue (location, var()));
+            if (matchIf (TokenTypes::undefined))        return parseSuffixes (new Expression (location));
+
+            if (currentType == TokenTypes::literal)
+            {
+                var v (currentValue); skip();
+                return parseSuffixes (new LiteralValue (location, v));
+            }
+
+            if (matchIf (TokenTypes::openBrace))
+            {
+                ScopedPointer<ObjectDeclaration> e (new ObjectDeclaration (location));
+
+                while (currentType != TokenTypes::closeBrace)
+                {
+                    e->names.add (currentValue.toString());
+                    match ((currentType == TokenTypes::literal && currentValue.isString())
+                             ? TokenTypes::literal : TokenTypes::identifier);
+                    match (TokenTypes::colon);
+                    e->initialisers.add (parseExpression());
+
+                    if (currentType != TokenTypes::closeBrace)
+                        match (TokenTypes::comma);
+                }
+
+                match (TokenTypes::closeBrace);
+                return parseSuffixes (e.release());
+            }
+
+            if (matchIf (TokenTypes::openBracket))
+            {
+                ScopedPointer<ArrayDeclaration> e (new ArrayDeclaration (location));
+
+                while (currentType != TokenTypes::closeBracket)
+                {
+                    e->values.add (parseExpression());
+
+                    if (currentType != TokenTypes::closeBracket)
+                        match (TokenTypes::comma);
+                }
+
+                match (TokenTypes::closeBracket);
+                return parseSuffixes (e.release());
+            }
+
+            if (matchIf (TokenTypes::function))
+            {
+                Identifier name;
+                var fn = parseFunctionDefinition (name);
+
+                if (name.isValid())
+                    throwError ("Inline functions definitions cannot have a name");
+
+                return new LiteralValue (location, fn);
+            }
+
+            if (matchIf (TokenTypes::new_))
+            {
+                ExpPtr name (new UnqualifiedName (location, parseIdentifier()));
+
+                while (matchIf (TokenTypes::dot))
+                    name = new DotOperator (location, name, parseIdentifier());
+
+                return parseFunctionCall (new NewOperator (location), name);
+            }
+
+            throwError ("Found " + getTokenName (currentType) + " when expecting an expression");
+            return nullptr;
+        }
+
+        template <typename OpType>
+        Expression* parsePreIncDec()
+        {
+            Expression* e = parseFactor(); // careful - bare pointer is deliberately alised
+            ExpPtr lhs (e), one (new LiteralValue (location, (int) 1));
+            return new SelfAssignment (location, e, new OpType (location, lhs, one));
+        }
+
+        template <typename OpType>
+        Expression* parsePostIncDec (ExpPtr& lhs)
+        {
+            Expression* e = lhs.release(); // careful - bare pointer is deliberately alised
+            ExpPtr lhs2 (e), one (new LiteralValue (location, (int) 1));
+            return new PostAssignment (location, e, new OpType (location, lhs2, one));
+        }
+
+        Expression* parseUnary()
+        {
+            if (matchIf (TokenTypes::minus))       { ExpPtr a (new LiteralValue (location, (int) 0)), b (parseUnary()); return new SubtractionOp   (location, a, b); }
+            if (matchIf (TokenTypes::logicalNot))  { ExpPtr a (new LiteralValue (location, (int) 0)), b (parseUnary()); return new EqualsOp        (location, a, b); }
+            if (matchIf (TokenTypes::plusplus))    return parsePreIncDec<AdditionOp>();
+            if (matchIf (TokenTypes::minusminus))  return parsePreIncDec<SubtractionOp>();
+
+            return parseFactor();
+        }
+
+        Expression* parseMultiplyDivide()
+        {
+            ExpPtr a (parseUnary());
+
+            for (;;)
+            {
+                if (matchIf (TokenTypes::times))        { ExpPtr b (parseUnary()); a = new MultiplyOp (location, a, b); }
+                else if (matchIf (TokenTypes::divide))  { ExpPtr b (parseUnary()); a = new DivideOp   (location, a, b); }
+                else if (matchIf (TokenTypes::modulo))  { ExpPtr b (parseUnary()); a = new ModuloOp   (location, a, b); }
+                else break;
+            }
+
+            return a.release();
+        }
+
+        Expression* parseAdditionSubtraction()
+        {
+            ExpPtr a (parseMultiplyDivide());
+
+            for (;;)
+            {
+                if (matchIf (TokenTypes::plus))            { ExpPtr b (parseMultiplyDivide()); a = new AdditionOp    (location, a, b); }
+                else if (matchIf (TokenTypes::minus))      { ExpPtr b (parseMultiplyDivide()); a = new SubtractionOp (location, a, b); }
+                else break;
+            }
+
+            return a.release();
+        }
+
+        Expression* parseShiftOperator()
+        {
+            ExpPtr a (parseAdditionSubtraction());
+
+            for (;;)
+            {
+                if (matchIf (TokenTypes::leftShift))                { ExpPtr b (parseExpression()); a = new LeftShiftOp          (location, a, b); }
+                else if (matchIf (TokenTypes::rightShift))          { ExpPtr b (parseExpression()); a = new RightShiftOp         (location, a, b); }
+                else if (matchIf (TokenTypes::rightShiftUnsigned))  { ExpPtr b (parseExpression()); a = new RightShiftUnsignedOp (location, a, b); }
+                else break;
+            }
+
+            return a.release();
+        }
+
+        Expression* parseComparator()
+        {
+            ExpPtr a (parseShiftOperator());
+
+            for (;;)
+            {
+                if (matchIf (TokenTypes::equals))                  { ExpPtr b (parseShiftOperator()); a = new EqualsOp             (location, a, b); }
+                else if (matchIf (TokenTypes::notEquals))          { ExpPtr b (parseShiftOperator()); a = new NotEqualsOp          (location, a, b); }
+                else if (matchIf (TokenTypes::typeEquals))         { ExpPtr b (parseShiftOperator()); a = new TypeEqualsOp         (location, a, b); }
+                else if (matchIf (TokenTypes::typeNotEquals))      { ExpPtr b (parseShiftOperator()); a = new TypeNotEqualsOp      (location, a, b); }
+                else if (matchIf (TokenTypes::lessThan))           { ExpPtr b (parseShiftOperator()); a = new LessThanOp           (location, a, b); }
+                else if (matchIf (TokenTypes::lessThanOrEqual))    { ExpPtr b (parseShiftOperator()); a = new LessThanOrEqualOp    (location, a, b); }
+                else if (matchIf (TokenTypes::greaterThan))        { ExpPtr b (parseShiftOperator()); a = new GreaterThanOp        (location, a, b); }
+                else if (matchIf (TokenTypes::greaterThanOrEqual)) { ExpPtr b (parseShiftOperator()); a = new GreaterThanOrEqualOp (location, a, b); }
+                else break;
+            }
+
+            return a.release();
+        }
+
+        Expression* parseLogicOperator()
+        {
+            ExpPtr a (parseComparator());
+
+            for (;;)
+            {
+                if (matchIf (TokenTypes::logicalAnd))       { ExpPtr b (parseComparator()); a = new LogicalAndOp (location, a, b); }
+                else if (matchIf (TokenTypes::logicalOr))   { ExpPtr b (parseComparator()); a = new LogicalOrOp  (location, a, b); }
+                else if (matchIf (TokenTypes::bitwiseAnd))  { ExpPtr b (parseComparator()); a = new BitwiseAndOp (location, a, b); }
+                else if (matchIf (TokenTypes::bitwiseOr))   { ExpPtr b (parseComparator()); a = new BitwiseOrOp  (location, a, b); }
+                else if (matchIf (TokenTypes::bitwiseXor))  { ExpPtr b (parseComparator()); a = new BitwiseXorOp (location, a, b); }
+                else break;
+            }
+
+            return a.release();
+        }
+
+        Expression* parseTerneryOperator (ExpPtr& condition)
+        {
+            ScopedPointer<ConditionalOp> e (new ConditionalOp (location));
+            e->condition = condition;
+            e->trueBranch = parseExpression();
+            match (TokenTypes::colon);
+            e->falseBranch = parseExpression();
+            return e.release();
+        }
+
+        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExpressionTreeBuilder)
+    };
+
+    //==============================================================================
+    static var get (Args a, int index) noexcept            { return index < a.numArguments ? a.arguments[index] : var(); }
+    static bool isInt (Args a, int index) noexcept         { return get (a, index).isInt() || get (a, index).isInt64(); }
+    static int getInt (Args a, int index) noexcept         { return get (a, index); }
+    static double getDouble (Args a, int index) noexcept   { return get (a, index); }
+    static String getString (Args a, int index) noexcept   { return get (a, index).toString(); }
+
+    //==============================================================================
+    struct ObjectClass  : public DynamicObject
+    {
+        ObjectClass()
+        {
+            setMethod ("dump",  dump);
+            setMethod ("clone", clone);
+        }
+
+        static Identifier getClassName()   { static const Identifier i ("Object"); return i; }
+        static var dump  (Args a)          { DBG (JSON::toString (a.thisObject)); (void) a; return var::undefined(); }
+        static var clone (Args a)          { return a.thisObject.clone(); }
+    };
+
+    //==============================================================================
+    struct ArrayClass  : public DynamicObject
+    {
+        ArrayClass()
+        {
+            setMethod ("contains", contains);
+            setMethod ("remove",   remove);
+            setMethod ("join",     join);
+        }
+
+        static Identifier getClassName()   { static const Identifier i ("Array"); return i; }
+
+        static var contains (Args a)
+        {
+            if (const Array<var>* array = a.thisObject.getArray())
+                return array->contains (get (a, 0));
+
+            return false;
+        }
+
+        static var remove (Args a)
+        {
+            if (Array<var>* array = a.thisObject.getArray())
+                array->removeAllInstancesOf (get (a, 0));
+
+            return var::undefined();
+        }
+
+        static var join (Args a)
+        {
+            StringArray strings;
+
+            if (const Array<var>* array = a.thisObject.getArray())
+                for (int i = 0; i < array->size(); ++i)
+                    strings.add (array->getReference(i).toString());
+
+            return strings.joinIntoString (getString (a, 0));
+        }
+    };
+
+    //==============================================================================
+    struct StringClass  : public DynamicObject
+    {
+        StringClass()
+        {
+            setMethod ("substring",     substring);
+            setMethod ("indexOf",       indexOf);
+            setMethod ("charAt",        charAt);
+            setMethod ("charCodeAt",    charCodeAt);
+            setMethod ("fromCharCode",  fromCharCode);
+            setMethod ("split",         split);
+        }
+
+        static Identifier getClassName()  { static const Identifier i ("String"); return i; }
+
+        static var fromCharCode (Args a)  { return String::charToString (getInt (a, 0)); }
+        static var substring (Args a)     { return a.thisObject.toString().substring (getInt (a, 0), getInt (a, 1)); }
+        static var indexOf (Args a)       { return a.thisObject.toString().indexOf (getString (a, 0)); }
+        static var charCodeAt (Args a)    { return (int) a.thisObject.toString() [getInt (a, 0)]; }
+        static var charAt (Args a)        { int p = getInt (a, 0); return a.thisObject.toString().substring (p, p + 1); }
+
+        static var split (Args a)
+        {
+            const String str (a.thisObject.toString());
+            const String sep (getString (a, 0));
+            StringArray strings;
+
+            if (sep.isNotEmpty())
+                strings.addTokens (str, sep.substring (0, 1), "");
+            else // special-case for empty separator: split all chars separately
+                for (String::CharPointerType pos = str.getCharPointer(); ! pos.isEmpty(); ++pos)
+                    strings.add (String::charToString (*pos));
+
+            var array;
+            for (int i = 0; i < strings.size(); ++i)
+                array.append (strings[i]);
+
+            return array;
+        }
+    };
+
+    //==============================================================================
+    struct MathClass  : public DynamicObject
+    {
+        MathClass()
+        {
+            setMethod ("abs",       Math_abs);              setMethod ("round",     Math_round);
+            setMethod ("random",    Math_random);           setMethod ("randInt",   Math_randInt);
+            setMethod ("min",       Math_min);              setMethod ("max",       Math_max);
+            setMethod ("range",     Math_range);            setMethod ("sign",      Math_sign);
+            setMethod ("PI",        Math_pi);               setMethod ("E",         Math_e);
+            setMethod ("toDegrees", Math_toDegrees);        setMethod ("toRadians", Math_toRadians);
+            setMethod ("sin",       Math_sin);              setMethod ("asin",      Math_asin);
+            setMethod ("sinh",      Math_sinh);             setMethod ("asinh",     Math_asinh);
+            setMethod ("cos",       Math_cos);              setMethod ("acos",      Math_acos);
+            setMethod ("cosh",      Math_cosh);             setMethod ("acosh",     Math_acosh);
+            setMethod ("tan",       Math_tan);              setMethod ("atan",      Math_atan);
+            setMethod ("tanh",      Math_tanh);             setMethod ("atanh",     Math_atanh);
+            setMethod ("log",       Math_log);              setMethod ("log10",     Math_log10);
+            setMethod ("exp",       Math_exp);              setMethod ("pow",       Math_pow);
+            setMethod ("sqr",       Math_sqr);              setMethod ("sqrt",      Math_sqrt);
+        }
+
+        static var Math_pi        (Args)   { return double_Pi; }
+        static var Math_e         (Args)   { return exp (1.0); }
+        static var Math_random    (Args)   { return Random::getSystemRandom().nextDouble(); }
+        static var Math_randInt   (Args a) { return Random::getSystemRandom().nextInt (Range<int> (getInt (a, 0), getInt (a, 1))); }
+        static var Math_abs       (Args a) { return isInt (a, 0) ? var (std::abs   (getInt (a, 0))) : var (std::abs   (getDouble (a, 0))); }
+        static var Math_round     (Args a) { return isInt (a, 0) ? var (roundToInt (getInt (a, 0))) : var (roundToInt (getDouble (a, 0))); }
+        static var Math_sign      (Args a) { return isInt (a, 0) ? var (sign       (getInt (a, 0))) : var (sign       (getDouble (a, 0))); }
+        static var Math_range     (Args a) { return isInt (a, 0) ? var (jlimit (getInt (a, 1), getInt (a, 2), getInt (a, 0))) : var (jlimit (getDouble (a, 1), getDouble (a, 2), getDouble (a, 0))); }
+        static var Math_min       (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmin (getInt (a, 0), getInt (a, 1))) : var (jmin (getDouble (a, 0), getDouble (a, 1))); }
+        static var Math_max       (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmax (getInt (a, 0), getInt (a, 1))) : var (jmax (getDouble (a, 0), getDouble (a, 1))); }
+        static var Math_toDegrees (Args a) { return (180.0 / double_Pi) * getDouble (a, 0); }
+        static var Math_toRadians (Args a) { return (double_Pi / 180.0) * getDouble (a, 0); }
+        static var Math_sin       (Args a) { return sin   (getDouble (a, 0)); }
+        static var Math_asin      (Args a) { return asin  (getDouble (a, 0)); }
+        static var Math_cos       (Args a) { return cos   (getDouble (a, 0)); }
+        static var Math_acos      (Args a) { return acos  (getDouble (a, 0)); }
+        static var Math_sinh      (Args a) { return sinh  (getDouble (a, 0)); }
+        static var Math_asinh     (Args a) { return asinh (getDouble (a, 0)); }
+        static var Math_cosh      (Args a) { return cosh  (getDouble (a, 0)); }
+        static var Math_acosh     (Args a) { return acosh (getDouble (a, 0)); }
+        static var Math_tan       (Args a) { return tan   (getDouble (a, 0)); }
+        static var Math_tanh      (Args a) { return tanh  (getDouble (a, 0)); }
+        static var Math_atan      (Args a) { return atan  (getDouble (a, 0)); }
+        static var Math_atanh     (Args a) { return atanh (getDouble (a, 0)); }
+        static var Math_log       (Args a) { return log   (getDouble (a, 0)); }
+        static var Math_log10     (Args a) { return log10 (getDouble (a, 0)); }
+        static var Math_exp       (Args a) { return exp   (getDouble (a, 0)); }
+        static var Math_pow       (Args a) { return pow   (getDouble (a, 0), getDouble (a, 1)); }
+        static var Math_sqr       (Args a) { double x = getDouble (a, 0); return x * x; }
+        static var Math_sqrt      (Args a) { return std::sqrt  (getDouble (a, 0)); }
+
+        static Identifier getClassName()   { static const Identifier i ("Math"); return i; }
+        template <typename Type> static Type sign (Type n) noexcept  { return n > 0 ? (Type) 1 : (n < 0 ? (Type) -1 : 0); }
+    };
+
+    //==============================================================================
+    struct JSONClass  : public DynamicObject
+    {
+        JSONClass()                        { setMethod ("stringify", stringify); }
+        static Identifier getClassName()   { static const Identifier i ("JSON"); return i; }
+        static var stringify (Args a)      { return JSON::toString (get (a, 0)); }
+    };
+
+    //==============================================================================
+    struct IntegerClass  : public DynamicObject
+    {
+        IntegerClass()                     { setMethod ("parseInt",  parseInt); }
+        static Identifier getClassName()   { static const Identifier i ("Integer"); return i; }
+
+        static var parseInt (Args a)
+        {
+            const String s (getString (a, 0).trim());
+
+            return s[0] == '0' ? (s[1] == 'x' ? s.substring(2).getHexValue64() : getOctalValue (s))
+                               : s.getLargeIntValue();
+        }
+    };
+
+    //==============================================================================
+    static var trace (Args a)      { Logger::outputDebugString (JSON::toString (a.thisObject)); return var::undefined(); }
+    static var charToInt (Args a)  { return (int) (getString (a, 0)[0]); }
+
+    static var exec (Args a)
+    {
+        if (RootObject* root = dynamic_cast<RootObject*> (a.thisObject.getObject()))
+            root->execute (getString (a, 0));
+
+        return var::undefined();
+    }
+
+    static var eval (Args a)
+    {
+        if (RootObject* root = dynamic_cast<RootObject*> (a.thisObject.getObject()))
+            return root->evaluate (getString (a, 0));
+
+        return var::undefined();
+    }
+};
+
+//==============================================================================
+JavascriptEngine::JavascriptEngine()  : maximumExecutionTime (15.0), root (new RootObject())
+{
+    registerNativeObject (RootObject::ObjectClass  ::getClassName(),  new RootObject::ObjectClass());
+    registerNativeObject (RootObject::ArrayClass   ::getClassName(),  new RootObject::ArrayClass());
+    registerNativeObject (RootObject::StringClass  ::getClassName(),  new RootObject::StringClass());
+    registerNativeObject (RootObject::MathClass    ::getClassName(),  new RootObject::MathClass());
+    registerNativeObject (RootObject::JSONClass    ::getClassName(),  new RootObject::JSONClass());
+    registerNativeObject (RootObject::IntegerClass ::getClassName(),  new RootObject::IntegerClass());
+}
+
+JavascriptEngine::~JavascriptEngine() {}
+
+void JavascriptEngine::prepareTimeout() const   { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
+
+void JavascriptEngine::registerNativeObject (Identifier name, DynamicObject* object)
+{
+    root->setProperty (name, object);
+}
+
+Result JavascriptEngine::execute (const String& code)
+{
+    try
+    {
+        prepareTimeout();
+        root->execute (code);
+    }
+    catch (String& error)
+    {
+        return Result::fail (error);
+    }
+
+    return Result::ok();
+}
+
+var JavascriptEngine::evaluate (const String& code, Result* result)
+{
+    try
+    {
+        prepareTimeout();
+        if (result != nullptr) *result = Result::ok();
+        return root->evaluate (code);
+    }
+    catch (String& error)
+    {
+        if (result != nullptr) *result = Result::fail (error);
+    }
+
+    return var::undefined();
+}
+
+var JavascriptEngine::callFunction (Identifier function, const var::NativeFunctionArgs& args, Result* result)
+{
+    var returnVal (var::undefined());
+
+    try
+    {
+        prepareTimeout();
+        if (result != nullptr) *result = Result::ok();
+        RootObject::Scope (nullptr, root, root).findAndInvokeMethod (function, args, returnVal);
+    }
+    catch (String& error)
+    {
+        if (result != nullptr) *result = Result::fail (error);
+    }
+
+    return returnVal;
+}
+
+#if JUCE_MSVC
+ #pragma warning (pop)
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_Javascript.h b/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_Javascript.h
new file mode 100644
index 0000000..42368a4
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/javascript/juce_Javascript.h
@@ -0,0 +1,105 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+/**
+    A simple javascript interpreter!
+
+    It's not fully standards-compliant, and won't be as fast as the fancy JIT-compiled
+    engines that you get in browsers, but this is an extremely compact, low-overhead javascript
+    interpreter, which is integrated with the juce var and DynamicObject classes. If you need
+    a few simple bits of scripting in your app, and want to be able to easily let the JS
+    work with native objects defined as DynamicObject subclasses, then this might do the job.
+
+    To use, simply create an instance of this class and call execute() to run your code.
+    Variables that the script sets can be retrieved with evaluate(), and if you need to provide
+    native objects for the script to use, you can add them with registerNativeObject().
+
+    One caveat: Because the values and objects that the engine works with are DynamicObject
+    and var objects, they use reference-counting rather than garbage-collection, so if your
+    script creates complex connections between objects, you run the risk of creating cyclic
+    dependencies and hence leaking.
+*/
+class JavascriptEngine
+{
+public:
+    /** Creates an instance of the engine.
+        This creates a root namespace and defines some basic Object, String, Array
+        and Math library methods.
+    */
+    JavascriptEngine();
+
+    /** Destructor. */
+    ~JavascriptEngine();
+
+    /** Attempts to parse and run a block of javascript code.
+        If there's a parse or execution error, the error description is returned in
+        the result.
+        You can specify a maximum time for which the program is allowed to run, and
+        it'll return with an error message if this time is exceeded.
+    */
+    Result execute (const String& javascriptCode);
+
+    /** Attempts to parse and run a javascript expression, and returns the result.
+        If there's a syntax error, or the expression can't be evaluated, the return value
+        will be var::undefined(). The errorMessage parameter gives you a way to find out
+        any parsing errors.
+        You can specify a maximum time for which the program is allowed to run, and
+        it'll return with an error message if this time is exceeded.
+    */
+    var evaluate (const String& javascriptCode,
+                  Result* errorMessage = nullptr);
+
+    /** Calls a function in the root namespace, and returns the result.
+        The function arguments are passed in the same format as used by native
+        methods in the var class.
+    */
+    var callFunction (Identifier function,
+                      const var::NativeFunctionArgs& args,
+                      Result* errorMessage = nullptr);
+
+    /** Adds a native object to the root namespace.
+        The object passed-in is reference-counted, and will be retained by the
+        engine until the engine is deleted. The name must be a simple JS identifier,
+        without any dots.
+    */
+    void registerNativeObject (Identifier objectName, DynamicObject* object);
+
+    /** This value indicates how long a call to one of the evaluate methods is permitted
+        to run before timing-out and failing.
+        The default value is a number of seconds, but you can change this to whatever value
+        suits your application.
+    */
+    RelativeTime maximumExecutionTime;
+
+private:
+    JUCE_PUBLIC_IN_DLL_BUILD (struct RootObject)
+    ReferenceCountedObjectPtr<RootObject> root;
+    void prepareTimeout() const;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JavascriptEngine)
+};
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/juce_core.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/juce_core.cpp
new file mode 100644
index 0000000..c6040cb
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/juce_core.cpp
@@ -0,0 +1,226 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#if defined (JUCE_CORE_H_INCLUDED) && ! JUCE_AMALGAMATED_INCLUDE
+ /* When you add this cpp file to your project, you mustn't include it in a file where you've
+    already included any other headers - just put it inside a file on its own, possibly with your config
+    flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
+    header files that the compiler may be using.
+ */
+ #error "Incorrect use of JUCE cpp file"
+#endif
+
+// Your project must contain an AppConfig.h file with your project-specific settings in it,
+// and your header search path must make it accessible to the module's files.
+#include "htio2/JUCE-3.0.8/AppConfig.h"
+
+//==============================================================================
+#include "native/juce_BasicNativeHeaders.h"
+#include "juce_core.h"
+
+#include <locale>
+#include <cctype>
+#include <sys/timeb.h>
+
+#if ! JUCE_ANDROID
+ #include <cwctype>
+#endif
+
+#if JUCE_WINDOWS
+ #include <ctime>
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+
+ #if ! JUCE_MINGW
+  #include <Dbghelp.h>
+
+  #if ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
+   #pragma comment (lib, "DbgHelp.lib")
+  #endif
+ #endif
+
+ #if JUCE_MINGW
+  #include <ws2spi.h>
+ #endif
+
+#else
+ #if JUCE_LINUX || JUCE_ANDROID
+  #include <sys/types.h>
+  #include <sys/socket.h>
+  #include <sys/errno.h>
+  #include <unistd.h>
+  #include <netinet/in.h>
+ #endif
+
+ #if JUCE_LINUX
+  #include <langinfo.h>
+ #endif
+
+ #include <pwd.h>
+ #include <fcntl.h>
+ #include <netdb.h>
+ #include <arpa/inet.h>
+ #include <netinet/tcp.h>
+ #include <sys/time.h>
+ #include <net/if.h>
+ #include <sys/ioctl.h>
+
+ #if ! JUCE_ANDROID
+  #include <execinfo.h>
+ #endif
+#endif
+
+#if JUCE_MAC || JUCE_IOS
+ #include <xlocale.h>
+ #include <mach/mach.h>
+#endif
+
+#if JUCE_ANDROID
+ #include <android/log.h>
+#endif
+
+
+//==============================================================================
+namespace htio2
+{
+namespace juce
+{
+
+#include "containers/juce_AbstractFifo.cpp"
+#include "containers/juce_NamedValueSet.cpp"
+#include "containers/juce_PropertySet.cpp"
+#include "containers/juce_Variant.cpp"
+#include "files/juce_DirectoryIterator.cpp"
+#include "files/juce_File.cpp"
+#include "files/juce_FileInputStream.cpp"
+#include "files/juce_FileOutputStream.cpp"
+#include "files/juce_FileSearchPath.cpp"
+#include "files/juce_TemporaryFile.cpp"
+#include "javascript/juce_JSON.cpp"
+#include "javascript/juce_Javascript.cpp"
+#include "containers/juce_DynamicObject.cpp"
+#include "logging/juce_FileLogger.cpp"
+#include "logging/juce_Logger.cpp"
+#include "maths/juce_BigInteger.cpp"
+#include "maths/juce_Expression.cpp"
+#include "maths/juce_Random.cpp"
+#include "memory/juce_MemoryBlock.cpp"
+#include "misc/juce_Result.cpp"
+#include "misc/juce_Uuid.cpp"
+#include "network/juce_MACAddress.cpp"
+#include "network/juce_NamedPipe.cpp"
+#include "network/juce_Socket.cpp"
+#include "network/juce_IPAddress.cpp"
+#include "streams/juce_BufferedInputStream.cpp"
+#include "streams/juce_FileInputSource.cpp"
+#include "streams/juce_InputStream.cpp"
+#include "streams/juce_MemoryInputStream.cpp"
+#include "streams/juce_MemoryOutputStream.cpp"
+#include "streams/juce_SubregionStream.cpp"
+#include "system/juce_SystemStats.cpp"
+#include "text/juce_CharacterFunctions.cpp"
+#include "text/juce_Identifier.cpp"
+#include "text/juce_LocalisedStrings.cpp"
+#include "text/juce_String.cpp"
+#include "streams/juce_OutputStream.cpp"
+#include "text/juce_StringArray.cpp"
+#include "text/juce_StringPairArray.cpp"
+#include "text/juce_StringPool.cpp"
+#include "text/juce_TextDiff.cpp"
+#include "threads/juce_ReadWriteLock.cpp"
+#include "threads/juce_Thread.cpp"
+#include "threads/juce_ThreadPool.cpp"
+#include "threads/juce_TimeSliceThread.cpp"
+#include "time/juce_PerformanceCounter.cpp"
+#include "time/juce_RelativeTime.cpp"
+#include "time/juce_Time.cpp"
+#include "unit_tests/juce_UnitTest.cpp"
+#include "xml/juce_XmlDocument.cpp"
+#include "xml/juce_XmlElement.cpp"
+#include "zip/juce_GZIPDecompressorInputStream.cpp"
+#include "zip/juce_GZIPCompressorOutputStream.cpp"
+#include "zip/juce_ZipFile.cpp"
+#include "files/juce_FileFilter.cpp"
+#include "files/juce_WildcardFileFilter.cpp"
+
+//==============================================================================
+#if JUCE_MAC || JUCE_IOS
+#include "native/juce_osx_ObjCHelpers.h"
+#endif
+
+#if JUCE_ANDROID
+#include "native/juce_android_JNIHelpers.h"
+#endif
+
+#if ! JUCE_WINDOWS
+#include "native/juce_posix_SharedCode.h"
+#include "native/juce_posix_NamedPipe.cpp"
+#endif
+
+//==============================================================================
+#if JUCE_MAC || JUCE_IOS
+#include "native/juce_mac_Files.mm"
+#include "native/juce_mac_Network.mm"
+#include "native/juce_mac_Strings.mm"
+#include "native/juce_mac_SystemStats.mm"
+#include "native/juce_mac_Threads.mm"
+
+//==============================================================================
+#elif JUCE_WINDOWS
+#include "native/juce_win32_ComSmartPtr.h"
+#include "native/juce_win32_Files.cpp"
+#include "native/juce_win32_Network.cpp"
+#include "native/juce_win32_Registry.cpp"
+#include "native/juce_win32_SystemStats.cpp"
+#include "native/juce_win32_Threads.cpp"
+
+//==============================================================================
+#elif JUCE_LINUX
+#include "native/juce_linux_CommonFile.cpp"
+#include "native/juce_linux_Files.cpp"
+#include "native/juce_linux_Network.cpp"
+#include "native/juce_linux_SystemStats.cpp"
+#include "native/juce_linux_Threads.cpp"
+
+//==============================================================================
+#elif JUCE_ANDROID
+#include "native/juce_linux_CommonFile.cpp"
+#include "native/juce_android_Files.cpp"
+#include "native/juce_android_Misc.cpp"
+#include "native/juce_android_Network.cpp"
+#include "native/juce_android_SystemStats.cpp"
+#include "native/juce_android_Threads.cpp"
+
+#endif
+
+#include "threads/juce_ChildProcess.cpp"
+#include "threads/juce_HighResolutionTimer.cpp"
+#include "network/juce_URL.cpp"
+
+} // namespace juce
+} // namespace htio2
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/juce_core.h b/src/htio2/JUCE-3.0.8/modules/juce_core/juce_core.h
new file mode 100644
index 0000000..7e0bfe2
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/juce_core.h
@@ -0,0 +1,286 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_CORE_H_INCLUDED
+#define JUCE_CORE_H_INCLUDED
+
+#ifndef JUCE_MODULE_AVAILABLE_juce_core
+ /* If you fail to make sure that all your compile units are building JUCE with the same set of
+    option flags, then there's a risk that different compile units will treat the classes as having
+    different memory layouts, leading to very nasty memory corruption errors when they all get
+    linked together. That's why it's best to always include the Introjucer-generated AppConfig.h
+    file before any juce headers.
+
+    Note that if you do have an AppConfig.h file and hit this warning, it means that it doesn't
+    contain the JUCE_MODULE_AVAILABLE_xxx flags, which are necessary for some inter-module
+    functionality to work correctly. In that case, you should either rebuild your AppConfig.h with
+    the latest introjucer, or fix it manually to contain these flags.
+ */
+ #ifdef _MSC_VER
+  #pragma message ("Have you included your AppConfig.h file before including the JUCE headers?")
+ #else
+  #warning "Have you included your AppConfig.h file before including the JUCE headers?"
+ #endif
+#endif
+
+//==============================================================================
+#include "system/juce_TargetPlatform.h"
+
+//=============================================================================
+/** Config: JUCE_FORCE_DEBUG
+
+    Normally, JUCE_DEBUG is set to 1 or 0 based on compiler and project settings,
+    but if you define this value, you can override this to force it to be true or false.
+*/
+#ifndef JUCE_FORCE_DEBUG
+ //#define JUCE_FORCE_DEBUG 0
+#endif
+
+//=============================================================================
+/** Config: JUCE_LOG_ASSERTIONS
+
+    If this flag is enabled, the jassert and jassertfalse macros will always use Logger::writeToLog()
+    to write a message when an assertion happens.
+
+    Enabling it will also leave this turned on in release builds. When it's disabled,
+    however, the jassert and jassertfalse macros will not be compiled in a
+    release build.
+
+    @see jassert, jassertfalse, Logger
+*/
+#ifndef JUCE_LOG_ASSERTIONS
+ #if JUCE_ANDROID
+  #define JUCE_LOG_ASSERTIONS 1
+ #else
+  #define JUCE_LOG_ASSERTIONS 0
+ #endif
+#endif
+
+//=============================================================================
+/** Config: JUCE_CHECK_MEMORY_LEAKS
+
+    Enables a memory-leak check for certain objects when the app terminates. See the LeakedObjectDetector
+    class and the JUCE_LEAK_DETECTOR macro for more details about enabling leak checking for specific classes.
+*/
+#if JUCE_DEBUG && ! defined (JUCE_CHECK_MEMORY_LEAKS)
+ #define JUCE_CHECK_MEMORY_LEAKS 1
+#endif
+
+//=============================================================================
+/** Config: JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
+
+    In a Visual C++  build, this can be used to stop the required system libs being
+    automatically added to the link stage.
+*/
+#ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
+ #define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES 0
+#endif
+
+/** Config: JUCE_INCLUDE_ZLIB_CODE
+    This can be used to disable Juce's embedded 3rd-party zlib code.
+    You might need to tweak this if you're linking to an external zlib library in your app,
+    but for normal apps, this option should be left alone.
+
+    If you disable this, you might also want to set a value for JUCE_ZLIB_INCLUDE_PATH, to
+    specify the path where your zlib headers live.
+*/
+#ifndef JUCE_INCLUDE_ZLIB_CODE
+ #define JUCE_INCLUDE_ZLIB_CODE 1
+#endif
+
+#ifndef JUCE_ZLIB_INCLUDE_PATH
+ #define JUCE_ZLIB_INCLUDE_PATH <zlib.h>
+#endif
+
+/*  Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS
+    If enabled, this will add some exception-catching code to forward unhandled exceptions
+    to your JUCEApplicationBase::unhandledException() callback.
+*/
+#ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS
+ //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1
+#endif
+
+#ifndef JUCE_STRING_UTF_TYPE
+ #define JUCE_STRING_UTF_TYPE 8
+#endif
+
+//=============================================================================
+//=============================================================================
+#if JUCE_MSVC
+ #pragma warning (disable: 4251) // (DLL build warning, must be disabled before pushing the warning state)
+ #pragma warning (push)
+ #pragma warning (disable: 4786) // (long class name warning)
+ #ifdef __INTEL_COMPILER
+  #pragma warning (disable: 1125)
+ #endif
+#endif
+
+#include "system/juce_StandardHeader.h"
+
+namespace htio2
+{
+namespace juce
+{
+
+class StringRef;
+class MemoryBlock;
+class File;
+class InputStream;
+class OutputStream;
+class DynamicObject;
+class FileInputStream;
+class FileOutputStream;
+class XmlElement;
+class JSONFormatter;
+
+extern JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger();
+extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noexcept;
+
+#include "memory/juce_Memory.h"
+#include "maths/juce_MathsFunctions.h"
+#include "memory/juce_ByteOrder.h"
+#include "memory/juce_Atomic.h"
+#include "text/juce_CharacterFunctions.h"
+
+#if JUCE_MSVC
+ #pragma warning (push)
+ #pragma warning (disable: 4514 4996)
+#endif
+
+#include "text/juce_CharPointer_UTF8.h"
+#include "text/juce_CharPointer_UTF16.h"
+#include "text/juce_CharPointer_UTF32.h"
+#include "text/juce_CharPointer_ASCII.h"
+
+#if JUCE_MSVC
+ #pragma warning (pop)
+#endif
+
+#include "text/juce_String.h"
+#include "text/juce_StringRef.h"
+#include "logging/juce_Logger.h"
+#include "memory/juce_LeakedObjectDetector.h"
+#include "memory/juce_ContainerDeletePolicy.h"
+#include "memory/juce_HeapBlock.h"
+#include "memory/juce_MemoryBlock.h"
+#include "memory/juce_ReferenceCountedObject.h"
+#include "memory/juce_ScopedPointer.h"
+#include "memory/juce_OptionalScopedPointer.h"
+#include "memory/juce_Singleton.h"
+#include "memory/juce_WeakReference.h"
+#include "threads/juce_ScopedLock.h"
+#include "threads/juce_CriticalSection.h"
+#include "maths/juce_Range.h"
+#include "containers/juce_ElementComparator.h"
+#include "containers/juce_ArrayAllocationBase.h"
+#include "containers/juce_Array.h"
+#include "containers/juce_LinkedListPointer.h"
+#include "containers/juce_OwnedArray.h"
+#include "containers/juce_ReferenceCountedArray.h"
+#include "containers/juce_ScopedValueSetter.h"
+#include "containers/juce_SortedSet.h"
+#include "containers/juce_SparseSet.h"
+#include "containers/juce_AbstractFifo.h"
+#include "text/juce_NewLine.h"
+#include "text/juce_StringPool.h"
+#include "text/juce_Identifier.h"
+#include "text/juce_StringArray.h"
+#include "text/juce_StringPairArray.h"
+#include "text/juce_TextDiff.h"
+#include "text/juce_LocalisedStrings.h"
+#include "misc/juce_Result.h"
+#include "containers/juce_Variant.h"
+#include "containers/juce_NamedValueSet.h"
+#include "containers/juce_DynamicObject.h"
+#include "containers/juce_HashMap.h"
+#include "time/juce_RelativeTime.h"
+#include "time/juce_Time.h"
+#include "streams/juce_InputStream.h"
+#include "streams/juce_OutputStream.h"
+#include "streams/juce_BufferedInputStream.h"
+#include "streams/juce_MemoryInputStream.h"
+#include "streams/juce_MemoryOutputStream.h"
+#include "streams/juce_SubregionStream.h"
+#include "streams/juce_InputSource.h"
+#include "files/juce_File.h"
+#include "files/juce_DirectoryIterator.h"
+#include "files/juce_FileInputStream.h"
+#include "files/juce_FileOutputStream.h"
+#include "files/juce_FileSearchPath.h"
+#include "files/juce_MemoryMappedFile.h"
+#include "files/juce_TemporaryFile.h"
+#include "files/juce_FileFilter.h"
+#include "files/juce_WildcardFileFilter.h"
+#include "streams/juce_FileInputSource.h"
+#include "logging/juce_FileLogger.h"
+#include "javascript/juce_JSON.h"
+#include "javascript/juce_Javascript.h"
+#include "maths/juce_BigInteger.h"
+#include "maths/juce_Expression.h"
+#include "maths/juce_Random.h"
+#include "misc/juce_Uuid.h"
+#include "misc/juce_WindowsRegistry.h"
+#include "system/juce_PlatformDefs.h"
+#include "system/juce_SystemStats.h"
+#include "threads/juce_ChildProcess.h"
+#include "threads/juce_DynamicLibrary.h"
+#include "threads/juce_HighResolutionTimer.h"
+#include "threads/juce_InterProcessLock.h"
+#include "threads/juce_Process.h"
+#include "threads/juce_SpinLock.h"
+#include "threads/juce_WaitableEvent.h"
+#include "threads/juce_Thread.h"
+#include "threads/juce_ThreadLocalValue.h"
+#include "threads/juce_ThreadPool.h"
+#include "threads/juce_TimeSliceThread.h"
+#include "threads/juce_ReadWriteLock.h"
+#include "threads/juce_ScopedReadLock.h"
+#include "threads/juce_ScopedWriteLock.h"
+#include "network/juce_IPAddress.h"
+#include "network/juce_MACAddress.h"
+#include "network/juce_NamedPipe.h"
+#include "network/juce_Socket.h"
+#include "network/juce_URL.h"
+#include "time/juce_PerformanceCounter.h"
+#include "unit_tests/juce_UnitTest.h"
+#include "xml/juce_XmlDocument.h"
+#include "xml/juce_XmlElement.h"
+#include "zip/juce_GZIPCompressorOutputStream.h"
+#include "zip/juce_GZIPDecompressorInputStream.h"
+#include "zip/juce_ZipFile.h"
+#include "containers/juce_PropertySet.h"
+#include "memory/juce_SharedResourcePointer.h"
+
+} // namespace juce
+} // namespace htio2
+
+#if JUCE_MSVC
+ #pragma warning (pop)
+#endif
+
+#endif   // JUCE_CORE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/juce_core.mm b/src/htio2/JUCE-3.0.8/modules/juce_core/juce_core.mm
new file mode 100644
index 0000000..90a2f7c
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/juce_core.mm
@@ -0,0 +1,29 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#include "juce_core.cpp"
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/juce_module_info b/src/htio2/JUCE-3.0.8/modules/juce_core/juce_module_info
new file mode 100644
index 0000000..7fb2073
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/juce_module_info
@@ -0,0 +1,38 @@
+{
+  "id":             "juce_core",
+  "name":           "JUCE core classes",
+  "version":        "3.0.8",
+  "description":    "The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality.",
+  "website":        "http://www.juce.com/juce",
+  "license":        "ISC Permissive",
+
+  "dependencies":   [],
+
+  "include":        "juce_core.h",
+
+  "compile":        [ { "file": "juce_core.cpp", "target": "! xcode" },
+                      { "file": "juce_core.mm",  "target": "xcode" } ],
+
+  "browse":         [ "text/*",
+                      "maths/*",
+                      "memory/*",
+                      "containers/*",
+                      "threads/*",
+                      "time/*",
+                      "files/*",
+                      "network/*",
+                      "streams/*",
+                      "logging/*",
+                      "system/*",
+                      "xml/*",
+                      "javascript/*",
+                      "zip/*",
+                      "unit_tests/*",
+                      "misc/*",
+                      "native/*" ],
+
+  "OSXFrameworks":  "Cocoa IOKit",
+  "iOSFrameworks":  "Foundation",
+  "LinuxLibs":      "rt dl pthread",
+  "mingwLibs":      "uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm"
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_FileLogger.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_FileLogger.cpp
new file mode 100644
index 0000000..8cadfda
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_FileLogger.cpp
@@ -0,0 +1,134 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+FileLogger::FileLogger (const File& file,
+                        const String& welcomeMessage,
+                        const int64 maxInitialFileSizeBytes)
+    : logFile (file)
+{
+    if (maxInitialFileSizeBytes >= 0)
+        trimFileSize (maxInitialFileSizeBytes);
+
+    if (! file.exists())
+        file.create();  // (to create the parent directories)
+
+    String welcome;
+    welcome << newLine
+            << "**********************************************************" << newLine
+            << welcomeMessage << newLine
+            << "Log started: " << Time::getCurrentTime().toString (true, true) << newLine;
+
+    FileLogger::logMessage (welcome);
+}
+
+FileLogger::~FileLogger() {}
+
+//==============================================================================
+void FileLogger::logMessage (const String& message)
+{
+    const ScopedLock sl (logLock);
+    DBG (message);
+    FileOutputStream out (logFile, 256);
+    out << message << newLine;
+}
+
+void FileLogger::trimFileSize (int64 maxFileSizeBytes) const
+{
+    if (maxFileSizeBytes <= 0)
+    {
+        logFile.deleteFile();
+    }
+    else
+    {
+        const int64 fileSize = logFile.getSize();
+
+        if (fileSize > maxFileSizeBytes)
+        {
+            TemporaryFile tempFile (logFile);
+
+            {
+                FileOutputStream out (tempFile.getFile());
+                FileInputStream in (logFile);
+
+                if (! (out.openedOk() && in.openedOk()))
+                    return;
+
+                in.setPosition (fileSize - maxFileSizeBytes);
+
+                for (;;)
+                {
+                    const char c = in.readByte();
+                    if (c == 0)
+                        return;
+
+                    if (c == '\n' || c == '\r')
+                    {
+                        out << c;
+                        break;
+                    }
+                }
+
+                out.writeFromInputStream (in, -1);
+            }
+
+            tempFile.overwriteTargetFileWithTemporary();
+        }
+    }
+}
+
+//==============================================================================
+File FileLogger::getSystemLogFileFolder()
+{
+   #if JUCE_MAC
+    return File ("~/Library/Logs");
+   #else
+    return File::getSpecialLocation (File::userApplicationDataDirectory);
+   #endif
+}
+
+FileLogger* FileLogger::createDefaultAppLogger (const String& logFileSubDirectoryName,
+                                                const String& logFileName,
+                                                const String& welcomeMessage,
+                                                const int64 maxInitialFileSizeBytes)
+{
+    return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
+                                                   .getChildFile (logFileName),
+                           welcomeMessage, maxInitialFileSizeBytes);
+}
+
+FileLogger* FileLogger::createDateStampedLogger (const String& logFileSubDirectoryName,
+                                                 const String& logFileNameRoot,
+                                                 const String& logFileNameSuffix,
+                                                 const String& welcomeMessage)
+{
+    return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
+                                                   .getChildFile (logFileNameRoot + Time::getCurrentTime().formatted ("%Y-%m-%d_%H-%M-%S"))
+                                                   .withFileExtension (logFileNameSuffix)
+                                                   .getNonexistentSibling(),
+                           welcomeMessage, 0);
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_FileLogger.h b/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_FileLogger.h
new file mode 100644
index 0000000..6be1668
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_FileLogger.h
@@ -0,0 +1,135 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_FILELOGGER_H_INCLUDED
+#define JUCE_FILELOGGER_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A simple implementation of a Logger that writes to a file.
+
+    @see Logger
+*/
+class JUCE_API  FileLogger  : public Logger
+{
+public:
+    //==============================================================================
+    /** Creates a FileLogger for a given file.
+
+        @param fileToWriteTo    the file that to use - new messages will be appended
+                                to the file. If the file doesn't exist, it will be created,
+                                along with any parent directories that are needed.
+        @param welcomeMessage   when opened, the logger will write a header to the log, along
+                                with the current date and time, and this welcome message
+        @param maxInitialFileSizeBytes  if this is zero or greater, then if the file already exists
+                                but is larger than this number of bytes, then the start of the
+                                file will be truncated to keep the size down. This prevents a log
+                                file getting ridiculously large over time. The file will be truncated
+                                at a new-line boundary. If this value is less than zero, no size limit
+                                will be imposed; if it's zero, the file will always be deleted. Note that
+                                the size is only checked once when this object is created - any logging
+                                that is done later will be appended without any checking
+    */
+    FileLogger (const File& fileToWriteTo,
+                const String& welcomeMessage,
+                const int64 maxInitialFileSizeBytes = 128 * 1024);
+
+    /** Destructor. */
+    ~FileLogger();
+
+    //==============================================================================
+    /** Returns the file that this logger is writing to. */
+    const File& getLogFile() const noexcept               { return logFile; }
+
+    //==============================================================================
+    /** Helper function to create a log file in the correct place for this platform.
+
+        The method might return nullptr if the file can't be created for some reason.
+
+        @param logFileSubDirectoryName      the name of the subdirectory to create inside the logs folder (as
+                                            returned by getSystemLogFileFolder). It's best to use something
+                                            like the name of your application here.
+        @param logFileName                  the name of the file to create, e.g. "MyAppLog.txt".
+        @param welcomeMessage               a message that will be written to the log when it's opened.
+        @param maxInitialFileSizeBytes      (see the FileLogger constructor for more info on this)
+    */
+    static FileLogger* createDefaultAppLogger (const String& logFileSubDirectoryName,
+                                               const String& logFileName,
+                                               const String& welcomeMessage,
+                                               const int64 maxInitialFileSizeBytes = 128 * 1024);
+
+    /** Helper function to create a log file in the correct place for this platform.
+
+        The filename used is based on the root and suffix strings provided, along with a
+        time and date string, meaning that a new, empty log file will be always be created
+        rather than appending to an exising one.
+
+        The method might return nullptr if the file can't be created for some reason.
+
+        @param logFileSubDirectoryName      the name of the subdirectory to create inside the logs folder (as
+                                            returned by getSystemLogFileFolder). It's best to use something
+                                            like the name of your application here.
+        @param logFileNameRoot              the start of the filename to use, e.g. "MyAppLog_". This will have
+                                            a timestamp and the logFileNameSuffix appended to it
+        @param logFileNameSuffix            the file suffix to use, e.g. ".txt"
+        @param welcomeMessage               a message that will be written to the log when it's opened.
+    */
+    static FileLogger* createDateStampedLogger (const String& logFileSubDirectoryName,
+                                                const String& logFileNameRoot,
+                                                const String& logFileNameSuffix,
+                                                const String& welcomeMessage);
+
+    //==============================================================================
+    /** Returns an OS-specific folder where log-files should be stored.
+
+        On Windows this will return a logger with a path such as:
+        c:\\Documents and Settings\\username\\Application Data\\[logFileSubDirectoryName]\\[logFileName]
+
+        On the Mac it'll create something like:
+        ~/Library/Logs/[logFileSubDirectoryName]/[logFileName]
+
+        @see createDefaultAppLogger
+    */
+    static File getSystemLogFileFolder();
+
+    // (implementation of the Logger virtual method)
+    void logMessage (const String&);
+
+private:
+    //==============================================================================
+    File logFile;
+    CriticalSection logLock;
+
+    void trimFileSize (int64 maxFileSizeBytes) const;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileLogger)
+};
+
+
+#endif   // JUCE_FILELOGGER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_Logger.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_Logger.cpp
new file mode 100644
index 0000000..0b1c8d6
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_Logger.cpp
@@ -0,0 +1,63 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+Logger::Logger() {}
+
+Logger::~Logger()
+{
+    // You're deleting this logger while it's still being used!
+    // Always call Logger::setCurrentLogger (nullptr) before deleting the active logger.
+    jassert (currentLogger != this);
+}
+
+Logger* Logger::currentLogger = nullptr;
+
+void Logger::setCurrentLogger (Logger* const newLogger) noexcept    { currentLogger = newLogger; }
+Logger* Logger::getCurrentLogger()  noexcept                        { return currentLogger; }
+
+void Logger::writeToLog (const String& message)
+{
+    if (currentLogger != nullptr)
+        currentLogger->logMessage (message);
+    else
+        outputDebugString (message);
+}
+
+#if JUCE_LOG_ASSERTIONS || JUCE_DEBUG
+void JUCE_API JUCE_CALLTYPE logAssertion (const char* const filename, const int lineNum) noexcept
+{
+    String m ("JUCE Assertion failure in ");
+    m << File::createFileWithoutCheckingPath (filename).getFileName() << ':' << lineNum;
+
+   #if JUCE_LOG_ASSERTIONS
+    Logger::writeToLog (m);
+   #else
+    DBG (m);
+   #endif
+}
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_Logger.h b/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_Logger.h
new file mode 100644
index 0000000..d0d3af5
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/logging/juce_Logger.h
@@ -0,0 +1,97 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_LOGGER_H_INCLUDED
+#define JUCE_LOGGER_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Acts as an application-wide logging class.
+
+    A subclass of Logger can be created and passed into the Logger::setCurrentLogger
+    method and this will then be used by all calls to writeToLog.
+
+    The logger class also contains methods for writing messages to the debugger's
+    output stream.
+
+    @see FileLogger
+*/
+class JUCE_API  Logger
+{
+public:
+    //==============================================================================
+    /** Destructor. */
+    virtual ~Logger();
+
+    //==============================================================================
+    /** Sets the current logging class to use.
+
+        Note that the object passed in will not be owned or deleted by the logger, so
+        the caller must make sure that it is not deleted while still being used.
+        A null pointer can be passed-in to disable any logging.
+    */
+    static void JUCE_CALLTYPE setCurrentLogger (Logger* newLogger) noexcept;
+
+    /** Returns the current logger, or nullptr if none has been set. */
+    static Logger* getCurrentLogger() noexcept;
+
+    /** Writes a string to the current logger.
+
+        This will pass the string to the logger's logMessage() method if a logger
+        has been set.
+
+        @see logMessage
+    */
+    static void JUCE_CALLTYPE writeToLog (const String& message);
+
+
+    //==============================================================================
+    /** Writes a message to the standard error stream.
+
+        This can be called directly, or by using the DBG() macro in
+        juce_PlatformDefs.h (which will avoid calling the method in non-debug builds).
+    */
+    static void JUCE_CALLTYPE outputDebugString (const String& text);
+
+
+protected:
+    //==============================================================================
+    Logger();
+
+    /** This is overloaded by subclasses to implement custom logging behaviour.
+        @see setCurrentLogger
+    */
+    virtual void logMessage (const String& message) = 0;
+
+private:
+    static Logger* currentLogger;
+};
+
+
+#endif   // JUCE_LOGGER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_BigInteger.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_BigInteger.cpp
new file mode 100644
index 0000000..b1c42b6
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_BigInteger.cpp
@@ -0,0 +1,1014 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+namespace
+{
+    inline size_t bitToIndex (const int bit) noexcept   { return (size_t) (bit >> 5); }
+    inline uint32 bitToMask  (const int bit) noexcept   { return (uint32) 1 << (bit & 31); }
+}
+
+//==============================================================================
+BigInteger::BigInteger()
+    : numValues (4),
+      highestBit (-1),
+      negative (false)
+{
+    values.calloc (numValues + 1);
+}
+
+BigInteger::BigInteger (const int32 value)
+    : numValues (4),
+      highestBit (31),
+      negative (value < 0)
+{
+    values.calloc (numValues + 1);
+    values[0] = (uint32) abs (value);
+    highestBit = getHighestBit();
+}
+
+BigInteger::BigInteger (const uint32 value)
+    : numValues (4),
+      highestBit (31),
+      negative (false)
+{
+    values.calloc (numValues + 1);
+    values[0] = value;
+    highestBit = getHighestBit();
+}
+
+BigInteger::BigInteger (int64 value)
+    : numValues (4),
+      highestBit (63),
+      negative (value < 0)
+{
+    values.calloc (numValues + 1);
+
+    if (value < 0)
+        value = -value;
+
+    values[0] = (uint32) value;
+    values[1] = (uint32) (value >> 32);
+    highestBit = getHighestBit();
+}
+
+BigInteger::BigInteger (const BigInteger& other)
+    : numValues ((size_t) jmax ((size_t) 4, bitToIndex (other.highestBit) + 1)),
+      highestBit (other.getHighestBit()),
+      negative (other.negative)
+{
+    values.malloc (numValues + 1);
+    memcpy (values, other.values, sizeof (uint32) * (numValues + 1));
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+BigInteger::BigInteger (BigInteger&& other) noexcept
+    : values (static_cast <HeapBlock <uint32>&&> (other.values)),
+      numValues (other.numValues),
+      highestBit (other.highestBit),
+      negative (other.negative)
+{
+}
+
+BigInteger& BigInteger::operator= (BigInteger&& other) noexcept
+{
+    values = static_cast <HeapBlock <uint32>&&> (other.values);
+    numValues = other.numValues;
+    highestBit = other.highestBit;
+    negative = other.negative;
+    return *this;
+}
+#endif
+
+BigInteger::~BigInteger()
+{
+}
+
+void BigInteger::swapWith (BigInteger& other) noexcept
+{
+    values.swapWith (other.values);
+    std::swap (numValues, other.numValues);
+    std::swap (highestBit, other.highestBit);
+    std::swap (negative, other.negative);
+}
+
+BigInteger& BigInteger::operator= (const BigInteger& other)
+{
+    if (this != &other)
+    {
+        highestBit = other.getHighestBit();
+        jassert (other.numValues >= 4);
+        numValues = (size_t) jmax ((size_t) 4, bitToIndex (highestBit) + 1);
+        negative = other.negative;
+        values.malloc (numValues + 1);
+        memcpy (values, other.values, sizeof (uint32) * (numValues + 1));
+    }
+
+    return *this;
+}
+
+void BigInteger::ensureSize (const size_t numVals)
+{
+    if (numVals + 2 >= numValues)
+    {
+        size_t oldSize = numValues;
+        numValues = ((numVals + 2) * 3) / 2;
+        values.realloc (numValues + 1);
+
+        while (oldSize < numValues)
+            values [oldSize++] = 0;
+    }
+}
+
+//==============================================================================
+bool BigInteger::operator[] (const int bit) const noexcept
+{
+    return bit <= highestBit && bit >= 0
+             && ((values [bitToIndex (bit)] & bitToMask (bit)) != 0);
+}
+
+int BigInteger::toInteger() const noexcept
+{
+    const int n = (int) (values[0] & 0x7fffffff);
+    return negative ? -n : n;
+}
+
+int64 BigInteger::toInt64() const noexcept
+{
+    const int64 n = (((int64) (values[1] & 0x7fffffff)) << 32) | values[0];
+    return negative ? -n : n;
+}
+
+BigInteger BigInteger::getBitRange (int startBit, int numBits) const
+{
+    BigInteger r;
+    numBits = jmin (numBits, getHighestBit() + 1 - startBit);
+    r.ensureSize ((size_t) bitToIndex (numBits));
+    r.highestBit = numBits;
+
+    int i = 0;
+    while (numBits > 0)
+    {
+        r.values[i++] = getBitRangeAsInt (startBit, (int) jmin (32, numBits));
+        numBits -= 32;
+        startBit += 32;
+    }
+
+    r.highestBit = r.getHighestBit();
+    return r;
+}
+
+uint32 BigInteger::getBitRangeAsInt (const int startBit, int numBits) const noexcept
+{
+    if (numBits > 32)
+    {
+        jassertfalse;  // use getBitRange() if you need more than 32 bits..
+        numBits = 32;
+    }
+
+    numBits = jmin (numBits, highestBit + 1 - startBit);
+
+    if (numBits <= 0)
+        return 0;
+
+    const size_t pos = bitToIndex (startBit);
+    const int offset = startBit & 31;
+    const int endSpace = 32 - numBits;
+
+    uint32 n = ((uint32) values [pos]) >> offset;
+
+    if (offset > endSpace)
+        n |= ((uint32) values [pos + 1]) << (32 - offset);
+
+    return n & (((uint32) 0xffffffff) >> endSpace);
+}
+
+void BigInteger::setBitRangeAsInt (const int startBit, int numBits, uint32 valueToSet)
+{
+    if (numBits > 32)
+    {
+        jassertfalse;
+        numBits = 32;
+    }
+
+    for (int i = 0; i < numBits; ++i)
+    {
+        setBit (startBit + i, (valueToSet & 1) != 0);
+        valueToSet >>= 1;
+    }
+}
+
+//==============================================================================
+void BigInteger::clear()
+{
+    if (numValues > 16)
+    {
+        numValues = 4;
+        values.calloc (numValues + 1);
+    }
+    else
+    {
+        values.clear (numValues + 1);
+    }
+
+    highestBit = -1;
+    negative = false;
+}
+
+void BigInteger::setBit (const int bit)
+{
+    if (bit >= 0)
+    {
+        if (bit > highestBit)
+        {
+            ensureSize (bitToIndex (bit));
+            highestBit = bit;
+        }
+
+        values [bitToIndex (bit)] |= bitToMask (bit);
+    }
+}
+
+void BigInteger::setBit (const int bit, const bool shouldBeSet)
+{
+    if (shouldBeSet)
+        setBit (bit);
+    else
+        clearBit (bit);
+}
+
+void BigInteger::clearBit (const int bit) noexcept
+{
+    if (bit >= 0 && bit <= highestBit)
+        values [bitToIndex (bit)] &= ~bitToMask (bit);
+}
+
+void BigInteger::setRange (int startBit, int numBits, const bool shouldBeSet)
+{
+    while (--numBits >= 0)
+        setBit (startBit++, shouldBeSet);
+}
+
+void BigInteger::insertBit (const int bit, const bool shouldBeSet)
+{
+    if (bit >= 0)
+        shiftBits (1, bit);
+
+    setBit (bit, shouldBeSet);
+}
+
+//==============================================================================
+bool BigInteger::isZero() const noexcept
+{
+    return getHighestBit() < 0;
+}
+
+bool BigInteger::isOne() const noexcept
+{
+    return getHighestBit() == 0 && ! negative;
+}
+
+bool BigInteger::isNegative() const noexcept
+{
+    return negative && ! isZero();
+}
+
+void BigInteger::setNegative (const bool neg) noexcept
+{
+    negative = neg;
+}
+
+void BigInteger::negate() noexcept
+{
+    negative = (! negative) && ! isZero();
+}
+
+#if JUCE_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
+ #pragma intrinsic (_BitScanReverse)
+#endif
+
+inline static int highestBitInInt (uint32 n) noexcept
+{
+    jassert (n != 0); // (the built-in functions may not work for n = 0)
+
+  #if JUCE_GCC
+    return 31 - __builtin_clz (n);
+  #elif JUCE_USE_INTRINSICS
+    unsigned long highest;
+    _BitScanReverse (&highest, n);
+    return (int) highest;
+  #else
+    n |= (n >> 1);
+    n |= (n >> 2);
+    n |= (n >> 4);
+    n |= (n >> 8);
+    n |= (n >> 16);
+    return countBitsInInt32 (n >> 1);
+  #endif
+}
+
+int BigInteger::countNumberOfSetBits() const noexcept
+{
+    int total = 0;
+
+    for (int i = (int) bitToIndex (highestBit) + 1; --i >= 0;)
+        total += countNumberOfBits (values[i]);
+
+    return total;
+}
+
+int BigInteger::getHighestBit() const noexcept
+{
+    for (int i = (int) bitToIndex (highestBit + 1); i >= 0; --i)
+    {
+        const uint32 n = values[i];
+
+        if (n != 0)
+            return highestBitInInt (n) + (i << 5);
+    }
+
+    return -1;
+}
+
+int BigInteger::findNextSetBit (int i) const noexcept
+{
+    for (; i <= highestBit; ++i)
+        if ((values [bitToIndex (i)] & bitToMask (i)) != 0)
+            return i;
+
+    return -1;
+}
+
+int BigInteger::findNextClearBit (int i) const noexcept
+{
+    for (; i <= highestBit; ++i)
+        if ((values [bitToIndex (i)] & bitToMask (i)) == 0)
+            break;
+
+    return i;
+}
+
+//==============================================================================
+BigInteger& BigInteger::operator+= (const BigInteger& other)
+{
+    if (other.isNegative())
+        return operator-= (-other);
+
+    if (isNegative())
+    {
+        if (compareAbsolute (other) < 0)
+        {
+            BigInteger temp (*this);
+            temp.negate();
+            *this = other;
+            operator-= (temp);
+        }
+        else
+        {
+            negate();
+            operator-= (other);
+            negate();
+        }
+    }
+    else
+    {
+        if (other.highestBit > highestBit)
+            highestBit = other.highestBit;
+
+        ++highestBit;
+
+        const size_t numInts = bitToIndex (highestBit) + 1;
+        ensureSize (numInts);
+
+        int64 remainder = 0;
+
+        for (size_t i = 0; i <= numInts; ++i)
+        {
+            if (i < numValues)
+                remainder += values[i];
+
+            if (i < other.numValues)
+                remainder += other.values[i];
+
+            values[i] = (uint32) remainder;
+            remainder >>= 32;
+        }
+
+        jassert (remainder == 0);
+        highestBit = getHighestBit();
+    }
+
+    return *this;
+}
+
+BigInteger& BigInteger::operator-= (const BigInteger& other)
+{
+    if (other.isNegative())
+        return operator+= (-other);
+
+    if (! isNegative())
+    {
+        if (compareAbsolute (other) < 0)
+        {
+            BigInteger temp (other);
+            swapWith (temp);
+            operator-= (temp);
+            negate();
+            return *this;
+        }
+    }
+    else
+    {
+        negate();
+        operator+= (other);
+        negate();
+        return *this;
+    }
+
+    const size_t numInts = bitToIndex (highestBit) + 1;
+    const size_t maxOtherInts = bitToIndex (other.highestBit) + 1;
+    int64 amountToSubtract = 0;
+
+    for (size_t i = 0; i <= numInts; ++i)
+    {
+        if (i <= maxOtherInts)
+            amountToSubtract += (int64) other.values[i];
+
+        if (values[i] >= amountToSubtract)
+        {
+            values[i] = (uint32) (values[i] - amountToSubtract);
+            amountToSubtract = 0;
+        }
+        else
+        {
+            const int64 n = ((int64) values[i] + (((int64) 1) << 32)) - amountToSubtract;
+            values[i] = (uint32) n;
+            amountToSubtract = 1;
+        }
+    }
+
+    return *this;
+}
+
+BigInteger& BigInteger::operator*= (const BigInteger& other)
+{
+    BigInteger total;
+    highestBit = getHighestBit();
+    const bool wasNegative = isNegative();
+    setNegative (false);
+
+    for (int i = 0; i <= highestBit; ++i)
+    {
+        if (operator[](i))
+        {
+            BigInteger n (other);
+            n.setNegative (false);
+            n <<= i;
+            total += n;
+        }
+    }
+
+    total.setNegative (wasNegative ^ other.isNegative());
+    swapWith (total);
+    return *this;
+}
+
+void BigInteger::divideBy (const BigInteger& divisor, BigInteger& remainder)
+{
+    jassert (this != &remainder); // (can't handle passing itself in to get the remainder)
+
+    const int divHB = divisor.getHighestBit();
+    const int ourHB = getHighestBit();
+
+    if (divHB < 0 || ourHB < 0)
+    {
+        // division by zero
+        remainder.clear();
+        clear();
+    }
+    else
+    {
+        const bool wasNegative = isNegative();
+
+        swapWith (remainder);
+        remainder.setNegative (false);
+        clear();
+
+        BigInteger temp (divisor);
+        temp.setNegative (false);
+
+        int leftShift = ourHB - divHB;
+        temp <<= leftShift;
+
+        while (leftShift >= 0)
+        {
+            if (remainder.compareAbsolute (temp) >= 0)
+            {
+                remainder -= temp;
+                setBit (leftShift);
+            }
+
+            if (--leftShift >= 0)
+                temp >>= 1;
+        }
+
+        negative = wasNegative ^ divisor.isNegative();
+        remainder.setNegative (wasNegative);
+    }
+}
+
+BigInteger& BigInteger::operator/= (const BigInteger& other)
+{
+    BigInteger remainder;
+    divideBy (other, remainder);
+    return *this;
+}
+
+BigInteger& BigInteger::operator|= (const BigInteger& other)
+{
+    // this operation doesn't take into account negative values..
+    jassert (isNegative() == other.isNegative());
+
+    if (other.highestBit >= 0)
+    {
+        ensureSize (bitToIndex (other.highestBit));
+
+        int n = (int) bitToIndex (other.highestBit) + 1;
+
+        while (--n >= 0)
+            values[n] |= other.values[n];
+
+        if (other.highestBit > highestBit)
+            highestBit = other.highestBit;
+
+        highestBit = getHighestBit();
+    }
+
+    return *this;
+}
+
+BigInteger& BigInteger::operator&= (const BigInteger& other)
+{
+    // this operation doesn't take into account negative values..
+    jassert (isNegative() == other.isNegative());
+
+    int n = (int) numValues;
+
+    while (n > (int) other.numValues)
+        values[--n] = 0;
+
+    while (--n >= 0)
+        values[n] &= other.values[n];
+
+    if (other.highestBit < highestBit)
+        highestBit = other.highestBit;
+
+    highestBit = getHighestBit();
+    return *this;
+}
+
+BigInteger& BigInteger::operator^= (const BigInteger& other)
+{
+    // this operation will only work with the absolute values
+    jassert (isNegative() == other.isNegative());
+
+    if (other.highestBit >= 0)
+    {
+        ensureSize (bitToIndex (other.highestBit));
+
+        int n = (int) bitToIndex (other.highestBit) + 1;
+
+        while (--n >= 0)
+            values[n] ^= other.values[n];
+
+        if (other.highestBit > highestBit)
+            highestBit = other.highestBit;
+
+        highestBit = getHighestBit();
+    }
+
+    return *this;
+}
+
+BigInteger& BigInteger::operator%= (const BigInteger& divisor)
+{
+    BigInteger remainder;
+    divideBy (divisor, remainder);
+    swapWith (remainder);
+    return *this;
+}
+
+BigInteger& BigInteger::operator++()      { return operator+= (1); }
+BigInteger& BigInteger::operator--()      { return operator-= (1); }
+BigInteger  BigInteger::operator++ (int)  { const BigInteger old (*this); operator+= (1); return old; }
+BigInteger  BigInteger::operator-- (int)  { const BigInteger old (*this); operator-= (1); return old; }
+
+BigInteger  BigInteger::operator-() const                            { BigInteger b (*this); b.negate(); return b; }
+BigInteger  BigInteger::operator+   (const BigInteger& other) const  { BigInteger b (*this); return b += other; }
+BigInteger  BigInteger::operator-   (const BigInteger& other) const  { BigInteger b (*this); return b -= other; }
+BigInteger  BigInteger::operator*   (const BigInteger& other) const  { BigInteger b (*this); return b *= other; }
+BigInteger  BigInteger::operator/   (const BigInteger& other) const  { BigInteger b (*this); return b /= other; }
+BigInteger  BigInteger::operator|   (const BigInteger& other) const  { BigInteger b (*this); return b |= other; }
+BigInteger  BigInteger::operator&   (const BigInteger& other) const  { BigInteger b (*this); return b &= other; }
+BigInteger  BigInteger::operator^   (const BigInteger& other) const  { BigInteger b (*this); return b ^= other; }
+BigInteger  BigInteger::operator%   (const BigInteger& other) const  { BigInteger b (*this); return b %= other; }
+BigInteger  BigInteger::operator<<  (const int numBits) const        { BigInteger b (*this); return b <<= numBits; }
+BigInteger  BigInteger::operator>>  (const int numBits) const        { BigInteger b (*this); return b >>= numBits; }
+BigInteger& BigInteger::operator<<= (const int numBits)              { shiftBits (numBits, 0);  return *this; }
+BigInteger& BigInteger::operator>>= (const int numBits)              { shiftBits (-numBits, 0); return *this; }
+
+//==============================================================================
+int BigInteger::compare (const BigInteger& other) const noexcept
+{
+    if (isNegative() == other.isNegative())
+    {
+        const int absComp = compareAbsolute (other);
+        return isNegative() ? -absComp : absComp;
+    }
+    else
+    {
+        return isNegative() ? -1 : 1;
+    }
+}
+
+int BigInteger::compareAbsolute (const BigInteger& other) const noexcept
+{
+    const int h1 = getHighestBit();
+    const int h2 = other.getHighestBit();
+
+    if (h1 > h2)
+        return 1;
+    else if (h1 < h2)
+        return -1;
+
+    for (int i = (int) bitToIndex (h1) + 1; --i >= 0;)
+        if (values[i] != other.values[i])
+            return (values[i] > other.values[i]) ? 1 : -1;
+
+    return 0;
+}
+
+bool BigInteger::operator== (const BigInteger& other) const noexcept    { return compare (other) == 0; }
+bool BigInteger::operator!= (const BigInteger& other) const noexcept    { return compare (other) != 0; }
+bool BigInteger::operator<  (const BigInteger& other) const noexcept    { return compare (other) < 0; }
+bool BigInteger::operator<= (const BigInteger& other) const noexcept    { return compare (other) <= 0; }
+bool BigInteger::operator>  (const BigInteger& other) const noexcept    { return compare (other) > 0; }
+bool BigInteger::operator>= (const BigInteger& other) const noexcept    { return compare (other) >= 0; }
+
+//==============================================================================
+void BigInteger::shiftLeft (int bits, const int startBit)
+{
+    if (startBit > 0)
+    {
+        for (int i = highestBit + 1; --i >= startBit;)
+            setBit (i + bits, operator[] (i));
+
+        while (--bits >= 0)
+            clearBit (bits + startBit);
+    }
+    else
+    {
+        ensureSize (bitToIndex (highestBit + bits) + 1);
+
+        const size_t wordsToMove = bitToIndex (bits);
+        size_t top = 1 + bitToIndex (highestBit);
+        highestBit += bits;
+
+        if (wordsToMove > 0)
+        {
+            for (int i = (int) top; --i >= 0;)
+                values [(size_t) i + wordsToMove] = values [i];
+
+            for (size_t j = 0; j < wordsToMove; ++j)
+                values [j] = 0;
+
+            bits &= 31;
+        }
+
+        if (bits != 0)
+        {
+            const int invBits = 32 - bits;
+
+            for (size_t i = top + 1 + wordsToMove; --i > wordsToMove;)
+                values[i] = (values[i] << bits) | (values [i - 1] >> invBits);
+
+            values [wordsToMove] = values [wordsToMove] << bits;
+        }
+
+        highestBit = getHighestBit();
+    }
+}
+
+void BigInteger::shiftRight (int bits, const int startBit)
+{
+    if (startBit > 0)
+    {
+        for (int i = startBit; i <= highestBit; ++i)
+            setBit (i, operator[] (i + bits));
+
+        highestBit = getHighestBit();
+    }
+    else
+    {
+        if (bits > highestBit)
+        {
+            clear();
+        }
+        else
+        {
+            const size_t wordsToMove = bitToIndex (bits);
+            size_t top = 1 + bitToIndex (highestBit) - wordsToMove;
+            highestBit -= bits;
+
+            if (wordsToMove > 0)
+            {
+                size_t i;
+                for (i = 0; i < top; ++i)
+                    values [i] = values [i + wordsToMove];
+
+                for (i = 0; i < wordsToMove; ++i)
+                    values [top + i] = 0;
+
+                bits &= 31;
+            }
+
+            if (bits != 0)
+            {
+                const int invBits = 32 - bits;
+
+                --top;
+                for (size_t i = 0; i < top; ++i)
+                    values[i] = (values[i] >> bits) | (values [i + 1] << invBits);
+
+                values[top] = (values[top] >> bits);
+            }
+
+            highestBit = getHighestBit();
+        }
+    }
+}
+
+void BigInteger::shiftBits (int bits, const int startBit)
+{
+    if (highestBit >= 0)
+    {
+        if (bits < 0)
+            shiftRight (-bits, startBit);
+        else if (bits > 0)
+            shiftLeft (bits, startBit);
+    }
+}
+
+//==============================================================================
+static BigInteger simpleGCD (BigInteger* m, BigInteger* n)
+{
+    while (! m->isZero())
+    {
+        if (n->compareAbsolute (*m) > 0)
+            std::swap (m, n);
+
+        *m -= *n;
+    }
+
+    return *n;
+}
+
+BigInteger BigInteger::findGreatestCommonDivisor (BigInteger n) const
+{
+    BigInteger m (*this);
+
+    while (! n.isZero())
+    {
+        if (abs (m.getHighestBit() - n.getHighestBit()) <= 16)
+            return simpleGCD (&m, &n);
+
+        BigInteger temp2;
+        m.divideBy (n, temp2);
+
+        m.swapWith (n);
+        n.swapWith (temp2);
+    }
+
+    return m;
+}
+
+void BigInteger::exponentModulo (const BigInteger& exponent, const BigInteger& modulus)
+{
+    BigInteger exp (exponent);
+    exp %= modulus;
+
+    BigInteger value (1);
+    swapWith (value);
+    value %= modulus;
+
+    while (! exp.isZero())
+    {
+        if (exp [0])
+        {
+            operator*= (value);
+            operator%= (modulus);
+        }
+
+        value *= value;
+        value %= modulus;
+        exp >>= 1;
+    }
+}
+
+void BigInteger::inverseModulo (const BigInteger& modulus)
+{
+    if (modulus.isOne() || modulus.isNegative())
+    {
+        clear();
+        return;
+    }
+
+    if (isNegative() || compareAbsolute (modulus) >= 0)
+        operator%= (modulus);
+
+    if (isOne())
+        return;
+
+    if (! (*this)[0])
+    {
+        // not invertible
+        clear();
+        return;
+    }
+
+    BigInteger a1 (modulus);
+    BigInteger a2 (*this);
+    BigInteger b1 (modulus);
+    BigInteger b2 (1);
+
+    while (! a2.isOne())
+    {
+        BigInteger temp1, multiplier (a1);
+        multiplier.divideBy (a2, temp1);
+
+        temp1 = a2;
+        temp1 *= multiplier;
+        BigInteger temp2 (a1);
+        temp2 -= temp1;
+        a1 = a2;
+        a2 = temp2;
+
+        temp1 = b2;
+        temp1 *= multiplier;
+        temp2 = b1;
+        temp2 -= temp1;
+        b1 = b2;
+        b2 = temp2;
+    }
+
+    while (b2.isNegative())
+        b2 += modulus;
+
+    b2 %= modulus;
+    swapWith (b2);
+}
+
+//==============================================================================
+OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const BigInteger& value)
+{
+    return stream << value.toString (10);
+}
+
+String BigInteger::toString (const int base, const int minimumNumCharacters) const
+{
+    String s;
+    BigInteger v (*this);
+
+    if (base == 2 || base == 8 || base == 16)
+    {
+        const int bits = (base == 2) ? 1 : (base == 8 ? 3 : 4);
+        static const char hexDigits[] = "0123456789abcdef";
+
+        for (;;)
+        {
+            const uint32 remainder = v.getBitRangeAsInt (0, bits);
+
+            v >>= bits;
+
+            if (remainder == 0 && v.isZero())
+                break;
+
+            s = String::charToString ((juce_wchar) (uint8) hexDigits [remainder]) + s;
+        }
+    }
+    else if (base == 10)
+    {
+        const BigInteger ten (10);
+        BigInteger remainder;
+
+        for (;;)
+        {
+            v.divideBy (ten, remainder);
+
+            if (remainder.isZero() && v.isZero())
+                break;
+
+            s = String (remainder.getBitRangeAsInt (0, 8)) + s;
+        }
+    }
+    else
+    {
+        jassertfalse; // can't do the specified base!
+        return String();
+    }
+
+    s = s.paddedLeft ('0', minimumNumCharacters);
+
+    return isNegative() ? "-" + s : s;
+}
+
+void BigInteger::parseString (StringRef text, const int base)
+{
+    clear();
+    String::CharPointerType t (text.text.findEndOfWhitespace());
+
+    setNegative (*t == (juce_wchar) '-');
+
+    if (base == 2 || base == 8 || base == 16)
+    {
+        const int bits = (base == 2) ? 1 : (base == 8 ? 3 : 4);
+
+        for (;;)
+        {
+            const juce_wchar c = t.getAndAdvance();
+            const int digit = CharacterFunctions::getHexDigitValue (c);
+
+            if (((uint32) digit) < (uint32) base)
+            {
+                operator<<= (bits);
+                operator+= (digit);
+            }
+            else if (c == 0)
+            {
+                break;
+            }
+        }
+    }
+    else if (base == 10)
+    {
+        const BigInteger ten ((uint32) 10);
+
+        for (;;)
+        {
+            const juce_wchar c = t.getAndAdvance();
+
+            if (c >= '0' && c <= '9')
+            {
+                operator*= (ten);
+                operator+= ((int) (c - '0'));
+            }
+            else if (c == 0)
+            {
+                break;
+            }
+        }
+    }
+}
+
+MemoryBlock BigInteger::toMemoryBlock() const
+{
+    const int numBytes = (getHighestBit() + 8) >> 3;
+    MemoryBlock mb ((size_t) numBytes);
+
+    for (int i = 0; i < numBytes; ++i)
+        mb[i] = (char) getBitRangeAsInt (i << 3, 8);
+
+    return mb;
+}
+
+void BigInteger::loadFromMemoryBlock (const MemoryBlock& data)
+{
+    clear();
+
+    for (int i = (int) data.getSize(); --i >= 0;)
+        this->setBitRangeAsInt (i << 3, 8, (uint32) data [i]);
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_BigInteger.h b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_BigInteger.h
new file mode 100644
index 0000000..4c6c25c
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_BigInteger.h
@@ -0,0 +1,334 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_BIGINTEGER_H_INCLUDED
+#define JUCE_BIGINTEGER_H_INCLUDED
+
+
+//==============================================================================
+/**
+    An arbitrarily large integer class.
+
+    A BigInteger can be used in a similar way to a normal integer, but has no size
+    limit (except for memory and performance constraints).
+
+    Negative values are possible, but the value isn't stored as 2s-complement, so
+    be careful if you use negative values and look at the values of individual bits.
+*/
+class JUCE_API  BigInteger
+{
+public:
+    //==============================================================================
+    /** Creates an empty BigInteger */
+    BigInteger();
+
+    /** Creates a BigInteger containing an integer value in its low bits.
+        The low 32 bits of the number are initialised with this value.
+    */
+    BigInteger (uint32 value);
+
+    /** Creates a BigInteger containing an integer value in its low bits.
+        The low 32 bits of the number are initialised with the absolute value
+        passed in, and its sign is set to reflect the sign of the number.
+    */
+    BigInteger (int32 value);
+
+    /** Creates a BigInteger containing an integer value in its low bits.
+        The low 64 bits of the number are initialised with the absolute value
+        passed in, and its sign is set to reflect the sign of the number.
+    */
+    BigInteger (int64 value);
+
+    /** Creates a copy of another BigInteger. */
+    BigInteger (const BigInteger&);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    BigInteger (BigInteger&&) noexcept;
+    BigInteger& operator= (BigInteger&&) noexcept;
+   #endif
+
+    /** Destructor. */
+    ~BigInteger();
+
+    //==============================================================================
+    /** Copies another BigInteger onto this one. */
+    BigInteger& operator= (const BigInteger&);
+
+    /** Swaps the internal contents of this with another object. */
+    void swapWith (BigInteger&) noexcept;
+
+    //==============================================================================
+    /** Returns the value of a specified bit in the number.
+        If the index is out-of-range, the result will be false.
+    */
+    bool operator[] (int bit) const noexcept;
+
+    /** Returns true if no bits are set. */
+    bool isZero() const noexcept;
+
+    /** Returns true if the value is 1. */
+    bool isOne() const noexcept;
+
+    /** Attempts to get the lowest 32 bits of the value as an integer.
+        If the value is bigger than the integer limits, this will return only the lower bits.
+    */
+    int toInteger() const noexcept;
+
+    /** Attempts to get the lowest 64 bits of the value as an integer.
+        If the value is bigger than the integer limits, this will return only the lower bits.
+    */
+    int64 toInt64() const noexcept;
+
+    //==============================================================================
+    /** Resets the value to 0. */
+    void clear();
+
+    /** Clears a particular bit in the number. */
+    void clearBit (int bitNumber) noexcept;
+
+    /** Sets a specified bit to 1. */
+    void setBit (int bitNumber);
+
+    /** Sets or clears a specified bit. */
+    void setBit (int bitNumber, bool shouldBeSet);
+
+    /** Sets a range of bits to be either on or off.
+
+        @param startBit     the first bit to change
+        @param numBits      the number of bits to change
+        @param shouldBeSet  whether to turn these bits on or off
+    */
+    void setRange (int startBit, int numBits, bool shouldBeSet);
+
+    /** Inserts a bit an a given position, shifting up any bits above it. */
+    void insertBit (int bitNumber, bool shouldBeSet);
+
+    /** Returns a range of bits as a new BigInteger.
+
+        e.g. getBitRangeAsInt (0, 64) would return the lowest 64 bits.
+        @see getBitRangeAsInt
+    */
+    BigInteger getBitRange (int startBit, int numBits) const;
+
+    /** Returns a range of bits as an integer value.
+
+        e.g. getBitRangeAsInt (0, 32) would return the lowest 32 bits.
+
+        Asking for more than 32 bits isn't allowed (obviously) - for that, use
+        getBitRange().
+    */
+    uint32 getBitRangeAsInt (int startBit, int numBits) const noexcept;
+
+    /** Sets a range of bits to an integer value.
+
+        Copies the given integer onto a range of bits, starting at startBit,
+        and using up to numBits of the available bits.
+    */
+    void setBitRangeAsInt (int startBit, int numBits, uint32 valueToSet);
+
+    /** Shifts a section of bits left or right.
+
+        @param howManyBitsLeft  how far to move the bits (+ve numbers shift it left, -ve numbers shift it right).
+        @param startBit         the first bit to affect - if this is > 0, only bits above that index will be affected.
+    */
+    void shiftBits (int howManyBitsLeft, int startBit);
+
+    /** Returns the total number of set bits in the value. */
+    int countNumberOfSetBits() const noexcept;
+
+    /** Looks for the index of the next set bit after a given starting point.
+
+        This searches from startIndex (inclusive) upwards for the first set bit,
+        and returns its index. If no set bits are found, it returns -1.
+    */
+    int findNextSetBit (int startIndex) const noexcept;
+
+    /** Looks for the index of the next clear bit after a given starting point.
+
+        This searches from startIndex (inclusive) upwards for the first clear bit,
+        and returns its index.
+    */
+    int findNextClearBit (int startIndex) const noexcept;
+
+    /** Returns the index of the highest set bit in the number.
+        If the value is zero, this will return -1.
+    */
+    int getHighestBit() const noexcept;
+
+    //==============================================================================
+    // All the standard arithmetic ops...
+
+    BigInteger& operator+= (const BigInteger&);
+    BigInteger& operator-= (const BigInteger&);
+    BigInteger& operator*= (const BigInteger&);
+    BigInteger& operator/= (const BigInteger&);
+    BigInteger& operator|= (const BigInteger&);
+    BigInteger& operator&= (const BigInteger&);
+    BigInteger& operator^= (const BigInteger&);
+    BigInteger& operator%= (const BigInteger&);
+    BigInteger& operator<<= (int numBitsToShift);
+    BigInteger& operator>>= (int numBitsToShift);
+    BigInteger& operator++();
+    BigInteger& operator--();
+    BigInteger operator++ (int);
+    BigInteger operator-- (int);
+
+    BigInteger operator-() const;
+    BigInteger operator+ (const BigInteger&) const;
+    BigInteger operator- (const BigInteger&) const;
+    BigInteger operator* (const BigInteger&) const;
+    BigInteger operator/ (const BigInteger&) const;
+    BigInteger operator| (const BigInteger&) const;
+    BigInteger operator& (const BigInteger&) const;
+    BigInteger operator^ (const BigInteger&) const;
+    BigInteger operator% (const BigInteger&) const;
+    BigInteger operator<< (int numBitsToShift) const;
+    BigInteger operator>> (int numBitsToShift) const;
+
+    bool operator== (const BigInteger&) const noexcept;
+    bool operator!= (const BigInteger&) const noexcept;
+    bool operator<  (const BigInteger&) const noexcept;
+    bool operator<= (const BigInteger&) const noexcept;
+    bool operator>  (const BigInteger&) const noexcept;
+    bool operator>= (const BigInteger&) const noexcept;
+
+    //==============================================================================
+    /** Does a signed comparison of two BigIntegers.
+
+        Return values are:
+            - 0 if the numbers are the same
+            - < 0 if this number is smaller than the other
+            - > 0 if this number is bigger than the other
+    */
+    int compare (const BigInteger& other) const noexcept;
+
+    /** Compares the magnitudes of two BigIntegers, ignoring their signs.
+
+        Return values are:
+            - 0 if the numbers are the same
+            - < 0 if this number is smaller than the other
+            - > 0 if this number is bigger than the other
+    */
+    int compareAbsolute (const BigInteger& other) const noexcept;
+
+    /** Divides this value by another one and returns the remainder.
+
+        This number is divided by other, leaving the quotient in this number,
+        with the remainder being copied to the other BigInteger passed in.
+    */
+    void divideBy (const BigInteger& divisor, BigInteger& remainder);
+
+    /** Returns the largest value that will divide both this value and the one passed-in. */
+    BigInteger findGreatestCommonDivisor (BigInteger other) const;
+
+    /** Performs a combined exponent and modulo operation.
+        This BigInteger's value becomes (this ^ exponent) % modulus.
+    */
+    void exponentModulo (const BigInteger& exponent, const BigInteger& modulus);
+
+    /** Performs an inverse modulo on the value.
+        i.e. the result is (this ^ -1) mod (modulus).
+    */
+    void inverseModulo (const BigInteger& modulus);
+
+    //==============================================================================
+    /** Returns true if the value is less than zero.
+        @see setNegative, negate
+    */
+    bool isNegative() const noexcept;
+
+    /** Changes the sign of the number to be positive or negative.
+        @see isNegative, negate
+    */
+    void setNegative (bool shouldBeNegative) noexcept;
+
+    /** Inverts the sign of the number.
+        @see isNegative, setNegative
+    */
+    void negate() noexcept;
+
+    //==============================================================================
+    /** Converts the number to a string.
+
+        Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
+        If minimumNumCharacters is greater than 0, the returned string will be
+        padded with leading zeros to reach at least that length.
+    */
+    String toString (int base, int minimumNumCharacters = 1) const;
+
+    /** Reads the numeric value from a string.
+
+        Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
+        Any invalid characters will be ignored.
+    */
+    void parseString (StringRef text, int base);
+
+    //==============================================================================
+    /** Turns the number into a block of binary data.
+
+        The data is arranged as little-endian, so the first byte of data is the low 8 bits
+        of the number, and so on.
+
+        @see loadFromMemoryBlock
+    */
+    MemoryBlock toMemoryBlock() const;
+
+    /** Converts a block of raw data into a number.
+
+        The data is arranged as little-endian, so the first byte of data is the low 8 bits
+        of the number, and so on.
+
+        @see toMemoryBlock
+    */
+    void loadFromMemoryBlock (const MemoryBlock& data);
+
+private:
+    //==============================================================================
+    HeapBlock<uint32> values;
+    size_t numValues;
+    int highestBit;
+    bool negative;
+
+    void ensureSize (size_t);
+    void shiftLeft (int bits, int startBit);
+    void shiftRight (int bits, int startBit);
+
+    JUCE_LEAK_DETECTOR (BigInteger)
+};
+
+/** Writes a BigInteger to an OutputStream as a UTF8 decimal string. */
+OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const BigInteger& value);
+
+//==============================================================================
+#ifndef DOXYGEN
+ // For backwards compatibility, BitArray is defined as an alias for BigInteger.
+ typedef BigInteger BitArray;
+#endif
+
+
+#endif   // JUCE_BIGINTEGER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Expression.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Expression.cpp
new file mode 100644
index 0000000..a18effa
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Expression.cpp
@@ -0,0 +1,1183 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+class Expression::Term  : public SingleThreadedReferenceCountedObject
+{
+public:
+    Term() {}
+    virtual ~Term() {}
+
+    virtual Type getType() const noexcept = 0;
+    virtual Term* clone() const = 0;
+    virtual ReferenceCountedObjectPtr<Term> resolve (const Scope&, int recursionDepth) = 0;
+    virtual String toString() const = 0;
+    virtual double toDouble() const                                          { return 0; }
+    virtual int getInputIndexFor (const Term*) const                         { return -1; }
+    virtual int getOperatorPrecedence() const                                { return 0; }
+    virtual int getNumInputs() const                                         { return 0; }
+    virtual Term* getInput (int) const                                       { return nullptr; }
+    virtual ReferenceCountedObjectPtr<Term> negated();
+
+    virtual ReferenceCountedObjectPtr<Term> createTermToEvaluateInput (const Scope&, const Term* /*inputTerm*/,
+                                                                       double /*overallTarget*/, Term* /*topLevelTerm*/) const
+    {
+        jassertfalse;
+        return ReferenceCountedObjectPtr<Term>();
+    }
+
+    virtual String getName() const
+    {
+        jassertfalse; // You shouldn't call this for an expression that's not actually a function!
+        return String();
+    }
+
+    virtual void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
+    {
+        for (int i = getNumInputs(); --i >= 0;)
+            getInput (i)->renameSymbol (oldSymbol, newName, scope, recursionDepth);
+    }
+
+    class SymbolVisitor
+    {
+    public:
+        virtual ~SymbolVisitor() {}
+        virtual void useSymbol (const Symbol&) = 0;
+    };
+
+    virtual void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
+    {
+        for (int i = getNumInputs(); --i >= 0;)
+            getInput(i)->visitAllSymbols (visitor, scope, recursionDepth);
+    }
+
+private:
+    JUCE_DECLARE_NON_COPYABLE (Term)
+};
+
+
+//==============================================================================
+struct Expression::Helpers
+{
+    typedef ReferenceCountedObjectPtr<Term> TermPtr;
+
+    static void checkRecursionDepth (const int depth)
+    {
+        if (depth > 256)
+            throw EvaluationError ("Recursive symbol references");
+    }
+
+    friend class Expression::Term;
+
+    //==============================================================================
+    /** An exception that can be thrown by Expression::evaluate(). */
+    class EvaluationError  : public std::exception
+    {
+    public:
+        EvaluationError (const String& desc)  : description (desc)
+        {
+            DBG ("Expression::EvaluationError: " + description);
+        }
+
+        String description;
+    };
+
+    //==============================================================================
+    class Constant  : public Term
+    {
+    public:
+        Constant (const double val, const bool resolutionTarget)
+            : value (val), isResolutionTarget (resolutionTarget) {}
+
+        Type getType() const noexcept                { return constantType; }
+        Term* clone() const                          { return new Constant (value, isResolutionTarget); }
+        TermPtr resolve (const Scope&, int)          { return this; }
+        double toDouble() const                      { return value; }
+        TermPtr negated()                            { return new Constant (-value, isResolutionTarget); }
+
+        String toString() const
+        {
+            String s (value);
+            if (isResolutionTarget)
+                s = "@" + s;
+
+            return s;
+        }
+
+        double value;
+        bool isResolutionTarget;
+    };
+
+    //==============================================================================
+    class BinaryTerm  : public Term
+    {
+    public:
+        BinaryTerm (Term* const l, Term* const r) : left (l), right (r)
+        {
+            jassert (l != nullptr && r != nullptr);
+        }
+
+        int getInputIndexFor (const Term* possibleInput) const
+        {
+            return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1);
+        }
+
+        Type getType() const noexcept       { return operatorType; }
+        int getNumInputs() const            { return 2; }
+        Term* getInput (int index) const    { return index == 0 ? left.get() : (index == 1 ? right.get() : 0); }
+
+        virtual double performFunction (double left, double right) const = 0;
+        virtual void writeOperator (String& dest) const = 0;
+
+        TermPtr resolve (const Scope& scope, int recursionDepth)
+        {
+            return new Constant (performFunction (left ->resolve (scope, recursionDepth)->toDouble(),
+                                                  right->resolve (scope, recursionDepth)->toDouble()), false);
+        }
+
+        String toString() const
+        {
+            String s;
+
+            const int ourPrecendence = getOperatorPrecedence();
+            if (left->getOperatorPrecedence() > ourPrecendence)
+                s << '(' << left->toString() << ')';
+            else
+                s = left->toString();
+
+            writeOperator (s);
+
+            if (right->getOperatorPrecedence() >= ourPrecendence)
+                s << '(' << right->toString() << ')';
+            else
+                s << right->toString();
+
+            return s;
+        }
+
+    protected:
+        const TermPtr left, right;
+
+        TermPtr createDestinationTerm (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
+        {
+            jassert (input == left || input == right);
+            if (input != left && input != right)
+                return TermPtr();
+
+            if (const Term* const dest = findDestinationFor (topLevelTerm, this))
+                return dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm);
+
+            return new Constant (overallTarget, false);
+        }
+    };
+
+    //==============================================================================
+    class SymbolTerm  : public Term
+    {
+    public:
+        explicit SymbolTerm (const String& sym) : symbol (sym) {}
+
+        TermPtr resolve (const Scope& scope, int recursionDepth)
+        {
+            checkRecursionDepth (recursionDepth);
+            return scope.getSymbolValue (symbol).term->resolve (scope, recursionDepth + 1);
+        }
+
+        Type getType() const noexcept   { return symbolType; }
+        Term* clone() const             { return new SymbolTerm (symbol); }
+        String toString() const         { return symbol; }
+        String getName() const          { return symbol; }
+
+        void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
+        {
+            checkRecursionDepth (recursionDepth);
+            visitor.useSymbol (Symbol (scope.getScopeUID(), symbol));
+            scope.getSymbolValue (symbol).term->visitAllSymbols (visitor, scope, recursionDepth + 1);
+        }
+
+        void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int /*recursionDepth*/)
+        {
+            if (oldSymbol.symbolName == symbol && scope.getScopeUID() == oldSymbol.scopeUID)
+                symbol = newName;
+        }
+
+        String symbol;
+    };
+
+    //==============================================================================
+    class Function  : public Term
+    {
+    public:
+        explicit Function (const String& name)  : functionName (name) {}
+
+        Function (const String& name, const Array<Expression>& params)
+            : functionName (name), parameters (params)
+        {}
+
+        Type getType() const noexcept   { return functionType; }
+        Term* clone() const             { return new Function (functionName, parameters); }
+        int getNumInputs() const        { return parameters.size(); }
+        Term* getInput (int i) const    { return parameters.getReference(i).term; }
+        String getName() const          { return functionName; }
+
+        TermPtr resolve (const Scope& scope, int recursionDepth)
+        {
+            checkRecursionDepth (recursionDepth);
+            double result = 0;
+            const int numParams = parameters.size();
+            if (numParams > 0)
+            {
+                HeapBlock<double> params ((size_t) numParams);
+                for (int i = 0; i < numParams; ++i)
+                    params[i] = parameters.getReference(i).term->resolve (scope, recursionDepth + 1)->toDouble();
+
+                result = scope.evaluateFunction (functionName, params, numParams);
+            }
+            else
+            {
+                result = scope.evaluateFunction (functionName, nullptr, 0);
+            }
+
+            return new Constant (result, false);
+        }
+
+        int getInputIndexFor (const Term* possibleInput) const
+        {
+            for (int i = 0; i < parameters.size(); ++i)
+                if (parameters.getReference(i).term == possibleInput)
+                    return i;
+
+            return -1;
+        }
+
+        String toString() const
+        {
+            if (parameters.size() == 0)
+                return functionName + "()";
+
+            String s (functionName + " (");
+
+            for (int i = 0; i < parameters.size(); ++i)
+            {
+                s << parameters.getReference(i).term->toString();
+
+                if (i < parameters.size() - 1)
+                    s << ", ";
+            }
+
+            s << ')';
+            return s;
+        }
+
+        const String functionName;
+        Array<Expression> parameters;
+    };
+
+    //==============================================================================
+    class DotOperator  : public BinaryTerm
+    {
+    public:
+        DotOperator (SymbolTerm* const l, Term* const r)  : BinaryTerm (l, r) {}
+
+        TermPtr resolve (const Scope& scope, int recursionDepth)
+        {
+            checkRecursionDepth (recursionDepth);
+
+            EvaluationVisitor visitor (right, recursionDepth + 1);
+            scope.visitRelativeScope (getSymbol()->symbol, visitor);
+            return visitor.output;
+        }
+
+        Term* clone() const                             { return new DotOperator (getSymbol(), right); }
+        String getName() const                          { return "."; }
+        int getOperatorPrecedence() const               { return 1; }
+        void writeOperator (String& dest) const         { dest << '.'; }
+        double performFunction (double, double) const   { return 0.0; }
+
+        void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
+        {
+            checkRecursionDepth (recursionDepth);
+            visitor.useSymbol (Symbol (scope.getScopeUID(), getSymbol()->symbol));
+
+            SymbolVisitingVisitor v (right, visitor, recursionDepth + 1);
+
+            try
+            {
+                scope.visitRelativeScope (getSymbol()->symbol, v);
+            }
+            catch (...) {}
+        }
+
+        void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
+        {
+            checkRecursionDepth (recursionDepth);
+            getSymbol()->renameSymbol (oldSymbol, newName, scope, recursionDepth);
+
+            SymbolRenamingVisitor visitor (right, oldSymbol, newName, recursionDepth + 1);
+
+            try
+            {
+                scope.visitRelativeScope (getSymbol()->symbol, visitor);
+            }
+            catch (...) {}
+        }
+
+    private:
+        //==============================================================================
+        class EvaluationVisitor  : public Scope::Visitor
+        {
+        public:
+            EvaluationVisitor (const TermPtr& t, const int recursion)
+                : input (t), output (t), recursionCount (recursion) {}
+
+            void visit (const Scope& scope)   { output = input->resolve (scope, recursionCount); }
+
+            const TermPtr input;
+            TermPtr output;
+            const int recursionCount;
+
+        private:
+            JUCE_DECLARE_NON_COPYABLE (EvaluationVisitor)
+        };
+
+        class SymbolVisitingVisitor  : public Scope::Visitor
+        {
+        public:
+            SymbolVisitingVisitor (const TermPtr& t, SymbolVisitor& v, const int recursion)
+                : input (t), visitor (v), recursionCount (recursion) {}
+
+            void visit (const Scope& scope)   { input->visitAllSymbols (visitor, scope, recursionCount); }
+
+        private:
+            const TermPtr input;
+            SymbolVisitor& visitor;
+            const int recursionCount;
+
+            JUCE_DECLARE_NON_COPYABLE (SymbolVisitingVisitor)
+        };
+
+        class SymbolRenamingVisitor   : public Scope::Visitor
+        {
+        public:
+            SymbolRenamingVisitor (const TermPtr& t, const Expression::Symbol& symbol_, const String& newName_, const int recursionCount_)
+                : input (t), symbol (symbol_), newName (newName_), recursionCount (recursionCount_)  {}
+
+            void visit (const Scope& scope)   { input->renameSymbol (symbol, newName, scope, recursionCount); }
+
+        private:
+            const TermPtr input;
+            const Symbol& symbol;
+            const String newName;
+            const int recursionCount;
+
+            JUCE_DECLARE_NON_COPYABLE (SymbolRenamingVisitor)
+        };
+
+        SymbolTerm* getSymbol() const  { return static_cast <SymbolTerm*> (left.get()); }
+
+        JUCE_DECLARE_NON_COPYABLE (DotOperator)
+    };
+
+    //==============================================================================
+    class Negate  : public Term
+    {
+    public:
+        explicit Negate (const TermPtr& t) : input (t)
+        {
+            jassert (t != nullptr);
+        }
+
+        Type getType() const noexcept                           { return operatorType; }
+        int getInputIndexFor (const Term* possibleInput) const  { return possibleInput == input ? 0 : -1; }
+        int getNumInputs() const                                { return 1; }
+        Term* getInput (int index) const                        { return index == 0 ? input.get() : nullptr; }
+        Term* clone() const                                     { return new Negate (input->clone()); }
+
+        TermPtr resolve (const Scope& scope, int recursionDepth)
+        {
+            return new Constant (-input->resolve (scope, recursionDepth)->toDouble(), false);
+        }
+
+        String getName() const          { return "-"; }
+        TermPtr negated()               { return input; }
+
+        TermPtr createTermToEvaluateInput (const Scope& scope, const Term* t, double overallTarget, Term* topLevelTerm) const
+        {
+            (void) t;
+            jassert (t == input);
+
+            const Term* const dest = findDestinationFor (topLevelTerm, this);
+
+            return new Negate (dest == nullptr ? new Constant (overallTarget, false)
+                                               : dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm));
+        }
+
+        String toString() const
+        {
+            if (input->getOperatorPrecedence() > 0)
+                return "-(" + input->toString() + ")";
+
+            return "-" + input->toString();
+        }
+
+    private:
+        const TermPtr input;
+    };
+
+    //==============================================================================
+    class Add  : public BinaryTerm
+    {
+    public:
+        Add (Term* const l, Term* const r) : BinaryTerm (l, r) {}
+
+        Term* clone() const                     { return new Add (left->clone(), right->clone()); }
+        double performFunction (double lhs, double rhs) const    { return lhs + rhs; }
+        int getOperatorPrecedence() const       { return 3; }
+        String getName() const                  { return "+"; }
+        void writeOperator (String& dest) const { dest << " + "; }
+
+        TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
+        {
+            const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
+            if (newDest == nullptr)
+                return TermPtr();
+
+            return new Subtract (newDest, (input == left ? right : left)->clone());
+        }
+
+    private:
+        JUCE_DECLARE_NON_COPYABLE (Add)
+    };
+
+    //==============================================================================
+    class Subtract  : public BinaryTerm
+    {
+    public:
+        Subtract (Term* const l, Term* const r) : BinaryTerm (l, r) {}
+
+        Term* clone() const                     { return new Subtract (left->clone(), right->clone()); }
+        double performFunction (double lhs, double rhs) const    { return lhs - rhs; }
+        int getOperatorPrecedence() const       { return 3; }
+        String getName() const                  { return "-"; }
+        void writeOperator (String& dest) const { dest << " - "; }
+
+        TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
+        {
+            const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
+            if (newDest == nullptr)
+                return TermPtr();
+
+            if (input == left)
+                return new Add (newDest, right->clone());
+
+            return new Subtract (left->clone(), newDest);
+        }
+
+    private:
+        JUCE_DECLARE_NON_COPYABLE (Subtract)
+    };
+
+    //==============================================================================
+    class Multiply  : public BinaryTerm
+    {
+    public:
+        Multiply (Term* const l, Term* const r) : BinaryTerm (l, r) {}
+
+        Term* clone() const                     { return new Multiply (left->clone(), right->clone()); }
+        double performFunction (double lhs, double rhs) const    { return lhs * rhs; }
+        String getName() const                  { return "*"; }
+        void writeOperator (String& dest) const { dest << " * "; }
+        int getOperatorPrecedence() const       { return 2; }
+
+        TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
+        {
+            const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
+            if (newDest == nullptr)
+                return TermPtr();
+
+            return new Divide (newDest, (input == left ? right : left)->clone());
+        }
+
+    private:
+        JUCE_DECLARE_NON_COPYABLE (Multiply)
+    };
+
+    //==============================================================================
+    class Divide  : public BinaryTerm
+    {
+    public:
+        Divide (Term* const l, Term* const r) : BinaryTerm (l, r) {}
+
+        Term* clone() const                     { return new Divide (left->clone(), right->clone()); }
+        double performFunction (double lhs, double rhs) const    { return lhs / rhs; }
+        String getName() const                  { return "/"; }
+        void writeOperator (String& dest) const { dest << " / "; }
+        int getOperatorPrecedence() const       { return 2; }
+
+        TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
+        {
+            const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
+            if (newDest == nullptr)
+                return TermPtr();
+
+            if (input == left)
+                return new Multiply (newDest, right->clone());
+
+            return new Divide (left->clone(), newDest);
+        }
+
+    private:
+        JUCE_DECLARE_NON_COPYABLE (Divide)
+    };
+
+    //==============================================================================
+    static Term* findDestinationFor (Term* const topLevel, const Term* const inputTerm)
+    {
+        const int inputIndex = topLevel->getInputIndexFor (inputTerm);
+        if (inputIndex >= 0)
+            return topLevel;
+
+        for (int i = topLevel->getNumInputs(); --i >= 0;)
+        {
+            Term* const t = findDestinationFor (topLevel->getInput (i), inputTerm);
+
+            if (t != nullptr)
+                return t;
+        }
+
+        return nullptr;
+    }
+
+    static Constant* findTermToAdjust (Term* const term, const bool mustBeFlagged)
+    {
+        jassert (term != nullptr);
+
+        if (term->getType() == constantType)
+        {
+            Constant* const c = static_cast<Constant*> (term);
+            if (c->isResolutionTarget || ! mustBeFlagged)
+                return c;
+        }
+
+        if (term->getType() == functionType)
+            return nullptr;
+
+        const int numIns = term->getNumInputs();
+
+        for (int i = 0; i < numIns; ++i)
+        {
+            Term* const input = term->getInput (i);
+
+            if (input->getType() == constantType)
+            {
+                Constant* const c = static_cast<Constant*> (input);
+
+                if (c->isResolutionTarget || ! mustBeFlagged)
+                    return c;
+            }
+        }
+
+        for (int i = 0; i < numIns; ++i)
+        {
+            Constant* const c = findTermToAdjust (term->getInput (i), mustBeFlagged);
+            if (c != nullptr)
+                return c;
+        }
+
+        return nullptr;
+    }
+
+    static bool containsAnySymbols (const Term* const t)
+    {
+        if (t->getType() == Expression::symbolType)
+            return true;
+
+        for (int i = t->getNumInputs(); --i >= 0;)
+            if (containsAnySymbols (t->getInput (i)))
+                return true;
+
+        return false;
+    }
+
+    //==============================================================================
+    class SymbolCheckVisitor  : public Term::SymbolVisitor
+    {
+    public:
+        SymbolCheckVisitor (const Symbol& symbol_) : wasFound (false), symbol (symbol_) {}
+        void useSymbol (const Symbol& s)    { wasFound = wasFound || s == symbol; }
+
+        bool wasFound;
+
+    private:
+        const Symbol& symbol;
+
+        JUCE_DECLARE_NON_COPYABLE (SymbolCheckVisitor)
+    };
+
+    //==============================================================================
+    class SymbolListVisitor  : public Term::SymbolVisitor
+    {
+    public:
+        SymbolListVisitor (Array<Symbol>& list_) : list (list_) {}
+        void useSymbol (const Symbol& s)    { list.addIfNotAlreadyThere (s); }
+
+    private:
+        Array<Symbol>& list;
+
+        JUCE_DECLARE_NON_COPYABLE (SymbolListVisitor)
+    };
+
+    //==============================================================================
+    class Parser
+    {
+    public:
+        //==============================================================================
+        Parser (String::CharPointerType& stringToParse)
+            : text (stringToParse)
+        {
+        }
+
+        TermPtr readUpToComma()
+        {
+            if (text.isEmpty())
+                return new Constant (0.0, false);
+
+            const TermPtr e (readExpression());
+
+            if (e == nullptr || ((! readOperator (",")) && ! text.isEmpty()))
+                throw ParseError ("Syntax error: \"" + String (text) + "\"");
+
+            return e;
+        }
+
+    private:
+        String::CharPointerType& text;
+
+        //==============================================================================
+        static inline bool isDecimalDigit (const juce_wchar c) noexcept
+        {
+            return c >= '0' && c <= '9';
+        }
+
+        bool readChar (const juce_wchar required) noexcept
+        {
+            if (*text == required)
+            {
+                ++text;
+                return true;
+            }
+
+            return false;
+        }
+
+        bool readOperator (const char* ops, char* const opType = nullptr) noexcept
+        {
+            text = text.findEndOfWhitespace();
+
+            while (*ops != 0)
+            {
+                if (readChar ((juce_wchar) (uint8) *ops))
+                {
+                    if (opType != nullptr)
+                        *opType = *ops;
+
+                    return true;
+                }
+
+                ++ops;
+            }
+
+            return false;
+        }
+
+        bool readIdentifier (String& identifier) noexcept
+        {
+            text = text.findEndOfWhitespace();
+            String::CharPointerType t (text);
+            int numChars = 0;
+
+            if (t.isLetter() || *t == '_')
+            {
+                ++t;
+                ++numChars;
+
+                while (t.isLetterOrDigit() || *t == '_')
+                {
+                    ++t;
+                    ++numChars;
+                }
+            }
+
+            if (numChars > 0)
+            {
+                identifier = String (text, (size_t) numChars);
+                text = t;
+                return true;
+            }
+
+            return false;
+        }
+
+        Term* readNumber() noexcept
+        {
+            text = text.findEndOfWhitespace();
+            String::CharPointerType t (text);
+
+            const bool isResolutionTarget = (*t == '@');
+            if (isResolutionTarget)
+            {
+                ++t;
+                t = t.findEndOfWhitespace();
+                text = t;
+            }
+
+            if (*t == '-')
+            {
+                ++t;
+                t = t.findEndOfWhitespace();
+            }
+
+            if (isDecimalDigit (*t) || (*t == '.' && isDecimalDigit (t[1])))
+                return new Constant (CharacterFunctions::readDoubleValue (text), isResolutionTarget);
+
+            return nullptr;
+        }
+
+        TermPtr readExpression()
+        {
+            TermPtr lhs (readMultiplyOrDivideExpression());
+
+            char opType;
+            while (lhs != nullptr && readOperator ("+-", &opType))
+            {
+                TermPtr rhs (readMultiplyOrDivideExpression());
+
+                if (rhs == nullptr)
+                    throw ParseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
+
+                if (opType == '+')
+                    lhs = new Add (lhs, rhs);
+                else
+                    lhs = new Subtract (lhs, rhs);
+            }
+
+            return lhs;
+        }
+
+        TermPtr readMultiplyOrDivideExpression()
+        {
+            TermPtr lhs (readUnaryExpression());
+
+            char opType;
+            while (lhs != nullptr && readOperator ("*/", &opType))
+            {
+                TermPtr rhs (readUnaryExpression());
+
+                if (rhs == nullptr)
+                    throw ParseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
+
+                if (opType == '*')
+                    lhs = new Multiply (lhs, rhs);
+                else
+                    lhs = new Divide (lhs, rhs);
+            }
+
+            return lhs;
+        }
+
+        TermPtr readUnaryExpression()
+        {
+            char opType;
+            if (readOperator ("+-", &opType))
+            {
+                TermPtr e (readUnaryExpression());
+
+                if (e == nullptr)
+                    throw ParseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
+
+                if (opType == '-')
+                    e = e->negated();
+
+                return e;
+            }
+
+            return readPrimaryExpression();
+        }
+
+        TermPtr readPrimaryExpression()
+        {
+            TermPtr e (readParenthesisedExpression());
+            if (e != nullptr)
+                return e;
+
+            e = readNumber();
+            if (e != nullptr)
+                return e;
+
+            return readSymbolOrFunction();
+        }
+
+        TermPtr readSymbolOrFunction()
+        {
+            String identifier;
+            if (readIdentifier (identifier))
+            {
+                if (readOperator ("(")) // method call...
+                {
+                    Function* const f = new Function (identifier);
+                    ScopedPointer<Term> func (f);  // (can't use ScopedPointer<Function> in MSVC)
+
+                    TermPtr param (readExpression());
+
+                    if (param == nullptr)
+                    {
+                        if (readOperator (")"))
+                            return func.release();
+
+                        throw ParseError ("Expected parameters after \"" + identifier + " (\"");
+                    }
+
+                    f->parameters.add (Expression (param));
+
+                    while (readOperator (","))
+                    {
+                        param = readExpression();
+
+                        if (param == nullptr)
+                            throw ParseError ("Expected expression after \",\"");
+
+                        f->parameters.add (Expression (param));
+                    }
+
+                    if (readOperator (")"))
+                        return func.release();
+
+                    throw ParseError ("Expected \")\"");
+                }
+
+                if (readOperator ("."))
+                {
+                    TermPtr rhs (readSymbolOrFunction());
+
+                    if (rhs == nullptr)
+                        throw ParseError ("Expected symbol or function after \".\"");
+
+                    if (identifier == "this")
+                        return rhs;
+
+                    return new DotOperator (new SymbolTerm (identifier), rhs);
+                }
+
+                // just a symbol..
+                jassert (identifier.trim() == identifier);
+                return new SymbolTerm (identifier);
+            }
+
+            return TermPtr();
+        }
+
+        TermPtr readParenthesisedExpression()
+        {
+            if (! readOperator ("("))
+                return TermPtr();
+
+            const TermPtr e (readExpression());
+            if (e == nullptr || ! readOperator (")"))
+                return TermPtr();
+
+            return e;
+        }
+
+        JUCE_DECLARE_NON_COPYABLE (Parser)
+    };
+};
+
+//==============================================================================
+Expression::Expression()
+    : term (new Expression::Helpers::Constant (0, false))
+{
+}
+
+Expression::~Expression()
+{
+}
+
+Expression::Expression (Term* const term_)
+    : term (term_)
+{
+    jassert (term != nullptr);
+}
+
+Expression::Expression (const double constant)
+    : term (new Expression::Helpers::Constant (constant, false))
+{
+}
+
+Expression::Expression (const Expression& other)
+    : term (other.term)
+{
+}
+
+Expression& Expression::operator= (const Expression& other)
+{
+    term = other.term;
+    return *this;
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+Expression::Expression (Expression&& other) noexcept
+    : term (static_cast <ReferenceCountedObjectPtr<Term>&&> (other.term))
+{
+}
+
+Expression& Expression::operator= (Expression&& other) noexcept
+{
+    term = static_cast <ReferenceCountedObjectPtr<Term>&&> (other.term);
+    return *this;
+}
+#endif
+
+Expression::Expression (const String& stringToParse)
+{
+    String::CharPointerType text (stringToParse.getCharPointer());
+    Helpers::Parser parser (text);
+    term = parser.readUpToComma();
+}
+
+Expression Expression::parse (String::CharPointerType& stringToParse)
+{
+    Helpers::Parser parser (stringToParse);
+    return Expression (parser.readUpToComma());
+}
+
+double Expression::evaluate() const
+{
+    return evaluate (Expression::Scope());
+}
+
+double Expression::evaluate (const Expression::Scope& scope) const
+{
+    try
+    {
+        return term->resolve (scope, 0)->toDouble();
+    }
+    catch (Helpers::EvaluationError&)
+    {}
+
+    return 0;
+}
+
+double Expression::evaluate (const Scope& scope, String& evaluationError) const
+{
+    try
+    {
+        return term->resolve (scope, 0)->toDouble();
+    }
+    catch (Helpers::EvaluationError& e)
+    {
+        evaluationError = e.description;
+    }
+
+    return 0;
+}
+
+Expression Expression::operator+ (const Expression& other) const  { return Expression (new Helpers::Add (term, other.term)); }
+Expression Expression::operator- (const Expression& other) const  { return Expression (new Helpers::Subtract (term, other.term)); }
+Expression Expression::operator* (const Expression& other) const  { return Expression (new Helpers::Multiply (term, other.term)); }
+Expression Expression::operator/ (const Expression& other) const  { return Expression (new Helpers::Divide (term, other.term)); }
+Expression Expression::operator-() const                          { return Expression (term->negated()); }
+Expression Expression::symbol (const String& symbol)              { return Expression (new Helpers::SymbolTerm (symbol)); }
+
+Expression Expression::function (const String& functionName, const Array<Expression>& parameters)
+{
+    return Expression (new Helpers::Function (functionName, parameters));
+}
+
+Expression Expression::adjustedToGiveNewResult (const double targetValue, const Expression::Scope& scope) const
+{
+    ScopedPointer<Term> newTerm (term->clone());
+
+    Helpers::Constant* termToAdjust = Helpers::findTermToAdjust (newTerm, true);
+
+    if (termToAdjust == nullptr)
+        termToAdjust = Helpers::findTermToAdjust (newTerm, false);
+
+    if (termToAdjust == nullptr)
+    {
+        newTerm = new Helpers::Add (newTerm.release(), new Helpers::Constant (0, false));
+        termToAdjust = Helpers::findTermToAdjust (newTerm, false);
+    }
+
+    jassert (termToAdjust != nullptr);
+
+    const Term* const parent = Helpers::findDestinationFor (newTerm, termToAdjust);
+
+    if (parent == nullptr)
+    {
+        termToAdjust->value = targetValue;
+    }
+    else
+    {
+        const Helpers::TermPtr reverseTerm (parent->createTermToEvaluateInput (scope, termToAdjust, targetValue, newTerm));
+
+        if (reverseTerm == nullptr)
+            return Expression (targetValue);
+
+        termToAdjust->value = reverseTerm->resolve (scope, 0)->toDouble();
+    }
+
+    return Expression (newTerm.release());
+}
+
+Expression Expression::withRenamedSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Scope& scope) const
+{
+    jassert (newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));
+
+    if (oldSymbol.symbolName == newName)
+        return *this;
+
+    Expression e (term->clone());
+    e.term->renameSymbol (oldSymbol, newName, scope, 0);
+    return e;
+}
+
+bool Expression::referencesSymbol (const Expression::Symbol& symbolToCheck, const Scope& scope) const
+{
+    Helpers::SymbolCheckVisitor visitor (symbolToCheck);
+
+    try
+    {
+        term->visitAllSymbols (visitor, scope, 0);
+    }
+    catch (Helpers::EvaluationError&)
+    {}
+
+    return visitor.wasFound;
+}
+
+void Expression::findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const
+{
+    try
+    {
+        Helpers::SymbolListVisitor visitor (results);
+        term->visitAllSymbols (visitor, scope, 0);
+    }
+    catch (Helpers::EvaluationError&)
+    {}
+}
+
+String Expression::toString() const                     { return term->toString(); }
+bool Expression::usesAnySymbols() const                 { return Helpers::containsAnySymbols (term); }
+Expression::Type Expression::getType() const noexcept   { return term->getType(); }
+String Expression::getSymbolOrFunction() const          { return term->getName(); }
+int Expression::getNumInputs() const                    { return term->getNumInputs(); }
+Expression Expression::getInput (int index) const       { return Expression (term->getInput (index)); }
+
+//==============================================================================
+ReferenceCountedObjectPtr<Expression::Term> Expression::Term::negated()
+{
+    return new Helpers::Negate (this);
+}
+
+//==============================================================================
+Expression::ParseError::ParseError (const String& message)
+    : description (message)
+{
+    DBG ("Expression::ParseError: " + message);
+}
+
+//==============================================================================
+Expression::Symbol::Symbol (const String& scopeUID_, const String& symbolName_)
+    : scopeUID (scopeUID_), symbolName (symbolName_)
+{
+}
+
+bool Expression::Symbol::operator== (const Symbol& other) const noexcept
+{
+    return symbolName == other.symbolName && scopeUID == other.scopeUID;
+}
+
+bool Expression::Symbol::operator!= (const Symbol& other) const noexcept
+{
+    return ! operator== (other);
+}
+
+//==============================================================================
+Expression::Scope::Scope()  {}
+Expression::Scope::~Scope() {}
+
+Expression Expression::Scope::getSymbolValue (const String& symbol) const
+{
+    if (symbol.isNotEmpty())
+        throw Helpers::EvaluationError ("Unknown symbol: " + symbol);
+
+    return Expression();
+}
+
+double Expression::Scope::evaluateFunction (const String& functionName, const double* parameters, int numParams) const
+{
+    if (numParams > 0)
+    {
+        if (functionName == "min")
+        {
+            double v = parameters[0];
+            for (int i = 1; i < numParams; ++i)
+                v = jmin (v, parameters[i]);
+
+            return v;
+        }
+
+        if (functionName == "max")
+        {
+            double v = parameters[0];
+            for (int i = 1; i < numParams; ++i)
+                v = jmax (v, parameters[i]);
+
+            return v;
+        }
+
+        if (numParams == 1)
+        {
+            if (functionName == "sin")  return sin (parameters[0]);
+            if (functionName == "cos")  return cos (parameters[0]);
+            if (functionName == "tan")  return tan (parameters[0]);
+            if (functionName == "abs")  return std::abs (parameters[0]);
+        }
+    }
+
+    throw Helpers::EvaluationError ("Unknown function: \"" + functionName + "\"");
+}
+
+void Expression::Scope::visitRelativeScope (const String& scopeName, Visitor&) const
+{
+    throw Helpers::EvaluationError ("Unknown symbol: " + scopeName);
+}
+
+String Expression::Scope::getScopeUID() const
+{
+    return String();
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Expression.h b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Expression.h
new file mode 100644
index 0000000..8939129
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Expression.h
@@ -0,0 +1,270 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_EXPRESSION_H_INCLUDED
+#define JUCE_EXPRESSION_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A class for dynamically evaluating simple numeric expressions.
+
+    This class can parse a simple C-style string expression involving floating point
+    numbers, named symbols and functions. The basic arithmetic operations of +, -, *, /
+    are supported, as well as parentheses, and any alphanumeric identifiers are
+    assumed to be named symbols which will be resolved when the expression is
+    evaluated.
+
+    Expressions which use identifiers and functions require a subclass of
+    Expression::Scope to be supplied when evaluating them, and this object
+    is expected to be able to resolve the symbol names and perform the functions that
+    are used.
+*/
+class JUCE_API  Expression
+{
+public:
+    //==============================================================================
+    /** Creates a simple expression with a value of 0. */
+    Expression();
+
+    /** Destructor. */
+    ~Expression();
+
+    /** Creates a simple expression with a specified constant value. */
+    explicit Expression (double constant);
+
+    /** Creates a copy of an expression. */
+    Expression (const Expression&);
+
+    /** Copies another expression. */
+    Expression& operator= (const Expression&);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    Expression (Expression&&) noexcept;
+    Expression& operator= (Expression&&) noexcept;
+   #endif
+
+    /** Creates an expression by parsing a string.
+        If there's a syntax error in the string, this will throw a ParseError exception.
+        @throws ParseError
+    */
+    explicit Expression (const String& stringToParse);
+
+    /** Returns a string version of the expression. */
+    String toString() const;
+
+    /** Returns an expression which is an addition operation of two existing expressions. */
+    Expression operator+ (const Expression&) const;
+    /** Returns an expression which is a subtraction operation of two existing expressions. */
+    Expression operator- (const Expression&) const;
+    /** Returns an expression which is a multiplication operation of two existing expressions. */
+    Expression operator* (const Expression&) const;
+    /** Returns an expression which is a division operation of two existing expressions. */
+    Expression operator/ (const Expression&) const;
+    /** Returns an expression which performs a negation operation on an existing expression. */
+    Expression operator-() const;
+
+    /** Returns an Expression which is an identifier reference. */
+    static Expression symbol (const String& symbol);
+
+    /** Returns an Expression which is a function call. */
+    static Expression function (const String& functionName, const Array<Expression>& parameters);
+
+    /** Returns an Expression which parses a string from a character pointer, and updates the pointer
+        to indicate where it finished.
+
+        The pointer is incremented so that on return, it indicates the character that follows
+        the end of the expression that was parsed.
+
+        If there's a syntax error in the string, this will throw a ParseError exception.
+        @throws ParseError
+    */
+    static Expression parse (String::CharPointerType& stringToParse);
+
+    //==============================================================================
+    /** When evaluating an Expression object, this class is used to resolve symbols and
+        perform functions that the expression uses.
+    */
+    class JUCE_API  Scope
+    {
+    public:
+        Scope();
+        virtual ~Scope();
+
+        /** Returns some kind of globally unique ID that identifies this scope. */
+        virtual String getScopeUID() const;
+
+        /** Returns the value of a symbol.
+            If the symbol is unknown, this can throw an Expression::EvaluationError exception.
+            The member value is set to the part of the symbol that followed the dot, if there is
+            one, e.g. for "foo.bar", symbol = "foo" and member = "bar".
+            @throws Expression::EvaluationError
+        */
+        virtual Expression getSymbolValue (const String& symbol) const;
+
+        /** Executes a named function.
+            If the function name is unknown, this can throw an Expression::EvaluationError exception.
+            @throws Expression::EvaluationError
+        */
+        virtual double evaluateFunction (const String& functionName,
+                                         const double* parameters, int numParameters) const;
+
+        /** Used as a callback by the Scope::visitRelativeScope() method.
+            You should never create an instance of this class yourself, it's used by the
+            expression evaluation code.
+        */
+        class Visitor
+        {
+        public:
+            virtual ~Visitor() {}
+            virtual void visit (const Scope&) = 0;
+        };
+
+        /** Creates a Scope object for a named scope, and then calls a visitor
+            to do some kind of processing with this new scope.
+
+            If the name is valid, this method must create a suitable (temporary) Scope
+            object to represent it, and must call the Visitor::visit() method with this
+            new scope.
+        */
+        virtual void visitRelativeScope (const String& scopeName, Visitor& visitor) const;
+    };
+
+    /** Evaluates this expression, without using a Scope.
+        Without a Scope, no symbols can be used, and only basic functions such as sin, cos, tan,
+        min, max are available.
+        To find out about any errors during evaluation, use the other version of this method which
+        takes a String parameter.
+    */
+    double evaluate() const;
+
+    /** Evaluates this expression, providing a scope that should be able to evaluate any symbols
+        or functions that it uses.
+        To find out about any errors during evaluation, use the other version of this method which
+        takes a String parameter.
+    */
+    double evaluate (const Scope& scope) const;
+
+    /** Evaluates this expression, providing a scope that should be able to evaluate any symbols
+        or functions that it uses.
+    */
+    double evaluate (const Scope& scope, String& evaluationError) const;
+
+    /** Attempts to return an expression which is a copy of this one, but with a constant adjusted
+        to make the expression resolve to a target value.
+
+        E.g. if the expression is "x + 10" and x is 5, then asking for a target value of 8 will return
+        the expression "x + 3". Obviously some expressions can't be reversed in this way, in which
+        case they might just be adjusted by adding a constant to the original expression.
+
+        @throws Expression::EvaluationError
+    */
+    Expression adjustedToGiveNewResult (double targetValue, const Scope& scope) const;
+
+    /** Represents a symbol that is used in an Expression. */
+    struct Symbol
+    {
+        Symbol (const String& scopeUID, const String& symbolName);
+        bool operator== (const Symbol&) const noexcept;
+        bool operator!= (const Symbol&) const noexcept;
+
+        String scopeUID;    /**< The unique ID of the Scope that contains this symbol. */
+        String symbolName;  /**< The name of the symbol. */
+    };
+
+    /** Returns a copy of this expression in which all instances of a given symbol have been renamed. */
+    Expression withRenamedSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope) const;
+
+    /** Returns true if this expression makes use of the specified symbol.
+        If a suitable scope is supplied, the search will dereference and recursively check
+        all symbols, so that it can be determined whether this expression relies on the given
+        symbol at any level in its evaluation. If the scope parameter is null, this just checks
+        whether the expression contains any direct references to the symbol.
+
+        @throws Expression::EvaluationError
+    */
+    bool referencesSymbol (const Symbol& symbol, const Scope& scope) const;
+
+    /** Returns true if this expression contains any symbols. */
+    bool usesAnySymbols() const;
+
+    /** Returns a list of all symbols that may be needed to resolve this expression in the given scope. */
+    void findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const;
+
+    //==============================================================================
+    /** An exception that can be thrown by Expression::parse(). */
+    class ParseError  : public std::exception
+    {
+    public:
+        ParseError (const String& message);
+
+        String description;
+    };
+
+    //==============================================================================
+    /** Expression type.
+        @see Expression::getType()
+    */
+    enum Type
+    {
+        constantType,
+        functionType,
+        operatorType,
+        symbolType
+    };
+
+    /** Returns the type of this expression. */
+    Type getType() const noexcept;
+
+    /** If this expression is a symbol, function or operator, this returns its identifier. */
+    String getSymbolOrFunction() const;
+
+    /** Returns the number of inputs to this expression.
+        @see getInput
+    */
+    int getNumInputs() const;
+
+    /** Retrieves one of the inputs to this expression.
+        @see getNumInputs
+    */
+    Expression getInput (int index) const;
+
+private:
+    //==============================================================================
+    class Term;
+    struct Helpers;
+    friend class Term;
+    friend struct Helpers;
+    friend struct ContainerDeletePolicy<Term>;
+    friend class ReferenceCountedObjectPtr<Term>;
+    ReferenceCountedObjectPtr<Term> term;
+
+    explicit Expression (Term*);
+};
+
+#endif   // JUCE_EXPRESSION_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_MathsFunctions.h b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_MathsFunctions.h
new file mode 100644
index 0000000..d2d02b9
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_MathsFunctions.h
@@ -0,0 +1,549 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_MATHSFUNCTIONS_H_INCLUDED
+#define JUCE_MATHSFUNCTIONS_H_INCLUDED
+
+//==============================================================================
+/*
+    This file sets up some handy mathematical typdefs and functions.
+*/
+
+//==============================================================================
+// Definitions for the int8, int16, int32, int64 and pointer_sized_int types.
+
+/** A platform-independent 8-bit signed integer type. */
+typedef signed char                 int8;
+/** A platform-independent 8-bit unsigned integer type. */
+typedef unsigned char               uint8;
+/** A platform-independent 16-bit signed integer type. */
+typedef signed short                int16;
+/** A platform-independent 16-bit unsigned integer type. */
+typedef unsigned short              uint16;
+/** A platform-independent 32-bit signed integer type. */
+typedef signed int                  int32;
+/** A platform-independent 32-bit unsigned integer type. */
+typedef unsigned int                uint32;
+
+#if JUCE_MSVC
+  /** A platform-independent 64-bit integer type. */
+  typedef __int64                   int64;
+  /** A platform-independent 64-bit unsigned integer type. */
+  typedef unsigned __int64          uint64;
+#else
+  /** A platform-independent 64-bit integer type. */
+  typedef long long                 int64;
+  /** A platform-independent 64-bit unsigned integer type. */
+  typedef unsigned long long        uint64;
+#endif
+
+#ifndef DOXYGEN
+ /** A macro for creating 64-bit literals.
+     Historically, this was needed to support portability with MSVC6, and is kept here
+     so that old code will still compile, but nowadays every compiler will support the
+     LL and ULL suffixes, so you should use those in preference to this macro.
+ */
+ #define literal64bit(longLiteral)     (longLiteral##LL)
+#endif
+
+#if JUCE_64BIT
+  /** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
+  typedef int64                     pointer_sized_int;
+  /** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
+  typedef uint64                    pointer_sized_uint;
+#elif JUCE_MSVC
+  /** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
+  typedef _W64 int                  pointer_sized_int;
+  /** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
+  typedef _W64 unsigned int         pointer_sized_uint;
+#else
+  /** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
+  typedef int                       pointer_sized_int;
+  /** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
+  typedef unsigned int              pointer_sized_uint;
+#endif
+
+#if JUCE_MSVC
+  typedef pointer_sized_int ssize_t;
+#endif
+
+//==============================================================================
+// Some indispensible min/max functions
+
+/** Returns the larger of two values. */
+template <typename Type>
+inline Type jmax (const Type a, const Type b)                                               { return (a < b) ? b : a; }
+
+/** Returns the larger of three values. */
+template <typename Type>
+inline Type jmax (const Type a, const Type b, const Type c)                                 { return (a < b) ? ((b < c) ? c : b) : ((a < c) ? c : a); }
+
+/** Returns the larger of four values. */
+template <typename Type>
+inline Type jmax (const Type a, const Type b, const Type c, const Type d)                   { return jmax (a, jmax (b, c, d)); }
+
+/** Returns the smaller of two values. */
+template <typename Type>
+inline Type jmin (const Type a, const Type b)                                               { return (b < a) ? b : a; }
+
+/** Returns the smaller of three values. */
+template <typename Type>
+inline Type jmin (const Type a, const Type b, const Type c)                                 { return (b < a) ? ((c < b) ? c : b) : ((c < a) ? c : a); }
+
+/** Returns the smaller of four values. */
+template <typename Type>
+inline Type jmin (const Type a, const Type b, const Type c, const Type d)                   { return jmin (a, jmin (b, c, d)); }
+
+/** Scans an array of values, returning the minimum value that it contains. */
+template <typename Type>
+const Type findMinimum (const Type* data, int numValues)
+{
+    if (numValues <= 0)
+        return Type();
+
+    Type result (*data++);
+
+    while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
+    {
+        const Type& v = *data++;
+        if (v < result)  result = v;
+    }
+
+    return result;
+}
+
+/** Scans an array of values, returning the maximum value that it contains. */
+template <typename Type>
+const Type findMaximum (const Type* values, int numValues)
+{
+    if (numValues <= 0)
+        return Type();
+
+    Type result (*values++);
+
+    while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
+    {
+        const Type& v = *values++;
+        if (result < v)  result = v;
+    }
+
+    return result;
+}
+
+/** Scans an array of values, returning the minimum and maximum values that it contains. */
+template <typename Type>
+void findMinAndMax (const Type* values, int numValues, Type& lowest, Type& highest)
+{
+    if (numValues <= 0)
+    {
+        lowest = Type();
+        highest = Type();
+    }
+    else
+    {
+        Type mn (*values++);
+        Type mx (mn);
+
+        while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
+        {
+            const Type& v = *values++;
+
+            if (mx < v)  mx = v;
+            if (v < mn)  mn = v;
+        }
+
+        lowest = mn;
+        highest = mx;
+    }
+}
+
+
+//==============================================================================
+/** Constrains a value to keep it within a given range.
+
+    This will check that the specified value lies between the lower and upper bounds
+    specified, and if not, will return the nearest value that would be in-range. Effectively,
+    it's like calling jmax (lowerLimit, jmin (upperLimit, value)).
+
+    Note that it expects that lowerLimit <= upperLimit. If this isn't true,
+    the results will be unpredictable.
+
+    @param lowerLimit           the minimum value to return
+    @param upperLimit           the maximum value to return
+    @param valueToConstrain     the value to try to return
+    @returns    the closest value to valueToConstrain which lies between lowerLimit
+                and upperLimit (inclusive)
+    @see jlimit0To, jmin, jmax
+*/
+template <typename Type>
+inline Type jlimit (const Type lowerLimit,
+                    const Type upperLimit,
+                    const Type valueToConstrain) noexcept
+{
+    jassert (lowerLimit <= upperLimit); // if these are in the wrong order, results are unpredictable..
+
+    return (valueToConstrain < lowerLimit) ? lowerLimit
+                                           : ((upperLimit < valueToConstrain) ? upperLimit
+                                                                              : valueToConstrain);
+}
+
+/** Returns true if a value is at least zero, and also below a specified upper limit.
+    This is basically a quicker way to write:
+    @code valueToTest >= 0 && valueToTest < upperLimit
+    @endcode
+*/
+template <typename Type>
+inline bool isPositiveAndBelow (Type valueToTest, Type upperLimit) noexcept
+{
+    jassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero..
+    return Type() <= valueToTest && valueToTest < upperLimit;
+}
+
+template <>
+inline bool isPositiveAndBelow (const int valueToTest, const int upperLimit) noexcept
+{
+    jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
+    return static_cast <unsigned int> (valueToTest) < static_cast <unsigned int> (upperLimit);
+}
+
+/** Returns true if a value is at least zero, and also less than or equal to a specified upper limit.
+    This is basically a quicker way to write:
+    @code valueToTest >= 0 && valueToTest <= upperLimit
+    @endcode
+*/
+template <typename Type>
+inline bool isPositiveAndNotGreaterThan (Type valueToTest, Type upperLimit) noexcept
+{
+    jassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero..
+    return Type() <= valueToTest && valueToTest <= upperLimit;
+}
+
+template <>
+inline bool isPositiveAndNotGreaterThan (const int valueToTest, const int upperLimit) noexcept
+{
+    jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
+    return static_cast <unsigned int> (valueToTest) <= static_cast <unsigned int> (upperLimit);
+}
+
+//==============================================================================
+/** Handy function to swap two values. */
+template <typename Type>
+inline void swapVariables (Type& variable1, Type& variable2)
+{
+    std::swap (variable1, variable2);
+}
+
+/** Handy function for getting the number of elements in a simple const C array.
+    E.g.
+    @code
+    static int myArray[] = { 1, 2, 3 };
+
+    int numElements = numElementsInArray (myArray) // returns 3
+    @endcode
+*/
+template <typename Type, int N>
+inline int numElementsInArray (Type (&array)[N])
+{
+    (void) array; // (required to avoid a spurious warning in MS compilers)
+    (void) sizeof (0[array]); // This line should cause an error if you pass an object with a user-defined subscript operator
+    return N;
+}
+
+//==============================================================================
+// Some useful maths functions that aren't always present with all compilers and build settings.
+
+/** Using juce_hypot is easier than dealing with the different types of hypot function
+    that are provided by the various platforms and compilers. */
+template <typename Type>
+inline Type juce_hypot (Type a, Type b) noexcept
+{
+   #if JUCE_MSVC
+    return static_cast <Type> (_hypot (a, b));
+   #else
+    return static_cast <Type> (hypot (a, b));
+   #endif
+}
+
+/** 64-bit abs function. */
+inline int64 abs64 (const int64 n) noexcept
+{
+    return (n >= 0) ? n : -n;
+}
+
+#if JUCE_MSVC && ! defined (DOXYGEN)  // The MSVC libraries omit these functions for some reason...
+ template<typename Type> Type asinh (Type x) noexcept  { return std::log (x + std::sqrt (x * x + (Type) 1)); }
+ template<typename Type> Type acosh (Type x) noexcept  { return std::log (x + std::sqrt (x * x - (Type) 1)); }
+ template<typename Type> Type atanh (Type x) noexcept  { return (std::log (x + (Type) 1) - std::log (((Type) 1) - x)) / (Type) 2; }
+#endif
+
+//==============================================================================
+/** A predefined value for Pi, at double-precision.
+    @see float_Pi
+*/
+const double  double_Pi  = 3.1415926535897932384626433832795;
+
+/** A predefined value for Pi, at single-precision.
+    @see double_Pi
+*/
+const float   float_Pi   = 3.14159265358979323846f;
+
+
+//==============================================================================
+/** The isfinite() method seems to vary between platforms, so this is a
+    platform-independent function for it.
+*/
+template <typename FloatingPointType>
+inline bool juce_isfinite (FloatingPointType value)
+{
+   #if JUCE_WINDOWS
+    return _finite (value);
+   #elif JUCE_ANDROID
+    return isfinite (value);
+   #else
+    return std::isfinite (value);
+   #endif
+}
+
+//==============================================================================
+#if JUCE_MSVC
+ #pragma optimize ("t", off)
+ #ifndef __INTEL_COMPILER
+  #pragma float_control (precise, on, push)
+ #endif
+#endif
+
+/** Fast floating-point-to-integer conversion.
+
+    This is faster than using the normal c++ cast to convert a float to an int, and
+    it will round the value to the nearest integer, rather than rounding it down
+    like the normal cast does.
+
+    Note that this routine gets its speed at the expense of some accuracy, and when
+    rounding values whose floating point component is exactly 0.5, odd numbers and
+    even numbers will be rounded up or down differently.
+*/
+template <typename FloatType>
+inline int roundToInt (const FloatType value) noexcept
+{
+  #ifdef __INTEL_COMPILER
+   #pragma float_control (precise, on, push)
+  #endif
+
+    union { int asInt[2]; double asDouble; } n;
+    n.asDouble = ((double) value) + 6755399441055744.0;
+
+   #if JUCE_BIG_ENDIAN
+    return n.asInt [1];
+   #else
+    return n.asInt [0];
+   #endif
+}
+
+inline int roundToInt (int value) noexcept
+{
+    return value;
+}
+
+#if JUCE_MSVC
+ #ifndef __INTEL_COMPILER
+  #pragma float_control (pop)
+ #endif
+ #pragma optimize ("", on)  // resets optimisations to the project defaults
+#endif
+
+/** Fast floating-point-to-integer conversion.
+
+    This is a slightly slower and slightly more accurate version of roundDoubleToInt(). It works
+    fine for values above zero, but negative numbers are rounded the wrong way.
+*/
+inline int roundToIntAccurate (const double value) noexcept
+{
+   #ifdef __INTEL_COMPILER
+    #pragma float_control (pop)
+   #endif
+
+    return roundToInt (value + 1.5e-8);
+}
+
+/** Fast floating-point-to-integer conversion.
+
+    This is faster than using the normal c++ cast to convert a double to an int, and
+    it will round the value to the nearest integer, rather than rounding it down
+    like the normal cast does.
+
+    Note that this routine gets its speed at the expense of some accuracy, and when
+    rounding values whose floating point component is exactly 0.5, odd numbers and
+    even numbers will be rounded up or down differently. For a more accurate conversion,
+    see roundDoubleToIntAccurate().
+*/
+inline int roundDoubleToInt (const double value) noexcept
+{
+    return roundToInt (value);
+}
+
+/** Fast floating-point-to-integer conversion.
+
+    This is faster than using the normal c++ cast to convert a float to an int, and
+    it will round the value to the nearest integer, rather than rounding it down
+    like the normal cast does.
+
+    Note that this routine gets its speed at the expense of some accuracy, and when
+    rounding values whose floating point component is exactly 0.5, odd numbers and
+    even numbers will be rounded up or down differently.
+*/
+inline int roundFloatToInt (const float value) noexcept
+{
+    return roundToInt (value);
+}
+
+//==============================================================================
+/** Returns true if the specified integer is a power-of-two.
+*/
+template <typename IntegerType>
+bool isPowerOfTwo (IntegerType value)
+{
+   return (value & (value - 1)) == 0;
+}
+
+/** Returns the smallest power-of-two which is equal to or greater than the given integer.
+*/
+inline int nextPowerOfTwo (int n) noexcept
+{
+    --n;
+    n |= (n >> 1);
+    n |= (n >> 2);
+    n |= (n >> 4);
+    n |= (n >> 8);
+    n |= (n >> 16);
+    return n + 1;
+}
+
+/** Returns the number of bits in a 32-bit integer. */
+inline int countNumberOfBits (uint32 n) noexcept
+{
+    n -= ((n >> 1) & 0x55555555);
+    n =  (((n >> 2) & 0x33333333) + (n & 0x33333333));
+    n =  (((n >> 4) + n) & 0x0f0f0f0f);
+    n += (n >> 8);
+    n += (n >> 16);
+    return (int) (n & 0x3f);
+}
+
+/** Returns the number of bits in a 64-bit integer. */
+inline int countNumberOfBits (uint64 n) noexcept
+{
+    return countNumberOfBits ((uint32) n) + countNumberOfBits ((uint32) (n >> 32));
+}
+
+/** Performs a modulo operation, but can cope with the dividend being negative.
+    The divisor must be greater than zero.
+*/
+template <typename IntegerType>
+IntegerType negativeAwareModulo (IntegerType dividend, const IntegerType divisor) noexcept
+{
+    jassert (divisor > 0);
+    dividend %= divisor;
+    return (dividend < 0) ? (dividend + divisor) : dividend;
+}
+
+/** Returns the square of its argument. */
+template <typename NumericType>
+NumericType square (NumericType n) noexcept
+{
+    return n * n;
+}
+
+//==============================================================================
+#if (JUCE_INTEL && JUCE_32BIT) || defined (DOXYGEN)
+ /** This macro can be applied to a float variable to check whether it contains a denormalised
+     value, and to normalise it if necessary.
+     On CPUs that aren't vulnerable to denormalisation problems, this will have no effect.
+ */
+ #define JUCE_UNDENORMALISE(x)   x += 1.0f; x -= 1.0f;
+#else
+ #define JUCE_UNDENORMALISE(x)
+#endif
+
+//==============================================================================
+/** This namespace contains a few template classes for helping work out class type variations.
+*/
+namespace TypeHelpers
+{
+   #if JUCE_VC8_OR_EARLIER
+    #define PARAMETER_TYPE(type) const type&
+   #else
+    /** The ParameterType struct is used to find the best type to use when passing some kind
+        of object as a parameter.
+
+        Of course, this is only likely to be useful in certain esoteric template situations.
+
+        Because "typename TypeHelpers::ParameterType<SomeClass>::type" is a bit of a mouthful, there's
+        a PARAMETER_TYPE(SomeClass) macro that you can use to get the same effect.
+
+        E.g. "myFunction (PARAMETER_TYPE (int), PARAMETER_TYPE (MyObject))"
+        would evaluate to "myfunction (int, const MyObject&)", keeping any primitive types as
+        pass-by-value, but passing objects as a const reference, to avoid copying.
+    */
+    template <typename Type> struct ParameterType                   { typedef const Type& type; };
+
+   #if ! DOXYGEN
+    template <typename Type> struct ParameterType <Type&>           { typedef Type& type; };
+    template <typename Type> struct ParameterType <Type*>           { typedef Type* type; };
+    template <>              struct ParameterType <char>            { typedef char type; };
+    template <>              struct ParameterType <unsigned char>   { typedef unsigned char type; };
+    template <>              struct ParameterType <short>           { typedef short type; };
+    template <>              struct ParameterType <unsigned short>  { typedef unsigned short type; };
+    template <>              struct ParameterType <int>             { typedef int type; };
+    template <>              struct ParameterType <unsigned int>    { typedef unsigned int type; };
+    template <>              struct ParameterType <long>            { typedef long type; };
+    template <>              struct ParameterType <unsigned long>   { typedef unsigned long type; };
+    template <>              struct ParameterType <int64>           { typedef int64 type; };
+    template <>              struct ParameterType <uint64>          { typedef uint64 type; };
+    template <>              struct ParameterType <bool>            { typedef bool type; };
+    template <>              struct ParameterType <float>           { typedef float type; };
+    template <>              struct ParameterType <double>          { typedef double type; };
+   #endif
+
+    /** A helpful macro to simplify the use of the ParameterType template.
+        @see ParameterType
+    */
+    #define PARAMETER_TYPE(a)    typename TypeHelpers::ParameterType<a>::type
+   #endif
+
+
+    /** These templates are designed to take a type, and if it's a double, they return a double
+        type; for anything else, they return a float type.
+    */
+    template <typename Type> struct SmallestFloatType             { typedef float  type; };
+    template <>              struct SmallestFloatType <double>    { typedef double type; };
+}
+
+
+//==============================================================================
+
+#endif   // JUCE_MATHSFUNCTIONS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Random.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Random.cpp
new file mode 100644
index 0000000..a196256
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Random.cpp
@@ -0,0 +1,189 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+Random::Random (const int64 seedValue) noexcept   : seed (seedValue)
+{
+}
+
+Random::Random()  : seed (1)
+{
+    setSeedRandomly();
+}
+
+Random::~Random() noexcept
+{
+}
+
+void Random::setSeed (const int64 newSeed) noexcept
+{
+    seed = newSeed;
+}
+
+void Random::combineSeed (const int64 seedValue) noexcept
+{
+    seed ^= nextInt64() ^ seedValue;
+}
+
+void Random::setSeedRandomly()
+{
+    static int64 globalSeed = 0;
+
+    combineSeed (globalSeed ^ (int64) (pointer_sized_int) this);
+    combineSeed (Time::getMillisecondCounter());
+    combineSeed (Time::getHighResolutionTicks());
+    combineSeed (Time::getHighResolutionTicksPerSecond());
+    combineSeed (Time::currentTimeMillis());
+    globalSeed ^= seed;
+}
+
+Random& Random::getSystemRandom() noexcept
+{
+    static Random sysRand;
+    return sysRand;
+}
+
+//==============================================================================
+int Random::nextInt() noexcept
+{
+    seed = (seed * 0x5deece66dLL + 11) & 0xffffffffffffLL;
+
+    return (int) (seed >> 16);
+}
+
+int Random::nextInt (const int maxValue) noexcept
+{
+    jassert (maxValue > 0);
+    return (int) ((((unsigned int) nextInt()) * (uint64) maxValue) >> 32);
+}
+
+int Random::nextInt (Range<int> range) noexcept
+{
+    return range.getStart() + nextInt (range.getLength());
+}
+
+int64 Random::nextInt64() noexcept
+{
+    return (((int64) nextInt()) << 32) | (int64) (uint64) (uint32) nextInt();
+}
+
+bool Random::nextBool() noexcept
+{
+    return (nextInt() & 0x40000000) != 0;
+}
+
+float Random::nextFloat() noexcept
+{
+    return static_cast<uint32> (nextInt()) / (std::numeric_limits<uint32>::max() + 1.0f);
+}
+
+double Random::nextDouble() noexcept
+{
+    return static_cast<uint32> (nextInt()) / (std::numeric_limits<uint32>::max() + 1.0);
+}
+
+BigInteger Random::nextLargeNumber (const BigInteger& maximumValue)
+{
+    BigInteger n;
+
+    do
+    {
+        fillBitsRandomly (n, 0, maximumValue.getHighestBit() + 1);
+    }
+    while (n >= maximumValue);
+
+    return n;
+}
+
+void Random::fillBitsRandomly (void* const buffer, size_t bytes)
+{
+    int* d = static_cast<int*> (buffer);
+
+    for (; bytes >= sizeof (int); bytes -= sizeof (int))
+        *d++ = nextInt();
+
+    if (bytes > 0)
+    {
+        const int lastBytes = nextInt();
+        memcpy (d, &lastBytes, bytes);
+    }
+}
+
+void Random::fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits)
+{
+    arrayToChange.setBit (startBit + numBits - 1, true);  // to force the array to pre-allocate space
+
+    while ((startBit & 31) != 0 && numBits > 0)
+    {
+        arrayToChange.setBit (startBit++, nextBool());
+        --numBits;
+    }
+
+    while (numBits >= 32)
+    {
+        arrayToChange.setBitRangeAsInt (startBit, 32, (unsigned int) nextInt());
+        startBit += 32;
+        numBits -= 32;
+    }
+
+    while (--numBits >= 0)
+        arrayToChange.setBit (startBit + numBits, nextBool());
+}
+
+//==============================================================================
+#if JUCE_UNIT_TESTS
+
+class RandomTests  : public UnitTest
+{
+public:
+    RandomTests() : UnitTest ("Random") {}
+
+    void runTest()
+    {
+        beginTest ("Random");
+
+        Random r = getRandom();
+
+        for (int i = 2000; --i >= 0;)
+        {
+            expect (r.nextDouble() >= 0.0 && r.nextDouble() < 1.0);
+            expect (r.nextFloat() >= 0.0f && r.nextFloat() < 1.0f);
+            expect (r.nextInt (5) >= 0 && r.nextInt (5) < 5);
+            expect (r.nextInt (1) == 0);
+
+            int n = r.nextInt (50) + 1;
+            expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
+
+            n = r.nextInt (0x7ffffffe) + 1;
+            expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
+        }
+    }
+};
+
+static RandomTests randomTests;
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Random.h b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Random.h
new file mode 100644
index 0000000..19e6d6e
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Random.h
@@ -0,0 +1,143 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_RANDOM_H_INCLUDED
+#define JUCE_RANDOM_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A random number generator.
+
+    You can create a Random object and use it to generate a sequence of random numbers.
+*/
+class JUCE_API  Random
+{
+public:
+    //==============================================================================
+    /** Creates a Random object based on a seed value.
+
+        For a given seed value, the subsequent numbers generated by this object
+        will be predictable, so a good idea is to set this value based
+        on the time, e.g.
+
+        new Random (Time::currentTimeMillis())
+    */
+    explicit Random (int64 seedValue) noexcept;
+
+    /** Creates a Random object using a random seed value.
+        Internally, this calls setSeedRandomly() to randomise the seed.
+    */
+    Random();
+
+    /** Destructor. */
+    ~Random() noexcept;
+
+    /** Returns the next random 32 bit integer.
+        @returns a random integer from the full range 0x80000000 to 0x7fffffff
+    */
+    int nextInt() noexcept;
+
+    /** Returns the next random number, limited to a given range.
+        The maxValue parameter may not be negative, or zero.
+        @returns a random integer between 0 (inclusive) and maxValue (exclusive).
+    */
+    int nextInt (int maxValue) noexcept;
+
+    /** Returns the next random number, limited to a given range.
+        @returns a random integer between the range start (inclusive) and its end (exclusive).
+    */
+    int nextInt (Range<int> range) noexcept;
+
+    /** Returns the next 64-bit random number.
+        @returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff
+    */
+    int64 nextInt64() noexcept;
+
+    /** Returns the next random floating-point number.
+        @returns a random value in the range 0 to 1.0
+    */
+    float nextFloat() noexcept;
+
+    /** Returns the next random floating-point number.
+        @returns a random value in the range 0 to 1.0
+    */
+    double nextDouble() noexcept;
+
+    /** Returns the next random boolean value. */
+    bool nextBool() noexcept;
+
+    /** Returns a BigInteger containing a random number.
+        @returns a random value in the range 0 to (maximumValue - 1).
+    */
+    BigInteger nextLargeNumber (const BigInteger& maximumValue);
+
+    /** Fills a block of memory with random values. */
+    void fillBitsRandomly (void* bufferToFill, size_t sizeInBytes);
+
+    /** Sets a range of bits in a BigInteger to random values. */
+    void fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits);
+
+    //==============================================================================
+    /** Resets this Random object to a given seed value. */
+    void setSeed (int64 newSeed) noexcept;
+
+    /** Returns the RNG's current seed. */
+    int64 getSeed() const noexcept                      { return seed; }
+
+    /** Merges this object's seed with another value.
+        This sets the seed to be a value created by combining the current seed and this
+        new value.
+    */
+    void combineSeed (int64 seedValue) noexcept;
+
+    /** Reseeds this generator using a value generated from various semi-random system
+        properties like the current time, etc.
+
+        Because this function convolves the time with the last seed value, calling
+        it repeatedly will increase the randomness of the final result.
+    */
+    void setSeedRandomly();
+
+    /** The overhead of creating a new Random object is fairly small, but if you want to avoid
+        it, you can call this method to get a global shared Random object.
+
+        It's not thread-safe though, so threads should use their own Random object, otherwise
+        you run the risk of your random numbers becoming.. erm.. randomly corrupted..
+    */
+    static Random& getSystemRandom() noexcept;
+
+private:
+    //==============================================================================
+    int64 seed;
+
+    JUCE_LEAK_DETECTOR (Random)
+};
+
+
+#endif   // JUCE_RANDOM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Range.h b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Range.h
new file mode 100644
index 0000000..6add152
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/maths/juce_Range.h
@@ -0,0 +1,304 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_RANGE_H_INCLUDED
+#define JUCE_RANGE_H_INCLUDED
+
+
+//==============================================================================
+/** A general-purpose range object, that simply represents any linear range with
+    a start and end point.
+
+    Note that when checking whether values fall within the range, the start value is
+    considered to be inclusive, and the end of the range exclusive.
+
+    The templated parameter is expected to be a primitive integer or floating point
+    type, though class types could also be used if they behave in a number-like way.
+*/
+template <typename ValueType>
+class Range
+{
+public:
+    //==============================================================================
+    /** Constructs an empty range. */
+    Range() noexcept  : start(), end()
+    {
+    }
+
+    /** Constructs a range with given start and end values. */
+    Range (const ValueType startValue, const ValueType endValue) noexcept
+        : start (startValue), end (jmax (startValue, endValue))
+    {
+    }
+
+    /** Constructs a copy of another range. */
+    Range (const Range& other) noexcept
+        : start (other.start), end (other.end)
+    {
+    }
+
+    /** Copies another range object. */
+    Range& operator= (Range other) noexcept
+    {
+        start = other.start;
+        end = other.end;
+        return *this;
+    }
+
+    /** Returns the range that lies between two positions (in either order). */
+    static Range between (const ValueType position1, const ValueType position2) noexcept
+    {
+        return position1 < position2 ? Range (position1, position2)
+                                     : Range (position2, position1);
+    }
+
+    /** Returns a range with a given start and length. */
+    static Range withStartAndLength (const ValueType startValue, const ValueType length) noexcept
+    {
+        jassert (length >= ValueType());
+        return Range (startValue, startValue + length);
+    }
+
+    /** Returns a range with the specified start position and a length of zero. */
+    static Range emptyRange (const ValueType start) noexcept
+    {
+        return Range (start, start);
+    }
+
+    //==============================================================================
+    /** Returns the start of the range. */
+    inline ValueType getStart() const noexcept          { return start; }
+
+    /** Returns the length of the range. */
+    inline ValueType getLength() const noexcept         { return end - start; }
+
+    /** Returns the end of the range. */
+    inline ValueType getEnd() const noexcept            { return end; }
+
+    /** Returns true if the range has a length of zero. */
+    inline bool isEmpty() const noexcept                { return start == end; }
+
+    //==============================================================================
+    /** Changes the start position of the range, leaving the end position unchanged.
+        If the new start position is higher than the current end of the range, the end point
+        will be pushed along to equal it, leaving an empty range at the new position.
+    */
+    void setStart (const ValueType newStart) noexcept
+    {
+        start = newStart;
+        if (end < newStart)
+            end = newStart;
+    }
+
+    /** Returns a range with the same end as this one, but a different start.
+        If the new start position is higher than the current end of the range, the end point
+        will be pushed along to equal it, returning an empty range at the new position.
+    */
+    Range withStart (const ValueType newStart) const noexcept
+    {
+        return Range (newStart, jmax (newStart, end));
+    }
+
+    /** Returns a range with the same length as this one, but moved to have the given start position. */
+    Range movedToStartAt (const ValueType newStart) const noexcept
+    {
+        return Range (newStart, end + (newStart - start));
+    }
+
+    /** Changes the end position of the range, leaving the start unchanged.
+        If the new end position is below the current start of the range, the start point
+        will be pushed back to equal the new end point.
+    */
+    void setEnd (const ValueType newEnd) noexcept
+    {
+        end = newEnd;
+        if (newEnd < start)
+            start = newEnd;
+    }
+
+    /** Returns a range with the same start position as this one, but a different end.
+        If the new end position is below the current start of the range, the start point
+        will be pushed back to equal the new end point.
+    */
+    Range withEnd (const ValueType newEnd) const noexcept
+    {
+        return Range (jmin (start, newEnd), newEnd);
+    }
+
+    /** Returns a range with the same length as this one, but moved to have the given end position. */
+    Range movedToEndAt (const ValueType newEnd) const noexcept
+    {
+        return Range (start + (newEnd - end), newEnd);
+    }
+
+    /** Changes the length of the range.
+        Lengths less than zero are treated as zero.
+    */
+    void setLength (const ValueType newLength) noexcept
+    {
+        end = start + jmax (ValueType(), newLength);
+    }
+
+    /** Returns a range with the same start as this one, but a different length.
+        Lengths less than zero are treated as zero.
+    */
+    Range withLength (const ValueType newLength) const noexcept
+    {
+        return Range (start, start + newLength);
+    }
+
+    //==============================================================================
+    /** Adds an amount to the start and end of the range. */
+    inline Range operator+= (const ValueType amountToAdd) noexcept
+    {
+        start += amountToAdd;
+        end += amountToAdd;
+        return *this;
+    }
+
+    /** Subtracts an amount from the start and end of the range. */
+    inline Range operator-= (const ValueType amountToSubtract) noexcept
+    {
+        start -= amountToSubtract;
+        end -= amountToSubtract;
+        return *this;
+    }
+
+    /** Returns a range that is equal to this one with an amount added to its
+        start and end.
+    */
+    Range operator+ (const ValueType amountToAdd) const noexcept
+    {
+        return Range (start + amountToAdd, end + amountToAdd);
+    }
+
+    /** Returns a range that is equal to this one with the specified amount
+        subtracted from its start and end. */
+    Range operator- (const ValueType amountToSubtract) const noexcept
+    {
+        return Range (start - amountToSubtract, end - amountToSubtract);
+    }
+
+    bool operator== (Range other) const noexcept     { return start == other.start && end == other.end; }
+    bool operator!= (Range other) const noexcept     { return start != other.start || end != other.end; }
+
+    //==============================================================================
+    /** Returns true if the given position lies inside this range. */
+    bool contains (const ValueType position) const noexcept
+    {
+        return start <= position && position < end;
+    }
+
+    /** Returns the nearest value to the one supplied, which lies within the range. */
+    ValueType clipValue (const ValueType value) const noexcept
+    {
+        return jlimit (start, end, value);
+    }
+
+    /** Returns true if the given range lies entirely inside this range.
+        When making this comparison, the start value is considered to be inclusive,
+        and the end of the range exclusive.
+     */
+    bool contains (Range other) const noexcept
+    {
+        return start <= other.start && end >= other.end;
+    }
+
+    /** Returns true if the given range intersects this one. */
+    bool intersects (Range other) const noexcept
+    {
+        return other.start < end && start < other.end;
+    }
+
+    /** Returns the range that is the intersection of the two ranges, or an empty range
+        with an undefined start position if they don't overlap. */
+    Range getIntersectionWith (Range other) const noexcept
+    {
+        return Range (jmax (start, other.start),
+                      jmin (end, other.end));
+    }
+
+    /** Returns the smallest range that contains both this one and the other one. */
+    Range getUnionWith (Range other) const noexcept
+    {
+        return Range (jmin (start, other.start),
+                      jmax (end, other.end));
+    }
+
+    /** Returns the smallest range that contains both this one and the given value. */
+    Range getUnionWith (const ValueType valueToInclude) const noexcept
+    {
+        return Range (jmin (valueToInclude, start),
+                      jmax (valueToInclude, end));
+    }
+
+    /** Returns a given range, after moving it forwards or backwards to fit it
+        within this range.
+
+        If the supplied range has a greater length than this one, the return value
+        will be this range.
+
+        Otherwise, if the supplied range is smaller than this one, the return value
+        will be the new range, shifted forwards or backwards so that it doesn't extend
+        beyond this one, but keeping its original length.
+    */
+    Range constrainRange (Range rangeToConstrain) const noexcept
+    {
+        const ValueType otherLen = rangeToConstrain.getLength();
+        return getLength() <= otherLen
+                ? *this
+                : rangeToConstrain.movedToStartAt (jlimit (start, end - otherLen, rangeToConstrain.getStart()));
+    }
+
+    /** Scans an array of values for its min and max, and returns these as a Range. */
+    static Range findMinAndMax (const ValueType* values, int numValues) noexcept
+    {
+        if (numValues <= 0)
+            return Range();
+
+        const ValueType first (*values++);
+        Range r (first, first);
+
+        while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
+        {
+            const ValueType v (*values++);
+
+            if (r.end < v)    r.end = v;
+            if (v < r.start)  r.start = v;
+        }
+
+        return r;
+    }
+
+private:
+    //==============================================================================
+    ValueType start, end;
+};
+
+
+#endif   // JUCE_RANGE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_Atomic.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_Atomic.h
new file mode 100644
index 0000000..d0dd6be
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_Atomic.h
@@ -0,0 +1,399 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_ATOMIC_H_INCLUDED
+#define JUCE_ATOMIC_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Simple class to hold a primitive value and perform atomic operations on it.
+
+    The type used must be a 32 or 64 bit primitive, like an int, pointer, etc.
+    There are methods to perform most of the basic atomic operations.
+*/
+template <typename Type>
+class Atomic
+{
+public:
+    /** Creates a new value, initialised to zero. */
+    inline Atomic() noexcept
+        : value (0)
+    {
+    }
+
+    /** Creates a new value, with a given initial value. */
+    inline explicit Atomic (const Type initialValue) noexcept
+        : value (initialValue)
+    {
+    }
+
+    /** Copies another value (atomically). */
+    inline Atomic (const Atomic& other) noexcept
+        : value (other.get())
+    {
+    }
+
+    /** Destructor. */
+    inline ~Atomic() noexcept
+    {
+        // This class can only be used for types which are 32 or 64 bits in size.
+        static_jassert (sizeof (Type) == 4 || sizeof (Type) == 8);
+    }
+
+    /** Atomically reads and returns the current value. */
+    Type get() const noexcept;
+
+    /** Copies another value onto this one (atomically). */
+    inline Atomic& operator= (const Atomic& other) noexcept         { exchange (other.get()); return *this; }
+
+    /** Copies another value onto this one (atomically). */
+    inline Atomic& operator= (const Type newValue) noexcept         { exchange (newValue); return *this; }
+
+    /** Atomically sets the current value. */
+    void set (Type newValue) noexcept                               { exchange (newValue); }
+
+    /** Atomically sets the current value, returning the value that was replaced. */
+    Type exchange (Type value) noexcept;
+
+    /** Atomically adds a number to this value, returning the new value. */
+    Type operator+= (Type amountToAdd) noexcept;
+
+    /** Atomically subtracts a number from this value, returning the new value. */
+    Type operator-= (Type amountToSubtract) noexcept;
+
+    /** Atomically increments this value, returning the new value. */
+    Type operator++() noexcept;
+
+    /** Atomically decrements this value, returning the new value. */
+    Type operator--() noexcept;
+
+    /** Atomically compares this value with a target value, and if it is equal, sets
+        this to be equal to a new value.
+
+        This operation is the atomic equivalent of doing this:
+        @code
+        bool compareAndSetBool (Type newValue, Type valueToCompare)
+        {
+            if (get() == valueToCompare)
+            {
+                set (newValue);
+                return true;
+            }
+
+            return false;
+        }
+        @endcode
+
+        @returns true if the comparison was true and the value was replaced; false if
+                 the comparison failed and the value was left unchanged.
+        @see compareAndSetValue
+    */
+    bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept;
+
+    /** Atomically compares this value with a target value, and if it is equal, sets
+        this to be equal to a new value.
+
+        This operation is the atomic equivalent of doing this:
+        @code
+        Type compareAndSetValue (Type newValue, Type valueToCompare)
+        {
+            Type oldValue = get();
+            if (oldValue == valueToCompare)
+                set (newValue);
+
+            return oldValue;
+        }
+        @endcode
+
+        @returns the old value before it was changed.
+        @see compareAndSetBool
+    */
+    Type compareAndSetValue (Type newValue, Type valueToCompare) noexcept;
+
+    /** Implements a memory read/write barrier. */
+    static void memoryBarrier() noexcept;
+
+    //==============================================================================
+   #if JUCE_64BIT
+    JUCE_ALIGN (8)
+   #else
+    JUCE_ALIGN (4)
+   #endif
+
+    /** The raw value that this class operates on.
+        This is exposed publically in case you need to manipulate it directly
+        for performance reasons.
+    */
+    volatile Type value;
+
+private:
+    template <typename Dest, typename Source>
+    static inline Dest castTo (Source value) noexcept         { union { Dest d; Source s; } u; u.s = value; return u.d; }
+
+    static inline Type castFrom32Bit (int32 value) noexcept   { return castTo <Type, int32> (value); }
+    static inline Type castFrom64Bit (int64 value) noexcept   { return castTo <Type, int64> (value); }
+    static inline int32 castTo32Bit (Type value) noexcept     { return castTo <int32, Type> (value); }
+    static inline int64 castTo64Bit (Type value) noexcept     { return castTo <int64, Type> (value); }
+
+    Type operator++ (int); // better to just use pre-increment with atomics..
+    Type operator-- (int);
+
+    /** This templated negate function will negate pointers as well as integers */
+    template <typename ValueType>
+    inline ValueType negateValue (ValueType n) noexcept
+    {
+        return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n
+            : (sizeof (ValueType) == 2 ? (ValueType) -(short) n
+            : (sizeof (ValueType) == 4 ? (ValueType) -(int) n
+            : ((ValueType) -(int64) n)));
+    }
+
+    /** This templated negate function will negate pointers as well as integers */
+    template <typename PointerType>
+    inline PointerType* negateValue (PointerType* n) noexcept
+    {
+        return reinterpret_cast <PointerType*> (-reinterpret_cast <pointer_sized_int> (n));
+    }
+};
+
+
+//==============================================================================
+/*
+    The following code is in the header so that the atomics can be inlined where possible...
+*/
+#if JUCE_MAC && (JUCE_PPC || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
+  #define JUCE_ATOMICS_MAC_LEGACY 1      // Older OSX builds using gcc4.1 or earlier
+
+  #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
+    #define JUCE_MAC_ATOMICS_VOLATILE
+  #else
+    #define JUCE_MAC_ATOMICS_VOLATILE volatile
+  #endif
+
+  #if JUCE_PPC
+    // None of these atomics are available for PPC or for iOS 3.1 or earlier!!
+    template <typename Type> static Type OSAtomicAdd64Barrier (Type b, JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept  { jassertfalse; return *a += b; }
+    template <typename Type> static Type OSAtomicIncrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept    { jassertfalse; return ++*a; }
+    template <typename Type> static Type OSAtomicDecrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept    { jassertfalse; return --*a; }
+    template <typename Type> static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, JUCE_MAC_ATOMICS_VOLATILE Type* value) noexcept
+        { jassertfalse; if (old == *value) { *value = newValue; return true; } return false; }
+    #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
+  #endif
+
+//==============================================================================
+#elif JUCE_GCC || JUCE_CLANG
+  #define JUCE_ATOMICS_GCC 1        // GCC with intrinsics
+
+  #if JUCE_IOS || JUCE_ANDROID // (64-bit ops will compile but not link on these mobile OSes)
+    #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
+  #endif
+
+//==============================================================================
+#else
+  #define JUCE_ATOMICS_WINDOWS 1    // Windows with intrinsics
+
+  #if JUCE_USE_INTRINSICS
+    #ifndef __INTEL_COMPILER
+     #pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
+                        _InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
+    #endif
+    #define juce_InterlockedExchange(a, b)              _InterlockedExchange(a, b)
+    #define juce_InterlockedIncrement(a)                _InterlockedIncrement(a)
+    #define juce_InterlockedDecrement(a)                _InterlockedDecrement(a)
+    #define juce_InterlockedExchangeAdd(a, b)           _InterlockedExchangeAdd(a, b)
+    #define juce_InterlockedCompareExchange(a, b, c)    _InterlockedCompareExchange(a, b, c)
+    #define juce_InterlockedCompareExchange64(a, b, c)  _InterlockedCompareExchange64(a, b, c)
+    #define juce_MemoryBarrier _ReadWriteBarrier
+  #else
+    long juce_InterlockedExchange (volatile long* a, long b) noexcept;
+    long juce_InterlockedIncrement (volatile long* a) noexcept;
+    long juce_InterlockedDecrement (volatile long* a) noexcept;
+    long juce_InterlockedExchangeAdd (volatile long* a, long b) noexcept;
+    long juce_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept;
+    __int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) noexcept;
+    inline void juce_MemoryBarrier() noexcept  { long x = 0; juce_InterlockedIncrement (&x); }
+  #endif
+
+  #if JUCE_64BIT
+    #ifndef __INTEL_COMPILER
+     #pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64)
+    #endif
+    #define juce_InterlockedExchangeAdd64(a, b)     _InterlockedExchangeAdd64(a, b)
+    #define juce_InterlockedExchange64(a, b)        _InterlockedExchange64(a, b)
+    #define juce_InterlockedIncrement64(a)          _InterlockedIncrement64(a)
+    #define juce_InterlockedDecrement64(a)          _InterlockedDecrement64(a)
+  #else
+    // None of these atomics are available in a 32-bit Windows build!!
+    template <typename Type> static Type juce_InterlockedExchangeAdd64 (volatile Type* a, Type b) noexcept  { jassertfalse; Type old = *a; *a += b; return old; }
+    template <typename Type> static Type juce_InterlockedExchange64 (volatile Type* a, Type b) noexcept     { jassertfalse; Type old = *a; *a = b; return old; }
+    template <typename Type> static Type juce_InterlockedIncrement64 (volatile Type* a) noexcept            { jassertfalse; return ++*a; }
+    template <typename Type> static Type juce_InterlockedDecrement64 (volatile Type* a) noexcept            { jassertfalse; return --*a; }
+    #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
+  #endif
+#endif
+
+
+#if JUCE_MSVC
+  #pragma warning (push)
+  #pragma warning (disable: 4311)  // (truncation warning)
+#endif
+
+//==============================================================================
+template <typename Type>
+inline Type Atomic<Type>::get() const noexcept
+{
+  #if JUCE_ATOMICS_MAC_LEGACY
+    return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value))
+                              : castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value));
+  #elif JUCE_ATOMICS_WINDOWS
+    return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0))
+                              : castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0));
+  #elif JUCE_ATOMICS_GCC
+    return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0))
+                              : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0));
+  #endif
+}
+
+template <typename Type>
+inline Type Atomic<Type>::exchange (const Type newValue) noexcept
+{
+  #if JUCE_ATOMICS_MAC_LEGACY || JUCE_ATOMICS_GCC
+    Type currentVal = value;
+    while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
+    return currentVal;
+  #elif JUCE_ATOMICS_WINDOWS
+    return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue)))
+                              : castFrom64Bit ((int64) juce_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue)));
+  #endif
+}
+
+template <typename Type>
+inline Type Atomic<Type>::operator+= (const Type amountToAdd) noexcept
+{
+  #if JUCE_ATOMICS_MAC_LEGACY
+    return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
+                              : (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
+  #elif JUCE_ATOMICS_WINDOWS
+    return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd)
+                              : (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd);
+  #elif JUCE_ATOMICS_GCC
+    return (Type) __sync_add_and_fetch (&value, amountToAdd);
+  #endif
+}
+
+template <typename Type>
+inline Type Atomic<Type>::operator-= (const Type amountToSubtract) noexcept
+{
+    return operator+= (negateValue (amountToSubtract));
+}
+
+template <typename Type>
+inline Type Atomic<Type>::operator++() noexcept
+{
+  #if JUCE_ATOMICS_MAC_LEGACY
+    return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
+                              : (Type) OSAtomicIncrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
+  #elif JUCE_ATOMICS_WINDOWS
+    return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value)
+                              : (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value);
+  #elif JUCE_ATOMICS_GCC
+    return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (&value, (Type) 1)
+                              : (Type) __sync_add_and_fetch ((int64_t*) &value, 1);
+  #endif
+}
+
+template <typename Type>
+inline Type Atomic<Type>::operator--() noexcept
+{
+  #if JUCE_ATOMICS_MAC_LEGACY
+    return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
+                              : (Type) OSAtomicDecrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
+  #elif JUCE_ATOMICS_WINDOWS
+    return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value)
+                              : (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value);
+  #elif JUCE_ATOMICS_GCC
+    return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (&value, (Type) -1)
+                              : (Type) __sync_add_and_fetch ((int64_t*) &value, -1);
+  #endif
+}
+
+template <typename Type>
+inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept
+{
+  #if JUCE_ATOMICS_MAC_LEGACY
+    return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
+                              : OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
+  #elif JUCE_ATOMICS_WINDOWS
+    return compareAndSetValue (newValue, valueToCompare) == valueToCompare;
+  #elif JUCE_ATOMICS_GCC
+    return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))
+                              : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue));
+  #endif
+}
+
+template <typename Type>
+inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept
+{
+  #if JUCE_ATOMICS_MAC_LEGACY
+    for (;;) // Annoying workaround for only having a bool CAS operation..
+    {
+        if (compareAndSetBool (newValue, valueToCompare))
+            return valueToCompare;
+
+        const Type result = value;
+        if (result != valueToCompare)
+            return result;
+    }
+
+  #elif JUCE_ATOMICS_WINDOWS
+    return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare)))
+                              : castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare)));
+  #elif JUCE_ATOMICS_GCC
+    return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)))
+                              : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)));
+  #endif
+}
+
+template <typename Type>
+inline void Atomic<Type>::memoryBarrier() noexcept
+{
+  #if JUCE_ATOMICS_MAC_LEGACY
+    OSMemoryBarrier();
+  #elif JUCE_ATOMICS_GCC
+    __sync_synchronize();
+  #elif JUCE_ATOMICS_WINDOWS
+    juce_MemoryBarrier();
+  #endif
+}
+
+#if JUCE_MSVC
+  #pragma warning (pop)
+#endif
+
+#endif   // JUCE_ATOMIC_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ByteOrder.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ByteOrder.h
new file mode 100644
index 0000000..0ecf2e4
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ByteOrder.h
@@ -0,0 +1,196 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_BYTEORDER_H_INCLUDED
+#define JUCE_BYTEORDER_H_INCLUDED
+
+
+//==============================================================================
+/** Contains static methods for converting the byte order between different
+    endiannesses.
+*/
+class JUCE_API  ByteOrder
+{
+public:
+    //==============================================================================
+    /** Swaps the upper and lower bytes of a 16-bit integer. */
+    static uint16 swap (uint16 value) noexcept;
+
+    /** Reverses the order of the 4 bytes in a 32-bit integer. */
+    static uint32 swap (uint32 value) noexcept;
+
+    /** Reverses the order of the 8 bytes in a 64-bit integer. */
+    static uint64 swap (uint64 value) noexcept;
+
+    //==============================================================================
+    /** Swaps the byte order of a 16-bit int if the CPU is big-endian */
+    static uint16 swapIfBigEndian (uint16 value) noexcept;
+
+    /** Swaps the byte order of a 32-bit int if the CPU is big-endian */
+    static uint32 swapIfBigEndian (uint32 value) noexcept;
+
+    /** Swaps the byte order of a 64-bit int if the CPU is big-endian */
+    static uint64 swapIfBigEndian (uint64 value) noexcept;
+
+    /** Swaps the byte order of a 16-bit int if the CPU is little-endian */
+    static uint16 swapIfLittleEndian (uint16 value) noexcept;
+
+    /** Swaps the byte order of a 32-bit int if the CPU is little-endian */
+    static uint32 swapIfLittleEndian (uint32 value) noexcept;
+
+    /** Swaps the byte order of a 64-bit int if the CPU is little-endian */
+    static uint64 swapIfLittleEndian (uint64 value) noexcept;
+
+    //==============================================================================
+    /** Turns 4 bytes into a little-endian integer. */
+    static uint32 littleEndianInt (const void* bytes) noexcept;
+
+    /** Turns 8 bytes into a little-endian integer. */
+    static uint64 littleEndianInt64 (const void* bytes) noexcept;
+
+    /** Turns 2 bytes into a little-endian integer. */
+    static uint16 littleEndianShort (const void* bytes) noexcept;
+
+    /** Turns 4 bytes into a big-endian integer. */
+    static uint32 bigEndianInt (const void* bytes) noexcept;
+
+    /** Turns 8 bytes into a big-endian integer. */
+    static uint64 bigEndianInt64 (const void* bytes) noexcept;
+
+    /** Turns 2 bytes into a big-endian integer. */
+    static uint16 bigEndianShort (const void* bytes) noexcept;
+
+    //==============================================================================
+    /** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
+    static int littleEndian24Bit (const void* bytes) noexcept;
+
+    /** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
+    static int bigEndian24Bit (const void* bytes) noexcept;
+
+    /** Copies a 24-bit number to 3 little-endian bytes. */
+    static void littleEndian24BitToChars (int value, void* destBytes) noexcept;
+
+    /** Copies a 24-bit number to 3 big-endian bytes. */
+    static void bigEndian24BitToChars (int value, void* destBytes) noexcept;
+
+    //==============================================================================
+    /** Returns true if the current CPU is big-endian. */
+    static bool isBigEndian() noexcept;
+
+private:
+    ByteOrder() JUCE_DELETED_FUNCTION;
+
+    JUCE_DECLARE_NON_COPYABLE (ByteOrder)
+};
+
+
+//==============================================================================
+#if JUCE_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
+ #pragma intrinsic (_byteswap_ulong)
+#endif
+
+inline uint16 ByteOrder::swap (uint16 n) noexcept
+{
+   #if JUCE_USE_INTRINSICSxxx // agh - the MS compiler has an internal error when you try to use this intrinsic!
+    return static_cast<uint16> (_byteswap_ushort (n));
+   #else
+    return static_cast<uint16> ((n << 8) | (n >> 8));
+   #endif
+}
+
+inline uint32 ByteOrder::swap (uint32 n) noexcept
+{
+   #if JUCE_MAC || JUCE_IOS
+    return OSSwapInt32 (n);
+   #elif JUCE_GCC && JUCE_INTEL && ! JUCE_NO_INLINE_ASM
+    asm("bswap %%eax" : "=a"(n) : "a"(n));
+    return n;
+   #elif JUCE_USE_INTRINSICS
+    return _byteswap_ulong (n);
+   #elif JUCE_MSVC && ! JUCE_NO_INLINE_ASM
+    __asm {
+        mov eax, n
+        bswap eax
+        mov n, eax
+    }
+    return n;
+   #elif JUCE_ANDROID
+    return bswap_32 (n);
+   #else
+    return (n << 24) | (n >> 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8);
+   #endif
+}
+
+inline uint64 ByteOrder::swap (uint64 value) noexcept
+{
+   #if JUCE_MAC || JUCE_IOS
+    return OSSwapInt64 (value);
+   #elif JUCE_USE_INTRINSICS
+    return _byteswap_uint64 (value);
+   #else
+    return (((int64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32));
+   #endif
+}
+
+#if JUCE_LITTLE_ENDIAN
+ inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) noexcept                                  { return v; }
+ inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) noexcept                                  { return v; }
+ inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) noexcept                                  { return v; }
+ inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) noexcept                               { return swap (v); }
+ inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) noexcept                               { return swap (v); }
+ inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) noexcept                               { return swap (v); }
+ inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept                         { return *static_cast<const uint32*> (bytes); }
+ inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept                       { return *static_cast<const uint64*> (bytes); }
+ inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept                       { return *static_cast<const uint16*> (bytes); }
+ inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept                            { return swap (*static_cast<const uint32*> (bytes)); }
+ inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept                          { return swap (*static_cast<const uint64*> (bytes)); }
+ inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept                          { return swap (*static_cast<const uint16*> (bytes)); }
+ inline bool ByteOrder::isBigEndian() noexcept                                                       { return false; }
+#else
+ inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) noexcept                                  { return swap (v); }
+ inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) noexcept                                  { return swap (v); }
+ inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) noexcept                                  { return swap (v); }
+ inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) noexcept                               { return v; }
+ inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) noexcept                               { return v; }
+ inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) noexcept                               { return v; }
+ inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept                         { return swap (*static_cast<const uint32*> (bytes)); }
+ inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept                       { return swap (*static_cast<const uint64*> (bytes)); }
+ inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept                       { return swap (*static_cast<const uint16*> (bytes)); }
+ inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept                            { return *static_cast<const uint32*> (bytes); }
+ inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept                          { return *static_cast<const uint64*> (bytes); }
+ inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept                          { return *static_cast<const uint16*> (bytes); }
+ inline bool ByteOrder::isBigEndian() noexcept                                                       { return true; }
+#endif
+
+inline int  ByteOrder::littleEndian24Bit (const void* const bytes) noexcept                          { return (((int) static_cast<const int8*> (bytes)[2]) << 16) | (((int) static_cast<const uint8*> (bytes)[1]) << 8) | ((int) static_cast<const uint8*> (bytes)[0]); }
+inline int  ByteOrder::bigEndian24Bit (const void* const bytes) noexcept                             { return (((int) static_cast<const int8*> (bytes)[0]) << 16) | (((int) static_cast<const uint8*> (bytes)[1]) << 8) | ((int) static_cast<const uint8*> (bytes)[2]); }
+inline void ByteOrder::littleEndian24BitToChars (const int value, void* const destBytes) noexcept    { static_cast<uint8*> (destBytes)[0] = (uint8) value;         static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) (value >> 16); }
+inline void ByteOrder::bigEndian24BitToChars (const int value, void* const destBytes) noexcept       { static_cast<uint8*> (destBytes)[0] = (uint8) (value >> 16); static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) value; }
+
+
+#endif   // JUCE_BYTEORDER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ContainerDeletePolicy.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ContainerDeletePolicy.h
new file mode 100644
index 0000000..60cddaa
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ContainerDeletePolicy.h
@@ -0,0 +1,53 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_CONTAINERDELETEPOLICY_H_INCLUDED
+#define JUCE_CONTAINERDELETEPOLICY_H_INCLUDED
+
+//==============================================================================
+/**
+    Used by container classes as an indirect way to delete an object of a
+    particular type.
+
+    The generic implementation of this class simply calls 'delete', but you can
+    create a specialised version of it for a particular class if you need to
+    delete that type of object in a more appropriate way.
+
+    @see ScopedPointer, OwnedArray
+*/
+template <typename ObjectType>
+struct ContainerDeletePolicy
+{
+    static void destroy (ObjectType* object)
+    {
+        delete object;
+    }
+};
+
+
+#endif   // JUCE_CONTAINERDELETEPOLICY_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_HeapBlock.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_HeapBlock.h
new file mode 100644
index 0000000..3731f0b
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_HeapBlock.h
@@ -0,0 +1,308 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_HEAPBLOCK_H_INCLUDED
+#define JUCE_HEAPBLOCK_H_INCLUDED
+
+#ifndef DOXYGEN
+namespace HeapBlockHelper
+{
+    template <bool shouldThrow>
+    struct ThrowOnFail          { static void check (void*) {} };
+
+    template<>
+    struct ThrowOnFail <true>   { static void check (void* data) { if (data == nullptr) throw std::bad_alloc(); } };
+}
+#endif
+
+//==============================================================================
+/**
+    Very simple container class to hold a pointer to some data on the heap.
+
+    When you need to allocate some heap storage for something, always try to use
+    this class instead of allocating the memory directly using malloc/free.
+
+    A HeapBlock<char> object can be treated in pretty much exactly the same way
+    as an char*, but as long as you allocate it on the stack or as a class member,
+    it's almost impossible for it to leak memory.
+
+    It also makes your code much more concise and readable than doing the same thing
+    using direct allocations,
+
+    E.g. instead of this:
+    @code
+        int* temp = (int*) malloc (1024 * sizeof (int));
+        memcpy (temp, xyz, 1024 * sizeof (int));
+        free (temp);
+        temp = (int*) calloc (2048 * sizeof (int));
+        temp[0] = 1234;
+        memcpy (foobar, temp, 2048 * sizeof (int));
+        free (temp);
+    @endcode
+
+    ..you could just write this:
+    @code
+        HeapBlock <int> temp (1024);
+        memcpy (temp, xyz, 1024 * sizeof (int));
+        temp.calloc (2048);
+        temp[0] = 1234;
+        memcpy (foobar, temp, 2048 * sizeof (int));
+    @endcode
+
+    The class is extremely lightweight, containing only a pointer to the
+    data, and exposes malloc/realloc/calloc/free methods that do the same jobs
+    as their less object-oriented counterparts. Despite adding safety, you probably
+    won't sacrifice any performance by using this in place of normal pointers.
+
+    The throwOnFailure template parameter can be set to true if you'd like the class
+    to throw a std::bad_alloc exception when an allocation fails. If this is false,
+    then a failed allocation will just leave the heapblock with a null pointer (assuming
+    that the system's malloc() function doesn't throw).
+
+    @see Array, OwnedArray, MemoryBlock
+*/
+template <class ElementType, bool throwOnFailure = false>
+class HeapBlock
+{
+public:
+    //==============================================================================
+    /** Creates a HeapBlock which is initially just a null pointer.
+
+        After creation, you can resize the array using the malloc(), calloc(),
+        or realloc() methods.
+    */
+    HeapBlock() noexcept  : data (nullptr)
+    {
+    }
+
+    /** Creates a HeapBlock containing a number of elements.
+
+        The contents of the block are undefined, as it will have been created by a
+        malloc call.
+
+        If you want an array of zero values, you can use the calloc() method or the
+        other constructor that takes an InitialisationState parameter.
+    */
+    explicit HeapBlock (const size_t numElements)
+        : data (static_cast <ElementType*> (std::malloc (numElements * sizeof (ElementType))))
+    {
+        throwOnAllocationFailure();
+    }
+
+    /** Creates a HeapBlock containing a number of elements.
+
+        The initialiseToZero parameter determines whether the new memory should be cleared,
+        or left uninitialised.
+    */
+    HeapBlock (const size_t numElements, const bool initialiseToZero)
+        : data (static_cast <ElementType*> (initialiseToZero
+                                               ? std::calloc (numElements, sizeof (ElementType))
+                                               : std::malloc (numElements * sizeof (ElementType))))
+    {
+        throwOnAllocationFailure();
+    }
+
+    /** Destructor.
+        This will free the data, if any has been allocated.
+    */
+    ~HeapBlock()
+    {
+        std::free (data);
+    }
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    HeapBlock (HeapBlock&& other) noexcept
+        : data (other.data)
+    {
+        other.data = nullptr;
+    }
+
+    HeapBlock& operator= (HeapBlock&& other) noexcept
+    {
+        std::swap (data, other.data);
+        return *this;
+    }
+   #endif
+
+    //==============================================================================
+    /** Returns a raw pointer to the allocated data.
+        This may be a null pointer if the data hasn't yet been allocated, or if it has been
+        freed by calling the free() method.
+    */
+    inline operator ElementType*() const noexcept                           { return data; }
+
+    /** Returns a raw pointer to the allocated data.
+        This may be a null pointer if the data hasn't yet been allocated, or if it has been
+        freed by calling the free() method.
+    */
+    inline ElementType* getData() const noexcept                            { return data; }
+
+    /** Returns a void pointer to the allocated data.
+        This may be a null pointer if the data hasn't yet been allocated, or if it has been
+        freed by calling the free() method.
+    */
+    inline operator void*() const noexcept                                  { return static_cast <void*> (data); }
+
+    /** Returns a void pointer to the allocated data.
+        This may be a null pointer if the data hasn't yet been allocated, or if it has been
+        freed by calling the free() method.
+    */
+    inline operator const void*() const noexcept                            { return static_cast <const void*> (data); }
+
+    /** Lets you use indirect calls to the first element in the array.
+        Obviously this will cause problems if the array hasn't been initialised, because it'll
+        be referencing a null pointer.
+    */
+    inline ElementType* operator->() const  noexcept                        { return data; }
+
+    /** Returns a reference to one of the data elements.
+        Obviously there's no bounds-checking here, as this object is just a dumb pointer and
+        has no idea of the size it currently has allocated.
+    */
+    template <typename IndexType>
+    inline ElementType& operator[] (IndexType index) const noexcept         { return data [index]; }
+
+    /** Returns a pointer to a data element at an offset from the start of the array.
+        This is the same as doing pointer arithmetic on the raw pointer itself.
+    */
+    template <typename IndexType>
+    inline ElementType* operator+ (IndexType index) const noexcept          { return data + index; }
+
+    //==============================================================================
+    /** Compares the pointer with another pointer.
+        This can be handy for checking whether this is a null pointer.
+    */
+    inline bool operator== (const ElementType* const otherPointer) const noexcept   { return otherPointer == data; }
+
+    /** Compares the pointer with another pointer.
+        This can be handy for checking whether this is a null pointer.
+    */
+    inline bool operator!= (const ElementType* const otherPointer) const noexcept   { return otherPointer != data; }
+
+    //==============================================================================
+    /** Allocates a specified amount of memory.
+
+        This uses the normal malloc to allocate an amount of memory for this object.
+        Any previously allocated memory will be freed by this method.
+
+        The number of bytes allocated will be (newNumElements * elementSize). Normally
+        you wouldn't need to specify the second parameter, but it can be handy if you need
+        to allocate a size in bytes rather than in terms of the number of elements.
+
+        The data that is allocated will be freed when this object is deleted, or when you
+        call free() or any of the allocation methods.
+    */
+    void malloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
+    {
+        std::free (data);
+        data = static_cast <ElementType*> (std::malloc (newNumElements * elementSize));
+        throwOnAllocationFailure();
+    }
+
+    /** Allocates a specified amount of memory and clears it.
+        This does the same job as the malloc() method, but clears the memory that it allocates.
+    */
+    void calloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
+    {
+        std::free (data);
+        data = static_cast <ElementType*> (std::calloc (newNumElements, elementSize));
+        throwOnAllocationFailure();
+    }
+
+    /** Allocates a specified amount of memory and optionally clears it.
+        This does the same job as either malloc() or calloc(), depending on the
+        initialiseToZero parameter.
+    */
+    void allocate (const size_t newNumElements, bool initialiseToZero)
+    {
+        std::free (data);
+        data = static_cast <ElementType*> (initialiseToZero
+                                             ? std::calloc (newNumElements, sizeof (ElementType))
+                                             : std::malloc (newNumElements * sizeof (ElementType)));
+        throwOnAllocationFailure();
+    }
+
+    /** Re-allocates a specified amount of memory.
+
+        The semantics of this method are the same as malloc() and calloc(), but it
+        uses realloc() to keep as much of the existing data as possible.
+    */
+    void realloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
+    {
+        data = static_cast <ElementType*> (data == nullptr ? std::malloc (newNumElements * elementSize)
+                                                           : std::realloc (data, newNumElements * elementSize));
+        throwOnAllocationFailure();
+    }
+
+    /** Frees any currently-allocated data.
+        This will free the data and reset this object to be a null pointer.
+    */
+    void free()
+    {
+        std::free (data);
+        data = nullptr;
+    }
+
+    /** Swaps this object's data with the data of another HeapBlock.
+        The two objects simply exchange their data pointers.
+    */
+    template <bool otherBlockThrows>
+    void swapWith (HeapBlock <ElementType, otherBlockThrows>& other) noexcept
+    {
+        std::swap (data, other.data);
+    }
+
+    /** This fills the block with zeros, up to the number of elements specified.
+        Since the block has no way of knowing its own size, you must make sure that the number of
+        elements you specify doesn't exceed the allocated size.
+    */
+    void clear (size_t numElements) noexcept
+    {
+        zeromem (data, sizeof (ElementType) * numElements);
+    }
+
+    /** This typedef can be used to get the type of the heapblock's elements. */
+    typedef ElementType Type;
+
+private:
+    //==============================================================================
+    ElementType* data;
+
+    void throwOnAllocationFailure() const
+    {
+        HeapBlockHelper::ThrowOnFail<throwOnFailure>::check (data);
+    }
+
+   #if ! (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD))
+    JUCE_DECLARE_NON_COPYABLE (HeapBlock)
+    JUCE_PREVENT_HEAP_ALLOCATION // Creating a 'new HeapBlock' would be missing the point!
+   #endif
+};
+
+
+#endif   // JUCE_HEAPBLOCK_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_LeakedObjectDetector.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_LeakedObjectDetector.h
new file mode 100644
index 0000000..248e7bc
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_LeakedObjectDetector.h
@@ -0,0 +1,146 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_LEAKEDOBJECTDETECTOR_H_INCLUDED
+#define JUCE_LEAKEDOBJECTDETECTOR_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Embedding an instance of this class inside another class can be used as a low-overhead
+    way of detecting leaked instances.
+
+    This class keeps an internal static count of the number of instances that are
+    active, so that when the app is shutdown and the static destructors are called,
+    it can check whether there are any left-over instances that may have been leaked.
+
+    To use it, use the JUCE_LEAK_DETECTOR macro as a simple way to put one in your
+    class declaration. Have a look through the juce codebase for examples, it's used
+    in most of the classes.
+*/
+template <class OwnerClass>
+class LeakedObjectDetector
+{
+public:
+    //==============================================================================
+    LeakedObjectDetector() noexcept                                 { ++(getCounter().numObjects); }
+    LeakedObjectDetector (const LeakedObjectDetector&) noexcept     { ++(getCounter().numObjects); }
+
+    ~LeakedObjectDetector()
+    {
+        if (--(getCounter().numObjects) < 0)
+        {
+            DBG ("*** Dangling pointer deletion! Class: " << getLeakedObjectClassName());
+
+            /** If you hit this, then you've managed to delete more instances of this class than you've
+                created.. That indicates that you're deleting some dangling pointers.
+
+                Note that although this assertion will have been triggered during a destructor, it might
+                not be this particular deletion that's at fault - the incorrect one may have happened
+                at an earlier point in the program, and simply not been detected until now.
+
+                Most errors like this are caused by using old-fashioned, non-RAII techniques for
+                your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
+                ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
+            */
+            jassertfalse;
+        }
+    }
+
+private:
+    //==============================================================================
+    class LeakCounter
+    {
+    public:
+        LeakCounter() noexcept {}
+
+        ~LeakCounter()
+        {
+            if (numObjects.value > 0)
+            {
+                DBG ("*** Leaked objects detected: " << numObjects.value << " instance(s) of class " << getLeakedObjectClassName());
+
+                /** If you hit this, then you've leaked one or more objects of the type specified by
+                    the 'OwnerClass' template parameter - the name should have been printed by the line above.
+
+                    If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for
+                    your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
+                    ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
+                */
+                jassertfalse;
+            }
+        }
+
+        Atomic<int> numObjects;
+    };
+
+    static const char* getLeakedObjectClassName()
+    {
+        return OwnerClass::getLeakedObjectClassName();
+    }
+
+    static LeakCounter& getCounter() noexcept
+    {
+        static LeakCounter counter;
+        return counter;
+    }
+};
+
+//==============================================================================
+#if DOXYGEN || ! defined (JUCE_LEAK_DETECTOR)
+ #if (DOXYGEN || JUCE_CHECK_MEMORY_LEAKS)
+  /** This macro lets you embed a leak-detecting object inside a class.
+
+      To use it, simply declare a JUCE_LEAK_DETECTOR(YourClassName) inside a private section
+      of the class declaration. E.g.
+
+      @code
+      class MyClass
+      {
+      public:
+          MyClass();
+          void blahBlah();
+
+      private:
+          JUCE_LEAK_DETECTOR (MyClass)
+      };
+      @endcode
+
+      @see JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR, LeakedObjectDetector
+  */
+  #define JUCE_LEAK_DETECTOR(OwnerClass) \
+        friend class juce::LeakedObjectDetector<OwnerClass>; \
+        static const char* getLeakedObjectClassName() noexcept { return #OwnerClass; } \
+        juce::LeakedObjectDetector<OwnerClass> JUCE_JOIN_MACRO (leakDetector, __LINE__);
+ #else
+  #define JUCE_LEAK_DETECTOR(OwnerClass)
+ #endif
+#endif
+
+
+#endif   // JUCE_LEAKEDOBJECTDETECTOR_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_Memory.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_Memory.h
new file mode 100644
index 0000000..57d1644
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_Memory.h
@@ -0,0 +1,126 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_MEMORY_H_INCLUDED
+#define JUCE_MEMORY_H_INCLUDED
+
+//==============================================================================
+/** Fills a block of memory with zeros. */
+inline void zeromem (void* memory, size_t numBytes) noexcept        { memset (memory, 0, numBytes); }
+
+/** Overwrites a structure or object with zeros. */
+template <typename Type>
+inline void zerostruct (Type& structure) noexcept                   { memset (&structure, 0, sizeof (structure)); }
+
+/** Delete an object pointer, and sets the pointer to null.
+
+    Remember that it's not good c++ practice to use delete directly - always try to use a ScopedPointer
+    or other automatic lifetime-management system rather than resorting to deleting raw pointers!
+*/
+template <typename Type>
+inline void deleteAndZero (Type& pointer)                           { delete pointer; pointer = nullptr; }
+
+/** A handy function which adds a number of bytes to any type of pointer and returns the result.
+    This can be useful to avoid casting pointers to a char* and back when you want to move them by
+    a specific number of bytes,
+*/
+template <typename Type, typename IntegerType>
+inline Type* addBytesToPointer (Type* pointer, IntegerType bytes) noexcept  { return (Type*) (((char*) pointer) + bytes); }
+
+/** A handy function which returns the difference between any two pointers, in bytes.
+    The address of the second pointer is subtracted from the first, and the difference in bytes is returned.
+*/
+template <typename Type1, typename Type2>
+inline int getAddressDifference (Type1* pointer1, Type2* pointer2) noexcept  { return (int) (((const char*) pointer1) - (const char*) pointer2); }
+
+/** If a pointer is non-null, this returns a new copy of the object that it points to, or safely returns
+    nullptr if the pointer is null.
+*/
+template <class Type>
+inline Type* createCopyIfNotNull (const Type* pointer)     { return pointer != nullptr ? new Type (*pointer) : nullptr; }
+
+//==============================================================================
+#if JUCE_MAC || JUCE_IOS || DOXYGEN
+
+ /** A handy C++ wrapper that creates and deletes an NSAutoreleasePool object using RAII.
+     You should use the JUCE_AUTORELEASEPOOL macro to create a local auto-release pool on the stack.
+ */
+ class JUCE_API  ScopedAutoReleasePool
+ {
+ public:
+     ScopedAutoReleasePool();
+     ~ScopedAutoReleasePool();
+
+ private:
+     void* pool;
+
+     JUCE_DECLARE_NON_COPYABLE (ScopedAutoReleasePool)
+ };
+
+ /** A macro that can be used to easily declare a local ScopedAutoReleasePool
+     object for RAII-based obj-C autoreleasing.
+     Because this may use the \@autoreleasepool syntax, you must follow the macro with
+     a set of braces to mark the scope of the pool.
+ */
+#if (JUCE_COMPILER_SUPPORTS_ARC && defined (__OBJC__)) || DOXYGEN
+ #define JUCE_AUTORELEASEPOOL  @autoreleasepool
+#else
+ #define JUCE_AUTORELEASEPOOL  const juce::ScopedAutoReleasePool JUCE_JOIN_MACRO (autoReleasePool_, __LINE__);
+#endif
+
+#else
+ #define JUCE_AUTORELEASEPOOL
+#endif
+
+//==============================================================================
+/* In a Windows DLL build, we'll expose some malloc/free functions that live inside the DLL, and use these for
+   allocating all the objects - that way all juce objects in the DLL and in the host will live in the same heap,
+   avoiding problems when an object is created in one module and passed across to another where it is deleted.
+   By piggy-backing on the JUCE_LEAK_DETECTOR macro, these allocators can be injected into most juce classes.
+*/
+#if JUCE_MSVC && (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD)) && ! (JUCE_DISABLE_DLL_ALLOCATORS || DOXYGEN)
+ extern JUCE_API void* juceDLL_malloc (size_t);
+ extern JUCE_API void  juceDLL_free (void*);
+
+ #define JUCE_LEAK_DETECTOR(OwnerClass)  public:\
+    static void* operator new (size_t sz)           { return juce::juceDLL_malloc (sz); } \
+    static void* operator new (size_t, void* p)     { return p; } \
+    static void operator delete (void* p)           { juce::juceDLL_free (p); } \
+    static void operator delete (void*, void*)      {}
+#endif
+
+//==============================================================================
+/** (Deprecated) This was a Windows-specific way of checking for object leaks - now please
+    use the JUCE_LEAK_DETECTOR instead.
+*/
+#ifndef juce_UseDebuggingNewOperator
+ #define juce_UseDebuggingNewOperator
+#endif
+
+
+#endif   // JUCE_MEMORY_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_MemoryBlock.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_MemoryBlock.cpp
new file mode 100644
index 0000000..a827037
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_MemoryBlock.cpp
@@ -0,0 +1,416 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+MemoryBlock::MemoryBlock() noexcept
+    : size (0)
+{
+}
+
+MemoryBlock::MemoryBlock (const size_t initialSize, const bool initialiseToZero)
+{
+    if (initialSize > 0)
+    {
+        size = initialSize;
+        data.allocate (initialSize, initialiseToZero);
+    }
+    else
+    {
+        size = 0;
+    }
+}
+
+MemoryBlock::MemoryBlock (const MemoryBlock& other)
+    : size (other.size)
+{
+    if (size > 0)
+    {
+        jassert (other.data != nullptr);
+        data.malloc (size);
+        memcpy (data, other.data, size);
+    }
+}
+
+MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, const size_t sizeInBytes)
+    : size (sizeInBytes)
+{
+    jassert (((ssize_t) sizeInBytes) >= 0);
+
+    if (size > 0)
+    {
+        jassert (dataToInitialiseFrom != nullptr); // non-zero size, but a zero pointer passed-in?
+
+        data.malloc (size);
+
+        if (dataToInitialiseFrom != nullptr)
+            memcpy (data, dataToInitialiseFrom, size);
+    }
+}
+
+MemoryBlock::~MemoryBlock() noexcept
+{
+}
+
+MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
+{
+    if (this != &other)
+    {
+        setSize (other.size, false);
+        memcpy (data, other.data, size);
+    }
+
+    return *this;
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
+    : data (static_cast <HeapBlock<char>&&> (other.data)),
+      size (other.size)
+{
+}
+
+MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
+{
+    data = static_cast <HeapBlock<char>&&> (other.data);
+    size = other.size;
+    return *this;
+}
+#endif
+
+
+//==============================================================================
+bool MemoryBlock::operator== (const MemoryBlock& other) const noexcept
+{
+    return matches (other.data, other.size);
+}
+
+bool MemoryBlock::operator!= (const MemoryBlock& other) const noexcept
+{
+    return ! operator== (other);
+}
+
+bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const noexcept
+{
+    return size == dataSize
+            && memcmp (data, dataToCompare, size) == 0;
+}
+
+//==============================================================================
+// this will resize the block to this size
+void MemoryBlock::setSize (const size_t newSize, const bool initialiseToZero)
+{
+    if (size != newSize)
+    {
+        if (newSize <= 0)
+        {
+            reset();
+        }
+        else
+        {
+            if (data != nullptr)
+            {
+                data.realloc (newSize);
+
+                if (initialiseToZero && (newSize > size))
+                    zeromem (data + size, newSize - size);
+            }
+            else
+            {
+                data.allocate (newSize, initialiseToZero);
+            }
+
+            size = newSize;
+        }
+    }
+}
+
+void MemoryBlock::reset()
+{
+    data.free();
+    size = 0;
+}
+
+void MemoryBlock::ensureSize (const size_t minimumSize, const bool initialiseToZero)
+{
+    if (size < minimumSize)
+        setSize (minimumSize, initialiseToZero);
+}
+
+void MemoryBlock::swapWith (MemoryBlock& other) noexcept
+{
+    std::swap (size, other.size);
+    data.swapWith (other.data);
+}
+
+//==============================================================================
+void MemoryBlock::fillWith (const uint8 value) noexcept
+{
+    memset (data, (int) value, size);
+}
+
+void MemoryBlock::append (const void* const srcData, const size_t numBytes)
+{
+    if (numBytes > 0)
+    {
+        jassert (srcData != nullptr); // this must not be null!
+        const size_t oldSize = size;
+        setSize (size + numBytes);
+        memcpy (data + oldSize, srcData, numBytes);
+    }
+}
+
+void MemoryBlock::replaceWith (const void* const srcData, const size_t numBytes)
+{
+    if (numBytes > 0)
+    {
+        jassert (srcData != nullptr); // this must not be null!
+        setSize (numBytes);
+        memcpy (data, srcData, numBytes);
+    }
+}
+
+void MemoryBlock::insert (const void* const srcData, const size_t numBytes, size_t insertPosition)
+{
+    if (numBytes > 0)
+    {
+        jassert (srcData != nullptr); // this must not be null!
+        insertPosition = jmin (size, insertPosition);
+        const size_t trailingDataSize = size - insertPosition;
+        setSize (size + numBytes, false);
+
+        if (trailingDataSize > 0)
+            memmove (data + insertPosition + numBytes,
+                     data + insertPosition,
+                     trailingDataSize);
+
+        memcpy (data + insertPosition, srcData, numBytes);
+    }
+}
+
+void MemoryBlock::removeSection (const size_t startByte, const size_t numBytesToRemove)
+{
+    if (startByte + numBytesToRemove >= size)
+    {
+        setSize (startByte);
+    }
+    else if (numBytesToRemove > 0)
+    {
+        memmove (data + startByte,
+                 data + startByte + numBytesToRemove,
+                 size - (startByte + numBytesToRemove));
+
+        setSize (size - numBytesToRemove);
+    }
+}
+
+void MemoryBlock::copyFrom (const void* const src, int offset, size_t num) noexcept
+{
+    const char* d = static_cast<const char*> (src);
+
+    if (offset < 0)
+    {
+        d -= offset;
+        num += (size_t) -offset;
+        offset = 0;
+    }
+
+    if ((size_t) offset + num > size)
+        num = size - (size_t) offset;
+
+    if (num > 0)
+        memcpy (data + offset, d, num);
+}
+
+void MemoryBlock::copyTo (void* const dst, int offset, size_t num) const noexcept
+{
+    char* d = static_cast<char*> (dst);
+
+    if (offset < 0)
+    {
+        zeromem (d, (size_t) -offset);
+        d -= offset;
+        num -= (size_t) -offset;
+        offset = 0;
+    }
+
+    if ((size_t) offset + num > size)
+    {
+        const size_t newNum = size - (size_t) offset;
+        zeromem (d + newNum, num - newNum);
+        num = newNum;
+    }
+
+    if (num > 0)
+        memcpy (d, data + offset, num);
+}
+
+String MemoryBlock::toString() const
+{
+    return String::fromUTF8 (data, (int) size);
+}
+
+//==============================================================================
+int MemoryBlock::getBitRange (const size_t bitRangeStart, size_t numBits) const noexcept
+{
+    int res = 0;
+
+    size_t byte = bitRangeStart >> 3;
+    size_t offsetInByte = bitRangeStart & 7;
+    size_t bitsSoFar = 0;
+
+    while (numBits > 0 && (size_t) byte < size)
+    {
+        const size_t bitsThisTime = jmin (numBits, 8 - offsetInByte);
+        const int mask = (0xff >> (8 - bitsThisTime)) << offsetInByte;
+
+        res |= (((data[byte] & mask) >> offsetInByte) << bitsSoFar);
+
+        bitsSoFar += bitsThisTime;
+        numBits -= bitsThisTime;
+        ++byte;
+        offsetInByte = 0;
+    }
+
+    return res;
+}
+
+void MemoryBlock::setBitRange (const size_t bitRangeStart, size_t numBits, int bitsToSet) noexcept
+{
+    size_t byte = bitRangeStart >> 3;
+    size_t offsetInByte = bitRangeStart & 7;
+    uint32 mask = ~((((uint32) 0xffffffff) << (32 - numBits)) >> (32 - numBits));
+
+    while (numBits > 0 && (size_t) byte < size)
+    {
+        const size_t bitsThisTime = jmin (numBits, 8 - offsetInByte);
+
+        const uint32 tempMask = (mask << offsetInByte) | ~((((uint32) 0xffffffff) >> offsetInByte) << offsetInByte);
+        const uint32 tempBits = (uint32) bitsToSet << offsetInByte;
+
+        data[byte] = (char) (((uint32) data[byte] & tempMask) | tempBits);
+
+        ++byte;
+        numBits -= bitsThisTime;
+        bitsToSet >>= bitsThisTime;
+        mask >>= bitsThisTime;
+        offsetInByte = 0;
+    }
+}
+
+//==============================================================================
+void MemoryBlock::loadFromHexString (StringRef hex)
+{
+    ensureSize ((size_t) hex.length() >> 1);
+    char* dest = data;
+    String::CharPointerType t (hex.text);
+
+    for (;;)
+    {
+        int byte = 0;
+
+        for (int loop = 2; --loop >= 0;)
+        {
+            byte <<= 4;
+
+            for (;;)
+            {
+                const juce_wchar c = t.getAndAdvance();
+
+                if (c >= '0' && c <= '9')    { byte |= c - '0';        break; }
+                if (c >= 'a' && c <= 'z')    { byte |= c - ('a' - 10); break; }
+                if (c >= 'A' && c <= 'Z')    { byte |= c - ('A' - 10); break; }
+
+                if (c == 0)
+                {
+                    setSize (static_cast <size_t> (dest - data));
+                    return;
+                }
+            }
+        }
+
+        *dest++ = (char) byte;
+    }
+}
+
+//==============================================================================
+static const char base64EncodingTable[] = ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
+
+String MemoryBlock::toBase64Encoding() const
+{
+    const size_t numChars = ((size << 3) + 5) / 6;
+
+    String destString ((unsigned int) size); // store the length, followed by a '.', and then the data.
+    const int initialLen = destString.length();
+    destString.preallocateBytes (sizeof (String::CharPointerType::CharType) * (size_t) initialLen + 2 + numChars);
+
+    String::CharPointerType d (destString.getCharPointer());
+    d += initialLen;
+    d.write ('.');
+
+    for (size_t i = 0; i < numChars; ++i)
+        d.write ((juce_wchar) (uint8) base64EncodingTable [getBitRange (i * 6, 6)]);
+
+    d.writeNull();
+    return destString;
+}
+
+static const char base64DecodingTable[] =
+{
+    63, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 0, 0, 0, 0, 0, 0, 0,
+    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+    0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52
+};
+
+bool MemoryBlock::fromBase64Encoding (StringRef s)
+{
+    String::CharPointerType dot (CharacterFunctions::find (s.text, (juce_wchar) '.'));
+
+    if (dot.isEmpty())
+        return false;
+
+    const int numBytesNeeded = String (s.text, dot).getIntValue();
+
+    setSize ((size_t) numBytesNeeded, true);
+
+    String::CharPointerType srcChars (dot + 1);
+    int pos = 0;
+
+    for (;;)
+    {
+        int c = (int) srcChars.getAndAdvance();
+
+        if (c == 0)
+            return true;
+
+        c -= 43;
+        if (isPositiveAndBelow (c, numElementsInArray (base64DecodingTable)))
+        {
+            setBitRange ((size_t) pos, 6, base64DecodingTable [c]);
+            pos += 6;
+        }
+    }
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_MemoryBlock.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_MemoryBlock.h
new file mode 100644
index 0000000..30bb3ca
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_MemoryBlock.h
@@ -0,0 +1,253 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_MEMORYBLOCK_H_INCLUDED
+#define JUCE_MEMORYBLOCK_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A class to hold a resizable block of raw data.
+
+*/
+class JUCE_API  MemoryBlock
+{
+public:
+    //==============================================================================
+    /** Create an uninitialised block with 0 size. */
+    MemoryBlock() noexcept;
+
+    /** Creates a memory block with a given initial size.
+
+        @param initialSize          the size of block to create
+        @param initialiseToZero     whether to clear the memory or just leave it uninitialised
+    */
+    MemoryBlock (const size_t initialSize,
+                 bool initialiseToZero = false);
+
+    /** Creates a copy of another memory block. */
+    MemoryBlock (const MemoryBlock&);
+
+    /** Creates a memory block using a copy of a block of data.
+
+        @param dataToInitialiseFrom     some data to copy into this block
+        @param sizeInBytes              how much space to use
+    */
+    MemoryBlock (const void* dataToInitialiseFrom, size_t sizeInBytes);
+
+    /** Destructor. */
+    ~MemoryBlock() noexcept;
+
+    /** Copies another memory block onto this one.
+        This block will be resized and copied to exactly match the other one.
+    */
+    MemoryBlock& operator= (const MemoryBlock&);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    MemoryBlock (MemoryBlock&&) noexcept;
+    MemoryBlock& operator= (MemoryBlock&&) noexcept;
+   #endif
+
+    //==============================================================================
+    /** Compares two memory blocks.
+        @returns true only if the two blocks are the same size and have identical contents.
+    */
+    bool operator== (const MemoryBlock& other) const noexcept;
+
+    /** Compares two memory blocks.
+        @returns true if the two blocks are different sizes or have different contents.
+    */
+    bool operator!= (const MemoryBlock& other) const noexcept;
+
+    /** Returns true if the data in this MemoryBlock matches the raw bytes passed-in. */
+    bool matches (const void* data, size_t dataSize) const noexcept;
+
+    //==============================================================================
+    /** Returns a void pointer to the data.
+
+        Note that the pointer returned will probably become invalid when the
+        block is resized.
+    */
+    void* getData() const noexcept                                  { return data; }
+
+    /** Returns a byte from the memory block.
+        This returns a reference, so you can also use it to set a byte.
+    */
+    template <typename Type>
+    char& operator[] (const Type offset) const noexcept             { return data [offset]; }
+
+
+    //==============================================================================
+    /** Returns the block's current allocated size, in bytes. */
+    size_t getSize() const noexcept                                 { return size; }
+
+    /** Resizes the memory block.
+
+        Any data that is present in both the old and new sizes will be retained.
+        When enlarging the block, the new space that is allocated at the end can either be
+        cleared, or left uninitialised.
+
+        @param newSize                      the new desired size for the block
+        @param initialiseNewSpaceToZero     if the block gets enlarged, this determines
+                                            whether to clear the new section or just leave it
+                                            uninitialised
+        @see ensureSize
+    */
+    void setSize (const size_t newSize,
+                  bool initialiseNewSpaceToZero = false);
+
+    /** Increases the block's size only if it's smaller than a given size.
+
+        @param minimumSize                  if the block is already bigger than this size, no action
+                                            will be taken; otherwise it will be increased to this size
+        @param initialiseNewSpaceToZero     if the block gets enlarged, this determines
+                                            whether to clear the new section or just leave it
+                                            uninitialised
+        @see setSize
+    */
+    void ensureSize (const size_t minimumSize,
+                     bool initialiseNewSpaceToZero = false);
+
+    /** Frees all the blocks data, setting its size to 0. */
+    void reset();
+
+    //==============================================================================
+    /** Fills the entire memory block with a repeated byte value.
+        This is handy for clearing a block of memory to zero.
+    */
+    void fillWith (uint8 valueToUse) noexcept;
+
+    /** Adds another block of data to the end of this one.
+        The data pointer must not be null. This block's size will be increased accordingly.
+    */
+    void append (const void* data, size_t numBytes);
+
+    /** Resizes this block to the given size and fills its contents from the supplied buffer.
+        The data pointer must not be null.
+    */
+    void replaceWith (const void* data, size_t numBytes);
+
+    /** Inserts some data into the block.
+        The dataToInsert pointer must not be null. This block's size will be increased accordingly.
+        If the insert position lies outside the valid range of the block, it will be clipped to
+        within the range before being used.
+    */
+    void insert (const void* dataToInsert, size_t numBytesToInsert, size_t insertPosition);
+
+    /** Chops out a section  of the block.
+
+        This will remove a section of the memory block and close the gap around it,
+        shifting any subsequent data downwards and reducing the size of the block.
+
+        If the range specified goes beyond the size of the block, it will be clipped.
+    */
+    void removeSection (size_t startByte, size_t numBytesToRemove);
+
+    //==============================================================================
+    /** Copies data into this MemoryBlock from a memory address.
+
+        @param srcData              the memory location of the data to copy into this block
+        @param destinationOffset    the offset in this block at which the data being copied should begin
+        @param numBytes             how much to copy in (if this goes beyond the size of the memory block,
+                                    it will be clipped so not to do anything nasty)
+    */
+    void copyFrom (const void* srcData,
+                   int destinationOffset,
+                   size_t numBytes) noexcept;
+
+    /** Copies data from this MemoryBlock to a memory address.
+
+        @param destData         the memory location to write to
+        @param sourceOffset     the offset within this block from which the copied data will be read
+        @param numBytes         how much to copy (if this extends beyond the limits of the memory block,
+                                zeros will be used for that portion of the data)
+    */
+    void copyTo (void* destData,
+                 int sourceOffset,
+                 size_t numBytes) const noexcept;
+
+    //==============================================================================
+    /** Exchanges the contents of this and another memory block.
+        No actual copying is required for this, so it's very fast.
+    */
+    void swapWith (MemoryBlock& other) noexcept;
+
+    //==============================================================================
+    /** Attempts to parse the contents of the block as a zero-terminated UTF8 string. */
+    String toString() const;
+
+    //==============================================================================
+    /** Parses a string of hexadecimal numbers and writes this data into the memory block.
+
+        The block will be resized to the number of valid bytes read from the string.
+        Non-hex characters in the string will be ignored.
+
+        @see String::toHexString()
+    */
+    void loadFromHexString (StringRef sourceHexString);
+
+    //==============================================================================
+    /** Sets a number of bits in the memory block, treating it as a long binary sequence. */
+    void setBitRange (size_t bitRangeStart,
+                      size_t numBits,
+                      int binaryNumberToApply) noexcept;
+
+    /** Reads a number of bits from the memory block, treating it as one long binary sequence */
+    int getBitRange (size_t bitRangeStart,
+                     size_t numBitsToRead) const noexcept;
+
+    //==============================================================================
+    /** Returns a string of characters that represent the binary contents of this block.
+
+        Uses a 64-bit encoding system to allow binary data to be turned into a string
+        of simple non-extended characters, e.g. for storage in XML.
+
+        @see fromBase64Encoding
+    */
+    String toBase64Encoding() const;
+
+    /** Takes a string of encoded characters and turns it into binary data.
+
+        The string passed in must have been created by to64BitEncoding(), and this
+        block will be resized to recreate the original data block.
+
+        @see toBase64Encoding
+    */
+    bool fromBase64Encoding  (StringRef encodedString);
+
+
+private:
+    //==============================================================================
+    HeapBlock<char> data;
+    size_t size;
+
+    JUCE_LEAK_DETECTOR (MemoryBlock)
+};
+
+
+#endif   // JUCE_MEMORYBLOCK_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_OptionalScopedPointer.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_OptionalScopedPointer.h
new file mode 100644
index 0000000..a633dca
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_OptionalScopedPointer.h
@@ -0,0 +1,186 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_OPTIONALSCOPEDPOINTER_H_INCLUDED
+#define JUCE_OPTIONALSCOPEDPOINTER_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Holds a pointer to an object which can optionally be deleted when this pointer
+    goes out of scope.
+
+    This acts in many ways like a ScopedPointer, but allows you to specify whether or
+    not the object is deleted.
+
+    @see ScopedPointer
+*/
+template <class ObjectType>
+class OptionalScopedPointer
+{
+public:
+    //==============================================================================
+    /** Creates an empty OptionalScopedPointer. */
+    OptionalScopedPointer() : shouldDelete (false) {}
+
+    /** Creates an OptionalScopedPointer to point to a given object, and specifying whether
+        the OptionalScopedPointer will delete it.
+
+        If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer,
+        deleting the object when it is itself deleted. If this parameter is false, then the
+        OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
+    */
+    OptionalScopedPointer (ObjectType* objectToHold, bool takeOwnership)
+        : object (objectToHold), shouldDelete (takeOwnership)
+    {
+    }
+
+    /** Takes ownership of the object that another OptionalScopedPointer holds.
+
+        Like a normal ScopedPointer, the objectToTransferFrom object will become null,
+        as ownership of the managed object is transferred to this object.
+
+        The flag to indicate whether or not to delete the managed object is also
+        copied from the source object.
+    */
+    OptionalScopedPointer (OptionalScopedPointer& objectToTransferFrom)
+        : object (objectToTransferFrom.release()),
+          shouldDelete (objectToTransferFrom.shouldDelete)
+    {
+    }
+
+    /** Takes ownership of the object that another OptionalScopedPointer holds.
+
+        Like a normal ScopedPointer, the objectToTransferFrom object will become null,
+        as ownership of the managed object is transferred to this object.
+
+        The ownership flag that says whether or not to delete the managed object is also
+        copied from the source object.
+    */
+    OptionalScopedPointer& operator= (OptionalScopedPointer& objectToTransferFrom)
+    {
+        if (object != objectToTransferFrom.object)
+        {
+            clear();
+            object = objectToTransferFrom.object;
+        }
+
+        shouldDelete = objectToTransferFrom.shouldDelete;
+        return *this;
+    }
+
+    /** The destructor may or may not delete the object that is being held, depending on the
+        takeOwnership flag that was specified when the object was first passed into an
+        OptionalScopedPointer constructor.
+    */
+    ~OptionalScopedPointer()
+    {
+        clear();
+    }
+
+    //==============================================================================
+    /** Returns the object that this pointer is managing. */
+    inline operator ObjectType*() const noexcept                    { return object; }
+
+    /** Returns the object that this pointer is managing. */
+    inline ObjectType* get() const noexcept                         { return object; }
+
+    /** Returns the object that this pointer is managing. */
+    inline ObjectType& operator*() const noexcept                   { return *object; }
+
+    /** Lets you access methods and properties of the object that this pointer is holding. */
+    inline ObjectType* operator->() const noexcept                  { return object; }
+
+    //==============================================================================
+    /** Removes the current object from this OptionalScopedPointer without deleting it.
+        This will return the current object, and set this OptionalScopedPointer to a null pointer.
+    */
+    ObjectType* release() noexcept                                  { return object.release(); }
+
+    /** Resets this pointer to null, possibly deleting the object that it holds, if it has
+        ownership of it.
+    */
+    void clear()
+    {
+        if (! shouldDelete)
+            object.release();
+    }
+
+    /** Makes this OptionalScopedPointer point at a new object, specifying whether the
+        OptionalScopedPointer will take ownership of the object.
+
+        If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer,
+        deleting the object when it is itself deleted. If this parameter is false, then the
+        OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
+    */
+    void set (ObjectType* newObject, bool takeOwnership)
+    {
+        if (object != newObject)
+        {
+            clear();
+            object = newObject;
+        }
+
+        shouldDelete = takeOwnership;
+    }
+
+    /** Makes this OptionalScopedPointer point at a new object, and take ownership of that object. */
+    void setOwned (ObjectType* newObject)
+    {
+        set (newObject, true);
+    }
+
+    /** Makes this OptionalScopedPointer point at a new object, but will not take ownership of that object. */
+    void setNonOwned (ObjectType* newObject)
+    {
+        set (newObject, false);
+    }
+
+    /** Returns true if the target object will be deleted when this pointer
+        object is deleted.
+    */
+    bool willDeleteObject() const noexcept                          { return shouldDelete; }
+
+    //==============================================================================
+    /** Swaps this object with another OptionalScopedPointer.
+        The two objects simply exchange their states.
+    */
+    void swapWith (OptionalScopedPointer<ObjectType>& other) noexcept
+    {
+        object.swapWith (other.object);
+        std::swap (shouldDelete, other.shouldDelete);
+    }
+
+private:
+    //==============================================================================
+    ScopedPointer<ObjectType> object;
+    bool shouldDelete;
+};
+
+
+#endif   // JUCE_OPTIONALSCOPEDPOINTER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ReferenceCountedObject.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ReferenceCountedObject.h
new file mode 100644
index 0000000..6464d85
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ReferenceCountedObject.h
@@ -0,0 +1,415 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_REFERENCECOUNTEDOBJECT_H_INCLUDED
+#define JUCE_REFERENCECOUNTEDOBJECT_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A base class which provides methods for reference-counting.
+
+    To add reference-counting to a class, derive it from this class, and
+    use the ReferenceCountedObjectPtr class to point to it.
+
+    e.g. @code
+    class MyClass : public ReferenceCountedObject
+    {
+        void foo();
+
+        // This is a neat way of declaring a typedef for a pointer class,
+        // rather than typing out the full templated name each time..
+        typedef ReferenceCountedObjectPtr<MyClass> Ptr;
+    };
+
+    MyClass::Ptr p = new MyClass();
+    MyClass::Ptr p2 = p;
+    p = nullptr;
+    p2->foo();
+    @endcode
+
+    Once a new ReferenceCountedObject has been assigned to a pointer, be
+    careful not to delete the object manually.
+
+    This class uses an Atomic<int> value to hold the reference count, so that it
+    the pointers can be passed between threads safely. For a faster but non-thread-safe
+    version, use SingleThreadedReferenceCountedObject instead.
+
+    @see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject
+*/
+class JUCE_API  ReferenceCountedObject
+{
+public:
+    //==============================================================================
+    /** Increments the object's reference count.
+
+        This is done automatically by the smart pointer, but is public just
+        in case it's needed for nefarious purposes.
+    */
+    void incReferenceCount() noexcept
+    {
+        ++refCount;
+    }
+
+    /** Decreases the object's reference count.
+        If the count gets to zero, the object will be deleted.
+    */
+    void decReferenceCount() noexcept
+    {
+        jassert (getReferenceCount() > 0);
+
+        if (--refCount == 0)
+            delete this;
+    }
+
+    /** Decreases the object's reference count.
+        If the count gets to zero, the object will not be deleted, but this method
+        will return true, allowing the caller to take care of deletion.
+    */
+    bool decReferenceCountWithoutDeleting() noexcept
+    {
+        jassert (getReferenceCount() > 0);
+        return --refCount == 0;
+    }
+
+    /** Returns the object's current reference count. */
+    int getReferenceCount() const noexcept       { return refCount.get(); }
+
+
+protected:
+    //==============================================================================
+    /** Creates the reference-counted object (with an initial ref count of zero). */
+    ReferenceCountedObject() {}
+
+    /** Destructor. */
+    virtual ~ReferenceCountedObject()
+    {
+        // it's dangerous to delete an object that's still referenced by something else!
+        jassert (getReferenceCount() == 0);
+    }
+
+    /** Resets the reference count to zero without deleting the object.
+        You should probably never need to use this!
+    */
+    void resetReferenceCount() noexcept
+    {
+        refCount = 0;
+    }
+
+private:
+    //==============================================================================
+    Atomic <int> refCount;
+
+    friend struct ContainerDeletePolicy<ReferenceCountedObject>;
+    JUCE_DECLARE_NON_COPYABLE (ReferenceCountedObject)
+};
+
+
+//==============================================================================
+/**
+    Adds reference-counting to an object.
+
+    This is effectively a version of the ReferenceCountedObject class, but which
+    uses a non-atomic counter, and so is not thread-safe (but which will be more
+    efficient).
+    For more details on how to use it, see the ReferenceCountedObject class notes.
+
+    @see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray
+*/
+class JUCE_API  SingleThreadedReferenceCountedObject
+{
+public:
+    //==============================================================================
+    /** Increments the object's reference count.
+
+        This is done automatically by the smart pointer, but is public just
+        in case it's needed for nefarious purposes.
+    */
+    void incReferenceCount() noexcept
+    {
+        ++refCount;
+    }
+
+    /** Decreases the object's reference count.
+        If the count gets to zero, the object will be deleted.
+    */
+    void decReferenceCount() noexcept
+    {
+        jassert (getReferenceCount() > 0);
+
+        if (--refCount == 0)
+            delete this;
+    }
+
+    /** Decreases the object's reference count.
+        If the count gets to zero, the object will not be deleted, but this method
+        will return true, allowing the caller to take care of deletion.
+    */
+    bool decReferenceCountWithoutDeleting() noexcept
+    {
+        jassert (getReferenceCount() > 0);
+        return --refCount == 0;
+    }
+
+    /** Returns the object's current reference count. */
+    int getReferenceCount() const noexcept       { return refCount; }
+
+
+protected:
+    //==============================================================================
+    /** Creates the reference-counted object (with an initial ref count of zero). */
+    SingleThreadedReferenceCountedObject() : refCount (0)  {}
+
+    /** Destructor. */
+    virtual ~SingleThreadedReferenceCountedObject()
+    {
+        // it's dangerous to delete an object that's still referenced by something else!
+        jassert (getReferenceCount() == 0);
+    }
+
+private:
+    //==============================================================================
+    int refCount;
+
+    friend struct ContainerDeletePolicy<ReferenceCountedObject>;
+    JUCE_DECLARE_NON_COPYABLE (SingleThreadedReferenceCountedObject)
+};
+
+
+//==============================================================================
+/**
+    A smart-pointer class which points to a reference-counted object.
+
+    The template parameter specifies the class of the object you want to point to - the easiest
+    way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
+    or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
+    class by implementing a set of mathods called incReferenceCount(), decReferenceCount(), and
+    decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
+    should behave.
+
+    When using this class, you'll probably want to create a typedef to abbreviate the full
+    templated name - e.g.
+    @code
+    struct MyClass  : public ReferenceCountedObject
+    {
+        typedef ReferenceCountedObjectPtr<MyClass> Ptr;
+        ...
+    @endcode
+
+    @see ReferenceCountedObject, ReferenceCountedObjectArray
+*/
+template <class ReferenceCountedObjectClass>
+class ReferenceCountedObjectPtr
+{
+public:
+    /** The class being referenced by this pointer. */
+    typedef ReferenceCountedObjectClass ReferencedType;
+
+    //==============================================================================
+    /** Creates a pointer to a null object. */
+    ReferenceCountedObjectPtr() noexcept
+        : referencedObject (nullptr)
+    {
+    }
+
+    /** Creates a pointer to an object.
+        This will increment the object's reference-count.
+    */
+    ReferenceCountedObjectPtr (ReferencedType* refCountedObject) noexcept
+        : referencedObject (refCountedObject)
+    {
+        incIfNotNull (refCountedObject);
+    }
+
+    /** Copies another pointer.
+        This will increment the object's reference-count.
+    */
+    ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept
+        : referencedObject (other.referencedObject)
+    {
+        incIfNotNull (referencedObject);
+    }
+
+    /** Copies another pointer.
+        This will increment the object's reference-count (if it is non-null).
+    */
+    template <class Convertible>
+    ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<Convertible>& other) noexcept
+        : referencedObject (static_cast <ReferencedType*> (other.get()))
+    {
+        incIfNotNull (referencedObject);
+    }
+
+    /** Changes this pointer to point at a different object.
+        The reference count of the old object is decremented, and it might be
+        deleted if it hits zero. The new object's count is incremented.
+    */
+    ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other)
+    {
+        return operator= (other.referencedObject);
+    }
+
+    /** Changes this pointer to point at a different object.
+        The reference count of the old object is decremented, and it might be
+        deleted if it hits zero. The new object's count is incremented.
+    */
+    template <class Convertible>
+    ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<Convertible>& other)
+    {
+        return operator= (static_cast<ReferencedType*> (other.get()));
+    }
+
+    /** Changes this pointer to point at a different object.
+
+        The reference count of the old object is decremented, and it might be
+        deleted if it hits zero. The new object's count is incremented.
+    */
+    ReferenceCountedObjectPtr& operator= (ReferencedType* const newObject)
+    {
+        if (referencedObject != newObject)
+        {
+            incIfNotNull (newObject);
+            ReferencedType* const oldObject = referencedObject;
+            referencedObject = newObject;
+            decIfNotNull (oldObject);
+        }
+
+        return *this;
+    }
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    /** Takes-over the object from another pointer. */
+    ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept
+        : referencedObject (other.referencedObject)
+    {
+        other.referencedObject = nullptr;
+    }
+
+    /** Takes-over the object from another pointer. */
+    ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other)
+    {
+        std::swap (referencedObject, other.referencedObject);
+        return *this;
+    }
+   #endif
+
+    /** Destructor.
+        This will decrement the object's reference-count, which will cause the
+        object to be deleted when the ref-count hits zero.
+    */
+    ~ReferenceCountedObjectPtr()
+    {
+        decIfNotNull (referencedObject);
+    }
+
+    //==============================================================================
+    /** Returns the object that this pointer references.
+        The pointer returned may be null, of course.
+    */
+    operator ReferencedType*() const noexcept       { return referencedObject; }
+
+    /** Returns the object that this pointer references.
+        The pointer returned may be null, of course.
+    */
+    ReferencedType* get() const noexcept            { return referencedObject; }
+
+    /** Returns the object that this pointer references.
+        The pointer returned may be null, of course.
+    */
+    ReferencedType* getObject() const noexcept      { return referencedObject; }
+
+    // the -> operator is called on the referenced object
+    ReferencedType* operator->() const noexcept
+    {
+        jassert (referencedObject != nullptr); // null pointer method call!
+        return referencedObject;
+    }
+
+private:
+    //==============================================================================
+    ReferencedType* referencedObject;
+
+    static void incIfNotNull (ReferencedType* o) noexcept
+    {
+        if (o != nullptr)
+            o->incReferenceCount();
+    }
+
+    static void decIfNotNull (ReferencedType* o) noexcept
+    {
+        if (o != nullptr && o->decReferenceCountWithoutDeleting())
+            ContainerDeletePolicy<ReferencedType>::destroy (o);
+    }
+};
+
+
+//==============================================================================
+/** Compares two ReferenceCountedObjectPointers. */
+template <class ReferenceCountedObjectClass>
+bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectClass* const object2) noexcept
+{
+    return object1.get() == object2;
+}
+
+/** Compares two ReferenceCountedObjectPointers. */
+template <class ReferenceCountedObjectClass>
+bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
+{
+    return object1.get() == object2.get();
+}
+
+/** Compares two ReferenceCountedObjectPointers. */
+template <class ReferenceCountedObjectClass>
+bool operator== (ReferenceCountedObjectClass* object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
+{
+    return object1 == object2.get();
+}
+
+/** Compares two ReferenceCountedObjectPointers. */
+template <class ReferenceCountedObjectClass>
+bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectClass* object2) noexcept
+{
+    return object1.get() != object2;
+}
+
+/** Compares two ReferenceCountedObjectPointers. */
+template <class ReferenceCountedObjectClass>
+bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
+{
+    return object1.get() != object2.get();
+}
+
+/** Compares two ReferenceCountedObjectPointers. */
+template <class ReferenceCountedObjectClass>
+bool operator!= (ReferenceCountedObjectClass* object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
+{
+    return object1 != object2.get();
+}
+
+
+#endif   // JUCE_REFERENCECOUNTEDOBJECT_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ScopedPointer.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ScopedPointer.h
new file mode 100644
index 0000000..a7fcff0
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_ScopedPointer.h
@@ -0,0 +1,253 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SCOPEDPOINTER_H_INCLUDED
+#define JUCE_SCOPEDPOINTER_H_INCLUDED
+
+//==============================================================================
+/**
+    This class holds a pointer which is automatically deleted when this object goes
+    out of scope.
+
+    Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer
+    gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or
+    as member variables is a good way to use RAII to avoid accidentally leaking dynamically
+    created objects.
+
+    A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer
+    to an object. If you use the assignment operator to assign a different object to a
+    ScopedPointer, the old one will be automatically deleted.
+
+    Important note: The class is designed to hold a pointer to an object, NOT to an array!
+    It calls delete on its payload, not delete[], so do not give it an array to hold! For
+    that kind of purpose, you should be using HeapBlock or Array instead.
+
+    A const ScopedPointer is guaranteed not to lose ownership of its object or change the
+    object to which it points during its lifetime. This means that making a copy of a const
+    ScopedPointer is impossible, as that would involve the new copy taking ownership from the
+    old one.
+
+    If you need to get a pointer out of a ScopedPointer without it being deleted, you
+    can use the release() method.
+
+    Something to note is the main difference between this class and the std::auto_ptr class,
+    which is that ScopedPointer provides a cast-to-object operator, wheras std::auto_ptr
+    requires that you always call get() to retrieve the pointer. The advantages of providing
+    the cast is that you don't need to call get(), so can use the ScopedPointer in pretty much
+    exactly the same way as a raw pointer. The disadvantage is that the compiler is free to
+    use the cast in unexpected and sometimes dangerous ways - in particular, it becomes difficult
+    to return a ScopedPointer as the result of a function. To avoid this causing errors,
+    ScopedPointer contains an overloaded constructor that should cause a syntax error in these
+    circumstances, but it does mean that instead of returning a ScopedPointer from a function,
+    you'd need to return a raw pointer (or use a std::auto_ptr instead).
+*/
+template <class ObjectType>
+class ScopedPointer
+{
+public:
+    //==============================================================================
+    /** Creates a ScopedPointer containing a null pointer. */
+    inline ScopedPointer() noexcept   : object (nullptr)
+    {
+    }
+
+    /** Creates a ScopedPointer that owns the specified object. */
+    inline ScopedPointer (ObjectType* const objectToTakePossessionOf) noexcept
+        : object (objectToTakePossessionOf)
+    {
+    }
+
+    /** Creates a ScopedPointer that takes its pointer from another ScopedPointer.
+
+        Because a pointer can only belong to one ScopedPointer, this transfers
+        the pointer from the other object to this one, and the other object is reset to
+        be a null pointer.
+    */
+    ScopedPointer (ScopedPointer& objectToTransferFrom) noexcept
+        : object (objectToTransferFrom.object)
+    {
+        objectToTransferFrom.object = nullptr;
+    }
+
+    /** Destructor.
+        This will delete the object that this ScopedPointer currently refers to.
+    */
+    inline ~ScopedPointer()                 { ContainerDeletePolicy<ObjectType>::destroy (object); }
+
+    /** Changes this ScopedPointer to point to a new object.
+
+        Because a pointer can only belong to one ScopedPointer, this transfers
+        the pointer from the other object to this one, and the other object is reset to
+        be a null pointer.
+
+        If this ScopedPointer already points to an object, that object
+        will first be deleted.
+    */
+    ScopedPointer& operator= (ScopedPointer& objectToTransferFrom)
+    {
+        if (this != objectToTransferFrom.getAddress())
+        {
+            // Two ScopedPointers should never be able to refer to the same object - if
+            // this happens, you must have done something dodgy!
+            jassert (object == nullptr || object != objectToTransferFrom.object);
+
+            ObjectType* const oldObject = object;
+            object = objectToTransferFrom.object;
+            objectToTransferFrom.object = nullptr;
+            ContainerDeletePolicy<ObjectType>::destroy (oldObject);
+        }
+
+        return *this;
+    }
+
+    /** Changes this ScopedPointer to point to a new object.
+
+        If this ScopedPointer already points to an object, that object
+        will first be deleted.
+
+        The pointer that you pass in may be a nullptr.
+    */
+    ScopedPointer& operator= (ObjectType* const newObjectToTakePossessionOf)
+    {
+        if (object != newObjectToTakePossessionOf)
+        {
+            ObjectType* const oldObject = object;
+            object = newObjectToTakePossessionOf;
+            ContainerDeletePolicy<ObjectType>::destroy (oldObject);
+        }
+
+        return *this;
+    }
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    ScopedPointer (ScopedPointer&& other) noexcept
+        : object (other.object)
+    {
+        other.object = nullptr;
+    }
+
+    ScopedPointer& operator= (ScopedPointer&& other) noexcept
+    {
+        object = other.object;
+        other.object = nullptr;
+        return *this;
+    }
+   #endif
+
+    //==============================================================================
+    /** Returns the object that this ScopedPointer refers to. */
+    inline operator ObjectType*() const noexcept                                    { return object; }
+
+    /** Returns the object that this ScopedPointer refers to. */
+    inline ObjectType* get() const noexcept                                         { return object; }
+
+    /** Returns the object that this ScopedPointer refers to. */
+    inline ObjectType& operator*() const noexcept                                   { return *object; }
+
+    /** Lets you access methods and properties of the object that this ScopedPointer refers to. */
+    inline ObjectType* operator->() const noexcept                                  { return object; }
+
+    //==============================================================================
+    /** Removes the current object from this ScopedPointer without deleting it.
+        This will return the current object, and set the ScopedPointer to a null pointer.
+    */
+    ObjectType* release() noexcept                                                  { ObjectType* const o = object; object = nullptr; return o; }
+
+    //==============================================================================
+    /** Swaps this object with that of another ScopedPointer.
+        The two objects simply exchange their pointers.
+    */
+    void swapWith (ScopedPointer <ObjectType>& other) noexcept
+    {
+        // Two ScopedPointers should never be able to refer to the same object - if
+        // this happens, you must have done something dodgy!
+        jassert (object != other.object || this == other.getAddress());
+
+        std::swap (object, other.object);
+    }
+
+    /** If the pointer is non-null, this will attempt to return a new copy of the object that is pointed to.
+        If the pointer is null, this will safely return a nullptr.
+    */
+    inline ObjectType* createCopy() const                                           { return createCopyIfNotNull (object); }
+
+private:
+    //==============================================================================
+    ObjectType* object;
+
+    // (Required as an alternative to the overloaded & operator).
+    const ScopedPointer* getAddress() const noexcept                                { return this; }
+
+  #if ! JUCE_MSVC  // (MSVC can't deal with multiple copy constructors)
+    /* The copy constructors are private to stop people accidentally copying a const ScopedPointer
+       (the compiler would let you do so by implicitly casting the source to its raw object pointer).
+
+       A side effect of this is that in a compiler that doesn't support C++11, you may hit an
+       error when you write something like this:
+
+          ScopedPointer<MyClass> m = new MyClass();  // Compile error: copy constructor is private.
+
+       Even though the compiler would normally ignore the assignment here, it can't do so when the
+       copy constructor is private. It's very easy to fix though - just write it like this:
+
+          ScopedPointer<MyClass> m (new MyClass());  // Compiles OK
+
+       It's probably best to use the latter form when writing your object declarations anyway, as
+       this is a better representation of the code that you actually want the compiler to produce.
+    */
+    JUCE_DECLARE_NON_COPYABLE (ScopedPointer)
+  #endif
+};
+
+//==============================================================================
+/** Compares a ScopedPointer with another pointer.
+    This can be handy for checking whether this is a null pointer.
+*/
+template <class ObjectType>
+bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
+{
+    return static_cast <ObjectType*> (pointer1) == pointer2;
+}
+
+/** Compares a ScopedPointer with another pointer.
+    This can be handy for checking whether this is a null pointer.
+*/
+template <class ObjectType>
+bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
+{
+    return static_cast <ObjectType*> (pointer1) != pointer2;
+}
+
+//==============================================================================
+#ifndef DOXYGEN
+// NB: This is just here to prevent any silly attempts to call deleteAndZero() on a ScopedPointer.
+template <typename Type>
+void deleteAndZero (ScopedPointer<Type>&)  { static_jassert (sizeof (Type) == 12345); }
+#endif
+
+#endif   // JUCE_SCOPEDPOINTER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_SharedResourcePointer.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_SharedResourcePointer.h
new file mode 100644
index 0000000..53d314b
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_SharedResourcePointer.h
@@ -0,0 +1,152 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SHAREDRESOURCEPOINTER_H_INCLUDED
+#define JUCE_SHAREDRESOURCEPOINTER_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A smart-pointer that automatically creates and manages the lifetime of a
+    shared static instance of a class.
+
+    The SharedObjectType template type indicates the class to use for the shared
+    object - the only requirements on this class are that it must have a public
+    default constructor and destructor.
+
+    The SharedResourcePointer offers a pattern that differs from using a singleton or
+    static instance of an object, because it uses reference-counting to make sure that
+    the underlying shared object is automatically created/destroyed according to the
+    number of SharedResourcePointer objects that exist. When the last one is deleted,
+    the underlying object is also immediately destroyed. This allows you to use scoping
+    to manage the lifetime of a shared resource.
+
+    Note: the construction/deletion of the shared object must not involve any
+    code that makes recursive calls to a SharedResourcePointer, or you'll cause
+    a deadlock.
+
+    Example:
+    @code
+    // An example of a class that contains the shared data you want to use.
+    struct MySharedData
+    {
+        // There's no need to ever create an instance of this class directly yourself,
+        // but it does need a public constructor that does the initialisation.
+        MySharedData()
+        {
+            sharedStuff = generateHeavyweightStuff();
+        }
+
+        Array<SomeKindOfData> sharedStuff;
+    };
+
+    struct DataUserClass
+    {
+        DataUserClass()
+        {
+            // Multiple instances of the DataUserClass will all have the same
+            // shared common instance of MySharedData referenced by their sharedData
+            // member variables.
+            useSharedStuff (sharedData->sharedStuff);
+        }
+
+        // By keeping this pointer as a member variable, the shared resource
+        // is guaranteed to be available for as long as the DataUserClass object.
+        SharedResourcePointer<MySharedData> sharedData;
+    };
+
+    @endcode
+ */
+template <typename SharedObjectType>
+class SharedResourcePointer
+{
+public:
+    /** Creates an instance of the shared object.
+        If other SharedResourcePointer objects for this type already exist, then
+        this one will simply point to the same shared object that they are already
+        using. Otherwise, if this is the first SharedResourcePointer to be created,
+        then a shared object will be created automatically.
+    */
+    SharedResourcePointer()
+    {
+        SharedObjectHolder& holder = getSharedObjectHolder();
+        const SpinLock::ScopedLockType sl (holder.lock);
+
+        if (++(holder.refCount) == 1)
+            holder.sharedInstance = new SharedObjectType();
+
+        sharedObject = holder.sharedInstance;
+    }
+
+    /** Destructor.
+        If no other SharedResourcePointer objects exist, this will also delete
+        the shared object to which it refers.
+    */
+    ~SharedResourcePointer()
+    {
+        SharedObjectHolder& holder = getSharedObjectHolder();
+        const SpinLock::ScopedLockType sl (holder.lock);
+
+        if (--(holder.refCount) == 0)
+            holder.sharedInstance = nullptr;
+    }
+
+    /** Returns the shared object. */
+    operator SharedObjectType*() const noexcept         { return sharedObject; }
+
+    /** Returns the shared object. */
+    SharedObjectType& get() const noexcept              { return *sharedObject; }
+
+    /** Returns the object that this pointer references.
+        The pointer returned may be zero, of course.
+    */
+    SharedObjectType& getObject() const noexcept        { return *sharedObject; }
+
+    SharedObjectType* operator->() const noexcept       { return sharedObject; }
+
+private:
+    struct SharedObjectHolder  : public ReferenceCountedObject
+    {
+        SpinLock lock;
+        ScopedPointer<SharedObjectType> sharedInstance;
+        int refCount;
+    };
+
+    static SharedObjectHolder& getSharedObjectHolder() noexcept
+    {
+        static void* holder [(sizeof (SharedObjectHolder) + sizeof(void*) - 1) / sizeof(void*)] = { 0 };
+        return *reinterpret_cast<SharedObjectHolder*> (holder);
+    }
+
+    SharedObjectType* sharedObject;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedResourcePointer)
+};
+
+
+#endif   // JUCE_SHAREDRESOURCEPOINTER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_Singleton.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_Singleton.h
new file mode 100644
index 0000000..00ea0af
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_Singleton.h
@@ -0,0 +1,292 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SINGLETON_H_INCLUDED
+#define JUCE_SINGLETON_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Macro to declare member variables and methods for a singleton class.
+
+    To use this, add the line juce_DeclareSingleton (MyClass, doNotRecreateAfterDeletion)
+    to the class's definition.
+
+    Then put a macro juce_ImplementSingleton (MyClass) along with the class's
+    implementation code.
+
+    It's also a very good idea to also add the call clearSingletonInstance() in your class's
+    destructor, in case it is deleted by other means than deleteInstance()
+
+    Clients can then call the static method MyClass::getInstance() to get a pointer
+    to the singleton, or MyClass::getInstanceWithoutCreating() which will return 0 if
+    no instance currently exists.
+
+    e.g. @code
+
+        class MySingleton
+        {
+        public:
+            MySingleton()
+            {
+            }
+
+            ~MySingleton()
+            {
+                // this ensures that no dangling pointers are left when the
+                // singleton is deleted.
+                clearSingletonInstance();
+            }
+
+            juce_DeclareSingleton (MySingleton, false)
+        };
+
+        juce_ImplementSingleton (MySingleton)
+
+
+        // example of usage:
+        MySingleton* m = MySingleton::getInstance(); // creates the singleton if there isn't already one.
+
+        ...
+
+        MySingleton::deleteInstance(); // safely deletes the singleton (if it's been created).
+
+    @endcode
+
+    If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
+    than once during the process's lifetime - i.e. after you've created and deleted the
+    object, getInstance() will refuse to create another one. This can be useful to stop
+    objects being accidentally re-created during your app's shutdown code.
+
+    If you know that your object will only be created and deleted by a single thread, you
+    can use the slightly more efficient juce_DeclareSingleton_SingleThreaded() macro instead
+    of this one.
+
+    @see juce_ImplementSingleton, juce_DeclareSingleton_SingleThreaded
+*/
+#define juce_DeclareSingleton(classname, doNotRecreateAfterDeletion) \
+\
+    static classname* _singletonInstance;  \
+    static juce::CriticalSection _singletonLock; \
+\
+    static classname* JUCE_CALLTYPE getInstance() \
+    { \
+        if (_singletonInstance == nullptr) \
+        {\
+            const juce::ScopedLock sl (_singletonLock); \
+\
+            if (_singletonInstance == nullptr) \
+            { \
+                static bool alreadyInside = false; \
+                static bool createdOnceAlready = false; \
+\
+                const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \
+                jassert (! problem); \
+                if (! problem) \
+                { \
+                    createdOnceAlready = true; \
+                    alreadyInside = true; \
+                    classname* newObject = new classname();  /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \
+                    alreadyInside = false; \
+\
+                    _singletonInstance = newObject; \
+                } \
+            } \
+        } \
+\
+        return _singletonInstance; \
+    } \
+\
+    static inline classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept\
+    { \
+        return _singletonInstance; \
+    } \
+\
+    static void JUCE_CALLTYPE deleteInstance() \
+    { \
+        const juce::ScopedLock sl (_singletonLock); \
+        if (_singletonInstance != nullptr) \
+        { \
+            classname* const old = _singletonInstance; \
+            _singletonInstance = nullptr; \
+            delete old; \
+        } \
+    } \
+\
+    void clearSingletonInstance() noexcept\
+    { \
+        if (_singletonInstance == this) \
+            _singletonInstance = nullptr; \
+    }
+
+
+//==============================================================================
+/** This is a counterpart to the juce_DeclareSingleton macro.
+
+    After adding the juce_DeclareSingleton to the class definition, this macro has
+    to be used in the cpp file.
+*/
+#define juce_ImplementSingleton(classname) \
+\
+    classname* classname::_singletonInstance = nullptr; \
+    juce::CriticalSection classname::_singletonLock;
+
+
+//==============================================================================
+/**
+    Macro to declare member variables and methods for a singleton class.
+
+    This is exactly the same as juce_DeclareSingleton, but doesn't use a critical
+    section to make access to it thread-safe. If you know that your object will
+    only ever be created or deleted by a single thread, then this is a
+    more efficient version to use.
+
+    If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
+    than once during the process's lifetime - i.e. after you've created and deleted the
+    object, getInstance() will refuse to create another one. This can be useful to stop
+    objects being accidentally re-created during your app's shutdown code.
+
+    See the documentation for juce_DeclareSingleton for more information about
+    how to use it, the only difference being that you have to use
+    juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton.
+
+    @see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton, juce_DeclareSingleton_SingleThreaded_Minimal
+*/
+#define juce_DeclareSingleton_SingleThreaded(classname, doNotRecreateAfterDeletion) \
+\
+    static classname* _singletonInstance;  \
+\
+    static classname* getInstance() \
+    { \
+        if (_singletonInstance == nullptr) \
+        { \
+            static bool alreadyInside = false; \
+            static bool createdOnceAlready = false; \
+\
+            const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \
+            jassert (! problem); \
+            if (! problem) \
+            { \
+                createdOnceAlready = true; \
+                alreadyInside = true; \
+                classname* newObject = new classname();  /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \
+                alreadyInside = false; \
+\
+                _singletonInstance = newObject; \
+            } \
+        } \
+\
+        return _singletonInstance; \
+    } \
+\
+    static inline classname* getInstanceWithoutCreating() noexcept\
+    { \
+        return _singletonInstance; \
+    } \
+\
+    static void deleteInstance() \
+    { \
+        if (_singletonInstance != nullptr) \
+        { \
+            classname* const old = _singletonInstance; \
+            _singletonInstance = nullptr; \
+            delete old; \
+        } \
+    } \
+\
+    void clearSingletonInstance() noexcept\
+    { \
+        if (_singletonInstance == this) \
+            _singletonInstance = nullptr; \
+    }
+
+//==============================================================================
+/**
+    Macro to declare member variables and methods for a singleton class.
+
+    This is like juce_DeclareSingleton_SingleThreaded, but doesn't do any checking
+    for recursion or repeated instantiation. It's intended for use as a lightweight
+    version of a singleton, where you're using it in very straightforward
+    circumstances and don't need the extra checking.
+
+    Juce use the normal juce_ImplementSingleton_SingleThreaded as the counterpart
+    to this declaration, as you would with juce_DeclareSingleton_SingleThreaded.
+
+    See the documentation for juce_DeclareSingleton for more information about
+    how to use it, the only difference being that you have to use
+    juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton.
+
+    @see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton
+*/
+#define juce_DeclareSingleton_SingleThreaded_Minimal(classname) \
+\
+    static classname* _singletonInstance;  \
+\
+    static classname* getInstance() \
+    { \
+        if (_singletonInstance == nullptr) \
+            _singletonInstance = new classname(); \
+\
+        return _singletonInstance; \
+    } \
+\
+    static inline classname* getInstanceWithoutCreating() noexcept\
+    { \
+        return _singletonInstance; \
+    } \
+\
+    static void deleteInstance() \
+    { \
+        if (_singletonInstance != nullptr) \
+        { \
+            classname* const old = _singletonInstance; \
+            _singletonInstance = nullptr; \
+            delete old; \
+        } \
+    } \
+\
+    void clearSingletonInstance() noexcept\
+    { \
+        if (_singletonInstance == this) \
+            _singletonInstance = nullptr; \
+    }
+
+
+//==============================================================================
+/** This is a counterpart to the juce_DeclareSingleton_SingleThreaded macro.
+
+    After adding juce_DeclareSingleton_SingleThreaded or juce_DeclareSingleton_SingleThreaded_Minimal
+    to the class definition, this macro has to be used somewhere in the cpp file.
+*/
+#define juce_ImplementSingleton_SingleThreaded(classname) \
+\
+    classname* classname::_singletonInstance = nullptr;
+
+
+
+#endif   // JUCE_SINGLETON_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_WeakReference.h b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_WeakReference.h
new file mode 100644
index 0000000..b56808a
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/memory/juce_WeakReference.h
@@ -0,0 +1,212 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_WEAKREFERENCE_H_INCLUDED
+#define JUCE_WEAKREFERENCE_H_INCLUDED
+
+
+//==============================================================================
+/**
+    This class acts as a pointer which will automatically become null if the object
+    to which it points is deleted.
+
+    To accomplish this, the source object needs to cooperate by performing a couple of simple tasks.
+    It must embed a WeakReference::Master object, which stores a shared pointer object, and must clear
+    this master pointer in its destructor.
+
+    E.g.
+    @code
+    class MyObject
+    {
+    public:
+        MyObject()
+        {
+            // If you're planning on using your WeakReferences in a multi-threaded situation, you may choose
+            // to create a WeakReference to the object here in the constructor, which will pre-initialise the
+            // embedded object, avoiding an (extremely unlikely) race condition that could occur if multiple
+            // threads overlap while creating the first WeakReference to it.
+        }
+
+        ~MyObject()
+        {
+            // This will zero all the references - you need to call this in your destructor.
+            masterReference.clear();
+        }
+
+    private:
+        // You need to embed a variable of this type, with the name "masterReference" inside your object. If the
+        // variable is not public, you should make your class a friend of WeakReference<MyObject> so that the
+        // WeakReference class can access it.
+        WeakReference<MyObject>::Master masterReference;
+        friend class WeakReference<MyObject>;
+    };
+
+    // Here's an example of using a pointer..
+
+    MyObject* n = new MyObject();
+    WeakReference<MyObject> myObjectRef = n;
+
+    MyObject* pointer1 = myObjectRef;  // returns a valid pointer to 'n'
+    delete n;
+    MyObject* pointer2 = myObjectRef;  // returns a null pointer
+    @endcode
+
+    @see WeakReference::Master
+*/
+template <class ObjectType, class ReferenceCountingType = ReferenceCountedObject>
+class WeakReference
+{
+public:
+    /** Creates a null SafePointer. */
+    inline WeakReference() noexcept {}
+
+    /** Creates a WeakReference that points at the given object. */
+    WeakReference (ObjectType* const object)  : holder (getRef (object)) {}
+
+    /** Creates a copy of another WeakReference. */
+    WeakReference (const WeakReference& other) noexcept         : holder (other.holder) {}
+
+    /** Copies another pointer to this one. */
+    WeakReference& operator= (const WeakReference& other)       { holder = other.holder; return *this; }
+
+    /** Copies another pointer to this one. */
+    WeakReference& operator= (ObjectType* const newObject)      { holder = getRef (newObject); return *this; }
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    WeakReference (WeakReference&& other) noexcept              : holder (static_cast <SharedRef&&> (other.holder)) {}
+    WeakReference& operator= (WeakReference&& other) noexcept   { holder = static_cast <SharedRef&&> (other.holder); return *this; }
+   #endif
+
+    /** Returns the object that this pointer refers to, or null if the object no longer exists. */
+    ObjectType* get() const noexcept                            { return holder != nullptr ? holder->get() : nullptr; }
+
+    /** Returns the object that this pointer refers to, or null if the object no longer exists. */
+    operator ObjectType*() const noexcept                       { return get(); }
+
+    /** Returns the object that this pointer refers to, or null if the object no longer exists. */
+    ObjectType* operator->() noexcept                           { return get(); }
+
+    /** Returns the object that this pointer refers to, or null if the object no longer exists. */
+    const ObjectType* operator->() const noexcept               { return get(); }
+
+    /** This returns true if this reference has been pointing at an object, but that object has
+        since been deleted.
+
+        If this reference was only ever pointing at a null pointer, this will return false. Using
+        operator=() to make this refer to a different object will reset this flag to match the status
+        of the reference from which you're copying.
+    */
+    bool wasObjectDeleted() const noexcept                      { return holder != nullptr && holder->get() == nullptr; }
+
+    bool operator== (ObjectType* const object) const noexcept   { return get() == object; }
+    bool operator!= (ObjectType* const object) const noexcept   { return get() != object; }
+
+    //==============================================================================
+    /** This class is used internally by the WeakReference class - don't use it directly
+        in your code!
+        @see WeakReference
+    */
+    class SharedPointer   : public ReferenceCountingType
+    {
+    public:
+        explicit SharedPointer (ObjectType* const obj) noexcept : owner (obj) {}
+
+        inline ObjectType* get() const noexcept     { return owner; }
+        void clearPointer() noexcept                { owner = nullptr; }
+
+    private:
+        ObjectType* volatile owner;
+
+        JUCE_DECLARE_NON_COPYABLE (SharedPointer)
+    };
+
+    typedef ReferenceCountedObjectPtr<SharedPointer> SharedRef;
+
+    //==============================================================================
+    /**
+        This class is embedded inside an object to which you want to attach WeakReference pointers.
+        See the WeakReference class notes for an example of how to use this class.
+        @see WeakReference
+    */
+    class Master
+    {
+    public:
+        Master() noexcept {}
+
+        ~Master()
+        {
+            // You must remember to call clear() in your source object's destructor! See the notes
+            // for the WeakReference class for an example of how to do this.
+            jassert (sharedPointer == nullptr || sharedPointer->get() == nullptr);
+        }
+
+        /** The first call to this method will create an internal object that is shared by all weak
+            references to the object.
+        */
+        SharedPointer* getSharedPointer (ObjectType* const object)
+        {
+            if (sharedPointer == nullptr)
+            {
+                sharedPointer = new SharedPointer (object);
+            }
+            else
+            {
+                // You're trying to create a weak reference to an object that has already been deleted!!
+                jassert (sharedPointer->get() != nullptr);
+            }
+
+            return sharedPointer;
+        }
+
+        /** The object that owns this master pointer should call this before it gets destroyed,
+            to zero all the references to this object that may be out there. See the WeakReference
+            class notes for an example of how to do this.
+        */
+        void clear()
+        {
+            if (sharedPointer != nullptr)
+                sharedPointer->clearPointer();
+        }
+
+    private:
+        SharedRef sharedPointer;
+
+        JUCE_DECLARE_NON_COPYABLE (Master)
+    };
+
+private:
+    SharedRef holder;
+
+    static inline SharedPointer* getRef (ObjectType* const o)
+    {
+        return (o != nullptr) ? o->masterReference.getSharedPointer (o) : nullptr;
+    }
+};
+
+
+#endif   // JUCE_WEAKREFERENCE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Result.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Result.cpp
new file mode 100644
index 0000000..1734907
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Result.cpp
@@ -0,0 +1,83 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+Result::Result() noexcept {}
+
+Result::Result (const String& message) noexcept
+    : errorMessage (message)
+{
+}
+
+Result::Result (const Result& other)
+    : errorMessage (other.errorMessage)
+{
+}
+
+Result& Result::operator= (const Result& other)
+{
+    errorMessage = other.errorMessage;
+    return *this;
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+Result::Result (Result&& other) noexcept
+    : errorMessage (static_cast <String&&> (other.errorMessage))
+{
+}
+
+Result& Result::operator= (Result&& other) noexcept
+{
+    errorMessage = static_cast <String&&> (other.errorMessage);
+    return *this;
+}
+#endif
+
+bool Result::operator== (const Result& other) const noexcept
+{
+    return errorMessage == other.errorMessage;
+}
+
+bool Result::operator!= (const Result& other) const noexcept
+{
+    return errorMessage != other.errorMessage;
+}
+
+Result Result::fail (const String& errorMessage) noexcept
+{
+    return Result (errorMessage.isEmpty() ? "Unknown Error" : errorMessage);
+}
+
+const String& Result::getErrorMessage() const noexcept
+{
+    return errorMessage;
+}
+
+bool Result::wasOk() const noexcept         { return errorMessage.isEmpty(); }
+Result::operator bool() const noexcept      { return errorMessage.isEmpty(); }
+bool Result::failed() const noexcept        { return errorMessage.isNotEmpty(); }
+bool Result::operator!() const noexcept     { return errorMessage.isNotEmpty(); }
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Result.h b/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Result.h
new file mode 100644
index 0000000..7c320ac
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Result.h
@@ -0,0 +1,125 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_RESULT_H_INCLUDED
+#define JUCE_RESULT_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Represents the 'success' or 'failure' of an operation, and holds an associated
+    error message to describe the error when there's a failure.
+
+    E.g.
+    @code
+    Result myOperation()
+    {
+        if (doSomeKindOfFoobar())
+            return Result::ok();
+        else
+            return Result::fail ("foobar didn't work!");
+    }
+
+    const Result result (myOperation());
+
+    if (result.wasOk())
+    {
+        ...it's all good...
+    }
+    else
+    {
+        warnUserAboutFailure ("The foobar operation failed! Error message was: "
+                                + result.getErrorMessage());
+    }
+    @endcode
+*/
+class JUCE_API  Result
+{
+public:
+    //==============================================================================
+    /** Creates and returns a 'successful' result. */
+    static Result ok() noexcept                         { return Result(); }
+
+    /** Creates a 'failure' result.
+        If you pass a blank error message in here, a default "Unknown Error" message
+        will be used instead.
+    */
+    static Result fail (const String& errorMessage) noexcept;
+
+    //==============================================================================
+    /** Returns true if this result indicates a success. */
+    bool wasOk() const noexcept;
+
+    /** Returns true if this result indicates a failure.
+        You can use getErrorMessage() to retrieve the error message associated
+        with the failure.
+    */
+    bool failed() const noexcept;
+
+    /** Returns true if this result indicates a success.
+        This is equivalent to calling wasOk().
+    */
+    operator bool() const noexcept;
+
+    /** Returns true if this result indicates a failure.
+        This is equivalent to calling failed().
+    */
+    bool operator!() const noexcept;
+
+    /** Returns the error message that was set when this result was created.
+        For a successful result, this will be an empty string;
+    */
+    const String& getErrorMessage() const noexcept;
+
+    //==============================================================================
+    Result (const Result&);
+    Result& operator= (const Result&);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    Result (Result&&) noexcept;
+    Result& operator= (Result&&) noexcept;
+   #endif
+
+    bool operator== (const Result& other) const noexcept;
+    bool operator!= (const Result& other) const noexcept;
+
+private:
+    String errorMessage;
+
+    // The default constructor is not for public use!
+    // Instead, use Result::ok() or Result::fail()
+    Result() noexcept;
+    explicit Result (const String&) noexcept;
+
+    // These casts are private to prevent people trying to use the Result object in numeric contexts
+    operator int() const;
+    operator void*() const;
+};
+
+
+#endif   // JUCE_RESULT_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Uuid.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Uuid.cpp
new file mode 100644
index 0000000..eb74964
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Uuid.cpp
@@ -0,0 +1,117 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+Uuid::Uuid()
+{
+    Random r;
+
+    for (size_t i = 0; i < sizeof (uuid); ++i)
+        uuid[i] = (uint8) (r.nextInt (256));
+
+    // To make it RFC 4122 compliant, need to force a few bits...
+    uuid[6] = (uuid[6] & 0x0f) | 0x40;
+    uuid[8] = (uuid[8] & 0x3f) | 0x80;
+}
+
+Uuid::~Uuid() noexcept {}
+
+Uuid::Uuid (const Uuid& other) noexcept
+{
+    memcpy (uuid, other.uuid, sizeof (uuid));
+}
+
+Uuid& Uuid::operator= (const Uuid& other) noexcept
+{
+    memcpy (uuid, other.uuid, sizeof (uuid));
+    return *this;
+}
+
+bool Uuid::operator== (const Uuid& other) const noexcept    { return memcmp (uuid, other.uuid, sizeof (uuid)) == 0; }
+bool Uuid::operator!= (const Uuid& other) const noexcept    { return ! operator== (other); }
+
+Uuid Uuid::null() noexcept
+{
+    return Uuid ((const uint8*) nullptr);
+}
+
+bool Uuid::isNull() const noexcept
+{
+    for (size_t i = 0; i < sizeof (uuid); ++i)
+        if (uuid[i] != 0)
+            return false;
+
+    return true;
+}
+
+String Uuid::getHexRegion (int start, int length) const
+{
+    return String::toHexString (uuid + start, length, 0);
+}
+
+String Uuid::toString() const
+{
+    return getHexRegion (0, 16);
+}
+
+String Uuid::toDashedString() const
+{
+    return getHexRegion (0, 4)
+            + "-" + getHexRegion (4, 2)
+            + "-" + getHexRegion (6, 2)
+            + "-" + getHexRegion (8, 2)
+            + "-" + getHexRegion (10, 6);
+}
+
+Uuid::Uuid (const String& uuidString)
+{
+    operator= (uuidString);
+}
+
+Uuid& Uuid::operator= (const String& uuidString)
+{
+    MemoryBlock mb;
+    mb.loadFromHexString (uuidString);
+    mb.ensureSize (sizeof (uuid), true);
+    mb.copyTo (uuid, 0, sizeof (uuid));
+    return *this;
+}
+
+Uuid::Uuid (const uint8* const rawData) noexcept
+{
+    operator= (rawData);
+}
+
+Uuid& Uuid::operator= (const uint8* const rawData) noexcept
+{
+    if (rawData != nullptr)
+        memcpy (uuid, rawData, sizeof (uuid));
+    else
+        zeromem (uuid, sizeof (uuid));
+
+    return *this;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Uuid.h b/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Uuid.h
new file mode 100644
index 0000000..cd7af0d
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_Uuid.h
@@ -0,0 +1,121 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_UUID_H_INCLUDED
+#define JUCE_UUID_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A universally unique 128-bit identifier.
+
+    This class generates very random unique numbers. It's vanishingly unlikely
+    that two identical UUIDs would ever be created by chance. The values are
+    formatted to meet the RFC 4122 version 4 standard.
+
+    The class includes methods for saving the ID as a string or as raw binary data.
+*/
+class JUCE_API  Uuid
+{
+public:
+    //==============================================================================
+    /** Creates a new unique ID, compliant with RFC 4122 version 4. */
+    Uuid();
+
+    /** Destructor. */
+    ~Uuid() noexcept;
+
+    /** Creates a copy of another UUID. */
+    Uuid (const Uuid&) noexcept;
+
+    /** Copies another UUID. */
+    Uuid& operator= (const Uuid&) noexcept;
+
+    //==============================================================================
+    /** Returns true if the ID is zero. */
+    bool isNull() const noexcept;
+
+    /** Returns a null Uuid object. */
+    static Uuid null() noexcept;
+
+    bool operator== (const Uuid&) const noexcept;
+    bool operator!= (const Uuid&) const noexcept;
+
+    //==============================================================================
+    /** Returns a stringified version of this UUID.
+
+        A Uuid object can later be reconstructed from this string using operator= or
+        the constructor that takes a string parameter.
+
+        @returns a 32 character hex string.
+    */
+    String toString() const;
+
+    /** Returns a stringified version of this UUID, separating it into sections with dashes.
+        @returns a string in the format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+    */
+    String toDashedString() const;
+
+    /** Creates an ID from an encoded string version.
+        @see toString
+    */
+    Uuid (const String& uuidString);
+
+    /** Copies from a stringified UUID.
+        The string passed in should be one that was created with the toString() method.
+    */
+    Uuid& operator= (const String& uuidString);
+
+
+    //==============================================================================
+    /** Returns a pointer to the internal binary representation of the ID.
+
+        This is an array of 16 bytes. To reconstruct a Uuid from its data, use
+        the constructor or operator= method that takes an array of uint8s.
+    */
+    const uint8* getRawData() const noexcept                { return uuid; }
+
+    /** Creates a UUID from a 16-byte array.
+        @see getRawData
+    */
+    Uuid (const uint8* rawData) noexcept;
+
+    /** Sets this UUID from 16-bytes of raw data. */
+    Uuid& operator= (const uint8* rawData) noexcept;
+
+
+private:
+    //==============================================================================
+    uint8 uuid[16];
+    String getHexRegion (int, int) const;
+
+    JUCE_LEAK_DETECTOR (Uuid)
+};
+
+
+#endif   // JUCE_UUID_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_WindowsRegistry.h b/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_WindowsRegistry.h
new file mode 100644
index 0000000..a1fb2a2
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/misc/juce_WindowsRegistry.h
@@ -0,0 +1,141 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_WINDOWSREGISTRY_H_INCLUDED
+#define JUCE_WINDOWSREGISTRY_H_INCLUDED
+
+#if JUCE_WINDOWS || DOXYGEN
+
+/**
+    Contains some static helper functions for manipulating the MS Windows registry
+    (Only available on Windows, of course!)
+*/
+class JUCE_API  WindowsRegistry
+{
+public:
+    /** These values can be used to specify whether the 32- or 64-bit registry should be used.
+        When running on a 32-bit OS, there is no 64-bit registry, so the mode will be ignored.
+    */
+    enum WoW64Mode
+    {
+        /** Default handling: 32-bit apps will use the 32-bit registry, and 64-bit apps
+            will use the 64-bit registry. */
+        WoW64_Default = 0,
+
+        /** Always use the 64-bit registry store. (KEY_WOW64_64KEY). */
+        WoW64_64bit  = 0x100,
+
+        /** Always use the 32-bit registry store. (KEY_WOW64_32KEY). */
+        WoW64_32bit  = 0x200
+    };
+
+    //==============================================================================
+    /** Returns a string from the registry.
+        The path is a string for the entire path of a value in the registry,
+        e.g. "HKEY_CURRENT_USER\Software\foo\bar"
+    */
+    static String JUCE_CALLTYPE getValue (const String& regValuePath,
+                                          const String& defaultValue = String::empty,
+                                          WoW64Mode mode = WoW64_Default);
+
+    /** Reads a binary block from the registry.
+        The path is a string for the entire path of a value in the registry,
+        e.g. "HKEY_CURRENT_USER\Software\foo\bar"
+        @returns a DWORD indicating the type of the key.
+    */
+    static uint32 JUCE_CALLTYPE getBinaryValue (const String& regValuePath, MemoryBlock& resultData, WoW64Mode mode = WoW64_Default);
+
+    /** Sets a registry value as a string.
+        This will take care of creating any groups needed to get to the given registry value.
+    */
+    static bool JUCE_CALLTYPE setValue (const String& regValuePath, const String& value, WoW64Mode mode = WoW64_Default);
+
+    /** Sets a registry value as a DWORD.
+        This will take care of creating any groups needed to get to the given registry value.
+    */
+    static bool JUCE_CALLTYPE setValue (const String& regValuePath, uint32 value, WoW64Mode mode = WoW64_Default);
+
+    /** Sets a registry value as a QWORD.
+        This will take care of creating any groups needed to get to the given registry value.
+    */
+    static bool JUCE_CALLTYPE setValue (const String& regValuePath, uint64 value, WoW64Mode mode = WoW64_Default);
+
+    /** Sets a registry value as a binary block.
+        This will take care of creating any groups needed to get to the given registry value.
+    */
+    static bool JUCE_CALLTYPE setValue (const String& regValuePath, const MemoryBlock& value, WoW64Mode mode = WoW64_Default);
+
+    /** Returns true if the given value exists in the registry. */
+    static bool JUCE_CALLTYPE valueExists (const String& regValuePath, WoW64Mode mode = WoW64_Default);
+
+    /** Returns true if the given key exists in the registry. */
+    static bool JUCE_CALLTYPE keyExists (const String& regValuePath, WoW64Mode mode = WoW64_Default);
+
+    /** Deletes a registry value. */
+    static void JUCE_CALLTYPE deleteValue (const String& regValuePath, WoW64Mode mode = WoW64_Default);
+
+    /** Deletes a registry key (which is registry-talk for 'folder'). */
+    static void JUCE_CALLTYPE deleteKey (const String& regKeyPath, WoW64Mode mode = WoW64_Default);
+
+    /** Creates a file association in the registry.
+
+        This lets you set the executable that should be launched by a given file extension.
+        @param fileExtension        the file extension to associate, including the
+                                    initial dot, e.g. ".txt"
+        @param symbolicDescription  a space-free short token to identify the file type
+        @param fullDescription      a human-readable description of the file type
+        @param targetExecutable     the executable that should be launched
+        @param iconResourceNumber   the icon that gets displayed for the file type will be
+                                    found by looking up this resource number in the
+                                    executable. Pass 0 here to not use an icon
+        @param registerForCurrentUserOnly   if false, this will try to register the association
+                                    for all users (you might not have permission to do this
+                                    unless running in an installer). If true, it will register the
+                                    association in HKEY_CURRENT_USER.
+        @param mode                 the WoW64 mode to use for choosing the database
+    */
+    static bool JUCE_CALLTYPE registerFileAssociation (const String& fileExtension,
+                                                       const String& symbolicDescription,
+                                                       const String& fullDescription,
+                                                       const File& targetExecutable,
+                                                       int iconResourceNumber,
+                                                       bool registerForCurrentUserOnly,
+                                                       WoW64Mode mode = WoW64_Default);
+
+    // DEPRECATED: use the other methods with a WoW64Mode parameter of WoW64_64bit instead.
+    JUCE_DEPRECATED (static String getValueWow64 (const String&, const String& defaultValue = String::empty));
+    JUCE_DEPRECATED (static bool valueExistsWow64 (const String&));
+    JUCE_DEPRECATED (static bool keyExistsWow64 (const String&));
+
+private:
+    WindowsRegistry() JUCE_DELETED_FUNCTION;
+    JUCE_DECLARE_NON_COPYABLE (WindowsRegistry)
+};
+
+#endif
+#endif   // JUCE_WINDOWSREGISTRY_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/java/JuceAppActivity.java b/src/htio2/JUCE-3.0.8/modules/juce_core/native/java/JuceAppActivity.java
new file mode 100644
index 0000000..882d0e0
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/java/JuceAppActivity.java
@@ -0,0 +1,746 @@
+/*
+  ==============================================================================
+
+   This file is part of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission is granted to use this software under the terms of either:
+   a) the GPL v2 (or any later version)
+   b) the Affero GPL v3
+
+   Details of these licenses can be found at: www.gnu.org/licenses
+
+   JUCE 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.
+
+   ------------------------------------------------------------------------------
+
+   To release a closed-source product which uses JUCE, commercial licenses are
+   available: visit www.juce.com for more information.
+
+  ==============================================================================
+*/
+
+package com.juce;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.*;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.graphics.*;
+import android.opengl.*;
+import android.text.ClipboardManager;
+import android.text.InputType;
+import android.util.DisplayMetrics;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.HttpURLConnection;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+import android.media.AudioManager;
+import android.media.MediaScannerConnection;
+import android.media.MediaScannerConnection.MediaScannerConnectionClient;
+
+//==============================================================================
+public final class JuceAppActivity   extends Activity
+{
+    //==============================================================================
+    static
+    {
+        System.loadLibrary ("juce_jni");
+    }
+
+    @Override
+    public final void onCreate (Bundle savedInstanceState)
+    {
+        super.onCreate (savedInstanceState);
+
+        viewHolder = new ViewHolder (this);
+        setContentView (viewHolder);
+
+        setVolumeControlStream (AudioManager.STREAM_MUSIC);
+    }
+
+    @Override
+    protected final void onDestroy()
+    {
+        quitApp();
+        super.onDestroy();
+    }
+
+    @Override
+    protected final void onPause()
+    {
+        if (viewHolder != null)
+            viewHolder.onPause();
+
+        suspendApp();
+        super.onPause();
+    }
+
+    @Override
+    protected final void onResume()
+    {
+        super.onResume();
+
+        if (viewHolder != null)
+            viewHolder.onResume();
+
+        resumeApp();
+    }
+
+    @Override
+    public void onConfigurationChanged (Configuration cfg)
+    {
+        super.onConfigurationChanged (cfg);
+        setContentView (viewHolder);
+    }
+
+    private void callAppLauncher()
+    {
+        launchApp (getApplicationInfo().publicSourceDir,
+                   getApplicationInfo().dataDir);
+    }
+
+    //==============================================================================
+    private native void launchApp (String appFile, String appDataDir);
+    private native void quitApp();
+    private native void suspendApp();
+    private native void resumeApp();
+    private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
+
+    //==============================================================================
+    public native void deliverMessage (long value);
+    private android.os.Handler messageHandler = new android.os.Handler();
+
+    public final void postMessage (long value)
+    {
+        messageHandler.post (new MessageCallback (value));
+    }
+
+    private final class MessageCallback  implements Runnable
+    {
+        public MessageCallback (long value_)        { value = value_; }
+        public final void run()                     { deliverMessage (value); }
+
+        private long value;
+    }
+
+    //==============================================================================
+    private ViewHolder viewHolder;
+
+    public final ComponentPeerView createNewView (boolean opaque, long host)
+    {
+        ComponentPeerView v = new ComponentPeerView (this, opaque, host);
+        viewHolder.addView (v);
+        return v;
+    }
+
+    public final void deleteView (ComponentPeerView view)
+    {
+        ViewGroup group = (ViewGroup) (view.getParent());
+
+        if (group != null)
+            group.removeView (view);
+    }
+
+    final class ViewHolder  extends ViewGroup
+    {
+        public ViewHolder (Context context)
+        {
+            super (context);
+            setDescendantFocusability (ViewGroup.FOCUS_AFTER_DESCENDANTS);
+            setFocusable (false);
+        }
+
+        protected final void onLayout (boolean changed, int left, int top, int right, int bottom)
+        {
+            setScreenSize (getWidth(), getHeight(), getDPI());
+
+            if (isFirstResize)
+            {
+                isFirstResize = false;
+                callAppLauncher();
+            }
+        }
+
+        public final void onPause()
+        {
+            for (int i = getChildCount(); --i >= 0;)
+            {
+                View v = getChildAt (i);
+
+                if (v instanceof ComponentPeerView)
+                    ((ComponentPeerView) v).onPause();
+            }
+        }
+
+        public final void onResume()
+        {
+            for (int i = getChildCount(); --i >= 0;)
+            {
+                View v = getChildAt (i);
+
+                if (v instanceof ComponentPeerView)
+                    ((ComponentPeerView) v).onResume();
+             }
+         }
+
+        private final int getDPI()
+        {
+            DisplayMetrics metrics = new DisplayMetrics();
+            getWindowManager().getDefaultDisplay().getMetrics (metrics);
+            return metrics.densityDpi;
+        }
+
+        private boolean isFirstResize = true;
+    }
+
+    public final void excludeClipRegion (android.graphics.Canvas canvas, float left, float top, float right, float bottom)
+    {
+        canvas.clipRect (left, top, right, bottom, android.graphics.Region.Op.DIFFERENCE);
+    }
+
+    //==============================================================================
+    public final String getClipboardContent()
+    {
+        ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
+        return clipboard.getText().toString();
+    }
+
+    public final void setClipboardContent (String newText)
+    {
+        ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
+        clipboard.setText (newText);
+    }
+
+    //==============================================================================
+    public final void showMessageBox (String title, String message, final long callback)
+    {
+        AlertDialog.Builder builder = new AlertDialog.Builder (this);
+        builder.setTitle (title)
+               .setMessage (message)
+               .setCancelable (true)
+               .setPositiveButton ("OK", new DialogInterface.OnClickListener()
+                    {
+                        public void onClick (DialogInterface dialog, int id)
+                        {
+                            dialog.cancel();
+                            JuceAppActivity.this.alertDismissed (callback, 0);
+                        }
+                    });
+
+        builder.create().show();
+    }
+
+    public final void showOkCancelBox (String title, String message, final long callback)
+    {
+        AlertDialog.Builder builder = new AlertDialog.Builder (this);
+        builder.setTitle (title)
+               .setMessage (message)
+               .setCancelable (true)
+               .setPositiveButton ("OK", new DialogInterface.OnClickListener()
+                    {
+                        public void onClick (DialogInterface dialog, int id)
+                        {
+                            dialog.cancel();
+                            JuceAppActivity.this.alertDismissed (callback, 1);
+                        }
+                    })
+               .setNegativeButton ("Cancel", new DialogInterface.OnClickListener()
+                    {
+                        public void onClick (DialogInterface dialog, int id)
+                        {
+                            dialog.cancel();
+                            JuceAppActivity.this.alertDismissed (callback, 0);
+                        }
+                    });
+
+        builder.create().show();
+    }
+
+    public final void showYesNoCancelBox (String title, String message, final long callback)
+    {
+        AlertDialog.Builder builder = new AlertDialog.Builder (this);
+        builder.setTitle (title)
+               .setMessage (message)
+               .setCancelable (true)
+               .setPositiveButton ("Yes", new DialogInterface.OnClickListener()
+                    {
+                        public void onClick (DialogInterface dialog, int id)
+                        {
+                            dialog.cancel();
+                            JuceAppActivity.this.alertDismissed (callback, 1);
+                        }
+                    })
+               .setNegativeButton ("No", new DialogInterface.OnClickListener()
+                    {
+                        public void onClick (DialogInterface dialog, int id)
+                        {
+                            dialog.cancel();
+                            JuceAppActivity.this.alertDismissed (callback, 2);
+                        }
+                    })
+               .setNeutralButton ("Cancel", new DialogInterface.OnClickListener()
+                    {
+                        public void onClick (DialogInterface dialog, int id)
+                        {
+                            dialog.cancel();
+                            JuceAppActivity.this.alertDismissed (callback, 0);
+                        }
+                    });
+
+        builder.create().show();
+    }
+
+    public native void alertDismissed (long callback, int id);
+
+    //==============================================================================
+    public final class ComponentPeerView extends ViewGroup
+                                         implements View.OnFocusChangeListener
+    {
+        public ComponentPeerView (Context context, boolean opaque_, long host)
+        {
+            super (context);
+            this.host = host;
+            setWillNotDraw (false);
+            opaque = opaque_;
+
+            setFocusable (true);
+            setFocusableInTouchMode (true);
+            setOnFocusChangeListener (this);
+            requestFocus();
+        }
+
+        //==============================================================================
+        private native void handlePaint (long host, Canvas canvas);
+
+        @Override
+        public void onDraw (Canvas canvas)
+        {
+            handlePaint (host, canvas);
+        }
+
+        @Override
+        public boolean isOpaque()
+        {
+            return opaque;
+        }
+
+        private boolean opaque;
+        private long host;
+
+        //==============================================================================
+        private native void handleMouseDown (long host, int index, float x, float y, long time);
+        private native void handleMouseDrag (long host, int index, float x, float y, long time);
+        private native void handleMouseUp   (long host, int index, float x, float y, long time);
+
+        @Override
+        public boolean onTouchEvent (MotionEvent event)
+        {
+            int action = event.getAction();
+            long time = event.getEventTime();
+
+            switch (action & MotionEvent.ACTION_MASK)
+            {
+                case MotionEvent.ACTION_DOWN:
+                    handleMouseDown (host, event.getPointerId(0), event.getX(), event.getY(), time);
+                    return true;
+
+                case MotionEvent.ACTION_CANCEL:
+                case MotionEvent.ACTION_UP:
+                    handleMouseUp (host, event.getPointerId(0), event.getX(), event.getY(), time);
+                    return true;
+
+                case MotionEvent.ACTION_MOVE:
+                {
+                    int n = event.getPointerCount();
+                    for (int i = 0; i < n; ++i)
+                        handleMouseDrag (host, event.getPointerId(i), event.getX(i), event.getY(i), time);
+
+                    return true;
+                }
+
+                case MotionEvent.ACTION_POINTER_UP:
+                {
+                    int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+                    handleMouseUp (host, event.getPointerId(i), event.getX(i), event.getY(i), time);
+                    return true;
+                }
+
+                case MotionEvent.ACTION_POINTER_DOWN:
+                {
+                    int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+                    handleMouseDown (host, event.getPointerId(i), event.getX(i), event.getY(i), time);
+                    return true;
+                }
+
+                default:
+                    break;
+            }
+
+            return false;
+        }
+
+        //==============================================================================
+        private native void handleKeyDown (long host, int keycode, int textchar);
+        private native void handleKeyUp (long host, int keycode, int textchar);
+
+        public void showKeyboard (String type)
+        {
+            InputMethodManager imm = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE);
+
+            if (imm != null)
+            {
+                if (type.length() > 0)
+                {
+                    imm.showSoftInput (this, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
+                    imm.setInputMethod (getWindowToken(), type);
+                }
+                else
+                {
+                    imm.hideSoftInputFromWindow (getWindowToken(), 0);
+                }
+            }
+        }
+
+        @Override
+        public boolean onKeyDown (int keyCode, KeyEvent event)
+        {
+            switch (keyCode)
+            {
+                case KeyEvent.KEYCODE_VOLUME_UP:
+                case KeyEvent.KEYCODE_VOLUME_DOWN:
+                    return super.onKeyDown (keyCode, event);
+
+                default: break;
+            }
+
+            handleKeyDown (host, keyCode, event.getUnicodeChar());
+            return true;
+        }
+
+        @Override
+        public boolean onKeyUp (int keyCode, KeyEvent event)
+        {
+            handleKeyUp (host, keyCode, event.getUnicodeChar());
+            return true;
+        }
+
+        // this is here to make keyboard entry work on a Galaxy Tab2 10.1
+        @Override
+        public InputConnection onCreateInputConnection (EditorInfo outAttrs)
+        {
+            outAttrs.actionLabel = "";
+            outAttrs.hintText = "";
+            outAttrs.initialCapsMode = 0;
+            outAttrs.initialSelEnd = outAttrs.initialSelStart = -1;
+            outAttrs.label = "";
+            outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI;
+            outAttrs.inputType = InputType.TYPE_NULL;
+
+            return new BaseInputConnection (this, false);
+        }
+
+        //==============================================================================
+        @Override
+        protected void onSizeChanged (int w, int h, int oldw, int oldh)
+        {
+            super.onSizeChanged (w, h, oldw, oldh);
+            viewSizeChanged (host);
+        }
+
+        @Override
+        protected void onLayout (boolean changed, int left, int top, int right, int bottom)
+        {
+            for (int i = getChildCount(); --i >= 0;)
+                requestTransparentRegion (getChildAt (i));
+        }
+
+        private native void viewSizeChanged (long host);
+
+        @Override
+        public void onFocusChange (View v, boolean hasFocus)
+        {
+            if (v == this)
+                focusChanged (host, hasFocus);
+        }
+
+        private native void focusChanged (long host, boolean hasFocus);
+
+        public void setViewName (String newName)    {}
+
+        public boolean isVisible()                  { return getVisibility() == VISIBLE; }
+        public void setVisible (boolean b)          { setVisibility (b ? VISIBLE : INVISIBLE); }
+
+        public boolean containsPoint (int x, int y)
+        {
+            return true; //xxx needs to check overlapping views
+        }
+
+        public final void onPause()
+        {
+            for (int i = getChildCount(); --i >= 0;)
+            {
+                View v = getChildAt (i);
+
+                if (v instanceof OpenGLView)
+                    ((OpenGLView) v).onPause();
+            }
+        }
+
+        public final void onResume()
+        {
+            for (int i = getChildCount(); --i >= 0;)
+            {
+                View v = getChildAt (i);
+
+                if (v instanceof OpenGLView)
+                    ((OpenGLView) v).onResume();
+            }
+        }
+
+        public OpenGLView createGLView()
+        {
+            OpenGLView glView = new OpenGLView (getContext());
+            addView (glView);
+            return glView;
+        }
+    }
+
+    //==============================================================================
+    public final class OpenGLView   extends GLSurfaceView
+                                    implements GLSurfaceView.Renderer
+    {
+        OpenGLView (Context context)
+        {
+            super (context);
+            setEGLContextClientVersion (2);
+            setRenderer (this);
+            setRenderMode (RENDERMODE_WHEN_DIRTY);
+        }
+
+        @Override
+        public void onSurfaceCreated (GL10 unused, EGLConfig config)
+        {
+            contextCreated();
+        }
+
+        @Override
+        public void onSurfaceChanged (GL10 unused, int width, int height)
+        {
+            contextChangedSize();
+        }
+
+        @Override
+        public void onDrawFrame (GL10 unused)
+        {
+            render();
+        }
+
+        private native void contextCreated();
+        private native void contextChangedSize();
+        private native void render();
+    }
+
+    //==============================================================================
+    public final int[] renderGlyph (char glyph, Paint paint, android.graphics.Matrix matrix, Rect bounds)
+    {
+        Path p = new Path();
+        paint.getTextPath (String.valueOf (glyph), 0, 1, 0.0f, 0.0f, p);
+
+        RectF boundsF = new RectF();
+        p.computeBounds (boundsF, true);
+        matrix.mapRect (boundsF);
+
+        boundsF.roundOut (bounds);
+        bounds.left--;
+        bounds.right++;
+
+        final int w = bounds.width();
+        final int h = Math.max (1, bounds.height());
+
+        Bitmap bm = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888);
+
+        Canvas c = new Canvas (bm);
+        matrix.postTranslate (-bounds.left, -bounds.top);
+        c.setMatrix (matrix);
+        c.drawPath (p, paint);
+
+        final int sizeNeeded = w * h;
+        if (cachedRenderArray.length < sizeNeeded)
+            cachedRenderArray = new int [sizeNeeded];
+
+        bm.getPixels (cachedRenderArray, 0, w, 0, 0, w, h);
+        bm.recycle();
+        return cachedRenderArray;
+    }
+
+    private int[] cachedRenderArray = new int [256];
+
+    //==============================================================================
+    public static class HTTPStream
+    {
+        public HTTPStream (HttpURLConnection connection_,
+                           int[] statusCode, StringBuffer responseHeaders) throws IOException
+        {
+            connection = connection_;
+
+            try
+            {
+                inputStream = new BufferedInputStream (connection.getInputStream());
+            }
+            catch (IOException e)
+            {
+                if (connection.getResponseCode() < org.apache.http.HttpStatus.SC_BAD_REQUEST)
+                    throw e;
+            }
+            finally
+            {
+                statusCode[0] = connection.getResponseCode();
+            }
+
+            if (statusCode[0] >= org.apache.http.HttpStatus.SC_BAD_REQUEST)
+                inputStream = connection.getErrorStream();
+            else
+                inputStream = connection.getInputStream();
+
+            for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
+                if (entry.getKey() != null && entry.getValue() != null)
+                    responseHeaders.append (entry.getKey() + ": "
+                                             + android.text.TextUtils.join (",", entry.getValue()) + "\n");
+        }
+
+        public final void release()
+        {
+            try
+            {
+                inputStream.close();
+            }
+            catch (IOException e)
+            {}
+
+            connection.disconnect();
+        }
+
+        public final int read (byte[] buffer, int numBytes)
+        {
+            int num = 0;
+
+            try
+            {
+                num = inputStream.read (buffer, 0, numBytes);
+            }
+            catch (IOException e)
+            {}
+
+            if (num > 0)
+                position += num;
+
+            return num;
+        }
+
+        public final long getPosition()                 { return position; }
+        public final long getTotalLength()              { return -1; }
+        public final boolean isExhausted()              { return false; }
+        public final boolean setPosition (long newPos)  { return false; }
+
+        private HttpURLConnection connection;
+        private InputStream inputStream;
+        private long position;
+    }
+
+    public static final HTTPStream createHTTPStream (String address,
+                                                     boolean isPost, byte[] postData, String headers,
+                                                     int timeOutMs, int[] statusCode,
+                                                     StringBuffer responseHeaders)
+    {
+        try
+        {
+            HttpURLConnection connection = (HttpURLConnection) (new URL(address)
+                    .openConnection());
+            if (connection != null)
+            {
+                try
+                {
+                    if (isPost)
+                    {
+                        connection.setRequestMethod("POST");
+                        connection.setConnectTimeout(timeOutMs);
+                        connection.setDoOutput(true);
+                        connection.setChunkedStreamingMode(0);
+                        OutputStream out = connection.getOutputStream();
+                        out.write(postData);
+                        out.flush();
+                    }
+
+                    return new HTTPStream (connection, statusCode, responseHeaders);
+                }
+                catch (Throwable e)
+                {
+                    connection.disconnect();
+                }
+            }
+        }
+        catch (Throwable e) {}
+
+        return null;
+    }
+
+    public final void launchURL (String url)
+    {
+        startActivity (new Intent (Intent.ACTION_VIEW, Uri.parse (url)));
+    }
+
+    public static final String getLocaleValue (boolean isRegion)
+    {
+        java.util.Locale locale = java.util.Locale.getDefault();
+
+        return isRegion ? locale.getDisplayCountry  (java.util.Locale.US)
+                        : locale.getDisplayLanguage (java.util.Locale.US);
+    }
+
+    //==============================================================================
+    private final class SingleMediaScanner  implements MediaScannerConnectionClient
+    {
+        public SingleMediaScanner (Context context, String filename)
+        {
+            file = filename;
+            msc = new MediaScannerConnection (context, this);
+            msc.connect();
+        }
+
+        @Override
+        public void onMediaScannerConnected()
+        {
+            msc.scanFile (file, null);
+        }
+
+        @Override
+        public void onScanCompleted (String path, Uri uri)
+        {
+            msc.disconnect();
+        }
+
+        private MediaScannerConnection msc;
+        private String file;
+    }
+
+    public final void scanFile (String filename)
+    {
+        new SingleMediaScanner (this, filename);
+    }
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_BasicNativeHeaders.h b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_BasicNativeHeaders.h
new file mode 100644
index 0000000..cdaa0ef
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_BasicNativeHeaders.h
@@ -0,0 +1,223 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_BASICNATIVEHEADERS_H_INCLUDED
+#define JUCE_BASICNATIVEHEADERS_H_INCLUDED
+
+#include "../system/juce_TargetPlatform.h"
+#undef T
+
+//==============================================================================
+#if JUCE_MAC || JUCE_IOS
+
+ #if JUCE_IOS
+  #import <Foundation/Foundation.h>
+  #import <UIKit/UIKit.h>
+  #import <CoreData/CoreData.h>
+  #import <MobileCoreServices/MobileCoreServices.h>
+  #include <sys/fcntl.h>
+ #else
+  #define Point CarbonDummyPointName
+  #define Component CarbonDummyCompName
+  #import <Cocoa/Cocoa.h>
+  #import <CoreAudio/HostTime.h>
+  #undef Point
+  #undef Component
+  #include <sys/dir.h>
+ #endif
+
+ #include <sys/socket.h>
+ #include <sys/sysctl.h>
+ #include <sys/stat.h>
+ #include <sys/param.h>
+ #include <sys/mount.h>
+ #include <sys/utsname.h>
+ #include <sys/mman.h>
+ #include <fnmatch.h>
+ #include <utime.h>
+ #include <dlfcn.h>
+ #include <ifaddrs.h>
+ #include <net/if_dl.h>
+ #include <mach/mach_time.h>
+ #include <mach-o/dyld.h>
+ #include <objc/runtime.h>
+ #include <objc/objc.h>
+ #include <objc/message.h>
+
+//==============================================================================
+#elif JUCE_WINDOWS
+ #if JUCE_MSVC
+  #ifndef _CPPRTTI
+   #error "You're compiling without RTTI enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
+  #endif
+
+  #ifndef _CPPUNWIND
+   #error "You're compiling without exceptions enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
+  #endif
+
+  #pragma warning (push)
+  #pragma warning (disable : 4100 4201 4514 4312 4995)
+ #endif
+
+ #define STRICT 1
+ #define WIN32_LEAN_AND_MEAN 1
+ #if JUCE_MINGW
+  #define _WIN32_WINNT 0x0501
+ #else
+  #define _WIN32_WINNT 0x0600
+ #endif
+ #define _UNICODE 1
+ #define UNICODE 1
+ #ifndef _WIN32_IE
+  #define _WIN32_IE 0x0500
+ #endif
+
+ #include <windows.h>
+ #include <shellapi.h>
+ #include <tchar.h>
+ #include <stddef.h>
+ #include <ctime>
+ #include <wininet.h>
+ #include <nb30.h>
+ #include <iphlpapi.h>
+ #include <mapi.h>
+ #include <float.h>
+ #include <process.h>
+ #include <shlobj.h>
+ #include <shlwapi.h>
+ #include <mmsystem.h>
+
+ #if JUCE_MINGW
+  #include <basetyps.h>
+ #else
+  #include <crtdbg.h>
+  #include <comutil.h>
+ #endif
+
+ #undef PACKED
+
+ #if JUCE_MSVC
+  #pragma warning (pop)
+  #pragma warning (4: 4511 4512 4100 /*4365*/)  // (enable some warnings that are turned off in VC8)
+ #endif
+
+ #if JUCE_MSVC && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
+  #pragma comment (lib, "kernel32.lib")
+  #pragma comment (lib, "user32.lib")
+  #pragma comment (lib, "wininet.lib")
+  #pragma comment (lib, "advapi32.lib")
+  #pragma comment (lib, "ws2_32.lib")
+  #pragma comment (lib, "version.lib")
+  #pragma comment (lib, "shlwapi.lib")
+  #pragma comment (lib, "winmm.lib")
+
+  #ifdef _NATIVE_WCHAR_T_DEFINED
+   #ifdef _DEBUG
+    #pragma comment (lib, "comsuppwd.lib")
+   #else
+    #pragma comment (lib, "comsuppw.lib")
+   #endif
+  #else
+   #ifdef _DEBUG
+    #pragma comment (lib, "comsuppd.lib")
+   #else
+    #pragma comment (lib, "comsupp.lib")
+   #endif
+  #endif
+ #endif
+
+ /* Used with DynamicLibrary to simplify importing functions from a win32 DLL.
+
+    dll: the DynamicLibrary object
+    functionName: function to import
+    localFunctionName: name you want to use to actually call it (must be different)
+    returnType: the return type
+    params: list of params (bracketed)
+ */
+ #define JUCE_LOAD_WINAPI_FUNCTION(dll, functionName, localFunctionName, returnType, params) \
+    typedef returnType (WINAPI *type##localFunctionName) params; \
+    type##localFunctionName localFunctionName = (type##localFunctionName) dll.getFunction (#functionName);
+
+//==============================================================================
+#elif JUCE_LINUX
+ #include <sched.h>
+ #include <pthread.h>
+ #include <sys/time.h>
+ #include <errno.h>
+ #include <sys/stat.h>
+ #include <sys/dir.h>
+ #include <sys/ptrace.h>
+ #include <sys/vfs.h>
+ #include <sys/wait.h>
+ #include <sys/mman.h>
+ #include <fnmatch.h>
+ #include <utime.h>
+ #include <pwd.h>
+ #include <fcntl.h>
+ #include <dlfcn.h>
+ #include <netdb.h>
+ #include <arpa/inet.h>
+ #include <netinet/in.h>
+ #include <sys/types.h>
+ #include <sys/ioctl.h>
+ #include <sys/socket.h>
+ #include <net/if.h>
+ #include <sys/sysinfo.h>
+ #include <sys/file.h>
+ #include <sys/prctl.h>
+ #include <signal.h>
+ #include <stddef.h>
+
+//==============================================================================
+#elif JUCE_ANDROID
+ #include <jni.h>
+ #include <pthread.h>
+ #include <sched.h>
+ #include <sys/time.h>
+ #include <utime.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <dlfcn.h>
+ #include <sys/stat.h>
+ #include <sys/statfs.h>
+ #include <sys/ptrace.h>
+ #include <sys/sysinfo.h>
+ #include <sys/mman.h>
+ #include <pwd.h>
+ #include <dirent.h>
+ #include <fnmatch.h>
+ #include <sys/wait.h>
+#endif
+
+// Need to clear various moronic redefinitions made by system headers..
+#undef max
+#undef min
+#undef direct
+#undef check
+
+#endif   // JUCE_BASICNATIVEHEADERS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Files.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Files.cpp
new file mode 100644
index 0000000..45903b1
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Files.cpp
@@ -0,0 +1,104 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+bool File::isOnCDRomDrive() const
+{
+    return false;
+}
+
+bool File::isOnHardDisk() const
+{
+    return true;
+}
+
+bool File::isOnRemovableDrive() const
+{
+    return false;
+}
+
+String File::getVersion() const
+{
+    return String::empty;
+}
+
+File File::getSpecialLocation (const SpecialLocationType type)
+{
+    switch (type)
+    {
+        case userHomeDirectory:
+        case userDocumentsDirectory:
+        case userMusicDirectory:
+        case userMoviesDirectory:
+        case userPicturesDirectory:
+        case userApplicationDataDirectory:
+        case userDesktopDirectory:
+            return File (android.appDataDir);
+
+        case commonApplicationDataDirectory:
+        case commonDocumentsDirectory:
+            return File (android.appDataDir);
+
+        case globalApplicationsDirectory:
+            return File ("/system/app");
+
+        case tempDirectory:
+            return File (android.appDataDir).getChildFile (".temp");
+
+        case invokedExecutableFile:
+        case currentExecutableFile:
+        case currentApplicationFile:
+        case hostApplicationPath:
+            return juce_getExecutableFile();
+
+        default:
+            jassertfalse; // unknown type?
+            break;
+    }
+
+    return File();
+}
+
+bool File::moveToTrash() const
+{
+    if (! exists())
+        return true;
+
+    // TODO
+    return false;
+}
+
+JUCE_API bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String& parameters)
+{
+    const LocalRef<jstring> t (javaString (fileName));
+    android.activity.callVoidMethod (JuceAppActivity.launchURL, t.get());
+    return true;
+}
+
+void File::revealToUser() const
+{
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_JNIHelpers.h b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_JNIHelpers.h
new file mode 100644
index 0000000..8e8b07d
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_JNIHelpers.h
@@ -0,0 +1,428 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_ANDROID_JNIHELPERS_H_INCLUDED
+#define JUCE_ANDROID_JNIHELPERS_H_INCLUDED
+
+#if ! (defined (JUCE_ANDROID_ACTIVITY_CLASSNAME) && defined (JUCE_ANDROID_ACTIVITY_CLASSPATH))
+ #error "The JUCE_ANDROID_ACTIVITY_CLASSNAME and JUCE_ANDROID_ACTIVITY_CLASSPATH macros must be set!"
+#endif
+
+//==============================================================================
+extern JNIEnv* getEnv() noexcept;
+
+//==============================================================================
+class GlobalRef
+{
+public:
+    inline GlobalRef() noexcept                 : obj (0) {}
+    inline explicit GlobalRef (jobject o)       : obj (retain (o)) {}
+    inline GlobalRef (const GlobalRef& other)   : obj (retain (other.obj)) {}
+    ~GlobalRef()                                { clear(); }
+
+    inline void clear()
+    {
+        if (obj != 0)
+        {
+            getEnv()->DeleteGlobalRef (obj);
+            obj = 0;
+        }
+    }
+
+    inline GlobalRef& operator= (const GlobalRef& other)
+    {
+        jobject newObj = retain (other.obj);
+        clear();
+        obj = newObj;
+        return *this;
+    }
+
+    //==============================================================================
+    inline operator jobject() const noexcept    { return obj; }
+    inline jobject get() const noexcept         { return obj; }
+
+    //==============================================================================
+    #define DECLARE_CALL_TYPE_METHOD(returnType, typeName) \
+        returnType call##typeName##Method (jmethodID methodID, ... ) const \
+        { \
+            va_list args; \
+            va_start (args, methodID); \
+            returnType result = getEnv()->Call##typeName##MethodV (obj, methodID, args); \
+            va_end (args); \
+            return result; \
+        }
+
+    DECLARE_CALL_TYPE_METHOD (jobject, Object)
+    DECLARE_CALL_TYPE_METHOD (jboolean, Boolean)
+    DECLARE_CALL_TYPE_METHOD (jbyte, Byte)
+    DECLARE_CALL_TYPE_METHOD (jchar, Char)
+    DECLARE_CALL_TYPE_METHOD (jshort, Short)
+    DECLARE_CALL_TYPE_METHOD (jint, Int)
+    DECLARE_CALL_TYPE_METHOD (jlong, Long)
+    DECLARE_CALL_TYPE_METHOD (jfloat, Float)
+    DECLARE_CALL_TYPE_METHOD (jdouble, Double)
+    #undef DECLARE_CALL_TYPE_METHOD
+
+    void callVoidMethod (jmethodID methodID, ... ) const
+    {
+        va_list args;
+        va_start (args, methodID);
+        getEnv()->CallVoidMethodV (obj, methodID, args);
+        va_end (args);
+    }
+
+private:
+    //==============================================================================
+    jobject obj;
+
+    static inline jobject retain (jobject obj)
+    {
+        return obj == 0 ? 0 : getEnv()->NewGlobalRef (obj);
+    }
+};
+
+//==============================================================================
+template <typename JavaType>
+class LocalRef
+{
+public:
+    explicit inline LocalRef (JavaType o) noexcept      : obj (o) {}
+    inline LocalRef (const LocalRef& other) noexcept    : obj (retain (other.obj)) {}
+    ~LocalRef()                                         { clear(); }
+
+    void clear()
+    {
+        if (obj != 0)
+            getEnv()->DeleteLocalRef (obj);
+    }
+
+    LocalRef& operator= (const LocalRef& other)
+    {
+        jobject newObj = retain (other.obj);
+        clear();
+        obj = newObj;
+        return *this;
+    }
+
+    inline operator JavaType() const noexcept   { return obj; }
+    inline JavaType get() const noexcept        { return obj; }
+
+private:
+    JavaType obj;
+
+    static JavaType retain (JavaType obj)
+    {
+        return obj == 0 ? 0 : (JavaType) getEnv()->NewLocalRef (obj);
+    }
+};
+
+//==============================================================================
+namespace
+{
+    String juceString (JNIEnv* env, jstring s)
+    {
+        const char* const utf8 = env->GetStringUTFChars (s, nullptr);
+        CharPointer_UTF8 utf8CP (utf8);
+        const String result (utf8CP);
+        env->ReleaseStringUTFChars (s, utf8);
+        return result;
+    }
+
+    String juceString (jstring s)
+    {
+        return juceString (getEnv(), s);
+    }
+
+    LocalRef<jstring> javaString (const String& s)
+    {
+        return LocalRef<jstring> (getEnv()->NewStringUTF (s.toUTF8()));
+    }
+
+    LocalRef<jstring> javaStringFromChar (const juce_wchar c)
+    {
+        char utf8[8] = { 0 };
+        CharPointer_UTF8 (utf8).write (c);
+        return LocalRef<jstring> (getEnv()->NewStringUTF (utf8));
+    }
+}
+
+//==============================================================================
+class JNIClassBase
+{
+public:
+    explicit JNIClassBase (const char* classPath);
+    virtual ~JNIClassBase();
+
+    inline operator jclass() const noexcept { return classRef; }
+
+    static void initialiseAllClasses (JNIEnv*);
+    static void releaseAllClasses (JNIEnv*);
+
+protected:
+    virtual void initialiseFields (JNIEnv*) = 0;
+
+    jmethodID resolveMethod (JNIEnv*, const char* methodName, const char* params);
+    jmethodID resolveStaticMethod (JNIEnv*, const char* methodName, const char* params);
+    jfieldID resolveField (JNIEnv*, const char* fieldName, const char* signature);
+    jfieldID resolveStaticField (JNIEnv*, const char* fieldName, const char* signature);
+
+private:
+    const char* const classPath;
+    jclass classRef;
+
+    static Array<JNIClassBase*>& getClasses();
+    void initialise (JNIEnv*);
+    void release (JNIEnv*);
+
+    JUCE_DECLARE_NON_COPYABLE (JNIClassBase)
+};
+
+//==============================================================================
+#define CREATE_JNI_METHOD(methodID, stringName, params)         methodID = resolveMethod (env, stringName, params);
+#define CREATE_JNI_STATICMETHOD(methodID, stringName, params)   methodID = resolveStaticMethod (env, stringName, params);
+#define CREATE_JNI_FIELD(fieldID, stringName, signature)        fieldID  = resolveField (env, stringName, signature);
+#define CREATE_JNI_STATICFIELD(fieldID, stringName, signature)  fieldID  = resolveStaticField (env, stringName, signature);
+#define DECLARE_JNI_METHOD(methodID, stringName, params)        jmethodID methodID;
+#define DECLARE_JNI_FIELD(fieldID, stringName, signature)       jfieldID  fieldID;
+
+#define DECLARE_JNI_CLASS(CppClassName, javaPath) \
+    class CppClassName ## _Class   : public JNIClassBase \
+    { \
+    public: \
+        CppClassName ## _Class() : JNIClassBase (javaPath) {} \
+    \
+        void initialiseFields (JNIEnv* env) \
+        { \
+            JNI_CLASS_MEMBERS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD); \
+        } \
+    \
+        JNI_CLASS_MEMBERS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD); \
+    }; \
+    static CppClassName ## _Class CppClassName;
+
+
+//==============================================================================
+#define JUCE_JNI_CALLBACK(className, methodName, returnType, params) \
+  extern "C" __attribute__ ((visibility("default"))) returnType JUCE_JOIN_MACRO (JUCE_JOIN_MACRO (Java_, className), _ ## methodName) params
+
+//==============================================================================
+class AndroidSystem
+{
+public:
+    AndroidSystem();
+
+    void initialise (JNIEnv*, jobject activity, jstring appFile, jstring appDataDir);
+    void shutdown (JNIEnv*);
+
+    //==============================================================================
+    GlobalRef activity;
+    String appFile, appDataDir;
+    int screenWidth, screenHeight, dpi;
+};
+
+extern AndroidSystem android;
+
+//==============================================================================
+class ThreadLocalJNIEnvHolder
+{
+public:
+    ThreadLocalJNIEnvHolder() noexcept
+        : jvm (nullptr)
+    {
+        zeromem (threads, sizeof (threads));
+        zeromem (envs, sizeof (envs));
+    }
+
+    void initialise (JNIEnv* env)
+    {
+        // NB: the DLL can be left loaded by the JVM, so the same static
+        // objects can end up being reused by subsequent runs of the app
+        zeromem (threads, sizeof (threads));
+        zeromem (envs, sizeof (envs));
+
+        env->GetJavaVM (&jvm);
+        addEnv (env);
+    }
+
+    JNIEnv* attach() noexcept
+    {
+        if (android.activity != nullptr)
+        {
+            if (JNIEnv* env = attachToCurrentThread())
+            {
+                SpinLock::ScopedLockType sl (addRemoveLock);
+                return addEnv (env);
+            }
+
+            jassertfalse;
+        }
+
+        return nullptr;
+    }
+
+    void detach() noexcept
+    {
+        if (android.activity != nullptr)
+        {
+            jvm->DetachCurrentThread();
+
+            const pthread_t thisThread = pthread_self();
+
+            SpinLock::ScopedLockType sl (addRemoveLock);
+            for (int i = 0; i < maxThreads; ++i)
+                if (threads[i] == thisThread)
+                    threads[i] = 0;
+        }
+    }
+
+    JNIEnv* getOrAttach() noexcept
+    {
+        if (JNIEnv* env = get())
+            return env;
+
+        SpinLock::ScopedLockType sl (addRemoveLock);
+
+        if (JNIEnv* env = get())
+            return env;
+
+        if (JNIEnv* env = attachToCurrentThread())
+            return addEnv (env);
+
+        return nullptr;
+    }
+
+private:
+    JavaVM* jvm;
+    enum { maxThreads = 32 };
+    pthread_t threads [maxThreads];
+    JNIEnv* envs [maxThreads];
+    SpinLock addRemoveLock;
+
+    JNIEnv* addEnv (JNIEnv* env) noexcept
+    {
+        const pthread_t thisThread = pthread_self();
+
+        for (int i = 0; i < maxThreads; ++i)
+        {
+            if (threads[i] == 0)
+            {
+                envs[i] = env;
+                threads[i] = thisThread;
+                return env;
+            }
+        }
+
+        jassertfalse; // too many threads!
+        return nullptr;
+    }
+
+    JNIEnv* get() const noexcept
+    {
+        const pthread_t thisThread = pthread_self();
+
+        for (int i = 0; i < maxThreads; ++i)
+            if (threads[i] == thisThread)
+                return envs[i];
+
+        return nullptr;
+    }
+
+    JNIEnv* attachToCurrentThread()
+    {
+        JNIEnv* env = nullptr;
+        jvm->AttachCurrentThread (&env, nullptr);
+        return env;
+    }
+};
+
+extern ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
+
+struct AndroidThreadScope
+{
+    AndroidThreadScope()   { threadLocalJNIEnvHolder.attach(); }
+    ~AndroidThreadScope()  { threadLocalJNIEnvHolder.detach(); }
+};
+
+//==============================================================================
+#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
+ METHOD (createNewView,          "createNewView",        "(ZJ)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \
+ METHOD (deleteView,             "deleteView",           "(L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;)V") \
+ METHOD (postMessage,            "postMessage",          "(J)V") \
+ METHOD (finish,                 "finish",               "()V") \
+ METHOD (getClipboardContent,    "getClipboardContent",  "()Ljava/lang/String;") \
+ METHOD (setClipboardContent,    "setClipboardContent",  "(Ljava/lang/String;)V") \
+ METHOD (excludeClipRegion,      "excludeClipRegion",    "(Landroid/graphics/Canvas;FFFF)V") \
+ METHOD (renderGlyph,            "renderGlyph",          "(CLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \
+ STATICMETHOD (createHTTPStream, "createHTTPStream",     "(Ljava/lang/String;Z[BLjava/lang/String;I[ILjava/lang/StringBuffer;)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream;") \
+ METHOD (launchURL,              "launchURL",            "(Ljava/lang/String;)V") \
+ METHOD (showMessageBox,         "showMessageBox",       "(Ljava/lang/String;Ljava/lang/String;J)V") \
+ METHOD (showOkCancelBox,        "showOkCancelBox",      "(Ljava/lang/String;Ljava/lang/String;J)V") \
+ METHOD (showYesNoCancelBox,     "showYesNoCancelBox",   "(Ljava/lang/String;Ljava/lang/String;J)V") \
+ STATICMETHOD (getLocaleValue,   "getLocaleValue",       "(Z)Ljava/lang/String;") \
+ METHOD (scanFile,               "scanFile",             "(Ljava/lang/String;)V")
+
+DECLARE_JNI_CLASS (JuceAppActivity, JUCE_ANDROID_ACTIVITY_CLASSPATH);
+#undef JNI_CLASS_MEMBERS
+
+//==============================================================================
+#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
+ METHOD (constructor,   "<init>",           "(I)V") \
+ METHOD (setColor,      "setColor",         "(I)V") \
+ METHOD (setAlpha,      "setAlpha",         "(I)V") \
+ METHOD (setTypeface,   "setTypeface",      "(Landroid/graphics/Typeface;)Landroid/graphics/Typeface;") \
+ METHOD (ascent,        "ascent",           "()F") \
+ METHOD (descent,       "descent",          "()F") \
+ METHOD (setTextSize,   "setTextSize",      "(F)V") \
+ METHOD (getTextWidths, "getTextWidths",    "(Ljava/lang/String;[F)I") \
+ METHOD (setTextScaleX, "setTextScaleX",    "(F)V") \
+ METHOD (getTextPath,   "getTextPath",      "(Ljava/lang/String;IIFFLandroid/graphics/Path;)V") \
+ METHOD (setShader,     "setShader",        "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \
+
+DECLARE_JNI_CLASS (Paint, "android/graphics/Paint");
+#undef JNI_CLASS_MEMBERS
+
+//==============================================================================
+#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
+ METHOD (constructor,   "<init>",    "()V") \
+ METHOD (setValues,     "setValues", "([F)V") \
+
+DECLARE_JNI_CLASS (Matrix, "android/graphics/Matrix");
+#undef JNI_CLASS_MEMBERS
+
+//==============================================================================
+#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
+ METHOD (constructor,   "<init>",   "(IIII)V") \
+ FIELD (left,           "left",     "I") \
+ FIELD (right,          "right",    "I") \
+ FIELD (top,            "top",      "I") \
+ FIELD (bottom,         "bottom",   "I") \
+
+DECLARE_JNI_CLASS (RectClass, "android/graphics/Rect");
+#undef JNI_CLASS_MEMBERS
+
+#endif   // JUCE_ANDROID_JNIHELPERS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Misc.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Misc.cpp
new file mode 100644
index 0000000..d26adc1
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Misc.cpp
@@ -0,0 +1,32 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+void Logger::outputDebugString (const String& text)
+{
+    __android_log_print (ANDROID_LOG_INFO, "JUCE", "%s", text.toUTF8().getAddress());
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Network.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Network.cpp
new file mode 100644
index 0000000..1b86dee
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Network.cpp
@@ -0,0 +1,181 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+//==============================================================================
+#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
+ METHOD (constructor, "<init>", "()V") \
+ METHOD (toString, "toString", "()Ljava/lang/String;") \
+
+DECLARE_JNI_CLASS (StringBuffer, "java/lang/StringBuffer");
+#undef JNI_CLASS_MEMBERS
+
+//==============================================================================
+#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
+ METHOD (release, "release", "()V") \
+ METHOD (read, "read", "([BI)I") \
+ METHOD (getPosition, "getPosition", "()J") \
+ METHOD (getTotalLength, "getTotalLength", "()J") \
+ METHOD (isExhausted, "isExhausted", "()Z") \
+ METHOD (setPosition, "setPosition", "(J)Z") \
+
+DECLARE_JNI_CLASS (HTTPStream, JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream");
+#undef JNI_CLASS_MEMBERS
+
+
+//==============================================================================
+void MACAddress::findAllAddresses (Array<MACAddress>& result)
+{
+    // TODO
+}
+
+
+JUCE_API bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailAddress,
+                                                               const String& emailSubject,
+                                                               const String& bodyText,
+                                                               const StringArray& filesToAttach)
+{
+    // TODO
+    return false;
+}
+
+
+//==============================================================================
+class WebInputStream  : public InputStream
+{
+public:
+    WebInputStream (String address, bool isPost, const MemoryBlock& postData,
+                    URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
+                    const String& headers, int timeOutMs, StringPairArray* responseHeaders)
+        : statusCode (0)
+    {
+        if (! address.contains ("://"))
+            address = "http://" + address;
+
+        JNIEnv* env = getEnv();
+
+        jbyteArray postDataArray = 0;
+
+        if (postData.getSize() > 0)
+        {
+            postDataArray = env->NewByteArray (postData.getSize());
+            env->SetByteArrayRegion (postDataArray, 0, postData.getSize(), (const jbyte*) postData.getData());
+        }
+
+        LocalRef<jobject> responseHeaderBuffer (env->NewObject (StringBuffer, StringBuffer.constructor));
+
+        // Annoyingly, the android HTTP functions will choke on this call if you try to do it on the message
+        // thread. You'll need to move your networking code to a background thread to keep it happy..
+        jassert (Thread::getCurrentThread() != nullptr);
+
+        jintArray statusCodeArray = env->NewIntArray (1);
+        jassert (statusCodeArray != 0);
+
+        stream = GlobalRef (env->CallStaticObjectMethod (JuceAppActivity,
+                                                         JuceAppActivity.createHTTPStream,
+                                                         javaString (address).get(),
+                                                         (jboolean) isPost,
+                                                         postDataArray,
+                                                         javaString (headers).get(),
+                                                         (jint) timeOutMs,
+                                                         statusCodeArray,
+                                                         responseHeaderBuffer.get()));
+
+        jint* const statusCodeElements = env->GetIntArrayElements (statusCodeArray, 0);
+        statusCode = statusCodeElements[0];
+        env->ReleaseIntArrayElements (statusCodeArray, statusCodeElements, 0);
+        env->DeleteLocalRef (statusCodeArray);
+
+        if (postDataArray != 0)
+            env->DeleteLocalRef (postDataArray);
+
+        if (stream != 0)
+        {
+            StringArray headerLines;
+
+            {
+                LocalRef<jstring> headersString ((jstring) env->CallObjectMethod (responseHeaderBuffer.get(),
+                                                                                  StringBuffer.toString));
+                headerLines.addLines (juceString (env, headersString));
+            }
+
+            if (responseHeaders != 0)
+            {
+                for (int i = 0; i < headerLines.size(); ++i)
+                {
+                    const String& header = headerLines[i];
+                    const String key (header.upToFirstOccurrenceOf (": ", false, false));
+                    const String value (header.fromFirstOccurrenceOf (": ", false, false));
+                    const String previousValue ((*responseHeaders) [key]);
+
+                    responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
+                }
+            }
+        }
+    }
+
+    ~WebInputStream()
+    {
+        if (stream != 0)
+            stream.callVoidMethod (HTTPStream.release);
+    }
+
+    //==============================================================================
+    bool isError() const                         { return stream == nullptr; }
+
+    bool isExhausted() override                  { return stream != nullptr && stream.callBooleanMethod (HTTPStream.isExhausted); }
+    int64 getTotalLength() override              { return stream != nullptr ? stream.callLongMethod (HTTPStream.getTotalLength) : 0; }
+    int64 getPosition() override                 { return stream != nullptr ? stream.callLongMethod (HTTPStream.getPosition) : 0; }
+    bool setPosition (int64 wantedPos) override  { return stream != nullptr && stream.callBooleanMethod (HTTPStream.setPosition, (jlong) wantedPos); }
+
+    int read (void* buffer, int bytesToRead) override
+    {
+        jassert (buffer != nullptr && bytesToRead >= 0);
+
+        if (stream == nullptr)
+            return 0;
+
+        JNIEnv* env = getEnv();
+
+        jbyteArray javaArray = env->NewByteArray (bytesToRead);
+
+        int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead);
+
+        if (numBytes > 0)
+            env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast <jbyte*> (buffer));
+
+        env->DeleteLocalRef (javaArray);
+        return numBytes;
+    }
+
+    //==============================================================================
+    GlobalRef stream;
+    int statusCode;
+
+private:
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
+};
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_SystemStats.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_SystemStats.cpp
new file mode 100644
index 0000000..8223b89
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_SystemStats.cpp
@@ -0,0 +1,315 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+JNIClassBase::JNIClassBase (const char* cp)   : classPath (cp), classRef (0)
+{
+    getClasses().add (this);
+}
+
+JNIClassBase::~JNIClassBase()
+{
+    getClasses().removeFirstMatchingValue (this);
+}
+
+Array<JNIClassBase*>& JNIClassBase::getClasses()
+{
+    static Array<JNIClassBase*> classes;
+    return classes;
+}
+
+void JNIClassBase::initialise (JNIEnv* env)
+{
+    classRef = (jclass) env->NewGlobalRef (env->FindClass (classPath));
+    jassert (classRef != 0);
+
+    initialiseFields (env);
+}
+
+void JNIClassBase::release (JNIEnv* env)
+{
+    env->DeleteGlobalRef (classRef);
+}
+
+void JNIClassBase::initialiseAllClasses (JNIEnv* env)
+{
+    const Array<JNIClassBase*>& classes = getClasses();
+    for (int i = classes.size(); --i >= 0;)
+        classes.getUnchecked(i)->initialise (env);
+}
+
+void JNIClassBase::releaseAllClasses (JNIEnv* env)
+{
+    const Array<JNIClassBase*>& classes = getClasses();
+    for (int i = classes.size(); --i >= 0;)
+        classes.getUnchecked(i)->release (env);
+}
+
+jmethodID JNIClassBase::resolveMethod (JNIEnv* env, const char* methodName, const char* params)
+{
+    jmethodID m = env->GetMethodID (classRef, methodName, params);
+    jassert (m != 0);
+    return m;
+}
+
+jmethodID JNIClassBase::resolveStaticMethod (JNIEnv* env, const char* methodName, const char* params)
+{
+    jmethodID m = env->GetStaticMethodID (classRef, methodName, params);
+    jassert (m != 0);
+    return m;
+}
+
+jfieldID JNIClassBase::resolveField (JNIEnv* env, const char* fieldName, const char* signature)
+{
+    jfieldID f = env->GetFieldID (classRef, fieldName, signature);
+    jassert (f != 0);
+    return f;
+}
+
+jfieldID JNIClassBase::resolveStaticField (JNIEnv* env, const char* fieldName, const char* signature)
+{
+    jfieldID f = env->GetStaticFieldID (classRef, fieldName, signature);
+    jassert (f != 0);
+    return f;
+}
+
+//==============================================================================
+ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
+
+#if JUCE_DEBUG
+static bool systemInitialised = false;
+#endif
+
+JNIEnv* getEnv() noexcept
+{
+   #if JUCE_DEBUG
+    if (! systemInitialised)
+    {
+        DBG ("*** Call to getEnv() when system not initialised");
+        jassertfalse;
+        std::exit (EXIT_FAILURE);
+    }
+   #endif
+
+    return threadLocalJNIEnvHolder.getOrAttach();
+}
+
+extern "C" jint JNI_OnLoad (JavaVM*, void*)
+{
+    return JNI_VERSION_1_2;
+}
+
+//==============================================================================
+AndroidSystem::AndroidSystem() : screenWidth (0), screenHeight (0), dpi (160)
+{
+}
+
+void AndroidSystem::initialise (JNIEnv* env, jobject act, jstring file, jstring dataDir)
+{
+    screenWidth = screenHeight = 0;
+    dpi = 160;
+    JNIClassBase::initialiseAllClasses (env);
+
+    threadLocalJNIEnvHolder.initialise (env);
+   #if JUCE_DEBUG
+    systemInitialised = true;
+   #endif
+
+    activity = GlobalRef (act);
+    appFile = juceString (env, file);
+    appDataDir = juceString (env, dataDir);
+}
+
+void AndroidSystem::shutdown (JNIEnv* env)
+{
+    activity.clear();
+
+   #if JUCE_DEBUG
+    systemInitialised = false;
+   #endif
+
+    JNIClassBase::releaseAllClasses (env);
+}
+
+AndroidSystem android;
+
+//==============================================================================
+namespace AndroidStatsHelpers
+{
+    #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
+     STATICMETHOD (getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;")
+
+    DECLARE_JNI_CLASS (SystemClass, "java/lang/System");
+    #undef JNI_CLASS_MEMBERS
+
+    String getSystemProperty (const String& name)
+    {
+        return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (SystemClass,
+                                                                                          SystemClass.getProperty,
+                                                                                          javaString (name).get())));
+    }
+
+    String getLocaleValue (bool isRegion)
+    {
+        return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (JuceAppActivity,
+                                                                                          JuceAppActivity.getLocaleValue,
+                                                                                          isRegion)));
+    }
+
+    #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD)
+    DECLARE_JNI_CLASS (BuildClass, "android/os/Build");
+    #undef JNI_CLASS_MEMBERS
+
+    String getAndroidOsBuildValue (const char* fieldName)
+    {
+        return juceString (LocalRef<jstring> ((jstring) getEnv()->GetStaticObjectField (
+                            BuildClass, getEnv()->GetStaticFieldID (BuildClass, fieldName, "Ljava/lang/String;"))));
+    }
+}
+
+//==============================================================================
+SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
+{
+    return Android;
+}
+
+String SystemStats::getOperatingSystemName()
+{
+    return "Android " + AndroidStatsHelpers::getSystemProperty ("os.version");
+}
+
+String SystemStats::getDeviceDescription()
+{
+    return AndroidStatsHelpers::getAndroidOsBuildValue ("MODEL")
+            + "-" + AndroidStatsHelpers::getAndroidOsBuildValue ("SERIAL");
+}
+
+bool SystemStats::isOperatingSystem64Bit()
+{
+   #if JUCE_64BIT
+    return true;
+   #else
+    return false;
+   #endif
+}
+
+String SystemStats::getCpuVendor()
+{
+    return AndroidStatsHelpers::getSystemProperty ("os.arch");
+}
+
+int SystemStats::getCpuSpeedInMegaherz()
+{
+    return 0; // TODO
+}
+
+int SystemStats::getMemorySizeInMegabytes()
+{
+   #if __ANDROID_API__ >= 9
+    struct sysinfo sysi;
+
+    if (sysinfo (&sysi) == 0)
+        return (sysi.totalram * sysi.mem_unit / (1024 * 1024));
+   #endif
+
+    return 0;
+}
+
+int SystemStats::getPageSize()
+{
+    return sysconf (_SC_PAGESIZE);
+}
+
+//==============================================================================
+String SystemStats::getLogonName()
+{
+    if (const char* user = getenv ("USER"))
+        return CharPointer_UTF8 (user);
+
+    if (struct passwd* const pw = getpwuid (getuid()))
+        return CharPointer_UTF8 (pw->pw_name);
+
+    return String::empty;
+}
+
+String SystemStats::getFullUserName()
+{
+    return getLogonName();
+}
+
+String SystemStats::getComputerName()
+{
+    char name [256] = { 0 };
+    if (gethostname (name, sizeof (name) - 1) == 0)
+        return name;
+
+    return String::empty;
+}
+
+
+String SystemStats::getUserLanguage()    { return AndroidStatsHelpers::getLocaleValue (false); }
+String SystemStats::getUserRegion()      { return AndroidStatsHelpers::getLocaleValue (true); }
+String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
+
+//==============================================================================
+void CPUInformation::initialise() noexcept
+{
+    numCpus = jmax (1, sysconf (_SC_NPROCESSORS_ONLN));
+}
+
+//==============================================================================
+uint32 juce_millisecondsSinceStartup() noexcept
+{
+    timespec t;
+    clock_gettime (CLOCK_MONOTONIC, &t);
+
+    return t.tv_sec * 1000 + t.tv_nsec / 1000000;
+}
+
+int64 Time::getHighResolutionTicks() noexcept
+{
+    timespec t;
+    clock_gettime (CLOCK_MONOTONIC, &t);
+
+    return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
+}
+
+int64 Time::getHighResolutionTicksPerSecond() noexcept
+{
+    return 1000000;  // (microseconds)
+}
+
+double Time::getMillisecondCounterHiRes() noexcept
+{
+    return getHighResolutionTicks() * 0.001;
+}
+
+bool Time::setSystemTimeToThisTime() const
+{
+    jassertfalse;
+    return false;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Threads.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Threads.cpp
new file mode 100644
index 0000000..981be9a
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_android_Threads.cpp
@@ -0,0 +1,76 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+/*
+    Note that a lot of methods that you'd expect to find in this file actually
+    live in juce_posix_SharedCode.h!
+*/
+
+//==============================================================================
+// sets the process to 0=low priority, 1=normal, 2=high, 3=realtime
+JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority prior)
+{
+    // TODO
+
+    struct sched_param param;
+    int policy, maxp, minp;
+
+    const int p = (int) prior;
+
+    if (p <= 1)
+        policy = SCHED_OTHER;
+    else
+        policy = SCHED_RR;
+
+    minp = sched_get_priority_min (policy);
+    maxp = sched_get_priority_max (policy);
+
+    if (p < 2)
+        param.sched_priority = 0;
+    else if (p == 2 )
+        // Set to middle of lower realtime priority range
+        param.sched_priority = minp + (maxp - minp) / 4;
+    else
+        // Set to middle of higher realtime priority range
+        param.sched_priority = minp + (3 * (maxp - minp) / 4);
+
+    pthread_setschedparam (pthread_self(), policy, &param);
+}
+
+JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
+{
+    return false;
+}
+
+JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
+{
+    return juce_isRunningUnderDebugger();
+}
+
+JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() {}
+JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() {}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_CommonFile.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_CommonFile.cpp
new file mode 100644
index 0000000..2ce98b3
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_CommonFile.cpp
@@ -0,0 +1,153 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+bool File::copyInternal (const File& dest) const
+{
+    FileInputStream in (*this);
+
+    if (dest.deleteFile())
+    {
+        {
+            FileOutputStream out (dest);
+
+            if (out.failedToOpen())
+                return false;
+
+            if (out.writeFromInputStream (in, -1) == getSize())
+                return true;
+        }
+
+        dest.deleteFile();
+    }
+
+    return false;
+}
+
+void File::findFileSystemRoots (Array<File>& destArray)
+{
+    destArray.add (File ("/"));
+}
+
+bool File::isHidden() const
+{
+    return getFileName().startsWithChar ('.');
+}
+
+static String getLinkedFile (StringRef file)
+{
+    HeapBlock<char> buffer (8194);
+    const int numBytes = (int) readlink (file.text, buffer, 8192);
+    return String::fromUTF8 (buffer, jmax (0, numBytes));
+};
+
+bool File::isLink() const
+{
+    return getLinkedFile (getFullPathName()).isNotEmpty();
+}
+
+File File::getLinkedTarget() const
+{
+    String f (getLinkedFile (getFullPathName()));
+
+    if (f.isNotEmpty())
+        return getSiblingFile (f);
+
+    return *this;
+}
+
+//==============================================================================
+class DirectoryIterator::NativeIterator::Pimpl
+{
+public:
+    Pimpl (const File& directory, const String& wc)
+        : parentDir (File::addTrailingSeparator (directory.getFullPathName())),
+          wildCard (wc), dir (opendir (directory.getFullPathName().toUTF8()))
+    {
+    }
+
+    ~Pimpl()
+    {
+        if (dir != nullptr)
+            closedir (dir);
+    }
+
+    bool next (String& filenameFound,
+               bool* const isDir, bool* const isHidden, int64* const fileSize,
+               Time* const modTime, Time* const creationTime, bool* const isReadOnly)
+    {
+        if (dir != nullptr)
+        {
+            const char* wildcardUTF8 = nullptr;
+
+            for (;;)
+            {
+                struct dirent* const de = readdir (dir);
+
+                if (de == nullptr)
+                    break;
+
+                if (wildcardUTF8 == nullptr)
+                    wildcardUTF8 = wildCard.toUTF8();
+
+                if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
+                {
+                    filenameFound = CharPointer_UTF8 (de->d_name);
+
+                    updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
+
+                    if (isHidden != nullptr)
+                        *isHidden = filenameFound.startsWithChar ('.');
+
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+private:
+    String parentDir, wildCard;
+    DIR* dir;
+
+    JUCE_DECLARE_NON_COPYABLE (Pimpl)
+};
+
+DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
+    : pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
+{
+}
+
+DirectoryIterator::NativeIterator::~NativeIterator() {}
+
+bool DirectoryIterator::NativeIterator::next (String& filenameFound,
+                                              bool* isDir, bool* isHidden, int64* fileSize,
+                                              Time* modTime, Time* creationTime, bool* isReadOnly)
+{
+    return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_Files.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_Files.cpp
new file mode 100644
index 0000000..d0dd54d
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_Files.cpp
@@ -0,0 +1,241 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+enum
+{
+    U_ISOFS_SUPER_MAGIC = 0x9660,   // linux/iso_fs.h
+    U_MSDOS_SUPER_MAGIC = 0x4d44,   // linux/msdos_fs.h
+    U_NFS_SUPER_MAGIC = 0x6969,     // linux/nfs_fs.h
+    U_SMB_SUPER_MAGIC = 0x517B      // linux/smb_fs.h
+};
+
+bool File::isOnCDRomDrive() const
+{
+    struct statfs buf;
+
+    return statfs (getFullPathName().toUTF8(), &buf) == 0
+             && buf.f_type == (short) U_ISOFS_SUPER_MAGIC;
+}
+
+bool File::isOnHardDisk() const
+{
+    struct statfs buf;
+
+    if (statfs (getFullPathName().toUTF8(), &buf) == 0)
+    {
+        switch (buf.f_type)
+        {
+            case U_ISOFS_SUPER_MAGIC:   // CD-ROM
+            case U_MSDOS_SUPER_MAGIC:   // Probably floppy (but could be mounted FAT filesystem)
+            case U_NFS_SUPER_MAGIC:     // Network NFS
+            case U_SMB_SUPER_MAGIC:     // Network Samba
+                return false;
+
+            default: break;
+        }
+    }
+
+    // Assume so if this fails for some reason
+    return true;
+}
+
+bool File::isOnRemovableDrive() const
+{
+    jassertfalse; // xxx not implemented for linux!
+    return false;
+}
+
+String File::getVersion() const
+{
+    return String(); // xxx not yet implemented
+}
+
+//==============================================================================
+static File resolveXDGFolder (const char* const type, const char* const fallbackFolder)
+{
+    StringArray confLines;
+    File ("~/.config/user-dirs.dirs").readLines (confLines);
+
+    for (int i = 0; i < confLines.size(); ++i)
+    {
+        const String line (confLines[i].trimStart());
+
+        if (line.startsWith (type))
+        {
+            // eg. resolve XDG_MUSIC_DIR="$HOME/Music" to /home/user/Music
+            const File f (line.replace ("$HOME", File ("~").getFullPathName())
+                              .fromFirstOccurrenceOf ("=", false, false)
+                              .trim().unquoted());
+
+            if (f.isDirectory())
+                return f;
+        }
+    }
+
+    return File (fallbackFolder);
+}
+
+const char* const* juce_argv = nullptr;
+int juce_argc = 0;
+
+File File::getSpecialLocation (const SpecialLocationType type)
+{
+    switch (type)
+    {
+        case userHomeDirectory:
+        {
+            if (const char* homeDir = getenv ("HOME"))
+                return File (CharPointer_UTF8 (homeDir));
+
+            if (struct passwd* const pw = getpwuid (getuid()))
+                return File (CharPointer_UTF8 (pw->pw_dir));
+
+            return File();
+        }
+
+        case userDocumentsDirectory:          return resolveXDGFolder ("XDG_DOCUMENTS_DIR", "~");
+        case userMusicDirectory:              return resolveXDGFolder ("XDG_MUSIC_DIR",     "~");
+        case userMoviesDirectory:             return resolveXDGFolder ("XDG_VIDEOS_DIR",    "~");
+        case userPicturesDirectory:           return resolveXDGFolder ("XDG_PICTURES_DIR",  "~");
+        case userDesktopDirectory:            return resolveXDGFolder ("XDG_DESKTOP_DIR",   "~/Desktop");
+        case userApplicationDataDirectory:    return resolveXDGFolder ("XDG_CONFIG_HOME",   "~");
+        case commonDocumentsDirectory:
+        case commonApplicationDataDirectory:  return File ("/var");
+        case globalApplicationsDirectory:     return File ("/usr");
+
+        case tempDirectory:
+        {
+            File tmp ("/var/tmp");
+
+            if (! tmp.isDirectory())
+            {
+                tmp = "/tmp";
+
+                if (! tmp.isDirectory())
+                    tmp = File::getCurrentWorkingDirectory();
+            }
+
+            return tmp;
+        }
+
+        case invokedExecutableFile:
+            if (juce_argv != nullptr && juce_argc > 0)
+                return File (CharPointer_UTF8 (juce_argv[0]));
+            // deliberate fall-through...
+
+        case currentExecutableFile:
+        case currentApplicationFile:
+            return juce_getExecutableFile();
+
+        case hostApplicationPath:
+        {
+            const File f ("/proc/self/exe");
+            return f.isLink() ? f.getLinkedTarget() : juce_getExecutableFile();
+        }
+
+        default:
+            jassertfalse; // unknown type?
+            break;
+    }
+
+    return File();
+}
+
+//==============================================================================
+bool File::moveToTrash() const
+{
+    if (! exists())
+        return true;
+
+    File trashCan ("~/.Trash");
+
+    if (! trashCan.isDirectory())
+        trashCan = "~/.local/share/Trash/files";
+
+    if (! trashCan.isDirectory())
+        return false;
+
+    return moveFileTo (trashCan.getNonexistentChildFile (getFileNameWithoutExtension(),
+                                                         getFileExtension()));
+}
+
+//==============================================================================
+static bool isFileExecutable (const String& filename)
+{
+    juce_statStruct info;
+
+    return juce_stat (filename, info)
+            && S_ISREG (info.st_mode)
+            && access (filename.toUTF8(), X_OK) == 0;
+}
+
+bool Process::openDocument (const String& fileName, const String& parameters)
+{
+    String cmdString (fileName.replace (" ", "\\ ",false));
+    cmdString << " " << parameters;
+
+    if (URL::isProbablyAWebsiteURL (fileName)
+         || cmdString.startsWithIgnoreCase ("file:")
+         || URL::isProbablyAnEmailAddress (fileName)
+         || File::createFileWithoutCheckingPath (fileName).isDirectory()
+         || ! isFileExecutable (fileName))
+    {
+        // create a command that tries to launch a bunch of likely browsers
+        static const char* const browserNames[] = { "xdg-open", "/etc/alternatives/x-www-browser", "firefox", "mozilla",
+                                                    "google-chrome", "chromium-browser", "opera", "konqueror" };
+        StringArray cmdLines;
+
+        for (int i = 0; i < numElementsInArray (browserNames); ++i)
+            cmdLines.add (String (browserNames[i]) + " " + cmdString.trim().quoted());
+
+        cmdString = cmdLines.joinIntoString (" || ");
+    }
+
+    const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 };
+
+    const int cpid = fork();
+
+    if (cpid == 0)
+    {
+        setsid();
+
+        // Child process
+        execve (argv[0], (char**) argv, environ);
+        exit (0);
+    }
+
+    return cpid >= 0;
+}
+
+void File::revealToUser() const
+{
+    if (isDirectory())
+        startAsProcess();
+    else if (getParentDirectory().exists())
+        getParentDirectory().startAsProcess();
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_Network.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_Network.cpp
new file mode 100644
index 0000000..7543a77
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_Network.cpp
@@ -0,0 +1,444 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+void MACAddress::findAllAddresses (Array<MACAddress>& result)
+{
+    const int s = socket (AF_INET, SOCK_DGRAM, 0);
+    if (s != -1)
+    {
+        char buf [1024];
+        struct ifconf ifc;
+        ifc.ifc_len = sizeof (buf);
+        ifc.ifc_buf = buf;
+        ioctl (s, SIOCGIFCONF, &ifc);
+
+        for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
+        {
+            struct ifreq ifr;
+            strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
+
+            if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
+                 && (ifr.ifr_flags & IFF_LOOPBACK) == 0
+                 && ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
+            {
+                MACAddress ma ((const uint8*) ifr.ifr_hwaddr.sa_data);
+
+                if (! ma.isNull())
+                    result.addIfNotAlreadyThere (ma);
+            }
+        }
+
+        close (s);
+    }
+}
+
+
+bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& /* targetEmailAddress */,
+                                                      const String& /* emailSubject */,
+                                                      const String& /* bodyText */,
+                                                      const StringArray& /* filesToAttach */)
+{
+    jassertfalse;    // xxx todo
+    return false;
+}
+
+
+//==============================================================================
+class WebInputStream  : public InputStream
+{
+public:
+    WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
+                    URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
+                    const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
+      : statusCode (0), socketHandle (-1), levelsOfRedirection (0),
+        address (address_), headers (headers_), postData (postData_), position (0),
+        finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
+    {
+        statusCode = createConnection (progressCallback, progressCallbackContext);
+
+        if (responseHeaders != nullptr && ! isError())
+        {
+            for (int i = 0; i < headerLines.size(); ++i)
+            {
+                const String& headersEntry = headerLines[i];
+                const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
+                const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
+                const String previousValue ((*responseHeaders) [key]);
+                responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
+            }
+        }
+    }
+
+    ~WebInputStream()
+    {
+        closeSocket();
+    }
+
+    //==============================================================================
+    bool isError() const                 { return socketHandle < 0; }
+    bool isExhausted() override          { return finished; }
+    int64 getPosition() override         { return position; }
+
+    int64 getTotalLength() override
+    {
+        //xxx to do
+        return -1;
+    }
+
+    int read (void* buffer, int bytesToRead) override
+    {
+        if (finished || isError())
+            return 0;
+
+        fd_set readbits;
+        FD_ZERO (&readbits);
+        FD_SET (socketHandle, &readbits);
+
+        struct timeval tv;
+        tv.tv_sec = jmax (1, timeOutMs / 1000);
+        tv.tv_usec = 0;
+
+        if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
+            return 0;   // (timeout)
+
+        const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
+        if (bytesRead == 0)
+            finished = true;
+
+        position += bytesRead;
+        return bytesRead;
+    }
+
+    bool setPosition (int64 wantedPos) override
+    {
+        if (isError())
+            return false;
+
+        if (wantedPos != position)
+        {
+            finished = false;
+
+            if (wantedPos < position)
+            {
+                closeSocket();
+                position = 0;
+                statusCode = createConnection (0, 0);
+            }
+
+            skipNextBytes (wantedPos - position);
+        }
+
+        return true;
+    }
+
+    //==============================================================================
+    int statusCode;
+
+private:
+    int socketHandle, levelsOfRedirection;
+    StringArray headerLines;
+    String address, headers;
+    MemoryBlock postData;
+    int64 position;
+    bool finished;
+    const bool isPost;
+    const int timeOutMs;
+
+    void closeSocket()
+    {
+        if (socketHandle >= 0)
+            close (socketHandle);
+
+        socketHandle = -1;
+        levelsOfRedirection = 0;
+    }
+
+    int createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
+    {
+        closeSocket();
+
+        uint32 timeOutTime = Time::getMillisecondCounter();
+
+        if (timeOutMs == 0)
+            timeOutTime += 60000;
+        else if (timeOutMs < 0)
+            timeOutTime = 0xffffffff;
+        else
+            timeOutTime += timeOutMs;
+
+        String hostName, hostPath;
+        int hostPort;
+        if (! decomposeURL (address, hostName, hostPath, hostPort))
+            return 0;
+
+        String serverName, proxyName, proxyPath;
+        int proxyPort = 0;
+        int port = 0;
+
+        const String proxyURL (getenv ("http_proxy"));
+        if (proxyURL.startsWithIgnoreCase ("http://"))
+        {
+            if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
+                return 0;
+
+            serverName = proxyName;
+            port = proxyPort;
+        }
+        else
+        {
+            serverName = hostName;
+            port = hostPort;
+        }
+
+        struct addrinfo hints;
+        zerostruct (hints);
+
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+        hints.ai_flags = AI_NUMERICSERV;
+
+        struct addrinfo* result = nullptr;
+        if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0)
+            return 0;
+
+        socketHandle = socket (result->ai_family, result->ai_socktype, 0);
+
+        if (socketHandle == -1)
+        {
+            freeaddrinfo (result);
+            return 0;
+        }
+
+        int receiveBufferSize = 16384;
+        setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
+        setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
+
+      #if JUCE_MAC
+        setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
+      #endif
+
+        if (connect (socketHandle, result->ai_addr, result->ai_addrlen) == -1)
+        {
+            closeSocket();
+            freeaddrinfo (result);
+            return 0;
+        }
+
+        freeaddrinfo (result);
+
+        {
+            const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort, proxyName, proxyPort,
+                                                                  hostPath, address, headers, postData, isPost));
+
+            if (! sendHeader (socketHandle, requestHeader, timeOutTime,
+                              progressCallback, progressCallbackContext))
+            {
+                closeSocket();
+                return 0;
+            }
+        }
+
+        String responseHeader (readResponse (socketHandle, timeOutTime));
+        position = 0;
+
+        if (responseHeader.isNotEmpty())
+        {
+            headerLines = StringArray::fromLines (responseHeader);
+
+            const int status = responseHeader.fromFirstOccurrenceOf (" ", false, false)
+                                             .substring (0, 3).getIntValue();
+
+            //int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
+            //bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
+
+            String location (findHeaderItem (headerLines, "Location:"));
+
+            if (status >= 300 && status < 400
+                 && location.isNotEmpty() && location != address)
+            {
+                if (! location.startsWithIgnoreCase ("http://"))
+                    location = "http://" + location;
+
+                if (++levelsOfRedirection <= 3)
+                {
+                    address = location;
+                    return createConnection (progressCallback, progressCallbackContext);
+                }
+            }
+            else
+            {
+                levelsOfRedirection = 0;
+                return status;
+            }
+        }
+
+        closeSocket();
+        return 0;
+    }
+
+    //==============================================================================
+    String readResponse (const int socketHandle, const uint32 timeOutTime)
+    {
+        int numConsecutiveLFs  = 0;
+        MemoryOutputStream buffer;
+
+        while (numConsecutiveLFs < 2
+                && buffer.getDataSize() < 32768
+                && Time::getMillisecondCounter() <= timeOutTime
+                && ! (finished || isError()))
+        {
+            char c = 0;
+            if (read (&c, 1) != 1)
+                return String();
+
+            buffer.writeByte (c);
+
+            if (c == '\n')
+                ++numConsecutiveLFs;
+            else if (c != '\r')
+                numConsecutiveLFs = 0;
+        }
+
+        const String header (buffer.toString().trimEnd());
+
+        if (header.startsWithIgnoreCase ("HTTP/"))
+            return header;
+
+        return String();
+    }
+
+    static void writeValueIfNotPresent (MemoryOutputStream& dest, const String& headers, const String& key, const String& value)
+    {
+        if (! headers.containsIgnoreCase (key))
+            dest << "\r\n" << key << ' ' << value;
+    }
+
+    static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port)
+    {
+        dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host;
+    }
+
+    static MemoryBlock createRequestHeader (const String& hostName, const int hostPort,
+                                            const String& proxyName, const int proxyPort,
+                                            const String& hostPath, const String& originalURL,
+                                            const String& userHeaders, const MemoryBlock& postData,
+                                            const bool isPost)
+    {
+        MemoryOutputStream header;
+
+        if (proxyName.isEmpty())
+            writeHost (header, isPost, hostPath, hostName, hostPort);
+        else
+            writeHost (header, isPost, originalURL, proxyName, proxyPort);
+
+        writeValueIfNotPresent (header, userHeaders, "User-Agent:", "JUCE/" JUCE_STRINGIFY(JUCE_MAJOR_VERSION)
+                                                                        "." JUCE_STRINGIFY(JUCE_MINOR_VERSION)
+                                                                        "." JUCE_STRINGIFY(JUCE_BUILDNUMBER));
+        writeValueIfNotPresent (header, userHeaders, "Connection:", "close");
+
+        if (isPost)
+            writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize()));
+
+        header << "\r\n" << userHeaders
+               << "\r\n" << postData;
+
+        return header.getMemoryBlock();
+    }
+
+    static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime,
+                            URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
+    {
+        size_t totalHeaderSent = 0;
+
+        while (totalHeaderSent < requestHeader.getSize())
+        {
+            if (Time::getMillisecondCounter() > timeOutTime)
+                return false;
+
+            const int numToSend = jmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
+
+            if (send (socketHandle, static_cast <const char*> (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend)
+                return false;
+
+            totalHeaderSent += numToSend;
+
+            if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize()))
+                return false;
+        }
+
+        return true;
+    }
+
+    static bool decomposeURL (const String& url, String& host, String& path, int& port)
+    {
+        if (! url.startsWithIgnoreCase ("http://"))
+            return false;
+
+        const int nextSlash = url.indexOfChar (7, '/');
+        int nextColon = url.indexOfChar (7, ':');
+        if (nextColon > nextSlash && nextSlash > 0)
+            nextColon = -1;
+
+        if (nextColon >= 0)
+        {
+            host = url.substring (7, nextColon);
+
+            if (nextSlash >= 0)
+                port = url.substring (nextColon + 1, nextSlash).getIntValue();
+            else
+                port = url.substring (nextColon + 1).getIntValue();
+        }
+        else
+        {
+            port = 80;
+
+            if (nextSlash >= 0)
+                host = url.substring (7, nextSlash);
+            else
+                host = url.substring (7);
+        }
+
+        if (nextSlash >= 0)
+            path = url.substring (nextSlash);
+        else
+            path = "/";
+
+        return true;
+    }
+
+    static String findHeaderItem (const StringArray& lines, const String& itemName)
+    {
+        for (int i = 0; i < lines.size(); ++i)
+            if (lines[i].startsWithIgnoreCase (itemName))
+                return lines[i].substring (itemName.length()).trim();
+
+        return String();
+    }
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
+};
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_SystemStats.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_SystemStats.cpp
new file mode 100644
index 0000000..939edb4
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_SystemStats.cpp
@@ -0,0 +1,191 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+void Logger::outputDebugString (const String& text)
+{
+    std::cerr << text << std::endl;
+}
+
+//==============================================================================
+SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
+{
+    return Linux;
+}
+
+String SystemStats::getOperatingSystemName()
+{
+    return "Linux";
+}
+
+bool SystemStats::isOperatingSystem64Bit()
+{
+   #if JUCE_64BIT
+    return true;
+   #else
+    //xxx not sure how to find this out?..
+    return false;
+   #endif
+}
+
+//==============================================================================
+namespace LinuxStatsHelpers
+{
+    String getCpuInfo (const char* const key)
+    {
+        StringArray lines;
+        File ("/proc/cpuinfo").readLines (lines);
+
+        for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
+            if (lines[i].upToFirstOccurrenceOf (":", false, false).trim().equalsIgnoreCase (key))
+                return lines[i].fromFirstOccurrenceOf (":", false, false).trim();
+
+        return String();
+    }
+}
+
+String SystemStats::getDeviceDescription()
+{
+    return LinuxStatsHelpers::getCpuInfo ("Hardware");
+}
+
+String SystemStats::getCpuVendor()
+{
+    String v (LinuxStatsHelpers::getCpuInfo ("vendor_id"));
+
+    if (v.isEmpty())
+        v = LinuxStatsHelpers::getCpuInfo ("model name");
+
+    return v;
+}
+
+int SystemStats::getCpuSpeedInMegaherz()
+{
+    return roundToInt (LinuxStatsHelpers::getCpuInfo ("cpu MHz").getFloatValue());
+}
+
+int SystemStats::getMemorySizeInMegabytes()
+{
+    struct sysinfo sysi;
+
+    if (sysinfo (&sysi) == 0)
+        return sysi.totalram * sysi.mem_unit / (1024 * 1024);
+
+    return 0;
+}
+
+int SystemStats::getPageSize()
+{
+    return sysconf (_SC_PAGESIZE);
+}
+
+//==============================================================================
+String SystemStats::getLogonName()
+{
+    if (const char* user = getenv ("USER"))
+        return CharPointer_UTF8 (user);
+
+    if (struct passwd* const pw = getpwuid (getuid()))
+        return CharPointer_UTF8 (pw->pw_name);
+
+    return String();
+}
+
+String SystemStats::getFullUserName()
+{
+    return getLogonName();
+}
+
+String SystemStats::getComputerName()
+{
+    char name [256] = { 0 };
+    if (gethostname (name, sizeof (name) - 1) == 0)
+        return name;
+
+    return String();
+}
+
+static String getLocaleValue (nl_item key)
+{
+    const char* oldLocale = ::setlocale (LC_ALL, "");
+    String result (String::fromUTF8 (nl_langinfo (key)));
+    ::setlocale (LC_ALL, oldLocale);
+    return result;
+}
+
+String SystemStats::getUserLanguage()    { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); }
+String SystemStats::getUserRegion()      { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); }
+String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
+
+//==============================================================================
+void CPUInformation::initialise() noexcept
+{
+    const String flags (LinuxStatsHelpers::getCpuInfo ("flags"));
+    hasMMX   = flags.contains ("mmx");
+    hasSSE   = flags.contains ("sse");
+    hasSSE2  = flags.contains ("sse2");
+    hasSSE3  = flags.contains ("sse3");
+    has3DNow = flags.contains ("3dnow");
+
+    numCpus = LinuxStatsHelpers::getCpuInfo ("processor").getIntValue() + 1;
+}
+
+//==============================================================================
+uint32 juce_millisecondsSinceStartup() noexcept
+{
+    timespec t;
+    clock_gettime (CLOCK_MONOTONIC, &t);
+
+    return t.tv_sec * 1000 + t.tv_nsec / 1000000;
+}
+
+int64 Time::getHighResolutionTicks() noexcept
+{
+    timespec t;
+    clock_gettime (CLOCK_MONOTONIC, &t);
+
+    return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
+}
+
+int64 Time::getHighResolutionTicksPerSecond() noexcept
+{
+    return 1000000;  // (microseconds)
+}
+
+double Time::getMillisecondCounterHiRes() noexcept
+{
+    return getHighResolutionTicks() * 0.001;
+}
+
+bool Time::setSystemTimeToThisTime() const
+{
+    timeval t;
+    t.tv_sec = millisSinceEpoch / 1000;
+    t.tv_usec = (millisSinceEpoch - t.tv_sec * 1000) * 1000;
+
+    return settimeofday (&t, 0) == 0;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_Threads.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_Threads.cpp
new file mode 100644
index 0000000..659fbd9
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_linux_Threads.cpp
@@ -0,0 +1,90 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+/*
+    Note that a lot of methods that you'd expect to find in this file actually
+    live in juce_posix_SharedCode.h!
+*/
+
+//==============================================================================
+JUCE_API void JUCE_CALLTYPE Process::setPriority (const ProcessPriority prior)
+{
+    const int policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR;
+    const int minp = sched_get_priority_min (policy);
+    const int maxp = sched_get_priority_max (policy);
+
+    struct sched_param param;
+
+    switch (prior)
+    {
+        case LowPriority:
+        case NormalPriority:    param.sched_priority = 0; break;
+        case HighPriority:      param.sched_priority = minp + (maxp - minp) / 4; break;
+        case RealtimePriority:  param.sched_priority = minp + (3 * (maxp - minp) / 4); break;
+        default:                jassertfalse; break;
+    }
+
+    pthread_setschedparam (pthread_self(), policy, &param);
+}
+
+JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
+{
+   #if JUCE_BSD
+    return false;
+   #else
+    static char testResult = 0;
+
+    if (testResult == 0)
+    {
+        testResult = (char) ptrace (PT_TRACE_ME, 0, 0, 0);
+
+        if (testResult >= 0)
+        {
+            ptrace (PT_DETACH, 0, (caddr_t) 1, 0);
+            testResult = 1;
+        }
+    }
+
+    return testResult < 0;
+   #endif
+}
+
+JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
+{
+    return juce_isRunningUnderDebugger();
+}
+
+static bool swapUserAndEffectiveUser()
+{
+    int result1 = setreuid (geteuid(), getuid());
+    int result2 = setregid (getegid(), getgid());
+    return result1 == 0 && result2 == 0;
+}
+
+JUCE_API void JUCE_CALLTYPE Process::raisePrivilege()  { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); }
+JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege()  { if (geteuid() == 0 && getuid() != 0) swapUserAndEffectiveUser(); }
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Files.mm b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Files.mm
new file mode 100644
index 0000000..0a00e92
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Files.mm
@@ -0,0 +1,498 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+/*
+    Note that a lot of methods that you'd expect to find in this file actually
+    live in juce_posix_SharedCode.h!
+*/
+
+//==============================================================================
+bool File::copyInternal (const File& dest) const
+{
+    JUCE_AUTORELEASEPOOL
+    {
+        NSFileManager* fm = [NSFileManager defaultManager];
+
+        return [fm fileExistsAtPath: juceStringToNS (fullPath)]
+               #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+                && [fm copyItemAtPath: juceStringToNS (fullPath)
+                               toPath: juceStringToNS (dest.getFullPathName())
+                                error: nil];
+               #else
+                && [fm copyPath: juceStringToNS (fullPath)
+                         toPath: juceStringToNS (dest.getFullPathName())
+                        handler: nil];
+               #endif
+    }
+}
+
+void File::findFileSystemRoots (Array<File>& destArray)
+{
+    destArray.add (File ("/"));
+}
+
+
+//==============================================================================
+namespace FileHelpers
+{
+    static bool isFileOnDriveType (const File& f, const char* const* types)
+    {
+        struct statfs buf;
+
+        if (juce_doStatFS (f, buf))
+        {
+            const String type (buf.f_fstypename);
+
+            while (*types != 0)
+                if (type.equalsIgnoreCase (*types++))
+                    return true;
+        }
+
+        return false;
+    }
+
+    static bool isHiddenFile (const String& path)
+    {
+       #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+        JUCE_AUTORELEASEPOOL
+        {
+            NSNumber* hidden = nil;
+            NSError* err = nil;
+
+            return [[NSURL fileURLWithPath: juceStringToNS (path)]
+                        getResourceValue: &hidden forKey: NSURLIsHiddenKey error: &err]
+                    && [hidden boolValue];
+        }
+       #elif JUCE_IOS
+        return File (path).getFileName().startsWithChar ('.');
+       #else
+        FSRef ref;
+        LSItemInfoRecord info;
+
+        return FSPathMakeRefWithOptions ((const UInt8*) path.toRawUTF8(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr
+                 && LSCopyItemInfoForRef (&ref, kLSRequestBasicFlagsOnly, &info) == noErr
+                 && (info.flags & kLSItemInfoIsInvisible) != 0;
+       #endif
+    }
+
+   #if JUCE_IOS
+    static String getIOSSystemLocation (NSSearchPathDirectory type)
+    {
+        return nsStringToJuce ([NSSearchPathForDirectoriesInDomains (type, NSUserDomainMask, YES)
+                                objectAtIndex: 0]);
+    }
+   #endif
+
+    static bool launchExecutable (const String& pathAndArguments)
+    {
+        const char* const argv[4] = { "/bin/sh", "-c", pathAndArguments.toUTF8(), 0 };
+
+        const int cpid = fork();
+
+        if (cpid == 0)
+        {
+            // Child process
+            if (execve (argv[0], (char**) argv, 0) < 0)
+                exit (0);
+        }
+        else
+        {
+            if (cpid < 0)
+                return false;
+        }
+
+        return true;
+    }
+}
+
+bool File::isOnCDRomDrive() const
+{
+    static const char* const cdTypes[] = { "cd9660", "cdfs", "cddafs", "udf", nullptr };
+
+    return FileHelpers::isFileOnDriveType (*this, cdTypes);
+}
+
+bool File::isOnHardDisk() const
+{
+    static const char* const nonHDTypes[] = { "nfs", "smbfs", "ramfs", nullptr };
+
+    return ! (isOnCDRomDrive() || FileHelpers::isFileOnDriveType (*this, nonHDTypes));
+}
+
+bool File::isOnRemovableDrive() const
+{
+   #if JUCE_IOS
+    return false; // xxx is this possible?
+   #else
+    JUCE_AUTORELEASEPOOL
+    {
+        BOOL removable = false;
+
+        [[NSWorkspace sharedWorkspace]
+               getFileSystemInfoForPath: juceStringToNS (getFullPathName())
+                            isRemovable: &removable
+                             isWritable: nil
+                          isUnmountable: nil
+                            description: nil
+                                   type: nil];
+
+        return removable;
+    }
+   #endif
+}
+
+bool File::isHidden() const
+{
+    return FileHelpers::isHiddenFile (getFullPathName());
+}
+
+//==============================================================================
+const char* const* juce_argv = nullptr;
+int juce_argc = 0;
+
+File File::getSpecialLocation (const SpecialLocationType type)
+{
+    JUCE_AUTORELEASEPOOL
+    {
+        String resultPath;
+
+        switch (type)
+        {
+            case userHomeDirectory:                 resultPath = nsStringToJuce (NSHomeDirectory()); break;
+
+          #if JUCE_IOS
+            case userDocumentsDirectory:            resultPath = FileHelpers::getIOSSystemLocation (NSDocumentDirectory); break;
+            case userDesktopDirectory:              resultPath = FileHelpers::getIOSSystemLocation (NSDesktopDirectory); break;
+
+            case tempDirectory:
+            {
+                File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory));
+                tmp = tmp.getChildFile (juce_getExecutableFile().getFileNameWithoutExtension());
+                tmp.createDirectory();
+                return tmp.getFullPathName();
+            }
+
+          #else
+            case userDocumentsDirectory:            resultPath = "~/Documents"; break;
+            case userDesktopDirectory:              resultPath = "~/Desktop"; break;
+
+            case tempDirectory:
+            {
+                File tmp ("~/Library/Caches/" + juce_getExecutableFile().getFileNameWithoutExtension());
+                tmp.createDirectory();
+                return File (tmp.getFullPathName());
+            }
+          #endif
+            case userMusicDirectory:                resultPath = "~/Music"; break;
+            case userMoviesDirectory:               resultPath = "~/Movies"; break;
+            case userPicturesDirectory:             resultPath = "~/Pictures"; break;
+            case userApplicationDataDirectory:      resultPath = "~/Library"; break;
+            case commonApplicationDataDirectory:    resultPath = "/Library"; break;
+            case commonDocumentsDirectory:          resultPath = "/Users/Shared"; break;
+            case globalApplicationsDirectory:       resultPath = "/Applications"; break;
+
+            case invokedExecutableFile:
+                if (juce_argv != nullptr && juce_argc > 0)
+                    return File (CharPointer_UTF8 (juce_argv[0]));
+                // deliberate fall-through...
+
+            case currentExecutableFile:
+                return juce_getExecutableFile();
+
+            case currentApplicationFile:
+            {
+                const File exe (juce_getExecutableFile());
+                const File parent (exe.getParentDirectory());
+
+              #if JUCE_IOS
+                return parent;
+              #else
+                return parent.getFullPathName().endsWithIgnoreCase ("Contents/MacOS")
+                        ? parent.getParentDirectory().getParentDirectory()
+                        : exe;
+              #endif
+            }
+
+            case hostApplicationPath:
+            {
+                unsigned int size = 8192;
+                HeapBlock<char> buffer;
+                buffer.calloc (size + 8);
+
+                _NSGetExecutablePath (buffer.getData(), &size);
+                return File (String::fromUTF8 (buffer, (int) size));
+            }
+
+            default:
+                jassertfalse; // unknown type?
+                break;
+        }
+
+        if (resultPath.isNotEmpty())
+            return File (resultPath.convertToPrecomposedUnicode());
+    }
+
+    return File();
+}
+
+//==============================================================================
+String File::getVersion() const
+{
+    JUCE_AUTORELEASEPOOL
+    {
+        if (NSBundle* bundle = [NSBundle bundleWithPath: juceStringToNS (getFullPathName())])
+            if (NSDictionary* info = [bundle infoDictionary])
+                if (NSString* name = [info valueForKey: nsStringLiteral ("CFBundleShortVersionString")])
+                    return nsStringToJuce (name);
+    }
+
+    return String();
+}
+
+//==============================================================================
+static NSString* getFileLink (const String& path)
+{
+   #if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+    return [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath: juceStringToNS (path) error: nil];
+   #else
+    // (the cast here avoids a deprecation warning)
+    return [((id) [NSFileManager defaultManager]) pathContentOfSymbolicLinkAtPath: juceStringToNS (path)];
+   #endif
+}
+
+bool File::isLink() const
+{
+    return getFileLink (fullPath) != nil;
+}
+
+File File::getLinkedTarget() const
+{
+    if (NSString* dest = getFileLink (fullPath))
+        return getSiblingFile (nsStringToJuce (dest));
+
+    return *this;
+}
+
+//==============================================================================
+bool File::moveToTrash() const
+{
+    if (! exists())
+        return true;
+
+   #if JUCE_IOS
+    return deleteFile(); //xxx is there a trashcan on the iOS?
+   #else
+    JUCE_AUTORELEASEPOOL
+    {
+        NSString* p = juceStringToNS (getFullPathName());
+
+        return [[NSWorkspace sharedWorkspace]
+                    performFileOperation: NSWorkspaceRecycleOperation
+                                  source: [p stringByDeletingLastPathComponent]
+                             destination: nsEmptyString()
+                                   files: [NSArray arrayWithObject: [p lastPathComponent]]
+                                     tag: nil ];
+    }
+   #endif
+}
+
+//==============================================================================
+class DirectoryIterator::NativeIterator::Pimpl
+{
+public:
+    Pimpl (const File& directory, const String& wildCard_)
+        : parentDir (File::addTrailingSeparator (directory.getFullPathName())),
+          wildCard (wildCard_),
+          enumerator (nil)
+    {
+        JUCE_AUTORELEASEPOOL
+        {
+            enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: juceStringToNS (directory.getFullPathName())] retain];
+        }
+    }
+
+    ~Pimpl()
+    {
+        [enumerator release];
+    }
+
+    bool next (String& filenameFound,
+               bool* const isDir, bool* const isHidden, int64* const fileSize,
+               Time* const modTime, Time* const creationTime, bool* const isReadOnly)
+    {
+        JUCE_AUTORELEASEPOOL
+        {
+            const char* wildcardUTF8 = nullptr;
+
+            for (;;)
+            {
+                NSString* file;
+                if (enumerator == nil || (file = [enumerator nextObject]) == nil)
+                    return false;
+
+                [enumerator skipDescendents];
+                filenameFound = nsStringToJuce (file).convertToPrecomposedUnicode();
+
+                if (wildcardUTF8 == nullptr)
+                    wildcardUTF8 = wildCard.toUTF8();
+
+                if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0)
+                    continue;
+
+                const String fullPath (parentDir + filenameFound);
+                updateStatInfoForFile (fullPath, isDir, fileSize, modTime, creationTime, isReadOnly);
+
+                if (isHidden != nullptr)
+                    *isHidden = FileHelpers::isHiddenFile (fullPath);
+
+                return true;
+            }
+        }
+    }
+
+private:
+    String parentDir, wildCard;
+    NSDirectoryEnumerator* enumerator;
+
+    JUCE_DECLARE_NON_COPYABLE (Pimpl)
+};
+
+DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildcard)
+    : pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildcard))
+{
+}
+
+DirectoryIterator::NativeIterator::~NativeIterator()
+{
+}
+
+bool DirectoryIterator::NativeIterator::next (String& filenameFound,
+                                              bool* const isDir, bool* const isHidden, int64* const fileSize,
+                                              Time* const modTime, Time* const creationTime, bool* const isReadOnly)
+{
+    return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
+}
+
+
+//==============================================================================
+bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String& parameters)
+{
+    JUCE_AUTORELEASEPOOL
+    {
+        NSURL* filenameAsURL = [NSURL URLWithString: juceStringToNS (fileName)];
+
+      #if JUCE_IOS
+        (void) parameters;
+        return [[UIApplication sharedApplication] openURL: filenameAsURL];
+      #else
+        NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
+
+        if (parameters.isEmpty())
+            return [workspace openFile: juceStringToNS (fileName)]
+                || [workspace openURL: filenameAsURL];
+
+        const File file (fileName);
+
+        if (file.isBundle())
+        {
+            StringArray params;
+            params.addTokens (parameters, true);
+
+            NSMutableArray* paramArray = [[[NSMutableArray alloc] init] autorelease];
+            for (int i = 0; i < params.size(); ++i)
+                [paramArray addObject: juceStringToNS (params[i])];
+
+            NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease];
+            [dict setObject: paramArray
+                     forKey: nsStringLiteral ("NSWorkspaceLaunchConfigurationArguments")];
+
+            return [workspace launchApplicationAtURL: filenameAsURL
+                                             options: NSWorkspaceLaunchDefault | NSWorkspaceLaunchNewInstance
+                                       configuration: dict
+                                               error: nil];
+        }
+
+        if (file.exists())
+            return FileHelpers::launchExecutable ("\"" + fileName + "\" " + parameters);
+
+        return false;
+      #endif
+    }
+}
+
+void File::revealToUser() const
+{
+   #if ! JUCE_IOS
+    if (exists())
+        [[NSWorkspace sharedWorkspace] selectFile: juceStringToNS (getFullPathName()) inFileViewerRootedAtPath: nsEmptyString()];
+    else if (getParentDirectory().exists())
+        getParentDirectory().revealToUser();
+   #endif
+}
+
+//==============================================================================
+OSType File::getMacOSType() const
+{
+    JUCE_AUTORELEASEPOOL
+    {
+       #if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+        NSDictionary* fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath: juceStringToNS (getFullPathName()) error: nil];
+       #else
+        // (the cast here avoids a deprecation warning)
+        NSDictionary* fileDict = [((id) [NSFileManager defaultManager]) fileAttributesAtPath: juceStringToNS (getFullPathName()) traverseLink: NO];
+       #endif
+
+        return [fileDict fileHFSTypeCode];
+    }
+}
+
+bool File::isBundle() const
+{
+   #if JUCE_IOS
+    return false; // xxx can't find a sensible way to do this without trying to open the bundle..
+   #else
+    JUCE_AUTORELEASEPOOL
+    {
+        return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: juceStringToNS (getFullPathName())];
+    }
+   #endif
+}
+
+#if JUCE_MAC
+void File::addToDock() const
+{
+    // check that it's not already there...
+    if (! juce_getOutputFromCommand ("defaults read com.apple.dock persistent-apps").containsIgnoreCase (getFullPathName()))
+    {
+        juce_runSystemCommand ("defaults write com.apple.dock persistent-apps -array-add \"<dict><key>tile-data</key><dict><key>file-data</key><dict><key>_CFURLString</key><string>"
+                                 + getFullPathName() + "</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>\"");
+
+        juce_runSystemCommand ("osascript -e \"tell application \\\"Dock\\\" to quit\"");
+    }
+}
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Network.mm b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Network.mm
new file mode 100644
index 0000000..130759e
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Network.mm
@@ -0,0 +1,445 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+void MACAddress::findAllAddresses (Array<MACAddress>& result)
+{
+    ifaddrs* addrs = nullptr;
+
+    if (getifaddrs (&addrs) == 0)
+    {
+        for (const ifaddrs* cursor = addrs; cursor != nullptr; cursor = cursor->ifa_next)
+        {
+            sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr;
+            if (sto->ss_family == AF_LINK)
+            {
+                const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
+
+               #ifndef IFT_ETHER
+                enum { IFT_ETHER = 6 };
+               #endif
+
+                if (sadd->sdl_type == IFT_ETHER)
+                {
+                    MACAddress ma (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
+
+                    if (! ma.isNull())
+                        result.addIfNotAlreadyThere (ma);
+                }
+            }
+        }
+
+        freeifaddrs (addrs);
+    }
+}
+
+//==============================================================================
+bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailAddress,
+                                                      const String& emailSubject,
+                                                      const String& bodyText,
+                                                      const StringArray& filesToAttach)
+{
+  #if JUCE_IOS
+    (void) targetEmailAddress;
+    (void) emailSubject;
+    (void) bodyText;
+    (void) filesToAttach;
+
+    //xxx probably need to use MFMailComposeViewController
+    jassertfalse;
+    return false;
+  #else
+    JUCE_AUTORELEASEPOOL
+    {
+        String script;
+        script << "tell application \"Mail\"\r\n"
+                  "set newMessage to make new outgoing message with properties {subject:\""
+               << emailSubject.replace ("\"", "\\\"")
+               << "\", content:\""
+               << bodyText.replace ("\"", "\\\"")
+               << "\" & return & return}\r\n"
+                  "tell newMessage\r\n"
+                  "set visible to true\r\n"
+                  "set sender to \"sdfsdfsdfewf\"\r\n"
+                  "make new to recipient at end of to recipients with properties {address:\""
+               << targetEmailAddress
+               << "\"}\r\n";
+
+        for (int i = 0; i < filesToAttach.size(); ++i)
+        {
+            script << "tell content\r\n"
+                      "make new attachment with properties {file name:\""
+                   << filesToAttach[i].replace ("\"", "\\\"")
+                   << "\"} at after the last paragraph\r\n"
+                      "end tell\r\n";
+        }
+
+        script << "end tell\r\n"
+                  "end tell\r\n";
+
+        NSAppleScript* s = [[NSAppleScript alloc] initWithSource: juceStringToNS (script)];
+        NSDictionary* error = nil;
+        const bool ok = [s executeAndReturnError: &error] != nil;
+        [s release];
+
+        return ok;
+    }
+  #endif
+}
+
+//==============================================================================
+class URLConnectionState   : public Thread
+{
+public:
+    URLConnectionState (NSURLRequest* req)
+        : Thread ("http connection"),
+          contentLength (-1),
+          delegate (nil),
+          request ([req retain]),
+          connection (nil),
+          data ([[NSMutableData data] retain]),
+          headers (nil),
+          statusCode (0),
+          initialised (false),
+          hasFailed (false),
+          hasFinished (false)
+    {
+        static DelegateClass cls;
+        delegate = [cls.createInstance() init];
+        DelegateClass::setState (delegate, this);
+    }
+
+    ~URLConnectionState()
+    {
+        stop();
+        [connection release];
+        [data release];
+        [request release];
+        [headers release];
+        [delegate release];
+    }
+
+    bool start (URL::OpenStreamProgressCallback* callback, void* context)
+    {
+        startThread();
+
+        while (isThreadRunning() && ! initialised)
+        {
+            if (callback != nullptr)
+                callback (context, -1, (int) [[request HTTPBody] length]);
+
+            Thread::sleep (1);
+        }
+
+        return connection != nil && ! hasFailed;
+    }
+
+    void stop()
+    {
+        [connection cancel];
+        stopThread (10000);
+    }
+
+    int read (char* dest, int numBytes)
+    {
+        int numDone = 0;
+
+        while (numBytes > 0)
+        {
+            const int available = jmin (numBytes, (int) [data length]);
+
+            if (available > 0)
+            {
+                const ScopedLock sl (dataLock);
+                [data getBytes: dest length: (NSUInteger) available];
+                [data replaceBytesInRange: NSMakeRange (0, (NSUInteger) available) withBytes: nil length: 0];
+
+                numDone += available;
+                numBytes -= available;
+                dest += available;
+            }
+            else
+            {
+                if (hasFailed || hasFinished)
+                    break;
+
+                Thread::sleep (1);
+            }
+        }
+
+        return numDone;
+    }
+
+    void didReceiveResponse (NSURLResponse* response)
+    {
+        {
+            const ScopedLock sl (dataLock);
+            [data setLength: 0];
+        }
+
+        initialised = true;
+        contentLength = [response expectedContentLength];
+
+        [headers release];
+        headers = nil;
+
+        if ([response isKindOfClass: [NSHTTPURLResponse class]])
+        {
+            NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
+            headers = [[httpResponse allHeaderFields] retain];
+            statusCode = (int) [httpResponse statusCode];
+        }
+    }
+
+    void didFailWithError (NSError* error)
+    {
+        DBG (nsStringToJuce ([error description])); (void) error;
+        hasFailed = true;
+        initialised = true;
+        signalThreadShouldExit();
+    }
+
+    void didReceiveData (NSData* newData)
+    {
+        const ScopedLock sl (dataLock);
+        [data appendData: newData];
+        initialised = true;
+    }
+
+    void didSendBodyData (NSInteger /*totalBytesWritten*/, NSInteger /*totalBytesExpected*/)
+    {
+    }
+
+    void finishedLoading()
+    {
+        hasFinished = true;
+        initialised = true;
+        signalThreadShouldExit();
+    }
+
+    void run() override
+    {
+        connection = [[NSURLConnection alloc] initWithRequest: request
+                                                     delegate: delegate];
+        while (! threadShouldExit())
+        {
+            JUCE_AUTORELEASEPOOL
+            {
+                [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
+            }
+        }
+    }
+
+    int64 contentLength;
+    CriticalSection dataLock;
+    NSObject* delegate;
+    NSURLRequest* request;
+    NSURLConnection* connection;
+    NSMutableData* data;
+    NSDictionary* headers;
+    int statusCode;
+    bool initialised, hasFailed, hasFinished;
+
+private:
+    //==============================================================================
+    struct DelegateClass  : public ObjCClass<NSObject>
+    {
+        DelegateClass()  : ObjCClass<NSObject> ("JUCEAppDelegate_")
+        {
+            addIvar<URLConnectionState*> ("state");
+
+            addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse,            "v@:@@");
+            addMethod (@selector (connection:didFailWithError:),   didFailWithError,              "v@:@@");
+            addMethod (@selector (connection:didReceiveData:),     didReceiveData,                "v@:@@");
+            addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:),
+                                                                   connectionDidSendBodyData,     "v@:@iii");
+            addMethod (@selector (connectionDidFinishLoading:),    connectionDidFinishLoading,    "v@:@");
+            addMethod (@selector (connection:willSendRequest:redirectResponse:), willSendRequest, "@@:@@");
+
+            registerClass();
+        }
+
+        static void setState (id self, URLConnectionState* state)  { object_setInstanceVariable (self, "state", state); }
+        static URLConnectionState* getState (id self)              { return getIvar<URLConnectionState*> (self, "state"); }
+
+    private:
+        static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response)
+        {
+            getState (self)->didReceiveResponse (response);
+        }
+
+        static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error)
+        {
+            getState (self)->didFailWithError (error);
+        }
+
+        static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData)
+        {
+            getState (self)->didReceiveData (newData);
+        }
+
+        static NSURLRequest* willSendRequest (id, SEL, NSURLConnection*, NSURLRequest* request, NSURLResponse*)
+        {
+            return request;
+        }
+
+        static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected)
+        {
+            getState (self)->didSendBodyData (totalBytesWritten, totalBytesExpected);
+        }
+
+        static void connectionDidFinishLoading (id self, SEL, NSURLConnection*)
+        {
+            getState (self)->finishedLoading();
+        }
+    };
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState)
+};
+
+
+//==============================================================================
+class WebInputStream  : public InputStream
+{
+public:
+    WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
+                    URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
+                    const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
+      : statusCode (0), address (address_), headers (headers_), postData (postData_), position (0),
+        finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
+    {
+        JUCE_AUTORELEASEPOOL
+        {
+            createConnection (progressCallback, progressCallbackContext);
+
+            if (responseHeaders != nullptr && connection != nullptr && connection->headers != nil)
+            {
+                statusCode = connection->statusCode;
+
+                NSEnumerator* enumerator = [connection->headers keyEnumerator];
+
+                while (NSString* key = [enumerator nextObject])
+                    responseHeaders->set (nsStringToJuce (key),
+                                          nsStringToJuce ((NSString*) [connection->headers objectForKey: key]));
+            }
+        }
+    }
+
+    //==============================================================================
+    bool isError() const                { return connection == nullptr; }
+    int64 getTotalLength() override     { return connection == nullptr ? -1 : connection->contentLength; }
+    bool isExhausted() override         { return finished; }
+    int64 getPosition() override        { return position; }
+
+    int read (void* buffer, int bytesToRead) override
+    {
+        jassert (buffer != nullptr && bytesToRead >= 0);
+
+        if (finished || isError())
+            return 0;
+
+        JUCE_AUTORELEASEPOOL
+        {
+            const int bytesRead = connection->read (static_cast<char*> (buffer), bytesToRead);
+            position += bytesRead;
+
+            if (bytesRead == 0)
+                finished = true;
+
+            return bytesRead;
+        }
+    }
+
+    bool setPosition (int64 wantedPos) override
+    {
+        if (wantedPos != position)
+        {
+            finished = false;
+
+            if (wantedPos < position)
+            {
+                connection = nullptr;
+                position = 0;
+                createConnection (0, 0);
+            }
+
+            skipNextBytes (wantedPos - position);
+        }
+
+        return true;
+    }
+
+    int statusCode;
+
+private:
+    ScopedPointer<URLConnectionState> connection;
+    String address, headers;
+    MemoryBlock postData;
+    int64 position;
+    bool finished;
+    const bool isPost;
+    const int timeOutMs;
+
+    void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
+    {
+        jassert (connection == nullptr);
+
+        NSMutableURLRequest* req = [NSMutableURLRequest  requestWithURL: [NSURL URLWithString: juceStringToNS (address)]
+                                                            cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
+                                                        timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)];
+
+        if (req != nil)
+        {
+            [req setHTTPMethod: nsStringLiteral (isPost ? "POST" : "GET")];
+            //[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
+
+            StringArray headerLines;
+            headerLines.addLines (headers);
+            headerLines.removeEmptyStrings (true);
+
+            for (int i = 0; i < headerLines.size(); ++i)
+            {
+                const String key (headerLines[i].upToFirstOccurrenceOf (":", false, false).trim());
+                const String value (headerLines[i].fromFirstOccurrenceOf (":", false, false).trim());
+
+                if (key.isNotEmpty() && value.isNotEmpty())
+                    [req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)];
+            }
+
+            if (isPost && postData.getSize() > 0)
+                [req setHTTPBody: [NSData dataWithBytes: postData.getData()
+                                                 length: postData.getSize()]];
+
+            connection = new URLConnectionState (req);
+
+            if (! connection->start (progressCallback, progressCallbackContext))
+                connection = nullptr;
+        }
+    }
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
+};
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Strings.mm b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Strings.mm
new file mode 100644
index 0000000..862eb53
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Strings.mm
@@ -0,0 +1,96 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+String String::fromCFString (CFStringRef cfString)
+{
+    if (cfString == 0)
+        return String();
+
+    CFRange range = { 0, CFStringGetLength (cfString) };
+    HeapBlock <UniChar> u ((size_t) range.length + 1);
+    CFStringGetCharacters (cfString, range, u);
+    u[range.length] = 0;
+
+    return String (CharPointer_UTF16 ((const CharPointer_UTF16::CharType*) u.getData()));
+}
+
+CFStringRef String::toCFString() const
+{
+    CharPointer_UTF16 utf16 (toUTF16());
+    return CFStringCreateWithCharacters (kCFAllocatorDefault, (const UniChar*) utf16.getAddress(), (CFIndex) utf16.length());
+}
+
+String String::convertToPrecomposedUnicode() const
+{
+   #if JUCE_IOS
+    JUCE_AUTORELEASEPOOL
+    {
+        return nsStringToJuce ([juceStringToNS (*this) precomposedStringWithCanonicalMapping]);
+    }
+   #else
+    UnicodeMapping map;
+
+    map.unicodeEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
+                                              kUnicodeNoSubset,
+                                              kTextEncodingDefaultFormat);
+
+    map.otherEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
+                                            kUnicodeCanonicalCompVariant,
+                                            kTextEncodingDefaultFormat);
+
+    map.mappingVersion = kUnicodeUseLatestMapping;
+
+    UnicodeToTextInfo conversionInfo = 0;
+    String result;
+
+    if (CreateUnicodeToTextInfo (&map, &conversionInfo) == noErr)
+    {
+        const size_t bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (getCharPointer());
+
+        HeapBlock <char> tempOut;
+        tempOut.calloc (bytesNeeded + 4);
+
+        ByteCount bytesRead = 0;
+        ByteCount outputBufferSize = 0;
+
+        if (ConvertFromUnicodeToText (conversionInfo,
+                                      bytesNeeded, (ConstUniCharArrayPtr) toUTF16().getAddress(),
+                                      kUnicodeDefaultDirectionMask,
+                                      0, 0, 0, 0,
+                                      bytesNeeded, &bytesRead,
+                                      &outputBufferSize, tempOut) == noErr)
+        {
+            result = String (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData()));
+        }
+
+        DisposeUnicodeToTextInfo (&conversionInfo);
+    }
+
+    return result;
+   #endif
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_SystemStats.mm b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_SystemStats.mm
new file mode 100644
index 0000000..2d49ae6
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_SystemStats.mm
@@ -0,0 +1,306 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+ScopedAutoReleasePool::ScopedAutoReleasePool()
+{
+    pool = [[NSAutoreleasePool alloc] init];
+}
+
+ScopedAutoReleasePool::~ScopedAutoReleasePool()
+{
+    [((NSAutoreleasePool*) pool) release];
+}
+
+//==============================================================================
+void Logger::outputDebugString (const String& text)
+{
+    // Would prefer to use std::cerr here, but avoiding it for
+    // the moment, due to clang JIT linkage problems.
+    fputs (text.toRawUTF8(), stderr);
+    fputs ("\n", stderr);
+    fflush (stderr);
+}
+
+//==============================================================================
+namespace SystemStatsHelpers
+{
+   #if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
+    static void doCPUID (uint32& a, uint32& b, uint32& c, uint32& d, uint32 type)
+    {
+        uint32 la = a, lb = b, lc = c, ld = d;
+
+        asm ("mov %%ebx, %%esi \n\t"
+             "cpuid \n\t"
+             "xchg %%esi, %%ebx"
+               : "=a" (la), "=S" (lb), "=c" (lc), "=d" (ld) : "a" (type)
+           #if JUCE_64BIT
+                  , "b" (lb), "c" (lc), "d" (ld)
+           #endif
+        );
+
+        a = la; b = lb; c = lc; d = ld;
+    }
+   #endif
+}
+
+//==============================================================================
+void CPUInformation::initialise() noexcept
+{
+   #if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
+    uint32 a = 0, b = 0, d = 0, c = 0;
+    SystemStatsHelpers::doCPUID (a, b, c, d, 1);
+
+    hasMMX   = (d & (1u << 23)) != 0;
+    hasSSE   = (d & (1u << 25)) != 0;
+    hasSSE2  = (d & (1u << 26)) != 0;
+    has3DNow = (b & (1u << 31)) != 0;
+    hasSSE3  = (c & (1u <<  0)) != 0;
+   #endif
+
+   #if JUCE_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+    numCpus = (int) [[NSProcessInfo processInfo] activeProcessorCount];
+   #else
+    numCpus = (int) MPProcessors();
+   #endif
+}
+
+#if JUCE_MAC
+struct RLimitInitialiser
+{
+    RLimitInitialiser()
+    {
+        rlimit lim;
+        getrlimit (RLIMIT_NOFILE, &lim);
+        lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
+        setrlimit (RLIMIT_NOFILE, &lim);
+    }
+};
+
+static RLimitInitialiser rLimitInitialiser;
+#endif
+
+//==============================================================================
+#if ! JUCE_IOS
+static String getOSXVersion()
+{
+    JUCE_AUTORELEASEPOOL
+    {
+        NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:
+                                    nsStringLiteral ("/System/Library/CoreServices/SystemVersion.plist")];
+
+        return nsStringToJuce ([dict objectForKey: nsStringLiteral ("ProductVersion")]);
+    }
+}
+#endif
+
+SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
+{
+   #if JUCE_IOS
+    return iOS;
+   #else
+    StringArray parts;
+    parts.addTokens (getOSXVersion(), ".", StringRef());
+
+    jassert (parts[0].getIntValue() == 10);
+    const int major = parts[1].getIntValue();
+    jassert (major > 2);
+
+    return (OperatingSystemType) (major + MacOSX_10_4 - 4);
+   #endif
+}
+
+String SystemStats::getOperatingSystemName()
+{
+   #if JUCE_IOS
+    return "iOS " + nsStringToJuce ([[UIDevice currentDevice] systemVersion]);
+   #else
+    return "Mac OSX " + getOSXVersion();
+   #endif
+}
+
+String SystemStats::getDeviceDescription()
+{
+   #if JUCE_IOS
+    return nsStringToJuce ([[UIDevice currentDevice] model]);
+   #else
+    return String();
+   #endif
+}
+
+bool SystemStats::isOperatingSystem64Bit()
+{
+   #if JUCE_IOS
+    return false;
+   #elif JUCE_64BIT
+    return true;
+   #else
+    return getOperatingSystemType() >= MacOSX_10_6;
+   #endif
+}
+
+int SystemStats::getMemorySizeInMegabytes()
+{
+    uint64 mem = 0;
+    size_t memSize = sizeof (mem);
+    int mib[] = { CTL_HW, HW_MEMSIZE };
+    sysctl (mib, 2, &mem, &memSize, 0, 0);
+    return (int) (mem / (1024 * 1024));
+}
+
+String SystemStats::getCpuVendor()
+{
+   #if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
+    uint32 dummy = 0;
+    uint32 vendor[4] = { 0 };
+
+    SystemStatsHelpers::doCPUID (dummy, vendor[0], vendor[2], vendor[1], 0);
+
+    return String (reinterpret_cast <const char*> (vendor), 12);
+   #else
+    return String();
+   #endif
+}
+
+int SystemStats::getCpuSpeedInMegaherz()
+{
+    uint64 speedHz = 0;
+    size_t speedSize = sizeof (speedHz);
+    int mib[] = { CTL_HW, HW_CPU_FREQ };
+    sysctl (mib, 2, &speedHz, &speedSize, 0, 0);
+
+   #if JUCE_BIG_ENDIAN
+    if (speedSize == 4)
+        speedHz >>= 32;
+   #endif
+
+    return (int) (speedHz / 1000000);
+}
+
+//==============================================================================
+String SystemStats::getLogonName()
+{
+    return nsStringToJuce (NSUserName());
+}
+
+String SystemStats::getFullUserName()
+{
+    return nsStringToJuce (NSFullUserName());
+}
+
+String SystemStats::getComputerName()
+{
+    char name [256] = { 0 };
+    if (gethostname (name, sizeof (name) - 1) == 0)
+        return String (name).upToLastOccurrenceOf (".local", false, true);
+
+    return String();
+}
+
+static String getLocaleValue (CFStringRef key)
+{
+    CFLocaleRef cfLocale = CFLocaleCopyCurrent();
+    const String result (String::fromCFString ((CFStringRef) CFLocaleGetValue (cfLocale, key)));
+    CFRelease (cfLocale);
+    return result;
+}
+
+String SystemStats::getUserLanguage()   { return getLocaleValue (kCFLocaleLanguageCode); }
+String SystemStats::getUserRegion()     { return getLocaleValue (kCFLocaleCountryCode); }
+
+String SystemStats::getDisplayLanguage()
+{
+    CFArrayRef cfPrefLangs = CFLocaleCopyPreferredLanguages();
+    const String result (String::fromCFString ((CFStringRef) CFArrayGetValueAtIndex (cfPrefLangs, 0)));
+    CFRelease (cfPrefLangs);
+    return result;
+}
+
+//==============================================================================
+/*  NB: these are kept outside the HiResCounterInfo struct and initialised to 1 to avoid
+    division-by-zero errors if some other static constructor calls us before this file's
+    static constructors have had a chance to fill them in correctly..
+*/
+static uint64 hiResCounterNumerator = 0, hiResCounterDenominator = 1;
+
+class HiResCounterInfo
+{
+public:
+    HiResCounterInfo()
+    {
+        mach_timebase_info_data_t timebase;
+        (void) mach_timebase_info (&timebase);
+
+        if (timebase.numer % 1000000 == 0)
+        {
+            hiResCounterNumerator   = timebase.numer / 1000000;
+            hiResCounterDenominator = timebase.denom;
+        }
+        else
+        {
+            hiResCounterNumerator   = timebase.numer;
+            hiResCounterDenominator = timebase.denom * (uint64) 1000000;
+        }
+
+        highResTimerFrequency = (timebase.denom * (uint64) 1000000000) / timebase.numer;
+        highResTimerToMillisecRatio = hiResCounterNumerator / (double) hiResCounterDenominator;
+    }
+
+    uint32 millisecondsSinceStartup() const noexcept
+    {
+        return (uint32) ((mach_absolute_time() * hiResCounterNumerator) / hiResCounterDenominator);
+    }
+
+    double getMillisecondCounterHiRes() const noexcept
+    {
+        return mach_absolute_time() * highResTimerToMillisecRatio;
+    }
+
+    int64 highResTimerFrequency;
+
+private:
+    double highResTimerToMillisecRatio;
+};
+
+static HiResCounterInfo hiResCounterInfo;
+
+uint32 juce_millisecondsSinceStartup() noexcept         { return hiResCounterInfo.millisecondsSinceStartup(); }
+double Time::getMillisecondCounterHiRes() noexcept      { return hiResCounterInfo.getMillisecondCounterHiRes(); }
+int64  Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterInfo.highResTimerFrequency; }
+int64  Time::getHighResolutionTicks() noexcept          { return (int64) mach_absolute_time(); }
+
+bool Time::setSystemTimeToThisTime() const
+{
+    jassertfalse;
+    return false;
+}
+
+//==============================================================================
+int SystemStats::getPageSize()
+{
+    return (int) NSPageSize();
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Threads.mm b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Threads.mm
new file mode 100644
index 0000000..004baeb
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_mac_Threads.mm
@@ -0,0 +1,97 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+/*
+    Note that a lot of methods that you'd expect to find in this file actually
+    live in juce_posix_SharedCode.h!
+*/
+
+#if JUCE_IOS
+bool isIOSAppActive = true;
+#endif
+
+//==============================================================================
+JUCE_API bool JUCE_CALLTYPE Process::isForegroundProcess()
+{
+   #if JUCE_MAC
+    return [NSApp isActive];
+   #else
+    return isIOSAppActive;
+   #endif
+}
+
+JUCE_API void JUCE_CALLTYPE Process::makeForegroundProcess()
+{
+   #if JUCE_MAC
+    [NSApp activateIgnoringOtherApps: YES];
+   #endif
+}
+
+JUCE_API void JUCE_CALLTYPE Process::hide()
+{
+   #if JUCE_MAC
+    [NSApp hide: nil];
+   #endif
+}
+
+JUCE_API void JUCE_CALLTYPE Process::raisePrivilege()
+{
+    jassertfalse;
+}
+
+JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege()
+{
+    jassertfalse;
+}
+
+JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority)
+{
+    // xxx
+}
+
+//==============================================================================
+JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
+{
+    static char testResult = 0;
+
+    if (testResult == 0)
+    {
+        struct kinfo_proc info;
+        int m[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
+        size_t sz = sizeof (info);
+        sysctl (m, 4, &info, &sz, 0, 0);
+        testResult = ((info.kp_proc.p_flag & P_TRACED) != 0) ? 1 : -1;
+    }
+
+    return testResult > 0;
+}
+
+JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
+{
+    return juce_isRunningUnderDebugger();
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_osx_ObjCHelpers.h b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_osx_ObjCHelpers.h
new file mode 100644
index 0000000..10878d0
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_osx_ObjCHelpers.h
@@ -0,0 +1,169 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_OSX_OBJCHELPERS_H_INCLUDED
+#define JUCE_OSX_OBJCHELPERS_H_INCLUDED
+
+
+/* This file contains a few helper functions that are used internally but which
+   need to be kept away from the public headers because they use obj-C symbols.
+*/
+namespace
+{
+    //==============================================================================
+    static inline String nsStringToJuce (NSString* s)
+    {
+        return CharPointer_UTF8 ([s UTF8String]);
+    }
+
+    static inline NSString* juceStringToNS (const String& s)
+    {
+        return [NSString stringWithUTF8String: s.toUTF8()];
+    }
+
+    static inline NSString* nsStringLiteral (const char* const s) noexcept
+    {
+        return [NSString stringWithUTF8String: s];
+    }
+
+    static inline NSString* nsEmptyString() noexcept
+    {
+        return [NSString string];
+    }
+
+   #if JUCE_MAC
+    template <typename RectangleType>
+    static NSRect makeNSRect (const RectangleType& r) noexcept
+    {
+        return NSMakeRect (static_cast <CGFloat> (r.getX()),
+                           static_cast <CGFloat> (r.getY()),
+                           static_cast <CGFloat> (r.getWidth()),
+                           static_cast <CGFloat> (r.getHeight()));
+    }
+   #endif
+}
+
+//==============================================================================
+template <typename ObjectType>
+struct NSObjectRetainer
+{
+    inline NSObjectRetainer (ObjectType* o) : object (o)  { [object retain]; }
+    inline ~NSObjectRetainer()                            { [object release]; }
+
+    ObjectType* object;
+};
+
+//==============================================================================
+template <typename SuperclassType>
+struct ObjCClass
+{
+    ObjCClass (const char* nameRoot)
+        : cls (objc_allocateClassPair ([SuperclassType class], getRandomisedName (nameRoot).toUTF8(), 0))
+    {
+    }
+
+    ~ObjCClass()
+    {
+        objc_disposeClassPair (cls);
+    }
+
+    void registerClass()
+    {
+        objc_registerClassPair (cls);
+    }
+
+    SuperclassType* createInstance() const
+    {
+        return class_createInstance (cls, 0);
+    }
+
+    template <typename Type>
+    void addIvar (const char* name)
+    {
+        BOOL b = class_addIvar (cls, name, sizeof (Type), (uint8_t) rint (log2 (sizeof (Type))), @encode (Type));
+        jassert (b); (void) b;
+    }
+
+    template <typename FunctionType>
+    void addMethod (SEL selector, FunctionType callbackFn, const char* signature)
+    {
+        BOOL b = class_addMethod (cls, selector, (IMP) callbackFn, signature);
+        jassert (b); (void) b;
+    }
+
+    template <typename FunctionType>
+    void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2)
+    {
+        addMethod (selector, callbackFn, (String (sig1) + sig2).toUTF8());
+    }
+
+    template <typename FunctionType>
+    void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3)
+    {
+        addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3).toUTF8());
+    }
+
+    template <typename FunctionType>
+    void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3, const char* sig4)
+    {
+        addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3 + sig4).toUTF8());
+    }
+
+    void addProtocol (Protocol* protocol)
+    {
+        BOOL b = class_addProtocol (cls, protocol);
+        jassert (b); (void) b;
+    }
+
+    static id sendSuperclassMessage (id self, SEL selector)
+    {
+        objc_super s = { self, [SuperclassType class] };
+        return objc_msgSendSuper (&s, selector);
+    }
+
+    template <typename Type>
+    static Type getIvar (id self, const char* name)
+    {
+        void* v = nullptr;
+        object_getInstanceVariable (self, name, &v);
+        return static_cast <Type> (v);
+    }
+
+    Class cls;
+
+private:
+    static String getRandomisedName (const char* root)
+    {
+        return root + String::toHexString (juce::Random::getSystemRandom().nextInt64());
+    }
+
+    JUCE_DECLARE_NON_COPYABLE (ObjCClass)
+};
+
+
+#endif   // JUCE_OSX_OBJCHELPERS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_posix_NamedPipe.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_posix_NamedPipe.cpp
new file mode 100644
index 0000000..d0c0b09
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_posix_NamedPipe.cpp
@@ -0,0 +1,224 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+class NamedPipe::Pimpl
+{
+public:
+    Pimpl (const String& pipePath, bool createPipe)
+       : pipeInName  (pipePath + "_in"),
+         pipeOutName (pipePath + "_out"),
+         pipeIn (-1), pipeOut (-1),
+         createdPipe (createPipe),
+         stopReadOperation (false)
+    {
+        signal (SIGPIPE, signalHandler);
+        juce_siginterrupt (SIGPIPE, 1);
+    }
+
+    ~Pimpl()
+    {
+        if (pipeIn  != -1)  ::close (pipeIn);
+        if (pipeOut != -1)  ::close (pipeOut);
+
+        if (createdPipe)
+        {
+            unlink (pipeInName.toUTF8());
+            unlink (pipeOutName.toUTF8());
+        }
+    }
+
+    int read (char* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
+    {
+        const uint32 timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
+
+        if (pipeIn == -1)
+        {
+            pipeIn = openPipe (createdPipe ? pipeInName : pipeOutName, O_RDWR | O_NONBLOCK, timeoutEnd);
+
+            if (pipeIn == -1)
+                return -1;
+        }
+
+        int bytesRead = 0;
+
+        while (bytesRead < maxBytesToRead)
+        {
+            const int bytesThisTime = maxBytesToRead - bytesRead;
+            const int numRead = (int) ::read (pipeIn, destBuffer, (size_t) bytesThisTime);
+
+            if (numRead <= 0)
+            {
+                if (errno != EWOULDBLOCK || stopReadOperation || hasExpired (timeoutEnd))
+                    return -1;
+
+                const int maxWaitingTime = 30;
+                waitForInput (pipeIn, timeoutEnd == 0 ? maxWaitingTime
+                                                      : jmin (maxWaitingTime,
+                                                              (int) (timeoutEnd - Time::getMillisecondCounter())));
+                continue;
+            }
+
+            bytesRead += numRead;
+            destBuffer += numRead;
+        }
+
+        return bytesRead;
+    }
+
+    int write (const char* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
+    {
+        const uint32 timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
+
+        if (pipeOut == -1)
+        {
+            pipeOut = openPipe (createdPipe ? pipeOutName : pipeInName, O_WRONLY, timeoutEnd);
+
+            if (pipeOut == -1)
+                return -1;
+        }
+
+        int bytesWritten = 0;
+
+        while (bytesWritten < numBytesToWrite && ! hasExpired (timeoutEnd))
+        {
+            const int bytesThisTime = numBytesToWrite - bytesWritten;
+            const int numWritten = (int) ::write (pipeOut, sourceBuffer, (size_t) bytesThisTime);
+
+            if (numWritten <= 0)
+                return -1;
+
+            bytesWritten += numWritten;
+            sourceBuffer += numWritten;
+        }
+
+        return bytesWritten;
+    }
+
+    bool createFifos() const
+    {
+        return (mkfifo (pipeInName .toUTF8(), 0666) == 0 || errno == EEXIST)
+            && (mkfifo (pipeOutName.toUTF8(), 0666) == 0 || errno == EEXIST);
+    }
+
+    const String pipeInName, pipeOutName;
+    int pipeIn, pipeOut;
+
+    const bool createdPipe;
+    bool stopReadOperation;
+
+private:
+    static void signalHandler (int) {}
+
+    static uint32 getTimeoutEnd (const int timeOutMilliseconds)
+    {
+        return timeOutMilliseconds >= 0 ? Time::getMillisecondCounter() + (uint32) timeOutMilliseconds : 0;
+    }
+
+    static bool hasExpired (const uint32 timeoutEnd)
+    {
+        return timeoutEnd != 0 && Time::getMillisecondCounter() >= timeoutEnd;
+    }
+
+    int openPipe (const String& name, int flags, const uint32 timeoutEnd)
+    {
+        for (;;)
+        {
+            const int p = ::open (name.toUTF8(), flags);
+
+            if (p != -1 || hasExpired (timeoutEnd) || stopReadOperation)
+                return p;
+
+            Thread::sleep (2);
+        }
+    }
+
+    static void waitForInput (const int handle, const int timeoutMsecs) noexcept
+    {
+        struct timeval timeout;
+        timeout.tv_sec = timeoutMsecs / 1000;
+        timeout.tv_usec = (timeoutMsecs % 1000) * 1000;
+
+        fd_set rset;
+        FD_ZERO (&rset);
+        FD_SET (handle, &rset);
+
+        select (handle + 1, &rset, nullptr, 0, &timeout);
+    }
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
+};
+
+void NamedPipe::close()
+{
+    if (pimpl != nullptr)
+    {
+        pimpl->stopReadOperation = true;
+
+        char buffer[1] = { 0 };
+        ssize_t done = ::write (pimpl->pipeIn, buffer, 1);
+        (void) done;
+
+        ScopedWriteLock sl (lock);
+        pimpl = nullptr;
+    }
+}
+
+bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
+{
+   #if JUCE_IOS
+    pimpl = new Pimpl (File::getSpecialLocation (File::tempDirectory)
+                         .getChildFile (File::createLegalFileName (pipeName)).getFullPathName(), createPipe);
+   #else
+    String file (pipeName);
+
+    if (! File::isAbsolutePath (file))
+        file = "/tmp/" + File::createLegalFileName (file);
+
+    pimpl = new Pimpl (file, createPipe);
+   #endif
+
+    if (createPipe && ! pimpl->createFifos())
+    {
+        pimpl = nullptr;
+        return false;
+    }
+
+    return true;
+}
+
+int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
+{
+    ScopedReadLock sl (lock);
+    return pimpl != nullptr ? pimpl->read (static_cast <char*> (destBuffer), maxBytesToRead, timeOutMilliseconds) : -1;
+}
+
+int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
+{
+    ScopedReadLock sl (lock);
+    return pimpl != nullptr ? pimpl->write (static_cast <const char*> (sourceBuffer), numBytesToWrite, timeOutMilliseconds) : -1;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_posix_SharedCode.h b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_posix_SharedCode.h
new file mode 100644
index 0000000..2636cea
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_posix_SharedCode.h
@@ -0,0 +1,1301 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+CriticalSection::CriticalSection() noexcept
+{
+    pthread_mutexattr_t atts;
+    pthread_mutexattr_init (&atts);
+    pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE);
+   #if ! JUCE_ANDROID
+    pthread_mutexattr_setprotocol (&atts, PTHREAD_PRIO_INHERIT);
+   #endif
+    pthread_mutex_init (&lock, &atts);
+    pthread_mutexattr_destroy (&atts);
+}
+
+CriticalSection::~CriticalSection() noexcept        { pthread_mutex_destroy (&lock); }
+void CriticalSection::enter() const noexcept        { pthread_mutex_lock (&lock); }
+bool CriticalSection::tryEnter() const noexcept     { return pthread_mutex_trylock (&lock) == 0; }
+void CriticalSection::exit() const noexcept         { pthread_mutex_unlock (&lock); }
+
+//==============================================================================
+WaitableEvent::WaitableEvent (const bool useManualReset) noexcept
+    : triggered (false), manualReset (useManualReset)
+{
+    pthread_cond_init (&condition, 0);
+
+    pthread_mutexattr_t atts;
+    pthread_mutexattr_init (&atts);
+   #if ! JUCE_ANDROID
+    pthread_mutexattr_setprotocol (&atts, PTHREAD_PRIO_INHERIT);
+   #endif
+    pthread_mutex_init (&mutex, &atts);
+}
+
+WaitableEvent::~WaitableEvent() noexcept
+{
+    pthread_cond_destroy (&condition);
+    pthread_mutex_destroy (&mutex);
+}
+
+bool WaitableEvent::wait (const int timeOutMillisecs) const noexcept
+{
+    pthread_mutex_lock (&mutex);
+
+    if (! triggered)
+    {
+        if (timeOutMillisecs < 0)
+        {
+            do
+            {
+                pthread_cond_wait (&condition, &mutex);
+            }
+            while (! triggered);
+        }
+        else
+        {
+            struct timeval now;
+            gettimeofday (&now, 0);
+
+            struct timespec time;
+            time.tv_sec  = now.tv_sec  + (timeOutMillisecs / 1000);
+            time.tv_nsec = (now.tv_usec + ((timeOutMillisecs % 1000) * 1000)) * 1000;
+
+            if (time.tv_nsec >= 1000000000)
+            {
+                time.tv_nsec -= 1000000000;
+                time.tv_sec++;
+            }
+
+            do
+            {
+                if (pthread_cond_timedwait (&condition, &mutex, &time) == ETIMEDOUT)
+                {
+                    pthread_mutex_unlock (&mutex);
+                    return false;
+                }
+            }
+            while (! triggered);
+        }
+    }
+
+    if (! manualReset)
+        triggered = false;
+
+    pthread_mutex_unlock (&mutex);
+    return true;
+}
+
+void WaitableEvent::signal() const noexcept
+{
+    pthread_mutex_lock (&mutex);
+
+    if (! triggered)
+    {
+        triggered = true;
+        pthread_cond_broadcast (&condition);
+    }
+
+    pthread_mutex_unlock (&mutex);
+}
+
+void WaitableEvent::reset() const noexcept
+{
+    pthread_mutex_lock (&mutex);
+    triggered = false;
+    pthread_mutex_unlock (&mutex);
+}
+
+//==============================================================================
+void JUCE_CALLTYPE Thread::sleep (int millisecs)
+{
+    struct timespec time;
+    time.tv_sec = millisecs / 1000;
+    time.tv_nsec = (millisecs % 1000) * 1000000;
+    nanosleep (&time, nullptr);
+}
+
+void JUCE_CALLTYPE Process::terminate()
+{
+   #if JUCE_ANDROID
+    _exit (EXIT_FAILURE);
+   #else
+    std::_Exit (EXIT_FAILURE);
+   #endif
+}
+
+//==============================================================================
+const juce_wchar File::separator = '/';
+const String File::separatorString ("/");
+
+//==============================================================================
+File File::getCurrentWorkingDirectory()
+{
+    HeapBlock<char> heapBuffer;
+
+    char localBuffer [1024];
+    char* cwd = getcwd (localBuffer, sizeof (localBuffer) - 1);
+    size_t bufferSize = 4096;
+
+    while (cwd == nullptr && errno == ERANGE)
+    {
+        heapBuffer.malloc (bufferSize);
+        cwd = getcwd (heapBuffer, bufferSize - 1);
+        bufferSize += 1024;
+    }
+
+    return File (CharPointer_UTF8 (cwd));
+}
+
+bool File::setAsCurrentWorkingDirectory() const
+{
+    return chdir (getFullPathName().toUTF8()) == 0;
+}
+
+//==============================================================================
+// The unix siginterrupt function is deprecated - this does the same job.
+int juce_siginterrupt (int sig, int flag)
+{
+    struct ::sigaction act;
+    (void) ::sigaction (sig, nullptr, &act);
+
+    if (flag != 0)
+        act.sa_flags &= ~SA_RESTART;
+    else
+        act.sa_flags |= SA_RESTART;
+
+    return ::sigaction (sig, &act, nullptr);
+}
+
+//==============================================================================
+namespace
+{
+   #if JUCE_LINUX || (JUCE_IOS && ! __DARWIN_ONLY_64_BIT_INO_T) // (this iOS stuff is to avoid a simulator bug)
+    typedef struct stat64 juce_statStruct;
+    #define JUCE_STAT     stat64
+   #else
+    typedef struct stat   juce_statStruct;
+    #define JUCE_STAT     stat
+   #endif
+
+    bool juce_stat (const String& fileName, juce_statStruct& info)
+    {
+        return fileName.isNotEmpty()
+                 && JUCE_STAT (fileName.toUTF8(), &info) == 0;
+    }
+
+    // if this file doesn't exist, find a parent of it that does..
+    bool juce_doStatFS (File f, struct statfs& result)
+    {
+        for (int i = 5; --i >= 0;)
+        {
+            if (f.exists())
+                break;
+
+            f = f.getParentDirectory();
+        }
+
+        return statfs (f.getFullPathName().toUTF8(), &result) == 0;
+    }
+
+    void updateStatInfoForFile (const String& path, bool* const isDir, int64* const fileSize,
+                                Time* const modTime, Time* const creationTime, bool* const isReadOnly)
+    {
+        if (isDir != nullptr || fileSize != nullptr || modTime != nullptr || creationTime != nullptr)
+        {
+            juce_statStruct info;
+            const bool statOk = juce_stat (path, info);
+
+            if (isDir != nullptr)         *isDir        = statOk && ((info.st_mode & S_IFDIR) != 0);
+            if (fileSize != nullptr)      *fileSize     = statOk ? info.st_size : 0;
+            if (modTime != nullptr)       *modTime      = Time (statOk ? (int64) info.st_mtime * 1000 : 0);
+            if (creationTime != nullptr)  *creationTime = Time (statOk ? (int64) info.st_ctime * 1000 : 0);
+        }
+
+        if (isReadOnly != nullptr)
+            *isReadOnly = access (path.toUTF8(), W_OK) != 0;
+    }
+
+    Result getResultForErrno()
+    {
+        return Result::fail (String (strerror (errno)));
+    }
+
+    Result getResultForReturnValue (int value)
+    {
+        return value == -1 ? getResultForErrno() : Result::ok();
+    }
+
+    int getFD (void* handle) noexcept        { return (int) (pointer_sized_int) handle; }
+    void* fdToVoidPointer (int fd) noexcept  { return (void*) (pointer_sized_int) fd; }
+}
+
+bool File::isDirectory() const
+{
+    juce_statStruct info;
+
+    return fullPath.isEmpty()
+            || (juce_stat (fullPath, info) && ((info.st_mode & S_IFDIR) != 0));
+}
+
+bool File::exists() const
+{
+    return fullPath.isNotEmpty()
+             && access (fullPath.toUTF8(), F_OK) == 0;
+}
+
+bool File::existsAsFile() const
+{
+    return exists() && ! isDirectory();
+}
+
+int64 File::getSize() const
+{
+    juce_statStruct info;
+    return juce_stat (fullPath, info) ? info.st_size : 0;
+}
+
+uint64 File::getFileIdentifier() const
+{
+    juce_statStruct info;
+    return juce_stat (fullPath, info) ? (uint64) info.st_ino : 0;
+}
+
+//==============================================================================
+bool File::hasWriteAccess() const
+{
+    if (exists())
+        return access (fullPath.toUTF8(), W_OK) == 0;
+
+    if ((! isDirectory()) && fullPath.containsChar (separator))
+        return getParentDirectory().hasWriteAccess();
+
+    return false;
+}
+
+bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const
+{
+    juce_statStruct info;
+    if (! juce_stat (fullPath, info))
+        return false;
+
+    info.st_mode &= 0777;   // Just permissions
+
+    if (shouldBeReadOnly)
+        info.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+    else
+        // Give everybody write permission?
+        info.st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
+
+    return chmod (fullPath.toUTF8(), info.st_mode) == 0;
+}
+
+void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int64& creationTime) const
+{
+    modificationTime = 0;
+    accessTime = 0;
+    creationTime = 0;
+
+    juce_statStruct info;
+    if (juce_stat (fullPath, info))
+    {
+        modificationTime = (int64) info.st_mtime * 1000;
+        accessTime = (int64) info.st_atime * 1000;
+        creationTime = (int64) info.st_ctime * 1000;
+    }
+}
+
+bool File::setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 /*creationTime*/) const
+{
+    juce_statStruct info;
+
+    if ((modificationTime != 0 || accessTime != 0) && juce_stat (fullPath, info))
+    {
+        struct utimbuf times;
+        times.actime  = accessTime != 0       ? (time_t) (accessTime / 1000)       : info.st_atime;
+        times.modtime = modificationTime != 0 ? (time_t) (modificationTime / 1000) : info.st_mtime;
+
+        return utime (fullPath.toUTF8(), &times) == 0;
+    }
+
+    return false;
+}
+
+bool File::deleteFile() const
+{
+    if (! exists())
+        return true;
+
+    if (isDirectory())
+        return rmdir (fullPath.toUTF8()) == 0;
+
+    return remove (fullPath.toUTF8()) == 0;
+}
+
+bool File::moveInternal (const File& dest) const
+{
+    if (rename (fullPath.toUTF8(), dest.getFullPathName().toUTF8()) == 0)
+        return true;
+
+    if (hasWriteAccess() && copyInternal (dest))
+    {
+        if (deleteFile())
+            return true;
+
+        dest.deleteFile();
+    }
+
+    return false;
+}
+
+Result File::createDirectoryInternal (const String& fileName) const
+{
+    return getResultForReturnValue (mkdir (fileName.toUTF8(), 0777));
+}
+
+//=====================================================================
+int64 juce_fileSetPosition (void* handle, int64 pos)
+{
+    if (handle != 0 && lseek (getFD (handle), pos, SEEK_SET) == pos)
+        return pos;
+
+    return -1;
+}
+
+void FileInputStream::openHandle()
+{
+    const int f = open (file.getFullPathName().toUTF8(), O_RDONLY, 00644);
+
+    if (f != -1)
+        fileHandle = fdToVoidPointer (f);
+    else
+        status = getResultForErrno();
+}
+
+FileInputStream::~FileInputStream()
+{
+    if (fileHandle != 0)
+        close (getFD (fileHandle));
+}
+
+size_t FileInputStream::readInternal (void* const buffer, const size_t numBytes)
+{
+    ssize_t result = 0;
+
+    if (fileHandle != 0)
+    {
+        result = ::read (getFD (fileHandle), buffer, numBytes);
+
+        if (result < 0)
+        {
+            status = getResultForErrno();
+            result = 0;
+        }
+    }
+
+    return (size_t) result;
+}
+
+//==============================================================================
+void FileOutputStream::openHandle()
+{
+    if (file.exists())
+    {
+        const int f = open (file.getFullPathName().toUTF8(), O_RDWR, 00644);
+
+        if (f != -1)
+        {
+            currentPosition = lseek (f, 0, SEEK_END);
+
+            if (currentPosition >= 0)
+            {
+                fileHandle = fdToVoidPointer (f);
+            }
+            else
+            {
+                status = getResultForErrno();
+                close (f);
+            }
+        }
+        else
+        {
+            status = getResultForErrno();
+        }
+    }
+    else
+    {
+        const int f = open (file.getFullPathName().toUTF8(), O_RDWR + O_CREAT, 00644);
+
+        if (f != -1)
+            fileHandle = fdToVoidPointer (f);
+        else
+            status = getResultForErrno();
+    }
+}
+
+void FileOutputStream::closeHandle()
+{
+    if (fileHandle != 0)
+    {
+        close (getFD (fileHandle));
+        fileHandle = 0;
+    }
+}
+
+ssize_t FileOutputStream::writeInternal (const void* const data, const size_t numBytes)
+{
+    ssize_t result = 0;
+
+    if (fileHandle != 0)
+    {
+        result = ::write (getFD (fileHandle), data, numBytes);
+
+        if (result == -1)
+            status = getResultForErrno();
+    }
+
+    return result;
+}
+
+void FileOutputStream::flushInternal()
+{
+    if (fileHandle != 0)
+    {
+        if (fsync (getFD (fileHandle)) == -1)
+            status = getResultForErrno();
+
+       #if JUCE_ANDROID
+        // This stuff tells the OS to asynchronously update the metadata
+        // that the OS has cached aboud the file - this metadata is used
+        // when the device is acting as a USB drive, and unless it's explicitly
+        // refreshed, it'll get out of step with the real file.
+        const LocalRef<jstring> t (javaString (file.getFullPathName()));
+        android.activity.callVoidMethod (JuceAppActivity.scanFile, t.get());
+       #endif
+    }
+}
+
+Result FileOutputStream::truncate()
+{
+    if (fileHandle == 0)
+        return status;
+
+    flush();
+    return getResultForReturnValue (ftruncate (getFD (fileHandle), (off_t) currentPosition));
+}
+
+//==============================================================================
+String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
+{
+    if (const char* s = ::getenv (name.toUTF8()))
+        return String::fromUTF8 (s);
+
+    return defaultValue;
+}
+
+//==============================================================================
+void MemoryMappedFile::openInternal (const File& file, AccessMode mode)
+{
+    jassert (mode == readOnly || mode == readWrite);
+
+    if (range.getStart() > 0)
+    {
+        const long pageSize = sysconf (_SC_PAGE_SIZE);
+        range.setStart (range.getStart() - (range.getStart() % pageSize));
+    }
+
+    fileHandle = open (file.getFullPathName().toUTF8(),
+                       mode == readWrite ? (O_CREAT + O_RDWR) : O_RDONLY, 00644);
+
+    if (fileHandle != -1)
+    {
+        void* m = mmap (0, (size_t) range.getLength(),
+                        mode == readWrite ? (PROT_READ | PROT_WRITE) : PROT_READ,
+                        MAP_SHARED, fileHandle,
+                        (off_t) range.getStart());
+
+        if (m != MAP_FAILED)
+        {
+            address = m;
+            madvise (m, (size_t) range.getLength(), MADV_SEQUENTIAL);
+        }
+        else
+        {
+            range = Range<int64>();
+        }
+    }
+}
+
+MemoryMappedFile::~MemoryMappedFile()
+{
+    if (address != nullptr)
+        munmap (address, (size_t) range.getLength());
+
+    if (fileHandle != 0)
+        close (fileHandle);
+}
+
+//==============================================================================
+#if JUCE_PROJUCER_LIVE_BUILD
+extern "C" const char* juce_getCurrentExecutablePath();
+#endif
+
+File juce_getExecutableFile();
+File juce_getExecutableFile()
+{
+   #if JUCE_PROJUCER_LIVE_BUILD
+    return File (juce_getCurrentExecutablePath());
+   #elif JUCE_ANDROID
+    return File (android.appFile);
+   #else
+    struct DLAddrReader
+    {
+        static String getFilename()
+        {
+            Dl_info exeInfo;
+            dladdr ((void*) juce_getExecutableFile, &exeInfo);
+            return CharPointer_UTF8 (exeInfo.dli_fname);
+        }
+    };
+
+    static String filename (DLAddrReader::getFilename());
+    return File::getCurrentWorkingDirectory().getChildFile (filename);
+   #endif
+}
+
+//==============================================================================
+int64 File::getBytesFreeOnVolume() const
+{
+    struct statfs buf;
+    if (juce_doStatFS (*this, buf))
+        return (int64) buf.f_bsize * (int64) buf.f_bavail; // Note: this returns space available to non-super user
+
+    return 0;
+}
+
+int64 File::getVolumeTotalSize() const
+{
+    struct statfs buf;
+    if (juce_doStatFS (*this, buf))
+        return (int64) buf.f_bsize * (int64) buf.f_blocks;
+
+    return 0;
+}
+
+String File::getVolumeLabel() const
+{
+   #if JUCE_MAC
+    struct VolAttrBuf
+    {
+        u_int32_t       length;
+        attrreference_t mountPointRef;
+        char            mountPointSpace [MAXPATHLEN];
+    } attrBuf;
+
+    struct attrlist attrList;
+    zerostruct (attrList); // (can't use "= { 0 }" on this object because it's typedef'ed as a C struct)
+    attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
+    attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME;
+
+    File f (*this);
+
+    for (;;)
+    {
+        if (getattrlist (f.getFullPathName().toUTF8(), &attrList, &attrBuf, sizeof (attrBuf), 0) == 0)
+            return String::fromUTF8 (((const char*) &attrBuf.mountPointRef) + attrBuf.mountPointRef.attr_dataoffset,
+                                     (int) attrBuf.mountPointRef.attr_length);
+
+        const File parent (f.getParentDirectory());
+
+        if (f == parent)
+            break;
+
+        f = parent;
+    }
+   #endif
+
+    return String();
+}
+
+int File::getVolumeSerialNumber() const
+{
+    int result = 0;
+/*    int fd = open (getFullPathName().toUTF8(), O_RDONLY | O_NONBLOCK);
+
+    char info [512];
+
+    #ifndef HDIO_GET_IDENTITY
+     #define HDIO_GET_IDENTITY 0x030d
+    #endif
+
+    if (ioctl (fd, HDIO_GET_IDENTITY, info) == 0)
+    {
+        DBG (String (info + 20, 20));
+        result = String (info + 20, 20).trim().getIntValue();
+    }
+
+    close (fd);*/
+    return result;
+}
+
+//==============================================================================
+void juce_runSystemCommand (const String&);
+void juce_runSystemCommand (const String& command)
+{
+    int result = system (command.toUTF8());
+    (void) result;
+}
+
+String juce_getOutputFromCommand (const String&);
+String juce_getOutputFromCommand (const String& command)
+{
+    // slight bodge here, as we just pipe the output into a temp file and read it...
+    const File tempFile (File::getSpecialLocation (File::tempDirectory)
+                           .getNonexistentChildFile (String::toHexString (Random::getSystemRandom().nextInt()), ".tmp", false));
+
+    juce_runSystemCommand (command + " > " + tempFile.getFullPathName());
+
+    String result (tempFile.loadFileAsString());
+    tempFile.deleteFile();
+    return result;
+}
+
+
+//==============================================================================
+#if JUCE_IOS
+class InterProcessLock::Pimpl
+{
+public:
+    Pimpl (const String&, int)
+        : handle (1), refCount (1) // On iOS just fake success..
+    {
+    }
+
+    int handle, refCount;
+};
+
+#else
+
+class InterProcessLock::Pimpl
+{
+public:
+    Pimpl (const String& lockName, const int timeOutMillisecs)
+        : handle (0), refCount (1)
+    {
+       #if JUCE_MAC
+        if (! createLockFile (File ("~/Library/Caches/com.juce.locks").getChildFile (lockName), timeOutMillisecs))
+            // Fallback if the user's home folder is on a network drive with no ability to lock..
+            createLockFile (File ("/tmp/com.juce.locks").getChildFile (lockName), timeOutMillisecs);
+
+       #else
+        File tempFolder ("/var/tmp");
+        if (! tempFolder.isDirectory())
+            tempFolder = "/tmp";
+
+        createLockFile (tempFolder.getChildFile (lockName), timeOutMillisecs);
+       #endif
+    }
+
+    ~Pimpl()
+    {
+        closeFile();
+    }
+
+    bool createLockFile (const File& file, const int timeOutMillisecs)
+    {
+        file.create();
+        handle = open (file.getFullPathName().toUTF8(), O_RDWR);
+
+        if (handle != 0)
+        {
+            struct flock fl;
+            zerostruct (fl);
+
+            fl.l_whence = SEEK_SET;
+            fl.l_type = F_WRLCK;
+
+            const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
+
+            for (;;)
+            {
+                const int result = fcntl (handle, F_SETLK, &fl);
+
+                if (result >= 0)
+                    return true;
+
+                const int error = errno;
+
+                if (error != EINTR)
+                {
+                    if (error == EBADF || error == ENOTSUP)
+                        return false;
+
+                    if (timeOutMillisecs == 0
+                         || (timeOutMillisecs > 0 && Time::currentTimeMillis() >= endTime))
+                        break;
+
+                    Thread::sleep (10);
+                }
+            }
+        }
+
+        closeFile();
+        return true; // only false if there's a file system error. Failure to lock still returns true.
+    }
+
+    void closeFile()
+    {
+        if (handle != 0)
+        {
+            struct flock fl;
+            zerostruct (fl);
+
+            fl.l_whence = SEEK_SET;
+            fl.l_type = F_UNLCK;
+
+            while (! (fcntl (handle, F_SETLKW, &fl) >= 0 || errno != EINTR))
+            {}
+
+            close (handle);
+            handle = 0;
+        }
+    }
+
+    int handle, refCount;
+};
+#endif
+
+InterProcessLock::InterProcessLock (const String& nm)  : name (nm)
+{
+}
+
+InterProcessLock::~InterProcessLock()
+{
+}
+
+bool InterProcessLock::enter (const int timeOutMillisecs)
+{
+    const ScopedLock sl (lock);
+
+    if (pimpl == nullptr)
+    {
+        pimpl = new Pimpl (name, timeOutMillisecs);
+
+        if (pimpl->handle == 0)
+            pimpl = nullptr;
+    }
+    else
+    {
+        pimpl->refCount++;
+    }
+
+    return pimpl != nullptr;
+}
+
+void InterProcessLock::exit()
+{
+    const ScopedLock sl (lock);
+
+    // Trying to release the lock too many times!
+    jassert (pimpl != nullptr);
+
+    if (pimpl != nullptr && --(pimpl->refCount) == 0)
+        pimpl = nullptr;
+}
+
+//==============================================================================
+void JUCE_API juce_threadEntryPoint (void*);
+
+extern "C" void* threadEntryProc (void*);
+extern "C" void* threadEntryProc (void* userData)
+{
+    JUCE_AUTORELEASEPOOL
+    {
+       #if JUCE_ANDROID
+        const AndroidThreadScope androidEnv;
+       #endif
+
+        juce_threadEntryPoint (userData);
+    }
+
+    return nullptr;
+}
+
+void Thread::launchThread()
+{
+    threadHandle = 0;
+    pthread_t handle = 0;
+
+    if (pthread_create (&handle, 0, threadEntryProc, this) == 0)
+    {
+        pthread_detach (handle);
+        threadHandle = (void*) handle;
+        threadId = (ThreadID) threadHandle;
+    }
+}
+
+void Thread::closeThreadHandle()
+{
+    threadId = 0;
+    threadHandle = 0;
+}
+
+void Thread::killThread()
+{
+    if (threadHandle != 0)
+    {
+       #if JUCE_ANDROID
+        jassertfalse; // pthread_cancel not available!
+       #else
+        pthread_cancel ((pthread_t) threadHandle);
+       #endif
+    }
+}
+
+void JUCE_CALLTYPE Thread::setCurrentThreadName (const String& name)
+{
+   #if JUCE_IOS || (JUCE_MAC && defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+    JUCE_AUTORELEASEPOOL
+    {
+        [[NSThread currentThread] setName: juceStringToNS (name)];
+    }
+   #elif JUCE_LINUX
+    #if (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012
+     pthread_setname_np (pthread_self(), name.toRawUTF8());
+    #else
+     prctl (PR_SET_NAME, name.toRawUTF8(), 0, 0, 0);
+    #endif
+   #endif
+}
+
+bool Thread::setThreadPriority (void* handle, int priority)
+{
+    struct sched_param param;
+    int policy;
+    priority = jlimit (0, 10, priority);
+
+    if (handle == nullptr)
+        handle = (void*) pthread_self();
+
+    if (pthread_getschedparam ((pthread_t) handle, &policy, &param) != 0)
+        return false;
+
+    policy = priority == 0 ? SCHED_OTHER : SCHED_RR;
+
+    const int minPriority = sched_get_priority_min (policy);
+    const int maxPriority = sched_get_priority_max (policy);
+
+    param.sched_priority = ((maxPriority - minPriority) * priority) / 10 + minPriority;
+    return pthread_setschedparam ((pthread_t) handle, policy, &param) == 0;
+}
+
+Thread::ThreadID JUCE_CALLTYPE Thread::getCurrentThreadId()
+{
+    return (ThreadID) pthread_self();
+}
+
+void JUCE_CALLTYPE Thread::yield()
+{
+    sched_yield();
+}
+
+//==============================================================================
+/* Remove this macro if you're having problems compiling the cpu affinity
+   calls (the API for these has changed about quite a bit in various Linux
+   versions, and a lot of distros seem to ship with obsolete versions)
+*/
+#if defined (CPU_ISSET) && ! defined (SUPPORT_AFFINITIES)
+ #define SUPPORT_AFFINITIES 1
+#endif
+
+void JUCE_CALLTYPE Thread::setCurrentThreadAffinityMask (const uint32 affinityMask)
+{
+   #if SUPPORT_AFFINITIES
+    cpu_set_t affinity;
+    CPU_ZERO (&affinity);
+
+    for (int i = 0; i < 32; ++i)
+        if ((affinityMask & (1 << i)) != 0)
+            CPU_SET (i, &affinity);
+
+    /*
+       N.B. If this line causes a compile error, then you've probably not got the latest
+       version of glibc installed.
+
+       If you don't want to update your copy of glibc and don't care about cpu affinities,
+       then you can just disable all this stuff by setting the SUPPORT_AFFINITIES macro to 0.
+    */
+    sched_setaffinity (getpid(), sizeof (cpu_set_t), &affinity);
+    sched_yield();
+
+   #else
+    /* affinities aren't supported because either the appropriate header files weren't found,
+       or the SUPPORT_AFFINITIES macro was turned off
+    */
+    jassertfalse;
+    (void) affinityMask;
+   #endif
+}
+
+//==============================================================================
+bool DynamicLibrary::open (const String& name)
+{
+    close();
+    handle = dlopen (name.isEmpty() ? nullptr : name.toUTF8().getAddress(), RTLD_LOCAL | RTLD_NOW);
+    return handle != nullptr;
+}
+
+void DynamicLibrary::close()
+{
+    if (handle != nullptr)
+    {
+        dlclose (handle);
+        handle = nullptr;
+    }
+}
+
+void* DynamicLibrary::getFunction (const String& functionName) noexcept
+{
+    return handle != nullptr ? dlsym (handle, functionName.toUTF8()) : nullptr;
+}
+
+
+
+//==============================================================================
+class ChildProcess::ActiveProcess
+{
+public:
+    ActiveProcess (const StringArray& arguments, int streamFlags)
+        : childPID (0), pipeHandle (0), readHandle (0)
+    {
+        // Looks like you're trying to launch a non-existent exe or a folder (perhaps on OSX
+        // you're trying to launch the .app folder rather than the actual binary inside it?)
+        jassert ((! arguments[0].containsChar ('/'))
+                  || File::getCurrentWorkingDirectory().getChildFile (arguments[0]).existsAsFile());
+
+        int pipeHandles[2] = { 0 };
+
+        if (pipe (pipeHandles) == 0)
+        {
+            const pid_t result = fork();
+
+            if (result < 0)
+            {
+                close (pipeHandles[0]);
+                close (pipeHandles[1]);
+            }
+            else if (result == 0)
+            {
+                // we're the child process..
+                close (pipeHandles[0]);   // close the read handle
+
+                if ((streamFlags & wantStdOut) != 0)
+                    dup2 (pipeHandles[1], 1); // turns the pipe into stdout
+                else
+                    close (STDOUT_FILENO);
+
+                if ((streamFlags & wantStdErr) != 0)
+                    dup2 (pipeHandles[1], 2);
+                else
+                    close (STDERR_FILENO);
+
+                close (pipeHandles[1]);
+
+                Array<char*> argv;
+                for (int i = 0; i < arguments.size(); ++i)
+                    if (arguments[i].isNotEmpty())
+                        argv.add (const_cast<char*> (arguments[i].toUTF8().getAddress()));
+
+                argv.add (nullptr);
+
+                execvp (argv[0], argv.getRawDataPointer());
+                exit (-1);
+            }
+            else
+            {
+                // we're the parent process..
+                childPID = result;
+                pipeHandle = pipeHandles[0];
+                close (pipeHandles[1]); // close the write handle
+            }
+        }
+    }
+
+    ~ActiveProcess()
+    {
+        if (readHandle != 0)
+            fclose (readHandle);
+
+        if (pipeHandle != 0)
+            close (pipeHandle);
+    }
+
+    bool isRunning() const noexcept
+    {
+        if (childPID != 0)
+        {
+            int childState;
+            const int pid = waitpid (childPID, &childState, WNOHANG);
+            return pid == 0 || ! (WIFEXITED (childState) || WIFSIGNALED (childState));
+        }
+
+        return false;
+    }
+
+    int read (void* const dest, const int numBytes) noexcept
+    {
+        jassert (dest != nullptr);
+
+        #ifdef fdopen
+         #error // the zlib headers define this function as NULL!
+        #endif
+
+        if (readHandle == 0 && childPID != 0)
+            readHandle = fdopen (pipeHandle, "r");
+
+        if (readHandle != 0)
+            return (int) fread (dest, 1, (size_t) numBytes, readHandle);
+
+        return 0;
+    }
+
+    bool killProcess() const noexcept
+    {
+        return ::kill (childPID, SIGKILL) == 0;
+    }
+
+    uint32 getExitCode() const noexcept
+    {
+        if (childPID != 0)
+        {
+            int childState = 0;
+            const int pid = waitpid (childPID, &childState, WNOHANG);
+
+            if (pid >= 0 && WIFEXITED (childState))
+                return WEXITSTATUS (childState);
+        }
+
+        return 0;
+    }
+
+    int childPID;
+
+private:
+    int pipeHandle;
+    FILE* readHandle;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ActiveProcess)
+};
+
+bool ChildProcess::start (const String& command, int streamFlags)
+{
+    return start (StringArray::fromTokens (command, true), streamFlags);
+}
+
+bool ChildProcess::start (const StringArray& args, int streamFlags)
+{
+    if (args.size() == 0)
+        return false;
+
+    activeProcess = new ActiveProcess (args, streamFlags);
+
+    if (activeProcess->childPID == 0)
+        activeProcess = nullptr;
+
+    return activeProcess != nullptr;
+}
+
+//==============================================================================
+struct HighResolutionTimer::Pimpl
+{
+    Pimpl (HighResolutionTimer& t)  : owner (t), thread (0), shouldStop (false)
+    {
+    }
+
+    ~Pimpl()
+    {
+        jassert (thread == 0);
+    }
+
+    void start (int newPeriod)
+    {
+        if (periodMs != newPeriod)
+        {
+            if (thread != pthread_self())
+            {
+                stop();
+
+                periodMs = newPeriod;
+                shouldStop = false;
+
+                if (pthread_create (&thread, nullptr, timerThread, this) == 0)
+                    setThreadToRealtime (thread, (uint64) newPeriod);
+                else
+                    jassertfalse;
+            }
+            else
+            {
+                periodMs = newPeriod;
+                shouldStop = false;
+            }
+        }
+    }
+
+    void stop()
+    {
+        if (thread != 0)
+        {
+            shouldStop = true;
+
+            while (thread != 0 && thread != pthread_self())
+                Thread::yield();
+        }
+    }
+
+    HighResolutionTimer& owner;
+    int volatile periodMs;
+
+private:
+    pthread_t thread;
+    bool volatile shouldStop;
+
+    static void* timerThread (void* param)
+    {
+       #if JUCE_ANDROID
+        const AndroidThreadScope androidEnv;
+       #else
+        int dummy;
+        pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &dummy);
+       #endif
+
+        reinterpret_cast<Pimpl*> (param)->timerThread();
+        return nullptr;
+    }
+
+    void timerThread()
+    {
+        int lastPeriod = periodMs;
+        Clock clock (lastPeriod);
+
+        while (! shouldStop)
+        {
+            clock.wait();
+            owner.hiResTimerCallback();
+
+            if (lastPeriod != periodMs)
+            {
+                lastPeriod = periodMs;
+                clock = Clock (lastPeriod);
+            }
+        }
+
+        periodMs = 0;
+        thread = 0;
+    }
+
+    struct Clock
+    {
+       #if JUCE_MAC || JUCE_IOS
+        Clock (double millis) noexcept
+        {
+            mach_timebase_info_data_t timebase;
+            (void) mach_timebase_info (&timebase);
+            delta = (((uint64_t) (millis * 1000000.0)) * timebase.denom) / timebase.numer;
+            time = mach_absolute_time();
+        }
+
+        void wait() noexcept
+        {
+            time += delta;
+            mach_wait_until (time);
+        }
+
+        uint64_t time, delta;
+
+       #elif JUCE_ANDROID
+        Clock (double millis) noexcept  : delta ((uint64) (millis * 1000000))
+        {
+        }
+
+        void wait() noexcept
+        {
+            struct timespec t;
+            t.tv_sec  = (time_t) (delta / 1000000000);
+            t.tv_nsec = (long)   (delta % 1000000000);
+            nanosleep (&t, nullptr);
+        }
+
+        uint64 delta;
+       #else
+        Clock (double millis) noexcept  : delta ((uint64) (millis * 1000000))
+        {
+            struct timespec t;
+            clock_gettime (CLOCK_MONOTONIC, &t);
+            time = 1000000000 * (int64) t.tv_sec + t.tv_nsec;
+        }
+
+        void wait() noexcept
+        {
+            time += delta;
+
+            struct timespec t;
+            t.tv_sec  = (time_t) (time / 1000000000);
+            t.tv_nsec = (long)   (time % 1000000000);
+
+            clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &t, nullptr);
+        }
+
+        uint64 time, delta;
+       #endif
+    };
+
+    static bool setThreadToRealtime (pthread_t thread, uint64 periodMs)
+    {
+       #if JUCE_MAC || JUCE_IOS
+        thread_time_constraint_policy_data_t policy;
+        policy.period      = (uint32_t) (periodMs * 1000000);
+        policy.computation = 50000;
+        policy.constraint  = policy.period;
+        policy.preemptible = true;
+
+        return thread_policy_set (pthread_mach_thread_np (thread),
+                                  THREAD_TIME_CONSTRAINT_POLICY,
+                                  (thread_policy_t) &policy,
+                                  THREAD_TIME_CONSTRAINT_POLICY_COUNT) == KERN_SUCCESS;
+
+       #else
+        (void) periodMs;
+        struct sched_param param;
+        param.sched_priority = sched_get_priority_max (SCHED_RR);
+        return pthread_setschedparam (thread, SCHED_RR, &param) == 0;
+
+       #endif
+    }
+
+    JUCE_DECLARE_NON_COPYABLE (Pimpl)
+};
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_ComSmartPtr.h b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_ComSmartPtr.h
new file mode 100644
index 0000000..0dc0efc
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_ComSmartPtr.h
@@ -0,0 +1,170 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_WIN32_COMSMARTPTR_H_INCLUDED
+#define JUCE_WIN32_COMSMARTPTR_H_INCLUDED
+
+#if ! (defined (_MSC_VER) || defined (__uuidof))
+template<typename Type> struct UUIDGetter { static CLSID get() { jassertfalse; return CLSID(); } };
+#define __uuidof(x)  UUIDGetter<x>::get()
+#endif
+
+inline GUID uuidFromString (const char* const s) noexcept
+{
+    unsigned long p0;
+    unsigned int p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
+
+  #ifndef _MSC_VER
+    sscanf
+  #else
+    sscanf_s
+  #endif
+        (s, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+              &p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);
+
+    GUID g = { p0, (uint16) p1, (uint16) p2, { (uint8) p3, (uint8) p4, (uint8) p5, (uint8) p6,
+                                               (uint8) p7, (uint8) p8, (uint8) p9, (uint8) p10 }};
+    return g;
+}
+
+//==============================================================================
+/** A simple COM smart pointer.
+*/
+template <class ComClass>
+class ComSmartPtr
+{
+public:
+    ComSmartPtr() throw() : p (0)                                  {}
+    ComSmartPtr (ComClass* const obj) : p (obj)                    { if (p) p->AddRef(); }
+    ComSmartPtr (const ComSmartPtr<ComClass>& other) : p (other.p) { if (p) p->AddRef(); }
+    ~ComSmartPtr()                                                 { release(); }
+
+    operator ComClass*() const throw()     { return p; }
+    ComClass& operator*() const throw()    { return *p; }
+    ComClass* operator->() const throw()   { return p; }
+
+    ComSmartPtr& operator= (ComClass* const newP)
+    {
+        if (newP != 0)  newP->AddRef();
+        release();
+        p = newP;
+        return *this;
+    }
+
+    ComSmartPtr& operator= (const ComSmartPtr<ComClass>& newP)  { return operator= (newP.p); }
+
+    // Releases and nullifies this pointer and returns its address
+    ComClass** resetAndGetPointerAddress()
+    {
+        release();
+        p = 0;
+        return &p;
+    }
+
+    HRESULT CoCreateInstance (REFCLSID classUUID, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
+    {
+        HRESULT hr = ::CoCreateInstance (classUUID, 0, dwClsContext, __uuidof (ComClass), (void**) resetAndGetPointerAddress());
+        jassert (hr != CO_E_NOTINITIALIZED); // You haven't called CoInitialize for the current thread!
+        return hr;
+    }
+
+    template <class OtherComClass>
+    HRESULT QueryInterface (REFCLSID classUUID, ComSmartPtr<OtherComClass>& destObject) const
+    {
+        if (p == 0)
+            return E_POINTER;
+
+        return p->QueryInterface (classUUID, (void**) destObject.resetAndGetPointerAddress());
+    }
+
+    template <class OtherComClass>
+    HRESULT QueryInterface (ComSmartPtr<OtherComClass>& destObject) const
+    {
+        return this->QueryInterface (__uuidof (OtherComClass), destObject);
+    }
+
+private:
+    ComClass* p;
+
+    void release()  { if (p != 0) p->Release(); }
+
+    ComClass** operator&() throw(); // private to avoid it being used accidentally
+};
+
+//==============================================================================
+#define JUCE_COMRESULT  HRESULT __stdcall
+
+//==============================================================================
+template <class ComClass>
+class ComBaseClassHelperBase   : public ComClass
+{
+public:
+    ComBaseClassHelperBase (unsigned int initialRefCount)  : refCount (initialRefCount) {}
+    virtual ~ComBaseClassHelperBase() {}
+
+    ULONG __stdcall AddRef()    { return ++refCount; }
+    ULONG __stdcall Release()   { const ULONG r = --refCount; if (r == 0) delete this; return r; }
+
+protected:
+    ULONG refCount;
+
+    JUCE_COMRESULT QueryInterface (REFIID refId, void** result)
+    {
+        if (refId == IID_IUnknown)
+            return castToType <IUnknown> (result);
+
+        *result = 0;
+        return E_NOINTERFACE;
+    }
+
+    template <class Type>
+    JUCE_COMRESULT castToType (void** result)
+    {
+        this->AddRef(); *result = dynamic_cast <Type*> (this); return S_OK;
+    }
+};
+
+/** Handy base class for writing COM objects, providing ref-counting and a basic QueryInterface method.
+*/
+template <class ComClass>
+class ComBaseClassHelper   : public ComBaseClassHelperBase <ComClass>
+{
+public:
+    ComBaseClassHelper (unsigned int initialRefCount = 1) : ComBaseClassHelperBase <ComClass> (initialRefCount) {}
+    ~ComBaseClassHelper() {}
+
+    JUCE_COMRESULT QueryInterface (REFIID refId, void** result)
+    {
+        if (refId == __uuidof (ComClass))
+            return this->template castToType <ComClass> (result);
+
+        return ComBaseClassHelperBase <ComClass>::QueryInterface (refId, result);
+    }
+};
+
+#endif   // JUCE_WIN32_COMSMARTPTR_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Files.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Files.cpp
new file mode 100644
index 0000000..a77aa5a
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Files.cpp
@@ -0,0 +1,999 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef INVALID_FILE_ATTRIBUTES
+ #define INVALID_FILE_ATTRIBUTES ((DWORD) -1)
+#endif
+
+//==============================================================================
+namespace WindowsFileHelpers
+{
+    DWORD getAtts (const String& path)
+    {
+        return GetFileAttributes (path.toWideCharPointer());
+    }
+
+    int64 fileTimeToTime (const FILETIME* const ft)
+    {
+        static_jassert (sizeof (ULARGE_INTEGER) == sizeof (FILETIME)); // tell me if this fails!
+
+        return (int64) ((reinterpret_cast<const ULARGE_INTEGER*> (ft)->QuadPart - 116444736000000000LL) / 10000);
+    }
+
+    FILETIME* timeToFileTime (const int64 time, FILETIME* const ft) noexcept
+    {
+        if (time <= 0)
+            return nullptr;
+
+        reinterpret_cast<ULARGE_INTEGER*> (ft)->QuadPart = (ULONGLONG) (time * 10000 + 116444736000000000LL);
+        return ft;
+    }
+
+    String getDriveFromPath (String path)
+    {
+        if (path.isNotEmpty() && path[1] == ':' && path[2] == 0)
+            path << '\\';
+
+        const size_t numBytes = CharPointer_UTF16::getBytesRequiredFor (path.getCharPointer()) + 4;
+        HeapBlock<WCHAR> pathCopy;
+        pathCopy.calloc (numBytes, 1);
+        path.copyToUTF16 (pathCopy, numBytes);
+
+        if (PathStripToRoot (pathCopy))
+            path = static_cast <const WCHAR*> (pathCopy);
+
+        return path;
+    }
+
+    int64 getDiskSpaceInfo (const String& path, const bool total)
+    {
+        ULARGE_INTEGER spc, tot, totFree;
+
+        if (GetDiskFreeSpaceEx (getDriveFromPath (path).toWideCharPointer(), &spc, &tot, &totFree))
+            return total ? (int64) tot.QuadPart
+                         : (int64) spc.QuadPart;
+
+        return 0;
+    }
+
+    unsigned int getWindowsDriveType (const String& path)
+    {
+        return GetDriveType (getDriveFromPath (path).toWideCharPointer());
+    }
+
+    File getSpecialFolderPath (int type)
+    {
+        WCHAR path [MAX_PATH + 256];
+
+        if (SHGetSpecialFolderPath (0, path, type, FALSE))
+            return File (String (path));
+
+        return File();
+    }
+
+    File getModuleFileName (HINSTANCE moduleHandle)
+    {
+        WCHAR dest [MAX_PATH + 256];
+        dest[0] = 0;
+        GetModuleFileName (moduleHandle, dest, (DWORD) numElementsInArray (dest));
+        return File (String (dest));
+    }
+
+    Result getResultForLastError()
+    {
+        TCHAR messageBuffer [256] = { 0 };
+
+        FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                       nullptr, GetLastError(), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+                       messageBuffer, (DWORD) numElementsInArray (messageBuffer) - 1, nullptr);
+
+        return Result::fail (String (messageBuffer));
+    }
+}
+
+//==============================================================================
+const juce_wchar File::separator = '\\';
+const String File::separatorString ("\\");
+
+
+//==============================================================================
+bool File::exists() const
+{
+    return fullPath.isNotEmpty()
+            && WindowsFileHelpers::getAtts (fullPath) != INVALID_FILE_ATTRIBUTES;
+}
+
+bool File::existsAsFile() const
+{
+    return fullPath.isNotEmpty()
+            && (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_DIRECTORY) == 0;
+}
+
+bool File::isDirectory() const
+{
+    const DWORD attr = WindowsFileHelpers::getAtts (fullPath);
+    return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) && (attr != INVALID_FILE_ATTRIBUTES);
+}
+
+bool File::hasWriteAccess() const
+{
+    if (exists())
+        return (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_READONLY) == 0;
+
+    // on windows, it seems that even read-only directories can still be written into,
+    // so checking the parent directory's permissions would return the wrong result..
+    return true;
+}
+
+bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const
+{
+    const DWORD oldAtts = WindowsFileHelpers::getAtts (fullPath);
+
+    if (oldAtts == INVALID_FILE_ATTRIBUTES)
+        return false;
+
+    const DWORD newAtts = shouldBeReadOnly ? (oldAtts |  FILE_ATTRIBUTE_READONLY)
+                                           : (oldAtts & ~FILE_ATTRIBUTE_READONLY);
+    return newAtts == oldAtts
+            || SetFileAttributes (fullPath.toWideCharPointer(), newAtts) != FALSE;
+}
+
+bool File::isHidden() const
+{
+    return (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_HIDDEN) != 0;
+}
+
+//==============================================================================
+bool File::deleteFile() const
+{
+    if (! exists())
+        return true;
+
+    return isDirectory() ? RemoveDirectory (fullPath.toWideCharPointer()) != 0
+                         : DeleteFile (fullPath.toWideCharPointer()) != 0;
+}
+
+bool File::moveToTrash() const
+{
+    if (! exists())
+        return true;
+
+    // The string we pass in must be double null terminated..
+    const size_t numBytes = CharPointer_UTF16::getBytesRequiredFor (fullPath.getCharPointer()) + 8;
+    HeapBlock<WCHAR> doubleNullTermPath;
+    doubleNullTermPath.calloc (numBytes, 1);
+    fullPath.copyToUTF16 (doubleNullTermPath, numBytes);
+
+    SHFILEOPSTRUCT fos = { 0 };
+    fos.wFunc = FO_DELETE;
+    fos.pFrom = doubleNullTermPath;
+    fos.fFlags = FOF_ALLOWUNDO | FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION
+                   | FOF_NOCONFIRMMKDIR | FOF_RENAMEONCOLLISION;
+
+    return SHFileOperation (&fos) == 0;
+}
+
+bool File::copyInternal (const File& dest) const
+{
+    return CopyFile (fullPath.toWideCharPointer(), dest.getFullPathName().toWideCharPointer(), false) != 0;
+}
+
+bool File::moveInternal (const File& dest) const
+{
+    return MoveFile (fullPath.toWideCharPointer(), dest.getFullPathName().toWideCharPointer()) != 0;
+}
+
+Result File::createDirectoryInternal (const String& fileName) const
+{
+    return CreateDirectory (fileName.toWideCharPointer(), 0) ? Result::ok()
+                                                             : WindowsFileHelpers::getResultForLastError();
+}
+
+//==============================================================================
+int64 juce_fileSetPosition (void* handle, int64 pos)
+{
+    LARGE_INTEGER li;
+    li.QuadPart = pos;
+    li.LowPart = SetFilePointer ((HANDLE) handle, (LONG) li.LowPart, &li.HighPart, FILE_BEGIN);  // (returns -1 if it fails)
+    return li.QuadPart;
+}
+
+void FileInputStream::openHandle()
+{
+    HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
+                           OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
+
+    if (h != INVALID_HANDLE_VALUE)
+        fileHandle = (void*) h;
+    else
+        status = WindowsFileHelpers::getResultForLastError();
+}
+
+FileInputStream::~FileInputStream()
+{
+    CloseHandle ((HANDLE) fileHandle);
+}
+
+size_t FileInputStream::readInternal (void* buffer, size_t numBytes)
+{
+    if (fileHandle != 0)
+    {
+        DWORD actualNum = 0;
+        if (! ReadFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0))
+            status = WindowsFileHelpers::getResultForLastError();
+
+        return (size_t) actualNum;
+    }
+
+    return 0;
+}
+
+//==============================================================================
+void FileOutputStream::openHandle()
+{
+    HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), GENERIC_WRITE, FILE_SHARE_READ, 0,
+                           OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+
+    if (h != INVALID_HANDLE_VALUE)
+    {
+        LARGE_INTEGER li;
+        li.QuadPart = 0;
+        li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_END);
+
+        if (li.LowPart != INVALID_SET_FILE_POINTER)
+        {
+            fileHandle = (void*) h;
+            currentPosition = li.QuadPart;
+            return;
+        }
+    }
+
+    status = WindowsFileHelpers::getResultForLastError();
+}
+
+void FileOutputStream::closeHandle()
+{
+    CloseHandle ((HANDLE) fileHandle);
+}
+
+ssize_t FileOutputStream::writeInternal (const void* buffer, size_t numBytes)
+{
+    if (fileHandle != nullptr)
+    {
+        DWORD actualNum = 0;
+        if (! WriteFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0))
+            status = WindowsFileHelpers::getResultForLastError();
+
+        return (ssize_t) actualNum;
+    }
+
+    return 0;
+}
+
+void FileOutputStream::flushInternal()
+{
+    if (fileHandle != nullptr)
+        if (! FlushFileBuffers ((HANDLE) fileHandle))
+            status = WindowsFileHelpers::getResultForLastError();
+}
+
+Result FileOutputStream::truncate()
+{
+    if (fileHandle == nullptr)
+        return status;
+
+    flush();
+    return SetEndOfFile ((HANDLE) fileHandle) ? Result::ok()
+                                              : WindowsFileHelpers::getResultForLastError();
+}
+
+//==============================================================================
+void MemoryMappedFile::openInternal (const File& file, AccessMode mode)
+{
+    jassert (mode == readOnly || mode == readWrite);
+
+    if (range.getStart() > 0)
+    {
+        SYSTEM_INFO systemInfo;
+        GetNativeSystemInfo (&systemInfo);
+
+        range.setStart (range.getStart() - (range.getStart() % systemInfo.dwAllocationGranularity));
+    }
+
+    DWORD accessMode = GENERIC_READ, createType = OPEN_EXISTING;
+    DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
+
+    if (mode == readWrite)
+    {
+        accessMode = GENERIC_READ | GENERIC_WRITE;
+        createType = OPEN_ALWAYS;
+        protect = PAGE_READWRITE;
+        access = FILE_MAP_ALL_ACCESS;
+    }
+
+    HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), accessMode, FILE_SHARE_READ, 0,
+                           createType, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
+
+    if (h != INVALID_HANDLE_VALUE)
+    {
+        fileHandle = (void*) h;
+
+        HANDLE mappingHandle = CreateFileMapping (h, 0, protect, (DWORD) (range.getEnd() >> 32), (DWORD) range.getEnd(), 0);
+
+        if (mappingHandle != 0)
+        {
+            address = MapViewOfFile (mappingHandle, access, (DWORD) (range.getStart() >> 32),
+                                     (DWORD) range.getStart(), (SIZE_T) range.getLength());
+
+            if (address == nullptr)
+                range = Range<int64>();
+
+            CloseHandle (mappingHandle);
+        }
+    }
+}
+
+MemoryMappedFile::~MemoryMappedFile()
+{
+    if (address != nullptr)
+        UnmapViewOfFile (address);
+
+    if (fileHandle != nullptr)
+        CloseHandle ((HANDLE) fileHandle);
+}
+
+//==============================================================================
+int64 File::getSize() const
+{
+    WIN32_FILE_ATTRIBUTE_DATA attributes;
+
+    if (GetFileAttributesEx (fullPath.toWideCharPointer(), GetFileExInfoStandard, &attributes))
+        return (((int64) attributes.nFileSizeHigh) << 32) | attributes.nFileSizeLow;
+
+    return 0;
+}
+
+void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int64& creationTime) const
+{
+    using namespace WindowsFileHelpers;
+    WIN32_FILE_ATTRIBUTE_DATA attributes;
+
+    if (GetFileAttributesEx (fullPath.toWideCharPointer(), GetFileExInfoStandard, &attributes))
+    {
+        modificationTime = fileTimeToTime (&attributes.ftLastWriteTime);
+        creationTime     = fileTimeToTime (&attributes.ftCreationTime);
+        accessTime       = fileTimeToTime (&attributes.ftLastAccessTime);
+    }
+    else
+    {
+        creationTime = accessTime = modificationTime = 0;
+    }
+}
+
+bool File::setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 creationTime) const
+{
+    using namespace WindowsFileHelpers;
+
+    bool ok = false;
+    HANDLE h = CreateFile (fullPath.toWideCharPointer(), GENERIC_WRITE, FILE_SHARE_READ, 0,
+                           OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+
+    if (h != INVALID_HANDLE_VALUE)
+    {
+        FILETIME m, a, c;
+
+        ok = SetFileTime (h,
+                          timeToFileTime (creationTime, &c),
+                          timeToFileTime (accessTime, &a),
+                          timeToFileTime (modificationTime, &m)) != 0;
+
+        CloseHandle (h);
+    }
+
+    return ok;
+}
+
+//==============================================================================
+void File::findFileSystemRoots (Array<File>& destArray)
+{
+    TCHAR buffer [2048] = { 0 };
+    GetLogicalDriveStrings (2048, buffer);
+
+    const TCHAR* n = buffer;
+    StringArray roots;
+
+    while (*n != 0)
+    {
+        roots.add (String (n));
+
+        while (*n++ != 0)
+        {}
+    }
+
+    roots.sort (true);
+
+    for (int i = 0; i < roots.size(); ++i)
+        destArray.add (roots [i]);
+}
+
+//==============================================================================
+String File::getVolumeLabel() const
+{
+    TCHAR dest[64];
+    if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toWideCharPointer(), dest,
+                                (DWORD) numElementsInArray (dest), 0, 0, 0, 0, 0))
+        dest[0] = 0;
+
+    return dest;
+}
+
+int File::getVolumeSerialNumber() const
+{
+    TCHAR dest[64];
+    DWORD serialNum;
+
+    if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toWideCharPointer(), dest,
+                                (DWORD) numElementsInArray (dest), &serialNum, 0, 0, 0, 0))
+        return 0;
+
+    return (int) serialNum;
+}
+
+int64 File::getBytesFreeOnVolume() const
+{
+    return WindowsFileHelpers::getDiskSpaceInfo (getFullPathName(), false);
+}
+
+int64 File::getVolumeTotalSize() const
+{
+    return WindowsFileHelpers::getDiskSpaceInfo (getFullPathName(), true);
+}
+
+uint64 File::getFileIdentifier() const
+{
+    uint64 result = 0;
+
+    HANDLE h = CreateFile (getFullPathName().toWideCharPointer(),
+                           GENERIC_READ, FILE_SHARE_READ, nullptr,
+                           OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+
+    if (h != INVALID_HANDLE_VALUE)
+    {
+        BY_HANDLE_FILE_INFORMATION info;
+        zerostruct (info);
+
+        if (GetFileInformationByHandle (h, &info))
+            result = (((uint64) info.nFileIndexHigh) << 32) | info.nFileIndexLow;
+
+        CloseHandle (h);
+    }
+
+    return result;
+}
+
+//==============================================================================
+bool File::isOnCDRomDrive() const
+{
+    return WindowsFileHelpers::getWindowsDriveType (getFullPathName()) == DRIVE_CDROM;
+}
+
+bool File::isOnHardDisk() const
+{
+    if (fullPath.isEmpty())
+        return false;
+
+    const unsigned int n = WindowsFileHelpers::getWindowsDriveType (getFullPathName());
+
+    if (fullPath.toLowerCase()[0] <= 'b' && fullPath[1] == ':')
+        return n != DRIVE_REMOVABLE;
+
+    return n != DRIVE_CDROM && n != DRIVE_REMOTE;
+}
+
+bool File::isOnRemovableDrive() const
+{
+    if (fullPath.isEmpty())
+        return false;
+
+    const unsigned int n = WindowsFileHelpers::getWindowsDriveType (getFullPathName());
+
+    return n == DRIVE_CDROM
+        || n == DRIVE_REMOTE
+        || n == DRIVE_REMOVABLE
+        || n == DRIVE_RAMDISK;
+}
+
+//==============================================================================
+File JUCE_CALLTYPE File::getSpecialLocation (const SpecialLocationType type)
+{
+    int csidlType = 0;
+
+    switch (type)
+    {
+        case userHomeDirectory:                 csidlType = CSIDL_PROFILE; break;
+        case userDocumentsDirectory:            csidlType = CSIDL_PERSONAL; break;
+        case userDesktopDirectory:              csidlType = CSIDL_DESKTOP; break;
+        case userApplicationDataDirectory:      csidlType = CSIDL_APPDATA; break;
+        case commonApplicationDataDirectory:    csidlType = CSIDL_COMMON_APPDATA; break;
+        case commonDocumentsDirectory:          csidlType = CSIDL_COMMON_DOCUMENTS; break;
+        case globalApplicationsDirectory:       csidlType = CSIDL_PROGRAM_FILES; break;
+        case userMusicDirectory:                csidlType = 0x0d; /*CSIDL_MYMUSIC*/ break;
+        case userMoviesDirectory:               csidlType = 0x0e; /*CSIDL_MYVIDEO*/ break;
+        case userPicturesDirectory:             csidlType = 0x27; /*CSIDL_MYPICTURES*/ break;
+
+        case tempDirectory:
+        {
+            WCHAR dest [2048];
+            dest[0] = 0;
+            GetTempPath ((DWORD) numElementsInArray (dest), dest);
+            return File (String (dest));
+        }
+
+        case windowsSystemDirectory:
+        {
+            WCHAR dest [2048];
+            dest[0] = 0;
+            GetSystemDirectoryW (dest, (UINT) numElementsInArray (dest));
+            return File (String (dest));
+        }
+
+        case invokedExecutableFile:
+        case currentExecutableFile:
+        case currentApplicationFile:
+            return WindowsFileHelpers::getModuleFileName ((HINSTANCE) Process::getCurrentModuleInstanceHandle());
+
+        case hostApplicationPath:
+            return WindowsFileHelpers::getModuleFileName (0);
+
+        default:
+            jassertfalse; // unknown type?
+            return File();
+    }
+
+    return WindowsFileHelpers::getSpecialFolderPath (csidlType);
+}
+
+//==============================================================================
+File File::getCurrentWorkingDirectory()
+{
+    WCHAR dest [MAX_PATH + 256];
+    dest[0] = 0;
+    GetCurrentDirectory ((DWORD) numElementsInArray (dest), dest);
+    return File (String (dest));
+}
+
+bool File::setAsCurrentWorkingDirectory() const
+{
+    return SetCurrentDirectory (getFullPathName().toWideCharPointer()) != FALSE;
+}
+
+//==============================================================================
+String File::getVersion() const
+{
+    String result;
+
+    DWORD handle = 0;
+    DWORD bufferSize = GetFileVersionInfoSize (getFullPathName().toWideCharPointer(), &handle);
+    HeapBlock<char> buffer;
+    buffer.calloc (bufferSize);
+
+    if (GetFileVersionInfo (getFullPathName().toWideCharPointer(), 0, bufferSize, buffer))
+    {
+        VS_FIXEDFILEINFO* vffi;
+        UINT len = 0;
+
+        if (VerQueryValue (buffer, (LPTSTR) _T("\\"), (LPVOID*) &vffi, &len))
+        {
+            result << (int) HIWORD (vffi->dwFileVersionMS) << '.'
+                   << (int) LOWORD (vffi->dwFileVersionMS) << '.'
+                   << (int) HIWORD (vffi->dwFileVersionLS) << '.'
+                   << (int) LOWORD (vffi->dwFileVersionLS);
+        }
+    }
+
+    return result;
+}
+
+//==============================================================================
+bool File::isLink() const
+{
+    return hasFileExtension (".lnk");
+}
+
+File File::getLinkedTarget() const
+{
+    File result (*this);
+    String p (getFullPathName());
+
+    if (! exists())
+        p += ".lnk";
+    else if (! hasFileExtension (".lnk"))
+        return result;
+
+    ComSmartPtr<IShellLink> shellLink;
+    ComSmartPtr<IPersistFile> persistFile;
+
+    if (SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink))
+         && SUCCEEDED (shellLink.QueryInterface (persistFile))
+         && SUCCEEDED (persistFile->Load (p.toWideCharPointer(), STGM_READ))
+         && SUCCEEDED (shellLink->Resolve (0, SLR_ANY_MATCH | SLR_NO_UI)))
+    {
+        WIN32_FIND_DATA winFindData;
+        WCHAR resolvedPath [MAX_PATH];
+
+        if (SUCCEEDED (shellLink->GetPath (resolvedPath, MAX_PATH, &winFindData, SLGP_UNCPRIORITY)))
+            result = File (resolvedPath);
+    }
+
+    return result;
+}
+
+bool File::createLink (const String& description, const File& linkFileToCreate) const
+{
+    linkFileToCreate.deleteFile();
+
+    ComSmartPtr<IShellLink> shellLink;
+    ComSmartPtr<IPersistFile> persistFile;
+
+    CoInitialize (0);
+
+    return SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink))
+        && SUCCEEDED (shellLink->SetPath (getFullPathName().toWideCharPointer()))
+        && SUCCEEDED (shellLink->SetDescription (description.toWideCharPointer()))
+        && SUCCEEDED (shellLink.QueryInterface (persistFile))
+        && SUCCEEDED (persistFile->Save (linkFileToCreate.getFullPathName().toWideCharPointer(), TRUE));
+}
+
+//==============================================================================
+class DirectoryIterator::NativeIterator::Pimpl
+{
+public:
+    Pimpl (const File& directory, const String& wildCard)
+        : directoryWithWildCard (File::addTrailingSeparator (directory.getFullPathName()) + wildCard),
+          handle (INVALID_HANDLE_VALUE)
+    {
+    }
+
+    ~Pimpl()
+    {
+        if (handle != INVALID_HANDLE_VALUE)
+            FindClose (handle);
+    }
+
+    bool next (String& filenameFound,
+               bool* const isDir, bool* const isHidden, int64* const fileSize,
+               Time* const modTime, Time* const creationTime, bool* const isReadOnly)
+    {
+        using namespace WindowsFileHelpers;
+        WIN32_FIND_DATA findData;
+
+        if (handle == INVALID_HANDLE_VALUE)
+        {
+            handle = FindFirstFile (directoryWithWildCard.toWideCharPointer(), &findData);
+
+            if (handle == INVALID_HANDLE_VALUE)
+                return false;
+        }
+        else
+        {
+            if (FindNextFile (handle, &findData) == 0)
+                return false;
+        }
+
+        filenameFound = findData.cFileName;
+
+        if (isDir != nullptr)         *isDir        = ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
+        if (isHidden != nullptr)      *isHidden     = ((findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0);
+        if (isReadOnly != nullptr)    *isReadOnly   = ((findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
+        if (fileSize != nullptr)      *fileSize     = findData.nFileSizeLow + (((int64) findData.nFileSizeHigh) << 32);
+        if (modTime != nullptr)       *modTime      = Time (fileTimeToTime (&findData.ftLastWriteTime));
+        if (creationTime != nullptr)  *creationTime = Time (fileTimeToTime (&findData.ftCreationTime));
+
+        return true;
+    }
+
+private:
+    const String directoryWithWildCard;
+    HANDLE handle;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
+};
+
+DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
+    : pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
+{
+}
+
+DirectoryIterator::NativeIterator::~NativeIterator()
+{
+}
+
+bool DirectoryIterator::NativeIterator::next (String& filenameFound,
+                                              bool* const isDir, bool* const isHidden, int64* const fileSize,
+                                              Time* const modTime, Time* const creationTime, bool* const isReadOnly)
+{
+    return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
+}
+
+
+//==============================================================================
+bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String& parameters)
+{
+    HINSTANCE hInstance = 0;
+
+    JUCE_TRY
+    {
+        hInstance = ShellExecute (0, 0, fileName.toWideCharPointer(),
+                                  parameters.toWideCharPointer(), 0, SW_SHOWDEFAULT);
+    }
+    JUCE_CATCH_ALL
+
+    return hInstance > (HINSTANCE) 32;
+}
+
+void File::revealToUser() const
+{
+    DynamicLibrary dll ("Shell32.dll");
+    JUCE_LOAD_WINAPI_FUNCTION (dll, ILCreateFromPathW, ilCreateFromPathW, ITEMIDLIST*, (LPCWSTR))
+    JUCE_LOAD_WINAPI_FUNCTION (dll, ILFree, ilFree, void, (ITEMIDLIST*))
+    JUCE_LOAD_WINAPI_FUNCTION (dll, SHOpenFolderAndSelectItems, shOpenFolderAndSelectItems, HRESULT, (ITEMIDLIST*, UINT, void*, DWORD))
+
+    if (ilCreateFromPathW != nullptr && shOpenFolderAndSelectItems != nullptr && ilFree != nullptr)
+    {
+        if (ITEMIDLIST* const itemIDList = ilCreateFromPathW (fullPath.toWideCharPointer()))
+        {
+            shOpenFolderAndSelectItems (itemIDList, 0, nullptr, 0);
+            ilFree (itemIDList);
+        }
+    }
+}
+
+//==============================================================================
+class NamedPipe::Pimpl
+{
+public:
+    Pimpl (const String& pipeName, const bool createPipe)
+        : filename ("\\\\.\\pipe\\" + File::createLegalFileName (pipeName)),
+          pipeH (INVALID_HANDLE_VALUE),
+          cancelEvent (CreateEvent (0, FALSE, FALSE, 0)),
+          connected (false), ownsPipe (createPipe), shouldStop (false)
+    {
+        if (createPipe)
+            pipeH = CreateNamedPipe (filename.toWideCharPointer(),
+                                     PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0,
+                                     PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, 0);
+    }
+
+    ~Pimpl()
+    {
+        disconnectPipe();
+
+        if (pipeH != INVALID_HANDLE_VALUE)
+            CloseHandle (pipeH);
+
+        CloseHandle (cancelEvent);
+    }
+
+    bool connect (const int timeOutMs)
+    {
+        if (! ownsPipe)
+        {
+            if (pipeH != INVALID_HANDLE_VALUE)
+                return true;
+
+            const Time timeOutEnd (Time::getCurrentTime() + RelativeTime::milliseconds (timeOutMs));
+
+            for (;;)
+            {
+                {
+                    const ScopedLock sl (createFileLock);
+
+                    if (pipeH == INVALID_HANDLE_VALUE)
+                        pipeH = CreateFile (filename.toWideCharPointer(),
+                                            GENERIC_READ | GENERIC_WRITE, 0, 0,
+                                            OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+                }
+
+                if (pipeH != INVALID_HANDLE_VALUE)
+                    return true;
+
+                if (shouldStop || (timeOutMs >= 0 && Time::getCurrentTime() > timeOutEnd))
+                    return false;
+
+                Thread::sleep (1);
+            }
+        }
+
+        if (! connected)
+        {
+            OverlappedEvent over;
+
+            if (ConnectNamedPipe (pipeH, &over.over) == 0)
+            {
+                switch (GetLastError())
+                {
+                    case ERROR_PIPE_CONNECTED:   connected = true; break;
+                    case ERROR_IO_PENDING:
+                    case ERROR_PIPE_LISTENING:   connected = waitForIO (over, timeOutMs); break;
+                    default: break;
+                }
+            }
+        }
+
+        return connected;
+    }
+
+    void disconnectPipe()
+    {
+        if (ownsPipe && connected)
+        {
+            DisconnectNamedPipe (pipeH);
+            connected = false;
+        }
+    }
+
+    int read (void* destBuffer, const int maxBytesToRead, const int timeOutMilliseconds)
+    {
+        while (connect (timeOutMilliseconds))
+        {
+            if (maxBytesToRead <= 0)
+                return 0;
+
+            OverlappedEvent over;
+            unsigned long numRead;
+
+            if (ReadFile (pipeH, destBuffer, (DWORD) maxBytesToRead, &numRead, &over.over))
+                return (int) numRead;
+
+            const DWORD lastError = GetLastError();
+
+            if (lastError == ERROR_IO_PENDING)
+            {
+                if (! waitForIO (over, timeOutMilliseconds))
+                    return -1;
+
+                if (GetOverlappedResult (pipeH, &over.over, &numRead, FALSE))
+                    return (int) numRead;
+            }
+
+            if (ownsPipe && (GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_PIPE_NOT_CONNECTED))
+                disconnectPipe();
+            else
+                break;
+        }
+
+        return -1;
+    }
+
+    int write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
+    {
+        if (connect (timeOutMilliseconds))
+        {
+            if (numBytesToWrite <= 0)
+                return 0;
+
+            OverlappedEvent over;
+            unsigned long numWritten;
+
+            if (WriteFile (pipeH, sourceBuffer, (DWORD) numBytesToWrite, &numWritten, &over.over))
+                return (int) numWritten;
+
+            if (GetLastError() == ERROR_IO_PENDING)
+            {
+                if (! waitForIO (over, timeOutMilliseconds))
+                    return -1;
+
+                if (GetOverlappedResult (pipeH, &over.over, &numWritten, FALSE))
+                    return (int) numWritten;
+
+                if (GetLastError() == ERROR_BROKEN_PIPE && ownsPipe)
+                    disconnectPipe();
+            }
+        }
+
+        return -1;
+    }
+
+    const String filename;
+    HANDLE pipeH, cancelEvent;
+    bool connected, ownsPipe, shouldStop;
+    CriticalSection createFileLock;
+
+private:
+    struct OverlappedEvent
+    {
+        OverlappedEvent()
+        {
+            zerostruct (over);
+            over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
+        }
+
+        ~OverlappedEvent()
+        {
+            CloseHandle (over.hEvent);
+        }
+
+        OVERLAPPED over;
+    };
+
+    bool waitForIO (OverlappedEvent& over, int timeOutMilliseconds)
+    {
+        if (shouldStop)
+            return false;
+
+        HANDLE handles[] = { over.over.hEvent, cancelEvent };
+        DWORD waitResult = WaitForMultipleObjects (2, handles, FALSE,
+                                                   timeOutMilliseconds >= 0 ? timeOutMilliseconds
+                                                                            : INFINITE);
+
+        if (waitResult == WAIT_OBJECT_0)
+            return true;
+
+        CancelIo (pipeH);
+        return false;
+    }
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
+};
+
+void NamedPipe::close()
+{
+    if (pimpl != nullptr)
+    {
+        pimpl->shouldStop = true;
+        SetEvent (pimpl->cancelEvent);
+
+        ScopedWriteLock sl (lock);
+        pimpl = nullptr;
+    }
+}
+
+bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
+{
+    pimpl = new Pimpl (pipeName, createPipe);
+
+    if (createPipe && pimpl->pipeH == INVALID_HANDLE_VALUE)
+    {
+        pimpl = nullptr;
+        return false;
+    }
+
+    return true;
+}
+
+int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
+{
+    ScopedReadLock sl (lock);
+    return pimpl != nullptr ? pimpl->read (destBuffer, maxBytesToRead, timeOutMilliseconds) : -1;
+}
+
+int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
+{
+    ScopedReadLock sl (lock);
+    return pimpl != nullptr ? pimpl->write (sourceBuffer, numBytesToWrite, timeOutMilliseconds) : -1;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Network.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Network.cpp
new file mode 100644
index 0000000..1b35453
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Network.cpp
@@ -0,0 +1,486 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef INTERNET_FLAG_NEED_FILE
+ #define INTERNET_FLAG_NEED_FILE 0x00000010
+#endif
+
+#ifndef INTERNET_OPTION_DISABLE_AUTODIAL
+ #define INTERNET_OPTION_DISABLE_AUTODIAL 70
+#endif
+
+//==============================================================================
+class WebInputStream  : public InputStream
+{
+public:
+    WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
+                    URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
+                    const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
+      : statusCode (0), connection (0), request (0),
+        address (address_), headers (headers_), postData (postData_), position (0),
+        finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
+    {
+        createConnection (progressCallback, progressCallbackContext);
+
+        if (! isError())
+        {
+            if (responseHeaders != nullptr)
+            {
+                DWORD bufferSizeBytes = 4096;
+
+                for (;;)
+                {
+                    HeapBlock<char> buffer ((size_t) bufferSizeBytes);
+
+                    if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0))
+                    {
+                        StringArray headersArray;
+                        headersArray.addLines (String (reinterpret_cast<const WCHAR*> (buffer.getData())));
+
+                        for (int i = 0; i < headersArray.size(); ++i)
+                        {
+                            const String& header = headersArray[i];
+                            const String key (header.upToFirstOccurrenceOf (": ", false, false));
+                            const String value (header.fromFirstOccurrenceOf (": ", false, false));
+                            const String previousValue ((*responseHeaders) [key]);
+
+                            responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
+                        }
+
+                        break;
+                    }
+
+                    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+                        break;
+                }
+            }
+
+            DWORD status = 0;
+            DWORD statusSize = sizeof (status);
+
+            if (HttpQueryInfo (request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &statusSize, 0))
+                statusCode = (int) status;
+        }
+    }
+
+    ~WebInputStream()
+    {
+        close();
+    }
+
+    //==============================================================================
+    bool isError() const        { return request == 0; }
+    bool isExhausted()          { return finished; }
+    int64 getPosition()         { return position; }
+
+    int64 getTotalLength()
+    {
+        if (! isError())
+        {
+            DWORD index = 0, result = 0, size = sizeof (result);
+
+            if (HttpQueryInfo (request, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &result, &size, &index))
+                return (int64) result;
+        }
+
+        return -1;
+    }
+
+    int read (void* buffer, int bytesToRead)
+    {
+        jassert (buffer != nullptr && bytesToRead >= 0);
+        DWORD bytesRead = 0;
+
+        if (! (finished || isError()))
+        {
+            InternetReadFile (request, buffer, (DWORD) bytesToRead, &bytesRead);
+            position += bytesRead;
+
+            if (bytesRead == 0)
+                finished = true;
+        }
+
+        return (int) bytesRead;
+    }
+
+    bool setPosition (int64 wantedPos)
+    {
+        if (isError())
+            return false;
+
+        if (wantedPos != position)
+        {
+            finished = false;
+            position = (int64) InternetSetFilePointer (request, (LONG) wantedPos, 0, FILE_BEGIN, 0);
+
+            if (position == wantedPos)
+                return true;
+
+            if (wantedPos < position)
+            {
+                close();
+                position = 0;
+                createConnection (0, 0);
+            }
+
+            skipNextBytes (wantedPos - position);
+        }
+
+        return true;
+    }
+
+    int statusCode;
+
+private:
+    //==============================================================================
+    HINTERNET connection, request;
+    String address, headers;
+    MemoryBlock postData;
+    int64 position;
+    bool finished;
+    const bool isPost;
+    int timeOutMs;
+
+    void close()
+    {
+        if (request != 0)
+        {
+            InternetCloseHandle (request);
+            request = 0;
+        }
+
+        if (connection != 0)
+        {
+            InternetCloseHandle (connection);
+            connection = 0;
+        }
+    }
+
+    void createConnection (URL::OpenStreamProgressCallback* progressCallback,
+                           void* progressCallbackContext)
+    {
+        static HINTERNET sessionHandle = InternetOpen (_T("juce"), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
+
+        close();
+
+        if (sessionHandle != 0)
+        {
+            // break up the url..
+            const int fileNumChars = 65536;
+            const int serverNumChars = 2048;
+            const int usernameNumChars = 1024;
+            const int passwordNumChars = 1024;
+            HeapBlock<TCHAR> file (fileNumChars), server (serverNumChars),
+                             username (usernameNumChars), password (passwordNumChars);
+
+            URL_COMPONENTS uc = { 0 };
+            uc.dwStructSize = sizeof (uc);
+            uc.lpszUrlPath = file;
+            uc.dwUrlPathLength = fileNumChars;
+            uc.lpszHostName = server;
+            uc.dwHostNameLength = serverNumChars;
+            uc.lpszUserName = username;
+            uc.dwUserNameLength = usernameNumChars;
+            uc.lpszPassword = password;
+            uc.dwPasswordLength = passwordNumChars;
+
+            if (InternetCrackUrl (address.toWideCharPointer(), 0, 0, &uc))
+                openConnection (uc, sessionHandle, progressCallback, progressCallbackContext);
+        }
+    }
+
+    void openConnection (URL_COMPONENTS& uc, HINTERNET sessionHandle,
+                         URL::OpenStreamProgressCallback* progressCallback,
+                         void* progressCallbackContext)
+    {
+        int disable = 1;
+        InternetSetOption (sessionHandle, INTERNET_OPTION_DISABLE_AUTODIAL, &disable, sizeof (disable));
+
+        if (timeOutMs == 0)
+            timeOutMs = 30000;
+        else if (timeOutMs < 0)
+            timeOutMs = -1;
+
+        applyTimeout (sessionHandle, INTERNET_OPTION_CONNECT_TIMEOUT);
+        applyTimeout (sessionHandle, INTERNET_OPTION_RECEIVE_TIMEOUT);
+        applyTimeout (sessionHandle, INTERNET_OPTION_SEND_TIMEOUT);
+        applyTimeout (sessionHandle, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT);
+        applyTimeout (sessionHandle, INTERNET_OPTION_DATA_SEND_TIMEOUT);
+
+        const bool isFtp = address.startsWithIgnoreCase ("ftp:");
+
+        connection = InternetConnect (sessionHandle, uc.lpszHostName, uc.nPort,
+                                      uc.lpszUserName, uc.lpszPassword,
+                                      isFtp ? (DWORD) INTERNET_SERVICE_FTP
+                                            : (DWORD) INTERNET_SERVICE_HTTP,
+                                      0, 0);
+        if (connection != 0)
+        {
+            if (isFtp)
+                request = FtpOpenFile (connection, uc.lpszUrlPath, GENERIC_READ,
+                                       FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_NEED_FILE, 0);
+            else
+                openHTTPConnection (uc, progressCallback, progressCallbackContext);
+        }
+    }
+
+    void applyTimeout (HINTERNET sessionHandle, const DWORD option)
+    {
+        InternetSetOption (sessionHandle, option, &timeOutMs, sizeof (timeOutMs));
+    }
+
+    void openHTTPConnection (URL_COMPONENTS& uc, URL::OpenStreamProgressCallback* progressCallback,
+                             void* progressCallbackContext)
+    {
+        const TCHAR* mimeTypes[] = { _T("*/*"), nullptr };
+
+        DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES
+                        | INTERNET_FLAG_NO_AUTO_REDIRECT | SECURITY_SET_MASK;
+
+        if (address.startsWithIgnoreCase ("https:"))
+            flags |= INTERNET_FLAG_SECURE;  // (this flag only seems necessary if the OS is running IE6 -
+                                            //  IE7 seems to automatically work out when it's https)
+
+        request = HttpOpenRequest (connection, isPost ? _T("POST") : _T("GET"),
+                                   uc.lpszUrlPath, 0, 0, mimeTypes, flags, 0);
+
+        if (request != 0)
+        {
+            setSecurityFlags();
+
+            INTERNET_BUFFERS buffers = { 0 };
+            buffers.dwStructSize = sizeof (INTERNET_BUFFERS);
+            buffers.lpcszHeader = headers.toWideCharPointer();
+            buffers.dwHeadersLength = (DWORD) headers.length();
+            buffers.dwBufferTotal = (DWORD) postData.getSize();
+
+            if (HttpSendRequestEx (request, &buffers, 0, HSR_INITIATE, 0))
+            {
+                int bytesSent = 0;
+
+                for (;;)
+                {
+                    const int bytesToDo = jmin (1024, (int) postData.getSize() - bytesSent);
+                    DWORD bytesDone = 0;
+
+                    if (bytesToDo > 0
+                         && ! InternetWriteFile (request,
+                                                 static_cast<const char*> (postData.getData()) + bytesSent,
+                                                 (DWORD) bytesToDo, &bytesDone))
+                    {
+                        break;
+                    }
+
+                    if (bytesToDo == 0 || (int) bytesDone < bytesToDo)
+                    {
+                        if (HttpEndRequest (request, 0, 0, 0))
+                            return;
+
+                        break;
+                    }
+
+                    bytesSent += bytesDone;
+
+                    if (progressCallback != nullptr
+                          && ! progressCallback (progressCallbackContext, bytesSent, (int) postData.getSize()))
+                        break;
+                }
+            }
+        }
+
+        close();
+    }
+
+    void setSecurityFlags()
+    {
+        DWORD dwFlags = 0, dwBuffLen = sizeof (DWORD);
+        InternetQueryOption (request, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, &dwBuffLen);
+        dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_SET_MASK;
+        InternetSetOption (request, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags));
+    }
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
+};
+
+
+//==============================================================================
+struct GetAdaptersInfoHelper
+{
+    bool callGetAdaptersInfo()
+    {
+        DynamicLibrary dll ("iphlpapi.dll");
+        JUCE_LOAD_WINAPI_FUNCTION (dll, GetAdaptersInfo, getAdaptersInfo, DWORD, (PIP_ADAPTER_INFO, PULONG))
+
+        if (getAdaptersInfo == nullptr)
+            return false;
+
+        adapterInfo.malloc (1);
+        ULONG len = sizeof (IP_ADAPTER_INFO);
+
+        if (getAdaptersInfo (adapterInfo, &len) == ERROR_BUFFER_OVERFLOW)
+            adapterInfo.malloc (len, 1);
+
+        return getAdaptersInfo (adapterInfo, &len) == NO_ERROR;
+    }
+
+    HeapBlock<IP_ADAPTER_INFO> adapterInfo;
+};
+
+namespace MACAddressHelpers
+{
+    static void addAddress (Array<MACAddress>& result, const MACAddress& ma)
+    {
+        if (! ma.isNull())
+            result.addIfNotAlreadyThere (ma);
+    }
+
+    static void getViaGetAdaptersInfo (Array<MACAddress>& result)
+    {
+        GetAdaptersInfoHelper gah;
+
+        if (gah.callGetAdaptersInfo())
+        {
+            for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
+                if (adapter->AddressLength >= 6)
+                    addAddress (result, MACAddress (adapter->Address));
+        }
+    }
+
+    static void getViaNetBios (Array<MACAddress>& result)
+    {
+        DynamicLibrary dll ("netapi32.dll");
+        JUCE_LOAD_WINAPI_FUNCTION (dll, Netbios, NetbiosCall, UCHAR, (PNCB))
+
+        if (NetbiosCall != 0)
+        {
+            LANA_ENUM enums = { 0 };
+
+            {
+                NCB ncb = { 0 };
+                ncb.ncb_command = NCBENUM;
+                ncb.ncb_buffer = (unsigned char*) &enums;
+                ncb.ncb_length = sizeof (LANA_ENUM);
+                NetbiosCall (&ncb);
+            }
+
+            for (int i = 0; i < enums.length; ++i)
+            {
+                NCB ncb2 = { 0 };
+                ncb2.ncb_command = NCBRESET;
+                ncb2.ncb_lana_num = enums.lana[i];
+
+                if (NetbiosCall (&ncb2) == 0)
+                {
+                    NCB ncb = { 0 };
+                    memcpy (ncb.ncb_callname, "*                   ", NCBNAMSZ);
+                    ncb.ncb_command = NCBASTAT;
+                    ncb.ncb_lana_num = enums.lana[i];
+
+                    struct ASTAT
+                    {
+                        ADAPTER_STATUS adapt;
+                        NAME_BUFFER    NameBuff [30];
+                    };
+
+                    ASTAT astat;
+                    zerostruct (astat);
+                    ncb.ncb_buffer = (unsigned char*) &astat;
+                    ncb.ncb_length = sizeof (ASTAT);
+
+                    if (NetbiosCall (&ncb) == 0 && astat.adapt.adapter_type == 0xfe)
+                        addAddress (result, MACAddress (astat.adapt.adapter_address));
+                }
+            }
+        }
+    }
+}
+
+void MACAddress::findAllAddresses (Array<MACAddress>& result)
+{
+    MACAddressHelpers::getViaGetAdaptersInfo (result);
+    MACAddressHelpers::getViaNetBios (result);
+}
+
+void IPAddress::findAllAddresses (Array<IPAddress>& result)
+{
+    result.addIfNotAlreadyThere (IPAddress::local());
+
+    GetAdaptersInfoHelper gah;
+
+    if (gah.callGetAdaptersInfo())
+    {
+        for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
+        {
+            IPAddress ip (adapter->IpAddressList.IpAddress.String);
+
+            if (ip != IPAddress::any())
+                result.addIfNotAlreadyThere (ip);
+        }
+    }
+}
+
+//==============================================================================
+bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailAddress,
+                                                      const String& emailSubject,
+                                                      const String& bodyText,
+                                                      const StringArray& filesToAttach)
+{
+    DynamicLibrary dll ("MAPI32.dll");
+    JUCE_LOAD_WINAPI_FUNCTION (dll, MAPISendMail, mapiSendMail,
+                               ULONG, (LHANDLE, ULONG, lpMapiMessage, ::FLAGS, ULONG))
+
+    if (mapiSendMail == nullptr)
+        return false;
+
+    MapiMessage message = { 0 };
+    message.lpszSubject = (LPSTR) emailSubject.toRawUTF8();
+    message.lpszNoteText = (LPSTR) bodyText.toRawUTF8();
+
+    MapiRecipDesc recip = { 0 };
+    recip.ulRecipClass = MAPI_TO;
+    String targetEmailAddress_ (targetEmailAddress);
+    if (targetEmailAddress_.isEmpty())
+        targetEmailAddress_ = " "; // (Windows Mail can't deal with a blank address)
+    recip.lpszName = (LPSTR) targetEmailAddress_.toRawUTF8();
+    message.nRecipCount = 1;
+    message.lpRecips = &recip;
+
+    HeapBlock <MapiFileDesc> files;
+    files.calloc ((size_t) filesToAttach.size());
+
+    message.nFileCount = (ULONG) filesToAttach.size();
+    message.lpFiles = files;
+
+    for (int i = 0; i < filesToAttach.size(); ++i)
+    {
+        files[i].nPosition = (ULONG) -1;
+        files[i].lpszPathName = (LPSTR) filesToAttach[i].toRawUTF8();
+    }
+
+    return mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Registry.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Registry.cpp
new file mode 100644
index 0000000..8119474
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Registry.cpp
@@ -0,0 +1,227 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+struct RegistryKeyWrapper
+{
+    RegistryKeyWrapper (String name, const bool createForWriting, const DWORD wow64Flags)
+        : key (0), wideCharValueName (nullptr)
+    {
+        HKEY rootKey = 0;
+
+        if (name.startsWithIgnoreCase ("HKEY_CURRENT_USER\\"))        rootKey = HKEY_CURRENT_USER;
+        else if (name.startsWithIgnoreCase ("HKEY_LOCAL_MACHINE\\"))  rootKey = HKEY_LOCAL_MACHINE;
+        else if (name.startsWithIgnoreCase ("HKEY_CLASSES_ROOT\\"))   rootKey = HKEY_CLASSES_ROOT;
+
+        if (rootKey != 0)
+        {
+            name = name.substring (name.indexOfChar ('\\') + 1);
+
+            const int lastSlash = name.lastIndexOfChar ('\\');
+            valueName = name.substring (lastSlash + 1);
+            wideCharValueName = valueName.toWideCharPointer();
+
+            name = name.substring (0, lastSlash);
+            const wchar_t* const wideCharName = name.toWideCharPointer();
+            DWORD result;
+
+            if (createForWriting)
+                RegCreateKeyEx (rootKey, wideCharName, 0, 0, REG_OPTION_NON_VOLATILE,
+                                KEY_WRITE | KEY_QUERY_VALUE | wow64Flags, 0, &key, &result);
+            else
+                RegOpenKeyEx (rootKey, wideCharName, 0, KEY_READ | wow64Flags, &key);
+        }
+    }
+
+    ~RegistryKeyWrapper()
+    {
+        if (key != 0)
+            RegCloseKey (key);
+    }
+
+    static bool setValue (const String& regValuePath, const DWORD type,
+                          const void* data, size_t dataSize, const DWORD wow64Flags)
+    {
+        const RegistryKeyWrapper key (regValuePath, true, wow64Flags);
+
+        return key.key != 0
+                && RegSetValueEx (key.key, key.wideCharValueName, 0, type,
+                                  reinterpret_cast <const BYTE*> (data),
+                                  (DWORD) dataSize) == ERROR_SUCCESS;
+    }
+
+    static uint32 getBinaryValue (const String& regValuePath, MemoryBlock& result, DWORD wow64Flags)
+    {
+        const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
+
+        if (key.key != 0)
+        {
+            for (unsigned long bufferSize = 1024; ; bufferSize *= 2)
+            {
+                result.setSize (bufferSize, false);
+                DWORD type = REG_NONE;
+
+                const LONG err = RegQueryValueEx (key.key, key.wideCharValueName, 0, &type,
+                                                  (LPBYTE) result.getData(), &bufferSize);
+
+                if (err == ERROR_SUCCESS)
+                {
+                    result.setSize (bufferSize, false);
+                    return type;
+                }
+
+                if (err != ERROR_MORE_DATA)
+                    break;
+            }
+        }
+
+        return REG_NONE;
+    }
+
+    static String getValue (const String& regValuePath, const String& defaultValue, DWORD wow64Flags)
+    {
+        MemoryBlock buffer;
+        switch (getBinaryValue (regValuePath, buffer, wow64Flags))
+        {
+            case REG_SZ:    return static_cast <const WCHAR*> (buffer.getData());
+            case REG_DWORD: return String ((int) *reinterpret_cast<const DWORD*> (buffer.getData()));
+            default:        break;
+        }
+
+        return defaultValue;
+    }
+
+    static bool keyExists (const String& regValuePath, const DWORD wow64Flags)
+    {
+        return RegistryKeyWrapper (regValuePath, false, wow64Flags).key != 0;
+    }
+
+    static bool valueExists (const String& regValuePath, const DWORD wow64Flags)
+    {
+        const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
+
+        if (key.key == 0)
+            return false;
+
+        unsigned char buffer [512];
+        unsigned long bufferSize = sizeof (buffer);
+        DWORD type = 0;
+
+        const LONG result = RegQueryValueEx (key.key, key.wideCharValueName,
+                                             0, &type, buffer, &bufferSize);
+
+        return result == ERROR_SUCCESS || result == ERROR_MORE_DATA;
+    }
+
+    HKEY key;
+    const wchar_t* wideCharValueName;
+    String valueName;
+
+    JUCE_DECLARE_NON_COPYABLE (RegistryKeyWrapper)
+};
+
+uint32 JUCE_CALLTYPE WindowsRegistry::getBinaryValue (const String& regValuePath, MemoryBlock& result, WoW64Mode mode)
+{
+    return RegistryKeyWrapper::getBinaryValue (regValuePath, result, (DWORD) mode);
+}
+
+String JUCE_CALLTYPE WindowsRegistry::getValue (const String& regValuePath, const String& defaultValue, WoW64Mode mode)
+{
+    return RegistryKeyWrapper::getValue (regValuePath, defaultValue, (DWORD) mode);
+}
+
+bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const String& value, WoW64Mode mode)
+{
+    return RegistryKeyWrapper::setValue (regValuePath, REG_SZ, value.toWideCharPointer(),
+                                         CharPointer_UTF16::getBytesRequiredFor (value.getCharPointer()), mode);
+}
+
+bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const uint32 value, WoW64Mode mode)
+{
+    return RegistryKeyWrapper::setValue (regValuePath, REG_DWORD, &value, sizeof (value), (DWORD) mode);
+}
+
+bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const uint64 value, WoW64Mode mode)
+{
+    return RegistryKeyWrapper::setValue (regValuePath, REG_QWORD, &value, sizeof (value), (DWORD) mode);
+}
+
+bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const MemoryBlock& value, WoW64Mode mode)
+{
+    return RegistryKeyWrapper::setValue (regValuePath, REG_BINARY, value.getData(), value.getSize(), (DWORD) mode);
+}
+
+bool JUCE_CALLTYPE WindowsRegistry::valueExists (const String& regValuePath, WoW64Mode mode)
+{
+    return RegistryKeyWrapper::valueExists (regValuePath, (DWORD) mode);
+}
+
+bool JUCE_CALLTYPE WindowsRegistry::keyExists (const String& regValuePath, WoW64Mode mode)
+{
+    return RegistryKeyWrapper::keyExists (regValuePath, (DWORD) mode);
+}
+
+void JUCE_CALLTYPE WindowsRegistry::deleteValue (const String& regValuePath, WoW64Mode mode)
+{
+    const RegistryKeyWrapper key (regValuePath, true, (DWORD) mode);
+
+    if (key.key != 0)
+        RegDeleteValue (key.key, key.wideCharValueName);
+}
+
+void JUCE_CALLTYPE WindowsRegistry::deleteKey (const String& regKeyPath, WoW64Mode mode)
+{
+    const RegistryKeyWrapper key (regKeyPath, true, (DWORD) mode);
+
+    if (key.key != 0)
+        RegDeleteKey (key.key, key.wideCharValueName);
+}
+
+bool JUCE_CALLTYPE WindowsRegistry::registerFileAssociation (const String& fileExtension,
+                                                             const String& symbolicDescription,
+                                                             const String& fullDescription,
+                                                             const File& targetExecutable,
+                                                             const int iconResourceNumber,
+                                                             const bool registerForCurrentUserOnly,
+                                                             WoW64Mode mode)
+{
+    const char* const root = registerForCurrentUserOnly ? "HKEY_CURRENT_USER\\Software\\Classes\\"
+                                                        : "HKEY_CLASSES_ROOT\\";
+    const String key (root + symbolicDescription);
+
+    return setValue (root + fileExtension + "\\", symbolicDescription, mode)
+        && setValue (key + "\\", fullDescription, mode)
+        && setValue (key + "\\shell\\open\\command\\", targetExecutable.getFullPathName() + " \"%1\"", mode)
+        && (iconResourceNumber == 0
+              || setValue (key + "\\DefaultIcon\\",
+                           targetExecutable.getFullPathName() + "," + String (iconResourceNumber)));
+}
+
+// These methods are deprecated:
+String WindowsRegistry::getValueWow64 (const String& p, const String& defVal)  { return getValue (p, defVal, WoW64_64bit); }
+bool WindowsRegistry::valueExistsWow64 (const String& p)                       { return valueExists (p, WoW64_64bit); }
+bool WindowsRegistry::keyExistsWow64 (const String& p)                         { return keyExists (p, WoW64_64bit); }
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_SystemStats.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_SystemStats.cpp
new file mode 100644
index 0000000..901bc76
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_SystemStats.cpp
@@ -0,0 +1,459 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+void Logger::outputDebugString (const String& text)
+{
+    OutputDebugString ((text + "\n").toWideCharPointer());
+}
+
+//==============================================================================
+#ifdef JUCE_DLL_BUILD
+ JUCE_API void* juceDLL_malloc (size_t sz)    { return std::malloc (sz); }
+ JUCE_API void  juceDLL_free (void* block)    { std::free (block); }
+#endif
+
+//==============================================================================
+#if JUCE_USE_INTRINSICS
+
+// CPU info functions using intrinsics...
+
+#pragma intrinsic (__cpuid)
+#pragma intrinsic (__rdtsc)
+
+static void callCPUID (int result[4], int infoType)
+{
+    __cpuid (result, infoType);
+}
+
+#else
+
+static void callCPUID (int result[4], int infoType)
+{
+   #if ! JUCE_MINGW
+    __try
+   #endif
+    {
+       #if JUCE_GCC
+        __asm__ __volatile__ ("cpuid" : "=a" (result[0]), "=b" (result[1]), "=c" (result[2]),"=d" (result[3]) : "a" (infoType));
+       #else
+        __asm
+        {
+            mov    esi, result
+            mov    eax, infoType
+            xor    ecx, ecx
+            cpuid
+            mov    dword ptr [esi +  0], eax
+            mov    dword ptr [esi +  4], ebx
+            mov    dword ptr [esi +  8], ecx
+            mov    dword ptr [esi + 12], edx
+        }
+       #endif
+    }
+   #if ! JUCE_MINGW
+    __except (EXCEPTION_EXECUTE_HANDLER) {}
+   #endif
+}
+
+#endif
+
+String SystemStats::getCpuVendor()
+{
+    int info[4] = { 0 };
+    callCPUID (info, 0);
+
+    char v [12];
+    memcpy (v, info + 1, 4);
+    memcpy (v + 4, info + 3, 4);
+    memcpy (v + 8, info + 2, 4);
+
+    return String (v, 12);
+}
+
+//==============================================================================
+void CPUInformation::initialise() noexcept
+{
+    int info[4] = { 0 };
+    callCPUID (info, 1);
+
+    // NB: IsProcessorFeaturePresent doesn't work on XP
+    hasMMX   = (info[3] & (1 << 23)) != 0;
+    hasSSE   = (info[3] & (1 << 25)) != 0;
+    hasSSE2  = (info[3] & (1 << 26)) != 0;
+    hasSSE3  = (info[2] & (1 <<  0)) != 0;
+    has3DNow = (info[1] & (1 << 31)) != 0;
+
+    SYSTEM_INFO systemInfo;
+    GetNativeSystemInfo (&systemInfo);
+    numCpus = (int) systemInfo.dwNumberOfProcessors;
+}
+
+#if JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS
+struct DebugFlagsInitialiser
+{
+    DebugFlagsInitialiser()
+    {
+        _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+    }
+};
+
+static DebugFlagsInitialiser debugFlagsInitialiser;
+#endif
+
+//==============================================================================
+static bool isWindowsVersionOrLater (SystemStats::OperatingSystemType target)
+{
+    OSVERSIONINFOEX info;
+    zerostruct (info);
+    info.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
+
+    if (target >= SystemStats::WinVista)
+    {
+        info.dwMajorVersion = 6;
+
+        switch (target)
+        {
+            case SystemStats::WinVista:    break;
+            case SystemStats::Windows7:    info.dwMinorVersion = 1; break;
+            case SystemStats::Windows8_0:  info.dwMinorVersion = 2; break;
+            case SystemStats::Windows8_1:  info.dwMinorVersion = 3; break;
+            default:                       jassertfalse; break;
+        }
+    }
+    else
+    {
+        info.dwMajorVersion = 5;
+        info.dwMinorVersion = target >= SystemStats::WinXP ? 1 : 0;
+    }
+
+    DWORDLONG mask = 0;
+
+    VER_SET_CONDITION (mask, VER_MAJORVERSION,     VER_GREATER_EQUAL);
+    VER_SET_CONDITION (mask, VER_MINORVERSION,     VER_GREATER_EQUAL);
+    VER_SET_CONDITION (mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
+    VER_SET_CONDITION (mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
+
+    return VerifyVersionInfo (&info,
+                              VER_MAJORVERSION | VER_MINORVERSION
+                               | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
+                              mask) != FALSE;
+}
+
+SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
+{
+    const SystemStats::OperatingSystemType types[]
+            = { Windows8_1, Windows8_0, Windows7, WinVista, WinXP, Win2000 };
+
+    for (int i = 0; i < numElementsInArray (types); ++i)
+        if (isWindowsVersionOrLater (types[i]))
+            return types[i];
+
+    jassertfalse;  // need to support whatever new version is running!
+    return UnknownOS;
+}
+
+String SystemStats::getOperatingSystemName()
+{
+    const char* name = "Unknown OS";
+
+    switch (getOperatingSystemType())
+    {
+        case Windows8_1:        name = "Windows 8.1";       break;
+        case Windows8_0:        name = "Windows 8.0";       break;
+        case Windows7:          name = "Windows 7";         break;
+        case WinVista:          name = "Windows Vista";     break;
+        case WinXP:             name = "Windows XP";        break;
+        case Win2000:           name = "Windows 2000";      break;
+        default:                jassertfalse; break; // !! new type of OS?
+    }
+
+    return name;
+}
+
+String SystemStats::getDeviceDescription()
+{
+    return String();
+}
+
+bool SystemStats::isOperatingSystem64Bit()
+{
+   #if JUCE_64BIT
+    return true;
+   #else
+    typedef BOOL (WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+
+    LPFN_ISWOW64PROCESS fnIsWow64Process
+        = (LPFN_ISWOW64PROCESS) GetProcAddress (GetModuleHandleA ("kernel32"), "IsWow64Process");
+
+    BOOL isWow64 = FALSE;
+
+    return fnIsWow64Process != nullptr
+            && fnIsWow64Process (GetCurrentProcess(), &isWow64)
+            && isWow64 != FALSE;
+   #endif
+}
+
+//==============================================================================
+int SystemStats::getMemorySizeInMegabytes()
+{
+    MEMORYSTATUSEX mem;
+    mem.dwLength = sizeof (mem);
+    GlobalMemoryStatusEx (&mem);
+    return (int) (mem.ullTotalPhys / (1024 * 1024)) + 1;
+}
+
+//==============================================================================
+String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
+{
+    DWORD len = GetEnvironmentVariableW (name.toWideCharPointer(), nullptr, 0);
+    if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
+        return String (defaultValue);
+
+    HeapBlock<WCHAR> buffer (len);
+    len = GetEnvironmentVariableW (name.toWideCharPointer(), buffer, len);
+
+    return String (CharPointer_wchar_t (buffer),
+                   CharPointer_wchar_t (buffer + len));
+}
+
+//==============================================================================
+uint32 juce_millisecondsSinceStartup() noexcept
+{
+    return (uint32) timeGetTime();
+}
+
+//==============================================================================
+class HiResCounterHandler
+{
+public:
+    HiResCounterHandler()
+        : hiResTicksOffset (0)
+    {
+        // This macro allows you to override the default timer-period
+        // used on Windows. By default this is set to 1, because that has
+        // always been the value used in JUCE apps, and changing it could
+        // affect the behaviour of existing code, but you may wish to make
+        // it larger (or set it to 0 to use the system default) to make your
+        // app less demanding on the CPU.
+        // For more info, see win32 documentation about the timeBeginPeriod
+        // function.
+       #ifndef JUCE_WIN32_TIMER_PERIOD
+        #define JUCE_WIN32_TIMER_PERIOD 1
+       #endif
+
+       #if JUCE_WIN32_TIMER_PERIOD > 0
+        const MMRESULT res = timeBeginPeriod (JUCE_WIN32_TIMER_PERIOD);
+        (void) res;
+        jassert (res == TIMERR_NOERROR);
+       #endif
+
+        LARGE_INTEGER f;
+        QueryPerformanceFrequency (&f);
+        hiResTicksPerSecond = f.QuadPart;
+        hiResTicksScaleFactor = 1000.0 / hiResTicksPerSecond;
+    }
+
+    inline int64 getHighResolutionTicks() noexcept
+    {
+        LARGE_INTEGER ticks;
+        QueryPerformanceCounter (&ticks);
+
+        const int64 mainCounterAsHiResTicks = (juce_millisecondsSinceStartup() * hiResTicksPerSecond) / 1000;
+        const int64 newOffset = mainCounterAsHiResTicks - ticks.QuadPart;
+
+        // fix for a very obscure PCI hardware bug that can make the counter
+        // sometimes jump forwards by a few seconds..
+        const int64 offsetDrift = abs64 (newOffset - hiResTicksOffset);
+
+        if (offsetDrift > (hiResTicksPerSecond >> 1))
+            hiResTicksOffset = newOffset;
+
+        return ticks.QuadPart + hiResTicksOffset;
+    }
+
+    inline double getMillisecondCounterHiRes() noexcept
+    {
+        return getHighResolutionTicks() * hiResTicksScaleFactor;
+    }
+
+    int64 hiResTicksPerSecond, hiResTicksOffset;
+    double hiResTicksScaleFactor;
+};
+
+static HiResCounterHandler hiResCounterHandler;
+
+int64  Time::getHighResolutionTicksPerSecond() noexcept  { return hiResCounterHandler.hiResTicksPerSecond; }
+int64  Time::getHighResolutionTicks() noexcept           { return hiResCounterHandler.getHighResolutionTicks(); }
+double Time::getMillisecondCounterHiRes() noexcept       { return hiResCounterHandler.getMillisecondCounterHiRes(); }
+
+//==============================================================================
+static int64 juce_getClockCycleCounter() noexcept
+{
+   #if JUCE_USE_INTRINSICS
+    // MS intrinsics version...
+    return (int64) __rdtsc();
+
+   #elif JUCE_GCC
+    // GNU inline asm version...
+    unsigned int hi = 0, lo = 0;
+
+    __asm__ __volatile__ (
+        "xor %%eax, %%eax               \n\
+         xor %%edx, %%edx               \n\
+         rdtsc                          \n\
+         movl %%eax, %[lo]              \n\
+         movl %%edx, %[hi]"
+         :
+         : [hi] "m" (hi),
+           [lo] "m" (lo)
+         : "cc", "eax", "ebx", "ecx", "edx", "memory");
+
+    return (int64) ((((uint64) hi) << 32) | lo);
+   #else
+    // MSVC inline asm version...
+    unsigned int hi = 0, lo = 0;
+
+    __asm
+    {
+        xor eax, eax
+        xor edx, edx
+        rdtsc
+        mov lo, eax
+        mov hi, edx
+    }
+
+    return (int64) ((((uint64) hi) << 32) | lo);
+   #endif
+}
+
+int SystemStats::getCpuSpeedInMegaherz()
+{
+    const int64 cycles = juce_getClockCycleCounter();
+    const uint32 millis = Time::getMillisecondCounter();
+    int lastResult = 0;
+
+    for (;;)
+    {
+        int n = 1000000;
+        while (--n > 0) {}
+
+        const uint32 millisElapsed = Time::getMillisecondCounter() - millis;
+        const int64 cyclesNow = juce_getClockCycleCounter();
+
+        if (millisElapsed > 80)
+        {
+            const int newResult = (int) (((cyclesNow - cycles) / millisElapsed) / 1000);
+
+            if (millisElapsed > 500 || (lastResult == newResult && newResult > 100))
+                return newResult;
+
+            lastResult = newResult;
+        }
+    }
+}
+
+
+//==============================================================================
+bool Time::setSystemTimeToThisTime() const
+{
+    SYSTEMTIME st;
+
+    st.wDayOfWeek = 0;
+    st.wYear           = (WORD) getYear();
+    st.wMonth          = (WORD) (getMonth() + 1);
+    st.wDay            = (WORD) getDayOfMonth();
+    st.wHour           = (WORD) getHours();
+    st.wMinute         = (WORD) getMinutes();
+    st.wSecond         = (WORD) getSeconds();
+    st.wMilliseconds   = (WORD) (millisSinceEpoch % 1000);
+
+    // do this twice because of daylight saving conversion problems - the
+    // first one sets it up, the second one kicks it in.
+    return SetLocalTime (&st) != 0
+            && SetLocalTime (&st) != 0;
+}
+
+int SystemStats::getPageSize()
+{
+    SYSTEM_INFO systemInfo;
+    GetNativeSystemInfo (&systemInfo);
+
+    return (int) systemInfo.dwPageSize;
+}
+
+//==============================================================================
+String SystemStats::getLogonName()
+{
+    TCHAR text [256] = { 0 };
+    DWORD len = (DWORD) numElementsInArray (text) - 1;
+    GetUserName (text, &len);
+    return String (text, len);
+}
+
+String SystemStats::getFullUserName()
+{
+    return getLogonName();
+}
+
+String SystemStats::getComputerName()
+{
+    TCHAR text [MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
+    DWORD len = (DWORD) numElementsInArray (text) - 1;
+    GetComputerName (text, &len);
+    return String (text, len);
+}
+
+static String getLocaleValue (LCID locale, LCTYPE key, const char* defaultValue)
+{
+    TCHAR buffer [256] = { 0 };
+    if (GetLocaleInfo (locale, key, buffer, 255) > 0)
+        return buffer;
+
+    return defaultValue;
+}
+
+String SystemStats::getUserLanguage()     { return getLocaleValue (LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME,  "en"); }
+String SystemStats::getUserRegion()       { return getLocaleValue (LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, "US"); }
+
+String SystemStats::getDisplayLanguage()
+{
+    DynamicLibrary dll ("kernel32.dll");
+    JUCE_LOAD_WINAPI_FUNCTION (dll, GetUserDefaultUILanguage, getUserDefaultUILanguage, LANGID, (void))
+
+    if (getUserDefaultUILanguage == nullptr)
+        return "en";
+
+    const DWORD langID = MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT);
+
+    String mainLang (getLocaleValue (langID, LOCALE_SISO639LANGNAME, "en"));
+    String region   (getLocaleValue (langID, LOCALE_SISO3166CTRYNAME, nullptr));
+
+    if (region.isNotEmpty())
+        mainLang << '-' << region;
+
+    return mainLang;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Threads.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Threads.cpp
new file mode 100644
index 0000000..4eb24e2
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/native/juce_win32_Threads.cpp
@@ -0,0 +1,625 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+HWND juce_messageWindowHandle = 0;  // (this is used by other parts of the codebase)
+
+void* getUser32Function (const char* functionName)
+{
+    HMODULE module = GetModuleHandleA ("user32.dll");
+    jassert (module != 0);
+    return (void*) GetProcAddress (module, functionName);
+}
+
+//==============================================================================
+#if ! JUCE_USE_INTRINSICS
+// In newer compilers, the inline versions of these are used (in juce_Atomic.h), but in
+// older ones we have to actually call the ops as win32 functions..
+long juce_InterlockedExchange (volatile long* a, long b) noexcept                { return InterlockedExchange (a, b); }
+long juce_InterlockedIncrement (volatile long* a) noexcept                       { return InterlockedIncrement (a); }
+long juce_InterlockedDecrement (volatile long* a) noexcept                       { return InterlockedDecrement (a); }
+long juce_InterlockedExchangeAdd (volatile long* a, long b) noexcept             { return InterlockedExchangeAdd (a, b); }
+long juce_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept { return InterlockedCompareExchange (a, b, c); }
+
+__int64 juce_InterlockedCompareExchange64 (volatile __int64* value, __int64 newValue, __int64 valueToCompare) noexcept
+{
+    jassertfalse; // This operation isn't available in old MS compiler versions!
+
+    __int64 oldValue = *value;
+    if (oldValue == valueToCompare)
+        *value = newValue;
+
+    return oldValue;
+}
+
+#endif
+
+//==============================================================================
+CriticalSection::CriticalSection() noexcept
+{
+    // (just to check the MS haven't changed this structure and broken things...)
+   #if JUCE_VC7_OR_EARLIER
+    static_jassert (sizeof (CRITICAL_SECTION) <= 24);
+   #else
+    static_jassert (sizeof (CRITICAL_SECTION) <= sizeof (lock));
+   #endif
+
+    InitializeCriticalSection ((CRITICAL_SECTION*) lock);
+}
+
+CriticalSection::~CriticalSection() noexcept        { DeleteCriticalSection ((CRITICAL_SECTION*) lock); }
+void CriticalSection::enter() const noexcept        { EnterCriticalSection ((CRITICAL_SECTION*) lock); }
+bool CriticalSection::tryEnter() const noexcept     { return TryEnterCriticalSection ((CRITICAL_SECTION*) lock) != FALSE; }
+void CriticalSection::exit() const noexcept         { LeaveCriticalSection ((CRITICAL_SECTION*) lock); }
+
+
+//==============================================================================
+WaitableEvent::WaitableEvent (const bool manualReset) noexcept
+    : handle (CreateEvent (0, manualReset ? TRUE : FALSE, FALSE, 0)) {}
+
+WaitableEvent::~WaitableEvent() noexcept        { CloseHandle (handle); }
+
+void WaitableEvent::signal() const noexcept     { SetEvent (handle); }
+void WaitableEvent::reset() const noexcept      { ResetEvent (handle); }
+
+bool WaitableEvent::wait (const int timeOutMs) const noexcept
+{
+    return WaitForSingleObject (handle, (DWORD) timeOutMs) == WAIT_OBJECT_0;
+}
+
+//==============================================================================
+void JUCE_API juce_threadEntryPoint (void*);
+
+static unsigned int __stdcall threadEntryProc (void* userData)
+{
+    if (juce_messageWindowHandle != 0)
+        AttachThreadInput (GetWindowThreadProcessId (juce_messageWindowHandle, 0),
+                           GetCurrentThreadId(), TRUE);
+
+    juce_threadEntryPoint (userData);
+
+    _endthreadex (0);
+    return 0;
+}
+
+void Thread::launchThread()
+{
+    unsigned int newThreadId;
+    threadHandle = (void*) _beginthreadex (0, 0, &threadEntryProc, this, 0, &newThreadId);
+    threadId = (ThreadID) newThreadId;
+}
+
+void Thread::closeThreadHandle()
+{
+    CloseHandle ((HANDLE) threadHandle);
+    threadId = 0;
+    threadHandle = 0;
+}
+
+void Thread::killThread()
+{
+    if (threadHandle != 0)
+    {
+       #if JUCE_DEBUG
+        OutputDebugStringA ("** Warning - Forced thread termination **\n");
+       #endif
+        TerminateThread (threadHandle, 0);
+    }
+}
+
+void JUCE_CALLTYPE Thread::setCurrentThreadName (const String& name)
+{
+   #if JUCE_DEBUG && JUCE_MSVC
+    struct
+    {
+        DWORD dwType;
+        LPCSTR szName;
+        DWORD dwThreadID;
+        DWORD dwFlags;
+    } info;
+
+    info.dwType = 0x1000;
+    info.szName = name.toUTF8();
+    info.dwThreadID = GetCurrentThreadId();
+    info.dwFlags = 0;
+
+    __try
+    {
+        RaiseException (0x406d1388 /*MS_VC_EXCEPTION*/, 0, sizeof (info) / sizeof (ULONG_PTR), (ULONG_PTR*) &info);
+    }
+    __except (EXCEPTION_CONTINUE_EXECUTION)
+    {}
+   #else
+    (void) name;
+   #endif
+}
+
+Thread::ThreadID JUCE_CALLTYPE Thread::getCurrentThreadId()
+{
+    return (ThreadID) (pointer_sized_int) GetCurrentThreadId();
+}
+
+bool Thread::setThreadPriority (void* handle, int priority)
+{
+    int pri = THREAD_PRIORITY_TIME_CRITICAL;
+
+    if (priority < 1)       pri = THREAD_PRIORITY_IDLE;
+    else if (priority < 2)  pri = THREAD_PRIORITY_LOWEST;
+    else if (priority < 5)  pri = THREAD_PRIORITY_BELOW_NORMAL;
+    else if (priority < 7)  pri = THREAD_PRIORITY_NORMAL;
+    else if (priority < 9)  pri = THREAD_PRIORITY_ABOVE_NORMAL;
+    else if (priority < 10) pri = THREAD_PRIORITY_HIGHEST;
+
+    if (handle == 0)
+        handle = GetCurrentThread();
+
+    return SetThreadPriority (handle, pri) != FALSE;
+}
+
+void JUCE_CALLTYPE Thread::setCurrentThreadAffinityMask (const uint32 affinityMask)
+{
+    SetThreadAffinityMask (GetCurrentThread(), affinityMask);
+}
+
+//==============================================================================
+struct SleepEvent
+{
+    SleepEvent() noexcept
+        : handle (CreateEvent (nullptr, FALSE, FALSE,
+                              #if JUCE_DEBUG
+                               _T("JUCE Sleep Event")))
+                              #else
+                               nullptr))
+                              #endif
+    {}
+
+    ~SleepEvent() noexcept
+    {
+        CloseHandle (handle);
+        handle = 0;
+    }
+
+    HANDLE handle;
+};
+
+static SleepEvent sleepEvent;
+
+void JUCE_CALLTYPE Thread::sleep (const int millisecs)
+{
+    jassert (millisecs >= 0);
+
+    if (millisecs >= 10 || sleepEvent.handle == 0)
+        Sleep ((DWORD) millisecs);
+    else
+        // unlike Sleep() this is guaranteed to return to the current thread after
+        // the time expires, so we'll use this for short waits, which are more likely
+        // to need to be accurate
+        WaitForSingleObject (sleepEvent.handle, (DWORD) millisecs);
+}
+
+void Thread::yield()
+{
+    Sleep (0);
+}
+
+//==============================================================================
+static int lastProcessPriority = -1;
+
+// called when the app gains focus because Windows does weird things to process priority
+// when you swap apps, and this forces an update when the app is brought to the front.
+void juce_repeatLastProcessPriority()
+{
+    if (lastProcessPriority >= 0) // (avoid changing this if it's not been explicitly set by the app..)
+    {
+        DWORD p;
+
+        switch (lastProcessPriority)
+        {
+            case Process::LowPriority:          p = IDLE_PRIORITY_CLASS; break;
+            case Process::NormalPriority:       p = NORMAL_PRIORITY_CLASS; break;
+            case Process::HighPriority:         p = HIGH_PRIORITY_CLASS; break;
+            case Process::RealtimePriority:     p = REALTIME_PRIORITY_CLASS; break;
+            default:                            jassertfalse; return; // bad priority value
+        }
+
+        SetPriorityClass (GetCurrentProcess(), p);
+    }
+}
+
+void JUCE_CALLTYPE Process::setPriority (ProcessPriority prior)
+{
+    if (lastProcessPriority != (int) prior)
+    {
+        lastProcessPriority = (int) prior;
+        juce_repeatLastProcessPriority();
+    }
+}
+
+JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
+{
+    return IsDebuggerPresent() != FALSE;
+}
+
+bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
+{
+    return juce_isRunningUnderDebugger();
+}
+
+static void* currentModuleHandle = nullptr;
+
+void* JUCE_CALLTYPE Process::getCurrentModuleInstanceHandle() noexcept
+{
+    if (currentModuleHandle == nullptr)
+        currentModuleHandle = GetModuleHandleA (nullptr);
+
+    return currentModuleHandle;
+}
+
+void JUCE_CALLTYPE Process::setCurrentModuleInstanceHandle (void* const newHandle) noexcept
+{
+    currentModuleHandle = newHandle;
+}
+
+void JUCE_CALLTYPE Process::raisePrivilege()
+{
+    jassertfalse; // xxx not implemented
+}
+
+void JUCE_CALLTYPE Process::lowerPrivilege()
+{
+    jassertfalse; // xxx not implemented
+}
+
+void JUCE_CALLTYPE Process::terminate()
+{
+   #if JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS
+    _CrtDumpMemoryLeaks();
+   #endif
+
+    // bullet in the head in case there's a problem shutting down..
+    ExitProcess (1);
+}
+
+bool juce_isRunningInWine()
+{
+    HMODULE ntdll = GetModuleHandleA ("ntdll");
+    return ntdll != 0 && GetProcAddress (ntdll, "wine_get_version") != nullptr;
+}
+
+//==============================================================================
+bool DynamicLibrary::open (const String& name)
+{
+    close();
+
+    JUCE_TRY
+    {
+        handle = LoadLibrary (name.toWideCharPointer());
+    }
+    JUCE_CATCH_ALL
+
+    return handle != nullptr;
+}
+
+void DynamicLibrary::close()
+{
+    JUCE_TRY
+    {
+        if (handle != nullptr)
+        {
+            FreeLibrary ((HMODULE) handle);
+            handle = nullptr;
+        }
+    }
+    JUCE_CATCH_ALL
+}
+
+void* DynamicLibrary::getFunction (const String& functionName) noexcept
+{
+    return handle != nullptr ? (void*) GetProcAddress ((HMODULE) handle, functionName.toUTF8()) // (void* cast is required for mingw)
+                             : nullptr;
+}
+
+
+//==============================================================================
+class InterProcessLock::Pimpl
+{
+public:
+    Pimpl (String name, const int timeOutMillisecs)
+        : handle (0), refCount (1)
+    {
+        name = name.replaceCharacter ('\\', '/');
+        handle = CreateMutexW (0, TRUE, ("Global\\" + name).toWideCharPointer());
+
+        // Not 100% sure why a global mutex sometimes can't be allocated, but if it fails, fall back to
+        // a local one. (A local one also sometimes fails on other machines so neither type appears to be
+        // universally reliable)
+        if (handle == 0)
+            handle = CreateMutexW (0, TRUE, ("Local\\" + name).toWideCharPointer());
+
+        if (handle != 0 && GetLastError() == ERROR_ALREADY_EXISTS)
+        {
+            if (timeOutMillisecs == 0)
+            {
+                close();
+                return;
+            }
+
+            switch (WaitForSingleObject (handle, timeOutMillisecs < 0 ? INFINITE : timeOutMillisecs))
+            {
+                case WAIT_OBJECT_0:
+                case WAIT_ABANDONED:
+                    break;
+
+                case WAIT_TIMEOUT:
+                default:
+                    close();
+                    break;
+            }
+        }
+    }
+
+    ~Pimpl()
+    {
+        close();
+    }
+
+    void close()
+    {
+        if (handle != 0)
+        {
+            ReleaseMutex (handle);
+            CloseHandle (handle);
+            handle = 0;
+        }
+    }
+
+    HANDLE handle;
+    int refCount;
+};
+
+InterProcessLock::InterProcessLock (const String& name_)
+    : name (name_)
+{
+}
+
+InterProcessLock::~InterProcessLock()
+{
+}
+
+bool InterProcessLock::enter (const int timeOutMillisecs)
+{
+    const ScopedLock sl (lock);
+
+    if (pimpl == nullptr)
+    {
+        pimpl = new Pimpl (name, timeOutMillisecs);
+
+        if (pimpl->handle == 0)
+            pimpl = nullptr;
+    }
+    else
+    {
+        pimpl->refCount++;
+    }
+
+    return pimpl != nullptr;
+}
+
+void InterProcessLock::exit()
+{
+    const ScopedLock sl (lock);
+
+    // Trying to release the lock too many times!
+    jassert (pimpl != nullptr);
+
+    if (pimpl != nullptr && --(pimpl->refCount) == 0)
+        pimpl = nullptr;
+}
+
+//==============================================================================
+class ChildProcess::ActiveProcess
+{
+public:
+    ActiveProcess (const String& command, int streamFlags)
+        : ok (false), readPipe (0), writePipe (0)
+    {
+        SECURITY_ATTRIBUTES securityAtts = { 0 };
+        securityAtts.nLength = sizeof (securityAtts);
+        securityAtts.bInheritHandle = TRUE;
+
+        if (CreatePipe (&readPipe, &writePipe, &securityAtts, 0)
+             && SetHandleInformation (readPipe, HANDLE_FLAG_INHERIT, 0))
+        {
+            STARTUPINFOW startupInfo = { 0 };
+            startupInfo.cb = sizeof (startupInfo);
+
+            startupInfo.hStdOutput = (streamFlags | wantStdOut) != 0 ? writePipe : 0;
+            startupInfo.hStdError  = (streamFlags | wantStdErr) != 0 ? writePipe : 0;
+            startupInfo.dwFlags = STARTF_USESTDHANDLES;
+
+            ok = CreateProcess (nullptr, const_cast <LPWSTR> (command.toWideCharPointer()),
+                                nullptr, nullptr, TRUE, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
+                                nullptr, nullptr, &startupInfo, &processInfo) != FALSE;
+        }
+    }
+
+    ~ActiveProcess()
+    {
+        if (ok)
+        {
+            CloseHandle (processInfo.hThread);
+            CloseHandle (processInfo.hProcess);
+        }
+
+        if (readPipe != 0)
+            CloseHandle (readPipe);
+
+        if (writePipe != 0)
+            CloseHandle (writePipe);
+    }
+
+    bool isRunning() const noexcept
+    {
+        return WaitForSingleObject (processInfo.hProcess, 0) != WAIT_OBJECT_0;
+    }
+
+    int read (void* dest, int numNeeded) const noexcept
+    {
+        int total = 0;
+
+        while (ok && numNeeded > 0)
+        {
+            DWORD available = 0;
+
+            if (! PeekNamedPipe ((HANDLE) readPipe, nullptr, 0, nullptr, &available, nullptr))
+                break;
+
+            const int numToDo = jmin ((int) available, numNeeded);
+
+            if (available == 0)
+            {
+                if (! isRunning())
+                    break;
+
+                Thread::yield();
+            }
+            else
+            {
+                DWORD numRead = 0;
+                if (! ReadFile ((HANDLE) readPipe, dest, numToDo, &numRead, nullptr))
+                    break;
+
+                total += numRead;
+                dest = addBytesToPointer (dest, numRead);
+                numNeeded -= numRead;
+            }
+        }
+
+        return total;
+    }
+
+    bool killProcess() const noexcept
+    {
+        return TerminateProcess (processInfo.hProcess, 0) != FALSE;
+    }
+
+    uint32 getExitCode() const noexcept
+    {
+        DWORD exitCode = 0;
+        GetExitCodeProcess (processInfo.hProcess, &exitCode);
+        return (uint32) exitCode;
+    }
+
+    bool ok;
+
+private:
+    HANDLE readPipe, writePipe;
+    PROCESS_INFORMATION processInfo;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ActiveProcess)
+};
+
+bool ChildProcess::start (const String& command, int streamFlags)
+{
+    activeProcess = new ActiveProcess (command, streamFlags);
+
+    if (! activeProcess->ok)
+        activeProcess = nullptr;
+
+    return activeProcess != nullptr;
+}
+
+bool ChildProcess::start (const StringArray& args, int streamFlags)
+{
+    String escaped;
+
+    for (int i = 0; i < args.size(); ++i)
+    {
+        String arg (args[i]);
+
+        // If there are spaces, surround it with quotes. If there are quotes,
+        // replace them with \" so that CommandLineToArgv will correctly parse them.
+        if (arg.containsAnyOf ("\" "))
+            arg = arg.replace ("\"", "\\\"").quoted();
+
+        escaped << arg << ' ';
+    }
+
+    return start (escaped.trim(), streamFlags);
+}
+
+//==============================================================================
+struct HighResolutionTimer::Pimpl
+{
+    Pimpl (HighResolutionTimer& t) noexcept  : owner (t), periodMs (0)
+    {
+    }
+
+    ~Pimpl()
+    {
+        jassert (periodMs == 0);
+    }
+
+    void start (int newPeriod)
+    {
+        if (newPeriod != periodMs)
+        {
+            stop();
+            periodMs = newPeriod;
+
+            TIMECAPS tc;
+            if (timeGetDevCaps (&tc, sizeof (tc)) == TIMERR_NOERROR)
+            {
+                const int actualPeriod = jlimit ((int) tc.wPeriodMin, (int) tc.wPeriodMax, newPeriod);
+
+                timerID = timeSetEvent (actualPeriod, tc.wPeriodMin, callbackFunction, (DWORD_PTR) this,
+                                        TIME_PERIODIC | TIME_CALLBACK_FUNCTION | 0x100 /*TIME_KILL_SYNCHRONOUS*/);
+            }
+        }
+    }
+
+    void stop()
+    {
+        periodMs = 0;
+        timeKillEvent (timerID);
+    }
+
+    HighResolutionTimer& owner;
+    int periodMs;
+
+private:
+    unsigned int timerID;
+
+    static void __stdcall callbackFunction (UINT, UINT, DWORD_PTR userInfo, DWORD_PTR, DWORD_PTR)
+    {
+        if (Pimpl* const timer = reinterpret_cast<Pimpl*> (userInfo))
+            if (timer->periodMs != 0)
+                timer->owner.hiResTimerCallback();
+    }
+
+    JUCE_DECLARE_NON_COPYABLE (Pimpl)
+};
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_IPAddress.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_IPAddress.cpp
new file mode 100644
index 0000000..6c4d087
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_IPAddress.cpp
@@ -0,0 +1,149 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+IPAddress::IPAddress() noexcept
+{
+    address[0] = 0;  address[1] = 0;
+    address[2] = 0;  address[3] = 0;
+}
+
+IPAddress::IPAddress (const uint8 bytes[4]) noexcept
+{
+    address[0] = bytes[0];  address[1] = bytes[1];
+    address[2] = bytes[2];  address[3] = bytes[3];
+}
+
+IPAddress::IPAddress (uint8 a0, uint8 a1, uint8 a2, uint8 a3) noexcept
+{
+    address[0] = a0;  address[1] = a1;
+    address[2] = a2;  address[3] = a3;
+}
+
+IPAddress::IPAddress (uint32 n) noexcept
+{
+    address[0] = (n >> 24);
+    address[1] = (n >> 16) & 255;
+    address[2] = (n >> 8)  & 255;
+    address[3] = (n & 255);
+}
+
+IPAddress::IPAddress (const String& adr)
+{
+    StringArray tokens;
+    tokens.addTokens (adr, ".", String());
+
+    for (int i = 0; i < 4; ++i)
+        address[i] = (uint8) tokens[i].getIntValue();
+}
+
+String IPAddress::toString() const
+{
+    String s ((int) address[0]);
+
+    for (int i = 1; i < 4; ++i)
+        s << '.' << (int) address[i];
+
+    return s;
+}
+
+IPAddress IPAddress::any() noexcept           { return IPAddress(); }
+IPAddress IPAddress::broadcast() noexcept     { return IPAddress (255, 255, 255, 255); }
+IPAddress IPAddress::local() noexcept         { return IPAddress (127, 0, 0, 1); }
+
+bool IPAddress::operator== (const IPAddress& other) const noexcept
+{
+    return address[0] == other.address[0]
+        && address[1] == other.address[1]
+        && address[2] == other.address[2]
+        && address[3] == other.address[3];
+}
+
+bool IPAddress::operator!= (const IPAddress& other) const noexcept
+{
+    return ! operator== (other);
+}
+
+#if ! JUCE_WINDOWS
+static void addAddress (const sockaddr_in* addr_in, Array<IPAddress>& result)
+{
+    in_addr_t addr = addr_in->sin_addr.s_addr;
+
+    if (addr != INADDR_NONE)
+        result.addIfNotAlreadyThere (IPAddress (ntohl (addr)));
+}
+
+static void findIPAddresses (int sock, Array<IPAddress>& result)
+{
+    ifconf cfg;
+    HeapBlock<char> buffer;
+    int bufferSize = 1024;
+
+    do
+    {
+        bufferSize *= 2;
+        buffer.calloc ((size_t) bufferSize);
+
+        cfg.ifc_len = bufferSize;
+        cfg.ifc_buf = buffer;
+
+        if (ioctl (sock, SIOCGIFCONF, &cfg) < 0 && errno != EINVAL)
+            return;
+
+    } while (bufferSize < cfg.ifc_len + 2 * (int) (IFNAMSIZ + sizeof (struct sockaddr_in6)));
+
+   #if JUCE_MAC || JUCE_IOS
+    while (cfg.ifc_len >= (int) (IFNAMSIZ + sizeof (struct sockaddr_in)))
+    {
+        if (cfg.ifc_req->ifr_addr.sa_family == AF_INET) // Skip non-internet addresses
+            addAddress ((const sockaddr_in*) &cfg.ifc_req->ifr_addr, result);
+
+        cfg.ifc_len -= IFNAMSIZ + cfg.ifc_req->ifr_addr.sa_len;
+        cfg.ifc_buf += IFNAMSIZ + cfg.ifc_req->ifr_addr.sa_len;
+    }
+   #else
+    for (size_t i = 0; i < cfg.ifc_len / sizeof (struct ifreq); ++i)
+    {
+        const ifreq& item = cfg.ifc_req[i];
+
+        if (item.ifr_addr.sa_family == AF_INET)
+            addAddress ((const sockaddr_in*) &item.ifr_addr, result);
+    }
+   #endif
+}
+
+void IPAddress::findAllAddresses (Array<IPAddress>& result)
+{
+    const int sock = socket (AF_INET, SOCK_DGRAM, 0); // a dummy socket to execute the IO control
+
+    if (sock >= 0)
+    {
+        findIPAddresses (sock, result);
+        ::close (sock);
+    }
+}
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_IPAddress.h b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_IPAddress.h
new file mode 100644
index 0000000..1f2f0e8
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_IPAddress.h
@@ -0,0 +1,82 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_IPADDRESS_H_INCLUDED
+#define JUCE_IPADDRESS_H_INCLUDED
+
+
+//==============================================================================
+/**
+    An IPV4 address.
+*/
+class JUCE_API  IPAddress
+{
+public:
+    //==============================================================================
+    /** Populates a list of all the IP addresses that this machine is using. */
+    static void findAllAddresses (Array<IPAddress>& results);
+
+    //==============================================================================
+    /** Creates a null address (0.0.0.0). */
+    IPAddress() noexcept;
+
+    /** Creates an address from 4 bytes. */
+    explicit IPAddress (const uint8 bytes[4]) noexcept;
+
+    /** Creates an address from 4 bytes. */
+    IPAddress (uint8 address1, uint8 address2, uint8 address3, uint8 address4) noexcept;
+
+    /** Creates an address from a packed 32-bit integer, where the MSB is
+        the first number in the address, and the LSB is the last.
+    */
+    explicit IPAddress (uint32 asNativeEndian32Bit) noexcept;
+
+    /** Parses a string IP address of the form "a.b.c.d". */
+    explicit IPAddress (const String& address);
+
+    /** Returns a dot-separated string in the form "1.2.3.4" */
+    String toString() const;
+
+    /** Returns an address meaning "any" (0.0.0.0) */
+    static IPAddress any() noexcept;
+
+    /** Returns an address meaning "broadcast" (255.255.255.255) */
+    static IPAddress broadcast() noexcept;
+
+    /** Returns an address meaning "localhost" (127.0.0.1) */
+    static IPAddress local() noexcept;
+
+    bool operator== (const IPAddress& other) const noexcept;
+    bool operator!= (const IPAddress& other) const noexcept;
+
+    /** The elements of the IP address. */
+    uint8 address[4];
+};
+
+
+#endif   // JUCE_IPADDRESS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_MACAddress.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_MACAddress.cpp
new file mode 100644
index 0000000..b7cb3c1
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_MACAddress.cpp
@@ -0,0 +1,78 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+MACAddress::MACAddress()
+{
+    zeromem (address, sizeof (address));
+}
+
+MACAddress::MACAddress (const MACAddress& other)
+{
+    memcpy (address, other.address, sizeof (address));
+}
+
+MACAddress& MACAddress::operator= (const MACAddress& other)
+{
+    memcpy (address, other.address, sizeof (address));
+    return *this;
+}
+
+MACAddress::MACAddress (const uint8 bytes[6])
+{
+    memcpy (address, bytes, sizeof (address));
+}
+
+String MACAddress::toString() const
+{
+    String s;
+
+    for (size_t i = 0; i < sizeof (address); ++i)
+    {
+        s << String::toHexString ((int) address[i]).paddedLeft ('0', 2);
+
+        if (i < sizeof (address) - 1)
+            s << '-';
+    }
+
+    return s;
+}
+
+int64 MACAddress::toInt64() const noexcept
+{
+    int64 n = 0;
+
+    for (int i = (int) sizeof (address); --i >= 0;)
+        n = (n << 8) | address[i];
+
+    return n;
+}
+
+bool MACAddress::isNull() const noexcept                                { return toInt64() == 0; }
+
+bool MACAddress::operator== (const MACAddress& other) const noexcept    { return memcmp (address, other.address, sizeof (address)) == 0; }
+bool MACAddress::operator!= (const MACAddress& other) const noexcept    { return ! operator== (other); }
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_MACAddress.h b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_MACAddress.h
new file mode 100644
index 0000000..67e119e
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_MACAddress.h
@@ -0,0 +1,82 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_MACADDRESS_H_INCLUDED
+#define JUCE_MACADDRESS_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Represents a MAC network card adapter address ID.
+*/
+class JUCE_API  MACAddress
+{
+public:
+    //==============================================================================
+    /** Populates a list of the MAC addresses of all the available network cards. */
+    static void findAllAddresses (Array<MACAddress>& results);
+
+    //==============================================================================
+    /** Creates a null address (00-00-00-00-00-00). */
+    MACAddress();
+
+    /** Creates a copy of another address. */
+    MACAddress (const MACAddress&);
+
+    /** Creates a copy of another address. */
+    MACAddress& operator= (const MACAddress&);
+
+    /** Creates an address from 6 bytes. */
+    explicit MACAddress (const uint8 bytes[6]);
+
+    /** Returns a pointer to the 6 bytes that make up this address. */
+    const uint8* getBytes() const noexcept        { return address; }
+
+    /** Returns a dash-separated string in the form "11-22-33-44-55-66" */
+    String toString() const;
+
+    /** Returns the address in the lower 6 bytes of an int64.
+
+        This uses a little-endian arrangement, with the first byte of the address being
+        stored in the least-significant byte of the result value.
+    */
+    int64 toInt64() const noexcept;
+
+    /** Returns true if this address is null (00-00-00-00-00-00). */
+    bool isNull() const noexcept;
+
+    bool operator== (const MACAddress&) const noexcept;
+    bool operator!= (const MACAddress&) const noexcept;
+
+    //==============================================================================
+private:
+    uint8 address[6];
+};
+
+
+#endif   // JUCE_MACADDRESS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_NamedPipe.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_NamedPipe.cpp
new file mode 100644
index 0000000..488e63f
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_NamedPipe.cpp
@@ -0,0 +1,66 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+NamedPipe::NamedPipe()
+{
+}
+
+NamedPipe::~NamedPipe()
+{
+    close();
+}
+
+bool NamedPipe::openExisting (const String& pipeName)
+{
+    close();
+
+    ScopedWriteLock sl (lock);
+    currentPipeName = pipeName;
+    return openInternal (pipeName, false);
+}
+
+bool NamedPipe::isOpen() const
+{
+    return pimpl != nullptr;
+}
+
+bool NamedPipe::createNewPipe (const String& pipeName)
+{
+    close();
+
+    ScopedWriteLock sl (lock);
+    currentPipeName = pipeName;
+    return openInternal (pipeName, true);
+}
+
+String NamedPipe::getName() const
+{
+    return currentPipeName;
+}
+
+// other methods for this class are implemented in the platform-specific files
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_NamedPipe.h b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_NamedPipe.h
new file mode 100644
index 0000000..d2029bd
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_NamedPipe.h
@@ -0,0 +1,104 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_NAMEDPIPE_H_INCLUDED
+#define JUCE_NAMEDPIPE_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A cross-process pipe that can have data written to and read from it.
+
+    Two processes can use NamedPipe objects to exchange blocks of data.
+
+    @see InterprocessConnection
+*/
+class JUCE_API  NamedPipe
+{
+public:
+    //==============================================================================
+    /** Creates a NamedPipe. */
+    NamedPipe();
+
+    /** Destructor. */
+    ~NamedPipe();
+
+    //==============================================================================
+    /** Tries to open a pipe that already exists.
+        Returns true if it succeeds.
+    */
+    bool openExisting (const String& pipeName);
+
+    /** Tries to create a new pipe.
+        Returns true if it succeeds.
+    */
+    bool createNewPipe (const String& pipeName);
+
+    /** Closes the pipe, if it's open. */
+    void close();
+
+    /** True if the pipe is currently open. */
+    bool isOpen() const;
+
+    /** Returns the last name that was used to try to open this pipe. */
+    String getName() const;
+
+    //==============================================================================
+    /** Reads data from the pipe.
+
+        This will block until another thread has written enough data into the pipe to fill
+        the number of bytes specified, or until another thread calls the cancelPendingReads()
+        method.
+
+        If the operation fails, it returns -1, otherwise, it will return the number of
+        bytes read.
+
+        If timeOutMilliseconds is less than zero, it will wait indefinitely, otherwise
+        this is a maximum timeout for reading from the pipe.
+    */
+    int read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds);
+
+    /** Writes some data to the pipe.
+        @returns the number of bytes written, or -1 on failure.
+    */
+    int write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds);
+
+private:
+    //==============================================================================
+    JUCE_PUBLIC_IN_DLL_BUILD (class Pimpl)
+    ScopedPointer<Pimpl> pimpl;
+    String currentPipeName;
+    ReadWriteLock lock;
+
+    bool openInternal (const String& pipeName, const bool createPipe);
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NamedPipe)
+};
+
+
+#endif   // JUCE_NAMEDPIPE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_Socket.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_Socket.cpp
new file mode 100644
index 0000000..97d0e0f
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_Socket.cpp
@@ -0,0 +1,593 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#if JUCE_MSVC
+ #pragma warning (push)
+ #pragma warning (disable : 4127 4389 4018)
+#endif
+
+#ifndef AI_NUMERICSERV  // (missing in older Mac SDKs)
+ #define AI_NUMERICSERV 0x1000
+#endif
+
+#if JUCE_WINDOWS
+ typedef int       juce_socklen_t;
+ typedef SOCKET    SocketHandle;
+#else
+ typedef socklen_t juce_socklen_t;
+ typedef int       SocketHandle;
+#endif
+
+//==============================================================================
+namespace SocketHelpers
+{
+    static void initSockets()
+    {
+       #if JUCE_WINDOWS
+        static bool socketsStarted = false;
+
+        if (! socketsStarted)
+        {
+            socketsStarted = true;
+
+            WSADATA wsaData;
+            const WORD wVersionRequested = MAKEWORD (1, 1);
+            WSAStartup (wVersionRequested, &wsaData);
+        }
+       #endif
+    }
+
+    static bool resetSocketOptions (const SocketHandle handle, const bool isDatagram, const bool allowBroadcast) noexcept
+    {
+        const int sndBufSize = 65536;
+        const int rcvBufSize = 65536;
+        const int one = 1;
+
+        return handle > 0
+                && setsockopt (handle, SOL_SOCKET, SO_RCVBUF, (const char*) &rcvBufSize, sizeof (rcvBufSize)) == 0
+                && setsockopt (handle, SOL_SOCKET, SO_SNDBUF, (const char*) &sndBufSize, sizeof (sndBufSize)) == 0
+                && (isDatagram ? ((! allowBroadcast) || setsockopt (handle, SOL_SOCKET, SO_BROADCAST, (const char*) &one, sizeof (one)) == 0)
+                               : (setsockopt (handle, IPPROTO_TCP, TCP_NODELAY, (const char*) &one, sizeof (one)) == 0));
+    }
+
+    static bool bindSocketToPort (const SocketHandle handle, const int port) noexcept
+    {
+        if (handle <= 0 || port <= 0)
+            return false;
+
+        struct sockaddr_in servTmpAddr;
+        zerostruct (servTmpAddr); // (can't use "= { 0 }" on this object because it's typedef'ed as a C struct)
+        servTmpAddr.sin_family = PF_INET;
+        servTmpAddr.sin_addr.s_addr = htonl (INADDR_ANY);
+        servTmpAddr.sin_port = htons ((uint16) port);
+
+        return bind (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) >= 0;
+    }
+
+    static int readSocket (const SocketHandle handle,
+                           void* const destBuffer, const int maxBytesToRead,
+                           bool volatile& connected,
+                           const bool blockUntilSpecifiedAmountHasArrived) noexcept
+    {
+        int bytesRead = 0;
+
+        while (bytesRead < maxBytesToRead)
+        {
+            int bytesThisTime;
+
+           #if JUCE_WINDOWS
+            bytesThisTime = recv (handle, static_cast<char*> (destBuffer) + bytesRead, maxBytesToRead - bytesRead, 0);
+           #else
+            while ((bytesThisTime = (int) ::read (handle, addBytesToPointer (destBuffer, bytesRead),
+                                                  (size_t) (maxBytesToRead - bytesRead))) < 0
+                     && errno == EINTR
+                     && connected)
+            {
+            }
+           #endif
+
+            if (bytesThisTime <= 0 || ! connected)
+            {
+                if (bytesRead == 0)
+                    bytesRead = -1;
+
+                break;
+            }
+
+            bytesRead += bytesThisTime;
+
+            if (! blockUntilSpecifiedAmountHasArrived)
+                break;
+        }
+
+        return bytesRead;
+    }
+
+    static int waitForReadiness (const SocketHandle handle, const bool forReading, const int timeoutMsecs) noexcept
+    {
+        struct timeval timeout;
+        struct timeval* timeoutp;
+
+        if (timeoutMsecs >= 0)
+        {
+            timeout.tv_sec = timeoutMsecs / 1000;
+            timeout.tv_usec = (timeoutMsecs % 1000) * 1000;
+            timeoutp = &timeout;
+        }
+        else
+        {
+            timeoutp = 0;
+        }
+
+        fd_set rset, wset;
+        FD_ZERO (&rset);
+        FD_SET (handle, &rset);
+        FD_ZERO (&wset);
+        FD_SET (handle, &wset);
+
+        fd_set* const prset = forReading ? &rset : nullptr;
+        fd_set* const pwset = forReading ? nullptr : &wset;
+
+       #if JUCE_WINDOWS
+        if (select ((int) handle + 1, prset, pwset, 0, timeoutp) < 0)
+            return -1;
+       #else
+        {
+            int result;
+            while ((result = select (handle + 1, prset, pwset, 0, timeoutp)) < 0
+                    && errno == EINTR)
+            {
+            }
+
+            if (result < 0)
+                return -1;
+        }
+       #endif
+
+        {
+            int opt;
+            juce_socklen_t len = sizeof (opt);
+
+            if (getsockopt (handle, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0
+                 || opt != 0)
+                return -1;
+        }
+
+        return FD_ISSET (handle, forReading ? &rset : &wset) ? 1 : 0;
+    }
+
+    static bool setSocketBlockingState (const SocketHandle handle, const bool shouldBlock) noexcept
+    {
+       #if JUCE_WINDOWS
+        u_long nonBlocking = shouldBlock ? 0 : (u_long) 1;
+        return ioctlsocket (handle, FIONBIO, &nonBlocking) == 0;
+       #else
+        int socketFlags = fcntl (handle, F_GETFL, 0);
+
+        if (socketFlags == -1)
+            return false;
+
+        if (shouldBlock)
+            socketFlags &= ~O_NONBLOCK;
+        else
+            socketFlags |= O_NONBLOCK;
+
+        return fcntl (handle, F_SETFL, socketFlags) == 0;
+       #endif
+    }
+
+    static bool connectSocket (int volatile& handle,
+                               const bool isDatagram,
+                               struct addrinfo** const serverAddress,
+                               const String& hostName,
+                               const int portNumber,
+                               const int timeOutMillisecs) noexcept
+    {
+        struct addrinfo hints;
+        zerostruct (hints);
+
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_socktype = isDatagram ? SOCK_DGRAM : SOCK_STREAM;
+        hints.ai_flags = AI_NUMERICSERV;
+
+        struct addrinfo* info = nullptr;
+        if (getaddrinfo (hostName.toUTF8(), String (portNumber).toUTF8(), &hints, &info) != 0
+             || info == nullptr)
+            return false;
+
+        if (handle < 0)
+            handle = (int) socket (info->ai_family, info->ai_socktype, 0);
+
+        if (handle < 0)
+        {
+            freeaddrinfo (info);
+            return false;
+        }
+
+        if (isDatagram)
+        {
+            if (*serverAddress != nullptr)
+                freeaddrinfo (*serverAddress);
+
+            *serverAddress = info;
+            return true;
+        }
+
+        setSocketBlockingState (handle, false);
+        const int result = ::connect (handle, info->ai_addr, (socklen_t) info->ai_addrlen);
+        freeaddrinfo (info);
+
+        if (result < 0)
+        {
+           #if JUCE_WINDOWS
+            if (result == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
+           #else
+            if (errno == EINPROGRESS)
+           #endif
+            {
+                if (waitForReadiness (handle, false, timeOutMillisecs) != 1)
+                {
+                    setSocketBlockingState (handle, true);
+                    return false;
+                }
+            }
+        }
+
+        setSocketBlockingState (handle, true);
+        resetSocketOptions (handle, false, false);
+
+        return true;
+    }
+}
+
+//==============================================================================
+StreamingSocket::StreamingSocket()
+    : portNumber (0),
+      handle (-1),
+      connected (false),
+      isListener (false)
+{
+    SocketHelpers::initSockets();
+}
+
+StreamingSocket::StreamingSocket (const String& host, int portNum, int h)
+    : hostName (host),
+      portNumber (portNum),
+      handle (h),
+      connected (true),
+      isListener (false)
+{
+    SocketHelpers::initSockets();
+    SocketHelpers::resetSocketOptions (h, false, false);
+}
+
+StreamingSocket::~StreamingSocket()
+{
+    close();
+}
+
+//==============================================================================
+int StreamingSocket::read (void* destBuffer, const int maxBytesToRead,
+                           const bool blockUntilSpecifiedAmountHasArrived)
+{
+    return (connected && ! isListener) ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead,
+                                                                    connected, blockUntilSpecifiedAmountHasArrived)
+                                       : -1;
+}
+
+int StreamingSocket::write (const void* sourceBuffer, const int numBytesToWrite)
+{
+    if (isListener || ! connected)
+        return -1;
+
+   #if JUCE_WINDOWS
+    return send (handle, (const char*) sourceBuffer, numBytesToWrite, 0);
+   #else
+    int result;
+
+    while ((result = (int) ::write (handle, sourceBuffer, (size_t) numBytesToWrite)) < 0
+            && errno == EINTR)
+    {
+    }
+
+    return result;
+   #endif
+}
+
+//==============================================================================
+int StreamingSocket::waitUntilReady (const bool readyForReading,
+                                     const int timeoutMsecs) const
+{
+    return connected ? SocketHelpers::waitForReadiness (handle, readyForReading, timeoutMsecs)
+                     : -1;
+}
+
+//==============================================================================
+bool StreamingSocket::bindToPort (const int port)
+{
+    return SocketHelpers::bindSocketToPort (handle, port);
+}
+
+bool StreamingSocket::connect (const String& remoteHostName,
+                               const int remotePortNumber,
+                               const int timeOutMillisecs)
+{
+    if (isListener)
+    {
+        jassertfalse;    // a listener socket can't connect to another one!
+        return false;
+    }
+
+    if (connected)
+        close();
+
+    hostName = remoteHostName;
+    portNumber = remotePortNumber;
+    isListener = false;
+
+    connected = SocketHelpers::connectSocket (handle, false, nullptr, remoteHostName,
+                                              remotePortNumber, timeOutMillisecs);
+
+    if (! (connected && SocketHelpers::resetSocketOptions (handle, false, false)))
+    {
+        close();
+        return false;
+    }
+
+    return true;
+}
+
+void StreamingSocket::close()
+{
+   #if JUCE_WINDOWS
+    if (handle != SOCKET_ERROR || connected)
+        closesocket (handle);
+
+    connected = false;
+   #else
+    if (connected)
+    {
+        connected = false;
+
+        if (isListener)
+        {
+            // need to do this to interrupt the accept() function..
+            StreamingSocket temp;
+            temp.connect (IPAddress::local().toString(), portNumber, 1000);
+        }
+    }
+
+    if (handle != -1)
+        ::close (handle);
+   #endif
+
+    hostName.clear();
+    portNumber = 0;
+    handle = -1;
+    isListener = false;
+}
+
+//==============================================================================
+bool StreamingSocket::createListener (const int newPortNumber, const String& localHostName)
+{
+    if (connected)
+        close();
+
+    hostName = "listener";
+    portNumber = newPortNumber;
+    isListener = true;
+
+    struct sockaddr_in servTmpAddr;
+    zerostruct (servTmpAddr);
+
+    servTmpAddr.sin_family = PF_INET;
+    servTmpAddr.sin_addr.s_addr = htonl (INADDR_ANY);
+
+    if (localHostName.isNotEmpty())
+        servTmpAddr.sin_addr.s_addr = ::inet_addr (localHostName.toUTF8());
+
+    servTmpAddr.sin_port = htons ((uint16) portNumber);
+
+    handle = (int) socket (AF_INET, SOCK_STREAM, 0);
+
+    if (handle < 0)
+        return false;
+
+    const int reuse = 1;
+    setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuse, sizeof (reuse));
+
+    if (bind (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) < 0
+         || listen (handle, SOMAXCONN) < 0)
+    {
+        close();
+        return false;
+    }
+
+    connected = true;
+    return true;
+}
+
+StreamingSocket* StreamingSocket::waitForNextConnection() const
+{
+    // To call this method, you first have to use createListener() to
+    // prepare this socket as a listener.
+    jassert (isListener || ! connected);
+
+    if (connected && isListener)
+    {
+        struct sockaddr_storage address;
+        juce_socklen_t len = sizeof (address);
+        const int newSocket = (int) accept (handle, (struct sockaddr*) &address, &len);
+
+        if (newSocket >= 0 && connected)
+            return new StreamingSocket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr),
+                                        portNumber, newSocket);
+    }
+
+    return nullptr;
+}
+
+bool StreamingSocket::isLocal() const noexcept
+{
+    return hostName == "127.0.0.1";
+}
+
+
+//==============================================================================
+//==============================================================================
+DatagramSocket::DatagramSocket (const int localPortNumber, const bool canBroadcast)
+    : portNumber (0),
+      handle (-1),
+      connected (true),
+      allowBroadcast (canBroadcast),
+      serverAddress (nullptr)
+{
+    SocketHelpers::initSockets();
+
+    handle = (int) socket (AF_INET, SOCK_DGRAM, 0);
+    bindToPort (localPortNumber);
+}
+
+DatagramSocket::DatagramSocket (const String& host, const int portNum,
+                                const int h, const int localPortNumber)
+    : hostName (host),
+      portNumber (portNum),
+      handle (h),
+      connected (true),
+      allowBroadcast (false),
+      serverAddress (nullptr)
+{
+    SocketHelpers::initSockets();
+
+    SocketHelpers::resetSocketOptions (h, true, allowBroadcast);
+    bindToPort (localPortNumber);
+}
+
+DatagramSocket::~DatagramSocket()
+{
+    close();
+
+    if (serverAddress != nullptr)
+        freeaddrinfo (static_cast <struct addrinfo*> (serverAddress));
+}
+
+void DatagramSocket::close()
+{
+   #if JUCE_WINDOWS
+    closesocket (handle);
+    connected = false;
+   #else
+    connected = false;
+    ::close (handle);
+   #endif
+
+    hostName.clear();
+    portNumber = 0;
+    handle = -1;
+}
+
+bool DatagramSocket::bindToPort (const int port)
+{
+    return SocketHelpers::bindSocketToPort (handle, port);
+}
+
+bool DatagramSocket::connect (const String& remoteHostName,
+                              const int remotePortNumber,
+                              const int timeOutMillisecs)
+{
+    if (connected)
+        close();
+
+    hostName = remoteHostName;
+    portNumber = remotePortNumber;
+
+    connected = SocketHelpers::connectSocket (handle, true, (struct addrinfo**) &serverAddress,
+                                              remoteHostName, remotePortNumber,
+                                              timeOutMillisecs);
+
+    if (! (connected && SocketHelpers::resetSocketOptions (handle, true, allowBroadcast)))
+    {
+        close();
+        return false;
+    }
+
+    return true;
+}
+
+DatagramSocket* DatagramSocket::waitForNextConnection() const
+{
+    while (waitUntilReady (true, -1) == 1)
+    {
+        struct sockaddr_storage address;
+        juce_socklen_t len = sizeof (address);
+        char buf[1];
+
+        if (recvfrom (handle, buf, 0, 0, (struct sockaddr*) &address, &len) > 0)
+            return new DatagramSocket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr),
+                                       ntohs (((struct sockaddr_in*) &address)->sin_port),
+                                       -1, -1);
+    }
+
+    return nullptr;
+}
+
+//==============================================================================
+int DatagramSocket::waitUntilReady (const bool readyForReading,
+                                    const int timeoutMsecs) const
+{
+    return connected ? SocketHelpers::waitForReadiness (handle, readyForReading, timeoutMsecs)
+                     : -1;
+}
+
+int DatagramSocket::read (void* destBuffer, const int maxBytesToRead, const bool blockUntilSpecifiedAmountHasArrived)
+{
+    return connected ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead,
+                                                  connected, blockUntilSpecifiedAmountHasArrived)
+                     : -1;
+}
+
+int DatagramSocket::write (const void* sourceBuffer, const int numBytesToWrite)
+{
+    // You need to call connect() first to set the server address..
+    jassert (serverAddress != nullptr && connected);
+
+    return connected ? (int) sendto (handle, (const char*) sourceBuffer,
+                                     (size_t) numBytesToWrite, 0,
+                                     static_cast <const struct addrinfo*> (serverAddress)->ai_addr,
+                                     (juce_socklen_t) static_cast <const struct addrinfo*> (serverAddress)->ai_addrlen)
+                     : -1;
+}
+
+bool DatagramSocket::isLocal() const noexcept
+{
+    return hostName == "127.0.0.1";
+}
+
+#if JUCE_MSVC
+ #pragma warning (pop)
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_Socket.h b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_Socket.h
new file mode 100644
index 0000000..73795c9
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_Socket.h
@@ -0,0 +1,305 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SOCKET_H_INCLUDED
+#define JUCE_SOCKET_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A wrapper for a streaming (TCP) socket.
+
+    This allows low-level use of sockets; for an easier-to-use messaging layer on top of
+    sockets, you could also try the InterprocessConnection class.
+
+    @see DatagramSocket, InterprocessConnection, InterprocessConnectionServer
+*/
+class JUCE_API  StreamingSocket
+{
+public:
+    //==============================================================================
+    /** Creates an uninitialised socket.
+
+        To connect it, use the connect() method, after which you can read() or write()
+        to it.
+
+        To wait for other sockets to connect to this one, the createListener() method
+        enters "listener" mode, and can be used to spawn new sockets for each connection
+        that comes along.
+    */
+    StreamingSocket();
+
+    /** Destructor. */
+    ~StreamingSocket();
+
+    //==============================================================================
+    /** Binds the socket to the specified local port.
+
+        @returns    true on success; false may indicate that another socket is already bound
+                    on the same port
+    */
+    bool bindToPort (int localPortNumber);
+
+    /** Tries to connect the socket to hostname:port.
+
+        If timeOutMillisecs is 0, then this method will block until the operating system
+        rejects the connection (which could take a long time).
+
+        @returns true if it succeeds.
+        @see isConnected
+    */
+    bool connect (const String& remoteHostname,
+                  int remotePortNumber,
+                  int timeOutMillisecs = 3000);
+
+    /** True if the socket is currently connected. */
+    bool isConnected() const noexcept                           { return connected; }
+
+    /** Closes the connection. */
+    void close();
+
+    /** Returns the name of the currently connected host. */
+    const String& getHostName() const noexcept                  { return hostName; }
+
+    /** Returns the port number that's currently open. */
+    int getPort() const noexcept                                { return portNumber; }
+
+    /** True if the socket is connected to this machine rather than over the network. */
+    bool isLocal() const noexcept;
+
+    /** Returns the OS's socket handle that's currently open. */
+    int getRawSocketHandle() const noexcept                     { return handle; }
+
+    //==============================================================================
+    /** Waits until the socket is ready for reading or writing.
+
+        If readyForReading is true, it will wait until the socket is ready for
+        reading; if false, it will wait until it's ready for writing.
+
+        If the timeout is < 0, it will wait forever, or else will give up after
+        the specified time.
+
+        If the socket is ready on return, this returns 1. If it times-out before
+        the socket becomes ready, it returns 0. If an error occurs, it returns -1.
+    */
+    int waitUntilReady (bool readyForReading,
+                        int timeoutMsecs) const;
+
+    /** Reads bytes from the socket.
+
+        If blockUntilSpecifiedAmountHasArrived is true, the method will block until
+        maxBytesToRead bytes have been read, (or until an error occurs). If this
+        flag is false, the method will return as much data as is currently available
+        without blocking.
+
+        @returns the number of bytes read, or -1 if there was an error.
+        @see waitUntilReady
+    */
+    int read (void* destBuffer, int maxBytesToRead,
+              bool blockUntilSpecifiedAmountHasArrived);
+
+    /** Writes bytes to the socket from a buffer.
+
+        Note that this method will block unless you have checked the socket is ready
+        for writing before calling it (see the waitUntilReady() method).
+
+        @returns the number of bytes written, or -1 if there was an error.
+    */
+    int write (const void* sourceBuffer, int numBytesToWrite);
+
+    //==============================================================================
+    /** Puts this socket into "listener" mode.
+
+        When in this mode, your thread can call waitForNextConnection() repeatedly,
+        which will spawn new sockets for each new connection, so that these can
+        be handled in parallel by other threads.
+
+        @param portNumber       the port number to listen on
+        @param localHostName    the interface address to listen on - pass an empty
+                                string to listen on all addresses
+        @returns    true if it manages to open the socket successfully.
+
+        @see waitForNextConnection
+    */
+    bool createListener (int portNumber, const String& localHostName = String());
+
+    /** When in "listener" mode, this waits for a connection and spawns it as a new
+        socket.
+
+        The object that gets returned will be owned by the caller.
+
+        This method can only be called after using createListener().
+
+        @see createListener
+    */
+    StreamingSocket* waitForNextConnection() const;
+
+private:
+    //==============================================================================
+    String hostName;
+    int volatile portNumber, handle;
+    bool connected, isListener;
+
+    StreamingSocket (const String& hostname, int portNumber, int handle);
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StreamingSocket)
+};
+
+
+//==============================================================================
+/**
+    A wrapper for a datagram (UDP) socket.
+
+    This allows low-level use of sockets; for an easier-to-use messaging layer on top of
+    sockets, you could also try the InterprocessConnection class.
+
+    @see StreamingSocket, InterprocessConnection, InterprocessConnectionServer
+*/
+class JUCE_API  DatagramSocket
+{
+public:
+    //==============================================================================
+    /**
+        Creates an (uninitialised) datagram socket.
+
+        The localPortNumber is the port on which to bind this socket. If this value is 0,
+        the port number is assigned by the operating system.
+
+        To use the socket for sending, call the connect() method. This will not immediately
+        make a connection, but will save the destination you've provided. After this, you can
+        call read() or write().
+
+        If enableBroadcasting is true, the socket will be allowed to send broadcast messages
+        (may require extra privileges on linux)
+
+        To wait for other sockets to connect to this one, call waitForNextConnection().
+    */
+    DatagramSocket (int localPortNumber,
+                    bool enableBroadcasting = false);
+
+    /** Destructor. */
+    ~DatagramSocket();
+
+    //==============================================================================
+    /** Binds the socket to the specified local port.
+
+        @returns    true on success; false may indicate that another socket is already bound
+                    on the same port
+    */
+    bool bindToPort (int localPortNumber);
+
+    /** Tries to connect the socket to hostname:port.
+
+        If timeOutMillisecs is 0, then this method will block until the operating system
+        rejects the connection (which could take a long time).
+
+        @returns true if it succeeds.
+        @see isConnected
+    */
+    bool connect (const String& remoteHostname,
+                  int remotePortNumber,
+                  int timeOutMillisecs = 3000);
+
+    /** True if the socket is currently connected. */
+    bool isConnected() const noexcept                           { return connected; }
+
+    /** Closes the connection. */
+    void close();
+
+    /** Returns the name of the currently connected host. */
+    const String& getHostName() const noexcept                  { return hostName; }
+
+    /** Returns the port number that's currently open. */
+    int getPort() const noexcept                                { return portNumber; }
+
+    /** True if the socket is connected to this machine rather than over the network. */
+    bool isLocal() const noexcept;
+
+    /** Returns the OS's socket handle that's currently open. */
+    int getRawSocketHandle() const noexcept                     { return handle; }
+
+    //==============================================================================
+    /** Waits until the socket is ready for reading or writing.
+
+        If readyForReading is true, it will wait until the socket is ready for
+        reading; if false, it will wait until it's ready for writing.
+
+        If the timeout is < 0, it will wait forever, or else will give up after
+        the specified time.
+
+        If the socket is ready on return, this returns 1. If it times-out before
+        the socket becomes ready, it returns 0. If an error occurs, it returns -1.
+    */
+    int waitUntilReady (bool readyForReading,
+                        int timeoutMsecs) const;
+
+    /** Reads bytes from the socket.
+
+        If blockUntilSpecifiedAmountHasArrived is true, the method will block until
+        maxBytesToRead bytes have been read, (or until an error occurs). If this
+        flag is false, the method will return as much data as is currently available
+        without blocking.
+
+        @returns the number of bytes read, or -1 if there was an error.
+        @see waitUntilReady
+    */
+    int read (void* destBuffer, int maxBytesToRead,
+              bool blockUntilSpecifiedAmountHasArrived);
+
+    /** Writes bytes to the socket from a buffer.
+
+        Note that this method will block unless you have checked the socket is ready
+        for writing before calling it (see the waitUntilReady() method).
+
+        @returns the number of bytes written, or -1 if there was an error.
+    */
+    int write (const void* sourceBuffer, int numBytesToWrite);
+
+    //==============================================================================
+    /** This waits for incoming data to be sent, and returns a socket that can be used
+        to read it.
+
+        The object that gets returned is owned by the caller, and can't be used for
+        sending, but can be used to read the data.
+    */
+    DatagramSocket* waitForNextConnection() const;
+
+private:
+    //==============================================================================
+    String hostName;
+    int volatile portNumber, handle;
+    bool connected, allowBroadcast;
+    void* serverAddress;
+
+    DatagramSocket (const String& hostname, int portNumber, int handle, int localPortNumber);
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DatagramSocket)
+};
+
+
+#endif   // JUCE_SOCKET_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_URL.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_URL.cpp
new file mode 100644
index 0000000..49db1f9
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_URL.cpp
@@ -0,0 +1,497 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+URL::URL()
+{
+}
+
+URL::URL (const String& u)  : url (u)
+{
+    int i = url.indexOfChar ('?');
+
+    if (i >= 0)
+    {
+        do
+        {
+            const int nextAmp   = url.indexOfChar (i + 1, '&');
+            const int equalsPos = url.indexOfChar (i + 1, '=');
+
+            if (equalsPos > i + 1)
+            {
+                if (nextAmp < 0)
+                {
+                    addParameter (removeEscapeChars (url.substring (i + 1, equalsPos)),
+                                  removeEscapeChars (url.substring (equalsPos + 1)));
+                }
+                else if (nextAmp > 0 && equalsPos < nextAmp)
+                {
+                    addParameter (removeEscapeChars (url.substring (i + 1, equalsPos)),
+                                  removeEscapeChars (url.substring (equalsPos + 1, nextAmp)));
+                }
+            }
+
+            i = nextAmp;
+        }
+        while (i >= 0);
+
+        url = url.upToFirstOccurrenceOf ("?", false, false);
+    }
+}
+
+URL::URL (const String& u, int)  : url (u) {}
+
+URL URL::createWithoutParsing (const String& u)
+{
+    return URL (u, 0);
+}
+
+URL::URL (const URL& other)
+    : url (other.url),
+      postData (other.postData),
+      parameterNames (other.parameterNames),
+      parameterValues (other.parameterValues),
+      filesToUpload (other.filesToUpload)
+{
+}
+
+URL& URL::operator= (const URL& other)
+{
+    url = other.url;
+    postData = other.postData;
+    parameterNames = other.parameterNames;
+    parameterValues = other.parameterValues;
+    filesToUpload = other.filesToUpload;
+
+    return *this;
+}
+
+bool URL::operator== (const URL& other) const
+{
+    return url == other.url
+        && postData == other.postData
+        && parameterNames == other.parameterNames
+        && parameterValues == other.parameterValues
+        && filesToUpload == other.filesToUpload;
+}
+
+bool URL::operator!= (const URL& other) const
+{
+    return ! operator== (other);
+}
+
+URL::~URL()
+{
+}
+
+namespace URLHelpers
+{
+    static String getMangledParameters (const URL& url)
+    {
+        jassert (url.getParameterNames().size() == url.getParameterValues().size());
+        String p;
+
+        for (int i = 0; i < url.getParameterNames().size(); ++i)
+        {
+            if (i > 0)
+                p << '&';
+
+            p << URL::addEscapeChars (url.getParameterNames()[i], true)
+              << '='
+              << URL::addEscapeChars (url.getParameterValues()[i], true);
+        }
+
+        return p;
+    }
+
+    static int findEndOfScheme (const String& url)
+    {
+        int i = 0;
+
+        while (CharacterFunctions::isLetterOrDigit (url[i])
+                || url[i] == '+' || url[i] == '-' || url[i] == '.')
+            ++i;
+
+        return url[i] == ':' ? i + 1 : 0;
+    }
+
+    static int findStartOfNetLocation (const String& url)
+    {
+        int start = findEndOfScheme (url);
+        while (url[start] == '/')
+            ++start;
+
+        return start;
+    }
+
+    static int findStartOfPath (const String& url)
+    {
+        return url.indexOfChar (findStartOfNetLocation (url), '/') + 1;
+    }
+
+    static void concatenatePaths (String& path, const String& suffix)
+    {
+        if (! path.endsWithChar ('/'))
+            path << '/';
+
+        if (suffix.startsWithChar ('/'))
+            path += suffix.substring (1);
+        else
+            path += suffix;
+    }
+}
+
+void URL::addParameter (const String& name, const String& value)
+{
+    parameterNames.add (name);
+    parameterValues.add (value);
+}
+
+String URL::toString (const bool includeGetParameters) const
+{
+    if (includeGetParameters && parameterNames.size() > 0)
+        return url + "?" + URLHelpers::getMangledParameters (*this);
+
+    return url;
+}
+
+bool URL::isWellFormed() const
+{
+    //xxx TODO
+    return url.isNotEmpty();
+}
+
+String URL::getDomain() const
+{
+    const int start = URLHelpers::findStartOfNetLocation (url);
+    const int end1 = url.indexOfChar (start, '/');
+    const int end2 = url.indexOfChar (start, ':');
+
+    const int end = (end1 < 0 && end2 < 0) ? std::numeric_limits<int>::max()
+                                           : ((end1 < 0 || end2 < 0) ? jmax (end1, end2)
+                                                                     : jmin (end1, end2));
+    return url.substring (start, end);
+}
+
+String URL::getSubPath() const
+{
+    const int startOfPath = URLHelpers::findStartOfPath (url);
+
+    return startOfPath <= 0 ? String()
+                            : url.substring (startOfPath);
+}
+
+String URL::getScheme() const
+{
+    return url.substring (0, URLHelpers::findEndOfScheme (url) - 1);
+}
+
+int URL::getPort() const
+{
+    const int colonPos = url.indexOfChar (URLHelpers::findStartOfNetLocation (url), ':');
+
+    return colonPos > 0 ? url.substring (colonPos + 1).getIntValue() : 0;
+}
+
+URL URL::withNewSubPath (const String& newPath) const
+{
+    const int startOfPath = URLHelpers::findStartOfPath (url);
+
+    URL u (*this);
+
+    if (startOfPath > 0)
+        u.url = url.substring (0, startOfPath);
+
+    URLHelpers::concatenatePaths (u.url, newPath);
+    return u;
+}
+
+URL URL::getChildURL (const String& subPath) const
+{
+    URL u (*this);
+    URLHelpers::concatenatePaths (u.url, subPath);
+    return u;
+}
+
+void URL::createHeadersAndPostData (String& headers, MemoryBlock& headersAndPostData) const
+{
+    MemoryOutputStream data (headersAndPostData, false);
+
+    if (filesToUpload.size() > 0)
+    {
+        // (this doesn't currently support mixing custom post-data with uploads..)
+        jassert (postData.isEmpty());
+
+        const String boundary (String::toHexString (Random::getSystemRandom().nextInt64()));
+
+        headers << "Content-Type: multipart/form-data; boundary=" << boundary << "\r\n";
+
+        data << "--" << boundary;
+
+        for (int i = 0; i < parameterNames.size(); ++i)
+        {
+            data << "\r\nContent-Disposition: form-data; name=\"" << parameterNames[i]
+                 << "\"\r\n\r\n" << parameterValues[i]
+                 << "\r\n--" << boundary;
+        }
+
+        for (int i = 0; i < filesToUpload.size(); ++i)
+        {
+            const Upload& f = *filesToUpload.getObjectPointerUnchecked(i);
+
+            data << "\r\nContent-Disposition: form-data; name=\"" << f.parameterName
+                 << "\"; filename=\"" << f.filename << "\"\r\n";
+
+            if (f.mimeType.isNotEmpty())
+                data << "Content-Type: " << f.mimeType << "\r\n";
+
+            data << "Content-Transfer-Encoding: binary\r\n\r\n";
+
+            if (f.data != nullptr)
+                data << *f.data;
+            else
+                data << f.file;
+
+            data << "\r\n--" << boundary;
+        }
+
+        data << "--\r\n";
+    }
+    else
+    {
+        data << URLHelpers::getMangledParameters (*this)
+             << postData;
+
+        // if the user-supplied headers didn't contain a content-type, add one now..
+        if (! headers.containsIgnoreCase ("Content-Type"))
+            headers << "Content-Type: application/x-www-form-urlencoded\r\n";
+
+        headers << "Content-length: " << (int) data.getDataSize() << "\r\n";
+    }
+}
+
+//==============================================================================
+bool URL::isProbablyAWebsiteURL (const String& possibleURL)
+{
+    static const char* validProtocols[] = { "http:", "ftp:", "https:" };
+
+    for (int i = 0; i < numElementsInArray (validProtocols); ++i)
+        if (possibleURL.startsWithIgnoreCase (validProtocols[i]))
+            return true;
+
+    if (possibleURL.containsChar ('@')
+         || possibleURL.containsChar (' '))
+        return false;
+
+    const String topLevelDomain (possibleURL.upToFirstOccurrenceOf ("/", false, false)
+                                            .fromLastOccurrenceOf (".", false, false));
+
+    return topLevelDomain.isNotEmpty() && topLevelDomain.length() <= 3;
+}
+
+bool URL::isProbablyAnEmailAddress (const String& possibleEmailAddress)
+{
+    const int atSign = possibleEmailAddress.indexOfChar ('@');
+
+    return atSign > 0
+            && possibleEmailAddress.lastIndexOfChar ('.') > (atSign + 1)
+            && ! possibleEmailAddress.endsWithChar ('.');
+}
+
+//==============================================================================
+InputStream* URL::createInputStream (const bool usePostCommand,
+                                     OpenStreamProgressCallback* const progressCallback,
+                                     void* const progressCallbackContext,
+                                     String headers,
+                                     const int timeOutMs,
+                                     StringPairArray* const responseHeaders,
+                                     int* statusCode) const
+{
+    MemoryBlock headersAndPostData;
+
+    if (! headers.endsWithChar ('\n'))
+        headers << "\r\n";
+
+    if (usePostCommand)
+        createHeadersAndPostData (headers, headersAndPostData);
+
+    if (! headers.endsWithChar ('\n'))
+        headers << "\r\n";
+
+    ScopedPointer<WebInputStream> wi (new WebInputStream (toString (! usePostCommand),
+                                                          usePostCommand, headersAndPostData,
+                                                          progressCallback, progressCallbackContext,
+                                                          headers, timeOutMs, responseHeaders));
+
+    if (statusCode != nullptr)
+        *statusCode = wi->statusCode;
+
+    return wi->isError() ? nullptr : wi.release();
+}
+
+//==============================================================================
+bool URL::readEntireBinaryStream (MemoryBlock& destData,
+                                  const bool usePostCommand) const
+{
+    const ScopedPointer<InputStream> in (createInputStream (usePostCommand));
+
+    if (in != nullptr)
+    {
+        in->readIntoMemoryBlock (destData);
+        return true;
+    }
+
+    return false;
+}
+
+String URL::readEntireTextStream (const bool usePostCommand) const
+{
+    const ScopedPointer<InputStream> in (createInputStream (usePostCommand));
+
+    if (in != nullptr)
+        return in->readEntireStreamAsString();
+
+    return String();
+}
+
+XmlElement* URL::readEntireXmlStream (const bool usePostCommand) const
+{
+    return XmlDocument::parse (readEntireTextStream (usePostCommand));
+}
+
+//==============================================================================
+URL URL::withParameter (const String& parameterName,
+                        const String& parameterValue) const
+{
+    URL u (*this);
+    u.addParameter (parameterName, parameterValue);
+    return u;
+}
+
+URL URL::withPOSTData (const String& newPostData) const
+{
+    URL u (*this);
+    u.postData = newPostData;
+    return u;
+}
+
+URL::Upload::Upload (const String& param, const String& name,
+                     const String& mime, const File& f, MemoryBlock* mb)
+    : parameterName (param), filename (name), mimeType (mime), file (f), data (mb)
+{
+    jassert (mimeType.isNotEmpty()); // You need to supply a mime type!
+}
+
+URL URL::withUpload (Upload* const f) const
+{
+    URL u (*this);
+
+    for (int i = u.filesToUpload.size(); --i >= 0;)
+        if (u.filesToUpload.getObjectPointerUnchecked(i)->parameterName == f->parameterName)
+            u.filesToUpload.remove (i);
+
+    u.filesToUpload.add (f);
+    return u;
+}
+
+URL URL::withFileToUpload (const String& parameterName, const File& fileToUpload,
+                           const String& mimeType) const
+{
+    return withUpload (new Upload (parameterName, fileToUpload.getFileName(),
+                                   mimeType, fileToUpload, nullptr));
+}
+
+URL URL::withDataToUpload (const String& parameterName, const String& filename,
+                           const MemoryBlock& fileContentToUpload, const String& mimeType) const
+{
+    return withUpload (new Upload (parameterName, filename, mimeType, File(),
+                                   new MemoryBlock (fileContentToUpload)));
+}
+
+//==============================================================================
+String URL::removeEscapeChars (const String& s)
+{
+    String result (s.replaceCharacter ('+', ' '));
+
+    if (! result.containsChar ('%'))
+        return result;
+
+    // We need to operate on the string as raw UTF8 chars, and then recombine them into unicode
+    // after all the replacements have been made, so that multi-byte chars are handled.
+    Array<char> utf8 (result.toRawUTF8(), (int) result.getNumBytesAsUTF8());
+
+    for (int i = 0; i < utf8.size(); ++i)
+    {
+        if (utf8.getUnchecked(i) == '%')
+        {
+            const int hexDigit1 = CharacterFunctions::getHexDigitValue ((juce_wchar) (uint8) utf8 [i + 1]);
+            const int hexDigit2 = CharacterFunctions::getHexDigitValue ((juce_wchar) (uint8) utf8 [i + 2]);
+
+            if (hexDigit1 >= 0 && hexDigit2 >= 0)
+            {
+                utf8.set (i, (char) ((hexDigit1 << 4) + hexDigit2));
+                utf8.removeRange (i + 1, 2);
+            }
+        }
+    }
+
+    return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size());
+}
+
+String URL::addEscapeChars (const String& s, const bool isParameter)
+{
+    const CharPointer_UTF8 legalChars (isParameter ? "_-.*!'()"
+                                                   : ",$_-.*!'()");
+
+    Array<char> utf8 (s.toRawUTF8(), (int) s.getNumBytesAsUTF8());
+
+    for (int i = 0; i < utf8.size(); ++i)
+    {
+        const char c = utf8.getUnchecked(i);
+
+        if (! (CharacterFunctions::isLetterOrDigit (c)
+                 || legalChars.indexOf ((juce_wchar) c) >= 0))
+        {
+            utf8.set (i, '%');
+            utf8.insert (++i, "0123456789abcdef" [((uint8) c) >> 4]);
+            utf8.insert (++i, "0123456789abcdef" [c & 15]);
+        }
+    }
+
+    return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size());
+}
+
+//==============================================================================
+bool URL::launchInDefaultBrowser() const
+{
+    String u (toString (true));
+
+    if (u.containsChar ('@') && ! u.containsChar (':'))
+        u = "mailto:" + u;
+
+    return Process::openDocument (u, String());
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_URL.h b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_URL.h
new file mode 100644
index 0000000..4f511d8
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/network/juce_URL.h
@@ -0,0 +1,375 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_URL_H_INCLUDED
+#define JUCE_URL_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Represents a URL and has a bunch of useful functions to manipulate it.
+
+    This class can be used to launch URLs in browsers, and also to create
+    InputStreams that can read from remote http or ftp sources.
+*/
+class JUCE_API  URL
+{
+public:
+    //==============================================================================
+    /** Creates an empty URL. */
+    URL();
+
+    /** Creates a URL from a string.
+        This will parse any embedded parameters after a '?' character and store them
+        in the list (see getParameterNames etc). If you don't want this to happen, you
+        can use createWithoutParsing().
+    */
+    URL (const String& url);
+
+    /** Creates a copy of another URL. */
+    URL (const URL& other);
+
+    /** Destructor. */
+    ~URL();
+
+    /** Copies this URL from another one. */
+    URL& operator= (const URL& other);
+
+    /** Compares two URLs.
+        All aspects of the URLs must be identical for them to match, including any parameters,
+        upload files, etc.
+    */
+    bool operator== (const URL&) const;
+    bool operator!= (const URL&) const;
+
+    //==============================================================================
+    /** Returns a string version of the URL.
+
+        If includeGetParameters is true and any parameters have been set with the
+        withParameter() method, then the string will have these appended on the
+        end and url-encoded.
+    */
+    String toString (bool includeGetParameters) const;
+
+    /** True if it seems to be valid. */
+    bool isWellFormed() const;
+
+    /** Returns just the domain part of the URL.
+
+        E.g. for "http://www.xyz.com/foobar", this will return "www.xyz.com".
+    */
+    String getDomain() const;
+
+    /** Returns the path part of the URL.
+
+        E.g. for "http://www.xyz.com/foo/bar?x=1", this will return "foo/bar".
+    */
+    String getSubPath() const;
+
+    /** Returns the scheme of the URL.
+
+        E.g. for "http://www.xyz.com/foobar", this will return "http". (It won't
+        include the colon).
+    */
+    String getScheme() const;
+
+    /** Attempts to read a port number from the URL.
+        @returns the port number, or 0 if none is explicitly specified.
+    */
+    int getPort() const;
+
+    /** Returns a new version of this URL that uses a different sub-path.
+
+        E.g. if the URL is "http://www.xyz.com/foo?x=1" and you call this with
+        "bar", it'll return "http://www.xyz.com/bar?x=1".
+    */
+    URL withNewSubPath (const String& newPath) const;
+
+    /** Returns a new URL that refers to a sub-path relative to this one.
+
+        E.g. if the URL is "http://www.xyz.com/foo" and you call this with
+        "bar", it'll return "http://www.xyz.com/foo/bar". Note that there's no way for
+        this method to know whether the original URL is a file or directory, so it's
+        up to you to make sure it's a directory. It also won't attempt to be smart about
+        the content of the childPath string, so if this string is an absolute URL, it'll
+        still just get bolted onto the end of the path.
+
+        @see File::getChildFile
+    */
+    URL getChildURL (const String& subPath) const;
+
+    //==============================================================================
+    /** Returns a copy of this URL, with a GET or POST parameter added to the end.
+
+        Any control characters in the value will be encoded.
+
+        e.g. calling "withParameter ("amount", "some fish") for the url "www.fish.com"
+        would produce a new url whose toString(true) method would return
+        "www.fish.com?amount=some+fish".
+
+        @see getParameterNames, getParameterValues
+    */
+    URL withParameter (const String& parameterName,
+                       const String& parameterValue) const;
+
+    /** Returns a copy of this URL, with a file-upload type parameter added to it.
+
+        When performing a POST where one of your parameters is a binary file, this
+        lets you specify the file.
+
+        Note that the filename is stored, but the file itself won't actually be read
+        until this URL is later used to create a network input stream. If you want to
+        upload data from memory, use withDataToUpload().
+
+        @see withDataToUpload
+    */
+    URL withFileToUpload (const String& parameterName,
+                          const File& fileToUpload,
+                          const String& mimeType) const;
+
+    /** Returns a copy of this URL, with a file-upload type parameter added to it.
+
+        When performing a POST where one of your parameters is a binary file, this
+        lets you specify the file content.
+        Note that the filename parameter should not be a full path, it's just the
+        last part of the filename.
+
+        @see withFileToUpload
+    */
+    URL withDataToUpload (const String& parameterName,
+                          const String& filename,
+                          const MemoryBlock& fileContentToUpload,
+                          const String& mimeType) const;
+
+    /** Returns an array of the names of all the URL's parameters.
+
+        E.g. for the url "www.fish.com?type=haddock&amount=some+fish", this array would
+        contain two items: "type" and "amount".
+
+        You can call getParameterValues() to get the corresponding value of each
+        parameter. Note that the list can contain multiple parameters with the same name.
+
+        @see getParameterValues, withParameter
+    */
+    const StringArray& getParameterNames() const noexcept       { return parameterNames; }
+
+    /** Returns an array of the values of all the URL's parameters.
+
+        E.g. for the url "www.fish.com?type=haddock&amount=some+fish", this array would
+        contain two items: "haddock" and "some fish".
+
+        The values returned will have been cleaned up to remove any escape characters.
+
+        You can call getParameterNames() to get the corresponding name of each
+        parameter. Note that the list can contain multiple parameters with the same name.
+
+        @see getParameterNames, withParameter
+    */
+    const StringArray& getParameterValues() const noexcept      { return parameterValues; }
+
+    /** Returns a copy of this URL, with a block of data to send as the POST data.
+
+        If you're setting the POST data, be careful not to have any parameters set
+        as well, otherwise it'll all get thrown in together, and might not have the
+        desired effect.
+
+        If the URL already contains some POST data, this will replace it, rather
+        than being appended to it.
+
+        This data will only be used if you specify a post operation when you call
+        createInputStream().
+    */
+    URL withPOSTData (const String& postData) const;
+
+    /** Returns the data that was set using withPOSTData(). */
+    const String& getPostData() const noexcept                  { return postData; }
+
+    //==============================================================================
+    /** Tries to launch the system's default browser to open the URL.
+
+        Returns true if this seems to have worked.
+    */
+    bool launchInDefaultBrowser() const;
+
+    //==============================================================================
+    /** Takes a guess as to whether a string might be a valid website address.
+
+        This isn't foolproof!
+    */
+    static bool isProbablyAWebsiteURL (const String& possibleURL);
+
+    /** Takes a guess as to whether a string might be a valid email address.
+
+        This isn't foolproof!
+    */
+    static bool isProbablyAnEmailAddress (const String& possibleEmailAddress);
+
+    //==============================================================================
+    /** This callback function can be used by the createInputStream() method.
+
+        It allows your app to receive progress updates during a lengthy POST operation. If you
+        want to continue the operation, this should return true, or false to abort.
+    */
+    typedef bool (OpenStreamProgressCallback) (void* context, int bytesSent, int totalBytes);
+
+    /** Attempts to open a stream that can read from this URL.
+
+        @param usePostCommand   if true, it will try to do use a http 'POST' to pass
+                                the parameters, otherwise it'll encode them into the
+                                URL and do a 'GET'.
+        @param progressCallback if this is non-zero, it lets you supply a callback function
+                                to keep track of the operation's progress. This can be useful
+                                for lengthy POST operations, so that you can provide user feedback.
+        @param progressCallbackContext  if a callback is specified, this value will be passed to
+                                the function
+        @param extraHeaders     if not empty, this string is appended onto the headers that
+                                are used for the request. It must therefore be a valid set of HTML
+                                header directives, separated by newlines.
+        @param connectionTimeOutMs  if 0, this will use whatever default setting the OS chooses. If
+                                a negative number, it will be infinite. Otherwise it specifies a
+                                time in milliseconds.
+        @param responseHeaders  if this is non-null, all the (key, value) pairs received as headers
+                                in the response will be stored in this array
+        @param statusCode       if this is non-null, it will get set to the http status code, if one
+                                is known, or 0 if a code isn't available
+        @returns    an input stream that the caller must delete, or a null pointer if there was an
+                    error trying to open it.
+     */
+    InputStream* createInputStream (bool usePostCommand,
+                                    OpenStreamProgressCallback* progressCallback = nullptr,
+                                    void* progressCallbackContext = nullptr,
+                                    String extraHeaders = String(),
+                                    int connectionTimeOutMs = 0,
+                                    StringPairArray* responseHeaders = nullptr,
+                                    int* statusCode = nullptr) const;
+
+
+    //==============================================================================
+    /** Tries to download the entire contents of this URL into a binary data block.
+
+        If it succeeds, this will return true and append the data it read onto the end
+        of the memory block.
+
+        @param destData         the memory block to append the new data to
+        @param usePostCommand   whether to use a POST command to get the data (uses
+                                a GET command if this is false)
+        @see readEntireTextStream, readEntireXmlStream
+    */
+    bool readEntireBinaryStream (MemoryBlock& destData,
+                                 bool usePostCommand = false) const;
+
+    /** Tries to download the entire contents of this URL as a string.
+
+        If it fails, this will return an empty string, otherwise it will return the
+        contents of the downloaded file. If you need to distinguish between a read
+        operation that fails and one that returns an empty string, you'll need to use
+        a different method, such as readEntireBinaryStream().
+
+        @param usePostCommand   whether to use a POST command to get the data (uses
+                                a GET command if this is false)
+        @see readEntireBinaryStream, readEntireXmlStream
+    */
+    String readEntireTextStream (bool usePostCommand = false) const;
+
+    /** Tries to download the entire contents of this URL and parse it as XML.
+
+        If it fails, or if the text that it reads can't be parsed as XML, this will
+        return 0.
+
+        When it returns a valid XmlElement object, the caller is responsibile for deleting
+        this object when no longer needed.
+
+        @param usePostCommand   whether to use a POST command to get the data (uses
+                                a GET command if this is false)
+
+        @see readEntireBinaryStream, readEntireTextStream
+    */
+    XmlElement* readEntireXmlStream (bool usePostCommand = false) const;
+
+    //==============================================================================
+    /** Adds escape sequences to a string to encode any characters that aren't
+        legal in a URL.
+
+        E.g. any spaces will be replaced with "%20".
+
+        This is the opposite of removeEscapeChars().
+
+        If isParameter is true, it means that the string is going to be used
+        as a parameter, so it also encodes '$' and ',' (which would otherwise
+        be legal in a URL.
+
+        @see removeEscapeChars
+    */
+    static String addEscapeChars (const String& stringToAddEscapeCharsTo,
+                                  bool isParameter);
+
+    /** Replaces any escape character sequences in a string with their original
+        character codes.
+
+        E.g. any instances of "%20" will be replaced by a space.
+
+        This is the opposite of addEscapeChars().
+
+        @see addEscapeChars
+    */
+    static String removeEscapeChars (const String& stringToRemoveEscapeCharsFrom);
+
+    /** Returns a URL without attempting to remove any embedded parameters from the string.
+        This may be necessary if you need to create a request that involves both POST
+        parameters and parameters which are embedded in the URL address itself.
+    */
+    static URL createWithoutParsing (const String& url);
+
+private:
+    //==============================================================================
+    String url, postData;
+    StringArray parameterNames, parameterValues;
+
+    struct Upload  : public ReferenceCountedObject
+    {
+        Upload (const String&, const String&, const String&, const File&, MemoryBlock*);
+        String parameterName, filename, mimeType;
+        File file;
+        ScopedPointer<MemoryBlock> data;
+
+        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Upload)
+    };
+
+    friend struct ContainerDeletePolicy<Upload>;
+    ReferenceCountedArray<Upload> filesToUpload;
+
+    URL (const String&, int);
+    void addParameter (const String&, const String&);
+    void createHeadersAndPostData (String&, MemoryBlock&) const;
+    URL withUpload (Upload*) const;
+
+    JUCE_LEAK_DETECTOR (URL)
+};
+
+
+#endif   // JUCE_URL_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_BufferedInputStream.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_BufferedInputStream.cpp
new file mode 100644
index 0000000..ec01f8e
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_BufferedInputStream.cpp
@@ -0,0 +1,198 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+namespace
+{
+    int calcBufferStreamBufferSize (int requestedSize, InputStream* const source) noexcept
+    {
+        // You need to supply a real stream when creating a BufferedInputStream
+        jassert (source != nullptr);
+
+        requestedSize = jmax (256, requestedSize);
+
+        const int64 sourceSize = source->getTotalLength();
+        if (sourceSize >= 0 && sourceSize < requestedSize)
+            requestedSize = jmax (32, (int) sourceSize);
+
+        return requestedSize;
+    }
+}
+
+//==============================================================================
+BufferedInputStream::BufferedInputStream (InputStream* const sourceStream, const int bufferSize_,
+                                          const bool deleteSourceWhenDestroyed)
+   : source (sourceStream, deleteSourceWhenDestroyed),
+     bufferSize (calcBufferStreamBufferSize (bufferSize_, sourceStream)),
+     position (sourceStream->getPosition()),
+     lastReadPos (0),
+     bufferStart (position),
+     bufferOverlap (128)
+{
+    buffer.malloc ((size_t) bufferSize);
+}
+
+BufferedInputStream::BufferedInputStream (InputStream& sourceStream, const int bufferSize_)
+   : source (&sourceStream, false),
+     bufferSize (calcBufferStreamBufferSize (bufferSize_, &sourceStream)),
+     position (sourceStream.getPosition()),
+     lastReadPos (0),
+     bufferStart (position),
+     bufferOverlap (128)
+{
+    buffer.malloc ((size_t) bufferSize);
+}
+
+BufferedInputStream::~BufferedInputStream()
+{
+}
+
+//==============================================================================
+int64 BufferedInputStream::getTotalLength()
+{
+    return source->getTotalLength();
+}
+
+int64 BufferedInputStream::getPosition()
+{
+    return position;
+}
+
+bool BufferedInputStream::setPosition (int64 newPosition)
+{
+    position = jmax ((int64) 0, newPosition);
+    return true;
+}
+
+bool BufferedInputStream::isExhausted()
+{
+    return position >= lastReadPos && source->isExhausted();
+}
+
+void BufferedInputStream::ensureBuffered()
+{
+    const int64 bufferEndOverlap = lastReadPos - bufferOverlap;
+
+    if (position < bufferStart || position >= bufferEndOverlap)
+    {
+        int bytesRead;
+
+        if (position < lastReadPos
+             && position >= bufferEndOverlap
+             && position >= bufferStart)
+        {
+            const int bytesToKeep = (int) (lastReadPos - position);
+            memmove (buffer, buffer + (int) (position - bufferStart), (size_t) bytesToKeep);
+
+            bufferStart = position;
+
+            bytesRead = source->read (buffer + bytesToKeep,
+                                      (int) (bufferSize - bytesToKeep));
+
+            lastReadPos += bytesRead;
+            bytesRead += bytesToKeep;
+        }
+        else
+        {
+            bufferStart = position;
+            source->setPosition (bufferStart);
+            bytesRead = source->read (buffer, bufferSize);
+            lastReadPos = bufferStart + bytesRead;
+        }
+
+        while (bytesRead < bufferSize)
+            buffer [bytesRead++] = 0;
+    }
+}
+
+int BufferedInputStream::read (void* destBuffer, int maxBytesToRead)
+{
+    jassert (destBuffer != nullptr && maxBytesToRead >= 0);
+
+    if (position >= bufferStart
+         && position + maxBytesToRead <= lastReadPos)
+    {
+        memcpy (destBuffer, buffer + (int) (position - bufferStart), (size_t) maxBytesToRead);
+        position += maxBytesToRead;
+
+        return maxBytesToRead;
+    }
+    else
+    {
+        if (position < bufferStart || position >= lastReadPos)
+            ensureBuffered();
+
+        int bytesRead = 0;
+
+        while (maxBytesToRead > 0)
+        {
+            const int bytesAvailable = jmin (maxBytesToRead, (int) (lastReadPos - position));
+
+            if (bytesAvailable > 0)
+            {
+                memcpy (destBuffer, buffer + (int) (position - bufferStart), (size_t) bytesAvailable);
+                maxBytesToRead -= bytesAvailable;
+                bytesRead += bytesAvailable;
+                position += bytesAvailable;
+                destBuffer = static_cast <char*> (destBuffer) + bytesAvailable;
+            }
+
+            const int64 oldLastReadPos = lastReadPos;
+            ensureBuffered();
+
+            if (oldLastReadPos == lastReadPos)
+                break; // if ensureBuffered() failed to read any more data, bail out
+
+            if (isExhausted())
+                break;
+        }
+
+        return bytesRead;
+    }
+}
+
+String BufferedInputStream::readString()
+{
+    if (position >= bufferStart
+         && position < lastReadPos)
+    {
+        const int maxChars = (int) (lastReadPos - position);
+
+        const char* const src = buffer + (int) (position - bufferStart);
+
+        for (int i = 0; i < maxChars; ++i)
+        {
+            if (src[i] == 0)
+            {
+                position += i + 1;
+                return String::fromUTF8 (src, i);
+            }
+        }
+    }
+
+    return InputStream::readString();
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_BufferedInputStream.h b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_BufferedInputStream.h
new file mode 100644
index 0000000..8f1e633
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_BufferedInputStream.h
@@ -0,0 +1,92 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_BUFFEREDINPUTSTREAM_H_INCLUDED
+#define JUCE_BUFFEREDINPUTSTREAM_H_INCLUDED
+
+
+//==============================================================================
+/** Wraps another input stream, and reads from it using an intermediate buffer
+
+    If you're using an input stream such as a file input stream, and making lots of
+    small read accesses to it, it's probably sensible to wrap it in one of these,
+    so that the source stream gets accessed in larger chunk sizes, meaning less
+    work for the underlying stream.
+*/
+class JUCE_API  BufferedInputStream  : public InputStream
+{
+public:
+    //==============================================================================
+    /** Creates a BufferedInputStream from an input source.
+
+        @param sourceStream                 the source stream to read from
+        @param bufferSize                   the size of reservoir to use to buffer the source
+        @param deleteSourceWhenDestroyed    whether the sourceStream that is passed in should be
+                                            deleted by this object when it is itself deleted.
+    */
+    BufferedInputStream (InputStream* sourceStream,
+                         int bufferSize,
+                         bool deleteSourceWhenDestroyed);
+
+    /** Creates a BufferedInputStream from an input source.
+
+        @param sourceStream     the source stream to read from - the source stream  must not
+                                be deleted until this object has been destroyed.
+        @param bufferSize       the size of reservoir to use to buffer the source
+    */
+    BufferedInputStream (InputStream& sourceStream, int bufferSize);
+
+    /** Destructor.
+
+        This may also delete the source stream, if that option was chosen when the
+        buffered stream was created.
+    */
+    ~BufferedInputStream();
+
+
+    //==============================================================================
+    int64 getTotalLength() override;
+    int64 getPosition() override;
+    bool setPosition (int64 newPosition) override;
+    int read (void* destBuffer, int maxBytesToRead) override;
+    String readString() override;
+    bool isExhausted() override;
+
+
+private:
+    //==============================================================================
+    OptionalScopedPointer<InputStream> source;
+    int bufferSize;
+    int64 position, lastReadPos, bufferStart, bufferOverlap;
+    HeapBlock <char> buffer;
+    void ensureBuffered();
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BufferedInputStream)
+};
+
+#endif   // JUCE_BUFFEREDINPUTSTREAM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_FileInputSource.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_FileInputSource.cpp
new file mode 100644
index 0000000..51b9db9
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_FileInputSource.cpp
@@ -0,0 +1,56 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+FileInputSource::FileInputSource (const File& f, bool useFileTimeInHash)
+    : file (f), useFileTimeInHashGeneration (useFileTimeInHash)
+{
+}
+
+FileInputSource::~FileInputSource()
+{
+}
+
+InputStream* FileInputSource::createInputStream()
+{
+    return file.createInputStream();
+}
+
+InputStream* FileInputSource::createInputStreamFor (const String& relatedItemPath)
+{
+    return file.getSiblingFile (relatedItemPath).createInputStream();
+}
+
+int64 FileInputSource::hashCode() const
+{
+    int64 h = file.hashCode();
+
+    if (useFileTimeInHashGeneration)
+        h ^= file.getLastModificationTime().toMilliseconds();
+
+    return h;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_FileInputSource.h b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_FileInputSource.h
new file mode 100644
index 0000000..d2e6d86
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_FileInputSource.h
@@ -0,0 +1,66 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_FILEINPUTSOURCE_H_INCLUDED
+#define JUCE_FILEINPUTSOURCE_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A type of InputSource that represents a normal file.
+
+    @see InputSource
+*/
+class JUCE_API  FileInputSource     : public InputSource
+{
+public:
+    //==============================================================================
+    /** Creates a FileInputSource for a file.
+        If the useFileTimeInHashGeneration parameter is true, then this object's
+        hashCode() method will incorporate the file time into its hash code; if
+        false, only the file name will be used for the hash.
+    */
+    FileInputSource (const File& file, bool useFileTimeInHashGeneration = false);
+
+    /** Destructor. */
+    ~FileInputSource();
+
+    InputStream* createInputStream();
+    InputStream* createInputStreamFor (const String& relatedItemPath);
+    int64 hashCode() const;
+
+private:
+    //==============================================================================
+    const File file;
+    bool useFileTimeInHashGeneration;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputSource)
+};
+
+
+#endif   // JUCE_FILEINPUTSOURCE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_InputSource.h b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_InputSource.h
new file mode 100644
index 0000000..0e13ac5
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_InputSource.h
@@ -0,0 +1,78 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_INPUTSOURCE_H_INCLUDED
+#define JUCE_INPUTSOURCE_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A lightweight object that can create a stream to read some kind of resource.
+
+    This may be used to refer to a file, or some other kind of source, allowing a
+    caller to create an input stream that can read from it when required.
+
+    @see FileInputSource
+*/
+class JUCE_API  InputSource
+{
+public:
+    //==============================================================================
+    InputSource() noexcept      {}
+
+    /** Destructor. */
+    virtual ~InputSource()      {}
+
+    //==============================================================================
+    /** Returns a new InputStream to read this item.
+
+        @returns            an inputstream that the caller will delete, or nullptr if
+                            the filename isn't found.
+    */
+    virtual InputStream* createInputStream() = 0;
+
+    /** Returns a new InputStream to read an item, relative.
+
+        @param relatedItemPath  the relative pathname of the resource that is required
+        @returns            an inputstream that the caller will delete, or nullptr if
+                            the item isn't found.
+    */
+    virtual InputStream* createInputStreamFor (const String& relatedItemPath) = 0;
+
+    /** Returns a hash code that uniquely represents this item.
+    */
+    virtual int64 hashCode() const = 0;
+
+
+private:
+    //==============================================================================
+    JUCE_LEAK_DETECTOR (InputSource)
+};
+
+
+#endif   // JUCE_INPUTSOURCE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_InputStream.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_InputStream.cpp
new file mode 100644
index 0000000..07b9976
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_InputStream.cpp
@@ -0,0 +1,236 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+int64 InputStream::getNumBytesRemaining()
+{
+    int64 len = getTotalLength();
+
+    if (len >= 0)
+        len -= getPosition();
+
+    return len;
+}
+
+char InputStream::readByte()
+{
+    char temp = 0;
+    read (&temp, 1);
+    return temp;
+}
+
+bool InputStream::readBool()
+{
+    return readByte() != 0;
+}
+
+short InputStream::readShort()
+{
+    char temp[2];
+
+    if (read (temp, 2) == 2)
+        return (short) ByteOrder::littleEndianShort (temp);
+
+    return 0;
+}
+
+short InputStream::readShortBigEndian()
+{
+    char temp[2];
+
+    if (read (temp, 2) == 2)
+        return (short) ByteOrder::bigEndianShort (temp);
+
+    return 0;
+}
+
+int InputStream::readInt()
+{
+    char temp[4];
+
+    if (read (temp, 4) == 4)
+        return (int) ByteOrder::littleEndianInt (temp);
+
+    return 0;
+}
+
+int InputStream::readIntBigEndian()
+{
+    char temp[4];
+
+    if (read (temp, 4) == 4)
+        return (int) ByteOrder::bigEndianInt (temp);
+
+    return 0;
+}
+
+int InputStream::readCompressedInt()
+{
+    const uint8 sizeByte = (uint8) readByte();
+    if (sizeByte == 0)
+        return 0;
+
+    const int numBytes = (sizeByte & 0x7f);
+    if (numBytes > 4)
+    {
+        jassertfalse;    // trying to read corrupt data - this method must only be used
+                       // to read data that was written by OutputStream::writeCompressedInt()
+        return 0;
+    }
+
+    char bytes[4] = { 0, 0, 0, 0 };
+    if (read (bytes, numBytes) != numBytes)
+        return 0;
+
+    const int num = (int) ByteOrder::littleEndianInt (bytes);
+    return (sizeByte >> 7) ? -num : num;
+}
+
+int64 InputStream::readInt64()
+{
+    union { uint8 asBytes[8]; uint64 asInt64; } n;
+
+    if (read (n.asBytes, 8) == 8)
+        return (int64) ByteOrder::swapIfBigEndian (n.asInt64);
+
+    return 0;
+}
+
+int64 InputStream::readInt64BigEndian()
+{
+    union { uint8 asBytes[8]; uint64 asInt64; } n;
+
+    if (read (n.asBytes, 8) == 8)
+        return (int64) ByteOrder::swapIfLittleEndian (n.asInt64);
+
+    return 0;
+}
+
+float InputStream::readFloat()
+{
+    // the union below relies on these types being the same size...
+    static_jassert (sizeof (int32) == sizeof (float));
+    union { int32 asInt; float asFloat; } n;
+    n.asInt = (int32) readInt();
+    return n.asFloat;
+}
+
+float InputStream::readFloatBigEndian()
+{
+    union { int32 asInt; float asFloat; } n;
+    n.asInt = (int32) readIntBigEndian();
+    return n.asFloat;
+}
+
+double InputStream::readDouble()
+{
+    union { int64 asInt; double asDouble; } n;
+    n.asInt = readInt64();
+    return n.asDouble;
+}
+
+double InputStream::readDoubleBigEndian()
+{
+    union { int64 asInt; double asDouble; } n;
+    n.asInt = readInt64BigEndian();
+    return n.asDouble;
+}
+
+String InputStream::readString()
+{
+    MemoryBlock buffer (256);
+    char* data = static_cast<char*> (buffer.getData());
+    size_t i = 0;
+
+    while ((data[i] = readByte()) != 0)
+    {
+        if (++i >= buffer.getSize())
+        {
+            buffer.setSize (buffer.getSize() + 512);
+            data = static_cast<char*> (buffer.getData());
+        }
+    }
+
+    return String::fromUTF8 (data, (int) i);
+}
+
+String InputStream::readNextLine()
+{
+    MemoryBlock buffer (256);
+    char* data = static_cast<char*> (buffer.getData());
+    size_t i = 0;
+
+    while ((data[i] = readByte()) != 0)
+    {
+        if (data[i] == '\n')
+            break;
+
+        if (data[i] == '\r')
+        {
+            const int64 lastPos = getPosition();
+
+            if (readByte() != '\n')
+                setPosition (lastPos);
+
+            break;
+        }
+
+        if (++i >= buffer.getSize())
+        {
+            buffer.setSize (buffer.getSize() + 512);
+            data = static_cast<char*> (buffer.getData());
+        }
+    }
+
+    return String::fromUTF8 (data, (int) i);
+}
+
+size_t InputStream::readIntoMemoryBlock (MemoryBlock& block, ssize_t numBytes)
+{
+    MemoryOutputStream mo (block, true);
+    return (size_t) mo.writeFromInputStream (*this, numBytes);
+}
+
+String InputStream::readEntireStreamAsString()
+{
+    MemoryOutputStream mo;
+    mo << *this;
+    return mo.toString();
+}
+
+//==============================================================================
+void InputStream::skipNextBytes (int64 numBytesToSkip)
+{
+    if (numBytesToSkip > 0)
+    {
+        const int skipBufferSize = (int) jmin (numBytesToSkip, (int64) 16384);
+        HeapBlock<char> temp ((size_t) skipBufferSize);
+
+        while (numBytesToSkip > 0 && ! isExhausted())
+            numBytesToSkip -= read (temp, (int) jmin (numBytesToSkip, (int64) skipBufferSize));
+    }
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_InputStream.h b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_InputStream.h
new file mode 100644
index 0000000..ebdc795
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_InputStream.h
@@ -0,0 +1,266 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_INPUTSTREAM_H_INCLUDED
+#define JUCE_INPUTSTREAM_H_INCLUDED
+
+
+//==============================================================================
+/** The base class for streams that read data.
+
+    Input and output streams are used throughout the library - subclasses can override
+    some or all of the virtual functions to implement their behaviour.
+
+    @see OutputStream, MemoryInputStream, BufferedInputStream, FileInputStream
+*/
+class JUCE_API  InputStream
+{
+public:
+    /** Destructor. */
+    virtual ~InputStream()  {}
+
+    //==============================================================================
+    /** Returns the total number of bytes available for reading in this stream.
+
+        Note that this is the number of bytes available from the start of the
+        stream, not from the current position.
+
+        If the size of the stream isn't actually known, this will return -1.
+
+        @see getNumBytesRemaining
+    */
+    virtual int64 getTotalLength() = 0;
+
+    /** Returns the number of bytes available for reading, or a negative value if
+        the remaining length is not known.
+        @see getTotalLength
+    */
+    int64 getNumBytesRemaining();
+
+    /** Returns true if the stream has no more data to read. */
+    virtual bool isExhausted() = 0;
+
+    //==============================================================================
+    /** Reads some data from the stream into a memory buffer.
+
+        This is the only read method that subclasses actually need to implement, as the
+        InputStream base class implements the other read methods in terms of this one (although
+        it's often more efficient for subclasses to implement them directly).
+
+        @param destBuffer       the destination buffer for the data. This must not be null.
+        @param maxBytesToRead   the maximum number of bytes to read - make sure the
+                                memory block passed in is big enough to contain this
+                                many bytes. This value must not be negative.
+
+        @returns    the actual number of bytes that were read, which may be less than
+                    maxBytesToRead if the stream is exhausted before it gets that far
+    */
+    virtual int read (void* destBuffer, int maxBytesToRead) = 0;
+
+    /** Reads a byte from the stream.
+        If the stream is exhausted, this will return zero.
+        @see OutputStream::writeByte
+    */
+    virtual char readByte();
+
+    /** Reads a boolean from the stream.
+        The bool is encoded as a single byte - non-zero for true, 0 for false.
+        If the stream is exhausted, this will return false.
+        @see OutputStream::writeBool
+    */
+    virtual bool readBool();
+
+    /** Reads two bytes from the stream as a little-endian 16-bit value.
+        If the next two bytes read are byte1 and byte2, this returns (byte1 | (byte2 << 8)).
+        If the stream is exhausted partway through reading the bytes, this will return zero.
+        @see OutputStream::writeShort, readShortBigEndian
+    */
+    virtual short readShort();
+
+    /** Reads two bytes from the stream as a little-endian 16-bit value.
+        If the next two bytes read are byte1 and byte2, this returns (byte2 | (byte1 << 8)).
+        If the stream is exhausted partway through reading the bytes, this will return zero.
+        @see OutputStream::writeShortBigEndian, readShort
+    */
+    virtual short readShortBigEndian();
+
+    /** Reads four bytes from the stream as a little-endian 32-bit value.
+
+        If the next four bytes are byte1 to byte4, this returns
+        (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24)).
+
+        If the stream is exhausted partway through reading the bytes, this will return zero.
+
+        @see OutputStream::writeInt, readIntBigEndian
+    */
+    virtual int readInt();
+
+    /** Reads four bytes from the stream as a big-endian 32-bit value.
+
+        If the next four bytes are byte1 to byte4, this returns
+        (byte4 | (byte3 << 8) | (byte2 << 16) | (byte1 << 24)).
+
+        If the stream is exhausted partway through reading the bytes, this will return zero.
+
+        @see OutputStream::writeIntBigEndian, readInt
+    */
+    virtual int readIntBigEndian();
+
+    /** Reads eight bytes from the stream as a little-endian 64-bit value.
+
+        If the next eight bytes are byte1 to byte8, this returns
+        (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24) | (byte5 << 32) | (byte6 << 40) | (byte7 << 48) | (byte8 << 56)).
+
+        If the stream is exhausted partway through reading the bytes, this will return zero.
+
+        @see OutputStream::writeInt64, readInt64BigEndian
+    */
+    virtual int64 readInt64();
+
+    /** Reads eight bytes from the stream as a big-endian 64-bit value.
+
+        If the next eight bytes are byte1 to byte8, this returns
+        (byte8 | (byte7 << 8) | (byte6 << 16) | (byte5 << 24) | (byte4 << 32) | (byte3 << 40) | (byte2 << 48) | (byte1 << 56)).
+
+        If the stream is exhausted partway through reading the bytes, this will return zero.
+
+        @see OutputStream::writeInt64BigEndian, readInt64
+    */
+    virtual int64 readInt64BigEndian();
+
+    /** Reads four bytes as a 32-bit floating point value.
+        The raw 32-bit encoding of the float is read from the stream as a little-endian int.
+        If the stream is exhausted partway through reading the bytes, this will return zero.
+        @see OutputStream::writeFloat, readDouble
+    */
+    virtual float readFloat();
+
+    /** Reads four bytes as a 32-bit floating point value.
+        The raw 32-bit encoding of the float is read from the stream as a big-endian int.
+        If the stream is exhausted partway through reading the bytes, this will return zero.
+        @see OutputStream::writeFloatBigEndian, readDoubleBigEndian
+    */
+    virtual float readFloatBigEndian();
+
+    /** Reads eight bytes as a 64-bit floating point value.
+        The raw 64-bit encoding of the double is read from the stream as a little-endian int64.
+        If the stream is exhausted partway through reading the bytes, this will return zero.
+        @see OutputStream::writeDouble, readFloat
+    */
+    virtual double readDouble();
+
+    /** Reads eight bytes as a 64-bit floating point value.
+        The raw 64-bit encoding of the double is read from the stream as a big-endian int64.
+        If the stream is exhausted partway through reading the bytes, this will return zero.
+        @see OutputStream::writeDoubleBigEndian, readFloatBigEndian
+    */
+    virtual double readDoubleBigEndian();
+
+    /** Reads an encoded 32-bit number from the stream using a space-saving compressed format.
+        For small values, this is more space-efficient than using readInt() and OutputStream::writeInt()
+        The format used is: number of significant bytes + up to 4 bytes in little-endian order.
+        @see OutputStream::writeCompressedInt()
+    */
+    virtual int readCompressedInt();
+
+    //==============================================================================
+    /** Reads a UTF-8 string from the stream, up to the next linefeed or carriage return.
+
+        This will read up to the next "\n" or "\r\n" or end-of-stream.
+
+        After this call, the stream's position will be left pointing to the next character
+        following the line-feed, but the linefeeds aren't included in the string that
+        is returned.
+    */
+    virtual String readNextLine();
+
+    /** Reads a zero-terminated UTF-8 string from the stream.
+
+        This will read characters from the stream until it hits a null character
+        or end-of-stream.
+
+        @see OutputStream::writeString, readEntireStreamAsString
+    */
+    virtual String readString();
+
+    /** Tries to read the whole stream and turn it into a string.
+
+        This will read from the stream's current position until the end-of-stream.
+        It can read from UTF-8 data, or UTF-16 if it detects suitable header-bytes.
+    */
+    virtual String readEntireStreamAsString();
+
+    /** Reads from the stream and appends the data to a MemoryBlock.
+
+        @param destBlock            the block to append the data onto
+        @param maxNumBytesToRead    if this is a positive value, it sets a limit to the number
+                                    of bytes that will be read - if it's negative, data
+                                    will be read until the stream is exhausted.
+        @returns the number of bytes that were added to the memory block
+    */
+    virtual size_t readIntoMemoryBlock (MemoryBlock& destBlock,
+                                        ssize_t maxNumBytesToRead = -1);
+
+    //==============================================================================
+    /** Returns the offset of the next byte that will be read from the stream.
+        @see setPosition
+    */
+    virtual int64 getPosition() = 0;
+
+    /** Tries to move the current read position of the stream.
+
+        The position is an absolute number of bytes from the stream's start.
+
+        Some streams might not be able to do this, in which case they should do
+        nothing and return false. Others might be able to manage it by resetting
+        themselves and skipping to the correct position, although this is
+        obviously a bit slow.
+
+        @returns  true if the stream manages to reposition itself correctly
+        @see getPosition
+    */
+    virtual bool setPosition (int64 newPosition) = 0;
+
+    /** Reads and discards a number of bytes from the stream.
+
+        Some input streams might implement this efficiently, but the base
+        class will just keep reading data until the requisite number of bytes
+        have been done.
+    */
+    virtual void skipNextBytes (int64 numBytesToSkip);
+
+
+protected:
+    //==============================================================================
+    InputStream() noexcept {}
+
+private:
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InputStream)
+};
+
+#endif   // JUCE_INPUTSTREAM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryInputStream.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryInputStream.cpp
new file mode 100644
index 0000000..82b2d14
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryInputStream.cpp
@@ -0,0 +1,159 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+MemoryInputStream::MemoryInputStream (const void* const sourceData,
+                                      const size_t sourceDataSize,
+                                      const bool keepInternalCopy)
+    : data (sourceData),
+      dataSize (sourceDataSize),
+      position (0)
+{
+    if (keepInternalCopy)
+        createInternalCopy();
+}
+
+MemoryInputStream::MemoryInputStream (const MemoryBlock& sourceData,
+                                      const bool keepInternalCopy)
+    : data (sourceData.getData()),
+      dataSize (sourceData.getSize()),
+      position (0)
+{
+    if (keepInternalCopy)
+        createInternalCopy();
+}
+
+void MemoryInputStream::createInternalCopy()
+{
+    internalCopy.malloc (dataSize);
+    memcpy (internalCopy, data, dataSize);
+    data = internalCopy;
+}
+
+MemoryInputStream::~MemoryInputStream()
+{
+}
+
+int64 MemoryInputStream::getTotalLength()
+{
+    return (int64) dataSize;
+}
+
+int MemoryInputStream::read (void* const buffer, const int howMany)
+{
+    jassert (buffer != nullptr && howMany >= 0);
+
+    const int num = jmin (howMany, (int) (dataSize - position));
+    if (num <= 0)
+        return 0;
+
+    memcpy (buffer, addBytesToPointer (data, position), (size_t) num);
+    position += (unsigned int) num;
+    return num;
+}
+
+bool MemoryInputStream::isExhausted()
+{
+    return position >= dataSize;
+}
+
+bool MemoryInputStream::setPosition (const int64 pos)
+{
+    position = (size_t) jlimit ((int64) 0, (int64) dataSize, pos);
+    return true;
+}
+
+int64 MemoryInputStream::getPosition()
+{
+    return (int64) position;
+}
+
+
+//==============================================================================
+#if JUCE_UNIT_TESTS
+
+class MemoryStreamTests  : public UnitTest
+{
+public:
+    MemoryStreamTests() : UnitTest ("MemoryInputStream & MemoryOutputStream") {}
+
+    void runTest()
+    {
+        beginTest ("Basics");
+        Random r = getRandom();
+
+        int randomInt = r.nextInt();
+        int64 randomInt64 = r.nextInt64();
+        double randomDouble = r.nextDouble();
+        String randomString (createRandomWideCharString (r));
+
+        MemoryOutputStream mo;
+        mo.writeInt (randomInt);
+        mo.writeIntBigEndian (randomInt);
+        mo.writeCompressedInt (randomInt);
+        mo.writeString (randomString);
+        mo.writeInt64 (randomInt64);
+        mo.writeInt64BigEndian (randomInt64);
+        mo.writeDouble (randomDouble);
+        mo.writeDoubleBigEndian (randomDouble);
+
+        MemoryInputStream mi (mo.getData(), mo.getDataSize(), false);
+        expect (mi.readInt() == randomInt);
+        expect (mi.readIntBigEndian() == randomInt);
+        expect (mi.readCompressedInt() == randomInt);
+        expectEquals (mi.readString(), randomString);
+        expect (mi.readInt64() == randomInt64);
+        expect (mi.readInt64BigEndian() == randomInt64);
+        expect (mi.readDouble() == randomDouble);
+        expect (mi.readDoubleBigEndian() == randomDouble);
+    }
+
+    static String createRandomWideCharString (Random& r)
+    {
+        juce_wchar buffer [50] = { 0 };
+
+        for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
+        {
+            if (r.nextBool())
+            {
+                do
+                {
+                    buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
+                }
+                while (! CharPointer_UTF16::canRepresent (buffer[i]));
+            }
+            else
+                buffer[i] = (juce_wchar) (1 + r.nextInt (0xff));
+        }
+
+        return CharPointer_UTF32 (buffer);
+    }
+};
+
+static MemoryStreamTests memoryInputStreamUnitTests;
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryInputStream.h b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryInputStream.h
new file mode 100644
index 0000000..013bc39
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryInputStream.h
@@ -0,0 +1,97 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_MEMORYINPUTSTREAM_H_INCLUDED
+#define JUCE_MEMORYINPUTSTREAM_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Allows a block of data to be accessed as a stream.
+
+    This can either be used to refer to a shared block of memory, or can make its
+    own internal copy of the data when the MemoryInputStream is created.
+*/
+class JUCE_API  MemoryInputStream  : public InputStream
+{
+public:
+    //==============================================================================
+    /** Creates a MemoryInputStream.
+
+        @param sourceData               the block of data to use as the stream's source
+        @param sourceDataSize           the number of bytes in the source data block
+        @param keepInternalCopyOfData   if false, the stream will just keep a pointer to
+                                        the source data, so this data shouldn't be changed
+                                        for the lifetime of the stream; if this parameter is
+                                        true, the stream will make its own copy of the
+                                        data and use that.
+    */
+    MemoryInputStream (const void* sourceData,
+                       size_t sourceDataSize,
+                       bool keepInternalCopyOfData);
+
+    /** Creates a MemoryInputStream.
+
+        @param data                     a block of data to use as the stream's source
+        @param keepInternalCopyOfData   if false, the stream will just keep a reference to
+                                        the source data, so this data shouldn't be changed
+                                        for the lifetime of the stream; if this parameter is
+                                        true, the stream will make its own copy of the
+                                        data and use that.
+    */
+    MemoryInputStream (const MemoryBlock& data,
+                       bool keepInternalCopyOfData);
+
+    /** Destructor. */
+    ~MemoryInputStream();
+
+    /** Returns a pointer to the source data block from which this stream is reading. */
+    const void* getData() const noexcept        { return data; }
+
+    /** Returns the number of bytes of source data in the block from which this stream is reading. */
+    size_t getDataSize() const noexcept         { return dataSize; }
+
+    //==============================================================================
+    int64 getPosition() override;
+    bool setPosition (int64 pos) override;
+    int64 getTotalLength() override;
+    bool isExhausted() override;
+    int read (void* destBuffer, int maxBytesToRead) override;
+
+private:
+    //==============================================================================
+    const void* data;
+    size_t dataSize, position;
+    HeapBlock<char> internalCopy;
+
+    void createInternalCopy();
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryInputStream)
+};
+
+#endif   // JUCE_MEMORYINPUTSTREAM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryOutputStream.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryOutputStream.cpp
new file mode 100644
index 0000000..835b2bd
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryOutputStream.cpp
@@ -0,0 +1,214 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+MemoryOutputStream::MemoryOutputStream (const size_t initialSize)
+  : blockToUse (&internalBlock), externalData (nullptr),
+    position (0), size (0), availableSize (0)
+{
+    internalBlock.setSize (initialSize, false);
+}
+
+MemoryOutputStream::MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo,
+                                        const bool appendToExistingBlockContent)
+  : blockToUse (&memoryBlockToWriteTo), externalData (nullptr),
+    position (0), size (0), availableSize (0)
+{
+    if (appendToExistingBlockContent)
+        position = size = memoryBlockToWriteTo.getSize();
+}
+
+MemoryOutputStream::MemoryOutputStream (void* destBuffer, size_t destBufferSize)
+  : blockToUse (nullptr), externalData (destBuffer),
+    position (0), size (0), availableSize (destBufferSize)
+{
+    jassert (externalData != nullptr); // This must be a valid pointer.
+}
+
+MemoryOutputStream::~MemoryOutputStream()
+{
+    trimExternalBlockSize();
+}
+
+void MemoryOutputStream::flush()
+{
+    trimExternalBlockSize();
+}
+
+void MemoryOutputStream::trimExternalBlockSize()
+{
+    if (blockToUse != &internalBlock && blockToUse != nullptr)
+        blockToUse->setSize (size, false);
+}
+
+void MemoryOutputStream::preallocate (const size_t bytesToPreallocate)
+{
+    if (blockToUse != nullptr)
+        blockToUse->ensureSize (bytesToPreallocate + 1);
+}
+
+void MemoryOutputStream::reset() noexcept
+{
+    position = 0;
+    size = 0;
+}
+
+char* MemoryOutputStream::prepareToWrite (size_t numBytes)
+{
+    jassert ((ssize_t) numBytes >= 0);
+    size_t storageNeeded = position + numBytes;
+
+    char* data;
+
+    if (blockToUse != nullptr)
+    {
+        if (storageNeeded >= blockToUse->getSize())
+            blockToUse->ensureSize ((storageNeeded + jmin (storageNeeded / 2, (size_t) (1024 * 1024)) + 32) & ~31u);
+
+        data = static_cast <char*> (blockToUse->getData());
+    }
+    else
+    {
+        if (storageNeeded > availableSize)
+            return nullptr;
+
+        data = static_cast <char*> (externalData);
+    }
+
+    char* const writePointer = data + position;
+    position += numBytes;
+    size = jmax (size, position);
+    return writePointer;
+}
+
+bool MemoryOutputStream::write (const void* const buffer, size_t howMany)
+{
+    jassert (buffer != nullptr);
+
+    if (howMany == 0)
+        return true;
+
+    if (char* dest = prepareToWrite (howMany))
+    {
+        memcpy (dest, buffer, howMany);
+        return true;
+    }
+
+    return false;
+}
+
+bool MemoryOutputStream::writeRepeatedByte (uint8 byte, size_t howMany)
+{
+    if (howMany == 0)
+        return true;
+
+    if (char* dest = prepareToWrite (howMany))
+    {
+        memset (dest, byte, howMany);
+        return true;
+    }
+
+    return false;
+}
+
+bool MemoryOutputStream::appendUTF8Char (juce_wchar c)
+{
+    if (char* dest = prepareToWrite (CharPointer_UTF8::getBytesRequiredFor (c)))
+    {
+        CharPointer_UTF8 (dest).write (c);
+        return true;
+    }
+
+    return false;
+}
+
+MemoryBlock MemoryOutputStream::getMemoryBlock() const
+{
+    return MemoryBlock (getData(), getDataSize());
+}
+
+const void* MemoryOutputStream::getData() const noexcept
+{
+    if (blockToUse == nullptr)
+        return externalData;
+
+    if (blockToUse->getSize() > size)
+        static_cast <char*> (blockToUse->getData()) [size] = 0;
+
+    return blockToUse->getData();
+}
+
+bool MemoryOutputStream::setPosition (int64 newPosition)
+{
+    if (newPosition <= (int64) size)
+    {
+        // ok to seek backwards
+        position = jlimit ((size_t) 0, size, (size_t) newPosition);
+        return true;
+    }
+
+    // can't move beyond the end of the stream..
+    return false;
+}
+
+int64 MemoryOutputStream::writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite)
+{
+    // before writing from an input, see if we can preallocate to make it more efficient..
+    int64 availableData = source.getTotalLength() - source.getPosition();
+
+    if (availableData > 0)
+    {
+        if (maxNumBytesToWrite > availableData)
+            maxNumBytesToWrite = availableData;
+
+        if (blockToUse != nullptr)
+            preallocate (blockToUse->getSize() + (size_t) maxNumBytesToWrite);
+    }
+
+    return OutputStream::writeFromInputStream (source, maxNumBytesToWrite);
+}
+
+String MemoryOutputStream::toUTF8() const
+{
+    const char* const d = static_cast <const char*> (getData());
+    return String (CharPointer_UTF8 (d), CharPointer_UTF8 (d + getDataSize()));
+}
+
+String MemoryOutputStream::toString() const
+{
+    return String::createStringFromData (getData(), (int) getDataSize());
+}
+
+OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryOutputStream& streamToRead)
+{
+    const size_t dataSize = streamToRead.getDataSize();
+
+    if (dataSize > 0)
+        stream.write (streamToRead.getData(), dataSize);
+
+    return stream;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryOutputStream.h b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryOutputStream.h
new file mode 100644
index 0000000..2e764ef
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_MemoryOutputStream.h
@@ -0,0 +1,139 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_MEMORYOUTPUTSTREAM_H_INCLUDED
+#define JUCE_MEMORYOUTPUTSTREAM_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Writes data to an internal memory buffer, which grows as required.
+
+    The data that was written into the stream can then be accessed later as
+    a contiguous block of memory.
+*/
+class JUCE_API  MemoryOutputStream  : public OutputStream
+{
+public:
+    //==============================================================================
+    /** Creates an empty memory stream, ready to be written into.
+        @param initialSize  the intial amount of capacity to allocate for writing into
+    */
+    MemoryOutputStream (size_t initialSize = 256);
+
+    /** Creates a memory stream for writing into into a pre-existing MemoryBlock object.
+
+        Note that the destination block will always be larger than the amount of data
+        that has been written to the stream, because the MemoryOutputStream keeps some
+        spare capactity at its end. To trim the block's size down to fit the actual
+        data, call flush(), or delete the MemoryOutputStream.
+
+        @param memoryBlockToWriteTo             the block into which new data will be written.
+        @param appendToExistingBlockContent     if this is true, the contents of the block will be
+                                                kept, and new data will be appended to it. If false,
+                                                the block will be cleared before use
+    */
+    MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo,
+                        bool appendToExistingBlockContent);
+
+    /** Creates a MemoryOutputStream that will write into a user-supplied, fixed-size
+        block of memory.
+        When using this mode, the stream will write directly into this memory area until
+        it's full, at which point write operations will fail.
+    */
+    MemoryOutputStream (void* destBuffer, size_t destBufferSize);
+
+    /** Destructor.
+        This will free any data that was written to it.
+    */
+    ~MemoryOutputStream();
+
+    //==============================================================================
+    /** Returns a pointer to the data that has been written to the stream.
+        @see getDataSize
+    */
+    const void* getData() const noexcept;
+
+    /** Returns the number of bytes of data that have been written to the stream.
+        @see getData
+    */
+    size_t getDataSize() const noexcept                 { return size; }
+
+    /** Resets the stream, clearing any data that has been written to it so far. */
+    void reset() noexcept;
+
+    /** Increases the internal storage capacity to be able to contain at least the specified
+        amount of data without needing to be resized.
+    */
+    void preallocate (size_t bytesToPreallocate);
+
+    /** Appends the utf-8 bytes for a unicode character */
+    bool appendUTF8Char (juce_wchar character);
+
+    /** Returns a String created from the (UTF8) data that has been written to the stream. */
+    String toUTF8() const;
+
+    /** Attempts to detect the encoding of the data and convert it to a string.
+        @see String::createStringFromData
+    */
+    String toString() const;
+
+    /** Returns a copy of the stream's data as a memory block. */
+    MemoryBlock getMemoryBlock() const;
+
+    //==============================================================================
+    /** If the stream is writing to a user-supplied MemoryBlock, this will trim any excess
+        capacity off the block, so that its length matches the amount of actual data that
+        has been written so far.
+    */
+    void flush();
+
+    bool write (const void*, size_t) override;
+    int64 getPosition() override                                 { return (int64) position; }
+    bool setPosition (int64) override;
+    int64 writeFromInputStream (InputStream&, int64 maxNumBytesToWrite) override;
+    bool writeRepeatedByte (uint8 byte, size_t numTimesToRepeat) override;
+
+private:
+    //==============================================================================
+    MemoryBlock* const blockToUse;
+    MemoryBlock internalBlock;
+    void* externalData;
+    size_t position, size, availableSize;
+
+    void trimExternalBlockSize();
+    char* prepareToWrite (size_t);
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryOutputStream)
+};
+
+/** Copies all the data that has been written to a MemoryOutputStream into another stream. */
+OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryOutputStream& streamToRead);
+
+
+#endif   // JUCE_MEMORYOUTPUTSTREAM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_OutputStream.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_OutputStream.cpp
new file mode 100644
index 0000000..c67e3fb
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_OutputStream.cpp
@@ -0,0 +1,351 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#if JUCE_DEBUG
+
+struct DanglingStreamChecker
+{
+    DanglingStreamChecker() {}
+
+    ~DanglingStreamChecker()
+    {
+        /*
+            It's always a bad idea to leak any object, but if you're leaking output
+            streams, then there's a good chance that you're failing to flush a file
+            to disk properly, which could result in corrupted data and other similar
+            nastiness..
+        */
+        jassert (activeStreams.size() == 0);
+    }
+
+    Array<void*, CriticalSection> activeStreams;
+};
+
+static DanglingStreamChecker danglingStreamChecker;
+#endif
+
+//==============================================================================
+OutputStream::OutputStream()
+    : newLineString (NewLine::getDefault())
+{
+   #if JUCE_DEBUG
+    danglingStreamChecker.activeStreams.add (this);
+   #endif
+}
+
+OutputStream::~OutputStream()
+{
+   #if JUCE_DEBUG
+    danglingStreamChecker.activeStreams.removeFirstMatchingValue (this);
+   #endif
+}
+
+//==============================================================================
+bool OutputStream::writeBool (const bool b)
+{
+    return writeByte (b ? (char) 1
+                        : (char) 0);
+}
+
+bool OutputStream::writeByte (char byte)
+{
+    return write (&byte, 1);
+}
+
+bool OutputStream::writeRepeatedByte (uint8 byte, size_t numTimesToRepeat)
+{
+    for (size_t i = 0; i < numTimesToRepeat; ++i)
+        if (! writeByte ((char) byte))
+            return false;
+
+    return true;
+}
+
+bool OutputStream::writeShort (short value)
+{
+    const unsigned short v = ByteOrder::swapIfBigEndian ((unsigned short) value);
+    return write (&v, 2);
+}
+
+bool OutputStream::writeShortBigEndian (short value)
+{
+    const unsigned short v = ByteOrder::swapIfLittleEndian ((unsigned short) value);
+    return write (&v, 2);
+}
+
+bool OutputStream::writeInt (int value)
+{
+    const unsigned int v = ByteOrder::swapIfBigEndian ((unsigned int) value);
+    return write (&v, 4);
+}
+
+bool OutputStream::writeIntBigEndian (int value)
+{
+    const unsigned int v = ByteOrder::swapIfLittleEndian ((unsigned int) value);
+    return write (&v, 4);
+}
+
+bool OutputStream::writeCompressedInt (int value)
+{
+    unsigned int un = (value < 0) ? (unsigned int) -value
+                                  : (unsigned int) value;
+
+    uint8 data[5];
+    int num = 0;
+
+    while (un > 0)
+    {
+        data[++num] = (uint8) un;
+        un >>= 8;
+    }
+
+    data[0] = (uint8) num;
+
+    if (value < 0)
+        data[0] |= 0x80;
+
+    return write (data, (size_t) num + 1);
+}
+
+bool OutputStream::writeInt64 (int64 value)
+{
+    const uint64 v = ByteOrder::swapIfBigEndian ((uint64) value);
+    return write (&v, 8);
+}
+
+bool OutputStream::writeInt64BigEndian (int64 value)
+{
+    const uint64 v = ByteOrder::swapIfLittleEndian ((uint64) value);
+    return write (&v, 8);
+}
+
+bool OutputStream::writeFloat (float value)
+{
+    union { int asInt; float asFloat; } n;
+    n.asFloat = value;
+    return writeInt (n.asInt);
+}
+
+bool OutputStream::writeFloatBigEndian (float value)
+{
+    union { int asInt; float asFloat; } n;
+    n.asFloat = value;
+    return writeIntBigEndian (n.asInt);
+}
+
+bool OutputStream::writeDouble (double value)
+{
+    union { int64 asInt; double asDouble; } n;
+    n.asDouble = value;
+    return writeInt64 (n.asInt);
+}
+
+bool OutputStream::writeDoubleBigEndian (double value)
+{
+    union { int64 asInt; double asDouble; } n;
+    n.asDouble = value;
+    return writeInt64BigEndian (n.asInt);
+}
+
+bool OutputStream::writeString (const String& text)
+{
+   #if (JUCE_STRING_UTF_TYPE == 8)
+    return write (text.toRawUTF8(), text.getNumBytesAsUTF8() + 1);
+   #else
+    // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
+    // if lots of large, persistent strings were to be written to streams).
+    const size_t numBytes = text.getNumBytesAsUTF8() + 1;
+    HeapBlock<char> temp (numBytes);
+    text.copyToUTF8 (temp, numBytes);
+    return write (temp, numBytes);
+   #endif
+}
+
+bool OutputStream::writeText (const String& text, const bool asUTF16,
+                              const bool writeUTF16ByteOrderMark)
+{
+    if (asUTF16)
+    {
+        if (writeUTF16ByteOrderMark)
+            write ("\x0ff\x0fe", 2);
+
+        String::CharPointerType src (text.getCharPointer());
+        bool lastCharWasReturn = false;
+
+        for (;;)
+        {
+            const juce_wchar c = src.getAndAdvance();
+
+            if (c == 0)
+                break;
+
+            if (c == '\n' && ! lastCharWasReturn)
+                writeShort ((short) '\r');
+
+            lastCharWasReturn = (c == L'\r');
+
+            if (! writeShort ((short) c))
+                return false;
+        }
+    }
+    else
+    {
+        const char* src = text.toUTF8();
+        const char* t = src;
+
+        for (;;)
+        {
+            if (*t == '\n')
+            {
+                if (t > src)
+                    if (! write (src, (size_t) (t - src)))
+                        return false;
+
+                if (! write ("\r\n", 2))
+                    return false;
+
+                src = t + 1;
+            }
+            else if (*t == '\r')
+            {
+                if (t[1] == '\n')
+                    ++t;
+            }
+            else if (*t == 0)
+            {
+                if (t > src)
+                    if (! write (src, (size_t) (t - src)))
+                        return false;
+
+                break;
+            }
+
+            ++t;
+        }
+    }
+
+    return true;
+}
+
+int64 OutputStream::writeFromInputStream (InputStream& source, int64 numBytesToWrite)
+{
+    if (numBytesToWrite < 0)
+        numBytesToWrite = std::numeric_limits<int64>::max();
+
+    int64 numWritten = 0;
+
+    while (numBytesToWrite > 0)
+    {
+        char buffer [8192];
+        const int num = source.read (buffer, (int) jmin (numBytesToWrite, (int64) sizeof (buffer)));
+
+        if (num <= 0)
+            break;
+
+        write (buffer, (size_t) num);
+
+        numBytesToWrite -= num;
+        numWritten += num;
+    }
+
+    return numWritten;
+}
+
+//==============================================================================
+void OutputStream::setNewLineString (const String& newLineString_)
+{
+    newLineString = newLineString_;
+}
+
+//==============================================================================
+template <typename IntegerType>
+static void writeIntToStream (OutputStream& stream, IntegerType number)
+{
+    char buffer [NumberToStringConverters::charsNeededForInt];
+    char* end = buffer + numElementsInArray (buffer);
+    const char* start = NumberToStringConverters::numberToString (end, number);
+    stream.write (start, (size_t) (end - start - 1));
+}
+
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int number)
+{
+    writeIntToStream (stream, number);
+    return stream;
+}
+
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const int64 number)
+{
+    writeIntToStream (stream, number);
+    return stream;
+}
+
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const double number)
+{
+    return stream << String (number);
+}
+
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char character)
+{
+    stream.writeByte (character);
+    return stream;
+}
+
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char* const text)
+{
+    stream.write (text, strlen (text));
+    return stream;
+}
+
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryBlock& data)
+{
+    if (data.getSize() > 0)
+        stream.write (data.getData(), data.getSize());
+
+    return stream;
+}
+
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead)
+{
+    FileInputStream in (fileToRead);
+
+    if (in.openedOk())
+        return stream << in;
+
+    return stream;
+}
+
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, InputStream& streamToRead)
+{
+    stream.writeFromInputStream (streamToRead, -1);
+    return stream;
+}
+
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const NewLine&)
+{
+    return stream << stream.getNewLineString();
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_OutputStream.h b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_OutputStream.h
new file mode 100644
index 0000000..102ab5a
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_OutputStream.h
@@ -0,0 +1,278 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_OUTPUTSTREAM_H_INCLUDED
+#define JUCE_OUTPUTSTREAM_H_INCLUDED
+
+
+//==============================================================================
+/**
+    The base class for streams that write data to some kind of destination.
+
+    Input and output streams are used throughout the library - subclasses can override
+    some or all of the virtual functions to implement their behaviour.
+
+    @see InputStream, MemoryOutputStream, FileOutputStream
+*/
+class JUCE_API  OutputStream
+{
+protected:
+    //==============================================================================
+    OutputStream();
+
+public:
+    /** Destructor.
+
+        Some subclasses might want to do things like call flush() during their
+        destructors.
+    */
+    virtual ~OutputStream();
+
+    //==============================================================================
+    /** If the stream is using a buffer, this will ensure it gets written
+        out to the destination. */
+    virtual void flush() = 0;
+
+    /** Tries to move the stream's output position.
+
+        Not all streams will be able to seek to a new position - this will return
+        false if it fails to work.
+
+        @see getPosition
+    */
+    virtual bool setPosition (int64 newPosition) = 0;
+
+    /** Returns the stream's current position.
+
+        @see setPosition
+    */
+    virtual int64 getPosition() = 0;
+
+    //==============================================================================
+    /** Writes a block of data to the stream.
+
+        When creating a subclass of OutputStream, this is the only write method
+        that needs to be overloaded - the base class has methods for writing other
+        types of data which use this to do the work.
+
+        @param dataToWrite      the target buffer to receive the data. This must not be null.
+        @param numberOfBytes    the number of bytes to write.
+        @returns false if the write operation fails for some reason
+    */
+    virtual bool write (const void* dataToWrite,
+                        size_t numberOfBytes) = 0;
+
+    //==============================================================================
+    /** Writes a single byte to the stream.
+        @returns false if the write operation fails for some reason
+        @see InputStream::readByte
+    */
+    virtual bool writeByte (char byte);
+
+    /** Writes a boolean to the stream as a single byte.
+        This is encoded as a binary byte (not as text) with a value of 1 or 0.
+        @returns false if the write operation fails for some reason
+        @see InputStream::readBool
+    */
+    virtual bool writeBool (bool boolValue);
+
+    /** Writes a 16-bit integer to the stream in a little-endian byte order.
+        This will write two bytes to the stream: (value & 0xff), then (value >> 8).
+        @returns false if the write operation fails for some reason
+        @see InputStream::readShort
+    */
+    virtual bool writeShort (short value);
+
+    /** Writes a 16-bit integer to the stream in a big-endian byte order.
+        This will write two bytes to the stream: (value >> 8), then (value & 0xff).
+        @returns false if the write operation fails for some reason
+        @see InputStream::readShortBigEndian
+    */
+    virtual bool writeShortBigEndian (short value);
+
+    /** Writes a 32-bit integer to the stream in a little-endian byte order.
+        @returns false if the write operation fails for some reason
+        @see InputStream::readInt
+    */
+    virtual bool writeInt (int value);
+
+    /** Writes a 32-bit integer to the stream in a big-endian byte order.
+        @returns false if the write operation fails for some reason
+        @see InputStream::readIntBigEndian
+    */
+    virtual bool writeIntBigEndian (int value);
+
+    /** Writes a 64-bit integer to the stream in a little-endian byte order.
+        @returns false if the write operation fails for some reason
+        @see InputStream::readInt64
+    */
+    virtual bool writeInt64 (int64 value);
+
+    /** Writes a 64-bit integer to the stream in a big-endian byte order.
+        @returns false if the write operation fails for some reason
+        @see InputStream::readInt64BigEndian
+    */
+    virtual bool writeInt64BigEndian (int64 value);
+
+    /** Writes a 32-bit floating point value to the stream in a binary format.
+        The binary 32-bit encoding of the float is written as a little-endian int.
+        @returns false if the write operation fails for some reason
+        @see InputStream::readFloat
+    */
+    virtual bool writeFloat (float value);
+
+    /** Writes a 32-bit floating point value to the stream in a binary format.
+        The binary 32-bit encoding of the float is written as a big-endian int.
+        @returns false if the write operation fails for some reason
+        @see InputStream::readFloatBigEndian
+    */
+    virtual bool writeFloatBigEndian (float value);
+
+    /** Writes a 64-bit floating point value to the stream in a binary format.
+        The eight raw bytes of the double value are written out as a little-endian 64-bit int.
+        @returns false if the write operation fails for some reason
+        @see InputStream::readDouble
+    */
+    virtual bool writeDouble (double value);
+
+    /** Writes a 64-bit floating point value to the stream in a binary format.
+        The eight raw bytes of the double value are written out as a big-endian 64-bit int.
+        @see InputStream::readDoubleBigEndian
+        @returns false if the write operation fails for some reason
+    */
+    virtual bool writeDoubleBigEndian (double value);
+
+    /** Writes a byte to the output stream a given number of times.
+        @returns false if the write operation fails for some reason
+    */
+    virtual bool writeRepeatedByte (uint8 byte, size_t numTimesToRepeat);
+
+    /** Writes a condensed binary encoding of a 32-bit integer.
+
+        If you're storing a lot of integers which are unlikely to have very large values,
+        this can save a lot of space, because values under 0xff will only take up 2 bytes,
+        under 0xffff only 3 bytes, etc.
+
+        The format used is: number of significant bytes + up to 4 bytes in little-endian order.
+
+        @returns false if the write operation fails for some reason
+        @see InputStream::readCompressedInt
+    */
+    virtual bool writeCompressedInt (int value);
+
+    /** Stores a string in the stream in a binary format.
+
+        This isn't the method to use if you're trying to append text to the end of a
+        text-file! It's intended for storing a string so that it can be retrieved later
+        by InputStream::readString().
+
+        It writes the string to the stream as UTF8, including the null termination character.
+
+        For appending text to a file, instead use writeText, or operator<<
+
+        @returns false if the write operation fails for some reason
+        @see InputStream::readString, writeText, operator<<
+    */
+    virtual bool writeString (const String& text);
+
+    /** Writes a string of text to the stream.
+
+        It can either write the text as UTF-8 or UTF-16, and can also add the UTF-16 byte-order-mark
+        bytes (0xff, 0xfe) to indicate the endianness (these should only be used at the start
+        of a file).
+
+        The method also replaces '\\n' characters in the text with '\\r\\n'.
+        @returns false if the write operation fails for some reason
+    */
+    virtual bool writeText (const String& text,
+                            bool asUTF16,
+                            bool writeUTF16ByteOrderMark);
+
+    /** Reads data from an input stream and writes it to this stream.
+
+        @param source               the stream to read from
+        @param maxNumBytesToWrite   the number of bytes to read from the stream (if this is
+                                    less than zero, it will keep reading until the input
+                                    is exhausted)
+        @returns the number of bytes written
+    */
+    virtual int64 writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite);
+
+    //==============================================================================
+    /** Sets the string that will be written to the stream when the writeNewLine()
+        method is called.
+        By default this will be set the value of NewLine::getDefault().
+    */
+    void setNewLineString (const String& newLineString);
+
+    /** Returns the current new-line string that was set by setNewLineString(). */
+    const String& getNewLineString() const noexcept         { return newLineString; }
+
+private:
+    //==============================================================================
+    String newLineString;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OutputStream)
+};
+
+//==============================================================================
+/** Writes a number to a stream as 8-bit characters in the default system encoding. */
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, int number);
+
+/** Writes a number to a stream as 8-bit characters in the default system encoding. */
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, int64 number);
+
+/** Writes a number to a stream as 8-bit characters in the default system encoding. */
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, double number);
+
+/** Writes a character to a stream. */
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, char character);
+
+/** Writes a null-terminated text string to a stream. */
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char* text);
+
+/** Writes a block of data from a MemoryBlock to a stream. */
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryBlock& data);
+
+/** Writes the contents of a file to a stream. */
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead);
+
+/** Writes the complete contents of an input stream to an output stream. */
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, InputStream& streamToRead);
+
+/** Writes a new-line to a stream.
+    You can use the predefined symbol 'newLine' to invoke this, e.g.
+    @code
+    myOutputStream << "Hello World" << newLine << newLine;
+    @endcode
+    @see OutputStream::setNewLineString
+*/
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const NewLine&);
+
+
+#endif   // JUCE_OUTPUTSTREAM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_SubregionStream.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_SubregionStream.cpp
new file mode 100644
index 0000000..c998c79
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_SubregionStream.cpp
@@ -0,0 +1,82 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+SubregionStream::SubregionStream (InputStream* const sourceStream,
+                                  const int64 start, const int64 length,
+                                  const bool deleteSourceWhenDestroyed)
+  : source (sourceStream, deleteSourceWhenDestroyed),
+    startPositionInSourceStream (start),
+    lengthOfSourceStream (length)
+{
+    SubregionStream::setPosition (0);
+}
+
+SubregionStream::~SubregionStream()
+{
+}
+
+int64 SubregionStream::getTotalLength()
+{
+    const int64 srcLen = source->getTotalLength() - startPositionInSourceStream;
+
+    return lengthOfSourceStream >= 0 ? jmin (lengthOfSourceStream, srcLen)
+                                     : srcLen;
+}
+
+int64 SubregionStream::getPosition()
+{
+    return source->getPosition() - startPositionInSourceStream;
+}
+
+bool SubregionStream::setPosition (int64 newPosition)
+{
+    return source->setPosition (jmax ((int64) 0, newPosition + startPositionInSourceStream));
+}
+
+int SubregionStream::read (void* destBuffer, int maxBytesToRead)
+{
+    jassert (destBuffer != nullptr && maxBytesToRead >= 0);
+
+    if (lengthOfSourceStream < 0)
+        return source->read (destBuffer, maxBytesToRead);
+
+    maxBytesToRead = (int) jmin ((int64) maxBytesToRead, lengthOfSourceStream - getPosition());
+
+    if (maxBytesToRead <= 0)
+        return 0;
+
+    return source->read (destBuffer, maxBytesToRead);
+}
+
+bool SubregionStream::isExhausted()
+{
+    if (lengthOfSourceStream >= 0 && getPosition() >= lengthOfSourceStream)
+        return true;
+
+    return source->isExhausted();
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_SubregionStream.h b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_SubregionStream.h
new file mode 100644
index 0000000..d291a03
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/streams/juce_SubregionStream.h
@@ -0,0 +1,88 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SUBREGIONSTREAM_H_INCLUDED
+#define JUCE_SUBREGIONSTREAM_H_INCLUDED
+
+
+//==============================================================================
+/** Wraps another input stream, and reads from a specific part of it.
+
+    This lets you take a subsection of a stream and present it as an entire
+    stream in its own right.
+*/
+class JUCE_API  SubregionStream  : public InputStream
+{
+public:
+    //==============================================================================
+    /** Creates a SubregionStream from an input source.
+
+        @param sourceStream                 the source stream to read from
+        @param startPositionInSourceStream  this is the position in the source stream that
+                                            corresponds to position 0 in this stream
+        @param lengthOfSourceStream         this specifies the maximum number of bytes
+                                            from the source stream that will be passed through
+                                            by this stream. When the position of this stream
+                                            exceeds lengthOfSourceStream, it will cause an end-of-stream.
+                                            If the length passed in here is greater than the length
+                                            of the source stream (as returned by getTotalLength()),
+                                            then the smaller value will be used.
+                                            Passing a negative value for this parameter means it
+                                            will keep reading until the source's end-of-stream.
+        @param deleteSourceWhenDestroyed    whether the sourceStream that is passed in should be
+                                            deleted by this object when it is itself deleted.
+    */
+    SubregionStream (InputStream* sourceStream,
+                     int64 startPositionInSourceStream,
+                     int64 lengthOfSourceStream,
+                     bool deleteSourceWhenDestroyed);
+
+    /** Destructor.
+
+        This may also delete the source stream, if that option was chosen when the
+        buffered stream was created.
+    */
+    ~SubregionStream();
+
+
+    //==============================================================================
+    int64 getTotalLength() override;
+    int64 getPosition() override;
+    bool setPosition (int64 newPosition) override;
+    int read (void* destBuffer, int maxBytesToRead) override;
+    bool isExhausted() override;
+
+private:
+    //==============================================================================
+    OptionalScopedPointer<InputStream> source;
+    const int64 startPositionInSourceStream, lengthOfSourceStream;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SubregionStream)
+};
+
+#endif   // JUCE_SUBREGIONSTREAM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_PlatformDefs.h b/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_PlatformDefs.h
new file mode 100644
index 0000000..1271185
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_PlatformDefs.h
@@ -0,0 +1,388 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_PLATFORMDEFS_H_INCLUDED
+#define JUCE_PLATFORMDEFS_H_INCLUDED
+
+//==============================================================================
+/*  This file defines miscellaneous macros for debugging, assertions, etc.
+*/
+
+//==============================================================================
+#ifdef JUCE_FORCE_DEBUG
+ #undef JUCE_DEBUG
+
+ #if JUCE_FORCE_DEBUG
+  #define JUCE_DEBUG 1
+ #endif
+#endif
+
+/** This macro defines the C calling convention used as the standard for Juce calls. */
+#if JUCE_MSVC
+ #define JUCE_CALLTYPE   __stdcall
+ #define JUCE_CDECL      __cdecl
+#else
+ #define JUCE_CALLTYPE
+ #define JUCE_CDECL
+#endif
+
+//==============================================================================
+// Debugging and assertion macros
+
+#if JUCE_LOG_ASSERTIONS || JUCE_DEBUG
+ #define juce_LogCurrentAssertion    juce::logAssertion (__FILE__, __LINE__);
+#else
+ #define juce_LogCurrentAssertion
+#endif
+
+//==============================================================================
+#if JUCE_IOS || JUCE_LINUX || JUCE_ANDROID || JUCE_PPC
+  /** This will try to break into the debugger if the app is currently being debugged.
+      If called by an app that's not being debugged, the behaiour isn't defined - it may crash or not, depending
+      on the platform.
+      @see jassert()
+  */
+  #define juce_breakDebugger        { ::kill (0, SIGTRAP); }
+#elif JUCE_USE_INTRINSICS
+  #ifndef __INTEL_COMPILER
+    #pragma intrinsic (__debugbreak)
+  #endif
+  #define juce_breakDebugger        { __debugbreak(); }
+#elif JUCE_GCC || JUCE_MAC
+  #if JUCE_NO_INLINE_ASM
+   #define juce_breakDebugger       { }
+  #else
+   #define juce_breakDebugger       { asm ("int $3"); }
+  #endif
+#else
+  #define juce_breakDebugger        { __asm int 3 }
+#endif
+
+#if JUCE_CLANG && defined (__has_feature) && ! defined (JUCE_ANALYZER_NORETURN)
+ #if __has_feature (attribute_analyzer_noreturn)
+  inline void __attribute__((analyzer_noreturn)) juce_assert_noreturn() {}
+  #define JUCE_ANALYZER_NORETURN juce_assert_noreturn();
+ #endif
+#endif
+
+#ifndef JUCE_ANALYZER_NORETURN
+ #define JUCE_ANALYZER_NORETURN
+#endif
+
+//==============================================================================
+#if JUCE_DEBUG || DOXYGEN
+  /** Writes a string to the standard error stream.
+      This is only compiled in a debug build.
+      @see Logger::outputDebugString
+  */
+  #define DBG(dbgtext)              { juce::String tempDbgBuf; tempDbgBuf << dbgtext; juce::Logger::outputDebugString (tempDbgBuf); }
+
+  //==============================================================================
+  /** This will always cause an assertion failure.
+      It is only compiled in a debug build, (unless JUCE_LOG_ASSERTIONS is enabled for your build).
+      @see jassert
+  */
+  #define jassertfalse              { juce_LogCurrentAssertion; if (juce::juce_isRunningUnderDebugger()) juce_breakDebugger; JUCE_ANALYZER_NORETURN }
+
+  //==============================================================================
+  /** Platform-independent assertion macro.
+
+      This macro gets turned into a no-op when you're building with debugging turned off, so be
+      careful that the expression you pass to it doesn't perform any actions that are vital for the
+      correct behaviour of your program!
+      @see jassertfalse
+  */
+  #define jassert(expression)       { if (! (expression)) jassertfalse; }
+
+#else
+  //==============================================================================
+  // If debugging is disabled, these dummy debug and assertion macros are used..
+
+  #define DBG(dbgtext)
+  #define jassertfalse              { juce_LogCurrentAssertion }
+
+  #if JUCE_LOG_ASSERTIONS
+   #define jassert(expression)      { if (! (expression)) jassertfalse; }
+  #else
+   #define jassert(a)               {}
+  #endif
+
+#endif
+
+//==============================================================================
+#ifndef DOXYGEN
+namespace htio2
+{
+namespace juce
+{
+    template <bool b> struct JuceStaticAssert;
+    template <> struct JuceStaticAssert <true> { static void dummy() {} };
+}
+}
+#endif
+
+/** A compile-time assertion macro.
+    If the expression parameter is false, the macro will cause a compile error. (The actual error
+    message that the compiler generates may be completely bizarre and seem to have no relation to
+    the place where you put the static_assert though!)
+*/
+#define static_jassert(expression)      juce::JuceStaticAssert<expression>::dummy();
+
+/** This is a shorthand macro for declaring stubs for a class's copy constructor and operator=.
+
+    For example, instead of
+    @code
+    class MyClass
+    {
+        etc..
+
+    private:
+        MyClass (const MyClass&);
+        MyClass& operator= (const MyClass&);
+    };@endcode
+
+    ..you can just write:
+
+    @code
+    class MyClass
+    {
+        etc..
+
+    private:
+        JUCE_DECLARE_NON_COPYABLE (MyClass)
+    };@endcode
+*/
+#define JUCE_DECLARE_NON_COPYABLE(className) \
+    className (const className&) JUCE_DELETED_FUNCTION;\
+    className& operator= (const className&) JUCE_DELETED_FUNCTION;
+
+/** This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and
+    JUCE_LEAK_DETECTOR macro for a class.
+*/
+#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className) \
+    JUCE_DECLARE_NON_COPYABLE(className) \
+    JUCE_LEAK_DETECTOR(className)
+
+/** This macro can be added to class definitions to disable the use of new/delete to
+    allocate the object on the heap, forcing it to only be used as a stack or member variable.
+*/
+#define JUCE_PREVENT_HEAP_ALLOCATION \
+   private: \
+    static void* operator new (size_t) JUCE_DELETED_FUNCTION; \
+    static void operator delete (void*) JUCE_DELETED_FUNCTION;
+
+
+//==============================================================================
+#if ! DOXYGEN
+ #define JUCE_JOIN_MACRO_HELPER(a, b) a ## b
+ #define JUCE_STRINGIFY_MACRO_HELPER(a) #a
+#endif
+
+/** A good old-fashioned C macro concatenation helper.
+    This combines two items (which may themselves be macros) into a single string,
+    avoiding the pitfalls of the ## macro operator.
+*/
+#define JUCE_JOIN_MACRO(item1, item2)  JUCE_JOIN_MACRO_HELPER (item1, item2)
+
+/** A handy C macro for stringifying any symbol, rather than just a macro parameter.
+*/
+#define JUCE_STRINGIFY(item)  JUCE_STRINGIFY_MACRO_HELPER (item)
+
+
+//==============================================================================
+#if JUCE_CATCH_UNHANDLED_EXCEPTIONS
+
+  #define JUCE_TRY try
+
+  #define JUCE_CATCH_ALL            catch (...) {}
+  #define JUCE_CATCH_ALL_ASSERT     catch (...) { jassertfalse; }
+
+  #if ! JUCE_MODULE_AVAILABLE_juce_gui_basics
+    #define JUCE_CATCH_EXCEPTION    JUCE_CATCH_ALL
+  #else
+    /** Used in try-catch blocks, this macro will send exceptions to the JUCEApplicationBase
+        object so they can be logged by the application if it wants to.
+    */
+    #define JUCE_CATCH_EXCEPTION \
+      catch (const std::exception& e)  \
+      { \
+          juce::JUCEApplicationBase::sendUnhandledException (&e, __FILE__, __LINE__); \
+      } \
+      catch (...) \
+      { \
+          juce::JUCEApplicationBase::sendUnhandledException (nullptr, __FILE__, __LINE__); \
+      }
+  #endif
+
+#else
+
+  #define JUCE_TRY
+  #define JUCE_CATCH_EXCEPTION
+  #define JUCE_CATCH_ALL
+  #define JUCE_CATCH_ALL_ASSERT
+
+#endif
+
+//==============================================================================
+#if JUCE_DEBUG || DOXYGEN
+  /** A platform-independent way of forcing an inline function.
+      Use the syntax: @code
+      forcedinline void myfunction (int x)
+      @endcode
+  */
+  #define forcedinline  inline
+#else
+  #if JUCE_MSVC
+   #define forcedinline       __forceinline
+  #else
+   #define forcedinline       inline __attribute__((always_inline))
+  #endif
+#endif
+
+#if JUCE_MSVC || DOXYGEN
+  /** This can be placed before a stack or member variable declaration to tell the compiler
+      to align it to the specified number of bytes. */
+  #define JUCE_ALIGN(bytes)   __declspec (align (bytes))
+#else
+  #define JUCE_ALIGN(bytes)   __attribute__ ((aligned (bytes)))
+#endif
+
+//==============================================================================
+// Cross-compiler deprecation macros..
+#ifdef DOXYGEN
+ /** This macro can be used to wrap a function which has been deprecated. */
+ #define JUCE_DEPRECATED(functionDef)
+ #define JUCE_DEPRECATED_WITH_BODY(functionDef, body)
+#elif JUCE_MSVC && ! JUCE_NO_DEPRECATION_WARNINGS
+ #define JUCE_DEPRECATED(functionDef)                   __declspec(deprecated) functionDef
+ #define JUCE_DEPRECATED_WITH_BODY(functionDef, body)   __declspec(deprecated) functionDef body
+#elif JUCE_GCC && ! JUCE_NO_DEPRECATION_WARNINGS
+ #define JUCE_DEPRECATED(functionDef)                   functionDef __attribute__ ((deprecated))
+ #define JUCE_DEPRECATED_WITH_BODY(functionDef, body)   functionDef __attribute__ ((deprecated)) body
+#else
+ #define JUCE_DEPRECATED(functionDef)                   functionDef
+ #define JUCE_DEPRECATED_WITH_BODY(functionDef, body)   functionDef body
+#endif
+
+//==============================================================================
+#if JUCE_ANDROID && ! DOXYGEN
+ #define JUCE_MODAL_LOOPS_PERMITTED 0
+#elif ! defined (JUCE_MODAL_LOOPS_PERMITTED)
+ /** Some operating environments don't provide a modal loop mechanism, so this flag can be
+     used to disable any functions that try to run a modal loop. */
+ #define JUCE_MODAL_LOOPS_PERMITTED 1
+#endif
+
+//==============================================================================
+#if JUCE_GCC
+ #define JUCE_PACKED __attribute__((packed))
+#elif ! DOXYGEN
+ #define JUCE_PACKED
+#endif
+
+//==============================================================================
+// Here, we'll check for C++11 compiler support, and if it's not available, define
+// a few workarounds, so that we can still use some of the newer language features.
+#if (__cplusplus >= 201103L || defined (__GXX_EXPERIMENTAL_CXX0X__)) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
+ #define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1
+ #define JUCE_COMPILER_SUPPORTS_NULLPTR 1
+ #define JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS 1
+
+ #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && ! defined (JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL)
+  #define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
+ #endif
+
+ #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && ! defined (JUCE_DELETED_FUNCTION)
+  #define JUCE_DELETED_FUNCTION = delete
+ #endif
+#endif
+
+#if JUCE_CLANG && defined (__has_feature)
+ #if __has_feature (cxx_nullptr)
+  #define JUCE_COMPILER_SUPPORTS_NULLPTR 1
+ #endif
+
+ #if __has_feature (cxx_noexcept)
+  #define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1
+ #endif
+
+ #if __has_feature (cxx_rvalue_references)
+  #define JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS 1
+ #endif
+
+ #if __has_feature (cxx_deleted_functions)
+  #define JUCE_DELETED_FUNCTION = delete
+ #endif
+
+ #ifndef JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL
+  #define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
+ #endif
+
+ #ifndef JUCE_COMPILER_SUPPORTS_ARC
+  #define JUCE_COMPILER_SUPPORTS_ARC 1
+ #endif
+#endif
+
+#if defined (_MSC_VER) && _MSC_VER >= 1600
+ #define JUCE_COMPILER_SUPPORTS_NULLPTR 1
+ #define JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS 1
+#endif
+
+#if defined (_MSC_VER) && _MSC_VER >= 1700
+ #define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
+#endif
+
+#ifndef JUCE_DELETED_FUNCTION
+ #define JUCE_DELETED_FUNCTION
+#endif
+
+//==============================================================================
+// Declare some fake versions of nullptr and noexcept, for older compilers:
+#if ! (DOXYGEN || JUCE_COMPILER_SUPPORTS_NOEXCEPT)
+ #ifdef noexcept
+  #undef noexcept
+ #endif
+ #define noexcept  throw()
+ #if defined (_MSC_VER) && _MSC_VER > 1600
+  #define _ALLOW_KEYWORD_MACROS 1 // (to stop VC2012 complaining)
+ #endif
+#endif
+
+#if ! (DOXYGEN || JUCE_COMPILER_SUPPORTS_NULLPTR)
+ #ifdef nullptr
+  #undef nullptr
+ #endif
+ #define nullptr (0)
+#endif
+
+#if ! (DOXYGEN || JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL)
+ #undef  override
+ #define override
+#endif
+
+#endif   // JUCE_PLATFORMDEFS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_StandardHeader.h b/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_StandardHeader.h
new file mode 100644
index 0000000..2f420e8
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_StandardHeader.h
@@ -0,0 +1,157 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_STANDARDHEADER_H_INCLUDED
+#define JUCE_STANDARDHEADER_H_INCLUDED
+
+//==============================================================================
+/** Current JUCE version number.
+
+    See also SystemStats::getJUCEVersion() for a string version.
+*/
+#define JUCE_MAJOR_VERSION      3
+#define JUCE_MINOR_VERSION      0
+#define JUCE_BUILDNUMBER        8
+
+/** Current Juce version number.
+
+    Bits 16 to 32 = major version.
+    Bits 8 to 16 = minor version.
+    Bits 0 to 8 = point release.
+
+    See also SystemStats::getJUCEVersion() for a string version.
+*/
+#define JUCE_VERSION   ((JUCE_MAJOR_VERSION << 16) + (JUCE_MINOR_VERSION << 8) + JUCE_BUILDNUMBER)
+
+
+//==============================================================================
+#include "juce_PlatformDefs.h"
+
+//==============================================================================
+// Now we'll include some common OS headers..
+#if JUCE_MSVC
+ #pragma warning (push)
+ #pragma warning (disable: 4514 4245 4100)
+#endif
+
+#include <cstdlib>
+#include <cstdarg>
+#include <climits>
+#include <limits>
+#include <cmath>
+#include <cwchar>
+#include <stdexcept>
+#include <typeinfo>
+#include <cstring>
+#include <cstdio>
+#include <iostream>
+#include <vector>
+#include <algorithm>
+
+#if JUCE_USE_INTRINSICS
+ #include <intrin.h>
+#endif
+
+#if JUCE_MAC || JUCE_IOS
+ #include <libkern/OSAtomic.h>
+#endif
+
+#if JUCE_LINUX
+ #include <signal.h>
+
+ #if __INTEL_COMPILER
+  #if __ia64__
+   #include <ia64intrin.h>
+  #else
+   #include <ia32intrin.h>
+  #endif
+ #endif
+#endif
+
+#if JUCE_MSVC && JUCE_DEBUG
+ #include <crtdbg.h>
+#endif
+
+#if JUCE_MSVC
+ #pragma warning (pop)
+#endif
+
+#if JUCE_ANDROID
+ #include <sys/atomics.h>
+ #include <byteswap.h>
+#endif
+
+// undef symbols that are sometimes set by misguided 3rd-party headers..
+#undef check
+#undef TYPE_BOOL
+#undef max
+#undef min
+
+//==============================================================================
+// DLL building settings on Windows
+#if JUCE_MSVC
+ #ifdef JUCE_DLL_BUILD
+  #define JUCE_API __declspec (dllexport)
+  #pragma warning (disable: 4251)
+ #elif defined (JUCE_DLL)
+  #define JUCE_API __declspec (dllimport)
+  #pragma warning (disable: 4251)
+ #endif
+ #ifdef __INTEL_COMPILER
+  #pragma warning (disable: 1125) // (virtual override warning)
+ #endif
+#elif defined (JUCE_DLL) || defined (JUCE_DLL_BUILD)
+ #define JUCE_API __attribute__ ((visibility("default")))
+#endif
+
+//==============================================================================
+#ifndef JUCE_API
+ #define JUCE_API   /**< This macro is added to all juce public class declarations. */
+#endif
+
+#if JUCE_MSVC && JUCE_DLL_BUILD
+ #define JUCE_PUBLIC_IN_DLL_BUILD(declaration)  public: declaration; private:
+#else
+ #define JUCE_PUBLIC_IN_DLL_BUILD(declaration)  declaration;
+#endif
+
+/** This macro is added to all juce public function declarations. */
+#define JUCE_PUBLIC_FUNCTION        JUCE_API JUCE_CALLTYPE
+
+#if (! defined (JUCE_CATCH_DEPRECATED_CODE_MISUSE)) && JUCE_DEBUG && ! DOXYGEN
+ /** This turns on some non-essential bits of code that should prevent old code from compiling
+     in cases where method signatures have changed, etc.
+ */
+ #define JUCE_CATCH_DEPRECATED_CODE_MISUSE 1
+#endif
+
+#ifndef DOXYGEN
+ #define JUCE_NAMESPACE juce  // This old macro is deprecated: you should just use the juce namespace directly.
+#endif
+
+#endif   // JUCE_STANDARDHEADER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_SystemStats.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_SystemStats.cpp
new file mode 100644
index 0000000..365e94d
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_SystemStats.cpp
@@ -0,0 +1,183 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+String SystemStats::getJUCEVersion()
+{
+    // Some basic tests, to keep an eye on things and make sure these types work ok
+    // on all platforms. Let me know if any of these assertions fail on your system!
+    static_jassert (sizeof (pointer_sized_int) == sizeof (void*));
+    static_jassert (sizeof (int8) == 1);
+    static_jassert (sizeof (uint8) == 1);
+    static_jassert (sizeof (int16) == 2);
+    static_jassert (sizeof (uint16) == 2);
+    static_jassert (sizeof (int32) == 4);
+    static_jassert (sizeof (uint32) == 4);
+    static_jassert (sizeof (int64) == 8);
+    static_jassert (sizeof (uint64) == 8);
+
+    return "JUCE v" JUCE_STRINGIFY(JUCE_MAJOR_VERSION)
+                "." JUCE_STRINGIFY(JUCE_MINOR_VERSION)
+                "." JUCE_STRINGIFY(JUCE_BUILDNUMBER);
+}
+
+#if JUCE_ANDROID && ! defined (JUCE_DISABLE_JUCE_VERSION_PRINTING)
+ #define JUCE_DISABLE_JUCE_VERSION_PRINTING 1
+#endif
+
+#if JUCE_DEBUG && ! JUCE_DISABLE_JUCE_VERSION_PRINTING
+ struct JuceVersionPrinter
+ {
+     JuceVersionPrinter()
+     {
+         DBG (SystemStats::getJUCEVersion());
+     }
+ };
+
+ static JuceVersionPrinter juceVersionPrinter;
+#endif
+
+
+//==============================================================================
+struct CPUInformation
+{
+    CPUInformation() noexcept
+        : numCpus (0), hasMMX (false), hasSSE (false),
+          hasSSE2 (false), hasSSE3 (false), has3DNow (false)
+    {
+        initialise();
+    }
+
+    void initialise() noexcept;
+
+    int numCpus;
+    bool hasMMX, hasSSE, hasSSE2, hasSSE3, has3DNow;
+};
+
+static const CPUInformation& getCPUInformation() noexcept
+{
+    static CPUInformation info;
+    return info;
+}
+
+int SystemStats::getNumCpus() noexcept        { return getCPUInformation().numCpus; }
+bool SystemStats::hasMMX() noexcept           { return getCPUInformation().hasMMX; }
+bool SystemStats::hasSSE() noexcept           { return getCPUInformation().hasSSE; }
+bool SystemStats::hasSSE2() noexcept          { return getCPUInformation().hasSSE2; }
+bool SystemStats::hasSSE3() noexcept          { return getCPUInformation().hasSSE3; }
+bool SystemStats::has3DNow() noexcept         { return getCPUInformation().has3DNow; }
+
+
+//==============================================================================
+String SystemStats::getStackBacktrace()
+{
+    String result;
+
+   #if JUCE_ANDROID || JUCE_MINGW
+    jassertfalse; // sorry, not implemented yet!
+
+   #elif JUCE_WINDOWS
+    HANDLE process = GetCurrentProcess();
+    SymInitialize (process, nullptr, TRUE);
+
+    void* stack[128];
+    int frames = (int) CaptureStackBackTrace (0, numElementsInArray (stack), stack, nullptr);
+
+    HeapBlock<SYMBOL_INFO> symbol;
+    symbol.calloc (sizeof (SYMBOL_INFO) + 256, 1);
+    symbol->MaxNameLen = 255;
+    symbol->SizeOfStruct = sizeof (SYMBOL_INFO);
+
+    for (int i = 0; i < frames; ++i)
+    {
+        DWORD64 displacement = 0;
+
+        if (SymFromAddr (process, (DWORD64) stack[i], &displacement, symbol))
+        {
+            result << i << ": ";
+
+            IMAGEHLP_MODULE64 moduleInfo;
+            zerostruct (moduleInfo);
+            moduleInfo.SizeOfStruct = sizeof (moduleInfo);
+
+            if (::SymGetModuleInfo64 (process, symbol->ModBase, &moduleInfo))
+                result << moduleInfo.ModuleName << ": ";
+
+            result << symbol->Name << " + 0x" << String::toHexString ((int64) displacement) << newLine;
+        }
+    }
+
+   #else
+    void* stack[128];
+    int frames = backtrace (stack, numElementsInArray (stack));
+    char** frameStrings = backtrace_symbols (stack, frames);
+
+    for (int i = 0; i < frames; ++i)
+        result << frameStrings[i] << newLine;
+
+    ::free (frameStrings);
+   #endif
+
+    return result;
+}
+
+//==============================================================================
+static SystemStats::CrashHandlerFunction globalCrashHandler = nullptr;
+
+#if JUCE_WINDOWS
+static LONG WINAPI handleCrash (LPEXCEPTION_POINTERS)
+{
+    globalCrashHandler();
+    return EXCEPTION_EXECUTE_HANDLER;
+}
+#else
+static void handleCrash (int)
+{
+    globalCrashHandler();
+    kill (getpid(), SIGKILL);
+}
+
+int juce_siginterrupt (int sig, int flag);
+#endif
+
+void SystemStats::setApplicationCrashHandler (CrashHandlerFunction handler)
+{
+    jassert (handler != nullptr); // This must be a valid function.
+    globalCrashHandler = handler;
+
+   #if JUCE_WINDOWS
+    SetUnhandledExceptionFilter (handleCrash);
+   #else
+    const int signals[] = { SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGABRT, SIGSYS };
+
+    for (int i = 0; i < numElementsInArray (signals); ++i)
+    {
+        ::signal (signals[i], handleCrash);
+        juce_siginterrupt (signals[i], 1);
+    }
+   #endif
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_SystemStats.h b/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_SystemStats.h
new file mode 100644
index 0000000..835e6e6
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_SystemStats.h
@@ -0,0 +1,195 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SYSTEMSTATS_H_INCLUDED
+#define JUCE_SYSTEMSTATS_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Contains methods for finding out about the current hardware and OS configuration.
+*/
+class JUCE_API  SystemStats
+{
+public:
+    //==============================================================================
+    /** Returns the current version of JUCE,
+        See also the JUCE_VERSION, JUCE_MAJOR_VERSION and JUCE_MINOR_VERSION macros.
+    */
+    static String getJUCEVersion();
+
+    //==============================================================================
+    /** The set of possible results of the getOperatingSystemType() method. */
+    enum OperatingSystemType
+    {
+        UnknownOS   = 0,
+
+        Linux       = 0x2000,
+        Android     = 0x3000,
+        iOS         = 0x8000,
+
+        MacOSX_10_4 = 0x1004,
+        MacOSX_10_5 = 0x1005,
+        MacOSX_10_6 = 0x1006,
+        MacOSX_10_7 = 0x1007,
+        MacOSX_10_8 = 0x1008,
+        MacOSX_10_9 = 0x1009,
+
+        Win2000     = 0x4105,
+        WinXP       = 0x4106,
+        WinVista    = 0x4107,
+        Windows7    = 0x4108,
+        Windows8_0  = 0x4109,
+        Windows8_1  = 0x410a,
+
+        Windows     = 0x4000,   /**< To test whether any version of Windows is running,
+                                     you can use the expression ((getOperatingSystemType() & Windows) != 0). */
+    };
+
+    /** Returns the type of operating system we're running on.
+
+        @returns one of the values from the OperatingSystemType enum.
+        @see getOperatingSystemName
+    */
+    static OperatingSystemType getOperatingSystemType();
+
+    /** Returns the name of the type of operating system we're running on.
+
+        @returns a string describing the OS type.
+        @see getOperatingSystemType
+    */
+    static String getOperatingSystemName();
+
+    /** Returns true if the OS is 64-bit, or false for a 32-bit OS. */
+    static bool isOperatingSystem64Bit();
+
+    /** Returns an environment variable.
+        If the named value isn't set, this will return the defaultValue string instead.
+    */
+    static String getEnvironmentVariable (const String& name, const String& defaultValue);
+
+    //==============================================================================
+    /** Returns the current user's name, if available.
+        @see getFullUserName()
+    */
+    static String getLogonName();
+
+    /** Returns the current user's full name, if available.
+        On some OSes, this may just return the same value as getLogonName().
+        @see getLogonName()
+    */
+    static String getFullUserName();
+
+    /** Returns the host-name of the computer. */
+    static String getComputerName();
+
+    /** Returns the language of the user's locale.
+        The return value is a 2 or 3 letter language code (ISO 639-1 or ISO 639-2)
+    */
+    static String getUserLanguage();
+
+    /** Returns the region of the user's locale.
+        The return value is a 2 letter country code (ISO 3166-1 alpha-2).
+    */
+    static String getUserRegion();
+
+    /** Returns the user's display language.
+        The return value is a 2 or 3 letter language code (ISO 639-1 or ISO 639-2).
+        Note that depending on the OS and region, this may also be followed by a dash
+        and a sub-region code, e.g "en-GB"
+    */
+    static String getDisplayLanguage();
+
+    /** This will attempt to return some kind of string describing the device.
+        If no description is available, it'll just return an empty string. You may
+        want to use this for things like determining the type of phone/iPad, etc.
+    */
+    static String getDeviceDescription();
+
+    //==============================================================================
+    // CPU and memory information..
+
+    /** Returns the number of CPU cores. */
+    static int getNumCpus() noexcept;
+
+    /** Returns the approximate CPU speed.
+        @returns    the speed in megahertz, e.g. 1500, 2500, 32000 (depending on
+                    what year you're reading this...)
+    */
+    static int getCpuSpeedInMegaherz();
+
+    /** Returns a string to indicate the CPU vendor.
+        Might not be known on some systems.
+    */
+    static String getCpuVendor();
+
+    static bool hasMMX() noexcept;   /**< Returns true if Intel MMX instructions are available. */
+    static bool hasSSE() noexcept;   /**< Returns true if Intel SSE instructions are available. */
+    static bool hasSSE2() noexcept;  /**< Returns true if Intel SSE2 instructions are available. */
+    static bool hasSSE3() noexcept;  /**< Returns true if Intel SSE2 instructions are available. */
+    static bool has3DNow() noexcept; /**< Returns true if AMD 3DNOW instructions are available. */
+
+    //==============================================================================
+    /** Finds out how much RAM is in the machine.
+        @returns    the approximate number of megabytes of memory, or zero if
+                    something goes wrong when finding out.
+    */
+    static int getMemorySizeInMegabytes();
+
+    /** Returns the system page-size.
+        This is only used by programmers with beards.
+    */
+    static int getPageSize();
+
+    //==============================================================================
+    /** Returns a backtrace of the current call-stack.
+        The usefulness of the result will depend on the level of debug symbols
+        that are available in the executable.
+    */
+    static String getStackBacktrace();
+
+    /** A void() function type, used by setApplicationCrashHandler(). */
+    typedef void (*CrashHandlerFunction)();
+
+    /** Sets up a global callback function that will be called if the application
+        executes some kind of illegal instruction.
+
+        You may want to call getStackBacktrace() in your handler function, to find out
+        where the problem happened and log it, etc.
+    */
+    static void setApplicationCrashHandler (CrashHandlerFunction);
+
+private:
+    //==============================================================================
+    SystemStats();
+
+    JUCE_DECLARE_NON_COPYABLE (SystemStats)
+};
+
+
+#endif   // JUCE_SYSTEMSTATS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_TargetPlatform.h b/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_TargetPlatform.h
new file mode 100644
index 0000000..86adc38
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/system/juce_TargetPlatform.h
@@ -0,0 +1,201 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_TARGETPLATFORM_H_INCLUDED
+#define JUCE_TARGETPLATFORM_H_INCLUDED
+
+//==============================================================================
+/*  This file figures out which platform is being built, and defines some macros
+    that the rest of the code can use for OS-specific compilation.
+
+    Macros that will be set here are:
+
+    - One of JUCE_WINDOWS, JUCE_MAC JUCE_LINUX, JUCE_IOS, JUCE_ANDROID, etc.
+    - Either JUCE_32BIT or JUCE_64BIT, depending on the architecture.
+    - Either JUCE_LITTLE_ENDIAN or JUCE_BIG_ENDIAN.
+    - Either JUCE_INTEL or JUCE_PPC
+    - Either JUCE_GCC or JUCE_MSVC
+*/
+
+//==============================================================================
+#if (defined (_WIN32) || defined (_WIN64))
+  #define       JUCE_WIN32 1
+  #define       JUCE_WINDOWS 1
+#elif defined (JUCE_ANDROID)
+  #undef        JUCE_ANDROID
+  #define       JUCE_ANDROID 1
+#elif defined (LINUX) || defined (__linux__)
+  #define     JUCE_LINUX 1
+#elif defined (__APPLE_CPP__) || defined(__APPLE_CC__)
+  #define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers)
+  #define Component CarbonDummyCompName
+  #include <CoreFoundation/CoreFoundation.h> // (needed to find out what platform we're using)
+  #undef Point
+  #undef Component
+
+  #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
+    #define     JUCE_IPHONE 1
+    #define     JUCE_IOS 1
+  #else
+    #define     JUCE_MAC 1
+  #endif
+#elif defined (__FreeBSD__)
+  #define       JUCE_BSD 1
+#else
+  #error "Unknown platform!"
+#endif
+
+//==============================================================================
+#if JUCE_WINDOWS
+  #ifdef _MSC_VER
+    #ifdef _WIN64
+      #define JUCE_64BIT 1
+    #else
+      #define JUCE_32BIT 1
+    #endif
+  #endif
+
+  #ifdef _DEBUG
+    #define JUCE_DEBUG 1
+  #endif
+
+  #ifdef __MINGW32__
+    #define JUCE_MINGW 1
+    #ifdef __MINGW64__
+      #define JUCE_64BIT 1
+    #else
+      #define JUCE_32BIT 1
+    #endif
+  #endif
+
+  /** If defined, this indicates that the processor is little-endian. */
+  #define JUCE_LITTLE_ENDIAN 1
+
+  #define JUCE_INTEL 1
+#endif
+
+//==============================================================================
+#if JUCE_MAC || JUCE_IOS
+
+  #if defined (DEBUG) || defined (_DEBUG) || ! (defined (NDEBUG) || defined (_NDEBUG))
+    #define JUCE_DEBUG 1
+  #endif
+
+  #if ! (defined (DEBUG) || defined (_DEBUG) || defined (NDEBUG) || defined (_NDEBUG))
+    #warning "Neither NDEBUG or DEBUG has been defined - you should set one of these to make it clear whether this is a release build,"
+  #endif
+
+  #ifdef __LITTLE_ENDIAN__
+    #define JUCE_LITTLE_ENDIAN 1
+  #else
+    #define JUCE_BIG_ENDIAN 1
+  #endif
+
+  #ifdef __LP64__
+    #define JUCE_64BIT 1
+  #else
+    #define JUCE_32BIT 1
+  #endif
+
+  #if defined (__ppc__) || defined (__ppc64__)
+    #define JUCE_PPC 1
+  #elif defined (__arm__) || defined (__arm64__)
+    #define JUCE_ARM 1
+  #else
+    #define JUCE_INTEL 1
+  #endif
+
+  #if JUCE_MAC && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4
+    #error "Building for OSX 10.3 is no longer supported!"
+  #endif
+
+  #if JUCE_MAC && ! defined (MAC_OS_X_VERSION_10_5)
+    #error "To build with 10.4 compatibility, use a 10.5 or 10.6 SDK and set the deployment target to 10.4"
+  #endif
+#endif
+
+//==============================================================================
+#if JUCE_LINUX || JUCE_ANDROID
+
+  #ifdef _DEBUG
+    #define JUCE_DEBUG 1
+  #endif
+
+  // Allow override for big-endian Linux platforms
+  #if defined (__LITTLE_ENDIAN__) || ! defined (JUCE_BIG_ENDIAN)
+    #define JUCE_LITTLE_ENDIAN 1
+    #undef JUCE_BIG_ENDIAN
+  #else
+    #undef JUCE_LITTLE_ENDIAN
+    #define JUCE_BIG_ENDIAN 1
+  #endif
+
+  #if defined (__LP64__) || defined (_LP64)
+    #define JUCE_64BIT 1
+  #else
+    #define JUCE_32BIT 1
+  #endif
+
+  #if defined (__arm__) || defined (__arm64__)
+    #define JUCE_ARM 1
+  #elif __MMX__ || __SSE__ || __amd64__
+    #define JUCE_INTEL 1
+  #endif
+#endif
+
+//==============================================================================
+// Compiler type macros.
+
+#ifdef __clang__
+ #define JUCE_CLANG 1
+ #define JUCE_GCC 1
+#elif defined (__GNUC__)
+  #define JUCE_GCC 1
+#elif defined (_MSC_VER)
+  #define JUCE_MSVC 1
+
+  #if _MSC_VER < 1500
+    #define JUCE_VC8_OR_EARLIER 1
+
+    #if _MSC_VER < 1400
+      #define JUCE_VC7_OR_EARLIER 1
+
+      #if _MSC_VER < 1300
+        #warning "MSVC 6.0 is no longer supported!"
+      #endif
+    #endif
+  #endif
+
+  #if JUCE_64BIT || ! JUCE_VC7_OR_EARLIER
+    #define JUCE_USE_INTRINSICS 1
+  #endif
+#else
+  #error unknown compiler
+#endif
+
+#endif   // JUCE_TARGETPLATFORM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_ASCII.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_ASCII.h
new file mode 100644
index 0000000..a966543
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_ASCII.h
@@ -0,0 +1,387 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_CHARPOINTER_ASCII_H_INCLUDED
+#define JUCE_CHARPOINTER_ASCII_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Wraps a pointer to a null-terminated ASCII character string, and provides
+    various methods to operate on the data.
+
+    A valid ASCII string is assumed to not contain any characters above 127.
+
+    @see CharPointer_UTF8, CharPointer_UTF16, CharPointer_UTF32
+*/
+class CharPointer_ASCII
+{
+public:
+    typedef char CharType;
+
+    inline explicit CharPointer_ASCII (const CharType* const rawPointer) noexcept
+        : data (const_cast <CharType*> (rawPointer))
+    {
+    }
+
+    inline CharPointer_ASCII (const CharPointer_ASCII& other) noexcept
+        : data (other.data)
+    {
+    }
+
+    inline CharPointer_ASCII operator= (const CharPointer_ASCII other) noexcept
+    {
+        data = other.data;
+        return *this;
+    }
+
+    inline CharPointer_ASCII operator= (const CharType* text) noexcept
+    {
+        data = const_cast <CharType*> (text);
+        return *this;
+    }
+
+    /** This is a pointer comparison, it doesn't compare the actual text. */
+    inline bool operator== (CharPointer_ASCII other) const noexcept     { return data == other.data; }
+    inline bool operator!= (CharPointer_ASCII other) const noexcept     { return data != other.data; }
+    inline bool operator<= (CharPointer_ASCII other) const noexcept     { return data <= other.data; }
+    inline bool operator<  (CharPointer_ASCII other) const noexcept     { return data <  other.data; }
+    inline bool operator>= (CharPointer_ASCII other) const noexcept     { return data >= other.data; }
+    inline bool operator>  (CharPointer_ASCII other) const noexcept     { return data >  other.data; }
+
+    /** Returns the address that this pointer is pointing to. */
+    inline CharType* getAddress() const noexcept        { return data; }
+
+    /** Returns the address that this pointer is pointing to. */
+    inline operator const CharType*() const noexcept    { return data; }
+
+    /** Returns true if this pointer is pointing to a null character. */
+    inline bool isEmpty() const noexcept                { return *data == 0; }
+
+    /** Returns the unicode character that this pointer is pointing to. */
+    inline juce_wchar operator*() const noexcept        { return (juce_wchar) (uint8) *data; }
+
+    /** Moves this pointer along to the next character in the string. */
+    inline CharPointer_ASCII operator++() noexcept
+    {
+        ++data;
+        return *this;
+    }
+
+    /** Moves this pointer to the previous character in the string. */
+    inline CharPointer_ASCII operator--() noexcept
+    {
+        --data;
+        return *this;
+    }
+
+    /** Returns the character that this pointer is currently pointing to, and then
+        advances the pointer to point to the next character. */
+    inline juce_wchar getAndAdvance() noexcept  { return (juce_wchar) (uint8) *data++; }
+
+    /** Moves this pointer along to the next character in the string. */
+    CharPointer_ASCII operator++ (int) noexcept
+    {
+        CharPointer_ASCII temp (*this);
+        ++data;
+        return temp;
+    }
+
+    /** Moves this pointer forwards by the specified number of characters. */
+    inline void operator+= (const int numToSkip) noexcept
+    {
+        data += numToSkip;
+    }
+
+    inline void operator-= (const int numToSkip) noexcept
+    {
+        data -= numToSkip;
+    }
+
+    /** Returns the character at a given character index from the start of the string. */
+    inline juce_wchar operator[] (const int characterIndex) const noexcept
+    {
+        return (juce_wchar) (unsigned char) data [characterIndex];
+    }
+
+    /** Returns a pointer which is moved forwards from this one by the specified number of characters. */
+    CharPointer_ASCII operator+ (const int numToSkip) const noexcept
+    {
+        return CharPointer_ASCII (data + numToSkip);
+    }
+
+    /** Returns a pointer which is moved backwards from this one by the specified number of characters. */
+    CharPointer_ASCII operator- (const int numToSkip) const noexcept
+    {
+        return CharPointer_ASCII (data - numToSkip);
+    }
+
+    /** Writes a unicode character to this string, and advances this pointer to point to the next position. */
+    inline void write (const juce_wchar charToWrite) noexcept
+    {
+        *data++ = (char) charToWrite;
+    }
+
+    inline void replaceChar (const juce_wchar newChar) noexcept
+    {
+        *data = (char) newChar;
+    }
+
+    /** Writes a null character to this string (leaving the pointer's position unchanged). */
+    inline void writeNull() const noexcept
+    {
+        *data = 0;
+    }
+
+    /** Returns the number of characters in this string. */
+    size_t length() const noexcept
+    {
+        return (size_t) strlen (data);
+    }
+
+    /** Returns the number of characters in this string, or the given value, whichever is lower. */
+    size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
+    {
+        return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
+    }
+
+    /** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
+    size_t lengthUpTo (const CharPointer_ASCII end) const noexcept
+    {
+        return CharacterFunctions::lengthUpTo (*this, end);
+    }
+
+    /** Returns the number of bytes that are used to represent this string.
+        This includes the terminating null character.
+    */
+    size_t sizeInBytes() const noexcept
+    {
+        return length() + 1;
+    }
+
+    /** Returns the number of bytes that would be needed to represent the given
+        unicode character in this encoding format.
+    */
+    static inline size_t getBytesRequiredFor (const juce_wchar) noexcept
+    {
+        return 1;
+    }
+
+    /** Returns the number of bytes that would be needed to represent the given
+        string in this encoding format.
+        The value returned does NOT include the terminating null character.
+    */
+    template <class CharPointer>
+    static size_t getBytesRequiredFor (const CharPointer text) noexcept
+    {
+        return text.length();
+    }
+
+    /** Returns a pointer to the null character that terminates this string. */
+    CharPointer_ASCII findTerminatingNull() const noexcept
+    {
+        return CharPointer_ASCII (data + length());
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes. */
+    template <typename CharPointer>
+    void writeAll (const CharPointer src) noexcept
+    {
+        CharacterFunctions::copyAll (*this, src);
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes. */
+    void writeAll (const CharPointer_ASCII src) noexcept
+    {
+        strcpy (data, src.data);
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes.
+        The maxDestBytes parameter specifies the maximum number of bytes that can be written
+        to the destination buffer before stopping.
+    */
+    template <typename CharPointer>
+    size_t writeWithDestByteLimit (const CharPointer src, const size_t maxDestBytes) noexcept
+    {
+        return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes.
+        The maxChars parameter specifies the maximum number of characters that can be
+        written to the destination buffer before stopping (including the terminating null).
+    */
+    template <typename CharPointer>
+    void writeWithCharLimit (const CharPointer src, const int maxChars) noexcept
+    {
+        CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
+    }
+
+    /** Compares this string with another one. */
+    template <typename CharPointer>
+    int compare (const CharPointer other) const noexcept
+    {
+        return CharacterFunctions::compare (*this, other);
+    }
+
+    /** Compares this string with another one. */
+    int compare (const CharPointer_ASCII other) const noexcept
+    {
+        return strcmp (data, other.data);
+    }
+
+    /** Compares this string with another one, up to a specified number of characters. */
+    template <typename CharPointer>
+    int compareUpTo (const CharPointer other, const int maxChars) const noexcept
+    {
+        return CharacterFunctions::compareUpTo (*this, other, maxChars);
+    }
+
+    /** Compares this string with another one, up to a specified number of characters. */
+    int compareUpTo (const CharPointer_ASCII other, const int maxChars) const noexcept
+    {
+        return strncmp (data, other.data, (size_t) maxChars);
+    }
+
+    /** Compares this string with another one. */
+    template <typename CharPointer>
+    int compareIgnoreCase (const CharPointer other) const
+    {
+        return CharacterFunctions::compareIgnoreCase (*this, other);
+    }
+
+    int compareIgnoreCase (const CharPointer_ASCII other) const
+    {
+       #if JUCE_WINDOWS
+        return stricmp (data, other.data);
+       #else
+        return strcasecmp (data, other.data);
+       #endif
+    }
+
+    /** Compares this string with another one, up to a specified number of characters. */
+    template <typename CharPointer>
+    int compareIgnoreCaseUpTo (const CharPointer other, const int maxChars) const noexcept
+    {
+        return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
+    }
+
+    /** Returns the character index of a substring, or -1 if it isn't found. */
+    template <typename CharPointer>
+    int indexOf (const CharPointer stringToFind) const noexcept
+    {
+        return CharacterFunctions::indexOf (*this, stringToFind);
+    }
+
+    /** Returns the character index of a unicode character, or -1 if it isn't found. */
+    int indexOf (const juce_wchar charToFind) const noexcept
+    {
+        int i = 0;
+
+        while (data[i] != 0)
+        {
+            if (data[i] == (char) charToFind)
+                return i;
+
+            ++i;
+        }
+
+        return -1;
+    }
+
+    /** Returns the character index of a unicode character, or -1 if it isn't found. */
+    int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
+    {
+        return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
+                          : CharacterFunctions::indexOfChar (*this, charToFind);
+    }
+
+    /** Returns true if the first character of this string is whitespace. */
+    bool isWhitespace() const               { return CharacterFunctions::isWhitespace (*data) != 0; }
+    /** Returns true if the first character of this string is a digit. */
+    bool isDigit() const                    { return CharacterFunctions::isDigit (*data) != 0; }
+    /** Returns true if the first character of this string is a letter. */
+    bool isLetter() const                   { return CharacterFunctions::isLetter (*data) != 0; }
+    /** Returns true if the first character of this string is a letter or digit. */
+    bool isLetterOrDigit() const            { return CharacterFunctions::isLetterOrDigit (*data) != 0; }
+    /** Returns true if the first character of this string is upper-case. */
+    bool isUpperCase() const                { return CharacterFunctions::isUpperCase ((juce_wchar) (uint8) *data) != 0; }
+    /** Returns true if the first character of this string is lower-case. */
+    bool isLowerCase() const                { return CharacterFunctions::isLowerCase ((juce_wchar) (uint8) *data) != 0; }
+
+    /** Returns an upper-case version of the first character of this string. */
+    juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase ((juce_wchar) (uint8) *data); }
+    /** Returns a lower-case version of the first character of this string. */
+    juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase ((juce_wchar) (uint8) *data); }
+
+    /** Parses this string as a 32-bit integer. */
+    int getIntValue32() const noexcept      { return atoi (data); }
+
+    /** Parses this string as a 64-bit integer. */
+    int64 getIntValue64() const noexcept
+    {
+       #if JUCE_LINUX || JUCE_ANDROID
+        return atoll (data);
+       #elif JUCE_WINDOWS
+        return _atoi64 (data);
+       #else
+        return CharacterFunctions::getIntValue <int64, CharPointer_ASCII> (*this);
+       #endif
+    }
+
+    /** Parses this string as a floating point double. */
+    double getDoubleValue() const noexcept  { return CharacterFunctions::getDoubleValue (*this); }
+
+    /** Returns the first non-whitespace character in the string. */
+    CharPointer_ASCII findEndOfWhitespace() const noexcept   { return CharacterFunctions::findEndOfWhitespace (*this); }
+
+    /** Returns true if the given unicode character can be represented in this encoding. */
+    static bool canRepresent (juce_wchar character) noexcept
+    {
+        return ((unsigned int) character) < (unsigned int) 128;
+    }
+
+    /** Returns true if this data contains a valid string in this encoding. */
+    static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+    {
+        while (--maxBytesToRead >= 0)
+        {
+            if (((signed char) *dataToTest) <= 0)
+                return *dataToTest == 0;
+
+            ++dataToTest;
+        }
+
+        return true;
+    }
+
+private:
+    CharType* data;
+};
+
+
+#endif   // JUCE_CHARPOINTER_ASCII_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_UTF16.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_UTF16.h
new file mode 100644
index 0000000..d0eba5c
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_UTF16.h
@@ -0,0 +1,525 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_CHARPOINTER_UTF16_H_INCLUDED
+#define JUCE_CHARPOINTER_UTF16_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Wraps a pointer to a null-terminated UTF-16 character string, and provides
+    various methods to operate on the data.
+    @see CharPointer_UTF8, CharPointer_UTF32
+*/
+class CharPointer_UTF16
+{
+public:
+   #if JUCE_NATIVE_WCHAR_IS_UTF16
+    typedef wchar_t CharType;
+   #else
+    typedef int16 CharType;
+   #endif
+
+    inline explicit CharPointer_UTF16 (const CharType* const rawPointer) noexcept
+        : data (const_cast <CharType*> (rawPointer))
+    {
+    }
+
+    inline CharPointer_UTF16 (const CharPointer_UTF16& other) noexcept
+        : data (other.data)
+    {
+    }
+
+    inline CharPointer_UTF16 operator= (CharPointer_UTF16 other) noexcept
+    {
+        data = other.data;
+        return *this;
+    }
+
+    inline CharPointer_UTF16 operator= (const CharType* text) noexcept
+    {
+        data = const_cast <CharType*> (text);
+        return *this;
+    }
+
+    /** This is a pointer comparison, it doesn't compare the actual text. */
+    inline bool operator== (CharPointer_UTF16 other) const noexcept     { return data == other.data; }
+    inline bool operator!= (CharPointer_UTF16 other) const noexcept     { return data != other.data; }
+    inline bool operator<= (CharPointer_UTF16 other) const noexcept     { return data <= other.data; }
+    inline bool operator<  (CharPointer_UTF16 other) const noexcept     { return data <  other.data; }
+    inline bool operator>= (CharPointer_UTF16 other) const noexcept     { return data >= other.data; }
+    inline bool operator>  (CharPointer_UTF16 other) const noexcept     { return data >  other.data; }
+
+    /** Returns the address that this pointer is pointing to. */
+    inline CharType* getAddress() const noexcept        { return data; }
+
+    /** Returns the address that this pointer is pointing to. */
+    inline operator const CharType*() const noexcept    { return data; }
+
+    /** Returns true if this pointer is pointing to a null character. */
+    inline bool isEmpty() const noexcept                { return *data == 0; }
+
+    /** Returns the unicode character that this pointer is pointing to. */
+    juce_wchar operator*() const noexcept
+    {
+        uint32 n = (uint32) (uint16) *data;
+
+        if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) data[1]) >= 0xdc00)
+            n = 0x10000 + (((n - 0xd800) << 10) | (((uint32) (uint16) data[1]) - 0xdc00));
+
+        return (juce_wchar) n;
+    }
+
+    /** Moves this pointer along to the next character in the string. */
+    CharPointer_UTF16 operator++() noexcept
+    {
+        const juce_wchar n = *data++;
+
+        if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) *data) >= 0xdc00)
+            ++data;
+
+        return *this;
+    }
+
+    /** Moves this pointer back to the previous character in the string. */
+    CharPointer_UTF16 operator--() noexcept
+    {
+        const juce_wchar n = *--data;
+
+        if (n >= 0xdc00 && n <= 0xdfff)
+            --data;
+
+        return *this;
+    }
+
+    /** Returns the character that this pointer is currently pointing to, and then
+        advances the pointer to point to the next character. */
+    juce_wchar getAndAdvance() noexcept
+    {
+        uint32 n = (uint32) (uint16) *data++;
+
+        if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) *data) >= 0xdc00)
+            n = 0x10000 + ((((n - 0xd800) << 10) | (((uint32) (uint16) *data++) - 0xdc00)));
+
+        return (juce_wchar) n;
+    }
+
+    /** Moves this pointer along to the next character in the string. */
+    CharPointer_UTF16 operator++ (int) noexcept
+    {
+        CharPointer_UTF16 temp (*this);
+        ++*this;
+        return temp;
+    }
+
+    /** Moves this pointer forwards by the specified number of characters. */
+    void operator+= (int numToSkip) noexcept
+    {
+        if (numToSkip < 0)
+        {
+            while (++numToSkip <= 0)
+                --*this;
+        }
+        else
+        {
+            while (--numToSkip >= 0)
+                ++*this;
+        }
+    }
+
+    /** Moves this pointer backwards by the specified number of characters. */
+    void operator-= (int numToSkip) noexcept
+    {
+        operator+= (-numToSkip);
+    }
+
+    /** Returns the character at a given character index from the start of the string. */
+    juce_wchar operator[] (const int characterIndex) const noexcept
+    {
+        CharPointer_UTF16 p (*this);
+        p += characterIndex;
+        return *p;
+    }
+
+    /** Returns a pointer which is moved forwards from this one by the specified number of characters. */
+    CharPointer_UTF16 operator+ (const int numToSkip) const noexcept
+    {
+        CharPointer_UTF16 p (*this);
+        p += numToSkip;
+        return p;
+    }
+
+    /** Returns a pointer which is moved backwards from this one by the specified number of characters. */
+    CharPointer_UTF16 operator- (const int numToSkip) const noexcept
+    {
+        CharPointer_UTF16 p (*this);
+        p += -numToSkip;
+        return p;
+    }
+
+    /** Writes a unicode character to this string, and advances this pointer to point to the next position. */
+    void write (juce_wchar charToWrite) noexcept
+    {
+        if (charToWrite >= 0x10000)
+        {
+            charToWrite -= 0x10000;
+            *data++ = (CharType) (0xd800 + (charToWrite >> 10));
+            *data++ = (CharType) (0xdc00 + (charToWrite & 0x3ff));
+        }
+        else
+        {
+            *data++ = (CharType) charToWrite;
+        }
+    }
+
+    /** Writes a null character to this string (leaving the pointer's position unchanged). */
+    inline void writeNull() const noexcept
+    {
+        *data = 0;
+    }
+
+    /** Returns the number of characters in this string. */
+    size_t length() const noexcept
+    {
+        const CharType* d = data;
+        size_t count = 0;
+
+        for (;;)
+        {
+            const int n = *d++;
+
+            if (n >= 0xd800 && n <= 0xdfff)
+            {
+                if (*d++ == 0)
+                    break;
+            }
+            else if (n == 0)
+                break;
+
+            ++count;
+        }
+
+        return count;
+    }
+
+    /** Returns the number of characters in this string, or the given value, whichever is lower. */
+    size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
+    {
+        return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
+    }
+
+    /** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
+    size_t lengthUpTo (const CharPointer_UTF16 end) const noexcept
+    {
+        return CharacterFunctions::lengthUpTo (*this, end);
+    }
+
+    /** Returns the number of bytes that are used to represent this string.
+        This includes the terminating null character.
+    */
+    size_t sizeInBytes() const noexcept
+    {
+        return sizeof (CharType) * (findNullIndex (data) + 1);
+    }
+
+    /** Returns the number of bytes that would be needed to represent the given
+        unicode character in this encoding format.
+    */
+    static size_t getBytesRequiredFor (const juce_wchar charToWrite) noexcept
+    {
+        return (charToWrite >= 0x10000) ? (sizeof (CharType) * 2) : sizeof (CharType);
+    }
+
+    /** Returns the number of bytes that would be needed to represent the given
+        string in this encoding format.
+        The value returned does NOT include the terminating null character.
+    */
+    template <class CharPointer>
+    static size_t getBytesRequiredFor (CharPointer text) noexcept
+    {
+        size_t count = 0;
+        juce_wchar n;
+
+        while ((n = text.getAndAdvance()) != 0)
+            count += getBytesRequiredFor (n);
+
+        return count;
+    }
+
+    /** Returns a pointer to the null character that terminates this string. */
+    CharPointer_UTF16 findTerminatingNull() const noexcept
+    {
+        const CharType* t = data;
+
+        while (*t != 0)
+            ++t;
+
+        return CharPointer_UTF16 (t);
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes. */
+    template <typename CharPointer>
+    void writeAll (const CharPointer src) noexcept
+    {
+        CharacterFunctions::copyAll (*this, src);
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes. */
+    void writeAll (const CharPointer_UTF16 src) noexcept
+    {
+        const CharType* s = src.data;
+
+        while ((*data = *s) != 0)
+        {
+            ++data;
+            ++s;
+        }
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes.
+        The maxDestBytes parameter specifies the maximum number of bytes that can be written
+        to the destination buffer before stopping.
+    */
+    template <typename CharPointer>
+    size_t writeWithDestByteLimit (const CharPointer src, const size_t maxDestBytes) noexcept
+    {
+        return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes.
+        The maxChars parameter specifies the maximum number of characters that can be
+        written to the destination buffer before stopping (including the terminating null).
+    */
+    template <typename CharPointer>
+    void writeWithCharLimit (const CharPointer src, const int maxChars) noexcept
+    {
+        CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
+    }
+
+    /** Compares this string with another one. */
+    template <typename CharPointer>
+    int compare (const CharPointer other) const noexcept
+    {
+        return CharacterFunctions::compare (*this, other);
+    }
+
+    /** Compares this string with another one, up to a specified number of characters. */
+    template <typename CharPointer>
+    int compareUpTo (const CharPointer other, const int maxChars) const noexcept
+    {
+        return CharacterFunctions::compareUpTo (*this, other, maxChars);
+    }
+
+    /** Compares this string with another one. */
+    template <typename CharPointer>
+    int compareIgnoreCase (const CharPointer other) const noexcept
+    {
+        return CharacterFunctions::compareIgnoreCase (*this, other);
+    }
+
+    /** Compares this string with another one, up to a specified number of characters. */
+    template <typename CharPointer>
+    int compareIgnoreCaseUpTo (const CharPointer other, const int maxChars) const noexcept
+    {
+        return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
+    }
+
+   #if JUCE_WINDOWS && ! DOXYGEN
+    int compareIgnoreCase (const CharPointer_UTF16 other) const noexcept
+    {
+        return _wcsicmp (data, other.data);
+    }
+
+    int compareIgnoreCaseUpTo (const CharPointer_UTF16 other, int maxChars) const noexcept
+    {
+        return _wcsnicmp (data, other.data, (size_t) maxChars);
+    }
+
+    int indexOf (const CharPointer_UTF16 stringToFind) const noexcept
+    {
+        const CharType* const t = wcsstr (data, stringToFind.getAddress());
+        return t == nullptr ? -1 : (int) (t - data);
+    }
+   #endif
+
+    /** Returns the character index of a substring, or -1 if it isn't found. */
+    template <typename CharPointer>
+    int indexOf (const CharPointer stringToFind) const noexcept
+    {
+        return CharacterFunctions::indexOf (*this, stringToFind);
+    }
+
+    /** Returns the character index of a unicode character, or -1 if it isn't found. */
+    int indexOf (const juce_wchar charToFind) const noexcept
+    {
+        return CharacterFunctions::indexOfChar (*this, charToFind);
+    }
+
+    /** Returns the character index of a unicode character, or -1 if it isn't found. */
+    int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
+    {
+        return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
+                          : CharacterFunctions::indexOfChar (*this, charToFind);
+    }
+
+    /** Returns true if the first character of this string is whitespace. */
+    bool isWhitespace() const noexcept      { return CharacterFunctions::isWhitespace (operator*()) != 0; }
+    /** Returns true if the first character of this string is a digit. */
+    bool isDigit() const noexcept           { return CharacterFunctions::isDigit (operator*()) != 0; }
+    /** Returns true if the first character of this string is a letter. */
+    bool isLetter() const noexcept          { return CharacterFunctions::isLetter (operator*()) != 0; }
+    /** Returns true if the first character of this string is a letter or digit. */
+    bool isLetterOrDigit() const noexcept   { return CharacterFunctions::isLetterOrDigit (operator*()) != 0; }
+    /** Returns true if the first character of this string is upper-case. */
+    bool isUpperCase() const noexcept       { return CharacterFunctions::isUpperCase (operator*()) != 0; }
+    /** Returns true if the first character of this string is lower-case. */
+    bool isLowerCase() const noexcept       { return CharacterFunctions::isLowerCase (operator*()) != 0; }
+
+    /** Returns an upper-case version of the first character of this string. */
+    juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase (operator*()); }
+    /** Returns a lower-case version of the first character of this string. */
+    juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase (operator*()); }
+
+    /** Parses this string as a 32-bit integer. */
+    int getIntValue32() const noexcept
+    {
+       #if JUCE_WINDOWS
+        return _wtoi (data);
+       #else
+        return CharacterFunctions::getIntValue <int, CharPointer_UTF16> (*this);
+       #endif
+    }
+
+    /** Parses this string as a 64-bit integer. */
+    int64 getIntValue64() const noexcept
+    {
+       #if JUCE_WINDOWS
+        return _wtoi64 (data);
+       #else
+        return CharacterFunctions::getIntValue <int64, CharPointer_UTF16> (*this);
+       #endif
+    }
+
+    /** Parses this string as a floating point double. */
+    double getDoubleValue() const noexcept  { return CharacterFunctions::getDoubleValue (*this); }
+
+    /** Returns the first non-whitespace character in the string. */
+    CharPointer_UTF16 findEndOfWhitespace() const noexcept   { return CharacterFunctions::findEndOfWhitespace (*this); }
+
+    /** Returns true if the given unicode character can be represented in this encoding. */
+    static bool canRepresent (juce_wchar character) noexcept
+    {
+        return ((unsigned int) character) < (unsigned int) 0x10ffff
+                 && (((unsigned int) character) < 0xd800 || ((unsigned int) character) > 0xdfff);
+    }
+
+    /** Returns true if this data contains a valid string in this encoding. */
+    static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+    {
+        maxBytesToRead /= (int) sizeof (CharType);
+
+        while (--maxBytesToRead >= 0 && *dataToTest != 0)
+        {
+            const uint32 n = (uint32) (uint16) *dataToTest++;
+
+            if (n >= 0xd800)
+            {
+                if (n > 0x10ffff)
+                    return false;
+
+                if (n <= 0xdfff)
+                {
+                    if (n > 0xdc00)
+                        return false;
+
+                    const uint32 nextChar = (uint32) (uint16) *dataToTest++;
+
+                    if (nextChar < 0xdc00 || nextChar > 0xdfff)
+                        return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /** Atomically swaps this pointer for a new value, returning the previous value. */
+    CharPointer_UTF16 atomicSwap (const CharPointer_UTF16 newValue)
+    {
+        return CharPointer_UTF16 (reinterpret_cast <Atomic<CharType*>&> (data).exchange (newValue.data));
+    }
+
+    /** These values are the byte-order-mark (BOM) values for a UTF-16 stream. */
+    enum
+    {
+        byteOrderMarkBE1 = 0xfe,
+        byteOrderMarkBE2 = 0xff,
+        byteOrderMarkLE1 = 0xff,
+        byteOrderMarkLE2 = 0xfe
+    };
+
+    /** Returns true if the first pair of bytes in this pointer are the UTF16 byte-order mark (big endian).
+        The pointer must not be null, and must contain at least two valid bytes.
+    */
+    static bool isByteOrderMarkBigEndian (const void* possibleByteOrder) noexcept
+    {
+        jassert (possibleByteOrder != nullptr);
+        const uint8* const c = static_cast<const uint8*> (possibleByteOrder);
+
+        return c[0] == (uint8) byteOrderMarkBE1
+            && c[1] == (uint8) byteOrderMarkBE2;
+    }
+
+    /** Returns true if the first pair of bytes in this pointer are the UTF16 byte-order mark (little endian).
+        The pointer must not be null, and must contain at least two valid bytes.
+    */
+    static bool isByteOrderMarkLittleEndian (const void* possibleByteOrder) noexcept
+    {
+        jassert (possibleByteOrder != nullptr);
+        const uint8* const c = static_cast<const uint8*> (possibleByteOrder);
+
+        return c[0] == (uint8) byteOrderMarkLE1
+            && c[1] == (uint8) byteOrderMarkLE2;
+    }
+
+private:
+    CharType* data;
+
+    static unsigned int findNullIndex (const CharType* const t) noexcept
+    {
+        unsigned int n = 0;
+
+        while (t[n] != 0)
+            ++n;
+
+        return n;
+    }
+};
+
+
+#endif   // JUCE_CHARPOINTER_UTF16_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_UTF32.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_UTF32.h
new file mode 100644
index 0000000..42cfe48
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_UTF32.h
@@ -0,0 +1,378 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_CHARPOINTER_UTF32_H_INCLUDED
+#define JUCE_CHARPOINTER_UTF32_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Wraps a pointer to a null-terminated UTF-32 character string, and provides
+    various methods to operate on the data.
+    @see CharPointer_UTF8, CharPointer_UTF16
+*/
+class CharPointer_UTF32
+{
+public:
+    typedef juce_wchar CharType;
+
+    inline explicit CharPointer_UTF32 (const CharType* const rawPointer) noexcept
+        : data (const_cast <CharType*> (rawPointer))
+    {
+    }
+
+    inline CharPointer_UTF32 (const CharPointer_UTF32& other) noexcept
+        : data (other.data)
+    {
+    }
+
+    inline CharPointer_UTF32 operator= (CharPointer_UTF32 other) noexcept
+    {
+        data = other.data;
+        return *this;
+    }
+
+    inline CharPointer_UTF32 operator= (const CharType* text) noexcept
+    {
+        data = const_cast <CharType*> (text);
+        return *this;
+    }
+
+    /** This is a pointer comparison, it doesn't compare the actual text. */
+    inline bool operator== (CharPointer_UTF32 other) const noexcept     { return data == other.data; }
+    inline bool operator!= (CharPointer_UTF32 other) const noexcept     { return data != other.data; }
+    inline bool operator<= (CharPointer_UTF32 other) const noexcept     { return data <= other.data; }
+    inline bool operator<  (CharPointer_UTF32 other) const noexcept     { return data <  other.data; }
+    inline bool operator>= (CharPointer_UTF32 other) const noexcept     { return data >= other.data; }
+    inline bool operator>  (CharPointer_UTF32 other) const noexcept     { return data >  other.data; }
+
+    /** Returns the address that this pointer is pointing to. */
+    inline CharType* getAddress() const noexcept        { return data; }
+
+    /** Returns the address that this pointer is pointing to. */
+    inline operator const CharType*() const noexcept    { return data; }
+
+    /** Returns true if this pointer is pointing to a null character. */
+    inline bool isEmpty() const noexcept                { return *data == 0; }
+
+    /** Returns the unicode character that this pointer is pointing to. */
+    inline juce_wchar operator*() const noexcept        { return *data; }
+
+    /** Moves this pointer along to the next character in the string. */
+    inline CharPointer_UTF32 operator++() noexcept
+    {
+        ++data;
+        return *this;
+    }
+
+    /** Moves this pointer to the previous character in the string. */
+    inline CharPointer_UTF32 operator--() noexcept
+    {
+        --data;
+        return *this;
+    }
+
+    /** Returns the character that this pointer is currently pointing to, and then
+        advances the pointer to point to the next character. */
+    inline juce_wchar getAndAdvance() noexcept  { return *data++; }
+
+    /** Moves this pointer along to the next character in the string. */
+    CharPointer_UTF32 operator++ (int) noexcept
+    {
+        CharPointer_UTF32 temp (*this);
+        ++data;
+        return temp;
+    }
+
+    /** Moves this pointer forwards by the specified number of characters. */
+    inline void operator+= (const int numToSkip) noexcept
+    {
+        data += numToSkip;
+    }
+
+    inline void operator-= (const int numToSkip) noexcept
+    {
+        data -= numToSkip;
+    }
+
+    /** Returns the character at a given character index from the start of the string. */
+    inline juce_wchar& operator[] (const int characterIndex) const noexcept
+    {
+        return data [characterIndex];
+    }
+
+    /** Returns a pointer which is moved forwards from this one by the specified number of characters. */
+    CharPointer_UTF32 operator+ (const int numToSkip) const noexcept
+    {
+        return CharPointer_UTF32 (data + numToSkip);
+    }
+
+    /** Returns a pointer which is moved backwards from this one by the specified number of characters. */
+    CharPointer_UTF32 operator- (const int numToSkip) const noexcept
+    {
+        return CharPointer_UTF32 (data - numToSkip);
+    }
+
+    /** Writes a unicode character to this string, and advances this pointer to point to the next position. */
+    inline void write (const juce_wchar charToWrite) noexcept
+    {
+        *data++ = charToWrite;
+    }
+
+    inline void replaceChar (const juce_wchar newChar) noexcept
+    {
+        *data = newChar;
+    }
+
+    /** Writes a null character to this string (leaving the pointer's position unchanged). */
+    inline void writeNull() const noexcept
+    {
+        *data = 0;
+    }
+
+    /** Returns the number of characters in this string. */
+    size_t length() const noexcept
+    {
+       #if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID
+        return wcslen (data);
+       #else
+        size_t n = 0;
+        while (data[n] != 0)
+            ++n;
+        return n;
+       #endif
+    }
+
+    /** Returns the number of characters in this string, or the given value, whichever is lower. */
+    size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
+    {
+        return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
+    }
+
+    /** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
+    size_t lengthUpTo (const CharPointer_UTF32 end) const noexcept
+    {
+        return CharacterFunctions::lengthUpTo (*this, end);
+    }
+
+    /** Returns the number of bytes that are used to represent this string.
+        This includes the terminating null character.
+    */
+    size_t sizeInBytes() const noexcept
+    {
+        return sizeof (CharType) * (length() + 1);
+    }
+
+    /** Returns the number of bytes that would be needed to represent the given
+        unicode character in this encoding format.
+    */
+    static inline size_t getBytesRequiredFor (const juce_wchar) noexcept
+    {
+        return sizeof (CharType);
+    }
+
+    /** Returns the number of bytes that would be needed to represent the given
+        string in this encoding format.
+        The value returned does NOT include the terminating null character.
+    */
+    template <class CharPointer>
+    static size_t getBytesRequiredFor (const CharPointer text) noexcept
+    {
+        return sizeof (CharType) * text.length();
+    }
+
+    /** Returns a pointer to the null character that terminates this string. */
+    CharPointer_UTF32 findTerminatingNull() const noexcept
+    {
+        return CharPointer_UTF32 (data + length());
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes. */
+    template <typename CharPointer>
+    void writeAll (const CharPointer src) noexcept
+    {
+        CharacterFunctions::copyAll (*this, src);
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes. */
+    void writeAll (const CharPointer_UTF32 src) noexcept
+    {
+        const CharType* s = src.data;
+
+        while ((*data = *s) != 0)
+        {
+            ++data;
+            ++s;
+        }
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes.
+        The maxDestBytes parameter specifies the maximum number of bytes that can be written
+        to the destination buffer before stopping.
+    */
+    template <typename CharPointer>
+    size_t writeWithDestByteLimit (const CharPointer src, const size_t maxDestBytes) noexcept
+    {
+        return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes.
+        The maxChars parameter specifies the maximum number of characters that can be
+        written to the destination buffer before stopping (including the terminating null).
+    */
+    template <typename CharPointer>
+    void writeWithCharLimit (const CharPointer src, const int maxChars) noexcept
+    {
+        CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
+    }
+
+    /** Compares this string with another one. */
+    template <typename CharPointer>
+    int compare (const CharPointer other) const noexcept
+    {
+        return CharacterFunctions::compare (*this, other);
+    }
+
+   #if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID
+    /** Compares this string with another one. */
+    int compare (const CharPointer_UTF32 other) const noexcept
+    {
+        return wcscmp (data, other.data);
+    }
+   #endif
+
+    /** Compares this string with another one, up to a specified number of characters. */
+    template <typename CharPointer>
+    int compareUpTo (const CharPointer other, const int maxChars) const noexcept
+    {
+        return CharacterFunctions::compareUpTo (*this, other, maxChars);
+    }
+
+    /** Compares this string with another one. */
+    template <typename CharPointer>
+    int compareIgnoreCase (const CharPointer other) const
+    {
+        return CharacterFunctions::compareIgnoreCase (*this, other);
+    }
+
+    /** Compares this string with another one, up to a specified number of characters. */
+    template <typename CharPointer>
+    int compareIgnoreCaseUpTo (const CharPointer other, const int maxChars) const noexcept
+    {
+        return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
+    }
+
+    /** Returns the character index of a substring, or -1 if it isn't found. */
+    template <typename CharPointer>
+    int indexOf (const CharPointer stringToFind) const noexcept
+    {
+        return CharacterFunctions::indexOf (*this, stringToFind);
+    }
+
+    /** Returns the character index of a unicode character, or -1 if it isn't found. */
+    int indexOf (const juce_wchar charToFind) const noexcept
+    {
+        int i = 0;
+
+        while (data[i] != 0)
+        {
+            if (data[i] == charToFind)
+                return i;
+
+            ++i;
+        }
+
+        return -1;
+    }
+
+    /** Returns the character index of a unicode character, or -1 if it isn't found. */
+    int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
+    {
+        return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
+                          : CharacterFunctions::indexOfChar (*this, charToFind);
+    }
+
+    /** Returns true if the first character of this string is whitespace. */
+    bool isWhitespace() const               { return CharacterFunctions::isWhitespace (*data) != 0; }
+    /** Returns true if the first character of this string is a digit. */
+    bool isDigit() const                    { return CharacterFunctions::isDigit (*data) != 0; }
+    /** Returns true if the first character of this string is a letter. */
+    bool isLetter() const                   { return CharacterFunctions::isLetter (*data) != 0; }
+    /** Returns true if the first character of this string is a letter or digit. */
+    bool isLetterOrDigit() const            { return CharacterFunctions::isLetterOrDigit (*data) != 0; }
+    /** Returns true if the first character of this string is upper-case. */
+    bool isUpperCase() const                { return CharacterFunctions::isUpperCase (*data) != 0; }
+    /** Returns true if the first character of this string is lower-case. */
+    bool isLowerCase() const                { return CharacterFunctions::isLowerCase (*data) != 0; }
+
+    /** Returns an upper-case version of the first character of this string. */
+    juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase (*data); }
+    /** Returns a lower-case version of the first character of this string. */
+    juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase (*data); }
+
+    /** Parses this string as a 32-bit integer. */
+    int getIntValue32() const noexcept      { return CharacterFunctions::getIntValue <int, CharPointer_UTF32> (*this); }
+    /** Parses this string as a 64-bit integer. */
+    int64 getIntValue64() const noexcept    { return CharacterFunctions::getIntValue <int64, CharPointer_UTF32> (*this); }
+
+    /** Parses this string as a floating point double. */
+    double getDoubleValue() const noexcept  { return CharacterFunctions::getDoubleValue (*this); }
+
+    /** Returns the first non-whitespace character in the string. */
+    CharPointer_UTF32 findEndOfWhitespace() const noexcept   { return CharacterFunctions::findEndOfWhitespace (*this); }
+
+    /** Returns true if the given unicode character can be represented in this encoding. */
+    static bool canRepresent (juce_wchar character) noexcept
+    {
+        return ((unsigned int) character) < (unsigned int) 0x10ffff;
+    }
+
+    /** Returns true if this data contains a valid string in this encoding. */
+    static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+    {
+        maxBytesToRead /= (int) sizeof (CharType);
+
+        while (--maxBytesToRead >= 0 && *dataToTest != 0)
+            if (! canRepresent (*dataToTest++))
+                return false;
+
+        return true;
+    }
+
+    /** Atomically swaps this pointer for a new value, returning the previous value. */
+    CharPointer_UTF32 atomicSwap (const CharPointer_UTF32 newValue)
+    {
+        return CharPointer_UTF32 (reinterpret_cast <Atomic<CharType*>&> (data).exchange (newValue.data));
+    }
+
+private:
+    CharType* data;
+};
+
+
+#endif   // JUCE_CHARPOINTER_UTF32_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_UTF8.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_UTF8.h
new file mode 100644
index 0000000..78d9a97
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharPointer_UTF8.h
@@ -0,0 +1,572 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_CHARPOINTER_UTF8_H_INCLUDED
+#define JUCE_CHARPOINTER_UTF8_H_INCLUDED
+
+//==============================================================================
+/**
+    Wraps a pointer to a null-terminated UTF-8 character string, and provides
+    various methods to operate on the data.
+    @see CharPointer_UTF16, CharPointer_UTF32
+*/
+class CharPointer_UTF8
+{
+public:
+    typedef char CharType;
+
+    inline explicit CharPointer_UTF8 (const CharType* const rawPointer) noexcept
+        : data (const_cast <CharType*> (rawPointer))
+    {
+    }
+
+    inline CharPointer_UTF8 (const CharPointer_UTF8& other) noexcept
+        : data (other.data)
+    {
+    }
+
+    inline CharPointer_UTF8 operator= (CharPointer_UTF8 other) noexcept
+    {
+        data = other.data;
+        return *this;
+    }
+
+    inline CharPointer_UTF8 operator= (const CharType* text) noexcept
+    {
+        data = const_cast <CharType*> (text);
+        return *this;
+    }
+
+    /** This is a pointer comparison, it doesn't compare the actual text. */
+    inline bool operator== (CharPointer_UTF8 other) const noexcept      { return data == other.data; }
+    inline bool operator!= (CharPointer_UTF8 other) const noexcept      { return data != other.data; }
+    inline bool operator<= (CharPointer_UTF8 other) const noexcept      { return data <= other.data; }
+    inline bool operator<  (CharPointer_UTF8 other) const noexcept      { return data <  other.data; }
+    inline bool operator>= (CharPointer_UTF8 other) const noexcept      { return data >= other.data; }
+    inline bool operator>  (CharPointer_UTF8 other) const noexcept      { return data >  other.data; }
+
+    /** Returns the address that this pointer is pointing to. */
+    inline CharType* getAddress() const noexcept        { return data; }
+
+    /** Returns the address that this pointer is pointing to. */
+    inline operator const CharType*() const noexcept    { return data; }
+
+    /** Returns true if this pointer is pointing to a null character. */
+    inline bool isEmpty() const noexcept                { return *data == 0; }
+
+    /** Returns the unicode character that this pointer is pointing to. */
+    juce_wchar operator*() const noexcept
+    {
+        const signed char byte = (signed char) *data;
+
+        if (byte >= 0)
+            return (juce_wchar) (uint8) byte;
+
+        uint32 n = (uint32) (uint8) byte;
+        uint32 mask = 0x7f;
+        uint32 bit = 0x40;
+        size_t numExtraValues = 0;
+
+        while ((n & bit) != 0 && bit > 0x10)
+        {
+            mask >>= 1;
+            ++numExtraValues;
+            bit >>= 1;
+        }
+
+        n &= mask;
+
+        for (size_t i = 1; i <= numExtraValues; ++i)
+        {
+            const uint8 nextByte = (uint8) data [i];
+
+            if ((nextByte & 0xc0) != 0x80)
+                break;
+
+            n <<= 6;
+            n |= (nextByte & 0x3f);
+        }
+
+        return (juce_wchar) n;
+    }
+
+    /** Moves this pointer along to the next character in the string. */
+    CharPointer_UTF8& operator++() noexcept
+    {
+        jassert (*data != 0); // trying to advance past the end of the string?
+        const signed char n = (signed char) *data++;
+
+        if (n < 0)
+        {
+            juce_wchar bit = 0x40;
+
+            while ((n & bit) != 0 && bit > 0x8)
+            {
+                ++data;
+                bit >>= 1;
+            }
+        }
+
+        return *this;
+    }
+
+    /** Moves this pointer back to the previous character in the string. */
+    CharPointer_UTF8 operator--() noexcept
+    {
+        int count = 0;
+
+        while ((*--data & 0xc0) == 0x80 && ++count < 4)
+        {}
+
+        return *this;
+    }
+
+    /** Returns the character that this pointer is currently pointing to, and then
+        advances the pointer to point to the next character. */
+    juce_wchar getAndAdvance() noexcept
+    {
+        const signed char byte = (signed char) *data++;
+
+        if (byte >= 0)
+            return (juce_wchar) (uint8) byte;
+
+        uint32 n = (uint32) (uint8) byte;
+        uint32 mask = 0x7f;
+        uint32 bit = 0x40;
+        int numExtraValues = 0;
+
+        while ((n & bit) != 0 && bit > 0x8)
+        {
+            mask >>= 1;
+            ++numExtraValues;
+            bit >>= 1;
+        }
+
+        n &= mask;
+
+        while (--numExtraValues >= 0)
+        {
+            const uint32 nextByte = (uint32) (uint8) *data;
+
+            if ((nextByte & 0xc0) != 0x80)
+                break;
+
+            ++data;
+            n <<= 6;
+            n |= (nextByte & 0x3f);
+        }
+
+        return (juce_wchar) n;
+    }
+
+    /** Moves this pointer along to the next character in the string. */
+    CharPointer_UTF8 operator++ (int) noexcept
+    {
+        CharPointer_UTF8 temp (*this);
+        ++*this;
+        return temp;
+    }
+
+    /** Moves this pointer forwards by the specified number of characters. */
+    void operator+= (int numToSkip) noexcept
+    {
+        if (numToSkip < 0)
+        {
+            while (++numToSkip <= 0)
+                --*this;
+        }
+        else
+        {
+            while (--numToSkip >= 0)
+                ++*this;
+        }
+    }
+
+    /** Moves this pointer backwards by the specified number of characters. */
+    void operator-= (int numToSkip) noexcept
+    {
+        operator+= (-numToSkip);
+    }
+
+    /** Returns the character at a given character index from the start of the string. */
+    juce_wchar operator[] (int characterIndex) const noexcept
+    {
+        CharPointer_UTF8 p (*this);
+        p += characterIndex;
+        return *p;
+    }
+
+    /** Returns a pointer which is moved forwards from this one by the specified number of characters. */
+    CharPointer_UTF8 operator+ (int numToSkip) const noexcept
+    {
+        CharPointer_UTF8 p (*this);
+        p += numToSkip;
+        return p;
+    }
+
+    /** Returns a pointer which is moved backwards from this one by the specified number of characters. */
+    CharPointer_UTF8 operator- (int numToSkip) const noexcept
+    {
+        CharPointer_UTF8 p (*this);
+        p += -numToSkip;
+        return p;
+    }
+
+    /** Returns the number of characters in this string. */
+    size_t length() const noexcept
+    {
+        const CharType* d = data;
+        size_t count = 0;
+
+        for (;;)
+        {
+            const uint32 n = (uint32) (uint8) *d++;
+
+            if ((n & 0x80) != 0)
+            {
+                while ((*d & 0xc0) == 0x80)
+                    ++d;
+            }
+            else if (n == 0)
+                break;
+
+            ++count;
+        }
+
+        return count;
+    }
+
+    /** Returns the number of characters in this string, or the given value, whichever is lower. */
+    size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
+    {
+        return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
+    }
+
+    /** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
+    size_t lengthUpTo (const CharPointer_UTF8 end) const noexcept
+    {
+        return CharacterFunctions::lengthUpTo (*this, end);
+    }
+
+    /** Returns the number of bytes that are used to represent this string.
+        This includes the terminating null character.
+    */
+    size_t sizeInBytes() const noexcept
+    {
+        jassert (data != nullptr);
+        return strlen (data) + 1;
+    }
+
+    /** Returns the number of bytes that would be needed to represent the given
+        unicode character in this encoding format.
+    */
+    static size_t getBytesRequiredFor (const juce_wchar charToWrite) noexcept
+    {
+        size_t num = 1;
+        const uint32 c = (uint32) charToWrite;
+
+        if (c >= 0x80)
+        {
+            ++num;
+            if (c >= 0x800)
+            {
+                ++num;
+                if (c >= 0x10000)
+                    ++num;
+            }
+        }
+
+        return num;
+    }
+
+    /** Returns the number of bytes that would be needed to represent the given
+        string in this encoding format.
+        The value returned does NOT include the terminating null character.
+    */
+    template <class CharPointer>
+    static size_t getBytesRequiredFor (CharPointer text) noexcept
+    {
+        size_t count = 0;
+        juce_wchar n;
+
+        while ((n = text.getAndAdvance()) != 0)
+            count += getBytesRequiredFor (n);
+
+        return count;
+    }
+
+    /** Returns a pointer to the null character that terminates this string. */
+    CharPointer_UTF8 findTerminatingNull() const noexcept
+    {
+        return CharPointer_UTF8 (data + strlen (data));
+    }
+
+    /** Writes a unicode character to this string, and advances this pointer to point to the next position. */
+    void write (const juce_wchar charToWrite) noexcept
+    {
+        const uint32 c = (uint32) charToWrite;
+
+        if (c >= 0x80)
+        {
+            int numExtraBytes = 1;
+            if (c >= 0x800)
+            {
+                ++numExtraBytes;
+                if (c >= 0x10000)
+                    ++numExtraBytes;
+            }
+
+            *data++ = (CharType) ((uint32) (0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6)));
+
+            while (--numExtraBytes >= 0)
+                *data++ = (CharType) (0x80 | (0x3f & (c >> (numExtraBytes * 6))));
+        }
+        else
+        {
+            *data++ = (CharType) c;
+        }
+    }
+
+    /** Writes a null character to this string (leaving the pointer's position unchanged). */
+    inline void writeNull() const noexcept
+    {
+        *data = 0;
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes. */
+    template <typename CharPointer>
+    void writeAll (const CharPointer src) noexcept
+    {
+        CharacterFunctions::copyAll (*this, src);
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes. */
+    void writeAll (const CharPointer_UTF8 src) noexcept
+    {
+        const CharType* s = src.data;
+
+        while ((*data = *s) != 0)
+        {
+            ++data;
+            ++s;
+        }
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes.
+        The maxDestBytes parameter specifies the maximum number of bytes that can be written
+        to the destination buffer before stopping.
+    */
+    template <typename CharPointer>
+    size_t writeWithDestByteLimit (const CharPointer src, const size_t maxDestBytes) noexcept
+    {
+        return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
+    }
+
+    /** Copies a source string to this pointer, advancing this pointer as it goes.
+        The maxChars parameter specifies the maximum number of characters that can be
+        written to the destination buffer before stopping (including the terminating null).
+    */
+    template <typename CharPointer>
+    void writeWithCharLimit (const CharPointer src, const int maxChars) noexcept
+    {
+        CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
+    }
+
+    /** Compares this string with another one. */
+    template <typename CharPointer>
+    int compare (const CharPointer other) const noexcept
+    {
+        return CharacterFunctions::compare (*this, other);
+    }
+
+    /** Compares this string with another one, up to a specified number of characters. */
+    template <typename CharPointer>
+    int compareUpTo (const CharPointer other, const int maxChars) const noexcept
+    {
+        return CharacterFunctions::compareUpTo (*this, other, maxChars);
+    }
+
+    /** Compares this string with another one. */
+    template <typename CharPointer>
+    int compareIgnoreCase (const CharPointer other) const noexcept
+    {
+        return CharacterFunctions::compareIgnoreCase (*this, other);
+    }
+
+    /** Compares this string with another one. */
+    int compareIgnoreCase (const CharPointer_UTF8 other) const noexcept
+    {
+       #if JUCE_WINDOWS
+        return stricmp (data, other.data);
+       #else
+        return strcasecmp (data, other.data);
+       #endif
+    }
+
+    /** Compares this string with another one, up to a specified number of characters. */
+    template <typename CharPointer>
+    int compareIgnoreCaseUpTo (const CharPointer other, const int maxChars) const noexcept
+    {
+        return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
+    }
+
+    /** Returns the character index of a substring, or -1 if it isn't found. */
+    template <typename CharPointer>
+    int indexOf (const CharPointer stringToFind) const noexcept
+    {
+        return CharacterFunctions::indexOf (*this, stringToFind);
+    }
+
+    /** Returns the character index of a unicode character, or -1 if it isn't found. */
+    int indexOf (const juce_wchar charToFind) const noexcept
+    {
+        return CharacterFunctions::indexOfChar (*this, charToFind);
+    }
+
+    /** Returns the character index of a unicode character, or -1 if it isn't found. */
+    int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
+    {
+        return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
+                          : CharacterFunctions::indexOfChar (*this, charToFind);
+    }
+
+    /** Returns true if the first character of this string is whitespace. */
+    bool isWhitespace() const noexcept      { return *data == ' ' || (*data <= 13 && *data >= 9); }
+    /** Returns true if the first character of this string is a digit. */
+    bool isDigit() const noexcept           { return *data >= '0' && *data <= '9'; }
+    /** Returns true if the first character of this string is a letter. */
+    bool isLetter() const noexcept          { return CharacterFunctions::isLetter (operator*()) != 0; }
+    /** Returns true if the first character of this string is a letter or digit. */
+    bool isLetterOrDigit() const noexcept   { return CharacterFunctions::isLetterOrDigit (operator*()) != 0; }
+    /** Returns true if the first character of this string is upper-case. */
+    bool isUpperCase() const noexcept       { return CharacterFunctions::isUpperCase (operator*()) != 0; }
+    /** Returns true if the first character of this string is lower-case. */
+    bool isLowerCase() const noexcept       { return CharacterFunctions::isLowerCase (operator*()) != 0; }
+
+    /** Returns an upper-case version of the first character of this string. */
+    juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase (operator*()); }
+    /** Returns a lower-case version of the first character of this string. */
+    juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase (operator*()); }
+
+    /** Parses this string as a 32-bit integer. */
+    int getIntValue32() const noexcept      { return atoi (data); }
+
+    /** Parses this string as a 64-bit integer. */
+    int64 getIntValue64() const noexcept
+    {
+       #if JUCE_LINUX || JUCE_ANDROID
+        return atoll (data);
+       #elif JUCE_WINDOWS
+        return _atoi64 (data);
+       #else
+        return CharacterFunctions::getIntValue <int64, CharPointer_UTF8> (*this);
+       #endif
+    }
+
+    /** Parses this string as a floating point double. */
+    double getDoubleValue() const noexcept  { return CharacterFunctions::getDoubleValue (*this); }
+
+    /** Returns the first non-whitespace character in the string. */
+    CharPointer_UTF8 findEndOfWhitespace() const noexcept   { return CharacterFunctions::findEndOfWhitespace (*this); }
+
+    /** Returns true if the given unicode character can be represented in this encoding. */
+    static bool canRepresent (juce_wchar character) noexcept
+    {
+        return ((unsigned int) character) < (unsigned int) 0x10ffff;
+    }
+
+    /** Returns true if this data contains a valid string in this encoding. */
+    static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+    {
+        while (--maxBytesToRead >= 0 && *dataToTest != 0)
+        {
+            const signed char byte = (signed char) *dataToTest++;
+
+            if (byte < 0)
+            {
+                uint8 bit = 0x40;
+                int numExtraValues = 0;
+
+                while ((byte & bit) != 0)
+                {
+                    if (bit < 8)
+                        return false;
+
+                    ++numExtraValues;
+                    bit >>= 1;
+
+                    if (bit == 8 && (numExtraValues > maxBytesToRead
+                                       || *CharPointer_UTF8 (dataToTest - 1) > 0x10ffff))
+                        return false;
+                }
+
+                maxBytesToRead -= numExtraValues;
+                if (maxBytesToRead < 0)
+                    return false;
+
+                while (--numExtraValues >= 0)
+                    if ((*dataToTest++ & 0xc0) != 0x80)
+                        return false;
+            }
+        }
+
+        return true;
+    }
+
+    /** Atomically swaps this pointer for a new value, returning the previous value. */
+    CharPointer_UTF8 atomicSwap (const CharPointer_UTF8 newValue)
+    {
+        return CharPointer_UTF8 (reinterpret_cast <Atomic<CharType*>&> (data).exchange (newValue.data));
+    }
+
+    /** These values are the byte-order mark (BOM) values for a UTF-8 stream. */
+    enum
+    {
+        byteOrderMark1 = 0xef,
+        byteOrderMark2 = 0xbb,
+        byteOrderMark3 = 0xbf
+    };
+
+    /** Returns true if the first three bytes in this pointer are the UTF8 byte-order mark (BOM).
+        The pointer must not be null, and must point to at least 3 valid bytes.
+    */
+    static bool isByteOrderMark (const void* possibleByteOrder) noexcept
+    {
+        jassert (possibleByteOrder != nullptr);
+        const uint8* const c = static_cast<const uint8*> (possibleByteOrder);
+
+        return c[0] == (uint8) byteOrderMark1
+            && c[1] == (uint8) byteOrderMark2
+            && c[2] == (uint8) byteOrderMark3;
+    }
+
+private:
+    CharType* data;
+};
+
+#endif   // JUCE_CHARPOINTER_UTF8_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharacterFunctions.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharacterFunctions.cpp
new file mode 100644
index 0000000..11eaa18
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharacterFunctions.cpp
@@ -0,0 +1,154 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+//==============================================================================
+#if JUCE_MSVC
+ #pragma warning (push)
+ #pragma warning (disable: 4514 4996)
+#endif
+
+juce_wchar CharacterFunctions::toUpperCase (const juce_wchar character) noexcept
+{
+    return towupper ((wchar_t) character);
+}
+
+juce_wchar CharacterFunctions::toLowerCase (const juce_wchar character) noexcept
+{
+    return towlower ((wchar_t) character);
+}
+
+bool CharacterFunctions::isUpperCase (const juce_wchar character) noexcept
+{
+   #if JUCE_WINDOWS
+    return iswupper ((wchar_t) character) != 0;
+   #else
+    return toLowerCase (character) != character;
+   #endif
+}
+
+bool CharacterFunctions::isLowerCase (const juce_wchar character) noexcept
+{
+   #if JUCE_WINDOWS
+    return iswlower ((wchar_t) character) != 0;
+   #else
+    return toUpperCase (character) != character;
+   #endif
+}
+
+#if JUCE_MSVC
+ #pragma warning (pop)
+#endif
+
+//==============================================================================
+bool CharacterFunctions::isWhitespace (const char character) noexcept
+{
+    return character == ' ' || (character <= 13 && character >= 9);
+}
+
+bool CharacterFunctions::isWhitespace (const juce_wchar character) noexcept
+{
+    return iswspace ((wchar_t) character) != 0;
+}
+
+bool CharacterFunctions::isDigit (const char character) noexcept
+{
+    return (character >= '0' && character <= '9');
+}
+
+bool CharacterFunctions::isDigit (const juce_wchar character) noexcept
+{
+    return iswdigit ((wchar_t) character) != 0;
+}
+
+bool CharacterFunctions::isLetter (const char character) noexcept
+{
+    return (character >= 'a' && character <= 'z')
+        || (character >= 'A' && character <= 'Z');
+}
+
+bool CharacterFunctions::isLetter (const juce_wchar character) noexcept
+{
+    return iswalpha ((wchar_t) character) != 0;
+}
+
+bool CharacterFunctions::isLetterOrDigit (const char character) noexcept
+{
+    return (character >= 'a' && character <= 'z')
+        || (character >= 'A' && character <= 'Z')
+        || (character >= '0' && character <= '9');
+}
+
+bool CharacterFunctions::isLetterOrDigit (const juce_wchar character) noexcept
+{
+    return iswalnum ((wchar_t) character) != 0;
+}
+
+int CharacterFunctions::getHexDigitValue (const juce_wchar digit) noexcept
+{
+    unsigned int d = (unsigned int) digit - '0';
+    if (d < (unsigned int) 10)
+        return (int) d;
+
+    d += (unsigned int) ('0' - 'a');
+    if (d < (unsigned int) 6)
+        return (int) d + 10;
+
+    d += (unsigned int) ('a' - 'A');
+    if (d < (unsigned int) 6)
+        return (int) d + 10;
+
+    return -1;
+}
+
+double CharacterFunctions::mulexp10 (const double value, int exponent) noexcept
+{
+    if (exponent == 0)
+        return value;
+
+    if (value == 0)
+        return 0;
+
+    const bool negative = (exponent < 0);
+    if (negative)
+        exponent = -exponent;
+
+    double result = 1.0, power = 10.0;
+    for (int bit = 1; exponent != 0; bit <<= 1)
+    {
+        if ((exponent & bit) != 0)
+        {
+            exponent ^= bit;
+            result *= power;
+            if (exponent == 0)
+                break;
+        }
+        power *= power;
+    }
+
+    return negative ? (value / result) : (value * result);
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharacterFunctions.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharacterFunctions.h
new file mode 100644
index 0000000..bade0dd
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_CharacterFunctions.h
@@ -0,0 +1,629 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_CHARACTERFUNCTIONS_H_INCLUDED
+#define JUCE_CHARACTERFUNCTIONS_H_INCLUDED
+
+
+//==============================================================================
+#if JUCE_WINDOWS && ! DOXYGEN
+ #define JUCE_NATIVE_WCHAR_IS_UTF8      0
+ #define JUCE_NATIVE_WCHAR_IS_UTF16     1
+ #define JUCE_NATIVE_WCHAR_IS_UTF32     0
+#else
+ /** This macro will be set to 1 if the compiler's native wchar_t is an 8-bit type. */
+ #define JUCE_NATIVE_WCHAR_IS_UTF8      0
+ /** This macro will be set to 1 if the compiler's native wchar_t is a 16-bit type. */
+ #define JUCE_NATIVE_WCHAR_IS_UTF16     0
+ /** This macro will be set to 1 if the compiler's native wchar_t is a 32-bit type. */
+ #define JUCE_NATIVE_WCHAR_IS_UTF32     1
+#endif
+
+#if JUCE_NATIVE_WCHAR_IS_UTF32 || DOXYGEN
+ /** A platform-independent 32-bit unicode character type. */
+ typedef wchar_t        juce_wchar;
+#else
+ typedef uint32         juce_wchar;
+#endif
+
+#ifndef DOXYGEN
+ /** This macro is deprecated, but preserved for compatibility with old code. */
+ #define JUCE_T(stringLiteral)   (L##stringLiteral)
+#endif
+
+#if JUCE_DEFINE_T_MACRO
+ /** The 'T' macro is an alternative for using the "L" prefix in front of a string literal.
+
+     This macro is deprecated, but available for compatibility with old code if you set
+     JUCE_DEFINE_T_MACRO = 1. The fastest, most portable and best way to write your string
+     literals is as standard char strings, using escaped utf-8 character sequences for extended
+     characters, rather than trying to store them as wide-char strings.
+ */
+ #define T(stringLiteral)   JUCE_T(stringLiteral)
+#endif
+
+//==============================================================================
+/**
+    A collection of functions for manipulating characters and character strings.
+
+    Most of these methods are designed for internal use by the String and CharPointer
+    classes, but some of them may be useful to call directly.
+
+    @see String, CharPointer_UTF8, CharPointer_UTF16, CharPointer_UTF32
+*/
+class JUCE_API  CharacterFunctions
+{
+public:
+    //==============================================================================
+    /** Converts a character to upper-case. */
+    static juce_wchar toUpperCase (juce_wchar character) noexcept;
+    /** Converts a character to lower-case. */
+    static juce_wchar toLowerCase (juce_wchar character) noexcept;
+
+    /** Checks whether a unicode character is upper-case. */
+    static bool isUpperCase (juce_wchar character) noexcept;
+    /** Checks whether a unicode character is lower-case. */
+    static bool isLowerCase (juce_wchar character) noexcept;
+
+    /** Checks whether a character is whitespace. */
+    static bool isWhitespace (char character) noexcept;
+    /** Checks whether a character is whitespace. */
+    static bool isWhitespace (juce_wchar character) noexcept;
+
+    /** Checks whether a character is a digit. */
+    static bool isDigit (char character) noexcept;
+    /** Checks whether a character is a digit. */
+    static bool isDigit (juce_wchar character) noexcept;
+
+    /** Checks whether a character is alphabetic. */
+    static bool isLetter (char character) noexcept;
+    /** Checks whether a character is alphabetic. */
+    static bool isLetter (juce_wchar character) noexcept;
+
+    /** Checks whether a character is alphabetic or numeric. */
+    static bool isLetterOrDigit (char character) noexcept;
+    /** Checks whether a character is alphabetic or numeric. */
+    static bool isLetterOrDigit (juce_wchar character) noexcept;
+
+    /** Returns 0 to 16 for '0' to 'F", or -1 for characters that aren't a legal hex digit. */
+    static int getHexDigitValue (juce_wchar digit) noexcept;
+
+    //==============================================================================
+    /** Parses a character string to read a floating-point number.
+        Note that this will advance the pointer that is passed in, leaving it at
+        the end of the number.
+    */
+    template <typename CharPointerType>
+    static double readDoubleValue (CharPointerType& text) noexcept
+    {
+        double result[3] = { 0 }, accumulator[2] = { 0 };
+        int exponentAdjustment[2] = { 0 }, exponentAccumulator[2] = { -1, -1 };
+        int exponent = 0, decPointIndex = 0, digit = 0;
+        int lastDigit = 0, numSignificantDigits = 0;
+        bool isNegative = false, digitsFound = false;
+        const int maxSignificantDigits = 15 + 2;
+
+        text = text.findEndOfWhitespace();
+        juce_wchar c = *text;
+
+        switch (c)
+        {
+            case '-':   isNegative = true; // fall-through..
+            case '+':   c = *++text;
+        }
+
+        switch (c)
+        {
+            case 'n':
+            case 'N':
+                if ((text[1] == 'a' || text[1] == 'A') && (text[2] == 'n' || text[2] == 'N'))
+                    return std::numeric_limits<double>::quiet_NaN();
+                break;
+
+            case 'i':
+            case 'I':
+                if ((text[1] == 'n' || text[1] == 'N') && (text[2] == 'f' || text[2] == 'F'))
+                    return std::numeric_limits<double>::infinity();
+                break;
+        }
+
+        for (;;)
+        {
+            if (text.isDigit())
+            {
+                lastDigit = digit;
+                digit = (int) text.getAndAdvance() - '0';
+                digitsFound = true;
+
+                if (decPointIndex != 0)
+                    exponentAdjustment[1]++;
+
+                if (numSignificantDigits == 0 && digit == 0)
+                    continue;
+
+                if (++numSignificantDigits > maxSignificantDigits)
+                {
+                    if (digit > 5)
+                        ++accumulator [decPointIndex];
+                    else if (digit == 5 && (lastDigit & 1) != 0)
+                        ++accumulator [decPointIndex];
+
+                    if (decPointIndex > 0)
+                        exponentAdjustment[1]--;
+                    else
+                        exponentAdjustment[0]++;
+
+                    while (text.isDigit())
+                    {
+                        ++text;
+                        if (decPointIndex == 0)
+                            exponentAdjustment[0]++;
+                    }
+                }
+                else
+                {
+                    const double maxAccumulatorValue = (double) ((std::numeric_limits<unsigned int>::max() - 9) / 10);
+                    if (accumulator [decPointIndex] > maxAccumulatorValue)
+                    {
+                        result [decPointIndex] = mulexp10 (result [decPointIndex], exponentAccumulator [decPointIndex])
+                                                    + accumulator [decPointIndex];
+                        accumulator [decPointIndex] = 0;
+                        exponentAccumulator [decPointIndex] = 0;
+                    }
+
+                    accumulator [decPointIndex] = accumulator[decPointIndex] * 10 + digit;
+                    exponentAccumulator [decPointIndex]++;
+                }
+            }
+            else if (decPointIndex == 0 && *text == '.')
+            {
+                ++text;
+                decPointIndex = 1;
+
+                if (numSignificantDigits > maxSignificantDigits)
+                {
+                    while (text.isDigit())
+                        ++text;
+                    break;
+                }
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        result[0] = mulexp10 (result[0], exponentAccumulator[0]) + accumulator[0];
+
+        if (decPointIndex != 0)
+            result[1] = mulexp10 (result[1], exponentAccumulator[1]) + accumulator[1];
+
+        c = *text;
+        if ((c == 'e' || c == 'E') && digitsFound)
+        {
+            bool negativeExponent = false;
+
+            switch (*++text)
+            {
+                case '-':   negativeExponent = true; // fall-through..
+                case '+':   ++text;
+            }
+
+            while (text.isDigit())
+                exponent = (exponent * 10) + ((int) text.getAndAdvance() - '0');
+
+            if (negativeExponent)
+                exponent = -exponent;
+        }
+
+        double r = mulexp10 (result[0], exponent + exponentAdjustment[0]);
+        if (decPointIndex != 0)
+            r += mulexp10 (result[1], exponent - exponentAdjustment[1]);
+
+        return isNegative ? -r : r;
+    }
+
+    /** Parses a character string, to read a floating-point value. */
+    template <typename CharPointerType>
+    static double getDoubleValue (CharPointerType text) noexcept
+    {
+        return readDoubleValue (text);
+    }
+
+    //==============================================================================
+    /** Parses a character string, to read an integer value. */
+    template <typename IntType, typename CharPointerType>
+    static IntType getIntValue (const CharPointerType text) noexcept
+    {
+        IntType v = 0;
+        CharPointerType s (text.findEndOfWhitespace());
+
+        const bool isNeg = *s == '-';
+        if (isNeg)
+            ++s;
+
+        for (;;)
+        {
+            const juce_wchar c = s.getAndAdvance();
+
+            if (c >= '0' && c <= '9')
+                v = v * 10 + (IntType) (c - '0');
+            else
+                break;
+        }
+
+        return isNeg ? -v : v;
+    }
+
+    template <typename ResultType>
+    struct HexParser
+    {
+        template <typename CharPointerType>
+        static ResultType parse (CharPointerType t) noexcept
+        {
+            ResultType result = 0;
+
+            while (! t.isEmpty())
+            {
+                const int hexValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance());
+
+                if (hexValue >= 0)
+                    result = (result << 4) | hexValue;
+            }
+
+            return result;
+        }
+    };
+
+    //==============================================================================
+    /** Counts the number of characters in a given string, stopping if the count exceeds
+        a specified limit. */
+    template <typename CharPointerType>
+    static size_t lengthUpTo (CharPointerType text, const size_t maxCharsToCount) noexcept
+    {
+        size_t len = 0;
+
+        while (len < maxCharsToCount && text.getAndAdvance() != 0)
+            ++len;
+
+        return len;
+    }
+
+    /** Counts the number of characters in a given string, stopping if the count exceeds
+        a specified end-pointer. */
+    template <typename CharPointerType>
+    static size_t lengthUpTo (CharPointerType start, const CharPointerType end) noexcept
+    {
+        size_t len = 0;
+
+        while (start < end && start.getAndAdvance() != 0)
+            ++len;
+
+        return len;
+    }
+
+    /** Copies null-terminated characters from one string to another. */
+    template <typename DestCharPointerType, typename SrcCharPointerType>
+    static void copyAll (DestCharPointerType& dest, SrcCharPointerType src) noexcept
+    {
+        for (;;)
+        {
+            const juce_wchar c = src.getAndAdvance();
+
+            if (c == 0)
+                break;
+
+            dest.write (c);
+        }
+
+        dest.writeNull();
+    }
+
+    /** Copies characters from one string to another, up to a null terminator
+        or a given byte size limit. */
+    template <typename DestCharPointerType, typename SrcCharPointerType>
+    static size_t copyWithDestByteLimit (DestCharPointerType& dest, SrcCharPointerType src, size_t maxBytesToWrite) noexcept
+    {
+        typename DestCharPointerType::CharType const* const startAddress = dest.getAddress();
+        ssize_t maxBytes = (ssize_t) maxBytesToWrite;
+        maxBytes -= sizeof (typename DestCharPointerType::CharType); // (allow for a terminating null)
+
+        for (;;)
+        {
+            const juce_wchar c = src.getAndAdvance();
+            const size_t bytesNeeded = DestCharPointerType::getBytesRequiredFor (c);
+
+            maxBytes -= bytesNeeded;
+            if (c == 0 || maxBytes < 0)
+                break;
+
+            dest.write (c);
+        }
+
+        dest.writeNull();
+
+        return (size_t) getAddressDifference (dest.getAddress(), startAddress)
+                 + sizeof (typename DestCharPointerType::CharType);
+    }
+
+    /** Copies characters from one string to another, up to a null terminator
+        or a given maximum number of characters. */
+    template <typename DestCharPointerType, typename SrcCharPointerType>
+    static void copyWithCharLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxChars) noexcept
+    {
+        while (--maxChars > 0)
+        {
+            const juce_wchar c = src.getAndAdvance();
+            if (c == 0)
+                break;
+
+            dest.write (c);
+        }
+
+        dest.writeNull();
+    }
+
+    /** Compares two null-terminated character strings. */
+    template <typename CharPointerType1, typename CharPointerType2>
+    static int compare (CharPointerType1 s1, CharPointerType2 s2) noexcept
+    {
+        for (;;)
+        {
+            const int c1 = (int) s1.getAndAdvance();
+            const int c2 = (int) s2.getAndAdvance();
+            const int diff = c1 - c2;
+
+            if (diff != 0)  return diff < 0 ? -1 : 1;
+            if (c1 == 0)    break;
+        }
+
+        return 0;
+    }
+
+    /** Compares two null-terminated character strings, up to a given number of characters. */
+    template <typename CharPointerType1, typename CharPointerType2>
+    static int compareUpTo (CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
+    {
+        while (--maxChars >= 0)
+        {
+            const int c1 = (int) s1.getAndAdvance();
+            const int c2 = (int) s2.getAndAdvance();
+            const int diff = c1 - c2;
+
+            if (diff != 0)  return diff < 0 ? -1 : 1;
+            if (c1 == 0)    break;
+        }
+
+        return 0;
+    }
+
+    /** Compares two null-terminated character strings, using a case-independant match. */
+    template <typename CharPointerType1, typename CharPointerType2>
+    static int compareIgnoreCase (CharPointerType1 s1, CharPointerType2 s2) noexcept
+    {
+        for (;;)
+        {
+            const int c1 = (int) s1.toUpperCase();
+            const int c2 = (int) s2.toUpperCase();
+            const int diff = c1 - c2;
+
+            if (diff != 0)  return diff < 0 ? -1 : 1;
+            if (c1 == 0)    break;
+
+             ++s1; ++s2;
+        }
+
+        return 0;
+    }
+
+    /** Compares two null-terminated character strings, using a case-independent match. */
+    template <typename CharPointerType1, typename CharPointerType2>
+    static int compareIgnoreCaseUpTo (CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
+    {
+        while (--maxChars >= 0)
+        {
+            const int c1 = (int) s1.toUpperCase();
+            const int c2 = (int) s2.toUpperCase();
+            const int diff = c1 - c2;
+
+            if (diff != 0)  return diff < 0 ? -1 : 1;
+            if (c1 == 0)    break;
+
+             ++s1; ++s2;
+        }
+
+        return 0;
+    }
+
+    /** Finds the character index of a given substring in another string.
+        Returns -1 if the substring is not found.
+    */
+    template <typename CharPointerType1, typename CharPointerType2>
+    static int indexOf (CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
+    {
+        int index = 0;
+        const int substringLength = (int) substringToLookFor.length();
+
+        for (;;)
+        {
+            if (textToSearch.compareUpTo (substringToLookFor, substringLength) == 0)
+                return index;
+
+            if (textToSearch.getAndAdvance() == 0)
+                return -1;
+
+            ++index;
+        }
+    }
+
+    /** Returns a pointer to the first occurrence of a substring in a string.
+        If the substring is not found, this will return a pointer to the string's
+        null terminator.
+    */
+    template <typename CharPointerType1, typename CharPointerType2>
+    static CharPointerType1 find (CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
+    {
+        const int substringLength = (int) substringToLookFor.length();
+
+        while (textToSearch.compareUpTo (substringToLookFor, substringLength) != 0
+                 && ! textToSearch.isEmpty())
+            ++textToSearch;
+
+        return textToSearch;
+    }
+
+    /** Returns a pointer to the first occurrence of a substring in a string.
+        If the substring is not found, this will return a pointer to the string's
+        null terminator.
+    */
+    template <typename CharPointerType>
+    static CharPointerType find (CharPointerType textToSearch, const juce_wchar charToLookFor) noexcept
+    {
+        for (;; ++textToSearch)
+        {
+            const juce_wchar c = *textToSearch;
+
+            if (c == charToLookFor || c == 0)
+                break;
+        }
+
+        return textToSearch;
+    }
+
+    /** Finds the character index of a given substring in another string, using
+        a case-independent match.
+        Returns -1 if the substring is not found.
+    */
+    template <typename CharPointerType1, typename CharPointerType2>
+    static int indexOfIgnoreCase (CharPointerType1 haystack, const CharPointerType2 needle) noexcept
+    {
+        int index = 0;
+        const int needleLength = (int) needle.length();
+
+        for (;;)
+        {
+            if (haystack.compareIgnoreCaseUpTo (needle, needleLength) == 0)
+                return index;
+
+            if (haystack.getAndAdvance() == 0)
+                return -1;
+
+            ++index;
+        }
+    }
+
+    /** Finds the character index of a given character in another string.
+        Returns -1 if the character is not found.
+    */
+    template <typename Type>
+    static int indexOfChar (Type text, const juce_wchar charToFind) noexcept
+    {
+        int i = 0;
+
+        while (! text.isEmpty())
+        {
+            if (text.getAndAdvance() == charToFind)
+                return i;
+
+            ++i;
+        }
+
+        return -1;
+    }
+
+    /** Finds the character index of a given character in another string, using
+        a case-independent match.
+        Returns -1 if the character is not found.
+    */
+    template <typename Type>
+    static int indexOfCharIgnoreCase (Type text, juce_wchar charToFind) noexcept
+    {
+        charToFind = CharacterFunctions::toLowerCase (charToFind);
+        int i = 0;
+
+        while (! text.isEmpty())
+        {
+            if (text.toLowerCase() == charToFind)
+                return i;
+
+            ++text;
+            ++i;
+        }
+
+        return -1;
+    }
+
+    /** Returns a pointer to the first non-whitespace character in a string.
+        If the string contains only whitespace, this will return a pointer
+        to its null terminator.
+    */
+    template <typename Type>
+    static Type findEndOfWhitespace (Type text) noexcept
+    {
+        while (text.isWhitespace())
+            ++text;
+
+        return text;
+    }
+
+    /** Returns a pointer to the first character in the string which is found in
+        the breakCharacters string.
+    */
+    template <typename Type, typename BreakType>
+    static Type findEndOfToken (Type text, const BreakType breakCharacters, const Type quoteCharacters)
+    {
+        juce_wchar currentQuoteChar = 0;
+
+        while (! text.isEmpty())
+        {
+            const juce_wchar c = text.getAndAdvance();
+
+            if (currentQuoteChar == 0 && breakCharacters.indexOf (c) >= 0)
+            {
+                --text;
+                break;
+            }
+
+            if (quoteCharacters.indexOf (c) >= 0)
+            {
+                if (currentQuoteChar == 0)
+                    currentQuoteChar = c;
+                else if (currentQuoteChar == c)
+                    currentQuoteChar = 0;
+            }
+        }
+
+        return text;
+    }
+
+private:
+    static double mulexp10 (const double value, int exponent) noexcept;
+};
+
+
+#endif   // JUCE_CHARACTERFUNCTIONS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_Identifier.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_Identifier.cpp
new file mode 100644
index 0000000..bac4dd5
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_Identifier.cpp
@@ -0,0 +1,70 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+Identifier::Identifier() noexcept {}
+Identifier::~Identifier() noexcept {}
+
+Identifier::Identifier (const Identifier& other) noexcept  : name (other.name) {}
+
+Identifier& Identifier::operator= (const Identifier other) noexcept
+{
+    name = other.name;
+    return *this;
+}
+
+Identifier::Identifier (const String& nm)
+    : name (StringPool::getGlobalPool().getPooledString (nm))
+{
+    /* An Identifier string must be suitable for use as a script variable or XML
+       attribute, so it can only contain this limited set of characters.. */
+    jassert (isValidIdentifier (toString()));
+}
+
+Identifier::Identifier (const char* nm)
+    : name (StringPool::getGlobalPool().getPooledString (nm))
+{
+    /* An Identifier string must be suitable for use as a script variable or XML
+       attribute, so it can only contain this limited set of characters.. */
+    jassert (isValidIdentifier (toString()));
+}
+
+Identifier::Identifier (String::CharPointerType start, String::CharPointerType end)
+    : name (StringPool::getGlobalPool().getPooledString (start, end))
+{
+    /* An Identifier string must be suitable for use as a script variable or XML
+       attribute, so it can only contain this limited set of characters.. */
+    jassert (isValidIdentifier (toString()));
+}
+
+Identifier Identifier::null;
+
+bool Identifier::isValidIdentifier (const String& possibleIdentifier) noexcept
+{
+    return possibleIdentifier.isNotEmpty()
+            && possibleIdentifier.containsOnly ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:#@$%");
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_Identifier.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_Identifier.h
new file mode 100644
index 0000000..f60eec8
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_Identifier.h
@@ -0,0 +1,120 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_IDENTIFIER_H_INCLUDED
+#define JUCE_IDENTIFIER_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Represents a string identifier, designed for accessing properties by name.
+
+    Comparing two Identifier objects is very fast (an O(1) operation), but creating
+    them can be slower than just using a String directly, so the optimal way to use them
+    is to keep some static Identifier objects for the things you use often.
+
+    @see NamedValueSet, ValueTree
+*/
+class JUCE_API  Identifier
+{
+public:
+    /** Creates a null identifier. */
+    Identifier() noexcept;
+
+    /** Creates an identifier with a specified name.
+        Because this name may need to be used in contexts such as script variables or XML
+        tags, it must only contain ascii letters and digits, or the underscore character.
+    */
+    Identifier (const char* name);
+
+    /** Creates an identifier with a specified name.
+        Because this name may need to be used in contexts such as script variables or XML
+        tags, it must only contain ascii letters and digits, or the underscore character.
+    */
+    Identifier (const String& name);
+
+    /** Creates an identifier with a specified name.
+        Because this name may need to be used in contexts such as script variables or XML
+        tags, it must only contain ascii letters and digits, or the underscore character.
+    */
+    Identifier (String::CharPointerType nameStart, String::CharPointerType nameEnd);
+
+    /** Creates a copy of another identifier. */
+    Identifier (const Identifier& other) noexcept;
+
+    /** Creates a copy of another identifier. */
+    Identifier& operator= (const Identifier other) noexcept;
+
+    /** Destructor */
+    ~Identifier() noexcept;
+
+    /** Compares two identifiers. This is a very fast operation. */
+    inline bool operator== (Identifier other) const noexcept            { return name.getCharPointer() == other.name.getCharPointer(); }
+
+    /** Compares two identifiers. This is a very fast operation. */
+    inline bool operator!= (Identifier other) const noexcept            { return name.getCharPointer() != other.name.getCharPointer(); }
+
+    /** Compares the identifier with a string. */
+    inline bool operator== (StringRef other) const noexcept             { return name == other; }
+
+    /** Compares the identifier with a string. */
+    inline bool operator!= (StringRef other) const noexcept             { return name != other; }
+
+    /** Returns this identifier as a string. */
+    const String& toString() const noexcept                             { return name; }
+
+    /** Returns this identifier's raw string pointer. */
+    operator String::CharPointerType() const noexcept                   { return name.getCharPointer(); }
+
+    /** Returns this identifier's raw string pointer. */
+    String::CharPointerType getCharPointer() const noexcept             { return name.getCharPointer(); }
+
+    /** Returns this identifier as a StringRef. */
+    operator StringRef() const noexcept                                 { return name; }
+
+    /** Returns true if this Identifier is not null */
+    bool isValid() const noexcept                                       { return name.isNotEmpty(); }
+
+    /** Returns true if this Identifier is null */
+    bool isNull() const noexcept                                        { return name.isEmpty(); }
+
+    /** A null identifier. */
+    static Identifier null;
+
+    /** Checks a given string for characters that might not be valid in an Identifier.
+        Since Identifiers are used as a script variables and XML attributes, they should only contain
+        alphanumeric characters, underscores, or the '-' and ':' characters.
+    */
+    static bool isValidIdentifier (const String& possibleIdentifier) noexcept;
+
+private:
+    String name;
+};
+
+
+#endif   // JUCE_IDENTIFIER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_LocalisedStrings.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_LocalisedStrings.cpp
new file mode 100644
index 0000000..e6118d3
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_LocalisedStrings.cpp
@@ -0,0 +1,209 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+LocalisedStrings::LocalisedStrings (const String& fileContents, bool ignoreCase)
+{
+    loadFromText (fileContents, ignoreCase);
+}
+
+LocalisedStrings::LocalisedStrings (const File& fileToLoad, bool ignoreCase)
+{
+    loadFromText (fileToLoad.loadFileAsString(), ignoreCase);
+}
+
+LocalisedStrings::LocalisedStrings (const LocalisedStrings& other)
+    : languageName (other.languageName), countryCodes (other.countryCodes),
+      translations (other.translations), fallback (createCopyIfNotNull (other.fallback.get()))
+{
+}
+
+LocalisedStrings& LocalisedStrings::operator= (const LocalisedStrings& other)
+{
+    languageName = other.languageName;
+    countryCodes = other.countryCodes;
+    translations = other.translations;
+    fallback = createCopyIfNotNull (other.fallback.get());
+    return *this;
+}
+
+LocalisedStrings::~LocalisedStrings()
+{
+}
+
+//==============================================================================
+String LocalisedStrings::translate (const String& text) const
+{
+    if (fallback != nullptr && ! translations.containsKey (text))
+        return fallback->translate (text);
+
+    return translations.getValue (text, text);
+}
+
+String LocalisedStrings::translate (const String& text, const String& resultIfNotFound) const
+{
+    if (fallback != nullptr && ! translations.containsKey (text))
+        return fallback->translate (text, resultIfNotFound);
+
+    return translations.getValue (text, resultIfNotFound);
+}
+
+namespace
+{
+   #if JUCE_CHECK_MEMORY_LEAKS
+    // By using this object to force a LocalisedStrings object to be created
+    // before the currentMappings object, we can force the static order-of-destruction to
+    // delete the currentMappings object first, which avoids a bogus leak warning.
+    // (Oddly, just creating a LocalisedStrings on the stack doesn't work in gcc, it
+    // has to be created with 'new' for this to work..)
+    struct LeakAvoidanceTrick
+    {
+        LeakAvoidanceTrick()
+        {
+            const ScopedPointer<LocalisedStrings> dummy (new LocalisedStrings (String(), false));
+        }
+    };
+
+    LeakAvoidanceTrick leakAvoidanceTrick;
+   #endif
+
+    SpinLock currentMappingsLock;
+    ScopedPointer<LocalisedStrings> currentMappings;
+
+    static int findCloseQuote (const String& text, int startPos)
+    {
+        juce_wchar lastChar = 0;
+        String::CharPointerType t (text.getCharPointer() + startPos);
+
+        for (;;)
+        {
+            const juce_wchar c = t.getAndAdvance();
+
+            if (c == 0 || (c == '"' && lastChar != '\\'))
+                break;
+
+            lastChar = c;
+            ++startPos;
+        }
+
+        return startPos;
+    }
+
+    static String unescapeString (const String& s)
+    {
+        return s.replace ("\\\"", "\"")
+                .replace ("\\\'", "\'")
+                .replace ("\\t", "\t")
+                .replace ("\\r", "\r")
+                .replace ("\\n", "\n");
+    }
+}
+
+void LocalisedStrings::loadFromText (const String& fileContents, bool ignoreCase)
+{
+    translations.setIgnoresCase (ignoreCase);
+
+    StringArray lines;
+    lines.addLines (fileContents);
+
+    for (int i = 0; i < lines.size(); ++i)
+    {
+        String line (lines[i].trim());
+
+        if (line.startsWithChar ('"'))
+        {
+            int closeQuote = findCloseQuote (line, 1);
+
+            const String originalText (unescapeString (line.substring (1, closeQuote)));
+
+            if (originalText.isNotEmpty())
+            {
+                const int openingQuote = findCloseQuote (line, closeQuote + 1);
+                closeQuote = findCloseQuote (line, openingQuote + 1);
+
+                const String newText (unescapeString (line.substring (openingQuote + 1, closeQuote)));
+
+                if (newText.isNotEmpty())
+                    translations.set (originalText, newText);
+            }
+        }
+        else if (line.startsWithIgnoreCase ("language:"))
+        {
+            languageName = line.substring (9).trim();
+        }
+        else if (line.startsWithIgnoreCase ("countries:"))
+        {
+            countryCodes.addTokens (line.substring (10).trim(), true);
+            countryCodes.trim();
+            countryCodes.removeEmptyStrings();
+        }
+    }
+
+    translations.minimiseStorageOverheads();
+}
+
+void LocalisedStrings::addStrings (const LocalisedStrings& other)
+{
+    jassert (languageName == other.languageName);
+    jassert (countryCodes == other.countryCodes);
+
+    translations.addArray (other.translations);
+}
+
+void LocalisedStrings::setFallback (LocalisedStrings* f)
+{
+    fallback = f;
+}
+
+//==============================================================================
+void LocalisedStrings::setCurrentMappings (LocalisedStrings* newTranslations)
+{
+    const SpinLock::ScopedLockType sl (currentMappingsLock);
+    currentMappings = newTranslations;
+}
+
+LocalisedStrings* LocalisedStrings::getCurrentMappings()
+{
+    return currentMappings;
+}
+
+String LocalisedStrings::translateWithCurrentMappings (const String& text)  { return juce::translate (text); }
+String LocalisedStrings::translateWithCurrentMappings (const char* text)    { return juce::translate (text); }
+
+JUCE_API String translate (const String& text)       { return juce::translate (text, text); }
+JUCE_API String translate (const char* text)         { return juce::translate (String (text)); }
+JUCE_API String translate (CharPointer_UTF8 text)    { return juce::translate (String (text)); }
+
+JUCE_API String translate (const String& text, const String& resultIfNotFound)
+{
+    const SpinLock::ScopedLockType sl (currentMappingsLock);
+
+    if (const LocalisedStrings* const mappings = LocalisedStrings::getCurrentMappings())
+        return mappings->translate (text, resultIfNotFound);
+
+    return resultIfNotFound;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_LocalisedStrings.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_LocalisedStrings.h
new file mode 100644
index 0000000..a594919
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_LocalisedStrings.h
@@ -0,0 +1,247 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_LOCALISEDSTRINGS_H_INCLUDED
+#define JUCE_LOCALISEDSTRINGS_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Used to convert strings to localised foreign-language versions.
+
+    This is basically a look-up table of strings and their translated equivalents.
+    It can be loaded from a text file, so that you can supply a set of localised
+    versions of strings that you use in your app.
+
+    To use it in your code, simply call the translate() method on each string that
+    might have foreign versions, and if none is found, the method will just return
+    the original string.
+
+    The translation file should start with some lines specifying a description of
+    the language it contains, and also a list of ISO country codes where it might
+    be appropriate to use the file. After that, each line of the file should contain
+    a pair of quoted strings with an '=' sign.
+
+    E.g. for a french translation, the file might be:
+
+    @code
+    language: French
+    countries: fr be mc ch lu
+
+    "hello" = "bonjour"
+    "goodbye" = "au revoir"
+    @endcode
+
+    If the strings need to contain a quote character, they can use '\"' instead, and
+    if the first non-whitespace character on a line isn't a quote, then it's ignored,
+    (you can use this to add comments).
+
+    Note that this is a singleton class, so don't create or destroy the object directly.
+    There's also a TRANS(text) macro defined to make it easy to use the this.
+
+    E.g. @code
+    printSomething (TRANS("hello"));
+    @endcode
+
+    This macro is used in the Juce classes themselves, so your application has a chance to
+    intercept and translate any internal Juce text strings that might be shown. (You can easily
+    get a list of all the messages by searching for the TRANS() macro in the Juce source
+    code).
+*/
+class JUCE_API  LocalisedStrings
+{
+public:
+    //==============================================================================
+    /** Creates a set of translations from the text of a translation file.
+
+        When you create one of these, you can call setCurrentMappings() to make it
+        the set of mappings that the system's using.
+    */
+    LocalisedStrings (const String& fileContents, bool ignoreCaseOfKeys);
+
+    /** Creates a set of translations from a file.
+
+        When you create one of these, you can call setCurrentMappings() to make it
+        the set of mappings that the system's using.
+    */
+    LocalisedStrings (const File& fileToLoad, bool ignoreCaseOfKeys);
+
+    LocalisedStrings (const LocalisedStrings&);
+    LocalisedStrings& operator= (const LocalisedStrings&);
+
+    /** Destructor. */
+    ~LocalisedStrings();
+
+    //==============================================================================
+    /** Selects the current set of mappings to be used by the system.
+
+        The object you pass in will be automatically deleted when no longer needed, so
+        don't keep a pointer to it. You can also pass in nullptr to remove the current
+        mappings.
+
+        See also the TRANS() macro, which uses the current set to do its translation.
+
+        @see translateWithCurrentMappings
+    */
+    static void setCurrentMappings (LocalisedStrings* newTranslations);
+
+    /** Returns the currently selected set of mappings.
+
+        This is the object that was last passed to setCurrentMappings(). It may
+        be nullptr if none has been created.
+    */
+    static LocalisedStrings* getCurrentMappings();
+
+    /** Tries to translate a string using the currently selected set of mappings.
+
+        If no mapping has been set, or if the mapping doesn't contain a translation
+        for the string, this will just return the original string.
+
+        See also the TRANS() macro, which uses this method to do its translation.
+
+        @see setCurrentMappings, getCurrentMappings
+    */
+    static String translateWithCurrentMappings (const String& text);
+
+    /** Tries to translate a string using the currently selected set of mappings.
+
+        If no mapping has been set, or if the mapping doesn't contain a translation
+        for the string, this will just return the original string.
+
+        See also the TRANS() macro, which uses this method to do its translation.
+
+        @see setCurrentMappings, getCurrentMappings
+    */
+    static String translateWithCurrentMappings (const char* text);
+
+    //==============================================================================
+    /** Attempts to look up a string and return its localised version.
+        If the string isn't found in the list, the original string will be returned.
+    */
+    String translate (const String& text) const;
+
+    /** Attempts to look up a string and return its localised version.
+        If the string isn't found in the list, the resultIfNotFound string will be returned.
+    */
+    String translate (const String& text, const String& resultIfNotFound) const;
+
+    /** Returns the name of the language specified in the translation file.
+
+        This is specified in the file using a line starting with "language:", e.g.
+        @code
+        language: german
+        @endcode
+    */
+    String getLanguageName() const                        { return languageName; }
+
+    /** Returns the list of suitable country codes listed in the translation file.
+
+        These is specified in the file using a line starting with "countries:", e.g.
+        @code
+        countries: fr be mc ch lu
+        @endcode
+
+        The country codes are supposed to be 2-character ISO complient codes.
+    */
+    const StringArray& getCountryCodes() const            { return countryCodes; }
+
+    /** Provides access to the actual list of mappings. */
+    const StringPairArray& getMappings() const            { return translations; }
+
+    //==============================================================================
+    /** Adds and merges another set of translations into this set.
+
+        Note that the language name and country codes of the new LocalisedStrings
+        object must match that of this object - an assertion will be thrown if they
+        don't match.
+
+        Any existing values will have their mappings overwritten by the new ones.
+    */
+    void addStrings (const LocalisedStrings&);
+
+    /** Gives this object a set of strings to use as a fallback if a string isn't found.
+        The object that is passed-in will be owned and deleted by this object
+        when no longer needed. It can be nullptr to clear the existing fallback object.
+    */
+    void setFallback (LocalisedStrings* fallbackStrings);
+
+private:
+    //==============================================================================
+    String languageName;
+    StringArray countryCodes;
+    StringPairArray translations;
+    ScopedPointer<LocalisedStrings> fallback;
+    friend struct ContainerDeletePolicy<LocalisedStrings>;
+
+    void loadFromText (const String&, bool ignoreCase);
+
+    JUCE_LEAK_DETECTOR (LocalisedStrings)
+};
+
+//==============================================================================
+#ifndef TRANS
+ /** Uses the LocalisedStrings class to translate the given string literal.
+     This macro is provided for backwards-compatibility, and just calls the translate()
+     function. In new code, it's recommended that you just call translate() directly
+     instead, and avoid using macros.
+     @see translate(), LocalisedStrings
+ */
+ #define TRANS(stringLiteral) juce::translate (stringLiteral)
+#endif
+
+/** A dummy version of the TRANS macro, used to indicate a string literal that should be
+    added to the translation file by source-code scanner tools.
+
+    Wrapping a string literal in this macro has no effect, but by using it around strings
+    that your app needs to translate at a later stage, it lets automatic code-scanning tools
+    find this string and add it to the list of strings that need translation.
+*/
+#define NEEDS_TRANS(stringLiteral) (stringLiteral)
+
+/** Uses the LocalisedStrings class to translate the given string literal.
+    @see LocalisedStrings
+*/
+JUCE_API String translate (const String& stringLiteral);
+
+/** Uses the LocalisedStrings class to translate the given string literal.
+    @see LocalisedStrings
+*/
+JUCE_API String translate (const char* stringLiteral);
+
+/** Uses the LocalisedStrings class to translate the given string literal.
+    @see LocalisedStrings
+*/
+JUCE_API String translate (CharPointer_UTF8 stringLiteral);
+
+/** Uses the LocalisedStrings class to translate the given string literal.
+    @see LocalisedStrings
+*/
+JUCE_API String translate (const String& stringLiteral, const String& resultIfNotFound);
+
+
+#endif   // JUCE_LOCALISEDSTRINGS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_NewLine.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_NewLine.h
new file mode 100644
index 0000000..980ac23
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_NewLine.h
@@ -0,0 +1,86 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_NEWLINE_H_INCLUDED
+#define JUCE_NEWLINE_H_INCLUDED
+
+
+//==============================================================================
+/** This class is used for represent a new-line character sequence.
+
+    To write a new-line to a stream, you can use the predefined 'newLine' variable, e.g.
+    @code
+    myOutputStream << "Hello World" << newLine << newLine;
+    @endcode
+
+    The exact character sequence that will be used for the new-line can be set and
+    retrieved with OutputStream::setNewLineString() and OutputStream::getNewLineString().
+*/
+class JUCE_API  NewLine
+{
+public:
+    /** Returns the default new-line sequence that the library uses.
+        @see OutputStream::setNewLineString()
+    */
+    static const char* getDefault() noexcept        { return "\r\n"; }
+
+    /** Returns the default new-line sequence that the library uses.
+        @see getDefault()
+    */
+    operator String() const                         { return getDefault(); }
+
+    /** Returns the default new-line sequence that the library uses.
+        @see OutputStream::setNewLineString()
+    */
+    operator StringRef() const noexcept             { return getDefault(); }
+};
+
+//==============================================================================
+/** A predefined object representing a new-line, which can be written to a string or stream.
+
+    To write a new-line to a stream, you can use the predefined 'newLine' variable like this:
+    @code
+    myOutputStream << "Hello World" << newLine << newLine;
+    @endcode
+*/
+extern NewLine newLine;
+
+//==============================================================================
+/** Writes a new-line sequence to a string.
+    You can use the predefined object 'newLine' to invoke this, e.g.
+    @code
+    myString << "Hello World" << newLine << newLine;
+    @endcode
+*/
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const NewLine&);
+
+#if JUCE_STRING_UTF_TYPE != 8 && ! defined (DOXYGEN)
+ inline String operator+ (String s1, const NewLine&)      { return s1 += NewLine::getDefault(); }
+#endif
+
+#endif   // JUCE_NEWLINE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_String.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_String.cpp
new file mode 100644
index 0000000..1dce723
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_String.cpp
@@ -0,0 +1,2543 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#if JUCE_MSVC
+ #pragma warning (push)
+ #pragma warning (disable: 4514 4996)
+#endif
+
+NewLine newLine;
+
+#if defined (JUCE_STRINGS_ARE_UNICODE) && ! JUCE_STRINGS_ARE_UNICODE
+ #error "JUCE_STRINGS_ARE_UNICODE is deprecated! All strings are now unicode by default."
+#endif
+
+#if JUCE_NATIVE_WCHAR_IS_UTF8
+ typedef CharPointer_UTF8          CharPointer_wchar_t;
+#elif JUCE_NATIVE_WCHAR_IS_UTF16
+ typedef CharPointer_UTF16         CharPointer_wchar_t;
+#else
+ typedef CharPointer_UTF32         CharPointer_wchar_t;
+#endif
+
+static inline CharPointer_wchar_t castToCharPointer_wchar_t (const void* t) noexcept
+{
+    return CharPointer_wchar_t (static_cast<const CharPointer_wchar_t::CharType*> (t));
+}
+
+//==============================================================================
+// (Mirrors the structure of StringHolder, but without the atomic member, so can be statically constructed)
+struct EmptyString
+{
+    int refCount;
+    size_t allocatedBytes;
+    String::CharPointerType::CharType text;
+};
+
+static const EmptyString emptyString = { 0x3fffffff, sizeof (String::CharPointerType::CharType), 0 };
+
+//==============================================================================
+class StringHolder
+{
+public:
+    StringHolder() JUCE_DELETED_FUNCTION;
+
+    typedef String::CharPointerType CharPointerType;
+    typedef String::CharPointerType::CharType CharType;
+
+    //==============================================================================
+    static CharPointerType createUninitialisedBytes (size_t numBytes)
+    {
+        numBytes = (numBytes + 3) & ~(size_t) 3;
+        StringHolder* const s = reinterpret_cast<StringHolder*> (new char [sizeof (StringHolder) - sizeof (CharType) + numBytes]);
+        s->refCount.value = 0;
+        s->allocatedNumBytes = numBytes;
+        return CharPointerType (s->text);
+    }
+
+    template <class CharPointer>
+    static CharPointerType createFromCharPointer (const CharPointer text)
+    {
+        if (text.getAddress() == nullptr || text.isEmpty())
+            return CharPointerType (&(emptyString.text));
+
+        CharPointer t (text);
+        size_t bytesNeeded = sizeof (CharType);
+
+        while (! t.isEmpty())
+            bytesNeeded += CharPointerType::getBytesRequiredFor (t.getAndAdvance());
+
+        const CharPointerType dest (createUninitialisedBytes (bytesNeeded));
+        CharPointerType (dest).writeAll (text);
+        return dest;
+    }
+
+    template <class CharPointer>
+    static CharPointerType createFromCharPointer (const CharPointer text, size_t maxChars)
+    {
+        if (text.getAddress() == nullptr || text.isEmpty() || maxChars == 0)
+            return CharPointerType (&(emptyString.text));
+
+        CharPointer end (text);
+        size_t numChars = 0;
+        size_t bytesNeeded = sizeof (CharType);
+
+        while (numChars < maxChars && ! end.isEmpty())
+        {
+            bytesNeeded += CharPointerType::getBytesRequiredFor (end.getAndAdvance());
+            ++numChars;
+        }
+
+        const CharPointerType dest (createUninitialisedBytes (bytesNeeded));
+        CharPointerType (dest).writeWithCharLimit (text, (int) numChars + 1);
+        return dest;
+    }
+
+    template <class CharPointer>
+    static CharPointerType createFromCharPointer (const CharPointer start, const CharPointer end)
+    {
+        if (start.getAddress() == nullptr || start.isEmpty())
+            return CharPointerType (&(emptyString.text));
+
+        CharPointer e (start);
+        int numChars = 0;
+        size_t bytesNeeded = sizeof (CharType);
+
+        while (e < end && ! e.isEmpty())
+        {
+            bytesNeeded += CharPointerType::getBytesRequiredFor (e.getAndAdvance());
+            ++numChars;
+        }
+
+        const CharPointerType dest (createUninitialisedBytes (bytesNeeded));
+        CharPointerType (dest).writeWithCharLimit (start, numChars + 1);
+        return dest;
+    }
+
+    static CharPointerType createFromCharPointer (const CharPointerType start, const CharPointerType end)
+    {
+        if (start.getAddress() == nullptr || start.isEmpty())
+            return CharPointerType (&(emptyString.text));
+
+        const size_t numBytes = (size_t) (reinterpret_cast<const char*> (end.getAddress())
+                                           - reinterpret_cast<const char*> (start.getAddress()));
+        const CharPointerType dest (createUninitialisedBytes (numBytes + sizeof (CharType)));
+        memcpy (dest.getAddress(), start, numBytes);
+        dest.getAddress()[numBytes / sizeof (CharType)] = 0;
+        return dest;
+    }
+
+    static CharPointerType createFromFixedLength (const char* const src, const size_t numChars)
+    {
+        const CharPointerType dest (createUninitialisedBytes (numChars * sizeof (CharType) + sizeof (CharType)));
+        CharPointerType (dest).writeWithCharLimit (CharPointer_UTF8 (src), (int) (numChars + 1));
+        return dest;
+    }
+
+    //==============================================================================
+    static void retain (const CharPointerType text) noexcept
+    {
+        StringHolder* const b = bufferFromText (text);
+
+        if (b != (StringHolder*) &emptyString)
+            ++(b->refCount);
+    }
+
+    static inline void release (StringHolder* const b) noexcept
+    {
+        if (b != (StringHolder*) &emptyString)
+            if (--(b->refCount) == -1)
+                delete[] reinterpret_cast<char*> (b);
+    }
+
+    static void release (const CharPointerType text) noexcept
+    {
+        release (bufferFromText (text));
+    }
+
+    static inline int getReferenceCount (const CharPointerType text) noexcept
+    {
+        return bufferFromText (text)->refCount.get() + 1;
+    }
+
+    //==============================================================================
+    static CharPointerType makeUniqueWithByteSize (const CharPointerType text, size_t numBytes)
+    {
+        StringHolder* const b = bufferFromText (text);
+
+        if (b == (StringHolder*) &emptyString)
+        {
+            CharPointerType newText (createUninitialisedBytes (numBytes));
+            newText.writeNull();
+            return newText;
+        }
+
+        if (b->allocatedNumBytes >= numBytes && b->refCount.get() <= 0)
+            return text;
+
+        CharPointerType newText (createUninitialisedBytes (jmax (b->allocatedNumBytes, numBytes)));
+        memcpy (newText.getAddress(), text.getAddress(), b->allocatedNumBytes);
+        release (b);
+
+        return newText;
+    }
+
+    static size_t getAllocatedNumBytes (const CharPointerType text) noexcept
+    {
+        return bufferFromText (text)->allocatedNumBytes;
+    }
+
+    //==============================================================================
+    Atomic<int> refCount;
+    size_t allocatedNumBytes;
+    CharType text[1];
+
+private:
+    static inline StringHolder* bufferFromText (const CharPointerType text) noexcept
+    {
+        // (Can't use offsetof() here because of warnings about this not being a POD)
+        return reinterpret_cast<StringHolder*> (reinterpret_cast<char*> (text.getAddress())
+                    - (reinterpret_cast<size_t> (reinterpret_cast<StringHolder*> (1)->text) - 1));
+    }
+
+    void compileTimeChecks()
+    {
+        // Let me know if any of these assertions fail on your system!
+       #if JUCE_NATIVE_WCHAR_IS_UTF8
+        static_jassert (sizeof (wchar_t) == 1);
+       #elif JUCE_NATIVE_WCHAR_IS_UTF16
+        static_jassert (sizeof (wchar_t) == 2);
+       #elif JUCE_NATIVE_WCHAR_IS_UTF32
+        static_jassert (sizeof (wchar_t) == 4);
+       #else
+        #error "native wchar_t size is unknown"
+       #endif
+
+        static_jassert (sizeof (EmptyString) == sizeof (StringHolder));
+    }
+};
+
+const String String::empty;
+
+//==============================================================================
+String::String() noexcept  : text (&(emptyString.text))
+{
+}
+
+String::~String() noexcept
+{
+    StringHolder::release (text);
+}
+
+String::String (const String& other) noexcept   : text (other.text)
+{
+    StringHolder::retain (text);
+}
+
+void String::swapWith (String& other) noexcept
+{
+    std::swap (text, other.text);
+}
+
+void String::clear() noexcept
+{
+    StringHolder::release (text);
+    text = &(emptyString.text);
+}
+
+String& String::operator= (const String& other) noexcept
+{
+    StringHolder::retain (other.text);
+    StringHolder::release (text.atomicSwap (other.text));
+    return *this;
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+String::String (String&& other) noexcept   : text (other.text)
+{
+    other.text = &(emptyString.text);
+}
+
+String& String::operator= (String&& other) noexcept
+{
+    std::swap (text, other.text);
+    return *this;
+}
+#endif
+
+inline String::PreallocationBytes::PreallocationBytes (const size_t num) noexcept : numBytes (num) {}
+
+String::String (const PreallocationBytes& preallocationSize)
+    : text (StringHolder::createUninitialisedBytes (preallocationSize.numBytes + sizeof (CharPointerType::CharType)))
+{
+}
+
+void String::preallocateBytes (const size_t numBytesNeeded)
+{
+    text = StringHolder::makeUniqueWithByteSize (text, numBytesNeeded + sizeof (CharPointerType::CharType));
+}
+
+int String::getReferenceCount() const noexcept
+{
+    return StringHolder::getReferenceCount (text);
+}
+
+//==============================================================================
+String::String (const char* const t)
+    : text (StringHolder::createFromCharPointer (CharPointer_ASCII (t)))
+{
+    /*  If you get an assertion here, then you're trying to create a string from 8-bit data
+        that contains values greater than 127. These can NOT be correctly converted to unicode
+        because there's no way for the String class to know what encoding was used to
+        create them. The source data could be UTF-8, ASCII or one of many local code-pages.
+
+        To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
+        string to the String class - so for example if your source data is actually UTF-8,
+        you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
+        correctly convert the multi-byte characters to unicode. It's *highly* recommended that
+        you use UTF-8 with escape characters in your source code to represent extended characters,
+        because there's no other way to represent these strings in a way that isn't dependent on
+        the compiler, source code editor and platform.
+
+        Note that the Introjucer has a handy string literal generator utility that will convert
+        any unicode string to a valid C++ string literal, creating ascii escape sequences that will
+        work in any compiler.
+    */
+    jassert (t == nullptr || CharPointer_ASCII::isValidString (t, std::numeric_limits<int>::max()));
+}
+
+String::String (const char* const t, const size_t maxChars)
+    : text (StringHolder::createFromCharPointer (CharPointer_ASCII (t), maxChars))
+{
+    /*  If you get an assertion here, then you're trying to create a string from 8-bit data
+        that contains values greater than 127. These can NOT be correctly converted to unicode
+        because there's no way for the String class to know what encoding was used to
+        create them. The source data could be UTF-8, ASCII or one of many local code-pages.
+
+        To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
+        string to the String class - so for example if your source data is actually UTF-8,
+        you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
+        correctly convert the multi-byte characters to unicode. It's *highly* recommended that
+        you use UTF-8 with escape characters in your source code to represent extended characters,
+        because there's no other way to represent these strings in a way that isn't dependent on
+        the compiler, source code editor and platform.
+
+        Note that the Introjucer has a handy string literal generator utility that will convert
+        any unicode string to a valid C++ string literal, creating ascii escape sequences that will
+        work in any compiler.
+    */
+    jassert (t == nullptr || CharPointer_ASCII::isValidString (t, (int) maxChars));
+}
+
+String::String (const wchar_t* const t)      : text (StringHolder::createFromCharPointer (castToCharPointer_wchar_t (t))) {}
+String::String (const CharPointer_UTF8  t)   : text (StringHolder::createFromCharPointer (t)) {}
+String::String (const CharPointer_UTF16 t)   : text (StringHolder::createFromCharPointer (t)) {}
+String::String (const CharPointer_UTF32 t)   : text (StringHolder::createFromCharPointer (t)) {}
+String::String (const CharPointer_ASCII t)   : text (StringHolder::createFromCharPointer (t)) {}
+
+String::String (const CharPointer_UTF8  t, const size_t maxChars)   : text (StringHolder::createFromCharPointer (t, maxChars)) {}
+String::String (const CharPointer_UTF16 t, const size_t maxChars)   : text (StringHolder::createFromCharPointer (t, maxChars)) {}
+String::String (const CharPointer_UTF32 t, const size_t maxChars)   : text (StringHolder::createFromCharPointer (t, maxChars)) {}
+String::String (const wchar_t* const t, size_t maxChars)            : text (StringHolder::createFromCharPointer (castToCharPointer_wchar_t (t), maxChars)) {}
+
+String::String (const CharPointer_UTF8  start, const CharPointer_UTF8  end)  : text (StringHolder::createFromCharPointer (start, end)) {}
+String::String (const CharPointer_UTF16 start, const CharPointer_UTF16 end)  : text (StringHolder::createFromCharPointer (start, end)) {}
+String::String (const CharPointer_UTF32 start, const CharPointer_UTF32 end)  : text (StringHolder::createFromCharPointer (start, end)) {}
+
+String::String (const std::string& s) : text (StringHolder::createFromFixedLength (s.data(), s.size())) {}
+
+String String::charToString (const juce_wchar character)
+{
+    String result (PreallocationBytes (CharPointerType::getBytesRequiredFor (character)));
+    CharPointerType t (result.text);
+    t.write (character);
+    t.writeNull();
+    return result;
+}
+
+//==============================================================================
+namespace NumberToStringConverters
+{
+    enum
+    {
+        charsNeededForInt = 32,
+        charsNeededForDouble = 48
+    };
+
+    template <typename Type>
+    static char* printDigits (char* t, Type v) noexcept
+    {
+        *--t = 0;
+
+        do
+        {
+            *--t = '0' + (char) (v % 10);
+            v /= 10;
+
+        } while (v > 0);
+
+        return t;
+    }
+
+    // pass in a pointer to the END of a buffer..
+    static char* numberToString (char* t, const int64 n) noexcept
+    {
+        if (n >= 0)
+            return printDigits (t, static_cast<uint64> (n));
+
+        // NB: this needs to be careful not to call -std::numeric_limits<int64>::min(),
+        // which has undefined behaviour
+        t = printDigits (t, static_cast<uint64> (-(n + 1)) + 1);
+        *--t = '-';
+        return t;
+    }
+
+    static char* numberToString (char* t, uint64 v) noexcept
+    {
+        return printDigits (t, v);
+    }
+
+    static char* numberToString (char* t, const int n) noexcept
+    {
+        if (n >= 0)
+            return printDigits (t, static_cast<unsigned int> (n));
+
+        // NB: this needs to be careful not to call -std::numeric_limits<int>::min(),
+        // which has undefined behaviour
+        t = printDigits (t, static_cast<unsigned int> (-(n + 1)) + 1);
+        *--t = '-';
+        return t;
+    }
+
+    static char* numberToString (char* t, unsigned int v) noexcept
+    {
+        return printDigits (t, v);
+    }
+
+    struct StackArrayStream  : public std::basic_streambuf<char, std::char_traits<char> >
+    {
+        explicit StackArrayStream (char* d)
+        {
+            static const std::locale classicLocale (std::locale::classic());
+            imbue (classicLocale);
+            setp (d, d + charsNeededForDouble);
+        }
+
+        size_t writeDouble (double n, int numDecPlaces)
+        {
+            {
+                std::ostream o (this);
+
+                if (numDecPlaces > 0)
+                    o.precision ((std::streamsize) numDecPlaces);
+
+                o << n;
+            }
+
+            return (size_t) (pptr() - pbase());
+        }
+    };
+
+    static char* doubleToString (char* buffer, const int numChars, double n, int numDecPlaces, size_t& len) noexcept
+    {
+        if (numDecPlaces > 0 && numDecPlaces < 7 && n > -1.0e20 && n < 1.0e20)
+        {
+            char* const end = buffer + numChars;
+            char* t = end;
+            int64 v = (int64) (pow (10.0, numDecPlaces) * std::abs (n) + 0.5);
+            *--t = (char) 0;
+
+            while (numDecPlaces >= 0 || v > 0)
+            {
+                if (numDecPlaces == 0)
+                    *--t = '.';
+
+                *--t = (char) ('0' + (v % 10));
+
+                v /= 10;
+                --numDecPlaces;
+            }
+
+            if (n < 0)
+                *--t = '-';
+
+            len = (size_t) (end - t - 1);
+            return t;
+        }
+
+        StackArrayStream strm (buffer);
+        len = strm.writeDouble (n, numDecPlaces);
+        jassert (len <= charsNeededForDouble);
+        return buffer;
+    }
+
+    template <typename IntegerType>
+    static String::CharPointerType createFromInteger (const IntegerType number)
+    {
+        char buffer [charsNeededForInt];
+        char* const end = buffer + numElementsInArray (buffer);
+        char* const start = numberToString (end, number);
+        return StringHolder::createFromFixedLength (start, (size_t) (end - start - 1));
+    }
+
+    static String::CharPointerType createFromDouble (const double number, const int numberOfDecimalPlaces)
+    {
+        char buffer [charsNeededForDouble];
+        size_t len;
+        char* const start = doubleToString (buffer, numElementsInArray (buffer), (double) number, numberOfDecimalPlaces, len);
+        return StringHolder::createFromFixedLength (start, len);
+    }
+}
+
+//==============================================================================
+String::String (const int number)            : text (NumberToStringConverters::createFromInteger (number)) {}
+String::String (const unsigned int number)   : text (NumberToStringConverters::createFromInteger (number)) {}
+String::String (const short number)          : text (NumberToStringConverters::createFromInteger ((int) number)) {}
+String::String (const unsigned short number) : text (NumberToStringConverters::createFromInteger ((unsigned int) number)) {}
+String::String (const int64  number)         : text (NumberToStringConverters::createFromInteger (number)) {}
+String::String (const uint64 number)         : text (NumberToStringConverters::createFromInteger (number)) {}
+
+String::String (const float  number)         : text (NumberToStringConverters::createFromDouble ((double) number, 0)) {}
+String::String (const double number)         : text (NumberToStringConverters::createFromDouble (number, 0)) {}
+String::String (const float  number, const int numberOfDecimalPlaces)  : text (NumberToStringConverters::createFromDouble ((double) number, numberOfDecimalPlaces)) {}
+String::String (const double number, const int numberOfDecimalPlaces)  : text (NumberToStringConverters::createFromDouble (number, numberOfDecimalPlaces)) {}
+
+//==============================================================================
+int String::length() const noexcept
+{
+    return (int) text.length();
+}
+
+static size_t findByteOffsetOfEnd (String::CharPointerType text) noexcept
+{
+    return (size_t) (((char*) text.findTerminatingNull().getAddress()) - (char*) text.getAddress());
+}
+
+size_t String::getByteOffsetOfEnd() const noexcept
+{
+    return findByteOffsetOfEnd (text);
+}
+
+juce_wchar String::operator[] (int index) const noexcept
+{
+    jassert (index == 0 || (index > 0 && index <= (int) text.lengthUpTo ((size_t) index + 1)));
+    return text [index];
+}
+
+template <typename Type>
+struct HashGenerator
+{
+    template <typename CharPointer>
+    static Type calculate (CharPointer t) noexcept
+    {
+        Type result = Type();
+
+        while (! t.isEmpty())
+            result = ((Type) multiplier) * result + (Type) t.getAndAdvance();
+
+        return result;
+    }
+
+    enum { multiplier = sizeof (Type) > 4 ? 101 : 31 };
+};
+
+int String::hashCode() const noexcept       { return HashGenerator<int>        ::calculate (text); }
+int64 String::hashCode64() const noexcept   { return HashGenerator<int64>      ::calculate (text); }
+std::size_t String::hash() const noexcept   { return HashGenerator<std::size_t>::calculate (text); }
+
+//==============================================================================
+JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const String& s2) noexcept            { return s1.compare (s2) == 0; }
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const String& s2) noexcept            { return s1.compare (s2) != 0; }
+JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const char* s2) noexcept              { return s1.compare (s2) == 0; }
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const char* s2) noexcept              { return s1.compare (s2) != 0; }
+JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const wchar_t* s2) noexcept           { return s1.compare (s2) == 0; }
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const wchar_t* s2) noexcept           { return s1.compare (s2) != 0; }
+JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, StringRef s2) noexcept                { return s1.getCharPointer().compare (s2.text) == 0; }
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, StringRef s2) noexcept                { return s1.getCharPointer().compare (s2.text) != 0; }
+JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF8 s2) noexcept   { return s1.getCharPointer().compare (s2) == 0; }
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF8 s2) noexcept   { return s1.getCharPointer().compare (s2) != 0; }
+JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF16 s2) noexcept  { return s1.getCharPointer().compare (s2) == 0; }
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF16 s2) noexcept  { return s1.getCharPointer().compare (s2) != 0; }
+JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF32 s2) noexcept  { return s1.getCharPointer().compare (s2) == 0; }
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF32 s2) noexcept  { return s1.getCharPointer().compare (s2) != 0; }
+JUCE_API bool JUCE_CALLTYPE operator>  (const String& s1, const String& s2) noexcept            { return s1.compare (s2) > 0; }
+JUCE_API bool JUCE_CALLTYPE operator<  (const String& s1, const String& s2) noexcept            { return s1.compare (s2) < 0; }
+JUCE_API bool JUCE_CALLTYPE operator>= (const String& s1, const String& s2) noexcept            { return s1.compare (s2) >= 0; }
+JUCE_API bool JUCE_CALLTYPE operator<= (const String& s1, const String& s2) noexcept            { return s1.compare (s2) <= 0; }
+
+bool String::equalsIgnoreCase (const wchar_t* const t) const noexcept
+{
+    return t != nullptr ? text.compareIgnoreCase (castToCharPointer_wchar_t (t)) == 0
+                        : isEmpty();
+}
+
+bool String::equalsIgnoreCase (const char* const t) const noexcept
+{
+    return t != nullptr ? text.compareIgnoreCase (CharPointer_UTF8 (t)) == 0
+                        : isEmpty();
+}
+
+bool String::equalsIgnoreCase (StringRef t) const noexcept
+{
+    return text.compareIgnoreCase (t.text) == 0;
+}
+
+bool String::equalsIgnoreCase (const String& other) const noexcept
+{
+    return text == other.text
+            || text.compareIgnoreCase (other.text) == 0;
+}
+
+int String::compare (const String& other) const noexcept           { return (text == other.text) ? 0 : text.compare (other.text); }
+int String::compare (const char* const other) const noexcept       { return text.compare (CharPointer_UTF8 (other)); }
+int String::compare (const wchar_t* const other) const noexcept    { return text.compare (castToCharPointer_wchar_t (other)); }
+int String::compareIgnoreCase (const String& other) const noexcept { return (text == other.text) ? 0 : text.compareIgnoreCase (other.text); }
+
+static int stringCompareRight (String::CharPointerType s1, String::CharPointerType s2) noexcept
+{
+    for (int bias = 0;;)
+    {
+        const juce_wchar c1 = s1.getAndAdvance();
+        const bool isDigit1 = CharacterFunctions::isDigit (c1);
+
+        const juce_wchar c2 = s2.getAndAdvance();
+        const bool isDigit2 = CharacterFunctions::isDigit (c2);
+
+        if (! (isDigit1 || isDigit2))   return bias;
+        if (! isDigit1)                 return -1;
+        if (! isDigit2)                 return 1;
+
+        if (c1 != c2 && bias == 0)
+            bias = c1 < c2 ? -1 : 1;
+
+        jassert (c1 != 0 && c2 != 0);
+    }
+}
+
+static int stringCompareLeft (String::CharPointerType s1, String::CharPointerType s2) noexcept
+{
+    for (;;)
+    {
+        const juce_wchar c1 = s1.getAndAdvance();
+        const bool isDigit1 = CharacterFunctions::isDigit (c1);
+
+        const juce_wchar c2 = s2.getAndAdvance();
+        const bool isDigit2 = CharacterFunctions::isDigit (c2);
+
+        if (! (isDigit1 || isDigit2))   return 0;
+        if (! isDigit1)                 return -1;
+        if (! isDigit2)                 return 1;
+        if (c1 < c2)                    return -1;
+        if (c1 > c2)                    return 1;
+    }
+}
+
+static int naturalStringCompare (String::CharPointerType s1, String::CharPointerType s2) noexcept
+{
+    bool firstLoop = true;
+
+    for (;;)
+    {
+        const bool hasSpace1 = s1.isWhitespace();
+        const bool hasSpace2 = s2.isWhitespace();
+
+        if ((! firstLoop) && (hasSpace1 ^ hasSpace2))
+            return hasSpace2 ? 1 : -1;
+
+        firstLoop = false;
+
+        if (hasSpace1)  s1 = s1.findEndOfWhitespace();
+        if (hasSpace2)  s2 = s2.findEndOfWhitespace();
+
+        if (s1.isDigit() && s2.isDigit())
+        {
+            const int result = (*s1 == '0' || *s2 == '0') ? stringCompareLeft  (s1, s2)
+                                                          : stringCompareRight (s1, s2);
+
+            if (result != 0)
+                return result;
+        }
+
+        juce_wchar c1 = s1.getAndAdvance();
+        juce_wchar c2 = s2.getAndAdvance();
+
+        if (c1 != c2)
+        {
+            c1 = CharacterFunctions::toUpperCase (c1);
+            c2 = CharacterFunctions::toUpperCase (c2);
+        }
+
+        if (c1 == c2)
+        {
+            if (c1 == 0)
+                return 0;
+        }
+        else
+        {
+            const bool isAlphaNum1 = CharacterFunctions::isLetterOrDigit (c1);
+            const bool isAlphaNum2 = CharacterFunctions::isLetterOrDigit (c2);
+
+            if (isAlphaNum2 && ! isAlphaNum1) return -1;
+            if (isAlphaNum1 && ! isAlphaNum2) return 1;
+
+            return c1 < c2 ? -1 : 1;
+        }
+
+        jassert (c1 != 0 && c2 != 0);
+    }
+}
+
+int String::compareNatural (StringRef other) const noexcept
+{
+    return naturalStringCompare (getCharPointer(), other.text);
+}
+
+//==============================================================================
+void String::append (const String& textToAppend, size_t maxCharsToTake)
+{
+    appendCharPointer (textToAppend.text, maxCharsToTake);
+}
+
+void String::appendCharPointer (const CharPointerType textToAppend)
+{
+    appendCharPointer (textToAppend, textToAppend.findTerminatingNull());
+}
+
+void String::appendCharPointer (const CharPointerType startOfTextToAppend,
+                                const CharPointerType endOfTextToAppend)
+{
+    jassert (startOfTextToAppend.getAddress() != nullptr && endOfTextToAppend.getAddress() != nullptr);
+
+    const int extraBytesNeeded = getAddressDifference (endOfTextToAppend.getAddress(),
+                                                       startOfTextToAppend.getAddress());
+    jassert (extraBytesNeeded >= 0);
+
+    if (extraBytesNeeded > 0)
+    {
+        const size_t byteOffsetOfNull = getByteOffsetOfEnd();
+        preallocateBytes (byteOffsetOfNull + (size_t) extraBytesNeeded);
+
+        CharPointerType::CharType* const newStringStart = addBytesToPointer (text.getAddress(), (int) byteOffsetOfNull);
+        memcpy (newStringStart, startOfTextToAppend.getAddress(), (size_t) extraBytesNeeded);
+        CharPointerType (addBytesToPointer (newStringStart, extraBytesNeeded)).writeNull();
+    }
+}
+
+String& String::operator+= (const wchar_t* const t)
+{
+    appendCharPointer (castToCharPointer_wchar_t (t));
+    return *this;
+}
+
+String& String::operator+= (const char* const t)
+{
+    appendCharPointer (CharPointer_UTF8 (t)); // (using UTF8 here triggers a faster code-path than ascii)
+    return *this;
+}
+
+String& String::operator+= (const String& other)
+{
+    if (isEmpty())
+        return operator= (other);
+
+    appendCharPointer (other.text);
+    return *this;
+}
+
+String& String::operator+= (const char ch)
+{
+    const char asString[] = { ch, 0 };
+    return operator+= (asString);
+}
+
+String& String::operator+= (const wchar_t ch)
+{
+    const wchar_t asString[] = { ch, 0 };
+    return operator+= (asString);
+}
+
+#if ! JUCE_NATIVE_WCHAR_IS_UTF32
+String& String::operator+= (const juce_wchar ch)
+{
+    const juce_wchar asString[] = { ch, 0 };
+    appendCharPointer (CharPointer_UTF32 (asString));
+    return *this;
+}
+#endif
+
+String& String::operator+= (const int number)
+{
+    char buffer [16];
+    char* end = buffer + numElementsInArray (buffer);
+    char* start = NumberToStringConverters::numberToString (end, number);
+
+   #if (JUCE_STRING_UTF_TYPE == 8)
+    appendCharPointer (CharPointerType (start), CharPointerType (end));
+   #else
+    appendCharPointer (CharPointer_ASCII (start), CharPointer_ASCII (end));
+   #endif
+    return *this;
+}
+
+String& String::operator+= (int64 number)
+{
+    char buffer [32];
+    char* end = buffer + numElementsInArray (buffer);
+    char* start = NumberToStringConverters::numberToString (end, number);
+
+   #if (JUCE_STRING_UTF_TYPE == 8)
+    appendCharPointer (CharPointerType (start), CharPointerType (end));
+   #else
+    appendCharPointer (CharPointer_ASCII (start), CharPointer_ASCII (end));
+   #endif
+    return *this;
+}
+
+//==============================================================================
+JUCE_API String JUCE_CALLTYPE operator+ (const char* const s1, const String& s2)    { String s (s1); return s += s2; }
+JUCE_API String JUCE_CALLTYPE operator+ (const wchar_t* const s1, const String& s2) { String s (s1); return s += s2; }
+
+JUCE_API String JUCE_CALLTYPE operator+ (const char s1, const String& s2)           { return String::charToString ((juce_wchar) (uint8) s1) + s2; }
+JUCE_API String JUCE_CALLTYPE operator+ (const wchar_t s1, const String& s2)        { return String::charToString (s1) + s2; }
+
+JUCE_API String JUCE_CALLTYPE operator+ (String s1, const String& s2)               { return s1 += s2; }
+JUCE_API String JUCE_CALLTYPE operator+ (String s1, const char* const s2)           { return s1 += s2; }
+JUCE_API String JUCE_CALLTYPE operator+ (String s1, const wchar_t* s2)              { return s1 += s2; }
+
+JUCE_API String JUCE_CALLTYPE operator+ (String s1, const char s2)                  { return s1 += s2; }
+JUCE_API String JUCE_CALLTYPE operator+ (String s1, const wchar_t s2)               { return s1 += s2; }
+
+#if ! JUCE_NATIVE_WCHAR_IS_UTF32
+JUCE_API String JUCE_CALLTYPE operator+ (const juce_wchar s1, const String& s2)     { return String::charToString (s1) + s2; }
+JUCE_API String JUCE_CALLTYPE operator+ (String s1, const juce_wchar s2)            { return s1 += s2; }
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const juce_wchar s2)         { return s1 += s2; }
+#endif
+
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const char s2)               { return s1 += s2; }
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const wchar_t s2)            { return s1 += s2; }
+
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const char* const s2)        { return s1 += s2; }
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const wchar_t* const s2)     { return s1 += s2; }
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const String& s2)            { return s1 += s2; }
+
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const int number)            { return s1 += number; }
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const short number)          { return s1 += (int) number; }
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const long number)           { return s1 += (int) number; }
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const int64 number)          { return s1 += String (number); }
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const float number)          { return s1 += String (number); }
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const double number)         { return s1 += String (number); }
+JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const uint64 number)         { return s1 += String (number); }
+
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const String& text)
+{
+    return operator<< (stream, StringRef (text));
+}
+
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, StringRef text)
+{
+    const size_t numBytes = CharPointer_UTF8::getBytesRequiredFor (text.text);
+
+   #if (JUCE_STRING_UTF_TYPE == 8)
+    stream.write (text.text.getAddress(), numBytes);
+   #else
+    // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
+    // if lots of large, persistent strings were to be written to streams).
+    HeapBlock<char> temp (numBytes + 1);
+    CharPointer_UTF8 (temp).writeAll (text.text);
+    stream.write (temp, numBytes);
+   #endif
+
+    return stream;
+}
+
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const NewLine&)
+{
+    return string1 += NewLine::getDefault();
+}
+
+//==============================================================================
+int String::indexOfChar (const juce_wchar character) const noexcept
+{
+    return text.indexOf (character);
+}
+
+int String::indexOfChar (const int startIndex, const juce_wchar character) const noexcept
+{
+    CharPointerType t (text);
+
+    for (int i = 0; ! t.isEmpty(); ++i)
+    {
+        if (i >= startIndex)
+        {
+            if (t.getAndAdvance() == character)
+                return i;
+        }
+        else
+        {
+            ++t;
+        }
+    }
+
+    return -1;
+}
+
+int String::lastIndexOfChar (const juce_wchar character) const noexcept
+{
+    CharPointerType t (text);
+    int last = -1;
+
+    for (int i = 0; ! t.isEmpty(); ++i)
+        if (t.getAndAdvance() == character)
+            last = i;
+
+    return last;
+}
+
+int String::indexOfAnyOf (StringRef charactersToLookFor, const int startIndex, const bool ignoreCase) const noexcept
+{
+    CharPointerType t (text);
+
+    for (int i = 0; ! t.isEmpty(); ++i)
+    {
+        if (i >= startIndex)
+        {
+            if (charactersToLookFor.text.indexOf (t.getAndAdvance(), ignoreCase) >= 0)
+                return i;
+        }
+        else
+        {
+            ++t;
+        }
+    }
+
+    return -1;
+}
+
+int String::indexOf (StringRef other) const noexcept
+{
+    return other.isEmpty() ? 0 : text.indexOf (other.text);
+}
+
+int String::indexOfIgnoreCase (StringRef other) const noexcept
+{
+    return other.isEmpty() ? 0 : CharacterFunctions::indexOfIgnoreCase (text, other.text);
+}
+
+int String::indexOf (const int startIndex, StringRef other) const noexcept
+{
+    if (other.isEmpty())
+        return -1;
+
+    CharPointerType t (text);
+
+    for (int i = startIndex; --i >= 0;)
+    {
+        if (t.isEmpty())
+            return -1;
+
+        ++t;
+    }
+
+    int found = t.indexOf (other.text);
+    if (found >= 0)
+        found += startIndex;
+    return found;
+}
+
+int String::indexOfIgnoreCase (const int startIndex, StringRef other) const noexcept
+{
+    if (other.isEmpty())
+        return -1;
+
+    CharPointerType t (text);
+
+    for (int i = startIndex; --i >= 0;)
+    {
+        if (t.isEmpty())
+            return -1;
+
+        ++t;
+    }
+
+    int found = CharacterFunctions::indexOfIgnoreCase (t, other.text);
+    if (found >= 0)
+        found += startIndex;
+    return found;
+}
+
+int String::lastIndexOf (StringRef other) const noexcept
+{
+    if (other.isNotEmpty())
+    {
+        const int len = other.length();
+        int i = length() - len;
+
+        if (i >= 0)
+        {
+            for (CharPointerType n (text + i); i >= 0; --i)
+            {
+                if (n.compareUpTo (other.text, len) == 0)
+                    return i;
+
+                --n;
+            }
+        }
+    }
+
+    return -1;
+}
+
+int String::lastIndexOfIgnoreCase (StringRef other) const noexcept
+{
+    if (other.isNotEmpty())
+    {
+        const int len = other.length();
+        int i = length() - len;
+
+        if (i >= 0)
+        {
+            for (CharPointerType n (text + i); i >= 0; --i)
+            {
+                if (n.compareIgnoreCaseUpTo (other.text, len) == 0)
+                    return i;
+
+                --n;
+            }
+        }
+    }
+
+    return -1;
+}
+
+int String::lastIndexOfAnyOf (StringRef charactersToLookFor, const bool ignoreCase) const noexcept
+{
+    CharPointerType t (text);
+    int last = -1;
+
+    for (int i = 0; ! t.isEmpty(); ++i)
+        if (charactersToLookFor.text.indexOf (t.getAndAdvance(), ignoreCase) >= 0)
+            last = i;
+
+    return last;
+}
+
+bool String::contains (StringRef other) const noexcept
+{
+    return indexOf (other) >= 0;
+}
+
+bool String::containsChar (const juce_wchar character) const noexcept
+{
+    return text.indexOf (character) >= 0;
+}
+
+bool String::containsIgnoreCase (StringRef t) const noexcept
+{
+    return indexOfIgnoreCase (t) >= 0;
+}
+
+int String::indexOfWholeWord (StringRef word) const noexcept
+{
+    if (word.isNotEmpty())
+    {
+        CharPointerType t (text);
+        const int wordLen = word.length();
+        const int end = (int) t.length() - wordLen;
+
+        for (int i = 0; i <= end; ++i)
+        {
+            if (t.compareUpTo (word.text, wordLen) == 0
+                  && (i == 0 || ! (t - 1).isLetterOrDigit())
+                  && ! (t + wordLen).isLetterOrDigit())
+                return i;
+
+            ++t;
+        }
+    }
+
+    return -1;
+}
+
+int String::indexOfWholeWordIgnoreCase (StringRef word) const noexcept
+{
+    if (word.isNotEmpty())
+    {
+        CharPointerType t (text);
+        const int wordLen = word.length();
+        const int end = (int) t.length() - wordLen;
+
+        for (int i = 0; i <= end; ++i)
+        {
+            if (t.compareIgnoreCaseUpTo (word.text, wordLen) == 0
+                  && (i == 0 || ! (t - 1).isLetterOrDigit())
+                  && ! (t + wordLen).isLetterOrDigit())
+                return i;
+
+            ++t;
+        }
+    }
+
+    return -1;
+}
+
+bool String::containsWholeWord (StringRef wordToLookFor) const noexcept
+{
+    return indexOfWholeWord (wordToLookFor) >= 0;
+}
+
+bool String::containsWholeWordIgnoreCase (StringRef wordToLookFor) const noexcept
+{
+    return indexOfWholeWordIgnoreCase (wordToLookFor) >= 0;
+}
+
+//==============================================================================
+template <typename CharPointer>
+struct WildCardMatcher
+{
+    static bool matches (CharPointer wildcard, CharPointer test, const bool ignoreCase) noexcept
+    {
+        for (;;)
+        {
+            const juce_wchar wc = wildcard.getAndAdvance();
+
+            if (wc == '*')
+                return wildcard.isEmpty() || matchesAnywhere (wildcard, test, ignoreCase);
+
+            if (! characterMatches (wc, test.getAndAdvance(), ignoreCase))
+                return false;
+
+            if (wc == 0)
+                return true;
+        }
+    }
+
+    static bool characterMatches (const juce_wchar wc, const juce_wchar tc, const bool ignoreCase) noexcept
+    {
+        return (wc == tc) || (wc == '?' && tc != 0)
+                || (ignoreCase && CharacterFunctions::toLowerCase (wc) == CharacterFunctions::toLowerCase (tc));
+    }
+
+    static bool matchesAnywhere (const CharPointer wildcard, CharPointer test, const bool ignoreCase) noexcept
+    {
+        for (; ! test.isEmpty(); ++test)
+            if (matches (wildcard, test, ignoreCase))
+                return true;
+
+        return false;
+    }
+};
+
+bool String::matchesWildcard (StringRef wildcard, const bool ignoreCase) const noexcept
+{
+    return WildCardMatcher<CharPointerType>::matches (wildcard.text, text, ignoreCase);
+}
+
+//==============================================================================
+String String::repeatedString (StringRef stringToRepeat, int numberOfTimesToRepeat)
+{
+    if (numberOfTimesToRepeat <= 0)
+        return String();
+
+    String result (PreallocationBytes (findByteOffsetOfEnd (stringToRepeat) * (size_t) numberOfTimesToRepeat));
+    CharPointerType n (result.text);
+
+    while (--numberOfTimesToRepeat >= 0)
+        n.writeAll (stringToRepeat.text);
+
+    return result;
+}
+
+String String::paddedLeft (const juce_wchar padCharacter, int minimumLength) const
+{
+    jassert (padCharacter != 0);
+
+    int extraChars = minimumLength;
+    CharPointerType end (text);
+
+    while (! end.isEmpty())
+    {
+        --extraChars;
+        ++end;
+    }
+
+    if (extraChars <= 0 || padCharacter == 0)
+        return *this;
+
+    const size_t currentByteSize = (size_t) (((char*) end.getAddress()) - (char*) text.getAddress());
+    String result (PreallocationBytes (currentByteSize + (size_t) extraChars * CharPointerType::getBytesRequiredFor (padCharacter)));
+    CharPointerType n (result.text);
+
+    while (--extraChars >= 0)
+        n.write (padCharacter);
+
+    n.writeAll (text);
+    return result;
+}
+
+String String::paddedRight (const juce_wchar padCharacter, int minimumLength) const
+{
+    jassert (padCharacter != 0);
+
+    int extraChars = minimumLength;
+    CharPointerType end (text);
+
+    while (! end.isEmpty())
+    {
+        --extraChars;
+        ++end;
+    }
+
+    if (extraChars <= 0 || padCharacter == 0)
+        return *this;
+
+    const size_t currentByteSize = (size_t) (((char*) end.getAddress()) - (char*) text.getAddress());
+    String result (PreallocationBytes (currentByteSize + (size_t) extraChars * CharPointerType::getBytesRequiredFor (padCharacter)));
+    CharPointerType n (result.text);
+
+    n.writeAll (text);
+
+    while (--extraChars >= 0)
+        n.write (padCharacter);
+
+    n.writeNull();
+    return result;
+}
+
+//==============================================================================
+String String::replaceSection (int index, int numCharsToReplace, StringRef stringToInsert) const
+{
+    if (index < 0)
+    {
+        // a negative index to replace from?
+        jassertfalse;
+        index = 0;
+    }
+
+    if (numCharsToReplace < 0)
+    {
+        // replacing a negative number of characters?
+        numCharsToReplace = 0;
+        jassertfalse;
+    }
+
+    CharPointerType insertPoint (text);
+
+    for (int i = 0; i < index; ++i)
+    {
+        if (insertPoint.isEmpty())
+        {
+            // replacing beyond the end of the string?
+            jassertfalse;
+            return *this + stringToInsert;
+        }
+
+        ++insertPoint;
+    }
+
+    CharPointerType startOfRemainder (insertPoint);
+
+    for (int i = 0; i < numCharsToReplace && ! startOfRemainder.isEmpty(); ++i)
+        ++startOfRemainder;
+
+    if (insertPoint == text && startOfRemainder.isEmpty())
+        return stringToInsert.text;
+
+    const size_t initialBytes = (size_t) (((char*) insertPoint.getAddress()) - (char*) text.getAddress());
+    const size_t newStringBytes = findByteOffsetOfEnd (stringToInsert);
+    const size_t remainderBytes = (size_t) (((char*) startOfRemainder.findTerminatingNull().getAddress()) - (char*) startOfRemainder.getAddress());
+
+    const size_t newTotalBytes = initialBytes + newStringBytes + remainderBytes;
+    if (newTotalBytes <= 0)
+        return String();
+
+    String result (PreallocationBytes ((size_t) newTotalBytes));
+
+    char* dest = (char*) result.text.getAddress();
+    memcpy (dest, text.getAddress(), initialBytes);
+    dest += initialBytes;
+    memcpy (dest, stringToInsert.text.getAddress(), newStringBytes);
+    dest += newStringBytes;
+    memcpy (dest, startOfRemainder.getAddress(), remainderBytes);
+    dest += remainderBytes;
+    CharPointerType ((CharPointerType::CharType*) dest).writeNull();
+
+    return result;
+}
+
+String String::replace (StringRef stringToReplace, StringRef stringToInsert, const bool ignoreCase) const
+{
+    const int stringToReplaceLen = stringToReplace.length();
+    const int stringToInsertLen = stringToInsert.length();
+
+    int i = 0;
+    String result (*this);
+
+    while ((i = (ignoreCase ? result.indexOfIgnoreCase (i, stringToReplace)
+                            : result.indexOf (i, stringToReplace))) >= 0)
+    {
+        result = result.replaceSection (i, stringToReplaceLen, stringToInsert);
+        i += stringToInsertLen;
+    }
+
+    return result;
+}
+
+class StringCreationHelper
+{
+public:
+    StringCreationHelper (const size_t initialBytes)
+        : source (nullptr), dest (nullptr), allocatedBytes (initialBytes), bytesWritten (0)
+    {
+        result.preallocateBytes (allocatedBytes);
+        dest = result.getCharPointer();
+    }
+
+    StringCreationHelper (const String::CharPointerType s)
+        : source (s), dest (nullptr), allocatedBytes (StringHolder::getAllocatedNumBytes (s)), bytesWritten (0)
+    {
+        result.preallocateBytes (allocatedBytes);
+        dest = result.getCharPointer();
+    }
+
+    void write (juce_wchar c)
+    {
+        bytesWritten += String::CharPointerType::getBytesRequiredFor (c);
+
+        if (bytesWritten > allocatedBytes)
+        {
+            allocatedBytes += jmax ((size_t) 8, allocatedBytes / 16);
+            const size_t destOffset = (size_t) (((char*) dest.getAddress()) - (char*) result.getCharPointer().getAddress());
+            result.preallocateBytes (allocatedBytes);
+            dest = addBytesToPointer (result.getCharPointer().getAddress(), (int) destOffset);
+        }
+
+        dest.write (c);
+    }
+
+    String result;
+    String::CharPointerType source;
+
+private:
+    String::CharPointerType dest;
+    size_t allocatedBytes, bytesWritten;
+};
+
+String String::replaceCharacter (const juce_wchar charToReplace, const juce_wchar charToInsert) const
+{
+    if (! containsChar (charToReplace))
+        return *this;
+
+    StringCreationHelper builder (text);
+
+    for (;;)
+    {
+        juce_wchar c = builder.source.getAndAdvance();
+
+        if (c == charToReplace)
+            c = charToInsert;
+
+        builder.write (c);
+
+        if (c == 0)
+            break;
+    }
+
+    return builder.result;
+}
+
+String String::replaceCharacters (StringRef charactersToReplace, StringRef charactersToInsertInstead) const
+{
+    StringCreationHelper builder (text);
+
+    for (;;)
+    {
+        juce_wchar c = builder.source.getAndAdvance();
+
+        const int index = charactersToReplace.text.indexOf (c);
+        if (index >= 0)
+            c = charactersToInsertInstead [index];
+
+        builder.write (c);
+
+        if (c == 0)
+            break;
+    }
+
+    return builder.result;
+}
+
+//==============================================================================
+bool String::startsWith (StringRef other) const noexcept
+{
+    return text.compareUpTo (other.text, other.length()) == 0;
+}
+
+bool String::startsWithIgnoreCase (StringRef other) const noexcept
+{
+    return text.compareIgnoreCaseUpTo (other.text, other.length()) == 0;
+}
+
+bool String::startsWithChar (const juce_wchar character) const noexcept
+{
+    jassert (character != 0); // strings can't contain a null character!
+
+    return *text == character;
+}
+
+bool String::endsWithChar (const juce_wchar character) const noexcept
+{
+    jassert (character != 0); // strings can't contain a null character!
+
+    if (text.isEmpty())
+        return false;
+
+    CharPointerType t (text.findTerminatingNull());
+    return *--t == character;
+}
+
+bool String::endsWith (StringRef other) const noexcept
+{
+    CharPointerType end (text.findTerminatingNull());
+    CharPointerType otherEnd (other.text.findTerminatingNull());
+
+    while (end > text && otherEnd > other.text)
+    {
+        --end;
+        --otherEnd;
+
+        if (*end != *otherEnd)
+            return false;
+    }
+
+    return otherEnd == other.text;
+}
+
+bool String::endsWithIgnoreCase (StringRef other) const noexcept
+{
+    CharPointerType end (text.findTerminatingNull());
+    CharPointerType otherEnd (other.text.findTerminatingNull());
+
+    while (end > text && otherEnd > other.text)
+    {
+        --end;
+        --otherEnd;
+
+        if (end.toLowerCase() != otherEnd.toLowerCase())
+            return false;
+    }
+
+    return otherEnd == other.text;
+}
+
+//==============================================================================
+String String::toUpperCase() const
+{
+    StringCreationHelper builder (text);
+
+    for (;;)
+    {
+        const juce_wchar c = builder.source.toUpperCase();
+        builder.write (c);
+
+        if (c == 0)
+            break;
+
+        ++(builder.source);
+    }
+
+    return builder.result;
+}
+
+String String::toLowerCase() const
+{
+    StringCreationHelper builder (text);
+
+    for (;;)
+    {
+        const juce_wchar c = builder.source.toLowerCase();
+        builder.write (c);
+
+        if (c == 0)
+            break;
+
+        ++(builder.source);
+    }
+
+    return builder.result;
+}
+
+//==============================================================================
+juce_wchar String::getLastCharacter() const noexcept
+{
+    return isEmpty() ? juce_wchar() : text [length() - 1];
+}
+
+String String::substring (int start, const int end) const
+{
+    if (start < 0)
+        start = 0;
+
+    if (end <= start)
+        return String();
+
+    int i = 0;
+    CharPointerType t1 (text);
+
+    while (i < start)
+    {
+        if (t1.isEmpty())
+            return String();
+
+        ++i;
+        ++t1;
+    }
+
+    CharPointerType t2 (t1);
+    while (i < end)
+    {
+        if (t2.isEmpty())
+        {
+            if (start == 0)
+                return *this;
+
+            break;
+        }
+
+        ++i;
+        ++t2;
+    }
+
+    return String (t1, t2);
+}
+
+String String::substring (int start) const
+{
+    if (start <= 0)
+        return *this;
+
+    CharPointerType t (text);
+
+    while (--start >= 0)
+    {
+        if (t.isEmpty())
+            return String();
+
+        ++t;
+    }
+
+    return String (t);
+}
+
+String String::dropLastCharacters (const int numberToDrop) const
+{
+    return String (text, (size_t) jmax (0, length() - numberToDrop));
+}
+
+String String::getLastCharacters (const int numCharacters) const
+{
+    return String (text + jmax (0, length() - jmax (0, numCharacters)));
+}
+
+String String::fromFirstOccurrenceOf (StringRef sub,
+                                      const bool includeSubString,
+                                      const bool ignoreCase) const
+{
+    const int i = ignoreCase ? indexOfIgnoreCase (sub)
+                             : indexOf (sub);
+    if (i < 0)
+        return String();
+
+    return substring (includeSubString ? i : i + sub.length());
+}
+
+String String::fromLastOccurrenceOf (StringRef sub,
+                                     const bool includeSubString,
+                                     const bool ignoreCase) const
+{
+    const int i = ignoreCase ? lastIndexOfIgnoreCase (sub)
+                             : lastIndexOf (sub);
+    if (i < 0)
+        return *this;
+
+    return substring (includeSubString ? i : i + sub.length());
+}
+
+String String::upToFirstOccurrenceOf (StringRef sub,
+                                      const bool includeSubString,
+                                      const bool ignoreCase) const
+{
+    const int i = ignoreCase ? indexOfIgnoreCase (sub)
+                             : indexOf (sub);
+    if (i < 0)
+        return *this;
+
+    return substring (0, includeSubString ? i + sub.length() : i);
+}
+
+String String::upToLastOccurrenceOf (StringRef sub,
+                                     const bool includeSubString,
+                                     const bool ignoreCase) const
+{
+    const int i = ignoreCase ? lastIndexOfIgnoreCase (sub)
+                             : lastIndexOf (sub);
+    if (i < 0)
+        return *this;
+
+    return substring (0, includeSubString ? i + sub.length() : i);
+}
+
+bool String::isQuotedString() const
+{
+    const String trimmed (trimStart());
+
+    return trimmed[0] == '"'
+        || trimmed[0] == '\'';
+}
+
+String String::unquoted() const
+{
+    const int len = length();
+
+    if (len == 0)
+        return String();
+
+    const juce_wchar lastChar = text [len - 1];
+    const int dropAtStart = (*text == '"' || *text == '\'') ? 1 : 0;
+    const int dropAtEnd = (lastChar == '"' || lastChar == '\'') ? 1 : 0;
+
+    return substring (dropAtStart, len - dropAtEnd);
+}
+
+String String::quoted (const juce_wchar quoteCharacter) const
+{
+    if (isEmpty())
+        return charToString (quoteCharacter) + quoteCharacter;
+
+    String t (*this);
+
+    if (! t.startsWithChar (quoteCharacter))
+        t = charToString (quoteCharacter) + t;
+
+    if (! t.endsWithChar (quoteCharacter))
+        t += quoteCharacter;
+
+    return t;
+}
+
+//==============================================================================
+static String::CharPointerType findTrimmedEnd (const String::CharPointerType start,
+                                               String::CharPointerType end)
+{
+    while (end > start)
+    {
+        if (! (--end).isWhitespace())
+        {
+            ++end;
+            break;
+        }
+    }
+
+    return end;
+}
+
+String String::trim() const
+{
+    if (isNotEmpty())
+    {
+        CharPointerType start (text.findEndOfWhitespace());
+
+        const CharPointerType end (start.findTerminatingNull());
+        CharPointerType trimmedEnd (findTrimmedEnd (start, end));
+
+        if (trimmedEnd <= start)
+            return String();
+
+        if (text < start || trimmedEnd < end)
+            return String (start, trimmedEnd);
+    }
+
+    return *this;
+}
+
+String String::trimStart() const
+{
+    if (isNotEmpty())
+    {
+        const CharPointerType t (text.findEndOfWhitespace());
+
+        if (t != text)
+            return String (t);
+    }
+
+    return *this;
+}
+
+String String::trimEnd() const
+{
+    if (isNotEmpty())
+    {
+        const CharPointerType end (text.findTerminatingNull());
+        CharPointerType trimmedEnd (findTrimmedEnd (text, end));
+
+        if (trimmedEnd < end)
+            return String (text, trimmedEnd);
+    }
+
+    return *this;
+}
+
+String String::trimCharactersAtStart (StringRef charactersToTrim) const
+{
+    CharPointerType t (text);
+
+    while (charactersToTrim.text.indexOf (*t) >= 0)
+        ++t;
+
+    return t == text ? *this : String (t);
+}
+
+String String::trimCharactersAtEnd (StringRef charactersToTrim) const
+{
+    if (isNotEmpty())
+    {
+        const CharPointerType end (text.findTerminatingNull());
+        CharPointerType trimmedEnd (end);
+
+        while (trimmedEnd > text)
+        {
+            if (charactersToTrim.text.indexOf (*--trimmedEnd) < 0)
+            {
+                ++trimmedEnd;
+                break;
+            }
+        }
+
+        if (trimmedEnd < end)
+            return String (text, trimmedEnd);
+    }
+
+    return *this;
+}
+
+//==============================================================================
+String String::retainCharacters (StringRef charactersToRetain) const
+{
+    if (isEmpty())
+        return String();
+
+    StringCreationHelper builder (text);
+
+    for (;;)
+    {
+        juce_wchar c = builder.source.getAndAdvance();
+
+        if (charactersToRetain.text.indexOf (c) >= 0)
+            builder.write (c);
+
+        if (c == 0)
+            break;
+    }
+
+    builder.write (0);
+    return builder.result;
+}
+
+String String::removeCharacters (StringRef charactersToRemove) const
+{
+    if (isEmpty())
+        return String();
+
+    StringCreationHelper builder (text);
+
+    for (;;)
+    {
+        juce_wchar c = builder.source.getAndAdvance();
+
+        if (charactersToRemove.text.indexOf (c) < 0)
+            builder.write (c);
+
+        if (c == 0)
+            break;
+    }
+
+    return builder.result;
+}
+
+String String::initialSectionContainingOnly (StringRef permittedCharacters) const
+{
+    for (CharPointerType t (text); ! t.isEmpty(); ++t)
+        if (permittedCharacters.text.indexOf (*t) < 0)
+            return String (text, t);
+
+    return *this;
+}
+
+String String::initialSectionNotContaining (StringRef charactersToStopAt) const
+{
+    for (CharPointerType t (text); ! t.isEmpty(); ++t)
+        if (charactersToStopAt.text.indexOf (*t) >= 0)
+            return String (text, t);
+
+    return *this;
+}
+
+bool String::containsOnly (StringRef chars) const noexcept
+{
+    for (CharPointerType t (text); ! t.isEmpty();)
+        if (chars.text.indexOf (t.getAndAdvance()) < 0)
+            return false;
+
+    return true;
+}
+
+bool String::containsAnyOf (StringRef chars) const noexcept
+{
+    for (CharPointerType t (text); ! t.isEmpty();)
+        if (chars.text.indexOf (t.getAndAdvance()) >= 0)
+            return true;
+
+    return false;
+}
+
+bool String::containsNonWhitespaceChars() const noexcept
+{
+    for (CharPointerType t (text); ! t.isEmpty(); ++t)
+        if (! t.isWhitespace())
+            return true;
+
+    return false;
+}
+
+// Note! The format parameter here MUST NOT be a reference, otherwise MS's va_start macro fails to work (but still compiles).
+String String::formatted (const String pf, ... )
+{
+    size_t bufferSize = 256;
+
+    for (;;)
+    {
+        va_list args;
+        va_start (args, pf);
+
+       #if JUCE_WINDOWS
+        HeapBlock<wchar_t> temp (bufferSize);
+        const int num = (int) _vsnwprintf (temp.getData(), bufferSize - 1, pf.toWideCharPointer(), args);
+       #elif JUCE_ANDROID
+        HeapBlock<char> temp (bufferSize);
+        const int num = (int) vsnprintf (temp.getData(), bufferSize - 1, pf.toUTF8(), args);
+       #else
+        HeapBlock<wchar_t> temp (bufferSize);
+        const int num = (int) vswprintf (temp.getData(), bufferSize - 1, pf.toWideCharPointer(), args);
+       #endif
+
+        va_end (args);
+
+        if (num > 0)
+            return String (temp);
+
+        bufferSize += 256;
+
+        if (num == 0 || bufferSize > 65536) // the upper limit is a sanity check to avoid situations where vprintf repeatedly
+            break;                          // returns -1 because of an error rather than because it needs more space.
+    }
+
+    return String();
+}
+
+//==============================================================================
+int String::getIntValue() const noexcept            { return text.getIntValue32(); }
+int64 String::getLargeIntValue() const noexcept     { return text.getIntValue64(); }
+float String::getFloatValue() const noexcept        { return (float) getDoubleValue(); }
+double String::getDoubleValue() const noexcept      { return text.getDoubleValue(); }
+
+int String::getTrailingIntValue() const noexcept
+{
+    int n = 0;
+    int mult = 1;
+    CharPointerType t (text.findTerminatingNull());
+
+    while (--t >= text)
+    {
+        if (! t.isDigit())
+        {
+            if (*t == '-')
+                n = -n;
+
+            break;
+        }
+
+        n += mult * (*t - '0');
+        mult *= 10;
+    }
+
+    return n;
+}
+
+static const char hexDigits[] = "0123456789abcdef";
+
+template <typename Type>
+static String hexToString (Type v)
+{
+    String::CharPointerType::CharType buffer[32];
+    String::CharPointerType::CharType* const end = buffer + numElementsInArray (buffer) - 1;
+    String::CharPointerType::CharType* t = end;
+    *t = 0;
+
+    do
+    {
+        *--t = hexDigits [(int) (v & 15)];
+        v >>= 4;
+
+    } while (v != 0);
+
+    return String (String::CharPointerType (t),
+                   String::CharPointerType (end));
+}
+
+String String::toHexString (int number)       { return hexToString ((unsigned int) number); }
+String String::toHexString (int64 number)     { return hexToString ((uint64) number); }
+String String::toHexString (short number)     { return toHexString ((int) (unsigned short) number); }
+
+String String::toHexString (const void* const d, const int size, const int groupSize)
+{
+    if (size <= 0)
+        return String();
+
+    int numChars = (size * 2) + 2;
+    if (groupSize > 0)
+        numChars += size / groupSize;
+
+    String s (PreallocationBytes (sizeof (CharPointerType::CharType) * (size_t) numChars));
+
+    const unsigned char* data = static_cast <const unsigned char*> (d);
+    CharPointerType dest (s.text);
+
+    for (int i = 0; i < size; ++i)
+    {
+        const unsigned char nextByte = *data++;
+        dest.write ((juce_wchar) hexDigits [nextByte >> 4]);
+        dest.write ((juce_wchar) hexDigits [nextByte & 0xf]);
+
+        if (groupSize > 0 && (i % groupSize) == (groupSize - 1) && i < (size - 1))
+            dest.write ((juce_wchar) ' ');
+    }
+
+    dest.writeNull();
+    return s;
+}
+
+int   String::getHexValue32() const noexcept    { return CharacterFunctions::HexParser<int>  ::parse (text); }
+int64 String::getHexValue64() const noexcept    { return CharacterFunctions::HexParser<int64>::parse (text); }
+
+//==============================================================================
+String String::createStringFromData (const void* const unknownData, const int size)
+{
+    const uint8* const data = static_cast<const uint8*> (unknownData);
+
+    if (size <= 0 || data == nullptr)
+        return String();
+
+    if (size == 1)
+        return charToString ((juce_wchar) data[0]);
+
+    if (CharPointer_UTF16::isByteOrderMarkBigEndian (data)
+         || CharPointer_UTF16::isByteOrderMarkLittleEndian (data))
+    {
+        const int numChars = size / 2 - 1;
+
+        StringCreationHelper builder ((size_t) numChars);
+
+        const uint16* const src = (const uint16*) (data + 2);
+
+        if (CharPointer_UTF16::isByteOrderMarkBigEndian (data))
+        {
+            for (int i = 0; i < numChars; ++i)
+                builder.write ((juce_wchar) ByteOrder::swapIfLittleEndian (src[i]));
+        }
+        else
+        {
+            for (int i = 0; i < numChars; ++i)
+                builder.write ((juce_wchar) ByteOrder::swapIfBigEndian (src[i]));
+        }
+
+        builder.write (0);
+        return builder.result;
+    }
+
+    const uint8* start = data;
+
+    if (size >= 3 && CharPointer_UTF8::isByteOrderMark (data))
+        start += 3;
+
+    return String (CharPointer_UTF8 ((const char*) start),
+                   CharPointer_UTF8 ((const char*) (data + size)));
+}
+
+//==============================================================================
+static const juce_wchar emptyChar = 0;
+
+template <class CharPointerType_Src, class CharPointerType_Dest>
+struct StringEncodingConverter
+{
+    static CharPointerType_Dest convert (const String& s)
+    {
+        String& source = const_cast<String&> (s);
+
+        typedef typename CharPointerType_Dest::CharType DestChar;
+
+        if (source.isEmpty())
+            return CharPointerType_Dest (reinterpret_cast<const DestChar*> (&emptyChar));
+
+        CharPointerType_Src text (source.getCharPointer());
+        const size_t extraBytesNeeded = CharPointerType_Dest::getBytesRequiredFor (text) + sizeof (typename CharPointerType_Dest::CharType);
+        const size_t endOffset = (text.sizeInBytes() + 3) & ~3u; // the new string must be word-aligned or many Windows
+                                                                // functions will fail to read it correctly!
+        source.preallocateBytes (endOffset + extraBytesNeeded);
+        text = source.getCharPointer();
+
+        void* const newSpace = addBytesToPointer (text.getAddress(), (int) endOffset);
+        const CharPointerType_Dest extraSpace (static_cast<DestChar*> (newSpace));
+
+       #if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..)
+        const size_t bytesToClear = (size_t) jmin ((int) extraBytesNeeded, 4);
+        zeromem (addBytesToPointer (newSpace, extraBytesNeeded - bytesToClear), bytesToClear);
+       #endif
+
+        CharPointerType_Dest (extraSpace).writeAll (text);
+        return extraSpace;
+    }
+};
+
+template <>
+struct StringEncodingConverter<CharPointer_UTF8, CharPointer_UTF8>
+{
+    static CharPointer_UTF8 convert (const String& source) noexcept   { return CharPointer_UTF8 ((CharPointer_UTF8::CharType*) source.getCharPointer().getAddress()); }
+};
+
+template <>
+struct StringEncodingConverter<CharPointer_UTF16, CharPointer_UTF16>
+{
+    static CharPointer_UTF16 convert (const String& source) noexcept  { return CharPointer_UTF16 ((CharPointer_UTF16::CharType*) source.getCharPointer().getAddress()); }
+};
+
+template <>
+struct StringEncodingConverter<CharPointer_UTF32, CharPointer_UTF32>
+{
+    static CharPointer_UTF32 convert (const String& source) noexcept  { return CharPointer_UTF32 ((CharPointer_UTF32::CharType*) source.getCharPointer().getAddress()); }
+};
+
+CharPointer_UTF8  String::toUTF8()  const { return StringEncodingConverter<CharPointerType, CharPointer_UTF8 >::convert (*this); }
+CharPointer_UTF16 String::toUTF16() const { return StringEncodingConverter<CharPointerType, CharPointer_UTF16>::convert (*this); }
+CharPointer_UTF32 String::toUTF32() const { return StringEncodingConverter<CharPointerType, CharPointer_UTF32>::convert (*this); }
+
+const char* String::toRawUTF8() const
+{
+    return toUTF8().getAddress();
+}
+
+const wchar_t* String::toWideCharPointer() const
+{
+    return StringEncodingConverter<CharPointerType, CharPointer_wchar_t>::convert (*this).getAddress();
+}
+
+std::string String::toStdString() const
+{
+    return std::string (toRawUTF8());
+}
+
+//==============================================================================
+template <class CharPointerType_Src, class CharPointerType_Dest>
+struct StringCopier
+{
+    static size_t copyToBuffer (const CharPointerType_Src source, typename CharPointerType_Dest::CharType* const buffer, const size_t maxBufferSizeBytes)
+    {
+        jassert (((ssize_t) maxBufferSizeBytes) >= 0); // keep this value positive!
+
+        if (buffer == nullptr)
+            return CharPointerType_Dest::getBytesRequiredFor (source) + sizeof (typename CharPointerType_Dest::CharType);
+
+        return CharPointerType_Dest (buffer).writeWithDestByteLimit (source, maxBufferSizeBytes);
+    }
+};
+
+size_t String::copyToUTF8 (CharPointer_UTF8::CharType* const buffer, size_t maxBufferSizeBytes) const noexcept
+{
+    return StringCopier<CharPointerType, CharPointer_UTF8>::copyToBuffer (text, buffer, maxBufferSizeBytes);
+}
+
+size_t String::copyToUTF16 (CharPointer_UTF16::CharType* const buffer, size_t maxBufferSizeBytes) const noexcept
+{
+    return StringCopier<CharPointerType, CharPointer_UTF16>::copyToBuffer (text, buffer, maxBufferSizeBytes);
+}
+
+size_t String::copyToUTF32 (CharPointer_UTF32::CharType* const buffer, size_t maxBufferSizeBytes) const noexcept
+{
+    return StringCopier<CharPointerType, CharPointer_UTF32>::copyToBuffer (text, buffer, maxBufferSizeBytes);
+}
+
+//==============================================================================
+size_t String::getNumBytesAsUTF8() const noexcept
+{
+    return CharPointer_UTF8::getBytesRequiredFor (text);
+}
+
+String String::fromUTF8 (const char* const buffer, int bufferSizeBytes)
+{
+    if (buffer != nullptr)
+    {
+        if (bufferSizeBytes < 0)
+            return String (CharPointer_UTF8 (buffer));
+
+        if (bufferSizeBytes > 0)
+        {
+            jassert (CharPointer_UTF8::isValidString (buffer, bufferSizeBytes));
+            return String (CharPointer_UTF8 (buffer), CharPointer_UTF8 (buffer + bufferSizeBytes));
+        }
+    }
+
+    return String();
+}
+
+#if JUCE_MSVC
+ #pragma warning (pop)
+#endif
+
+//==============================================================================
+StringRef::StringRef() noexcept  : text ((const String::CharPointerType::CharType*) "\0\0\0")
+{
+}
+
+StringRef::StringRef (const char* stringLiteral) noexcept
+   #if JUCE_STRING_UTF_TYPE != 8
+    : text (nullptr), stringCopy (stringLiteral)
+   #else
+    : text (stringLiteral)
+   #endif
+{
+   #if JUCE_STRING_UTF_TYPE != 8
+    text = stringCopy.getCharPointer();
+   #endif
+
+    jassert (stringLiteral != nullptr); // This must be a valid string literal, not a null pointer!!
+
+   #if JUCE_NATIVE_WCHAR_IS_UTF8
+    /*  If you get an assertion here, then you're trying to create a string from 8-bit data
+        that contains values greater than 127. These can NOT be correctly converted to unicode
+        because there's no way for the String class to know what encoding was used to
+        create them. The source data could be UTF-8, ASCII or one of many local code-pages.
+
+        To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
+        string to the StringRef class - so for example if your source data is actually UTF-8,
+        you'd call StringRef (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
+        correctly convert the multi-byte characters to unicode. It's *highly* recommended that
+        you use UTF-8 with escape characters in your source code to represent extended characters,
+        because there's no other way to represent these strings in a way that isn't dependent on
+        the compiler, source code editor and platform.
+    */
+    jassert (CharPointer_ASCII::isValidString (stringLiteral, std::numeric_limits<int>::max()));
+   #endif
+}
+
+StringRef::StringRef (String::CharPointerType stringLiteral) noexcept  : text (stringLiteral)
+{
+    jassert (stringLiteral.getAddress() != nullptr); // This must be a valid string literal, not a null pointer!!
+}
+
+StringRef::StringRef (const String& string) noexcept  : text (string.getCharPointer()) {}
+
+
+//==============================================================================
+//==============================================================================
+#if JUCE_UNIT_TESTS
+
+class StringTests  : public UnitTest
+{
+public:
+    StringTests() : UnitTest ("String class") {}
+
+    template <class CharPointerType>
+    struct TestUTFConversion
+    {
+        static void test (UnitTest& test, Random& r)
+        {
+            String s (createRandomWideCharString (r));
+
+            typename CharPointerType::CharType buffer [300];
+
+            memset (buffer, 0xff, sizeof (buffer));
+            CharPointerType (buffer).writeAll (s.toUTF32());
+            test.expectEquals (String (CharPointerType (buffer)), s);
+
+            memset (buffer, 0xff, sizeof (buffer));
+            CharPointerType (buffer).writeAll (s.toUTF16());
+            test.expectEquals (String (CharPointerType (buffer)), s);
+
+            memset (buffer, 0xff, sizeof (buffer));
+            CharPointerType (buffer).writeAll (s.toUTF8());
+            test.expectEquals (String (CharPointerType (buffer)), s);
+
+            test.expect (CharPointerType::isValidString (buffer, (int) strlen ((const char*) buffer)));
+        }
+    };
+
+    static String createRandomWideCharString (Random& r)
+    {
+        juce_wchar buffer[50] = { 0 };
+
+        for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
+        {
+            if (r.nextBool())
+            {
+                do
+                {
+                    buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
+                }
+                while (! CharPointer_UTF16::canRepresent (buffer[i]));
+            }
+            else
+                buffer[i] = (juce_wchar) (1 + r.nextInt (0xff));
+        }
+
+        return CharPointer_UTF32 (buffer);
+    }
+
+    void runTest()
+    {
+        Random r = getRandom();
+
+        {
+            beginTest ("Basics");
+
+            expect (String().length() == 0);
+            expect (String() == String::empty);
+            String s1, s2 ("abcd");
+            expect (s1.isEmpty() && ! s1.isNotEmpty());
+            expect (s2.isNotEmpty() && ! s2.isEmpty());
+            expect (s2.length() == 4);
+            s1 = "abcd";
+            expect (s2 == s1 && s1 == s2);
+            expect (s1 == "abcd" && s1 == L"abcd");
+            expect (String ("abcd") == String (L"abcd"));
+            expect (String ("abcdefg", 4) == L"abcd");
+            expect (String ("abcdefg", 4) == String (L"abcdefg", 4));
+            expect (String::charToString ('x') == "x");
+            expect (String::charToString (0) == String::empty);
+            expect (s2 + "e" == "abcde" && s2 + 'e' == "abcde");
+            expect (s2 + L'e' == "abcde" && s2 + L"e" == "abcde");
+            expect (s1.equalsIgnoreCase ("abcD") && s1 < "abce" && s1 > "abbb");
+            expect (s1.startsWith ("ab") && s1.startsWith ("abcd") && ! s1.startsWith ("abcde"));
+            expect (s1.startsWithIgnoreCase ("aB") && s1.endsWithIgnoreCase ("CD"));
+            expect (s1.endsWith ("bcd") && ! s1.endsWith ("aabcd"));
+            expectEquals (s1.indexOf (String::empty), 0);
+            expectEquals (s1.indexOfIgnoreCase (String::empty), 0);
+            expect (s1.startsWith (String::empty) && s1.endsWith (String::empty) && s1.contains (String::empty));
+            expect (s1.contains ("cd") && s1.contains ("ab") && s1.contains ("abcd"));
+            expect (s1.containsChar ('a'));
+            expect (! s1.containsChar ('x'));
+            expect (! s1.containsChar (0));
+            expect (String ("abc foo bar").containsWholeWord ("abc") && String ("abc foo bar").containsWholeWord ("abc"));
+        }
+
+        {
+            beginTest ("Operations");
+
+            String s ("012345678");
+            expect (s.hashCode() != 0);
+            expect (s.hashCode64() != 0);
+            expect (s.hashCode() != (s + s).hashCode());
+            expect (s.hashCode64() != (s + s).hashCode64());
+            expect (s.compare (String ("012345678")) == 0);
+            expect (s.compare (String ("012345679")) < 0);
+            expect (s.compare (String ("012345676")) > 0);
+            expect (String("a").compareNatural ("A") == 0);
+            expect (String("A").compareNatural ("B") < 0);
+            expect (String("a").compareNatural ("B") < 0);
+            expect (String("10").compareNatural ("2") > 0);
+            expect (String("Abc 10").compareNatural ("aBC 2") > 0);
+            expect (String("Abc 1").compareNatural ("aBC 2") < 0);
+            expect (s.substring (2, 3) == String::charToString (s[2]));
+            expect (s.substring (0, 1) == String::charToString (s[0]));
+            expect (s.getLastCharacter() == s [s.length() - 1]);
+            expect (String::charToString (s.getLastCharacter()) == s.getLastCharacters (1));
+            expect (s.substring (0, 3) == L"012");
+            expect (s.substring (0, 100) == s);
+            expect (s.substring (-1, 100) == s);
+            expect (s.substring (3) == "345678");
+            expect (s.indexOf (String (L"45")) == 4);
+            expect (String ("444445").indexOf ("45") == 4);
+            expect (String ("444445").lastIndexOfChar ('4') == 4);
+            expect (String ("45454545x").lastIndexOf (String (L"45")) == 6);
+            expect (String ("45454545x").lastIndexOfAnyOf ("456") == 7);
+            expect (String ("45454545x").lastIndexOfAnyOf (String (L"456x")) == 8);
+            expect (String ("abABaBaBa").lastIndexOfIgnoreCase ("aB") == 6);
+            expect (s.indexOfChar (L'4') == 4);
+            expect (s + s == "012345678012345678");
+            expect (s.startsWith (s));
+            expect (s.startsWith (s.substring (0, 4)));
+            expect (s.startsWith (s.dropLastCharacters (4)));
+            expect (s.endsWith (s.substring (5)));
+            expect (s.endsWith (s));
+            expect (s.contains (s.substring (3, 6)));
+            expect (s.contains (s.substring (3)));
+            expect (s.startsWithChar (s[0]));
+            expect (s.endsWithChar (s.getLastCharacter()));
+            expect (s [s.length()] == 0);
+            expect (String ("abcdEFGH").toLowerCase() == String ("abcdefgh"));
+            expect (String ("abcdEFGH").toUpperCase() == String ("ABCDEFGH"));
+
+            String s2 ("123");
+            s2 << ((int) 4) << ((short) 5) << "678" << L"9" << '0';
+            s2 += "xyz";
+            expect (s2 == "1234567890xyz");
+            s2 += (int) 123;
+            expect (s2 == "1234567890xyz123");
+            s2 += (int64) 123;
+            expect (s2 == "1234567890xyz123123");
+
+            beginTest ("Numeric conversions");
+            expect (String::empty.getIntValue() == 0);
+            expect (String::empty.getDoubleValue() == 0.0);
+            expect (String::empty.getFloatValue() == 0.0f);
+            expect (s.getIntValue() == 12345678);
+            expect (s.getLargeIntValue() == (int64) 12345678);
+            expect (s.getDoubleValue() == 12345678.0);
+            expect (s.getFloatValue() == 12345678.0f);
+            expect (String (-1234).getIntValue() == -1234);
+            expect (String ((int64) -1234).getLargeIntValue() == -1234);
+            expect (String (-1234.56).getDoubleValue() == -1234.56);
+            expect (String (-1234.56f).getFloatValue() == -1234.56f);
+            expect (String (std::numeric_limits<int>::max()).getIntValue() == std::numeric_limits<int>::max());
+            expect (String (std::numeric_limits<int>::min()).getIntValue() == std::numeric_limits<int>::min());
+            expect (String (std::numeric_limits<int64>::max()).getLargeIntValue() == std::numeric_limits<int64>::max());
+            expect (String (std::numeric_limits<int64>::min()).getLargeIntValue() == std::numeric_limits<int64>::min());
+            expect (("xyz" + s).getTrailingIntValue() == s.getIntValue());
+            expect (s.getHexValue32() == 0x12345678);
+            expect (s.getHexValue64() == (int64) 0x12345678);
+            expect (String::toHexString (0x1234abcd).equalsIgnoreCase ("1234abcd"));
+            expect (String::toHexString ((int64) 0x1234abcd).equalsIgnoreCase ("1234abcd"));
+            expect (String::toHexString ((short) 0x12ab).equalsIgnoreCase ("12ab"));
+
+            unsigned char data[] = { 1, 2, 3, 4, 0xa, 0xb, 0xc, 0xd };
+            expect (String::toHexString (data, 8, 0).equalsIgnoreCase ("010203040a0b0c0d"));
+            expect (String::toHexString (data, 8, 1).equalsIgnoreCase ("01 02 03 04 0a 0b 0c 0d"));
+            expect (String::toHexString (data, 8, 2).equalsIgnoreCase ("0102 0304 0a0b 0c0d"));
+
+            beginTest ("Subsections");
+            String s3;
+            s3 = "abcdeFGHIJ";
+            expect (s3.equalsIgnoreCase ("ABCdeFGhiJ"));
+            expect (s3.compareIgnoreCase (L"ABCdeFGhiJ") == 0);
+            expect (s3.containsIgnoreCase (s3.substring (3)));
+            expect (s3.indexOfAnyOf ("xyzf", 2, true) == 5);
+            expect (s3.indexOfAnyOf (String (L"xyzf"), 2, false) == -1);
+            expect (s3.indexOfAnyOf ("xyzF", 2, false) == 5);
+            expect (s3.containsAnyOf (String (L"zzzFs")));
+            expect (s3.startsWith ("abcd"));
+            expect (s3.startsWithIgnoreCase (String (L"abCD")));
+            expect (s3.startsWith (String::empty));
+            expect (s3.startsWithChar ('a'));
+            expect (s3.endsWith (String ("HIJ")));
+            expect (s3.endsWithIgnoreCase (String (L"Hij")));
+            expect (s3.endsWith (String::empty));
+            expect (s3.endsWithChar (L'J'));
+            expect (s3.indexOf ("HIJ") == 7);
+            expect (s3.indexOf (String (L"HIJK")) == -1);
+            expect (s3.indexOfIgnoreCase ("hij") == 7);
+            expect (s3.indexOfIgnoreCase (String (L"hijk")) == -1);
+            expect (s3.toStdString() == s3.toRawUTF8());
+
+            String s4 (s3);
+            s4.append (String ("xyz123"), 3);
+            expect (s4 == s3 + "xyz");
+
+            expect (String (1234) < String (1235));
+            expect (String (1235) > String (1234));
+            expect (String (1234) >= String (1234));
+            expect (String (1234) <= String (1234));
+            expect (String (1235) >= String (1234));
+            expect (String (1234) <= String (1235));
+
+            String s5 ("word word2 word3");
+            expect (s5.containsWholeWord (String ("word2")));
+            expect (s5.indexOfWholeWord ("word2") == 5);
+            expect (s5.containsWholeWord (String (L"word")));
+            expect (s5.containsWholeWord ("word3"));
+            expect (s5.containsWholeWord (s5));
+            expect (s5.containsWholeWordIgnoreCase (String (L"Word2")));
+            expect (s5.indexOfWholeWordIgnoreCase ("Word2") == 5);
+            expect (s5.containsWholeWordIgnoreCase (String (L"Word")));
+            expect (s5.containsWholeWordIgnoreCase ("Word3"));
+            expect (! s5.containsWholeWordIgnoreCase (String (L"Wordx")));
+            expect (! s5.containsWholeWordIgnoreCase ("xWord2"));
+            expect (s5.containsNonWhitespaceChars());
+            expect (s5.containsOnly ("ordw23 "));
+            expect (! String (" \n\r\t").containsNonWhitespaceChars());
+
+            expect (s5.matchesWildcard (String (L"wor*"), false));
+            expect (s5.matchesWildcard ("wOr*", true));
+            expect (s5.matchesWildcard (String (L"*word3"), true));
+            expect (s5.matchesWildcard ("*word?", true));
+            expect (s5.matchesWildcard (String (L"Word*3"), true));
+            expect (! s5.matchesWildcard (String (L"*34"), true));
+            expect (String ("xx**y").matchesWildcard ("*y", true));
+            expect (String ("xx**y").matchesWildcard ("x*y", true));
+            expect (String ("xx**y").matchesWildcard ("xx*y", true));
+            expect (String ("xx**y").matchesWildcard ("xx*", true));
+            expect (String ("xx?y").matchesWildcard ("x??y", true));
+            expect (String ("xx?y").matchesWildcard ("xx?y", true));
+            expect (! String ("xx?y").matchesWildcard ("xx?y?", true));
+            expect (String ("xx?y").matchesWildcard ("xx??", true));
+
+            expectEquals (s5.fromFirstOccurrenceOf (String::empty, true, false), s5);
+            expectEquals (s5.fromFirstOccurrenceOf ("xword2", true, false), s5.substring (100));
+            expectEquals (s5.fromFirstOccurrenceOf (String (L"word2"), true, false), s5.substring (5));
+            expectEquals (s5.fromFirstOccurrenceOf ("Word2", true, true), s5.substring (5));
+            expectEquals (s5.fromFirstOccurrenceOf ("word2", false, false), s5.getLastCharacters (6));
+            expectEquals (s5.fromFirstOccurrenceOf ("Word2", false, true), s5.getLastCharacters (6));
+
+            expectEquals (s5.fromLastOccurrenceOf (String::empty, true, false), s5);
+            expectEquals (s5.fromLastOccurrenceOf ("wordx", true, false), s5);
+            expectEquals (s5.fromLastOccurrenceOf ("word", true, false), s5.getLastCharacters (5));
+            expectEquals (s5.fromLastOccurrenceOf ("worD", true, true), s5.getLastCharacters (5));
+            expectEquals (s5.fromLastOccurrenceOf ("word", false, false), s5.getLastCharacters (1));
+            expectEquals (s5.fromLastOccurrenceOf ("worD", false, true), s5.getLastCharacters (1));
+
+            expect (s5.upToFirstOccurrenceOf (String::empty, true, false).isEmpty());
+            expectEquals (s5.upToFirstOccurrenceOf ("word4", true, false), s5);
+            expectEquals (s5.upToFirstOccurrenceOf ("word2", true, false), s5.substring (0, 10));
+            expectEquals (s5.upToFirstOccurrenceOf ("Word2", true, true), s5.substring (0, 10));
+            expectEquals (s5.upToFirstOccurrenceOf ("word2", false, false), s5.substring (0, 5));
+            expectEquals (s5.upToFirstOccurrenceOf ("Word2", false, true), s5.substring (0, 5));
+
+            expectEquals (s5.upToLastOccurrenceOf (String::empty, true, false), s5);
+            expectEquals (s5.upToLastOccurrenceOf ("zword", true, false), s5);
+            expectEquals (s5.upToLastOccurrenceOf ("word", true, false), s5.dropLastCharacters (1));
+            expectEquals (s5.dropLastCharacters(1).upToLastOccurrenceOf ("word", true, false), s5.dropLastCharacters (1));
+            expectEquals (s5.upToLastOccurrenceOf ("Word", true, true), s5.dropLastCharacters (1));
+            expectEquals (s5.upToLastOccurrenceOf ("word", false, false), s5.dropLastCharacters (5));
+            expectEquals (s5.upToLastOccurrenceOf ("Word", false, true), s5.dropLastCharacters (5));
+
+            expectEquals (s5.replace ("word", "xyz", false), String ("xyz xyz2 xyz3"));
+            expect (s5.replace ("Word", "xyz", true) == "xyz xyz2 xyz3");
+            expect (s5.dropLastCharacters (1).replace ("Word", String ("xyz"), true) == L"xyz xyz2 xyz");
+            expect (s5.replace ("Word", "", true) == " 2 3");
+            expectEquals (s5.replace ("Word2", "xyz", true), String ("word xyz word3"));
+            expect (s5.replaceCharacter (L'w', 'x') != s5);
+            expectEquals (s5.replaceCharacter ('w', L'x').replaceCharacter ('x', 'w'), s5);
+            expect (s5.replaceCharacters ("wo", "xy") != s5);
+            expectEquals (s5.replaceCharacters ("wo", "xy").replaceCharacters ("xy", "wo"), s5);
+            expectEquals (s5.retainCharacters ("1wordxya"), String ("wordwordword"));
+            expect (s5.retainCharacters (String::empty).isEmpty());
+            expect (s5.removeCharacters ("1wordxya") == " 2 3");
+            expectEquals (s5.removeCharacters (String::empty), s5);
+            expect (s5.initialSectionContainingOnly ("word") == L"word");
+            expect (String ("word").initialSectionContainingOnly ("word") == L"word");
+            expectEquals (s5.initialSectionNotContaining (String ("xyz ")), String ("word"));
+            expectEquals (s5.initialSectionNotContaining (String (";[:'/")), s5);
+            expect (! s5.isQuotedString());
+            expect (s5.quoted().isQuotedString());
+            expect (! s5.quoted().unquoted().isQuotedString());
+            expect (! String ("x'").isQuotedString());
+            expect (String ("'x").isQuotedString());
+
+            String s6 (" \t xyz  \t\r\n");
+            expectEquals (s6.trim(), String ("xyz"));
+            expect (s6.trim().trim() == "xyz");
+            expectEquals (s5.trim(), s5);
+            expectEquals (s6.trimStart().trimEnd(), s6.trim());
+            expectEquals (s6.trimStart().trimEnd(), s6.trimEnd().trimStart());
+            expectEquals (s6.trimStart().trimStart().trimEnd().trimEnd(), s6.trimEnd().trimStart());
+            expect (s6.trimStart() != s6.trimEnd());
+            expectEquals (("\t\r\n " + s6 + "\t\n \r").trim(), s6.trim());
+            expect (String::repeatedString ("xyz", 3) == L"xyzxyzxyz");
+        }
+
+        {
+            beginTest ("UTF conversions");
+
+            TestUTFConversion <CharPointer_UTF32>::test (*this, r);
+            TestUTFConversion <CharPointer_UTF8>::test (*this, r);
+            TestUTFConversion <CharPointer_UTF16>::test (*this, r);
+        }
+
+        {
+            beginTest ("StringArray");
+
+            StringArray s;
+            s.addTokens ("4,3,2,1,0", ";,", "x");
+            expectEquals (s.size(), 5);
+
+            expectEquals (s.joinIntoString ("-"), String ("4-3-2-1-0"));
+            s.remove (2);
+            expectEquals (s.joinIntoString ("--"), String ("4--3--1--0"));
+            expectEquals (s.joinIntoString (String::empty), String ("4310"));
+            s.clear();
+            expectEquals (s.joinIntoString ("x"), String::empty);
+
+            StringArray toks;
+            toks.addTokens ("x,,", ";,", "");
+            expectEquals (toks.size(), 3);
+            expectEquals (toks.joinIntoString ("-"), String ("x--"));
+            toks.clear();
+
+            toks.addTokens (",x,", ";,", "");
+            expectEquals (toks.size(), 3);
+            expectEquals (toks.joinIntoString ("-"), String ("-x-"));
+            toks.clear();
+
+            toks.addTokens ("x,'y,z',", ";,", "'");
+            expectEquals (toks.size(), 3);
+            expectEquals (toks.joinIntoString ("-"), String ("x-'y,z'-"));
+        }
+
+        {
+            beginTest ("var");
+
+            var v1 = 0;
+            var v2 = 0.1;
+            var v3 = "0.1";
+            var v4 = (int64) 0;
+            var v5 = 0.0;
+            expect (! v2.equals (v1));
+            expect (! v1.equals (v2));
+            expect (v2.equals (v3));
+            expect (v3.equals (v2));
+            expect (! v3.equals (v1));
+            expect (! v1.equals (v3));
+            expect (v1.equals (v4));
+            expect (v4.equals (v1));
+            expect (v5.equals (v4));
+            expect (v4.equals (v5));
+            expect (! v2.equals (v4));
+            expect (! v4.equals (v2));
+        }
+    }
+};
+
+static StringTests stringUnitTests;
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_String.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_String.h
new file mode 100644
index 0000000..4873bd9
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_String.h
@@ -0,0 +1,1370 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_STRING_H_INCLUDED
+#define JUCE_STRING_H_INCLUDED
+
+
+//==============================================================================
+/**
+    The JUCE String class!
+
+    Using a reference-counted internal representation, these strings are fast
+    and efficient, and there are methods to do just about any operation you'll ever
+    dream of.
+
+    @see StringArray, StringPairArray
+*/
+class JUCE_API  String
+{
+public:
+    //==============================================================================
+    /** Creates an empty string.
+        @see empty
+    */
+    String() noexcept;
+
+    /** Creates a copy of another string. */
+    String (const String& other) noexcept;
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    String (String&& other) noexcept;
+   #endif
+
+    /** Creates a string from a zero-terminated ascii text string.
+
+        The string passed-in must not contain any characters with a value above 127, because
+        these can't be converted to unicode without knowing the original encoding that was
+        used to create the string. If you attempt to pass-in values above 127, you'll get an
+        assertion.
+
+        To create strings with extended characters from UTF-8, you should explicitly call
+        String (CharPointer_UTF8 ("my utf8 string..")). It's *highly* recommended that you
+        use UTF-8 with escape characters in your source code to represent extended characters,
+        because there's no other way to represent unicode strings in a way that isn't dependent
+        on the compiler, source code editor and platform.
+    */
+    String (const char* text);
+
+    /** Creates a string from a string of 8-bit ascii characters.
+
+        The string passed-in must not contain any characters with a value above 127, because
+        these can't be converted to unicode without knowing the original encoding that was
+        used to create the string. If you attempt to pass-in values above 127, you'll get an
+        assertion.
+
+        To create strings with extended characters from UTF-8, you should explicitly call
+        String (CharPointer_UTF8 ("my utf8 string..")). It's *highly* recommended that you
+        use UTF-8 with escape characters in your source code to represent extended characters,
+        because there's no other way to represent unicode strings in a way that isn't dependent
+        on the compiler, source code editor and platform.
+
+        This will use up to the first maxChars characters of the string (or less if the string
+        is actually shorter).
+    */
+    String (const char* text, size_t maxChars);
+
+    /** Creates a string from a whcar_t character string.
+        Depending on the platform, this may be treated as either UTF-32 or UTF-16.
+    */
+    String (const wchar_t* text);
+
+    /** Creates a string from a whcar_t character string.
+        Depending on the platform, this may be treated as either UTF-32 or UTF-16.
+    */
+    String (const wchar_t* text, size_t maxChars);
+
+    //==============================================================================
+    /** Creates a string from a UTF-8 character string */
+    String (const CharPointer_UTF8 text);
+
+    /** Creates a string from a UTF-8 character string */
+    String (const CharPointer_UTF8 text, size_t maxChars);
+
+    /** Creates a string from a UTF-8 character string */
+    String (const CharPointer_UTF8 start, const CharPointer_UTF8 end);
+
+    //==============================================================================
+    /** Creates a string from a UTF-16 character string */
+    String (const CharPointer_UTF16 text);
+
+    /** Creates a string from a UTF-16 character string */
+    String (const CharPointer_UTF16 text, size_t maxChars);
+
+    /** Creates a string from a UTF-16 character string */
+    String (const CharPointer_UTF16 start, const CharPointer_UTF16 end);
+
+    //==============================================================================
+    /** Creates a string from a UTF-32 character string */
+    String (const CharPointer_UTF32 text);
+
+    /** Creates a string from a UTF-32 character string */
+    String (const CharPointer_UTF32 text, size_t maxChars);
+
+    /** Creates a string from a UTF-32 character string */
+    String (const CharPointer_UTF32 start, const CharPointer_UTF32 end);
+
+    //==============================================================================
+    /** Creates a string from an ASCII character string */
+    String (const CharPointer_ASCII text);
+
+    /** Creates a string from a UTF-8 encoded std::string. */
+    String (const std::string&);
+
+    //==============================================================================
+    /** Creates a string from a single character. */
+    static String charToString (juce_wchar character);
+
+    /** Destructor. */
+    ~String() noexcept;
+
+    //==============================================================================
+    /** This is an empty string that can be used whenever one is needed.
+
+        It's better to use this than String() because it explains what's going on
+        and is more efficient.
+    */
+    static const String empty;
+
+    /** This is the character encoding type used internally to store the string.
+
+        By setting the value of JUCE_STRING_UTF_TYPE to 8, 16, or 32, you can change the
+        internal storage format of the String class. UTF-8 uses the least space (if your strings
+        contain few extended characters), but call operator[] involves iterating the string to find
+        the required index. UTF-32 provides instant random access to its characters, but uses 4 bytes
+        per character to store them. UTF-16 uses more space than UTF-8 and is also slow to index,
+        but is the native wchar_t format used in Windows.
+
+        It doesn't matter too much which format you pick, because the toUTF8(), toUTF16() and
+        toUTF32() methods let you access the string's content in any of the other formats.
+    */
+   #if (JUCE_STRING_UTF_TYPE == 32)
+    typedef CharPointer_UTF32 CharPointerType;
+   #elif (JUCE_STRING_UTF_TYPE == 16)
+    typedef CharPointer_UTF16 CharPointerType;
+   #elif (DOXYGEN || JUCE_STRING_UTF_TYPE == 8)
+    typedef CharPointer_UTF8  CharPointerType;
+   #else
+    #error "You must set the value of JUCE_STRING_UTF_TYPE to be either 8, 16, or 32!"
+   #endif
+
+    //==============================================================================
+    /** Generates a probably-unique 32-bit hashcode from this string. */
+    int hashCode() const noexcept;
+
+    /** Generates a probably-unique 64-bit hashcode from this string. */
+    int64 hashCode64() const noexcept;
+
+    /** Generates a probably-unique hashcode from this string. */
+    std::size_t hash() const noexcept;
+
+    /** Returns the number of characters in the string. */
+    int length() const noexcept;
+
+    //==============================================================================
+    // Assignment and concatenation operators..
+
+    /** Replaces this string's contents with another string. */
+    String& operator= (const String& other) noexcept;
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    String& operator= (String&& other) noexcept;
+   #endif
+
+    /** Appends another string at the end of this one. */
+    String& operator+= (const String& stringToAppend);
+    /** Appends another string at the end of this one. */
+    String& operator+= (const char* textToAppend);
+    /** Appends another string at the end of this one. */
+    String& operator+= (const wchar_t* textToAppend);
+    /** Appends a decimal number at the end of this string. */
+    String& operator+= (int numberToAppend);
+    /** Appends a decimal number at the end of this string. */
+    String& operator+= (int64 numberToAppend);
+    /** Appends a character at the end of this string. */
+    String& operator+= (char characterToAppend);
+    /** Appends a character at the end of this string. */
+    String& operator+= (wchar_t characterToAppend);
+   #if ! JUCE_NATIVE_WCHAR_IS_UTF32
+    /** Appends a character at the end of this string. */
+    String& operator+= (juce_wchar characterToAppend);
+   #endif
+
+    /** Appends a string to the end of this one.
+
+        @param textToAppend     the string to add
+        @param maxCharsToTake   the maximum number of characters to take from the string passed in
+    */
+    void append (const String& textToAppend, size_t maxCharsToTake);
+
+    /** Appends a string to the end of this one.
+
+        @param startOfTextToAppend  the start of the string to add. This must not be a nullptr
+        @param endOfTextToAppend    the end of the string to add. This must not be a nullptr
+    */
+    void appendCharPointer (const CharPointerType startOfTextToAppend,
+                            const CharPointerType endOfTextToAppend);
+
+    /** Appends a string to the end of this one.
+
+        @param startOfTextToAppend  the start of the string to add. This must not be a nullptr
+        @param endOfTextToAppend    the end of the string to add. This must not be a nullptr
+    */
+    template <class CharPointer>
+    void appendCharPointer (const CharPointer startOfTextToAppend,
+                            const CharPointer endOfTextToAppend)
+    {
+        jassert (startOfTextToAppend.getAddress() != nullptr && endOfTextToAppend.getAddress() != nullptr);
+
+        size_t extraBytesNeeded = 0, numChars = 1;
+
+        for (CharPointer t (startOfTextToAppend); t != endOfTextToAppend && ! t.isEmpty(); ++numChars)
+            extraBytesNeeded += CharPointerType::getBytesRequiredFor (t.getAndAdvance());
+
+        if (extraBytesNeeded > 0)
+        {
+            const size_t byteOffsetOfNull = getByteOffsetOfEnd();
+
+            preallocateBytes (byteOffsetOfNull + extraBytesNeeded);
+            CharPointerType (addBytesToPointer (text.getAddress(), (int) byteOffsetOfNull))
+                .writeWithCharLimit (startOfTextToAppend, (int) numChars);
+        }
+    }
+
+    /** Appends a string to the end of this one. */
+    void appendCharPointer (const CharPointerType textToAppend);
+
+    /** Appends a string to the end of this one.
+
+        @param textToAppend     the string to add
+        @param maxCharsToTake   the maximum number of characters to take from the string passed in
+    */
+    template <class CharPointer>
+    void appendCharPointer (const CharPointer textToAppend, size_t maxCharsToTake)
+    {
+        if (textToAppend.getAddress() != nullptr)
+        {
+            size_t extraBytesNeeded = 0, numChars = 1;
+
+            for (CharPointer t (textToAppend); numChars <= maxCharsToTake && ! t.isEmpty(); ++numChars)
+                extraBytesNeeded += CharPointerType::getBytesRequiredFor (t.getAndAdvance());
+
+            if (extraBytesNeeded > 0)
+            {
+                const size_t byteOffsetOfNull = getByteOffsetOfEnd();
+
+                preallocateBytes (byteOffsetOfNull + extraBytesNeeded);
+                CharPointerType (addBytesToPointer (text.getAddress(), (int) byteOffsetOfNull))
+                    .writeWithCharLimit (textToAppend, (int) numChars);
+            }
+        }
+    }
+
+    /** Appends a string to the end of this one. */
+    template <class CharPointer>
+    void appendCharPointer (const CharPointer textToAppend)
+    {
+        appendCharPointer (textToAppend, std::numeric_limits<size_t>::max());
+    }
+
+    //==============================================================================
+    // Comparison methods..
+
+    /** Returns true if the string contains no characters.
+        Note that there's also an isNotEmpty() method to help write readable code.
+        @see containsNonWhitespaceChars()
+    */
+    inline bool isEmpty() const noexcept                    { return text[0] == 0; }
+
+    /** Returns true if the string contains at least one character.
+        Note that there's also an isEmpty() method to help write readable code.
+        @see containsNonWhitespaceChars()
+    */
+    inline bool isNotEmpty() const noexcept                 { return text[0] != 0; }
+
+    /** Resets this string to be empty. */
+    void clear() noexcept;
+
+    /** Case-insensitive comparison with another string. */
+    bool equalsIgnoreCase (const String& other) const noexcept;
+
+    /** Case-insensitive comparison with another string. */
+    bool equalsIgnoreCase (StringRef other) const noexcept;
+
+    /** Case-insensitive comparison with another string. */
+    bool equalsIgnoreCase (const wchar_t* other) const noexcept;
+
+    /** Case-insensitive comparison with another string. */
+    bool equalsIgnoreCase (const char* other) const noexcept;
+
+    /** Case-sensitive comparison with another string.
+        @returns     0 if the two strings are identical; negative if this string comes before
+                     the other one alphabetically, or positive if it comes after it.
+    */
+    int compare (const String& other) const noexcept;
+
+    /** Case-sensitive comparison with another string.
+        @returns     0 if the two strings are identical; negative if this string comes before
+                     the other one alphabetically, or positive if it comes after it.
+    */
+    int compare (const char* other) const noexcept;
+
+    /** Case-sensitive comparison with another string.
+        @returns     0 if the two strings are identical; negative if this string comes before
+                     the other one alphabetically, or positive if it comes after it.
+    */
+    int compare (const wchar_t* other) const noexcept;
+
+    /** Case-insensitive comparison with another string.
+        @returns     0 if the two strings are identical; negative if this string comes before
+                     the other one alphabetically, or positive if it comes after it.
+    */
+    int compareIgnoreCase (const String& other) const noexcept;
+
+    /** Compares two strings, taking into account textual characteristics like numbers and spaces.
+
+        This comparison is case-insensitive and can detect words and embedded numbers in the
+        strings, making it good for sorting human-readable lists of things like filenames.
+
+        @returns     0 if the two strings are identical; negative if this string comes before
+                     the other one alphabetically, or positive if it comes after it.
+    */
+    int compareNatural (StringRef other) const noexcept;
+
+    /** Tests whether the string begins with another string.
+        If the parameter is an empty string, this will always return true.
+        Uses a case-sensitive comparison.
+    */
+    bool startsWith (StringRef text) const noexcept;
+
+    /** Tests whether the string begins with a particular character.
+        If the character is 0, this will always return false.
+        Uses a case-sensitive comparison.
+    */
+    bool startsWithChar (juce_wchar character) const noexcept;
+
+    /** Tests whether the string begins with another string.
+        If the parameter is an empty string, this will always return true.
+        Uses a case-insensitive comparison.
+    */
+    bool startsWithIgnoreCase (StringRef text) const noexcept;
+
+    /** Tests whether the string ends with another string.
+        If the parameter is an empty string, this will always return true.
+        Uses a case-sensitive comparison.
+    */
+    bool endsWith (StringRef text) const noexcept;
+
+    /** Tests whether the string ends with a particular character.
+        If the character is 0, this will always return false.
+        Uses a case-sensitive comparison.
+    */
+    bool endsWithChar (juce_wchar character) const noexcept;
+
+    /** Tests whether the string ends with another string.
+        If the parameter is an empty string, this will always return true.
+        Uses a case-insensitive comparison.
+    */
+    bool endsWithIgnoreCase (StringRef text) const noexcept;
+
+    /** Tests whether the string contains another substring.
+        If the parameter is an empty string, this will always return true.
+        Uses a case-sensitive comparison.
+    */
+    bool contains (StringRef text) const noexcept;
+
+    /** Tests whether the string contains a particular character.
+        Uses a case-sensitive comparison.
+    */
+    bool containsChar (juce_wchar character) const noexcept;
+
+    /** Tests whether the string contains another substring.
+        Uses a case-insensitive comparison.
+    */
+    bool containsIgnoreCase (StringRef text) const noexcept;
+
+    /** Tests whether the string contains another substring as a distinct word.
+
+        @returns    true if the string contains this word, surrounded by
+                    non-alphanumeric characters
+        @see indexOfWholeWord, containsWholeWordIgnoreCase
+    */
+    bool containsWholeWord (StringRef wordToLookFor) const noexcept;
+
+    /** Tests whether the string contains another substring as a distinct word.
+
+        @returns    true if the string contains this word, surrounded by
+                    non-alphanumeric characters
+        @see indexOfWholeWordIgnoreCase, containsWholeWord
+    */
+    bool containsWholeWordIgnoreCase (StringRef wordToLookFor) const noexcept;
+
+    /** Finds an instance of another substring if it exists as a distinct word.
+
+        @returns    if the string contains this word, surrounded by non-alphanumeric characters,
+                    then this will return the index of the start of the substring. If it isn't
+                    found, then it will return -1
+        @see indexOfWholeWordIgnoreCase, containsWholeWord
+    */
+    int indexOfWholeWord (StringRef wordToLookFor) const noexcept;
+
+    /** Finds an instance of another substring if it exists as a distinct word.
+
+        @returns    if the string contains this word, surrounded by non-alphanumeric characters,
+                    then this will return the index of the start of the substring. If it isn't
+                    found, then it will return -1
+        @see indexOfWholeWord, containsWholeWordIgnoreCase
+    */
+    int indexOfWholeWordIgnoreCase (StringRef wordToLookFor) const noexcept;
+
+    /** Looks for any of a set of characters in the string.
+        Uses a case-sensitive comparison.
+
+        @returns    true if the string contains any of the characters from
+                    the string that is passed in.
+    */
+    bool containsAnyOf (StringRef charactersItMightContain) const noexcept;
+
+    /** Looks for a set of characters in the string.
+        Uses a case-sensitive comparison.
+
+        @returns    Returns false if any of the characters in this string do not occur in
+                    the parameter string. If this string is empty, the return value will
+                    always be true.
+    */
+    bool containsOnly (StringRef charactersItMightContain) const noexcept;
+
+    /** Returns true if this string contains any non-whitespace characters.
+
+        This will return false if the string contains only whitespace characters, or
+        if it's empty.
+
+        It is equivalent to calling "myString.trim().isNotEmpty()".
+    */
+    bool containsNonWhitespaceChars() const noexcept;
+
+    /** Returns true if the string matches this simple wildcard expression.
+
+        So for example String ("abcdef").matchesWildcard ("*DEF", true) would return true.
+
+        This isn't a full-blown regex though! The only wildcard characters supported
+        are "*" and "?". It's mainly intended for filename pattern matching.
+    */
+    bool matchesWildcard (StringRef wildcard, bool ignoreCase) const noexcept;
+
+    //==============================================================================
+    // Substring location methods..
+
+    /** Searches for a character inside this string.
+        Uses a case-sensitive comparison.
+        @returns    the index of the first occurrence of the character in this
+                    string, or -1 if it's not found.
+    */
+    int indexOfChar (juce_wchar characterToLookFor) const noexcept;
+
+    /** Searches for a character inside this string.
+        Uses a case-sensitive comparison.
+        @param startIndex           the index from which the search should proceed
+        @param characterToLookFor   the character to look for
+        @returns            the index of the first occurrence of the character in this
+                            string, or -1 if it's not found.
+    */
+    int indexOfChar (int startIndex, juce_wchar characterToLookFor) const noexcept;
+
+    /** Returns the index of the first character that matches one of the characters
+        passed-in to this method.
+
+        This scans the string, beginning from the startIndex supplied, and if it finds
+        a character that appears in the string charactersToLookFor, it returns its index.
+
+        If none of these characters are found, it returns -1.
+
+        If ignoreCase is true, the comparison will be case-insensitive.
+
+        @see indexOfChar, lastIndexOfAnyOf
+    */
+    int indexOfAnyOf (StringRef charactersToLookFor,
+                      int startIndex = 0,
+                      bool ignoreCase = false) const noexcept;
+
+    /** Searches for a substring within this string.
+        Uses a case-sensitive comparison.
+        @returns    the index of the first occurrence of this substring, or -1 if it's not found.
+                    If textToLookFor is an empty string, this will always return 0.
+    */
+    int indexOf (StringRef textToLookFor) const noexcept;
+
+    /** Searches for a substring within this string.
+        Uses a case-sensitive comparison.
+        @param startIndex       the index from which the search should proceed
+        @param textToLookFor    the string to search for
+        @returns                the index of the first occurrence of this substring, or -1 if it's not found.
+                                If textToLookFor is an empty string, this will always return -1.
+    */
+    int indexOf (int startIndex, StringRef textToLookFor) const noexcept;
+
+    /** Searches for a substring within this string.
+        Uses a case-insensitive comparison.
+        @returns    the index of the first occurrence of this substring, or -1 if it's not found.
+                    If textToLookFor is an empty string, this will always return 0.
+    */
+    int indexOfIgnoreCase (StringRef textToLookFor) const noexcept;
+
+    /** Searches for a substring within this string.
+        Uses a case-insensitive comparison.
+        @param startIndex       the index from which the search should proceed
+        @param textToLookFor    the string to search for
+        @returns                the index of the first occurrence of this substring, or -1 if it's not found.
+                                If textToLookFor is an empty string, this will always return -1.
+    */
+    int indexOfIgnoreCase (int startIndex, StringRef textToLookFor) const noexcept;
+
+    /** Searches for a character inside this string (working backwards from the end of the string).
+        Uses a case-sensitive comparison.
+        @returns    the index of the last occurrence of the character in this string, or -1 if it's not found.
+    */
+    int lastIndexOfChar (juce_wchar character) const noexcept;
+
+    /** Searches for a substring inside this string (working backwards from the end of the string).
+        Uses a case-sensitive comparison.
+        @returns    the index of the start of the last occurrence of the substring within this string,
+                    or -1 if it's not found. If textToLookFor is an empty string, this will always return -1.
+    */
+    int lastIndexOf (StringRef textToLookFor) const noexcept;
+
+    /** Searches for a substring inside this string (working backwards from the end of the string).
+        Uses a case-insensitive comparison.
+        @returns    the index of the start of the last occurrence of the substring within this string, or -1
+                    if it's not found. If textToLookFor is an empty string, this will always return -1.
+    */
+    int lastIndexOfIgnoreCase (StringRef textToLookFor) const noexcept;
+
+    /** Returns the index of the last character in this string that matches one of the
+        characters passed-in to this method.
+
+        This scans the string backwards, starting from its end, and if it finds
+        a character that appears in the string charactersToLookFor, it returns its index.
+
+        If none of these characters are found, it returns -1.
+
+        If ignoreCase is true, the comparison will be case-insensitive.
+
+        @see lastIndexOf, indexOfAnyOf
+    */
+    int lastIndexOfAnyOf (StringRef charactersToLookFor,
+                          bool ignoreCase = false) const noexcept;
+
+
+    //==============================================================================
+    // Substring extraction and manipulation methods..
+
+    /** Returns the character at this index in the string.
+        In a release build, no checks are made to see if the index is within a valid range, so be
+        careful! In a debug build, the index is checked and an assertion fires if it's out-of-range.
+
+        Also beware that depending on the encoding format that the string is using internally, this
+        method may execute in either O(1) or O(n) time, so be careful when using it in your algorithms.
+        If you're scanning through a string to inspect its characters, you should never use this operator
+        for random access, it's far more efficient to call getCharPointer() to return a pointer, and
+        then to use that to iterate the string.
+        @see getCharPointer
+    */
+    juce_wchar operator[] (int index) const noexcept;
+
+    /** Returns the final character of the string.
+        If the string is empty this will return 0.
+    */
+    juce_wchar getLastCharacter() const noexcept;
+
+    //==============================================================================
+    /** Returns a subsection of the string.
+
+        If the range specified is beyond the limits of the string, as much as
+        possible is returned.
+
+        @param startIndex   the index of the start of the substring needed
+        @param endIndex     all characters from startIndex up to (but not including)
+                            this index are returned
+        @see fromFirstOccurrenceOf, dropLastCharacters, getLastCharacters, upToFirstOccurrenceOf
+    */
+    String substring (int startIndex, int endIndex) const;
+
+    /** Returns a section of the string, starting from a given position.
+
+        @param startIndex   the first character to include. If this is beyond the end
+                            of the string, an empty string is returned. If it is zero or
+                            less, the whole string is returned.
+        @returns            the substring from startIndex up to the end of the string
+        @see dropLastCharacters, getLastCharacters, fromFirstOccurrenceOf, upToFirstOccurrenceOf, fromLastOccurrenceOf
+    */
+    String substring (int startIndex) const;
+
+    /** Returns a version of this string with a number of characters removed
+        from the end.
+
+        @param numberToDrop     the number of characters to drop from the end of the
+                                string. If this is greater than the length of the string,
+                                an empty string will be returned. If zero or less, the
+                                original string will be returned.
+        @see substring, fromFirstOccurrenceOf, upToFirstOccurrenceOf, fromLastOccurrenceOf, getLastCharacter
+    */
+    String dropLastCharacters (int numberToDrop) const;
+
+    /** Returns a number of characters from the end of the string.
+
+        This returns the last numCharacters characters from the end of the string. If the
+        string is shorter than numCharacters, the whole string is returned.
+
+        @see substring, dropLastCharacters, getLastCharacter
+    */
+    String getLastCharacters (int numCharacters) const;
+
+    //==============================================================================
+    /** Returns a section of the string starting from a given substring.
+
+        This will search for the first occurrence of the given substring, and
+        return the section of the string starting from the point where this is
+        found (optionally not including the substring itself).
+
+        e.g. for the string "123456", fromFirstOccurrenceOf ("34", true) would return "3456", and
+                                      fromFirstOccurrenceOf ("34", false) would return "56".
+
+        If the substring isn't found, the method will return an empty string.
+
+        If ignoreCase is true, the comparison will be case-insensitive.
+
+        @see upToFirstOccurrenceOf, fromLastOccurrenceOf
+    */
+    String fromFirstOccurrenceOf (StringRef substringToStartFrom,
+                                  bool includeSubStringInResult,
+                                  bool ignoreCase) const;
+
+    /** Returns a section of the string starting from the last occurrence of a given substring.
+
+        Similar to fromFirstOccurrenceOf(), but using the last occurrence of the substring, and
+        unlike fromFirstOccurrenceOf(), if the substring isn't found, this method will
+        return the whole of the original string.
+
+        @see fromFirstOccurrenceOf, upToLastOccurrenceOf
+    */
+    String fromLastOccurrenceOf (StringRef substringToFind,
+                                 bool includeSubStringInResult,
+                                 bool ignoreCase) const;
+
+    /** Returns the start of this string, up to the first occurrence of a substring.
+
+        This will search for the first occurrence of a given substring, and then
+        return a copy of the string, up to the position of this substring,
+        optionally including or excluding the substring itself in the result.
+
+        e.g. for the string "123456", upTo ("34", false) would return "12", and
+                                      upTo ("34", true) would return "1234".
+
+        If the substring isn't found, this will return the whole of the original string.
+
+        @see upToLastOccurrenceOf, fromFirstOccurrenceOf
+    */
+    String upToFirstOccurrenceOf (StringRef substringToEndWith,
+                                  bool includeSubStringInResult,
+                                  bool ignoreCase) const;
+
+    /** Returns the start of this string, up to the last occurrence of a substring.
+
+        Similar to upToFirstOccurrenceOf(), but this finds the last occurrence rather than the first.
+        If the substring isn't found, this will return the whole of the original string.
+
+        @see upToFirstOccurrenceOf, fromFirstOccurrenceOf
+    */
+    String upToLastOccurrenceOf (StringRef substringToFind,
+                                 bool includeSubStringInResult,
+                                 bool ignoreCase) const;
+
+    //==============================================================================
+    /** Returns a copy of this string with any whitespace characters removed from the start and end. */
+    String trim() const;
+
+    /** Returns a copy of this string with any whitespace characters removed from the start. */
+    String trimStart() const;
+
+    /** Returns a copy of this string with any whitespace characters removed from the end. */
+    String trimEnd() const;
+
+    /** Returns a copy of this string, having removed a specified set of characters from its start.
+        Characters are removed from the start of the string until it finds one that is not in the
+        specified set, and then it stops.
+        @param charactersToTrim     the set of characters to remove.
+        @see trim, trimStart, trimCharactersAtEnd
+    */
+    String trimCharactersAtStart (StringRef charactersToTrim) const;
+
+    /** Returns a copy of this string, having removed a specified set of characters from its end.
+        Characters are removed from the end of the string until it finds one that is not in the
+        specified set, and then it stops.
+        @param charactersToTrim     the set of characters to remove.
+        @see trim, trimEnd, trimCharactersAtStart
+    */
+    String trimCharactersAtEnd (StringRef charactersToTrim) const;
+
+    //==============================================================================
+    /** Returns an upper-case version of this string. */
+    String toUpperCase() const;
+
+    /** Returns an lower-case version of this string. */
+    String toLowerCase() const;
+
+    //==============================================================================
+    /** Replaces a sub-section of the string with another string.
+
+        This will return a copy of this string, with a set of characters
+        from startIndex to startIndex + numCharsToReplace removed, and with
+        a new string inserted in their place.
+
+        Note that this is a const method, and won't alter the string itself.
+
+        @param startIndex               the first character to remove. If this is beyond the bounds of the string,
+                                        it will be constrained to a valid range.
+        @param numCharactersToReplace   the number of characters to remove. If zero or less, no
+                                        characters will be taken out.
+        @param stringToInsert           the new string to insert at startIndex after the characters have been
+                                        removed.
+    */
+    String replaceSection (int startIndex,
+                           int numCharactersToReplace,
+                           StringRef stringToInsert) const;
+
+    /** Replaces all occurrences of a substring with another string.
+
+        Returns a copy of this string, with any occurrences of stringToReplace
+        swapped for stringToInsertInstead.
+
+        Note that this is a const method, and won't alter the string itself.
+    */
+    String replace (StringRef stringToReplace,
+                    StringRef stringToInsertInstead,
+                    bool ignoreCase = false) const;
+
+    /** Returns a string with all occurrences of a character replaced with a different one. */
+    String replaceCharacter (juce_wchar characterToReplace,
+                             juce_wchar characterToInsertInstead) const;
+
+    /** Replaces a set of characters with another set.
+
+        Returns a string in which each character from charactersToReplace has been replaced
+        by the character at the equivalent position in newCharacters (so the two strings
+        passed in must be the same length).
+
+        e.g. replaceCharacters ("abc", "def") replaces 'a' with 'd', 'b' with 'e', etc.
+
+        Note that this is a const method, and won't affect the string itself.
+    */
+    String replaceCharacters (StringRef charactersToReplace,
+                              StringRef charactersToInsertInstead) const;
+
+    /** Returns a version of this string that only retains a fixed set of characters.
+
+        This will return a copy of this string, omitting any characters which are not
+        found in the string passed-in.
+
+        e.g. for "1122334455", retainCharacters ("432") would return "223344"
+
+        Note that this is a const method, and won't alter the string itself.
+    */
+    String retainCharacters (StringRef charactersToRetain) const;
+
+    /** Returns a version of this string with a set of characters removed.
+
+        This will return a copy of this string, omitting any characters which are
+        found in the string passed-in.
+
+        e.g. for "1122334455", removeCharacters ("432") would return "1155"
+
+        Note that this is a const method, and won't alter the string itself.
+    */
+    String removeCharacters (StringRef charactersToRemove) const;
+
+    /** Returns a section from the start of the string that only contains a certain set of characters.
+
+        This returns the leftmost section of the string, up to (and not including) the
+        first character that doesn't appear in the string passed in.
+    */
+    String initialSectionContainingOnly (StringRef permittedCharacters) const;
+
+    /** Returns a section from the start of the string that only contains a certain set of characters.
+
+        This returns the leftmost section of the string, up to (and not including) the
+        first character that occurs in the string passed in. (If none of the specified
+        characters are found in the string, the return value will just be the original string).
+    */
+    String initialSectionNotContaining (StringRef charactersToStopAt) const;
+
+    //==============================================================================
+    /** Checks whether the string might be in quotation marks.
+
+        @returns    true if the string begins with a quote character (either a double or single quote).
+                    It is also true if there is whitespace before the quote, but it doesn't check the end of the string.
+        @see unquoted, quoted
+    */
+    bool isQuotedString() const;
+
+    /** Removes quotation marks from around the string, (if there are any).
+
+        Returns a copy of this string with any quotes removed from its ends. Quotes that aren't
+        at the ends of the string are not affected. If there aren't any quotes, the original string
+        is returned.
+
+        Note that this is a const method, and won't alter the string itself.
+
+        @see isQuotedString, quoted
+    */
+    String unquoted() const;
+
+    /** Adds quotation marks around a string.
+
+        This will return a copy of the string with a quote at the start and end, (but won't
+        add the quote if there's already one there, so it's safe to call this on strings that
+        may already have quotes around them).
+
+        Note that this is a const method, and won't alter the string itself.
+
+        @param quoteCharacter   the character to add at the start and end
+        @see isQuotedString, unquoted
+    */
+    String quoted (juce_wchar quoteCharacter = '"') const;
+
+
+    //==============================================================================
+    /** Creates a string which is a version of a string repeated and joined together.
+
+        @param stringToRepeat         the string to repeat
+        @param numberOfTimesToRepeat  how many times to repeat it
+    */
+    static String repeatedString (StringRef stringToRepeat,
+                                  int numberOfTimesToRepeat);
+
+    /** Returns a copy of this string with the specified character repeatedly added to its
+        beginning until the total length is at least the minimum length specified.
+    */
+    String paddedLeft (juce_wchar padCharacter, int minimumLength) const;
+
+    /** Returns a copy of this string with the specified character repeatedly added to its
+        end until the total length is at least the minimum length specified.
+    */
+    String paddedRight (juce_wchar padCharacter, int minimumLength) const;
+
+    /** Creates a string from data in an unknown format.
+
+        This looks at some binary data and tries to guess whether it's Unicode
+        or 8-bit characters, then returns a string that represents it correctly.
+
+        Should be able to handle Unicode endianness correctly, by looking at
+        the first two bytes.
+    */
+    static String createStringFromData (const void* data, int size);
+
+    /** Creates a String from a printf-style parameter list.
+
+        I don't like this method. I don't use it myself, and I recommend avoiding it and
+        using the operator<< methods or pretty much anything else instead. It's only provided
+        here because of the popular unrest that was stirred-up when I tried to remove it...
+
+        If you're really determined to use it, at least make sure that you never, ever,
+        pass any String objects to it as parameters. And bear in mind that internally, depending
+        on the platform, it may be using wchar_t or char character types, so that even string
+        literals can't be safely used as parameters if you're writing portable code.
+    */
+    static String formatted (const String formatString, ... );
+
+    //==============================================================================
+    // Numeric conversions..
+
+    /** Creates a string containing this signed 32-bit integer as a decimal number.
+        @see getIntValue, getFloatValue, getDoubleValue, toHexString
+    */
+    explicit String (int decimalInteger);
+
+    /** Creates a string containing this unsigned 32-bit integer as a decimal number.
+        @see getIntValue, getFloatValue, getDoubleValue, toHexString
+    */
+    explicit String (unsigned int decimalInteger);
+
+    /** Creates a string containing this signed 16-bit integer as a decimal number.
+        @see getIntValue, getFloatValue, getDoubleValue, toHexString
+    */
+    explicit String (short decimalInteger);
+
+    /** Creates a string containing this unsigned 16-bit integer as a decimal number.
+        @see getIntValue, getFloatValue, getDoubleValue, toHexString
+    */
+    explicit String (unsigned short decimalInteger);
+
+    /** Creates a string containing this signed 64-bit integer as a decimal number.
+        @see getLargeIntValue, getFloatValue, getDoubleValue, toHexString
+    */
+    explicit String (int64 largeIntegerValue);
+
+    /** Creates a string containing this unsigned 64-bit integer as a decimal number.
+        @see getLargeIntValue, getFloatValue, getDoubleValue, toHexString
+    */
+    explicit String (uint64 largeIntegerValue);
+
+    /** Creates a string representing this floating-point number.
+        @param floatValue               the value to convert to a string
+        @see getDoubleValue, getIntValue
+    */
+    explicit String (float floatValue);
+
+    /** Creates a string representing this floating-point number.
+        @param doubleValue              the value to convert to a string
+        @see getFloatValue, getIntValue
+    */
+    explicit String (double doubleValue);
+
+    /** Creates a string representing this floating-point number.
+        @param floatValue               the value to convert to a string
+        @param numberOfDecimalPlaces    if this is > 0, it will format the number using that many
+                                        decimal places, and will not use exponent notation. If 0 or
+                                        less, it will use exponent notation if necessary.
+        @see getDoubleValue, getIntValue
+    */
+    String (float floatValue, int numberOfDecimalPlaces);
+
+    /** Creates a string representing this floating-point number.
+        @param doubleValue              the value to convert to a string
+        @param numberOfDecimalPlaces    if this is > 0, it will format the number using that many
+                                        decimal places, and will not use exponent notation. If 0 or
+                                        less, it will use exponent notation if necessary.
+        @see getFloatValue, getIntValue
+    */
+    String (double doubleValue, int numberOfDecimalPlaces);
+
+    /** Reads the value of the string as a decimal number (up to 32 bits in size).
+
+        @returns the value of the string as a 32 bit signed base-10 integer.
+        @see getTrailingIntValue, getHexValue32, getHexValue64
+    */
+    int getIntValue() const noexcept;
+
+    /** Reads the value of the string as a decimal number (up to 64 bits in size).
+        @returns the value of the string as a 64 bit signed base-10 integer.
+    */
+    int64 getLargeIntValue() const noexcept;
+
+    /** Parses a decimal number from the end of the string.
+
+        This will look for a value at the end of the string.
+        e.g. for "321 xyz654" it will return 654; for "2 3 4" it'll return 4.
+
+        Negative numbers are not handled, so "xyz-5" returns 5.
+
+        @see getIntValue
+    */
+    int getTrailingIntValue() const noexcept;
+
+    /** Parses this string as a floating point number.
+
+        @returns    the value of the string as a 32-bit floating point value.
+        @see getDoubleValue
+    */
+    float getFloatValue() const noexcept;
+
+    /** Parses this string as a floating point number.
+
+        @returns    the value of the string as a 64-bit floating point value.
+        @see getFloatValue
+    */
+    double getDoubleValue() const noexcept;
+
+    /** Parses the string as a hexadecimal number.
+
+        Non-hexadecimal characters in the string are ignored.
+
+        If the string contains too many characters, then the lowest significant
+        digits are returned, e.g. "ffff12345678" would produce 0x12345678.
+
+        @returns    a 32-bit number which is the value of the string in hex.
+    */
+    int getHexValue32() const noexcept;
+
+    /** Parses the string as a hexadecimal number.
+
+        Non-hexadecimal characters in the string are ignored.
+
+        If the string contains too many characters, then the lowest significant
+        digits are returned, e.g. "ffff1234567812345678" would produce 0x1234567812345678.
+
+        @returns    a 64-bit number which is the value of the string in hex.
+    */
+    int64 getHexValue64() const noexcept;
+
+    /** Creates a string representing this 32-bit value in hexadecimal. */
+    static String toHexString (int number);
+
+    /** Creates a string representing this 64-bit value in hexadecimal. */
+    static String toHexString (int64 number);
+
+    /** Creates a string representing this 16-bit value in hexadecimal. */
+    static String toHexString (short number);
+
+    /** Creates a string containing a hex dump of a block of binary data.
+
+        @param data         the binary data to use as input
+        @param size         how many bytes of data to use
+        @param groupSize    how many bytes are grouped together before inserting a
+                            space into the output. e.g. group size 0 has no spaces,
+                            group size 1 looks like: "be a1 c2 ff", group size 2 looks
+                            like "bea1 c2ff".
+    */
+    static String toHexString (const void* data, int size, int groupSize = 1);
+
+    //==============================================================================
+    /** Returns the character pointer currently being used to store this string.
+
+        Because it returns a reference to the string's internal data, the pointer
+        that is returned must not be stored anywhere, as it can be deleted whenever the
+        string changes.
+    */
+    inline CharPointerType getCharPointer() const noexcept      { return text; }
+
+    /** Returns a pointer to a UTF-8 version of this string.
+
+        Because it returns a reference to the string's internal data, the pointer
+        that is returned must not be stored anywhere, as it can be deleted whenever the
+        string changes.
+
+        To find out how many bytes you need to store this string as UTF-8, you can call
+        CharPointer_UTF8::getBytesRequiredFor (myString.getCharPointer())
+
+        @see toRawUTF8, getCharPointer, toUTF16, toUTF32
+    */
+    CharPointer_UTF8 toUTF8() const;
+
+    /** Returns a pointer to a UTF-8 version of this string.
+
+        Because it returns a reference to the string's internal data, the pointer
+        that is returned must not be stored anywhere, as it can be deleted whenever the
+        string changes.
+
+        To find out how many bytes you need to store this string as UTF-8, you can call
+        CharPointer_UTF8::getBytesRequiredFor (myString.getCharPointer())
+
+        @see getCharPointer, toUTF8, toUTF16, toUTF32
+    */
+    const char* toRawUTF8() const;
+
+    /** Returns a pointer to a UTF-16 version of this string.
+
+        Because it returns a reference to the string's internal data, the pointer
+        that is returned must not be stored anywhere, as it can be deleted whenever the
+        string changes.
+
+        To find out how many bytes you need to store this string as UTF-16, you can call
+        CharPointer_UTF16::getBytesRequiredFor (myString.getCharPointer())
+
+        @see getCharPointer, toUTF8, toUTF32
+    */
+    CharPointer_UTF16 toUTF16() const;
+
+    /** Returns a pointer to a UTF-32 version of this string.
+
+        Because it returns a reference to the string's internal data, the pointer
+        that is returned must not be stored anywhere, as it can be deleted whenever the
+        string changes.
+
+        @see getCharPointer, toUTF8, toUTF16
+    */
+    CharPointer_UTF32 toUTF32() const;
+
+    /** Returns a pointer to a wchar_t version of this string.
+
+        Because it returns a reference to the string's internal data, the pointer
+        that is returned must not be stored anywhere, as it can be deleted whenever the
+        string changes.
+
+        Bear in mind that the wchar_t type is different on different platforms, so on
+        Windows, this will be equivalent to calling toUTF16(), on unix it'll be the same
+        as calling toUTF32(), etc.
+
+        @see getCharPointer, toUTF8, toUTF16, toUTF32
+    */
+    const wchar_t* toWideCharPointer() const;
+
+    /** */
+    std::string toStdString() const;
+
+    //==============================================================================
+    /** Creates a String from a UTF-8 encoded buffer.
+        If the size is < 0, it'll keep reading until it hits a zero.
+    */
+    static String fromUTF8 (const char* utf8buffer, int bufferSizeBytes = -1);
+
+    /** Returns the number of bytes required to represent this string as UTF8.
+        The number returned does NOT include the trailing zero.
+        @see toUTF8, copyToUTF8
+    */
+    size_t getNumBytesAsUTF8() const noexcept;
+
+    //==============================================================================
+    /** Copies the string to a buffer as UTF-8 characters.
+
+        Returns the number of bytes copied to the buffer, including the terminating null
+        character.
+
+        To find out how many bytes you need to store this string as UTF-8, you can call
+        CharPointer_UTF8::getBytesRequiredFor (myString.getCharPointer())
+
+        @param destBuffer       the place to copy it to; if this is a null pointer, the method just
+                                returns the number of bytes required (including the terminating null character).
+        @param maxBufferSizeBytes  the size of the destination buffer, in bytes. If the string won't fit, it'll
+                                put in as many as it can while still allowing for a terminating null char at the
+                                end, and will return the number of bytes that were actually used.
+        @see CharPointer_UTF8::writeWithDestByteLimit
+    */
+    size_t copyToUTF8 (CharPointer_UTF8::CharType* destBuffer, size_t maxBufferSizeBytes) const noexcept;
+
+    /** Copies the string to a buffer as UTF-16 characters.
+
+        Returns the number of bytes copied to the buffer, including the terminating null
+        character.
+
+        To find out how many bytes you need to store this string as UTF-16, you can call
+        CharPointer_UTF16::getBytesRequiredFor (myString.getCharPointer())
+
+        @param destBuffer       the place to copy it to; if this is a null pointer, the method just
+                                returns the number of bytes required (including the terminating null character).
+        @param maxBufferSizeBytes  the size of the destination buffer, in bytes. If the string won't fit, it'll
+                                put in as many as it can while still allowing for a terminating null char at the
+                                end, and will return the number of bytes that were actually used.
+        @see CharPointer_UTF16::writeWithDestByteLimit
+    */
+    size_t copyToUTF16 (CharPointer_UTF16::CharType* destBuffer, size_t maxBufferSizeBytes) const noexcept;
+
+    /** Copies the string to a buffer as UTF-32 characters.
+
+        Returns the number of bytes copied to the buffer, including the terminating null
+        character.
+
+        To find out how many bytes you need to store this string as UTF-32, you can call
+        CharPointer_UTF32::getBytesRequiredFor (myString.getCharPointer())
+
+        @param destBuffer       the place to copy it to; if this is a null pointer, the method just
+                                returns the number of bytes required (including the terminating null character).
+        @param maxBufferSizeBytes  the size of the destination buffer, in bytes. If the string won't fit, it'll
+                                put in as many as it can while still allowing for a terminating null char at the
+                                end, and will return the number of bytes that were actually used.
+        @see CharPointer_UTF32::writeWithDestByteLimit
+    */
+    size_t copyToUTF32 (CharPointer_UTF32::CharType* destBuffer, size_t maxBufferSizeBytes) const noexcept;
+
+    //==============================================================================
+    /** Increases the string's internally allocated storage.
+
+        Although the string's contents won't be affected by this call, it will
+        increase the amount of memory allocated internally for the string to grow into.
+
+        If you're about to make a large number of calls to methods such
+        as += or <<, it's more efficient to preallocate enough extra space
+        beforehand, so that these methods won't have to keep resizing the string
+        to append the extra characters.
+
+        @param numBytesNeeded   the number of bytes to allocate storage for. If this
+                                value is less than the currently allocated size, it will
+                                have no effect.
+    */
+    void preallocateBytes (size_t numBytesNeeded);
+
+    /** Swaps the contents of this string with another one.
+        This is a very fast operation, as no allocation or copying needs to be done.
+    */
+    void swapWith (String& other) noexcept;
+
+    //==============================================================================
+   #if JUCE_MAC || JUCE_IOS || DOXYGEN
+    /** MAC ONLY - Creates a String from an OSX CFString. */
+    static String fromCFString (CFStringRef cfString);
+
+    /** MAC ONLY - Converts this string to a CFString.
+        Remember that you must use CFRelease() to free the returned string when you're
+        finished with it.
+    */
+    CFStringRef toCFString() const;
+
+    /** MAC ONLY - Returns a copy of this string in which any decomposed unicode characters have
+        been converted to their precomposed equivalents. */
+    String convertToPrecomposedUnicode() const;
+   #endif
+
+    /** Returns the number of String objects which are currently sharing the same internal
+        data as this one.
+    */
+    int getReferenceCount() const noexcept;
+
+private:
+    //==============================================================================
+    CharPointerType text;
+
+    //==============================================================================
+    struct PreallocationBytes
+    {
+        explicit PreallocationBytes (size_t) noexcept;
+        size_t numBytes;
+    };
+
+    explicit String (const PreallocationBytes&); // This constructor preallocates a certain amount of memory
+    size_t getByteOffsetOfEnd() const noexcept;
+    JUCE_DEPRECATED (String (const String&, size_t));
+
+    // This private cast operator should prevent strings being accidentally cast
+    // to bools (this is possible because the compiler can add an implicit cast
+    // via a const char*)
+    operator bool() const noexcept  { return false; }
+};
+
+//==============================================================================
+/** Concatenates two strings. */
+JUCE_API String JUCE_CALLTYPE operator+ (const char* string1,     const String& string2);
+/** Concatenates two strings. */
+JUCE_API String JUCE_CALLTYPE operator+ (const wchar_t* string1,  const String& string2);
+/** Concatenates two strings. */
+JUCE_API String JUCE_CALLTYPE operator+ (char string1,            const String& string2);
+/** Concatenates two strings. */
+JUCE_API String JUCE_CALLTYPE operator+ (wchar_t string1,         const String& string2);
+#if ! JUCE_NATIVE_WCHAR_IS_UTF32
+/** Concatenates two strings. */
+JUCE_API String JUCE_CALLTYPE operator+ (juce_wchar string1,      const String& string2);
+#endif
+
+/** Concatenates two strings. */
+JUCE_API String JUCE_CALLTYPE operator+ (String string1, const String& string2);
+/** Concatenates two strings. */
+JUCE_API String JUCE_CALLTYPE operator+ (String string1, const char* string2);
+/** Concatenates two strings. */
+JUCE_API String JUCE_CALLTYPE operator+ (String string1, const wchar_t* string2);
+/** Concatenates two strings. */
+JUCE_API String JUCE_CALLTYPE operator+ (String string1, char characterToAppend);
+/** Concatenates two strings. */
+JUCE_API String JUCE_CALLTYPE operator+ (String string1, wchar_t characterToAppend);
+#if ! JUCE_NATIVE_WCHAR_IS_UTF32
+/** Concatenates two strings. */
+JUCE_API String JUCE_CALLTYPE operator+ (String string1, juce_wchar characterToAppend);
+#endif
+
+//==============================================================================
+/** Appends a character at the end of a string. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, char characterToAppend);
+/** Appends a character at the end of a string. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, wchar_t characterToAppend);
+#if ! JUCE_NATIVE_WCHAR_IS_UTF32
+/** Appends a character at the end of a string. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, juce_wchar characterToAppend);
+#endif
+
+/** Appends a string to the end of the first one. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const char* string2);
+/** Appends a string to the end of the first one. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const wchar_t* string2);
+/** Appends a string to the end of the first one. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const String& string2);
+
+/** Appends a decimal number at the end of a string. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, short number);
+/** Appends a decimal number at the end of a string. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, int number);
+/** Appends a decimal number at the end of a string. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, long number);
+/** Appends a decimal number at the end of a string. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, int64 number);
+/** Appends a decimal number at the end of a string. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, uint64 number);
+/** Appends a decimal number at the end of a string. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, float number);
+/** Appends a decimal number at the end of a string. */
+JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, double number);
+
+//==============================================================================
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const String& string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const char* string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const wchar_t* string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF8 string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF16 string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF32 string2) noexcept;
+
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const String& string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const char* string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const wchar_t* string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF8 string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF16 string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF32 string2) noexcept;
+
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator>  (const String& string1, const String& string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator<  (const String& string1, const String& string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator>= (const String& string1, const String& string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator<= (const String& string1, const String& string2) noexcept;
+
+//==============================================================================
+/** This operator allows you to write a juce String directly to std output streams.
+    This is handy for writing strings to std::cout, std::cerr, etc.
+*/
+template <class traits>
+std::basic_ostream <char, traits>& JUCE_CALLTYPE operator<< (std::basic_ostream <char, traits>& stream, const String& stringToWrite)
+{
+    return stream << stringToWrite.toRawUTF8();
+}
+
+/** This operator allows you to write a juce String directly to std output streams.
+    This is handy for writing strings to std::wcout, std::wcerr, etc.
+*/
+template <class traits>
+std::basic_ostream <wchar_t, traits>& JUCE_CALLTYPE operator<< (std::basic_ostream <wchar_t, traits>& stream, const String& stringToWrite)
+{
+    return stream << stringToWrite.toWideCharPointer();
+}
+
+/** Writes a string to an OutputStream as UTF8. */
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const String& stringToWrite);
+
+/** Writes a string to an OutputStream as UTF8. */
+JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, StringRef stringToWrite);
+
+
+#endif   // JUCE_STRING_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringArray.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringArray.cpp
new file mode 100644
index 0000000..6c49138
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringArray.cpp
@@ -0,0 +1,485 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+StringArray::StringArray() noexcept
+{
+}
+
+StringArray::StringArray (const StringArray& other)
+    : strings (other.strings)
+{
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+StringArray::StringArray (StringArray&& other) noexcept
+    : strings (static_cast <Array <String>&&> (other.strings))
+{
+}
+#endif
+
+StringArray::StringArray (const String& firstValue)
+{
+    strings.add (firstValue);
+}
+
+StringArray::StringArray (const String* initialStrings, int numberOfStrings)
+{
+    strings.addArray (initialStrings, numberOfStrings);
+}
+
+StringArray::StringArray (const char* const* initialStrings)
+{
+    strings.addNullTerminatedArray (initialStrings);
+}
+
+StringArray::StringArray (const char* const* initialStrings, int numberOfStrings)
+{
+    strings.addArray (initialStrings, numberOfStrings);
+}
+
+StringArray::StringArray (const wchar_t* const* initialStrings)
+{
+    strings.addNullTerminatedArray (initialStrings);
+}
+
+StringArray::StringArray (const wchar_t* const* initialStrings, int numberOfStrings)
+{
+    strings.addArray (initialStrings, numberOfStrings);
+}
+
+StringArray& StringArray::operator= (const StringArray& other)
+{
+    strings = other.strings;
+    return *this;
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+StringArray& StringArray::operator= (StringArray&& other) noexcept
+{
+    strings = static_cast <Array<String>&&> (other.strings);
+    return *this;
+}
+#endif
+
+StringArray::~StringArray()
+{
+}
+
+bool StringArray::operator== (const StringArray& other) const noexcept
+{
+    return strings == other.strings;
+}
+
+bool StringArray::operator!= (const StringArray& other) const noexcept
+{
+    return ! operator== (other);
+}
+
+void StringArray::swapWith (StringArray& other) noexcept
+{
+    strings.swapWith (other.strings);
+}
+
+void StringArray::clear()
+{
+    strings.clear();
+}
+
+void StringArray::clearQuick()
+{
+    strings.clearQuick();
+}
+
+const String& StringArray::operator[] (const int index) const noexcept
+{
+    if (isPositiveAndBelow (index, strings.size()))
+        return strings.getReference (index);
+
+    return String::empty;
+}
+
+String& StringArray::getReference (const int index) noexcept
+{
+    return strings.getReference (index);
+}
+
+void StringArray::add (const String& newString)
+{
+    strings.add (newString);
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+void StringArray::add (String&& stringToAdd)
+{
+    strings.add (static_cast<String&&> (stringToAdd));
+}
+#endif
+
+void StringArray::insert (const int index, const String& newString)
+{
+    strings.insert (index, newString);
+}
+
+void StringArray::addIfNotAlreadyThere (const String& newString, const bool ignoreCase)
+{
+    if (! contains (newString, ignoreCase))
+        add (newString);
+}
+
+void StringArray::addArray (const StringArray& otherArray, int startIndex, int numElementsToAdd)
+{
+    if (startIndex < 0)
+    {
+        jassertfalse;
+        startIndex = 0;
+    }
+
+    if (numElementsToAdd < 0 || startIndex + numElementsToAdd > otherArray.size())
+        numElementsToAdd = otherArray.size() - startIndex;
+
+    while (--numElementsToAdd >= 0)
+        strings.add (otherArray.strings.getReference (startIndex++));
+}
+
+void StringArray::set (const int index, const String& newString)
+{
+    strings.set (index, newString);
+}
+
+bool StringArray::contains (StringRef stringToLookFor, const bool ignoreCase) const
+{
+    return indexOf (stringToLookFor, ignoreCase) >= 0;
+}
+
+int StringArray::indexOf (StringRef stringToLookFor, const bool ignoreCase, int i) const
+{
+    if (i < 0)
+        i = 0;
+
+    const int numElements = size();
+
+    if (ignoreCase)
+    {
+        for (; i < numElements; ++i)
+            if (strings.getReference(i).equalsIgnoreCase (stringToLookFor))
+                return i;
+    }
+    else
+    {
+        for (; i < numElements; ++i)
+            if (stringToLookFor == strings.getReference (i))
+                return i;
+    }
+
+    return -1;
+}
+
+void StringArray::move (const int currentIndex, const int newIndex) noexcept
+{
+    strings.move (currentIndex, newIndex);
+}
+
+//==============================================================================
+void StringArray::remove (const int index)
+{
+    strings.remove (index);
+}
+
+void StringArray::removeString (StringRef stringToRemove, const bool ignoreCase)
+{
+    if (ignoreCase)
+    {
+        for (int i = size(); --i >= 0;)
+            if (strings.getReference(i).equalsIgnoreCase (stringToRemove))
+                strings.remove (i);
+    }
+    else
+    {
+        for (int i = size(); --i >= 0;)
+            if (stringToRemove == strings.getReference (i))
+                strings.remove (i);
+    }
+}
+
+void StringArray::removeRange (int startIndex, int numberToRemove)
+{
+    strings.removeRange (startIndex, numberToRemove);
+}
+
+//==============================================================================
+void StringArray::removeEmptyStrings (const bool removeWhitespaceStrings)
+{
+    if (removeWhitespaceStrings)
+    {
+        for (int i = size(); --i >= 0;)
+            if (! strings.getReference(i).containsNonWhitespaceChars())
+                strings.remove (i);
+    }
+    else
+    {
+        for (int i = size(); --i >= 0;)
+            if (strings.getReference(i).isEmpty())
+                strings.remove (i);
+    }
+}
+
+void StringArray::trim()
+{
+    for (int i = size(); --i >= 0;)
+    {
+        String& s = strings.getReference(i);
+        s = s.trim();
+    }
+}
+
+//==============================================================================
+struct InternalStringArrayComparator_CaseSensitive
+{
+    static int compareElements (String& s1, String& s2) noexcept    { return s1.compare (s2); }
+};
+
+struct InternalStringArrayComparator_CaseInsensitive
+{
+    static int compareElements (String& s1, String& s2) noexcept    { return s1.compareIgnoreCase (s2); }
+};
+
+struct InternalStringArrayComparator_Natural
+{
+    static int compareElements (String& s1, String& s2) noexcept    { return s1.compareNatural (s2); }
+};
+
+void StringArray::sort (const bool ignoreCase)
+{
+    if (ignoreCase)
+    {
+        InternalStringArrayComparator_CaseInsensitive comp;
+        strings.sort (comp);
+    }
+    else
+    {
+        InternalStringArrayComparator_CaseSensitive comp;
+        strings.sort (comp);
+    }
+}
+
+void StringArray::sortNatural()
+{
+    InternalStringArrayComparator_Natural comp;
+    strings.sort (comp);
+}
+
+//==============================================================================
+String StringArray::joinIntoString (StringRef separator, int start, int numberToJoin) const
+{
+    const int last = (numberToJoin < 0) ? size()
+                                        : jmin (size(), start + numberToJoin);
+
+    if (start < 0)
+        start = 0;
+
+    if (start >= last)
+        return String();
+
+    if (start == last - 1)
+        return strings.getReference (start);
+
+    const size_t separatorBytes = separator.text.sizeInBytes() - sizeof (String::CharPointerType::CharType);
+    size_t bytesNeeded = separatorBytes * (size_t) (last - start - 1);
+
+    for (int i = start; i < last; ++i)
+        bytesNeeded += strings.getReference(i).getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType);
+
+    String result;
+    result.preallocateBytes (bytesNeeded);
+
+    String::CharPointerType dest (result.getCharPointer());
+
+    while (start < last)
+    {
+        const String& s = strings.getReference (start);
+
+        if (! s.isEmpty())
+            dest.writeAll (s.getCharPointer());
+
+        if (++start < last && separatorBytes > 0)
+            dest.writeAll (separator.text);
+    }
+
+    dest.writeNull();
+
+    return result;
+}
+
+int StringArray::addTokens (StringRef text, const bool preserveQuotedStrings)
+{
+    return addTokens (text, " \n\r\t", preserveQuotedStrings ? "\"" : "");
+}
+
+int StringArray::addTokens (StringRef text, StringRef breakCharacters, StringRef quoteCharacters)
+{
+    int num = 0;
+
+    if (text.isNotEmpty())
+    {
+        for (String::CharPointerType t (text.text);;)
+        {
+            String::CharPointerType tokenEnd (CharacterFunctions::findEndOfToken (t,
+                                                                                  breakCharacters.text,
+                                                                                  quoteCharacters.text));
+            strings.add (String (t, tokenEnd));
+            ++num;
+
+            if (tokenEnd.isEmpty())
+                break;
+
+            t = ++tokenEnd;
+        }
+    }
+
+    return num;
+}
+
+int StringArray::addLines (StringRef sourceText)
+{
+    int numLines = 0;
+    String::CharPointerType text (sourceText.text);
+    bool finished = text.isEmpty();
+
+    while (! finished)
+    {
+        for (String::CharPointerType startOfLine (text);;)
+        {
+            const String::CharPointerType endOfLine (text);
+
+            switch (text.getAndAdvance())
+            {
+                case 0:     finished = true; break;
+                case '\n':  break;
+                case '\r':  if (*text == '\n') ++text; break;
+                default:    continue;
+            }
+
+            strings.add (String (startOfLine, endOfLine));
+            ++numLines;
+            break;
+        }
+    }
+
+    return numLines;
+}
+
+StringArray StringArray::fromTokens (StringRef stringToTokenise, bool preserveQuotedStrings)
+{
+    StringArray s;
+    s.addTokens (stringToTokenise, preserveQuotedStrings);
+    return s;
+}
+
+StringArray StringArray::fromTokens (StringRef stringToTokenise,
+                                     StringRef breakCharacters,
+                                     StringRef quoteCharacters)
+{
+    StringArray s;
+    s.addTokens (stringToTokenise, breakCharacters, quoteCharacters);
+    return s;
+}
+
+StringArray StringArray::fromLines (StringRef stringToBreakUp)
+{
+    StringArray s;
+    s.addLines (stringToBreakUp);
+    return s;
+}
+
+//==============================================================================
+void StringArray::removeDuplicates (const bool ignoreCase)
+{
+    for (int i = 0; i < size() - 1; ++i)
+    {
+        const String s (strings.getReference(i));
+
+        for (int nextIndex = i + 1;;)
+        {
+            nextIndex = indexOf (s, ignoreCase, nextIndex);
+
+            if (nextIndex < 0)
+                break;
+
+            strings.remove (nextIndex);
+        }
+    }
+}
+
+void StringArray::appendNumbersToDuplicates (const bool ignoreCase,
+                                             const bool appendNumberToFirstInstance,
+                                             CharPointer_UTF8 preNumberString,
+                                             CharPointer_UTF8 postNumberString)
+{
+    CharPointer_UTF8 defaultPre (" ("), defaultPost (")");
+
+    if (preNumberString.getAddress() == nullptr)
+        preNumberString = defaultPre;
+
+    if (postNumberString.getAddress() == nullptr)
+        postNumberString = defaultPost;
+
+    for (int i = 0; i < size() - 1; ++i)
+    {
+        String& s = strings.getReference(i);
+
+        int nextIndex = indexOf (s, ignoreCase, i + 1);
+
+        if (nextIndex >= 0)
+        {
+            const String original (s);
+
+            int number = 0;
+
+            if (appendNumberToFirstInstance)
+                s = original + String (preNumberString) + String (++number) + String (postNumberString);
+            else
+                ++number;
+
+            while (nextIndex >= 0)
+            {
+                set (nextIndex, (*this)[nextIndex] + String (preNumberString) + String (++number) + String (postNumberString));
+                nextIndex = indexOf (original, ignoreCase, nextIndex + 1);
+            }
+        }
+    }
+}
+
+void StringArray::ensureStorageAllocated (int minNumElements)
+{
+    strings.ensureStorageAllocated (minNumElements);
+}
+
+void StringArray::minimiseStorageOverheads()
+{
+    strings.minimiseStorageOverheads();
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringArray.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringArray.h
new file mode 100644
index 0000000..52335e1
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringArray.h
@@ -0,0 +1,421 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_STRINGARRAY_H_INCLUDED
+#define JUCE_STRINGARRAY_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A special array for holding a list of strings.
+
+    @see String, StringPairArray
+*/
+class JUCE_API  StringArray
+{
+public:
+    //==============================================================================
+    /** Creates an empty string array */
+    StringArray() noexcept;
+
+    /** Creates a copy of another string array */
+    StringArray (const StringArray&);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    StringArray (StringArray&&) noexcept;
+   #endif
+
+    /** Creates an array containing a single string. */
+    explicit StringArray (const String& firstValue);
+
+    /** Creates an array from a raw array of strings.
+        @param strings          an array of strings to add
+        @param numberOfStrings  how many items there are in the array
+    */
+    StringArray (const String* strings, int numberOfStrings);
+
+    /** Creates a copy of an array of string literals.
+        @param strings          an array of strings to add. Null pointers in the array will be
+                                treated as empty strings
+        @param numberOfStrings  how many items there are in the array
+    */
+    StringArray (const char* const* strings, int numberOfStrings);
+
+    /** Creates a copy of a null-terminated array of string literals.
+
+        Each item from the array passed-in is added, until it encounters a null pointer,
+        at which point it stops.
+    */
+    explicit StringArray (const char* const* strings);
+
+    /** Creates a copy of a null-terminated array of string literals.
+        Each item from the array passed-in is added, until it encounters a null pointer,
+        at which point it stops.
+    */
+    explicit StringArray (const wchar_t* const* strings);
+
+    /** Creates a copy of an array of string literals.
+        @param strings          an array of strings to add. Null pointers in the array will be
+                                treated as empty strings
+        @param numberOfStrings  how many items there are in the array
+    */
+    StringArray (const wchar_t* const* strings, int numberOfStrings);
+
+    /** Destructor. */
+    ~StringArray();
+
+    /** Copies the contents of another string array into this one */
+    StringArray& operator= (const StringArray&);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    StringArray& operator= (StringArray&&) noexcept;
+   #endif
+
+    /** Swaps the contents of this and another StringArray. */
+    void swapWith (StringArray&) noexcept;
+
+    //==============================================================================
+    /** Compares two arrays.
+        Comparisons are case-sensitive.
+        @returns    true only if the other array contains exactly the same strings in the same order
+    */
+    bool operator== (const StringArray&) const noexcept;
+
+    /** Compares two arrays.
+        Comparisons are case-sensitive.
+        @returns    false if the other array contains exactly the same strings in the same order
+    */
+    bool operator!= (const StringArray&) const noexcept;
+
+    //==============================================================================
+    /** Returns the number of strings in the array */
+    inline int size() const noexcept                                    { return strings.size(); };
+
+    /** Returns one of the strings from the array.
+
+        If the index is out-of-range, an empty string is returned.
+
+        Obviously the reference returned shouldn't be stored for later use, as the
+        string it refers to may disappear when the array changes.
+    */
+    const String& operator[] (int index) const noexcept;
+
+    /** Returns a reference to one of the strings in the array.
+        This lets you modify a string in-place in the array, but you must be sure that
+        the index is in-range.
+    */
+    String& getReference (int index) noexcept;
+
+    /** Returns a pointer to the first String in the array.
+        This method is provided for compatibility with standard C++ iteration mechanisms.
+    */
+    inline String* begin() const noexcept       { return strings.begin(); }
+
+    /** Returns a pointer to the String which follows the last element in the array.
+        This method is provided for compatibility with standard C++ iteration mechanisms.
+    */
+    inline String* end() const noexcept         { return strings.end(); }
+
+    /** Searches for a string in the array.
+
+        The comparison will be case-insensitive if the ignoreCase parameter is true.
+
+        @returns    true if the string is found inside the array
+    */
+    bool contains (StringRef stringToLookFor,
+                   bool ignoreCase = false) const;
+
+    /** Searches for a string in the array.
+
+        The comparison will be case-insensitive if the ignoreCase parameter is true.
+
+        @param stringToLookFor  the string to try to find
+        @param ignoreCase       whether the comparison should be case-insensitive
+        @param startIndex       the first index to start searching from
+        @returns                the index of the first occurrence of the string in this array,
+                                or -1 if it isn't found.
+    */
+    int indexOf (StringRef stringToLookFor,
+                 bool ignoreCase = false,
+                 int startIndex = 0) const;
+
+    //==============================================================================
+    /** Appends a string at the end of the array. */
+    void add (const String& stringToAdd);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    /** Appends a string at the end of the array. */
+    void add (String&& stringToAdd);
+   #endif
+
+    /** Inserts a string into the array.
+
+        This will insert a string into the array at the given index, moving
+        up the other elements to make room for it.
+        If the index is less than zero or greater than the size of the array,
+        the new string will be added to the end of the array.
+    */
+    void insert (int index, const String& stringToAdd);
+
+    /** Adds a string to the array as long as it's not already in there.
+        The search can optionally be case-insensitive.
+    */
+    void addIfNotAlreadyThere (const String& stringToAdd, bool ignoreCase = false);
+
+    /** Replaces one of the strings in the array with another one.
+
+        If the index is higher than the array's size, the new string will be
+        added to the end of the array; if it's less than zero nothing happens.
+    */
+    void set (int index, const String& newString);
+
+    /** Appends some strings from another array to the end of this one.
+
+        @param other                the array to add
+        @param startIndex           the first element of the other array to add
+        @param numElementsToAdd     the maximum number of elements to add (if this is
+                                    less than zero, they are all added)
+    */
+    void addArray (const StringArray& other,
+                   int startIndex = 0,
+                   int numElementsToAdd = -1);
+
+    /** Breaks up a string into tokens and adds them to this array.
+
+        This will tokenise the given string using whitespace characters as the
+        token delimiters, and will add these tokens to the end of the array.
+        @returns    the number of tokens added
+        @see fromTokens
+    */
+    int addTokens (StringRef stringToTokenise, bool preserveQuotedStrings);
+
+    /** Breaks up a string into tokens and adds them to this array.
+
+        This will tokenise the given string (using the string passed in to define the
+        token delimiters), and will add these tokens to the end of the array.
+
+        @param stringToTokenise     the string to tokenise
+        @param breakCharacters      a string of characters, any of which will be considered
+                                    to be a token delimiter.
+        @param quoteCharacters      if this string isn't empty, it defines a set of characters
+                                    which are treated as quotes. Any text occurring
+                                    between quotes is not broken up into tokens.
+        @returns    the number of tokens added
+        @see fromTokens
+    */
+    int addTokens (StringRef stringToTokenise,
+                   StringRef breakCharacters,
+                   StringRef quoteCharacters);
+
+    /** Breaks up a string into lines and adds them to this array.
+
+        This breaks a string down into lines separated by \\n or \\r\\n, and adds each line
+        to the array. Line-break characters are omitted from the strings that are added to
+        the array.
+    */
+    int addLines (StringRef stringToBreakUp);
+
+    /** Returns an array containing the tokens in a given string.
+
+        This will tokenise the given string using whitespace characters as the
+        token delimiters, and return these tokens as an array.
+        @see addTokens
+    */
+    static StringArray fromTokens (StringRef stringToTokenise,
+                                   bool preserveQuotedStrings);
+
+    /** Returns an array containing the tokens in a given string.
+
+        This will tokenise the given string using whitespace characters as the
+        token delimiters, and return these tokens as an array.
+
+        @param stringToTokenise     the string to tokenise
+        @param breakCharacters      a string of characters, any of which will be considered
+                                    to be a token delimiter.
+        @param quoteCharacters      if this string isn't empty, it defines a set of characters
+                                    which are treated as quotes. Any text occurring
+                                    between quotes is not broken up into tokens.
+        @see addTokens
+    */
+    static StringArray fromTokens (StringRef stringToTokenise,
+                                   StringRef breakCharacters,
+                                   StringRef quoteCharacters);
+
+    /** Returns an array containing the lines in a given string.
+
+        This breaks a string down into lines separated by \\n or \\r\\n, and returns an
+        array containing these lines. Line-break characters are omitted from the strings that
+        are added to the array.
+    */
+    static StringArray fromLines (StringRef stringToBreakUp);
+
+    //==============================================================================
+    /** Removes all elements from the array. */
+    void clear();
+
+    /** Removes all elements from the array without freeing the array's allocated storage.
+        @see clear
+    */
+    void clearQuick();
+
+    /** Removes a string from the array.
+        If the index is out-of-range, no action will be taken.
+    */
+    void remove (int index);
+
+    /** Finds a string in the array and removes it.
+        This will remove the first occurrence of the given string from the array. The
+        comparison may be case-insensitive depending on the ignoreCase parameter.
+    */
+    void removeString (StringRef stringToRemove,
+                       bool ignoreCase = false);
+
+    /** Removes a range of elements from the array.
+
+        This will remove a set of elements, starting from the given index,
+        and move subsequent elements down to close the gap.
+
+        If the range extends beyond the bounds of the array, it will
+        be safely clipped to the size of the array.
+
+        @param startIndex       the index of the first element to remove
+        @param numberToRemove   how many elements should be removed
+    */
+    void removeRange (int startIndex, int numberToRemove);
+
+    /** Removes any duplicated elements from the array.
+
+        If any string appears in the array more than once, only the first occurrence of
+        it will be retained.
+
+        @param ignoreCase   whether to use a case-insensitive comparison
+    */
+    void removeDuplicates (bool ignoreCase);
+
+    /** Removes empty strings from the array.
+        @param removeWhitespaceStrings  if true, strings that only contain whitespace
+                                        characters will also be removed
+    */
+    void removeEmptyStrings (bool removeWhitespaceStrings = true);
+
+    /** Moves one of the strings to a different position.
+
+        This will move the string to a specified index, shuffling along
+        any intervening elements as required.
+
+        So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
+        move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
+
+        @param currentIndex     the index of the value to be moved. If this isn't a
+                                valid index, then nothing will be done
+        @param newIndex         the index at which you'd like this value to end up. If this
+                                is less than zero, the value will be moved to the end
+                                of the array
+    */
+    void move (int currentIndex, int newIndex) noexcept;
+
+    /** Deletes any whitespace characters from the starts and ends of all the strings. */
+    void trim();
+
+    /** Adds numbers to the strings in the array, to make each string unique.
+
+        This will add numbers to the ends of groups of similar strings.
+        e.g. if there are two "moose" strings, they will become "moose (1)" and "moose (2)"
+
+        @param ignoreCaseWhenComparing      whether the comparison used is case-insensitive
+        @param appendNumberToFirstInstance  whether the first of a group of similar strings
+                                            also has a number appended to it.
+        @param preNumberString              when adding a number, this string is added before the number.
+                                            If you pass 0, a default string will be used, which adds
+                                            brackets around the number.
+        @param postNumberString             this string is appended after any numbers that are added.
+                                            If you pass 0, a default string will be used, which adds
+                                            brackets around the number.
+    */
+    void appendNumbersToDuplicates (bool ignoreCaseWhenComparing,
+                                    bool appendNumberToFirstInstance,
+                                    CharPointer_UTF8 preNumberString = CharPointer_UTF8 (nullptr),
+                                    CharPointer_UTF8 postNumberString = CharPointer_UTF8 (nullptr));
+
+    //==============================================================================
+    /** Joins the strings in the array together into one string.
+
+        This will join a range of elements from the array into a string, separating
+        them with a given string.
+
+        e.g. joinIntoString (",") will turn an array of "a" "b" and "c" into "a,b,c".
+
+        @param separatorString      the string to insert between all the strings
+        @param startIndex           the first element to join
+        @param numberOfElements     how many elements to join together. If this is less
+                                    than zero, all available elements will be used.
+    */
+    String joinIntoString (StringRef separatorString,
+                           int startIndex = 0,
+                           int numberOfElements = -1) const;
+
+    //==============================================================================
+    /** Sorts the array into alphabetical order.
+        @param ignoreCase       if true, the comparisons used will be case-sensitive.
+    */
+    void sort (bool ignoreCase);
+
+    /** Sorts the array using extra language-aware rules to do a better job of comparing
+        words containing spaces and numbers.
+        @see String::compareNatural()
+    */
+    void sortNatural();
+
+    //==============================================================================
+    /** Increases the array's internal storage to hold a minimum number of elements.
+
+        Calling this before adding a large known number of elements means that
+        the array won't have to keep dynamically resizing itself as the elements
+        are added, and it'll therefore be more efficient.
+    */
+    void ensureStorageAllocated (int minNumElements);
+
+    /** Reduces the amount of storage being used by the array.
+
+        Arrays typically allocate slightly more storage than they need, and after
+        removing elements, they may have quite a lot of unused space allocated.
+        This method will reduce the amount of allocated storage to a minimum.
+    */
+    void minimiseStorageOverheads();
+
+    /** This is the array holding the actual strings. This is public to allow direct access
+        to array methods that may not already be provided by the StringArray class.
+    */
+    Array<String> strings;
+
+private:
+    JUCE_LEAK_DETECTOR (StringArray)
+};
+
+
+#endif   // JUCE_STRINGARRAY_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPairArray.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPairArray.cpp
new file mode 100644
index 0000000..3275d2d
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPairArray.cpp
@@ -0,0 +1,147 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+StringPairArray::StringPairArray (const bool ignoreCase_)
+    : ignoreCase (ignoreCase_)
+{
+}
+
+StringPairArray::StringPairArray (const StringPairArray& other)
+    : keys (other.keys),
+      values (other.values),
+      ignoreCase (other.ignoreCase)
+{
+}
+
+StringPairArray::~StringPairArray()
+{
+}
+
+StringPairArray& StringPairArray::operator= (const StringPairArray& other)
+{
+    keys = other.keys;
+    values = other.values;
+    return *this;
+}
+
+bool StringPairArray::operator== (const StringPairArray& other) const
+{
+    for (int i = keys.size(); --i >= 0;)
+        if (other [keys[i]] != values[i])
+            return false;
+
+    return true;
+}
+
+bool StringPairArray::operator!= (const StringPairArray& other) const
+{
+    return ! operator== (other);
+}
+
+const String& StringPairArray::operator[] (StringRef key) const
+{
+    return values [keys.indexOf (key, ignoreCase)];
+}
+
+String StringPairArray::getValue (StringRef key, const String& defaultReturnValue) const
+{
+    const int i = keys.indexOf (key, ignoreCase);
+
+    if (i >= 0)
+        return values[i];
+
+    return defaultReturnValue;
+}
+
+bool StringPairArray::containsKey (StringRef key) const noexcept
+{
+    return keys.contains (key);
+}
+
+void StringPairArray::set (const String& key, const String& value)
+{
+    const int i = keys.indexOf (key, ignoreCase);
+
+    if (i >= 0)
+    {
+        values.set (i, value);
+    }
+    else
+    {
+        keys.add (key);
+        values.add (value);
+    }
+}
+
+void StringPairArray::addArray (const StringPairArray& other)
+{
+    for (int i = 0; i < other.size(); ++i)
+        set (other.keys[i], other.values[i]);
+}
+
+void StringPairArray::clear()
+{
+    keys.clear();
+    values.clear();
+}
+
+void StringPairArray::remove (StringRef key)
+{
+    remove (keys.indexOf (key, ignoreCase));
+}
+
+void StringPairArray::remove (const int index)
+{
+    keys.remove (index);
+    values.remove (index);
+}
+
+void StringPairArray::setIgnoresCase (const bool shouldIgnoreCase)
+{
+    ignoreCase = shouldIgnoreCase;
+}
+
+String StringPairArray::getDescription() const
+{
+    String s;
+
+    for (int i = 0; i < keys.size(); ++i)
+    {
+        s << keys[i] << " = " << values[i];
+        if (i < keys.size())
+            s << ", ";
+    }
+
+    return s;
+}
+
+void StringPairArray::minimiseStorageOverheads()
+{
+    keys.minimiseStorageOverheads();
+    values.minimiseStorageOverheads();
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPairArray.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPairArray.h
new file mode 100644
index 0000000..e1c774d
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPairArray.h
@@ -0,0 +1,157 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_STRINGPAIRARRAY_H_INCLUDED
+#define JUCE_STRINGPAIRARRAY_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A container for holding a set of strings which are keyed by another string.
+
+    @see StringArray
+*/
+class JUCE_API  StringPairArray
+{
+public:
+    //==============================================================================
+    /** Creates an empty array */
+    StringPairArray (bool ignoreCaseWhenComparingKeys = true);
+
+    /** Creates a copy of another array */
+    StringPairArray (const StringPairArray& other);
+
+    /** Destructor. */
+    ~StringPairArray();
+
+    /** Copies the contents of another string array into this one */
+    StringPairArray& operator= (const StringPairArray& other);
+
+    //==============================================================================
+    /** Compares two arrays.
+        Comparisons are case-sensitive.
+        @returns    true only if the other array contains exactly the same strings with the same keys
+    */
+    bool operator== (const StringPairArray& other) const;
+
+    /** Compares two arrays.
+        Comparisons are case-sensitive.
+        @returns    false if the other array contains exactly the same strings with the same keys
+    */
+    bool operator!= (const StringPairArray& other) const;
+
+    //==============================================================================
+    /** Finds the value corresponding to a key string.
+
+        If no such key is found, this will just return an empty string. To check whether
+        a given key actually exists (because it might actually be paired with an empty string), use
+        the getAllKeys() method to obtain a list.
+
+        Obviously the reference returned shouldn't be stored for later use, as the
+        string it refers to may disappear when the array changes.
+
+        @see getValue
+    */
+    const String& operator[] (StringRef key) const;
+
+    /** Finds the value corresponding to a key string.
+        If no such key is found, this will just return the value provided as a default.
+        @see operator[]
+    */
+    String getValue (StringRef, const String& defaultReturnValue) const;
+
+    /** Returns true if the given key exists. */
+    bool containsKey (StringRef key) const noexcept;
+
+    /** Returns a list of all keys in the array. */
+    const StringArray& getAllKeys() const noexcept          { return keys; }
+
+    /** Returns a list of all values in the array. */
+    const StringArray& getAllValues() const noexcept        { return values; }
+
+    /** Returns the number of strings in the array */
+    inline int size() const noexcept                        { return keys.size(); };
+
+
+    //==============================================================================
+    /** Adds or amends a key/value pair.
+        If a value already exists with this key, its value will be overwritten,
+        otherwise the key/value pair will be added to the array.
+    */
+    void set (const String& key, const String& value);
+
+    /** Adds the items from another array to this one.
+        This is equivalent to using set() to add each of the pairs from the other array.
+    */
+    void addArray (const StringPairArray& other);
+
+    //==============================================================================
+    /** Removes all elements from the array. */
+    void clear();
+
+    /** Removes a string from the array based on its key.
+        If the key isn't found, nothing will happen.
+    */
+    void remove (StringRef key);
+
+    /** Removes a string from the array based on its index.
+        If the index is out-of-range, no action will be taken.
+    */
+    void remove (int index);
+
+    //==============================================================================
+    /** Indicates whether to use a case-insensitive search when looking up a key string.
+    */
+    void setIgnoresCase (bool shouldIgnoreCase);
+
+    //==============================================================================
+    /** Returns a descriptive string containing the items.
+        This is handy for dumping the contents of an array.
+    */
+    String getDescription() const;
+
+    //==============================================================================
+    /** Reduces the amount of storage being used by the array.
+
+        Arrays typically allocate slightly more storage than they need, and after
+        removing elements, they may have quite a lot of unused space allocated.
+        This method will reduce the amount of allocated storage to a minimum.
+    */
+    void minimiseStorageOverheads();
+
+
+private:
+    //==============================================================================
+    StringArray keys, values;
+    bool ignoreCase;
+
+    JUCE_LEAK_DETECTOR (StringPairArray)
+};
+
+
+#endif   // JUCE_STRINGPAIRARRAY_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPool.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPool.cpp
new file mode 100644
index 0000000..039a30b
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPool.cpp
@@ -0,0 +1,166 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+static const int minNumberOfStringsForGarbageCollection = 300;
+static const uint32 garbageCollectionInterval = 30000;
+
+
+StringPool::StringPool() noexcept  : lastGarbageCollectionTime (0) {}
+StringPool::~StringPool() {}
+
+struct StartEndString
+{
+    StartEndString (String::CharPointerType s, String::CharPointerType e) noexcept : start (s), end (e) {}
+    operator String() const   { return String (start, end); }
+
+    String::CharPointerType start, end;
+};
+
+static int compareStrings (const String& s1, const String& s2) noexcept     { return s1.compare (s2); }
+static int compareStrings (CharPointer_UTF8 s1, const String& s2) noexcept  { return s1.compare (s2.getCharPointer()); }
+
+static int compareStrings (const StartEndString& string1, const String& string2) noexcept
+{
+    String::CharPointerType s1 (string1.start), s2 (string2.getCharPointer());
+
+    for (;;)
+    {
+        const int c1 = s1 < string1.end ? (int) s1.getAndAdvance() : 0;
+        const int c2 = (int) s2.getAndAdvance();
+        const int diff = c1 - c2;
+
+        if (diff != 0)  return diff < 0 ? -1 : 1;
+        if (c1 == 0)    break;
+    }
+
+    return 0;
+}
+
+template <typename NewStringType>
+static String addPooledString (Array<String>& strings, const NewStringType& newString)
+{
+    int start = 0;
+    int end = strings.size();
+
+    while (start < end)
+    {
+        const String& startString = strings.getReference (start);
+        const int startComp = compareStrings (newString, startString);
+
+        if (startComp == 0)
+            return startString;
+
+        const int halfway = (start + end) / 2;
+
+        if (halfway == start)
+        {
+            if (startComp > 0)
+                ++start;
+
+            break;
+        }
+
+        const String& halfwayString = strings.getReference (halfway);
+        const int halfwayComp = compareStrings (newString, halfwayString);
+
+        if (halfwayComp == 0)
+            return halfwayString;
+
+        if (halfwayComp > 0)
+            start = halfway;
+        else
+            end = halfway;
+    }
+
+    strings.insert (start, newString);
+    return strings.getReference (start);
+}
+
+String StringPool::getPooledString (const char* const newString)
+{
+    if (newString == nullptr || *newString == 0)
+        return String();
+
+    const ScopedLock sl (lock);
+    garbageCollectIfNeeded();
+    return addPooledString (strings, CharPointer_UTF8 (newString));
+}
+
+String StringPool::getPooledString (String::CharPointerType start, String::CharPointerType end)
+{
+    if (start.isEmpty() || start == end)
+        return String();
+
+    const ScopedLock sl (lock);
+    garbageCollectIfNeeded();
+    return addPooledString (strings, StartEndString (start, end));
+}
+
+String StringPool::getPooledString (StringRef newString)
+{
+    if (newString.isEmpty())
+        return String();
+
+    const ScopedLock sl (lock);
+    garbageCollectIfNeeded();
+    return addPooledString (strings, newString.text);
+}
+
+String StringPool::getPooledString (const String& newString)
+{
+    if (newString.isEmpty())
+        return String();
+
+    const ScopedLock sl (lock);
+    garbageCollectIfNeeded();
+    return addPooledString (strings, newString);
+}
+
+void StringPool::garbageCollectIfNeeded()
+{
+    if (strings.size() > minNumberOfStringsForGarbageCollection
+         && Time::getApproximateMillisecondCounter() > lastGarbageCollectionTime + garbageCollectionInterval)
+        garbageCollect();
+}
+
+void StringPool::garbageCollect()
+{
+    const ScopedLock sl (lock);
+
+    for (int i = strings.size(); --i >= 0;)
+        if (strings.getReference(i).getReferenceCount() == 1)
+            strings.remove (i);
+
+    lastGarbageCollectionTime = Time::getApproximateMillisecondCounter();
+}
+
+StringPool& StringPool::getGlobalPool() noexcept
+{
+    static StringPool pool;
+    return pool;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPool.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPool.h
new file mode 100644
index 0000000..4de2186
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringPool.h
@@ -0,0 +1,94 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_STRINGPOOL_H_INCLUDED
+#define JUCE_STRINGPOOL_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A StringPool holds a set of shared strings, which reduces storage overheads and improves
+    comparison speed when dealing with many duplicate strings.
+
+    When you add a string to a pool using getPooledString, it'll return a character
+    array containing the same string. This array is owned by the pool, and the same array
+    is returned every time a matching string is asked for. This means that it's trivial to
+    compare two pooled strings for equality, as you can simply compare their pointers. It
+    also cuts down on storage if you're using many copies of the same string.
+*/
+class JUCE_API  StringPool
+{
+public:
+    //==============================================================================
+    /** Creates an empty pool. */
+    StringPool() noexcept;
+
+    /** Destructor */
+    ~StringPool();
+
+    //==============================================================================
+    /** Returns a pointer to a shared copy of the string that is passed in.
+        The pool will always return the same String object when asked for a string that matches it.
+    */
+    String getPooledString (const String& original);
+
+    /** Returns a pointer to a copy of the string that is passed in.
+        The pool will always return the same String object when asked for a string that matches it.
+    */
+    String getPooledString (const char* original);
+
+    /** Returns a pointer to a shared copy of the string that is passed in.
+        The pool will always return the same String object when asked for a string that matches it.
+    */
+    String getPooledString (StringRef original);
+
+    /** Returns a pointer to a copy of the string that is passed in.
+        The pool will always return the same String object when asked for a string that matches it.
+    */
+    String getPooledString (String::CharPointerType start, String::CharPointerType end);
+
+    //==============================================================================
+    /** Scans the pool, and removes any strings that are unreferenced.
+        You don't generally need to call this - it'll be called automatically when the pool grows
+        large enough to warrant it.
+    */
+    void garbageCollect();
+
+    /** Returns a shared global pool which is used for things like Identifiers, XML parsing. */
+    static StringPool& getGlobalPool() noexcept;
+
+private:
+    Array<String> strings;
+    CriticalSection lock;
+    uint32 lastGarbageCollectionTime;
+
+    void garbageCollectIfNeeded();
+};
+
+
+#endif   // JUCE_STRINGPOOL_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringRef.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringRef.h
new file mode 100644
index 0000000..434bf4a
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_StringRef.h
@@ -0,0 +1,138 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_STRINGREF_H_INCLUDED
+#define JUCE_STRINGREF_H_INCLUDED
+
+//==============================================================================
+/**
+    A simple class for holding temporary references to a string literal or String.
+
+    Unlike a real String object, the StringRef does not allocate any memory or
+    take ownership of the strings you give to it - it simply holds a reference to
+    a string that has been allocated elsewhere.
+    The main purpose of the class is to be used instead of a const String& as the type
+    of function arguments where the caller may pass either a string literal or a String
+    object. This means that when the called uses a string literal, there's no need
+    for an temporary String object to be allocated, and this cuts down overheads
+    substantially.
+
+    Because the class is simply a wrapper around a pointer, you should always pass
+    it by value, not by reference.
+
+    @code
+    void myStringFunction1 (const String&);
+    void myStringFunction2 (StringRef);
+
+    myStringFunction1 ("abc"); // Implicitly allocates a temporary String object.
+    myStringFunction2 ("abc"); // Much faster, as no local allocations are needed.
+    @endcode
+
+    For examples of it in use, see the XmlElement or StringArray classes.
+
+    Bear in mind that there are still many cases where it's better to use an argument
+    which is a const String&. For example if the function stores the string or needs
+    to internally create a String from the argument, then it's better for the original
+    argument to already be a String.
+
+    @see String
+*/
+class JUCE_API  StringRef
+{
+public:
+    /** Creates a StringRef from a raw string literal.
+        The StringRef object does NOT take ownership or copy this data, so you must
+        ensure that the data does not change during the lifetime of the StringRef.
+        Note that this pointer not be null!
+    */
+    StringRef (const char* stringLiteral) noexcept;
+
+    /** Creates a StringRef from a raw char pointer.
+        The StringRef object does NOT take ownership or copy this data, so you must
+        ensure that the data does not change during the lifetime of the StringRef.
+    */
+    StringRef (String::CharPointerType stringLiteral) noexcept;
+
+    /** Creates a StringRef from a String.
+        The StringRef object does NOT take ownership or copy the data from the String,
+        so you must ensure that the String is not modified or deleted during the lifetime
+        of the StringRef.
+    */
+    StringRef (const String& string) noexcept;
+
+    /** Creates a StringRef pointer to an empty string. */
+    StringRef() noexcept;
+
+    //==============================================================================
+    /** Returns a raw pointer to the underlying string data. */
+    operator const String::CharPointerType::CharType*() const noexcept  { return text.getAddress(); }
+    /** Returns a pointer to the underlying string data as a char pointer object. */
+    operator String::CharPointerType() const noexcept                   { return text; }
+
+    /** Returns true if the string is empty. */
+    bool isEmpty() const noexcept                                       { return text.isEmpty(); }
+    /** Returns true if the string is not empty. */
+    bool isNotEmpty() const noexcept                                    { return ! text.isEmpty(); }
+    /** Returns the number of characters in the string. */
+    int length() const noexcept                                         { return (int) text.length(); }
+
+    /** Retrieves a character by index. */
+    juce_wchar operator[] (int index) const noexcept                    { return text[index]; }
+
+    /** Compares this StringRef with a String. */
+    bool operator== (const String& s) const noexcept                    { return text.compare (s.getCharPointer()) == 0; }
+    /** Compares this StringRef with a String. */
+    bool operator!= (const String& s) const noexcept                    { return text.compare (s.getCharPointer()) != 0; }
+
+    /** Case-sensitive comparison of two StringRefs. */
+    bool operator== (StringRef s) const noexcept                        { return text.compare (s.text) == 0; }
+    /** Case-sensitive comparison of two StringRefs. */
+    bool operator!= (StringRef s) const noexcept                        { return text.compare (s.text) != 0; }
+
+    //==============================================================================
+    /** The text that is referenced. */
+    String::CharPointerType text;
+
+    #if JUCE_STRING_UTF_TYPE != 8 && ! defined (DOXYGEN)
+     // Sorry, non-UTF8 people, you're unable to take advantage of StringRef, because
+     // you've chosen a character encoding that doesn't match C++ string literals.
+     String stringCopy;
+    #endif
+};
+
+//==============================================================================
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, StringRef string2) noexcept;
+/** Case-sensitive comparison of two strings. */
+JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, StringRef string2) noexcept;
+
+#if JUCE_STRING_UTF_TYPE != 8 && ! defined (DOXYGEN)
+ inline String operator+ (String s1, StringRef s2)      { return s1 += String (s2.text); }
+#endif
+
+#endif   // JUCE_STRINGREF_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_TextDiff.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_TextDiff.cpp
new file mode 100644
index 0000000..6b4c807
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_TextDiff.cpp
@@ -0,0 +1,247 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+struct TextDiffHelpers
+{
+    enum { minLengthToMatch = 3 };
+
+    struct StringRegion
+    {
+        StringRegion (const String& s) noexcept
+            : text (s.getCharPointer()), start (0), length (s.length()) {}
+
+        StringRegion (const String::CharPointerType t, int s, int len)  noexcept
+            : text (t), start (s), length (len) {}
+
+        String::CharPointerType text;
+        int start, length;
+    };
+
+    static void addInsertion (TextDiff& td, const String::CharPointerType text, int index, int length)
+    {
+        TextDiff::Change c;
+        c.insertedText = String (text, (size_t) length);
+        c.start = index;
+        c.length = length;
+        td.changes.add (c);
+    }
+
+    static void addDeletion (TextDiff& td, int index, int length)
+    {
+        TextDiff::Change c;
+        c.start = index;
+        c.length = length;
+        td.changes.add (c);
+    }
+
+    static void diffSkippingCommonStart (TextDiff& td, const StringRegion& a, const StringRegion& b)
+    {
+        String::CharPointerType sa (a.text);
+        String::CharPointerType sb (b.text);
+        const int maxLen = jmax (a.length, b.length);
+
+        for (int i = 0; i < maxLen; ++i, ++sa, ++sb)
+        {
+            if (*sa != *sb)
+            {
+                diffRecursively (td, StringRegion (sa, a.start + i, a.length - i),
+                                     StringRegion (sb, b.start + i, b.length - i));
+                break;
+            }
+        }
+    }
+
+    static void diffRecursively (TextDiff& td, const StringRegion& a, const StringRegion& b)
+    {
+        int indexA, indexB;
+        const int len = findLongestCommonSubstring (a.text, a.length,
+                                                    b.text, b.length,
+                                                    indexA, indexB);
+
+        if (len >= minLengthToMatch)
+        {
+            if (indexA > 0 && indexB > 0)
+                diffSkippingCommonStart (td, StringRegion (a.text, a.start, indexA),
+                                             StringRegion (b.text, b.start, indexB));
+            else if (indexA > 0)
+                addDeletion (td, b.start, indexA);
+            else if (indexB > 0)
+                addInsertion (td, b.text, b.start, indexB);
+
+            diffRecursively (td, StringRegion (a.text + indexA + len, a.start + indexA + len, a.length - indexA - len),
+                                 StringRegion (b.text + indexB + len, b.start + indexB + len, b.length - indexB - len));
+        }
+        else
+        {
+            if (a.length > 0)   addDeletion (td, b.start, a.length);
+            if (b.length > 0)   addInsertion (td, b.text, b.start, b.length);
+        }
+    }
+
+    static int findLongestCommonSubstring (String::CharPointerType a, const int lenA,
+                                           const String::CharPointerType b, const int lenB,
+                                           int& indexInA, int& indexInB)
+    {
+        if (lenA == 0 || lenB == 0)
+            return 0;
+
+        HeapBlock<int> lines;
+        lines.calloc (2 + 2 * (size_t) lenB);
+
+        int* l0 = lines;
+        int* l1 = l0 + lenB + 1;
+
+        int loopsWithoutImprovement = 0;
+        int bestLength = 0;
+        indexInA = indexInB = 0;
+
+        for (int i = 0; i < lenA; ++i)
+        {
+            const juce_wchar ca = a.getAndAdvance();
+            String::CharPointerType b2 (b);
+
+            for (int j = 0; j < lenB; ++j)
+            {
+                if (ca != b2.getAndAdvance())
+                {
+                    l1[j + 1] = 0;
+                }
+                else
+                {
+                    const int len = l0[j] + 1;
+                    l1[j + 1] = len;
+
+                    if (len > bestLength)
+                    {
+                        loopsWithoutImprovement = 0;
+                        bestLength = len;
+                        indexInA = i;
+                        indexInB = j;
+                    }
+                }
+            }
+
+            if (++loopsWithoutImprovement > 100)
+                break;
+
+            std::swap (l0, l1);
+        }
+
+        indexInA -= bestLength - 1;
+        indexInB -= bestLength - 1;
+        return bestLength;
+    }
+};
+
+TextDiff::TextDiff (const String& original, const String& target)
+{
+    TextDiffHelpers::diffSkippingCommonStart (*this, original, target);
+}
+
+String TextDiff::appliedTo (String text) const
+{
+    for (int i = 0; i < changes.size(); ++i)
+        text = changes.getReference(i).appliedTo (text);
+
+    return text;
+}
+
+bool TextDiff::Change::isDeletion() const noexcept
+{
+    return insertedText.isEmpty();
+}
+
+String TextDiff::Change::appliedTo (const String& text) const noexcept
+{
+    return text.substring (0, start) + (isDeletion() ? text.substring (start + length)
+                                                     : (insertedText + text.substring (start)));
+}
+
+//==============================================================================
+//==============================================================================
+#if JUCE_UNIT_TESTS
+
+class DiffTests  : public UnitTest
+{
+public:
+    DiffTests() : UnitTest ("TextDiff class") {}
+
+    static String createString (Random& r)
+    {
+        juce_wchar buffer[50] = { 0 };
+
+        for (int i = r.nextInt (49); --i >= 0;)
+        {
+            if (r.nextInt (10) == 0)
+            {
+                do
+                {
+                    buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
+                }
+                while (! CharPointer_UTF16::canRepresent (buffer[i]));
+            }
+            else
+                buffer[i] = (juce_wchar) ('a' + r.nextInt (3));
+        }
+
+        return CharPointer_UTF32 (buffer);
+    }
+
+    void testDiff (const String& a, const String& b)
+    {
+        TextDiff diff (a, b);
+        const String result (diff.appliedTo (a));
+        expectEquals (result, b);
+    }
+
+    void runTest()
+    {
+        beginTest ("TextDiff");
+
+        Random r = getRandom();
+
+        testDiff (String::empty, String::empty);
+        testDiff ("x", String::empty);
+        testDiff (String::empty, "x");
+        testDiff ("x", "x");
+        testDiff ("x", "y");
+        testDiff ("xxx", "x");
+        testDiff ("x", "xxx");
+
+        for (int i = 5000; --i >= 0;)
+        {
+            String s (createString (r));
+            testDiff (s, createString (r));
+            testDiff (s + createString (r), s + createString (r));
+        }
+    }
+};
+
+static DiffTests diffTests;
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_TextDiff.h b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_TextDiff.h
new file mode 100644
index 0000000..d420c3d
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/text/juce_TextDiff.h
@@ -0,0 +1,80 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_TEXTDIFF_H_INCLUDED
+#define JUCE_TEXTDIFF_H_INCLUDED
+
+
+/**
+    Calculates and applies a sequence of changes to convert one text string into
+    another.
+
+    Once created, the TextDiff object contains an array of change objects, where
+    each change can be either an insertion or a deletion. When applied in order
+    to the original string, these changes will convert it to the target string.
+*/
+class JUCE_API TextDiff
+{
+public:
+    /** Creates a set of diffs for converting the original string into the target. */
+    TextDiff (const String& original,
+              const String& target);
+
+    /** Applies this sequence of changes to the original string, producing the
+        target string that was specified when generating them.
+
+        Obviously it only makes sense to call this function with the string that
+        was originally passed to the constructor. Any other input will produce an
+        undefined result.
+    */
+    String appliedTo (String text) const;
+
+    /** Describes a change, which can be either an insertion or deletion. */
+    struct Change
+    {
+        String insertedText; /**< If this change is a deletion, this string will be empty; otherwise,
+                                  it'll be the text that should be inserted at the index specified by start. */
+        int start;    /**< Specifies the character index in a string at which text should be inserted or deleted. */
+        int length;   /**< If this change is a deletion, this specifies the number of characters to delete. For an
+                           insertion, this is the length of the new text being inserted. */
+
+        /** Returns true if this change is a deletion, or false for an insertion. */
+        bool isDeletion() const noexcept;
+
+        /** Returns the result of applying this change to a string. */
+        String appliedTo (const String& original) const noexcept;
+    };
+
+    /** The list of changes required to perform the transformation.
+        Applying each of these, in order, to the original string will produce the target.
+    */
+    Array<Change> changes;
+};
+
+
+#endif   // JUCE_TEXTDIFF_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ChildProcess.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ChildProcess.cpp
new file mode 100644
index 0000000..4566b13
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ChildProcess.cpp
@@ -0,0 +1,113 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+ChildProcess::ChildProcess() {}
+ChildProcess::~ChildProcess() {}
+
+bool ChildProcess::isRunning() const
+{
+    return activeProcess != nullptr && activeProcess->isRunning();
+}
+
+int ChildProcess::readProcessOutput (void* dest, int numBytes)
+{
+    return activeProcess != nullptr ? activeProcess->read (dest, numBytes) : 0;
+}
+
+bool ChildProcess::kill()
+{
+    return activeProcess == nullptr || activeProcess->killProcess();
+}
+
+uint32 ChildProcess::getExitCode() const
+{
+    return activeProcess != nullptr ? activeProcess->getExitCode() : 0;
+}
+
+bool ChildProcess::waitForProcessToFinish (const int timeoutMs) const
+{
+    const uint32 timeoutTime = Time::getMillisecondCounter() + (uint32) timeoutMs;
+
+    do
+    {
+        if (! isRunning())
+            return true;
+    }
+    while (timeoutMs < 0 || Time::getMillisecondCounter() < timeoutTime);
+
+    return false;
+}
+
+String ChildProcess::readAllProcessOutput()
+{
+    MemoryOutputStream result;
+
+    for (;;)
+    {
+        char buffer [512];
+        const int num = readProcessOutput (buffer, sizeof (buffer));
+
+        if (num <= 0)
+            break;
+
+        result.write (buffer, (size_t) num);
+    }
+
+    return result.toString();
+}
+
+//==============================================================================
+#if JUCE_UNIT_TESTS
+
+class ChildProcessTests  : public UnitTest
+{
+public:
+    ChildProcessTests() : UnitTest ("ChildProcess") {}
+
+    void runTest()
+    {
+        beginTest ("Child Processes");
+
+      #if JUCE_WINDOWS || JUCE_MAC || JUCE_LINUX
+        ChildProcess p;
+
+       #if JUCE_WINDOWS
+        expect (p.start ("tasklist"));
+       #else
+        expect (p.start ("ls /"));
+       #endif
+
+        //String output (p.readAllProcessOutput());
+        //expect (output.isNotEmpty());
+      #endif
+    }
+};
+
+static ChildProcessTests childProcessUnitTests;
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ChildProcess.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ChildProcess.h
new file mode 100644
index 0000000..0adcb57
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ChildProcess.h
@@ -0,0 +1,119 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_CHILDPROCESS_H_INCLUDED
+#define JUCE_CHILDPROCESS_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Launches and monitors a child process.
+
+    This class lets you launch an executable, and read its output. You can also
+    use it to check whether the child process has finished.
+*/
+class JUCE_API  ChildProcess
+{
+public:
+    //==============================================================================
+    /** Creates a process object.
+        To actually launch the process, use start().
+    */
+    ChildProcess();
+
+    /** Destructor.
+        Note that deleting this object won't terminate the child process.
+    */
+    ~ChildProcess();
+
+    /** These flags are used by the start() methods. */
+    enum StreamFlags
+    {
+        wantStdOut = 1,
+        wantStdErr = 2
+    };
+
+    /** Attempts to launch a child process command.
+
+        The command should be the name of the executable file, followed by any arguments
+        that are required.
+        If the process has already been launched, this will launch it again. If a problem
+        occurs, the method will return false.
+        The streamFlags is a combinations of values to indicate which of the child's output
+        streams should be read and returned by readProcessOutput().
+    */
+    bool start (const String& command, int streamFlags = wantStdOut | wantStdErr);
+
+    /** Attempts to launch a child process command.
+
+        The first argument should be the name of the executable file, followed by any other
+        arguments that are needed.
+        If the process has already been launched, this will launch it again. If a problem
+        occurs, the method will return false.
+        The streamFlags is a combinations of values to indicate which of the child's output
+        streams should be read and returned by readProcessOutput().
+    */
+    bool start (const StringArray& arguments, int streamFlags = wantStdOut | wantStdErr);
+
+    /** Returns true if the child process is alive. */
+    bool isRunning() const;
+
+    /** Attempts to read some output from the child process.
+        This will attempt to read up to the given number of bytes of data from the
+        process. It returns the number of bytes that were actually read.
+    */
+    int readProcessOutput (void* destBuffer, int numBytesToRead);
+
+    /** Blocks until the process has finished, and then returns its complete output
+        as a string.
+    */
+    String readAllProcessOutput();
+
+    /** Blocks until the process is no longer running. */
+    bool waitForProcessToFinish (int timeoutMs) const;
+
+    /** If the process has finished, this returns its exit code. */
+    uint32 getExitCode() const;
+
+    /** Attempts to kill the child process.
+        Returns true if it succeeded. Trying to read from the process after calling this may
+        result in undefined behaviour.
+    */
+    bool kill();
+
+private:
+    //==============================================================================
+    class ActiveProcess;
+    friend struct ContainerDeletePolicy<ActiveProcess>;
+    ScopedPointer<ActiveProcess> activeProcess;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcess)
+};
+
+
+#endif   // JUCE_CHILDPROCESS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_CriticalSection.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_CriticalSection.h
new file mode 100644
index 0000000..60e61dd
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_CriticalSection.h
@@ -0,0 +1,266 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_CRITICALSECTION_H_INCLUDED
+#define JUCE_CRITICALSECTION_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A re-entrant mutex.
+
+    A CriticalSection acts as a re-entrant mutex object. The best way to lock and unlock
+    one of these is by using RAII in the form of a local ScopedLock object - have a look
+    through the codebase for many examples of how to do this.
+
+    In almost all cases you'll want to declare your CriticalSection as a member variable.
+    Occasionally you may want to declare one as a static variable, but in that case the usual
+    C++ static object order-of-construction warnings should be heeded.
+
+    @see ScopedLock, ScopedTryLock, ScopedUnlock, SpinLock, ReadWriteLock, Thread, InterProcessLock
+*/
+class JUCE_API  CriticalSection
+{
+public:
+    //==============================================================================
+    /** Creates a CriticalSection object. */
+    CriticalSection() noexcept;
+
+    /** Destructor.
+        If the critical section is deleted whilst locked, any subsequent behaviour
+        is unpredictable.
+    */
+    ~CriticalSection() noexcept;
+
+    //==============================================================================
+    /** Acquires the lock.
+
+        If the lock is already held by the caller thread, the method returns immediately.
+        If the lock is currently held by another thread, this will wait until it becomes free.
+
+        It's strongly recommended that you never call this method directly - instead use the
+        ScopedLock class to manage the locking using an RAII pattern instead.
+
+        @see exit, tryEnter, ScopedLock
+    */
+    void enter() const noexcept;
+
+    /** Attempts to lock this critical section without blocking.
+
+        This method behaves identically to CriticalSection::enter, except that the caller thread
+        does not wait if the lock is currently held by another thread but returns false immediately.
+
+        @returns false if the lock is currently held by another thread, true otherwise.
+        @see enter
+    */
+    bool tryEnter() const noexcept;
+
+    /** Releases the lock.
+
+        If the caller thread hasn't got the lock, this can have unpredictable results.
+
+        If the enter() method has been called multiple times by the thread, each
+        call must be matched by a call to exit() before other threads will be allowed
+        to take over the lock.
+
+        @see enter, ScopedLock
+    */
+    void exit() const noexcept;
+
+
+    //==============================================================================
+    /** Provides the type of scoped lock to use with a CriticalSection. */
+    typedef GenericScopedLock <CriticalSection>       ScopedLockType;
+
+    /** Provides the type of scoped unlocker to use with a CriticalSection. */
+    typedef GenericScopedUnlock <CriticalSection>     ScopedUnlockType;
+
+    /** Provides the type of scoped try-locker to use with a CriticalSection. */
+    typedef GenericScopedTryLock <CriticalSection>    ScopedTryLockType;
+
+
+private:
+    //==============================================================================
+   #if JUCE_WINDOWS
+    // To avoid including windows.h in the public JUCE headers, we'll just allocate
+    // a block of memory here that's big enough to be used internally as a windows
+    // CRITICAL_SECTION structure.
+    #if JUCE_64BIT
+     uint8 lock[44];
+    #else
+     uint8 lock[24];
+    #endif
+   #else
+    mutable pthread_mutex_t lock;
+   #endif
+
+    JUCE_DECLARE_NON_COPYABLE (CriticalSection)
+};
+
+
+//==============================================================================
+/**
+    A class that can be used in place of a real CriticalSection object, but which
+    doesn't perform any locking.
+
+    This is currently used by some templated classes, and most compilers should
+    manage to optimise it out of existence.
+
+    @see CriticalSection, Array, OwnedArray, ReferenceCountedArray
+*/
+class JUCE_API  DummyCriticalSection
+{
+public:
+    inline DummyCriticalSection() noexcept      {}
+    inline ~DummyCriticalSection() noexcept     {}
+
+    inline void enter() const noexcept          {}
+    inline bool tryEnter() const noexcept       { return true; }
+    inline void exit() const noexcept           {}
+
+    //==============================================================================
+    /** A dummy scoped-lock type to use with a dummy critical section. */
+    struct ScopedLockType
+    {
+        ScopedLockType (const DummyCriticalSection&) noexcept {}
+    };
+
+    /** A dummy scoped-unlocker type to use with a dummy critical section. */
+    typedef ScopedLockType ScopedUnlockType;
+
+private:
+    JUCE_DECLARE_NON_COPYABLE (DummyCriticalSection)
+};
+
+//==============================================================================
+/**
+    Automatically locks and unlocks a CriticalSection object.
+
+    You can use a ScopedLock as a local variable to provide RAII-based locking of a CriticalSection.
+
+    e.g. @code
+
+    struct MyObject
+    {
+        CriticalSection objectLock;
+
+        // assuming that this example function will be called by multiple threads
+        void foo()
+        {
+            const ScopedLock myScopedLock (objectLock);
+
+            // objectLock is now locked..
+
+            ...do some thread-safe work here...
+
+            // ..and objectLock gets unlocked here, as myScopedLock goes out of
+            // scope at the end of the block
+        }
+    };
+    @endcode
+
+    @see CriticalSection, ScopedUnlock
+*/
+typedef CriticalSection::ScopedLockType  ScopedLock;
+
+//==============================================================================
+/**
+    Automatically unlocks and re-locks a CriticalSection object.
+
+    This is the reverse of a ScopedLock object - instead of locking the critical
+    section for the lifetime of this object, it unlocks it.
+
+    Make sure you don't try to unlock critical sections that aren't actually locked!
+
+    e.g. @code
+
+    struct MyObject
+    {
+        CriticalSection objectLock;
+
+        void foo()
+        {
+            {
+                const ScopedLock myScopedLock (objectLock);
+
+                // objectLock is now locked..
+
+                {
+                    ScopedUnlock myUnlocker (objectLock);
+
+                    // ..and now unlocked..
+                }
+
+                // ..and now locked again..
+            }
+
+            // ..and finally unlocked.
+        }
+    };
+    @endcode
+
+    @see CriticalSection, ScopedLock
+*/
+typedef CriticalSection::ScopedUnlockType  ScopedUnlock;
+
+//==============================================================================
+/**
+    Automatically tries to lock and unlock a CriticalSection object.
+
+    Use one of these as a local variable to control access to a CriticalSection.
+
+    e.g. @code
+
+    struct MyObject
+    {
+        CriticalSection objectLock;
+
+        void foo()
+        {
+            const ScopedTryLock myScopedTryLock (objectLock);
+
+            // Unlike using a ScopedLock, this may fail to actually get the lock, so you
+            // must call the isLocked() method before making any assumptions..
+            if (myScopedTryLock.isLocked())
+            {
+               ...safely do some work...
+            }
+            else
+            {
+                // If we get here, then our attempt at locking failed because another thread had already locked it..
+            }
+        }
+    };
+    @endcode
+
+    @see CriticalSection::tryEnter, ScopedLock, ScopedUnlock, ScopedReadLock
+*/
+typedef CriticalSection::ScopedTryLockType  ScopedTryLock;
+
+
+#endif   // JUCE_CRITICALSECTION_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_DynamicLibrary.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_DynamicLibrary.h
new file mode 100644
index 0000000..df6625b
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_DynamicLibrary.h
@@ -0,0 +1,85 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_DYNAMICLIBRARY_H_INCLUDED
+#define JUCE_DYNAMICLIBRARY_H_INCLUDED
+
+/**
+    Handles the opening and closing of DLLs.
+
+    This class can be used to open a DLL and get some function pointers from it.
+    Since the DLL is freed when this object is deleted, it's handy for managing
+    library lifetimes using RAII.
+*/
+class JUCE_API  DynamicLibrary
+{
+public:
+    /** Creates an unopened DynamicLibrary object.
+        Call open() to actually open one.
+    */
+    DynamicLibrary() noexcept : handle (nullptr) {}
+
+    /**
+    */
+    DynamicLibrary (const String& name) : handle (nullptr) { open (name); }
+
+    /** Destructor.
+        If a library is currently open, it will be closed when this object is destroyed.
+    */
+    ~DynamicLibrary()   { close(); }
+
+    /** Opens a DLL.
+        The name and the method by which it gets found is of course platform-specific, and
+        may or may not include a path, depending on the OS.
+        If a library is already open when this method is called, it will first close the library
+        before attempting to load the new one.
+        @returns true if the library was successfully found and opened.
+    */
+    bool open (const String& name);
+
+    /** Releases the currently-open DLL, or has no effect if none was open. */
+    void close();
+
+    /** Tries to find a named function in the currently-open DLL, and returns a pointer to it.
+        If no library is open, or if the function isn't found, this will return a null pointer.
+    */
+    void* getFunction (const String& functionName) noexcept;
+
+    /** Returns the platform-specific native library handle.
+        You'll need to cast this to whatever is appropriate for the OS that's in use.
+    */
+    void* getNativeHandle() const noexcept     { return handle; }
+
+private:
+    void* handle;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DynamicLibrary)
+};
+
+
+#endif   // JUCE_DYNAMICLIBRARY_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_HighResolutionTimer.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_HighResolutionTimer.cpp
new file mode 100644
index 0000000..3475b74
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_HighResolutionTimer.cpp
@@ -0,0 +1,36 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+HighResolutionTimer::HighResolutionTimer()                    { pimpl = new Pimpl (*this); }
+HighResolutionTimer::~HighResolutionTimer()                   { stopTimer(); }
+
+void HighResolutionTimer::startTimer (int periodMs)           { pimpl->start (jmax (1, periodMs)); }
+void HighResolutionTimer::stopTimer()                         { pimpl->stop(); }
+
+bool HighResolutionTimer::isTimerRunning() const noexcept     { return pimpl->periodMs != 0; }
+int HighResolutionTimer::getTimerInterval() const noexcept    { return pimpl->periodMs; }
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_HighResolutionTimer.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_HighResolutionTimer.h
new file mode 100644
index 0000000..21022ad
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_HighResolutionTimer.h
@@ -0,0 +1,109 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_HIGHRESOLUTIONTIMER_H_INCLUDED
+#define JUCE_HIGHRESOLUTIONTIMER_H_INCLUDED
+
+/**
+    A high-resolution periodic timer.
+
+    This provides accurately-timed regular callbacks. Unlike the normal Timer
+    class, this one uses a dedicated thread, not the message thread, so is
+    far more stable and precise.
+
+    You should only use this class in situations where you really need accuracy,
+    because unlike the normal Timer class, which is very lightweight and cheap
+    to start/stop, the HighResolutionTimer will use far more resources, and
+    starting/stopping it may involve launching and killing threads.
+
+    @see Timer
+*/
+class JUCE_API  HighResolutionTimer
+{
+protected:
+    /** Creates a HighResolutionTimer.
+        When created, the timer is stopped, so use startTimer() to get it going.
+    */
+    HighResolutionTimer();
+
+public:
+    /** Destructor. */
+    virtual ~HighResolutionTimer();
+
+    //==============================================================================
+    /** The user-defined callback routine that actually gets called periodically.
+
+        This will be called on a dedicated timer thread, so make sure your
+        implementation is thread-safe!
+
+        It's perfectly ok to call startTimer() or stopTimer() from within this
+        callback to change the subsequent intervals.
+    */
+    virtual void hiResTimerCallback() = 0;
+
+    //==============================================================================
+    /** Starts the timer and sets the length of interval required.
+
+        If the timer is already started, this will reset its counter, so the
+        time between calling this method and the next timer callback will not be
+        less than the interval length passed in.
+
+        @param  intervalInMilliseconds  the interval to use (any values less than 1 will be
+                                        rounded up to 1)
+    */
+    void startTimer (int intervalInMilliseconds);
+
+    /** Stops the timer.
+
+        This method may block while it waits for pending callbacks to complete. Once it
+        returns, no more callbacks will be made. If it is called from the timer's own thread,
+        it will cancel the timer after the current callback returns.
+    */
+    void stopTimer();
+
+    /** Checks if the timer has been started.
+        @returns true if the timer is running.
+    */
+    bool isTimerRunning() const noexcept;
+
+    /** Returns the timer's interval.
+        @returns the timer's interval in milliseconds if it's running, or 0 if it's not.
+    */
+    int getTimerInterval() const noexcept;
+
+private:
+    struct Pimpl;
+    friend struct Pimpl;
+    friend struct ContainerDeletePolicy<Pimpl>;
+    ScopedPointer<Pimpl> pimpl;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HighResolutionTimer)
+};
+
+
+#endif   // JUCE_HIGHRESOLUTIONTIMER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_InterProcessLock.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_InterProcessLock.h
new file mode 100644
index 0000000..dc903b0
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_InterProcessLock.h
@@ -0,0 +1,128 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_INTERPROCESSLOCK_H_INCLUDED
+#define JUCE_INTERPROCESSLOCK_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Acts as a critical section which processes can use to block each other.
+
+    @see CriticalSection
+*/
+class JUCE_API  InterProcessLock
+{
+public:
+    //==============================================================================
+    /** Creates a lock object.
+        @param name   a name that processes will use to identify this lock object
+    */
+    explicit InterProcessLock (const String& name);
+
+    /** Destructor.
+        This will also release the lock if it's currently held by this process.
+    */
+    ~InterProcessLock();
+
+    //==============================================================================
+    /** Attempts to lock the critical section.
+
+        @param timeOutMillisecs  how many milliseconds to wait if the lock is already
+                                 held by another process - a value of 0 will return
+                                 immediately, negative values will wait forever
+        @returns    true if the lock could be gained within the timeout period, or
+                    false if the timeout expired.
+    */
+    bool enter (int timeOutMillisecs = -1);
+
+    /** Releases the lock if it's currently held by this process. */
+    void exit();
+
+    //==============================================================================
+    /**
+        Automatically locks and unlocks an InterProcessLock object.
+
+        This works like a ScopedLock, but using an InterprocessLock rather than
+        a CriticalSection.
+
+        @see ScopedLock
+    */
+    class ScopedLockType
+    {
+    public:
+        //==============================================================================
+        /** Creates a scoped lock.
+
+            As soon as it is created, this will lock the InterProcessLock, and
+            when the ScopedLockType object is deleted, the InterProcessLock will
+            be unlocked.
+
+            Note that since an InterprocessLock can fail due to errors, you should check
+            isLocked() to make sure that the lock was successful before using it.
+
+            Make sure this object is created and deleted by the same thread,
+            otherwise there are no guarantees what will happen! Best just to use it
+            as a local stack object, rather than creating one with the new() operator.
+        */
+        explicit ScopedLockType (InterProcessLock& l)        : ipLock (l) { lockWasSuccessful = l.enter(); }
+
+        /** Destructor.
+
+            The InterProcessLock will be unlocked when the destructor is called.
+
+            Make sure this object is created and deleted by the same thread,
+            otherwise there are no guarantees what will happen!
+        */
+        inline ~ScopedLockType()                             { ipLock.exit(); }
+
+        /** Returns true if the InterProcessLock was successfully locked. */
+        bool isLocked() const noexcept                       { return lockWasSuccessful; }
+
+    private:
+        //==============================================================================
+        InterProcessLock& ipLock;
+        bool lockWasSuccessful;
+
+        JUCE_DECLARE_NON_COPYABLE (ScopedLockType)
+    };
+
+private:
+    //==============================================================================
+    class Pimpl;
+    friend struct ContainerDeletePolicy<Pimpl>;
+    ScopedPointer<Pimpl> pimpl;
+
+    CriticalSection lock;
+    String name;
+
+    JUCE_DECLARE_NON_COPYABLE (InterProcessLock)
+};
+
+
+#endif   // JUCE_INTERPROCESSLOCK_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_Process.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_Process.h
new file mode 100644
index 0000000..f3efd66
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_Process.h
@@ -0,0 +1,153 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_PROCESS_H_INCLUDED
+#define JUCE_PROCESS_H_INCLUDED
+
+
+//==============================================================================
+/** Represents the current executable's process.
+
+    This contains methods for controlling the current application at the
+    process-level.
+
+    @see Thread, JUCEApplicationBase
+*/
+class JUCE_API  Process
+{
+public:
+    //==============================================================================
+    enum ProcessPriority
+    {
+        LowPriority         = 0,
+        NormalPriority      = 1,
+        HighPriority        = 2,
+        RealtimePriority    = 3
+    };
+
+    /** Changes the current process's priority.
+
+        @param priority     the process priority, where
+                            0=low, 1=normal, 2=high, 3=realtime
+    */
+    static void JUCE_CALLTYPE setPriority (const ProcessPriority priority);
+
+    /** Kills the current process immediately.
+
+        This is an emergency process terminator that kills the application
+        immediately - it's intended only for use only when something goes
+        horribly wrong.
+
+        @see JUCEApplicationBase::quit
+    */
+    static void JUCE_CALLTYPE terminate();
+
+    //==============================================================================
+    /** Returns true if this application process is the one that the user is
+        currently using.
+    */
+    static bool JUCE_CALLTYPE isForegroundProcess();
+
+    /** Attempts to make the current process the active one.
+        (This is not possible on some platforms).
+    */
+    static void JUCE_CALLTYPE makeForegroundProcess();
+
+    /** Hides the application (on an OS that supports this, e.g. OSX) */
+    static void JUCE_CALLTYPE hide();
+
+    //==============================================================================
+    /** Raises the current process's privilege level.
+
+        Does nothing if this isn't supported by the current OS, or if process
+        privilege level is fixed.
+    */
+    static void JUCE_CALLTYPE raisePrivilege();
+
+    /** Lowers the current process's privilege level.
+
+        Does nothing if this isn't supported by the current OS, or if process
+        privilege level is fixed.
+    */
+    static void JUCE_CALLTYPE lowerPrivilege();
+
+    //==============================================================================
+    /** Returns true if this process is being hosted by a debugger. */
+    static bool JUCE_CALLTYPE isRunningUnderDebugger();
+
+
+    //==============================================================================
+    /** Tries to launch the OS's default reader application for a given file or URL. */
+    static bool JUCE_CALLTYPE openDocument (const String& documentURL, const String& parameters);
+
+    /** Tries to launch the OS's default email application to let the user create a message. */
+    static bool JUCE_CALLTYPE openEmailWithAttachments (const String& targetEmailAddress,
+                                                        const String& emailSubject,
+                                                        const String& bodyText,
+                                                        const StringArray& filesToAttach);
+
+   #if JUCE_WINDOWS || DOXYGEN
+    //==============================================================================
+    /** WINDOWS ONLY - This returns the HINSTANCE of the current module.
+
+        The return type is a void* to avoid being dependent on windows.h - just cast
+        it to a HINSTANCE to use it.
+
+        In a normal JUCE application, this will be automatically set to the module
+        handle of the executable.
+
+        If you've built a DLL and plan to use any JUCE messaging or windowing classes,
+        you'll need to make sure you call the setCurrentModuleInstanceHandle()
+        to provide the correct module handle in your DllMain() function, because
+        the system relies on the correct instance handle when opening windows.
+    */
+    static void* JUCE_CALLTYPE getCurrentModuleInstanceHandle() noexcept;
+
+    /** WINDOWS ONLY - Sets a new module handle to be used by the library.
+
+        The parameter type is a void* to avoid being dependent on windows.h, but it actually
+        expects a HINSTANCE value.
+
+        @see getCurrentModuleInstanceHandle()
+    */
+    static void JUCE_CALLTYPE setCurrentModuleInstanceHandle (void* newHandle) noexcept;
+   #endif
+
+   #if JUCE_MAC || DOXYGEN
+    //==============================================================================
+    /** OSX ONLY - Shows or hides the OSX dock icon for this app. */
+    static void setDockIconVisible (bool isVisible);
+   #endif
+
+private:
+    Process();
+    JUCE_DECLARE_NON_COPYABLE (Process)
+};
+
+
+#endif   // JUCE_PROCESS_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ReadWriteLock.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ReadWriteLock.cpp
new file mode 100644
index 0000000..a0821b4
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ReadWriteLock.cpp
@@ -0,0 +1,150 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+ReadWriteLock::ReadWriteLock() noexcept
+    : numWaitingWriters (0),
+      numWriters (0),
+      writerThreadId (0)
+{
+    readerThreads.ensureStorageAllocated (16);
+}
+
+ReadWriteLock::~ReadWriteLock() noexcept
+{
+    jassert (readerThreads.size() == 0);
+    jassert (numWriters == 0);
+}
+
+//==============================================================================
+void ReadWriteLock::enterRead() const noexcept
+{
+    while (! tryEnterRead())
+        waitEvent.wait (100);
+}
+
+bool ReadWriteLock::tryEnterRead() const noexcept
+{
+    const Thread::ThreadID threadId = Thread::getCurrentThreadId();
+
+    const SpinLock::ScopedLockType sl (accessLock);
+
+    for (int i = 0; i < readerThreads.size(); ++i)
+    {
+        ThreadRecursionCount& trc = readerThreads.getReference(i);
+
+        if (trc.threadID == threadId)
+        {
+            trc.count++;
+            return true;
+        }
+    }
+
+    if (numWriters + numWaitingWriters == 0
+         || (threadId == writerThreadId && numWriters > 0))
+    {
+        ThreadRecursionCount trc = { threadId, 1 };
+        readerThreads.add (trc);
+        return true;
+    }
+
+    return false;
+}
+
+void ReadWriteLock::exitRead() const noexcept
+{
+    const Thread::ThreadID threadId = Thread::getCurrentThreadId();
+    const SpinLock::ScopedLockType sl (accessLock);
+
+    for (int i = 0; i < readerThreads.size(); ++i)
+    {
+        ThreadRecursionCount& trc = readerThreads.getReference(i);
+
+        if (trc.threadID == threadId)
+        {
+            if (--(trc.count) == 0)
+            {
+                readerThreads.remove (i);
+                waitEvent.signal();
+            }
+
+            return;
+        }
+    }
+
+    jassertfalse; // unlocking a lock that wasn't locked..
+}
+
+//==============================================================================
+void ReadWriteLock::enterWrite() const noexcept
+{
+    const Thread::ThreadID threadId = Thread::getCurrentThreadId();
+    const SpinLock::ScopedLockType sl (accessLock);
+
+    while (! tryEnterWriteInternal (threadId))
+    {
+        ++numWaitingWriters;
+        accessLock.exit();
+        waitEvent.wait (100);
+        accessLock.enter();
+        --numWaitingWriters;
+    }
+}
+
+bool ReadWriteLock::tryEnterWrite() const noexcept
+{
+    const SpinLock::ScopedLockType sl (accessLock);
+    return tryEnterWriteInternal (Thread::getCurrentThreadId());
+}
+
+bool ReadWriteLock::tryEnterWriteInternal (Thread::ThreadID threadId) const noexcept
+{
+    if (readerThreads.size() + numWriters == 0
+         || threadId == writerThreadId
+         || (readerThreads.size() == 1 && readerThreads.getReference(0).threadID == threadId))
+    {
+        writerThreadId = threadId;
+        ++numWriters;
+        return true;
+    }
+
+    return false;
+}
+
+void ReadWriteLock::exitWrite() const noexcept
+{
+    const SpinLock::ScopedLockType sl (accessLock);
+
+    // check this thread actually had the lock..
+    jassert (numWriters > 0 && writerThreadId == Thread::getCurrentThreadId());
+
+    if (--numWriters == 0)
+    {
+        writerThreadId = 0;
+        waitEvent.signal();
+    }
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ReadWriteLock.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ReadWriteLock.h
new file mode 100644
index 0000000..c41d258
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ReadWriteLock.h
@@ -0,0 +1,152 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_READWRITELOCK_H_INCLUDED
+#define JUCE_READWRITELOCK_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A critical section that allows multiple simultaneous readers.
+
+    Features of this type of lock are:
+
+    - Multiple readers can hold the lock at the same time, but only one writer
+      can hold it at once.
+    - Writers trying to gain the lock will be blocked until all readers and writers
+      have released it
+    - Readers trying to gain the lock while a writer is waiting to acquire it will be
+      blocked until the writer has obtained and released it
+    - If a thread already has a read lock and tries to obtain a write lock, it will succeed if
+      there are no other readers
+    - If a thread already has the write lock and tries to obtain a read lock, this will succeed.
+    - Recursive locking is supported.
+
+    @see ScopedReadLock, ScopedWriteLock, CriticalSection
+*/
+class JUCE_API  ReadWriteLock
+{
+public:
+    //==============================================================================
+    /**
+        Creates a ReadWriteLock object.
+    */
+    ReadWriteLock() noexcept;
+
+    /** Destructor.
+        If the object is deleted whilst locked, any subsequent behaviour is undefined.
+    */
+    ~ReadWriteLock() noexcept;
+
+    //==============================================================================
+    /** Locks this object for reading.
+
+        Multiple threads can simultaneously lock the object for reading, but if another
+        thread has it locked for writing, then this will block until it releases the lock.
+
+        @see exitRead, ScopedReadLock
+    */
+    void enterRead() const noexcept;
+
+    /** Tries to lock this object for reading.
+
+        Multiple threads can simultaneously lock the object for reading, but if another
+        thread has it locked for writing, then this will fail and return false.
+
+        @returns true if the lock is successfully gained.
+        @see exitRead, ScopedReadLock
+    */
+    bool tryEnterRead() const noexcept;
+
+    /** Releases the read-lock.
+
+        If the caller thread hasn't got the lock, this can have unpredictable results.
+
+        If the enterRead() method has been called multiple times by the thread, each
+        call must be matched by a call to exitRead() before other threads will be allowed
+        to take over the lock.
+
+        @see enterRead, ScopedReadLock
+    */
+    void exitRead() const noexcept;
+
+    //==============================================================================
+    /** Locks this object for writing.
+
+        This will block until any other threads that have it locked for reading or
+        writing have released their lock.
+
+        @see exitWrite, ScopedWriteLock
+    */
+    void enterWrite() const noexcept;
+
+    /** Tries to lock this object for writing.
+
+        This is like enterWrite(), but doesn't block - it returns true if it manages
+        to obtain the lock.
+
+        @returns true if the lock is successfully gained.
+        @see enterWrite
+    */
+    bool tryEnterWrite() const noexcept;
+
+    /** Releases the write-lock.
+
+        If the caller thread hasn't got the lock, this can have unpredictable results.
+
+        If the enterWrite() method has been called multiple times by the thread, each
+        call must be matched by a call to exit() before other threads will be allowed
+        to take over the lock.
+
+        @see enterWrite, ScopedWriteLock
+    */
+    void exitWrite() const noexcept;
+
+
+private:
+    //==============================================================================
+    SpinLock accessLock;
+    WaitableEvent waitEvent;
+    mutable int numWaitingWriters, numWriters;
+    mutable Thread::ThreadID writerThreadId;
+
+    struct ThreadRecursionCount
+    {
+        Thread::ThreadID threadID;
+        int count;
+    };
+
+    mutable Array <ThreadRecursionCount> readerThreads;
+
+    bool tryEnterWriteInternal (Thread::ThreadID) const noexcept;
+
+    JUCE_DECLARE_NON_COPYABLE (ReadWriteLock)
+};
+
+
+#endif   // JUCE_READWRITELOCK_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ScopedLock.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ScopedLock.h
new file mode 100644
index 0000000..442551a
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ScopedLock.h
@@ -0,0 +1,237 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SCOPEDLOCK_H_INCLUDED
+#define JUCE_SCOPEDLOCK_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Automatically locks and unlocks a mutex object.
+
+    Use one of these as a local variable to provide RAII-based locking of a mutex.
+
+    The templated class could be a CriticalSection, SpinLock, or anything else that
+    provides enter() and exit() methods.
+
+    e.g. @code
+    CriticalSection myCriticalSection;
+
+    for (;;)
+    {
+        const GenericScopedLock<CriticalSection> myScopedLock (myCriticalSection);
+        // myCriticalSection is now locked
+
+        ...do some stuff...
+
+        // myCriticalSection gets unlocked here.
+    }
+    @endcode
+
+    @see GenericScopedUnlock, CriticalSection, SpinLock, ScopedLock, ScopedUnlock
+*/
+template <class LockType>
+class GenericScopedLock
+{
+public:
+    //==============================================================================
+    /** Creates a GenericScopedLock.
+
+        As soon as it is created, this will acquire the lock, and when the GenericScopedLock
+        object is deleted, the lock will be released.
+
+        Make sure this object is created and deleted by the same thread,
+        otherwise there are no guarantees what will happen! Best just to use it
+        as a local stack object, rather than creating one with the new() operator.
+    */
+    inline explicit GenericScopedLock (const LockType& lock) noexcept : lock_ (lock)     { lock.enter(); }
+
+    /** Destructor.
+        The lock will be released when the destructor is called.
+        Make sure this object is created and deleted by the same thread, otherwise there are
+        no guarantees what will happen!
+    */
+    inline ~GenericScopedLock() noexcept                                                 { lock_.exit(); }
+
+private:
+    //==============================================================================
+    const LockType& lock_;
+
+    JUCE_DECLARE_NON_COPYABLE (GenericScopedLock)
+};
+
+
+//==============================================================================
+/**
+    Automatically unlocks and re-locks a mutex object.
+
+    This is the reverse of a GenericScopedLock object - instead of locking the mutex
+    for the lifetime of this object, it unlocks it.
+
+    Make sure you don't try to unlock mutexes that aren't actually locked!
+
+    e.g. @code
+
+    CriticalSection myCriticalSection;
+
+    for (;;)
+    {
+        const GenericScopedLock<CriticalSection> myScopedLock (myCriticalSection);
+        // myCriticalSection is now locked
+
+        ... do some stuff with it locked ..
+
+        while (xyz)
+        {
+            ... do some stuff with it locked ..
+
+            const GenericScopedUnlock<CriticalSection> unlocker (myCriticalSection);
+
+            // myCriticalSection is now unlocked for the remainder of this block,
+            // and re-locked at the end.
+
+            ...do some stuff with it unlocked ...
+        }
+
+        // myCriticalSection gets unlocked here.
+    }
+    @endcode
+
+    @see GenericScopedLock, CriticalSection, ScopedLock, ScopedUnlock
+*/
+template <class LockType>
+class GenericScopedUnlock
+{
+public:
+    //==============================================================================
+    /** Creates a GenericScopedUnlock.
+
+        As soon as it is created, this will unlock the CriticalSection, and
+        when the ScopedLock object is deleted, the CriticalSection will
+        be re-locked.
+
+        Make sure this object is created and deleted by the same thread,
+        otherwise there are no guarantees what will happen! Best just to use it
+        as a local stack object, rather than creating one with the new() operator.
+    */
+    inline explicit GenericScopedUnlock (const LockType& lock) noexcept : lock_ (lock)   { lock.exit(); }
+
+    /** Destructor.
+
+        The CriticalSection will be unlocked when the destructor is called.
+
+        Make sure this object is created and deleted by the same thread,
+        otherwise there are no guarantees what will happen!
+    */
+    inline ~GenericScopedUnlock() noexcept                                               { lock_.enter(); }
+
+
+private:
+    //==============================================================================
+    const LockType& lock_;
+
+    JUCE_DECLARE_NON_COPYABLE (GenericScopedUnlock)
+};
+
+
+//==============================================================================
+/**
+    Automatically locks and unlocks a mutex object.
+
+    Use one of these as a local variable to provide RAII-based locking of a mutex.
+
+    The templated class could be a CriticalSection, SpinLock, or anything else that
+    provides enter() and exit() methods.
+
+    e.g. @code
+
+    CriticalSection myCriticalSection;
+
+    for (;;)
+    {
+        const GenericScopedTryLock<CriticalSection> myScopedTryLock (myCriticalSection);
+
+        // Unlike using a ScopedLock, this may fail to actually get the lock, so you
+        // should test this with the isLocked() method before doing your thread-unsafe
+        // action..
+        if (myScopedTryLock.isLocked())
+        {
+           ...do some stuff...
+        }
+        else
+        {
+            ..our attempt at locking failed because another thread had already locked it..
+        }
+
+        // myCriticalSection gets unlocked here (if it was locked)
+    }
+    @endcode
+
+    @see CriticalSection::tryEnter, GenericScopedLock, GenericScopedUnlock
+*/
+template <class LockType>
+class GenericScopedTryLock
+{
+public:
+    //==============================================================================
+    /** Creates a GenericScopedTryLock.
+
+        As soon as it is created, this will attempt to acquire the lock, and when the
+        GenericScopedTryLock is deleted, the lock will be released (if the lock was
+        successfully acquired).
+
+        Make sure this object is created and deleted by the same thread,
+        otherwise there are no guarantees what will happen! Best just to use it
+        as a local stack object, rather than creating one with the new() operator.
+    */
+    inline explicit GenericScopedTryLock (const LockType& lock) noexcept
+        : lock_ (lock), lockWasSuccessful (lock.tryEnter()) {}
+
+    /** Destructor.
+
+        The mutex will be unlocked (if it had been successfully locked) when the
+        destructor is called.
+
+        Make sure this object is created and deleted by the same thread,
+        otherwise there are no guarantees what will happen!
+    */
+    inline ~GenericScopedTryLock() noexcept         { if (lockWasSuccessful) lock_.exit(); }
+
+    /** Returns true if the mutex was successfully locked. */
+    bool isLocked() const noexcept                  { return lockWasSuccessful; }
+
+private:
+    //==============================================================================
+    const LockType& lock_;
+    const bool lockWasSuccessful;
+
+    JUCE_DECLARE_NON_COPYABLE (GenericScopedTryLock)
+};
+
+
+#endif   // JUCE_SCOPEDLOCK_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ScopedReadLock.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ScopedReadLock.h
new file mode 100644
index 0000000..107e838
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ScopedReadLock.h
@@ -0,0 +1,90 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SCOPEDREADLOCK_H_INCLUDED
+#define JUCE_SCOPEDREADLOCK_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Automatically locks and unlocks a ReadWriteLock object.
+
+    Use one of these as a local variable to control access to a ReadWriteLock.
+
+    e.g. @code
+
+    ReadWriteLock myLock;
+
+    for (;;)
+    {
+        const ScopedReadLock myScopedLock (myLock);
+        // myLock is now locked
+
+        ...do some stuff...
+
+        // myLock gets unlocked here.
+    }
+    @endcode
+
+    @see ReadWriteLock, ScopedWriteLock
+*/
+class JUCE_API  ScopedReadLock
+{
+public:
+    //==============================================================================
+    /** Creates a ScopedReadLock.
+
+        As soon as it is created, this will call ReadWriteLock::enterRead(), and
+        when the ScopedReadLock object is deleted, the ReadWriteLock will
+        be unlocked.
+
+        Make sure this object is created and deleted by the same thread,
+        otherwise there are no guarantees what will happen! Best just to use it
+        as a local stack object, rather than creating one with the new() operator.
+    */
+    inline explicit ScopedReadLock (const ReadWriteLock& lock) noexcept   : lock_ (lock) { lock.enterRead(); }
+
+    /** Destructor.
+
+        The ReadWriteLock's exitRead() method will be called when the destructor is called.
+
+        Make sure this object is created and deleted by the same thread,
+        otherwise there are no guarantees what will happen!
+    */
+    inline ~ScopedReadLock() noexcept                                     { lock_.exitRead(); }
+
+
+private:
+    //==============================================================================
+    const ReadWriteLock& lock_;
+
+    JUCE_DECLARE_NON_COPYABLE (ScopedReadLock)
+};
+
+
+#endif   // JUCE_SCOPEDREADLOCK_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ScopedWriteLock.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ScopedWriteLock.h
new file mode 100644
index 0000000..44e3198
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ScopedWriteLock.h
@@ -0,0 +1,90 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SCOPEDWRITELOCK_H_INCLUDED
+#define JUCE_SCOPEDWRITELOCK_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Automatically locks and unlocks a ReadWriteLock object.
+
+    Use one of these as a local variable to control access to a ReadWriteLock.
+
+    e.g. @code
+
+    ReadWriteLock myLock;
+
+    for (;;)
+    {
+        const ScopedWriteLock myScopedLock (myLock);
+        // myLock is now locked
+
+        ...do some stuff...
+
+        // myLock gets unlocked here.
+    }
+    @endcode
+
+    @see ReadWriteLock, ScopedReadLock
+*/
+class JUCE_API  ScopedWriteLock
+{
+public:
+    //==============================================================================
+    /** Creates a ScopedWriteLock.
+
+        As soon as it is created, this will call ReadWriteLock::enterWrite(), and
+        when the ScopedWriteLock object is deleted, the ReadWriteLock will
+        be unlocked.
+
+        Make sure this object is created and deleted by the same thread,
+        otherwise there are no guarantees what will happen! Best just to use it
+        as a local stack object, rather than creating one with the new() operator.
+    */
+    inline explicit ScopedWriteLock (const ReadWriteLock& lock) noexcept : lock_ (lock) { lock.enterWrite(); }
+
+    /** Destructor.
+
+        The ReadWriteLock's exitWrite() method will be called when the destructor is called.
+
+        Make sure this object is created and deleted by the same thread,
+        otherwise there are no guarantees what will happen!
+    */
+    inline ~ScopedWriteLock() noexcept                                   { lock_.exitWrite(); }
+
+
+private:
+    //==============================================================================
+    const ReadWriteLock& lock_;
+
+    JUCE_DECLARE_NON_COPYABLE (ScopedWriteLock)
+};
+
+
+#endif   // JUCE_SCOPEDWRITELOCK_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_SpinLock.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_SpinLock.h
new file mode 100644
index 0000000..664cc3c
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_SpinLock.h
@@ -0,0 +1,91 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_SPINLOCK_H_INCLUDED
+#define JUCE_SPINLOCK_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A simple spin-lock class that can be used as a simple, low-overhead mutex for
+    uncontended situations.
+
+    Note that unlike a CriticalSection, this type of lock is not re-entrant, and may
+    be less efficient when used it a highly contended situation, but it's very small and
+    requires almost no initialisation.
+    It's most appropriate for simple situations where you're only going to hold the
+    lock for a very brief time.
+
+    @see CriticalSection
+*/
+class JUCE_API  SpinLock
+{
+public:
+    inline SpinLock() noexcept {}
+    inline ~SpinLock() noexcept {}
+
+    /** Acquires the lock.
+        This will block until the lock has been successfully acquired by this thread.
+        Note that a SpinLock is NOT re-entrant, and is not smart enough to know whether the
+        caller thread already has the lock - so if a thread tries to acquire a lock that it
+        already holds, this method will never return!
+
+        It's strongly recommended that you never call this method directly - instead use the
+        ScopedLockType class to manage the locking using an RAII pattern instead.
+    */
+    void enter() const noexcept;
+
+    /** Attempts to acquire the lock, returning true if this was successful. */
+    inline bool tryEnter() const noexcept
+    {
+        return lock.compareAndSetBool (1, 0);
+    }
+
+    /** Releases the lock. */
+    inline void exit() const noexcept
+    {
+        jassert (lock.value == 1); // Agh! Releasing a lock that isn't currently held!
+        lock = 0;
+    }
+
+    //==============================================================================
+    /** Provides the type of scoped lock to use for locking a SpinLock. */
+    typedef GenericScopedLock <SpinLock>       ScopedLockType;
+
+    /** Provides the type of scoped unlocker to use with a SpinLock. */
+    typedef GenericScopedUnlock <SpinLock>     ScopedUnlockType;
+
+private:
+    //==============================================================================
+    mutable Atomic<int> lock;
+
+    JUCE_DECLARE_NON_COPYABLE (SpinLock)
+};
+
+
+#endif   // JUCE_SPINLOCK_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_Thread.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_Thread.cpp
new file mode 100644
index 0000000..3d1ff0a
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_Thread.cpp
@@ -0,0 +1,371 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+Thread::Thread (const String& threadName_)
+    : threadName (threadName_),
+      threadHandle (nullptr),
+      threadId (0),
+      threadPriority (5),
+      affinityMask (0),
+      shouldExit (false)
+{
+}
+
+Thread::~Thread()
+{
+    /* If your thread class's destructor has been called without first stopping the thread, that
+       means that this partially destructed object is still performing some work - and that's
+       probably a Bad Thing!
+
+       To avoid this type of nastiness, always make sure you call stopThread() before or during
+       your subclass's destructor.
+    */
+    jassert (! isThreadRunning());
+
+    stopThread (-1);
+}
+
+//==============================================================================
+// Use a ref-counted object to hold this shared data, so that it can outlive its static
+// shared pointer when threads are still running during static shutdown.
+struct CurrentThreadHolder   : public ReferenceCountedObject
+{
+    CurrentThreadHolder() noexcept {}
+
+    typedef ReferenceCountedObjectPtr <CurrentThreadHolder> Ptr;
+    ThreadLocalValue<Thread*> value;
+
+    JUCE_DECLARE_NON_COPYABLE (CurrentThreadHolder)
+};
+
+static char currentThreadHolderLock [sizeof (SpinLock)]; // (statically initialised to zeros).
+
+static SpinLock* castToSpinLockWithoutAliasingWarning (void* s)
+{
+    return static_cast<SpinLock*> (s);
+}
+
+static CurrentThreadHolder::Ptr getCurrentThreadHolder()
+{
+    static CurrentThreadHolder::Ptr currentThreadHolder;
+    SpinLock::ScopedLockType lock (*castToSpinLockWithoutAliasingWarning (currentThreadHolderLock));
+
+    if (currentThreadHolder == nullptr)
+        currentThreadHolder = new CurrentThreadHolder();
+
+    return currentThreadHolder;
+}
+
+void Thread::threadEntryPoint()
+{
+    const CurrentThreadHolder::Ptr currentThreadHolder (getCurrentThreadHolder());
+    currentThreadHolder->value = this;
+
+    JUCE_TRY
+    {
+        if (threadName.isNotEmpty())
+            setCurrentThreadName (threadName);
+
+        if (startSuspensionEvent.wait (10000))
+        {
+            jassert (getCurrentThreadId() == threadId);
+
+            if (affinityMask != 0)
+                setCurrentThreadAffinityMask (affinityMask);
+
+            run();
+        }
+    }
+    JUCE_CATCH_ALL_ASSERT
+
+    currentThreadHolder->value.releaseCurrentThreadStorage();
+    closeThreadHandle();
+}
+
+// used to wrap the incoming call from the platform-specific code
+void JUCE_API juce_threadEntryPoint (void* userData)
+{
+    static_cast <Thread*> (userData)->threadEntryPoint();
+}
+
+//==============================================================================
+void Thread::startThread()
+{
+    const ScopedLock sl (startStopLock);
+
+    shouldExit = false;
+
+    if (threadHandle == nullptr)
+    {
+        launchThread();
+        setThreadPriority (threadHandle, threadPriority);
+        startSuspensionEvent.signal();
+    }
+}
+
+void Thread::startThread (const int priority)
+{
+    const ScopedLock sl (startStopLock);
+
+    if (threadHandle == nullptr)
+    {
+        threadPriority = priority;
+        startThread();
+    }
+    else
+    {
+        setPriority (priority);
+    }
+}
+
+bool Thread::isThreadRunning() const
+{
+    return threadHandle != nullptr;
+}
+
+Thread* JUCE_CALLTYPE Thread::getCurrentThread()
+{
+    return getCurrentThreadHolder()->value.get();
+}
+
+//==============================================================================
+void Thread::signalThreadShouldExit()
+{
+    shouldExit = true;
+}
+
+bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const
+{
+    // Doh! So how exactly do you expect this thread to wait for itself to stop??
+    jassert (getThreadId() != getCurrentThreadId() || getCurrentThreadId() == 0);
+
+    const uint32 timeoutEnd = Time::getMillisecondCounter() + (uint32) timeOutMilliseconds;
+
+    while (isThreadRunning())
+    {
+        if (timeOutMilliseconds >= 0 && Time::getMillisecondCounter() > timeoutEnd)
+            return false;
+
+        sleep (2);
+    }
+
+    return true;
+}
+
+bool Thread::stopThread (const int timeOutMilliseconds)
+{
+    // agh! You can't stop the thread that's calling this method! How on earth
+    // would that work??
+    jassert (getCurrentThreadId() != getThreadId());
+
+    const ScopedLock sl (startStopLock);
+
+    if (isThreadRunning())
+    {
+        signalThreadShouldExit();
+        notify();
+
+        if (timeOutMilliseconds != 0)
+            waitForThreadToExit (timeOutMilliseconds);
+
+        if (isThreadRunning())
+        {
+            // very bad karma if this point is reached, as there are bound to be
+            // locks and events left in silly states when a thread is killed by force..
+            jassertfalse;
+            Logger::writeToLog ("!! killing thread by force !!");
+
+            killThread();
+
+            threadHandle = nullptr;
+            threadId = 0;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+//==============================================================================
+bool Thread::setPriority (const int newPriority)
+{
+    // NB: deadlock possible if you try to set the thread prio from the thread itself,
+    // so using setCurrentThreadPriority instead in that case.
+    if (getCurrentThreadId() == getThreadId())
+        return setCurrentThreadPriority (newPriority);
+
+    const ScopedLock sl (startStopLock);
+
+    if ((! isThreadRunning()) || setThreadPriority (threadHandle, newPriority))
+    {
+        threadPriority = newPriority;
+        return true;
+    }
+
+    return false;
+}
+
+bool Thread::setCurrentThreadPriority (const int newPriority)
+{
+    return setThreadPriority (0, newPriority);
+}
+
+void Thread::setAffinityMask (const uint32 newAffinityMask)
+{
+    affinityMask = newAffinityMask;
+}
+
+//==============================================================================
+bool Thread::wait (const int timeOutMilliseconds) const
+{
+    return defaultEvent.wait (timeOutMilliseconds);
+}
+
+void Thread::notify() const
+{
+    defaultEvent.signal();
+}
+
+//==============================================================================
+void SpinLock::enter() const noexcept
+{
+    if (! tryEnter())
+    {
+        for (int i = 20; --i >= 0;)
+            if (tryEnter())
+                return;
+
+        while (! tryEnter())
+            Thread::yield();
+    }
+}
+
+//==============================================================================
+#if JUCE_UNIT_TESTS
+
+class AtomicTests  : public UnitTest
+{
+public:
+    AtomicTests() : UnitTest ("Atomics") {}
+
+    void runTest()
+    {
+        beginTest ("Misc");
+
+        char a1[7];
+        expect (numElementsInArray(a1) == 7);
+        int a2[3];
+        expect (numElementsInArray(a2) == 3);
+
+        expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211);
+        expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
+        expect (ByteOrder::swap ((uint64) 0x1122334455667788ULL) == 0x8877665544332211LL);
+
+        beginTest ("Atomic int");
+        AtomicTester <int>::testInteger (*this);
+        beginTest ("Atomic unsigned int");
+        AtomicTester <unsigned int>::testInteger (*this);
+        beginTest ("Atomic int32");
+        AtomicTester <int32>::testInteger (*this);
+        beginTest ("Atomic uint32");
+        AtomicTester <uint32>::testInteger (*this);
+        beginTest ("Atomic long");
+        AtomicTester <long>::testInteger (*this);
+        beginTest ("Atomic void*");
+        AtomicTester <void*>::testInteger (*this);
+        beginTest ("Atomic int*");
+        AtomicTester <int*>::testInteger (*this);
+        beginTest ("Atomic float");
+        AtomicTester <float>::testFloat (*this);
+      #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE  // 64-bit intrinsics aren't available on some old platforms
+        beginTest ("Atomic int64");
+        AtomicTester <int64>::testInteger (*this);
+        beginTest ("Atomic uint64");
+        AtomicTester <uint64>::testInteger (*this);
+        beginTest ("Atomic double");
+        AtomicTester <double>::testFloat (*this);
+      #endif
+    }
+
+    template <typename Type>
+    class AtomicTester
+    {
+    public:
+        AtomicTester() {}
+
+        static void testInteger (UnitTest& test)
+        {
+            Atomic<Type> a, b;
+            a.set ((Type) 10);
+            test.expect (a.value == (Type) 10);
+            test.expect (a.get() == (Type) 10);
+            a += (Type) 15;
+            test.expect (a.get() == (Type) 25);
+            a.memoryBarrier();
+            a -= (Type) 5;
+            test.expect (a.get() == (Type) 20);
+            test.expect (++a == (Type) 21);
+            ++a;
+            test.expect (--a == (Type) 21);
+            test.expect (a.get() == (Type) 21);
+            a.memoryBarrier();
+
+            testFloat (test);
+        }
+
+        static void testFloat (UnitTest& test)
+        {
+            Atomic<Type> a, b;
+            a = (Type) 21;
+            a.memoryBarrier();
+
+            /*  These are some simple test cases to check the atomics - let me know
+                if any of these assertions fail on your system!
+            */
+            test.expect (a.get() == (Type) 21);
+            test.expect (a.compareAndSetValue ((Type) 100, (Type) 50) == (Type) 21);
+            test.expect (a.get() == (Type) 21);
+            test.expect (a.compareAndSetValue ((Type) 101, a.get()) == (Type) 21);
+            test.expect (a.get() == (Type) 101);
+            test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200));
+            test.expect (a.get() == (Type) 101);
+            test.expect (a.compareAndSetBool ((Type) 200, a.get()));
+            test.expect (a.get() == (Type) 200);
+
+            test.expect (a.exchange ((Type) 300) == (Type) 200);
+            test.expect (a.get() == (Type) 300);
+
+            b = a;
+            test.expect (b.get() == a.get());
+        }
+    };
+};
+
+static AtomicTests atomicUnitTests;
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_Thread.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_Thread.h
new file mode 100644
index 0000000..aef96b7
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_Thread.h
@@ -0,0 +1,289 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_THREAD_H_INCLUDED
+#define JUCE_THREAD_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Encapsulates a thread.
+
+    Subclasses derive from Thread and implement the run() method, in which they
+    do their business. The thread can then be started with the startThread() method
+    and controlled with various other methods.
+
+    This class also contains some thread-related static methods, such
+    as sleep(), yield(), getCurrentThreadId() etc.
+
+    @see CriticalSection, WaitableEvent, Process, ThreadWithProgressWindow,
+         MessageManagerLock
+*/
+class JUCE_API  Thread
+{
+public:
+    //==============================================================================
+    /**
+        Creates a thread.
+
+        When first created, the thread is not running. Use the startThread()
+        method to start it.
+    */
+    explicit Thread (const String& threadName);
+
+    /** Destructor.
+
+        You must never attempt to delete a Thread object while it's still running -
+        always call stopThread() and make sure your thread has stopped before deleting
+        the object. Failing to do so will throw an assertion, and put you firmly into
+        undefined behaviour territory.
+    */
+    virtual ~Thread();
+
+    //==============================================================================
+    /** Must be implemented to perform the thread's actual code.
+
+        Remember that the thread must regularly check the threadShouldExit()
+        method whilst running, and if this returns true it should return from
+        the run() method as soon as possible to avoid being forcibly killed.
+
+        @see threadShouldExit, startThread
+    */
+    virtual void run() = 0;
+
+    //==============================================================================
+    // Thread control functions..
+
+    /** Starts the thread running.
+
+        This will cause the thread's run() method to be called by a new thread.
+        If this thread is already running, startThread() won't do anything.
+
+        @see stopThread
+    */
+    void startThread();
+
+    /** Starts the thread with a given priority.
+
+        Launches the thread with a given priority, where 0 = lowest, 10 = highest.
+        If the thread is already running, its priority will be changed.
+
+        @see startThread, setPriority
+    */
+    void startThread (int priority);
+
+    /** Attempts to stop the thread running.
+
+        This method will cause the threadShouldExit() method to return true
+        and call notify() in case the thread is currently waiting.
+
+        Hopefully the thread will then respond to this by exiting cleanly, and
+        the stopThread method will wait for a given time-period for this to
+        happen.
+
+        If the thread is stuck and fails to respond after the time-out, it gets
+        forcibly killed, which is a very bad thing to happen, as it could still
+        be holding locks, etc. which are needed by other parts of your program.
+
+        @param timeOutMilliseconds  The number of milliseconds to wait for the
+                                    thread to finish before killing it by force. A negative
+                                    value in here will wait forever.
+        @returns    true if the thread was cleanly stopped before the timeout, or false
+                    if it had to be killed by force.
+        @see signalThreadShouldExit, threadShouldExit, waitForThreadToExit, isThreadRunning
+    */
+    bool stopThread (int timeOutMilliseconds);
+
+    //==============================================================================
+    /** Returns true if the thread is currently active */
+    bool isThreadRunning() const;
+
+    /** Sets a flag to tell the thread it should stop.
+
+        Calling this means that the threadShouldExit() method will then return true.
+        The thread should be regularly checking this to see whether it should exit.
+
+        If your thread makes use of wait(), you might want to call notify() after calling
+        this method, to interrupt any waits that might be in progress, and allow it
+        to reach a point where it can exit.
+
+        @see threadShouldExit
+        @see waitForThreadToExit
+    */
+    void signalThreadShouldExit();
+
+    /** Checks whether the thread has been told to stop running.
+
+        Threads need to check this regularly, and if it returns true, they should
+        return from their run() method at the first possible opportunity.
+
+        @see signalThreadShouldExit
+    */
+    inline bool threadShouldExit() const                { return shouldExit; }
+
+    /** Waits for the thread to stop.
+
+        This will waits until isThreadRunning() is false or until a timeout expires.
+
+        @param timeOutMilliseconds  the time to wait, in milliseconds. If this value
+                                    is less than zero, it will wait forever.
+        @returns    true if the thread exits, or false if the timeout expires first.
+    */
+    bool waitForThreadToExit (int timeOutMilliseconds) const;
+
+    //==============================================================================
+    /** Changes the thread's priority.
+        May return false if for some reason the priority can't be changed.
+
+        @param priority     the new priority, in the range 0 (lowest) to 10 (highest). A priority
+                            of 5 is normal.
+    */
+    bool setPriority (int priority);
+
+    /** Changes the priority of the caller thread.
+
+        Similar to setPriority(), but this static method acts on the caller thread.
+        May return false if for some reason the priority can't be changed.
+
+        @see setPriority
+    */
+    static bool setCurrentThreadPriority (int priority);
+
+    //==============================================================================
+    /** Sets the affinity mask for the thread.
+
+        This will only have an effect next time the thread is started - i.e. if the
+        thread is already running when called, it'll have no effect.
+
+        @see setCurrentThreadAffinityMask
+    */
+    void setAffinityMask (uint32 affinityMask);
+
+    /** Changes the affinity mask for the caller thread.
+        This will change the affinity mask for the thread that calls this static method.
+        @see setAffinityMask
+    */
+    static void JUCE_CALLTYPE setCurrentThreadAffinityMask (uint32 affinityMask);
+
+    //==============================================================================
+    // this can be called from any thread that needs to pause..
+    static void JUCE_CALLTYPE sleep (int milliseconds);
+
+    /** Yields the calling thread's current time-slot. */
+    static void JUCE_CALLTYPE yield();
+
+    //==============================================================================
+    /** Makes the thread wait for a notification.
+
+        This puts the thread to sleep until either the timeout period expires, or
+        another thread calls the notify() method to wake it up.
+
+        A negative time-out value means that the method will wait indefinitely.
+
+        @returns    true if the event has been signalled, false if the timeout expires.
+    */
+    bool wait (int timeOutMilliseconds) const;
+
+    /** Wakes up the thread.
+
+        If the thread has called the wait() method, this will wake it up.
+
+        @see wait
+    */
+    void notify() const;
+
+    //==============================================================================
+    /** A value type used for thread IDs.
+        @see getCurrentThreadId(), getThreadId()
+    */
+    typedef void* ThreadID;
+
+    /** Returns an id that identifies the caller thread.
+
+        To find the ID of a particular thread object, use getThreadId().
+
+        @returns    a unique identifier that identifies the calling thread.
+        @see getThreadId
+    */
+    static ThreadID JUCE_CALLTYPE getCurrentThreadId();
+
+    /** Finds the thread object that is currently running.
+
+        Note that the main UI thread (or other non-Juce threads) don't have a Thread
+        object associated with them, so this will return 0.
+    */
+    static Thread* JUCE_CALLTYPE getCurrentThread();
+
+    /** Returns the ID of this thread.
+
+        That means the ID of this thread object - not of the thread that's calling the method.
+
+        This can change when the thread is started and stopped, and will be invalid if the
+        thread's not actually running.
+
+        @see getCurrentThreadId
+    */
+    ThreadID getThreadId() const noexcept                           { return threadId; }
+
+    /** Returns the name of the thread.
+
+        This is the name that gets set in the constructor.
+    */
+    const String& getThreadName() const                             { return threadName; }
+
+    /** Changes the name of the caller thread.
+        Different OSes may place different length or content limits on this name.
+    */
+    static void JUCE_CALLTYPE setCurrentThreadName (const String& newThreadName);
+
+
+private:
+    //==============================================================================
+    const String threadName;
+    void* volatile threadHandle;
+    ThreadID threadId;
+    CriticalSection startStopLock;
+    WaitableEvent startSuspensionEvent, defaultEvent;
+    int threadPriority;
+    uint32 affinityMask;
+    bool volatile shouldExit;
+
+   #ifndef DOXYGEN
+    friend void JUCE_API juce_threadEntryPoint (void*);
+   #endif
+
+    void launchThread();
+    void closeThreadHandle();
+    void killThread();
+    void threadEntryPoint();
+    static bool setThreadPriority (void*, int);
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Thread)
+};
+
+#endif   // JUCE_THREAD_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ThreadLocalValue.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ThreadLocalValue.h
new file mode 100644
index 0000000..bd5c808
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ThreadLocalValue.h
@@ -0,0 +1,198 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_THREADLOCALVALUE_H_INCLUDED
+#define JUCE_THREADLOCALVALUE_H_INCLUDED
+
+// (NB: on win32, native thread-locals aren't possible in a dynamically loaded DLL in XP).
+#if ! ((JUCE_MSVC && (JUCE_64BIT || ! defined (JucePlugin_PluginCode))) \
+       || (JUCE_MAC && JUCE_CLANG && defined (MAC_OS_X_VERSION_10_7) \
+             && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7))
+ #define JUCE_NO_COMPILER_THREAD_LOCAL 1
+#endif
+
+//==============================================================================
+/**
+    Provides cross-platform support for thread-local objects.
+
+    This class holds an internal list of objects of the templated type, keeping
+    an instance for each thread that requests one. The first time a thread attempts
+    to access its value, an object is created and added to the list for that thread.
+
+    Typically, you'll probably want to create a static instance of a ThreadLocalValue
+    object, or hold one within a singleton.
+
+    The templated class for your value must be a primitive type, or a simple POD struct.
+
+    When a thread no longer needs to use its value, it can call releaseCurrentThreadStorage()
+    to allow the storage to be re-used by another thread. If a thread exits without calling
+    this method, the object storage will be left allocated until the ThreadLocalValue object
+    is deleted.
+*/
+template <typename Type>
+class ThreadLocalValue
+{
+public:
+    /** */
+    ThreadLocalValue() noexcept
+    {
+    }
+
+    /** Destructor.
+        When this object is deleted, all the value objects for all threads will be deleted.
+    */
+    ~ThreadLocalValue()
+    {
+       #if JUCE_NO_COMPILER_THREAD_LOCAL
+        for (ObjectHolder* o = first.value; o != nullptr;)
+        {
+            ObjectHolder* const next = o->next;
+            delete o;
+            o = next;
+        }
+       #endif
+    }
+
+    /** Returns a reference to this thread's instance of the value.
+        Note that the first time a thread tries to access the value, an instance of the
+        value object will be created - so if your value's class has a non-trivial
+        constructor, be aware that this method could invoke it.
+    */
+    Type& operator*() const noexcept                        { return get(); }
+
+    /** Returns a pointer to this thread's instance of the value.
+        Note that the first time a thread tries to access the value, an instance of the
+        value object will be created - so if your value's class has a non-trivial
+        constructor, be aware that this method could invoke it.
+    */
+    operator Type*() const noexcept                         { return &get(); }
+
+    /** Accesses a method or field of the value object.
+        Note that the first time a thread tries to access the value, an instance of the
+        value object will be created - so if your value's class has a non-trivial
+        constructor, be aware that this method could invoke it.
+    */
+    Type* operator->() const noexcept                       { return &get(); }
+
+    /** Assigns a new value to the thread-local object. */
+    ThreadLocalValue& operator= (const Type& newValue)      { get() = newValue; return *this; }
+
+    /** Returns a reference to this thread's instance of the value.
+        Note that the first time a thread tries to access the value, an instance of the
+        value object will be created - so if your value's class has a non-trivial
+        constructor, be aware that this method could invoke it.
+    */
+    Type& get() const noexcept
+    {
+       #if JUCE_NO_COMPILER_THREAD_LOCAL
+        const Thread::ThreadID threadId = Thread::getCurrentThreadId();
+
+        for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
+            if (o->threadId == threadId)
+                return o->object;
+
+        for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
+        {
+            if (o->threadId == nullptr)
+            {
+                {
+                    SpinLock::ScopedLockType sl (lock);
+
+                    if (o->threadId != nullptr)
+                        continue;
+
+                    o->threadId = threadId;
+                }
+
+                o->object = Type();
+                return o->object;
+            }
+        }
+
+        ObjectHolder* const newObject = new ObjectHolder (threadId);
+
+        do
+        {
+            newObject->next = first.get();
+        }
+        while (! first.compareAndSetBool (newObject, newObject->next));
+
+        return newObject->object;
+       #elif JUCE_MAC
+        static __thread Type object;
+        return object;
+       #elif JUCE_MSVC
+        static __declspec(thread) Type object;
+        return object;
+       #endif
+    }
+
+    /** Called by a thread before it terminates, to allow this class to release
+        any storage associated with the thread.
+    */
+    void releaseCurrentThreadStorage()
+    {
+       #if JUCE_NO_COMPILER_THREAD_LOCAL
+        const Thread::ThreadID threadId = Thread::getCurrentThreadId();
+
+        for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
+        {
+            if (o->threadId == threadId)
+            {
+                SpinLock::ScopedLockType sl (lock);
+                o->threadId = nullptr;
+            }
+        }
+       #endif
+    }
+
+private:
+    //==============================================================================
+   #if JUCE_NO_COMPILER_THREAD_LOCAL
+    struct ObjectHolder
+    {
+        ObjectHolder (const Thread::ThreadID& tid)
+            : threadId (tid), next (nullptr), object()
+        {}
+
+        Thread::ThreadID threadId;
+        ObjectHolder* next;
+        Type object;
+
+        JUCE_DECLARE_NON_COPYABLE (ObjectHolder)
+    };
+
+    mutable Atomic<ObjectHolder*> first;
+    SpinLock lock;
+   #endif
+
+    JUCE_DECLARE_NON_COPYABLE (ThreadLocalValue)
+};
+
+
+#endif   // JUCE_THREADLOCALVALUE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ThreadPool.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ThreadPool.cpp
new file mode 100644
index 0000000..e6b0b9f
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ThreadPool.cpp
@@ -0,0 +1,384 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+class ThreadPool::ThreadPoolThread  : public Thread
+{
+public:
+    ThreadPoolThread (ThreadPool& p)
+       : Thread ("Pool"), currentJob (nullptr), pool (p)
+    {
+    }
+
+    void run() override
+    {
+        while (! threadShouldExit())
+            if (! pool.runNextJob (*this))
+                wait (500);
+    }
+
+    ThreadPoolJob* volatile currentJob;
+    ThreadPool& pool;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolThread)
+};
+
+//==============================================================================
+ThreadPoolJob::ThreadPoolJob (const String& name)
+    : jobName (name), pool (nullptr),
+      shouldStop (false), isActive (false), shouldBeDeleted (false)
+{
+}
+
+ThreadPoolJob::~ThreadPoolJob()
+{
+    // you mustn't delete a job while it's still in a pool! Use ThreadPool::removeJob()
+    // to remove it first!
+    jassert (pool == nullptr || ! pool->contains (this));
+}
+
+String ThreadPoolJob::getJobName() const
+{
+    return jobName;
+}
+
+void ThreadPoolJob::setJobName (const String& newName)
+{
+    jobName = newName;
+}
+
+void ThreadPoolJob::signalJobShouldExit()
+{
+    shouldStop = true;
+}
+
+ThreadPoolJob* ThreadPoolJob::getCurrentThreadPoolJob()
+{
+    if (ThreadPool::ThreadPoolThread* t = dynamic_cast<ThreadPool::ThreadPoolThread*> (Thread::getCurrentThread()))
+        return t->currentJob;
+
+    return nullptr;
+}
+
+//==============================================================================
+ThreadPool::ThreadPool (const int numThreads)
+{
+    jassert (numThreads > 0); // not much point having a pool without any threads!
+
+    createThreads (numThreads);
+}
+
+ThreadPool::ThreadPool()
+{
+    createThreads (SystemStats::getNumCpus());
+}
+
+ThreadPool::~ThreadPool()
+{
+    removeAllJobs (true, 5000);
+    stopThreads();
+}
+
+void ThreadPool::createThreads (int numThreads)
+{
+    for (int i = jmax (1, numThreads); --i >= 0;)
+        threads.add (new ThreadPoolThread (*this));
+
+    for (int i = threads.size(); --i >= 0;)
+        threads.getUnchecked(i)->startThread();
+}
+
+void ThreadPool::stopThreads()
+{
+    for (int i = threads.size(); --i >= 0;)
+        threads.getUnchecked(i)->signalThreadShouldExit();
+
+    for (int i = threads.size(); --i >= 0;)
+        threads.getUnchecked(i)->stopThread (500);
+}
+
+void ThreadPool::addJob (ThreadPoolJob* const job, const bool deleteJobWhenFinished)
+{
+    jassert (job != nullptr);
+    jassert (job->pool == nullptr);
+
+    if (job->pool == nullptr)
+    {
+        job->pool = this;
+        job->shouldStop = false;
+        job->isActive = false;
+        job->shouldBeDeleted = deleteJobWhenFinished;
+
+        {
+            const ScopedLock sl (lock);
+            jobs.add (job);
+        }
+
+        for (int i = threads.size(); --i >= 0;)
+            threads.getUnchecked(i)->notify();
+    }
+}
+
+int ThreadPool::getNumJobs() const
+{
+    return jobs.size();
+}
+
+ThreadPoolJob* ThreadPool::getJob (const int index) const
+{
+    const ScopedLock sl (lock);
+    return jobs [index];
+}
+
+bool ThreadPool::contains (const ThreadPoolJob* const job) const
+{
+    const ScopedLock sl (lock);
+    return jobs.contains (const_cast <ThreadPoolJob*> (job));
+}
+
+bool ThreadPool::isJobRunning (const ThreadPoolJob* const job) const
+{
+    const ScopedLock sl (lock);
+    return jobs.contains (const_cast <ThreadPoolJob*> (job)) && job->isActive;
+}
+
+bool ThreadPool::waitForJobToFinish (const ThreadPoolJob* const job, const int timeOutMs) const
+{
+    if (job != nullptr)
+    {
+        const uint32 start = Time::getMillisecondCounter();
+
+        while (contains (job))
+        {
+            if (timeOutMs >= 0 && Time::getMillisecondCounter() >= start + (uint32) timeOutMs)
+                return false;
+
+            jobFinishedSignal.wait (2);
+        }
+    }
+
+    return true;
+}
+
+bool ThreadPool::removeJob (ThreadPoolJob* const job,
+                            const bool interruptIfRunning,
+                            const int timeOutMs)
+{
+    bool dontWait = true;
+    OwnedArray<ThreadPoolJob> deletionList;
+
+    if (job != nullptr)
+    {
+        const ScopedLock sl (lock);
+
+        if (jobs.contains (job))
+        {
+            if (job->isActive)
+            {
+                if (interruptIfRunning)
+                    job->signalJobShouldExit();
+
+                dontWait = false;
+            }
+            else
+            {
+                jobs.removeFirstMatchingValue (job);
+                addToDeleteList (deletionList, job);
+            }
+        }
+    }
+
+    return dontWait || waitForJobToFinish (job, timeOutMs);
+}
+
+bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, const int timeOutMs,
+                                ThreadPool::JobSelector* const selectedJobsToRemove)
+{
+    Array <ThreadPoolJob*> jobsToWaitFor;
+
+    {
+        OwnedArray<ThreadPoolJob> deletionList;
+
+        {
+            const ScopedLock sl (lock);
+
+            for (int i = jobs.size(); --i >= 0;)
+            {
+                ThreadPoolJob* const job = jobs.getUnchecked(i);
+
+                if (selectedJobsToRemove == nullptr || selectedJobsToRemove->isJobSuitable (job))
+                {
+                    if (job->isActive)
+                    {
+                        jobsToWaitFor.add (job);
+
+                        if (interruptRunningJobs)
+                            job->signalJobShouldExit();
+                    }
+                    else
+                    {
+                        jobs.remove (i);
+                        addToDeleteList (deletionList, job);
+                    }
+                }
+            }
+        }
+    }
+
+    const uint32 start = Time::getMillisecondCounter();
+
+    for (;;)
+    {
+        for (int i = jobsToWaitFor.size(); --i >= 0;)
+        {
+            ThreadPoolJob* const job = jobsToWaitFor.getUnchecked (i);
+
+            if (! isJobRunning (job))
+                jobsToWaitFor.remove (i);
+        }
+
+        if (jobsToWaitFor.size() == 0)
+            break;
+
+        if (timeOutMs >= 0 && Time::getMillisecondCounter() >= start + (uint32) timeOutMs)
+            return false;
+
+        jobFinishedSignal.wait (20);
+    }
+
+    return true;
+}
+
+StringArray ThreadPool::getNamesOfAllJobs (const bool onlyReturnActiveJobs) const
+{
+    StringArray s;
+    const ScopedLock sl (lock);
+
+    for (int i = 0; i < jobs.size(); ++i)
+    {
+        const ThreadPoolJob* const job = jobs.getUnchecked(i);
+        if (job->isActive || ! onlyReturnActiveJobs)
+            s.add (job->getJobName());
+    }
+
+    return s;
+}
+
+bool ThreadPool::setThreadPriorities (const int newPriority)
+{
+    bool ok = true;
+
+    for (int i = threads.size(); --i >= 0;)
+        if (! threads.getUnchecked(i)->setPriority (newPriority))
+            ok = false;
+
+    return ok;
+}
+
+ThreadPoolJob* ThreadPool::pickNextJobToRun()
+{
+    OwnedArray<ThreadPoolJob> deletionList;
+
+    {
+        const ScopedLock sl (lock);
+
+        for (int i = 0; i < jobs.size(); ++i)
+        {
+            ThreadPoolJob* job = jobs[i];
+
+            if (job != nullptr && ! job->isActive)
+            {
+                if (job->shouldStop)
+                {
+                    jobs.remove (i);
+                    addToDeleteList (deletionList, job);
+                    --i;
+                    continue;
+                }
+
+                job->isActive = true;
+                return job;
+            }
+        }
+    }
+
+    return nullptr;
+}
+
+bool ThreadPool::runNextJob (ThreadPoolThread& thread)
+{
+    if (ThreadPoolJob* const job = pickNextJobToRun())
+    {
+        ThreadPoolJob::JobStatus result = ThreadPoolJob::jobHasFinished;
+        thread.currentJob = job;
+
+        JUCE_TRY
+        {
+            result = job->runJob();
+        }
+        JUCE_CATCH_ALL_ASSERT
+
+        thread.currentJob = nullptr;
+
+        OwnedArray<ThreadPoolJob> deletionList;
+
+        {
+            const ScopedLock sl (lock);
+
+            if (jobs.contains (job))
+            {
+                job->isActive = false;
+
+                if (result != ThreadPoolJob::jobNeedsRunningAgain || job->shouldStop)
+                {
+                    jobs.removeFirstMatchingValue (job);
+                    addToDeleteList (deletionList, job);
+
+                    jobFinishedSignal.signal();
+                }
+                else
+                {
+                    // move the job to the end of the queue if it wants another go
+                    jobs.move (jobs.indexOf (job), -1);
+                }
+            }
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+void ThreadPool::addToDeleteList (OwnedArray<ThreadPoolJob>& deletionList, ThreadPoolJob* const job) const
+{
+    job->shouldStop = true;
+    job->pool = nullptr;
+
+    if (job->shouldBeDeleted)
+        deletionList.add (job);
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ThreadPool.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ThreadPool.h
new file mode 100644
index 0000000..3d5f762
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_ThreadPool.h
@@ -0,0 +1,321 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_THREADPOOL_H_INCLUDED
+#define JUCE_THREADPOOL_H_INCLUDED
+
+class ThreadPool;
+class ThreadPoolThread;
+
+
+//==============================================================================
+/**
+    A task that is executed by a ThreadPool object.
+
+    A ThreadPool keeps a list of ThreadPoolJob objects which are executed by
+    its threads.
+
+    The runJob() method needs to be implemented to do the task, and if the code that
+    does the work takes a significant time to run, it must keep checking the shouldExit()
+    method to see if something is trying to interrupt the job. If shouldExit() returns
+    true, the runJob() method must return immediately.
+
+    @see ThreadPool, Thread
+*/
+class JUCE_API  ThreadPoolJob
+{
+public:
+    //==============================================================================
+    /** Creates a thread pool job object.
+        After creating your job, add it to a thread pool with ThreadPool::addJob().
+    */
+    explicit ThreadPoolJob (const String& name);
+
+    /** Destructor. */
+    virtual ~ThreadPoolJob();
+
+    //==============================================================================
+    /** Returns the name of this job.
+        @see setJobName
+    */
+    String getJobName() const;
+
+    /** Changes the job's name.
+        @see getJobName
+    */
+    void setJobName (const String& newName);
+
+    //==============================================================================
+    /** These are the values that can be returned by the runJob() method.
+    */
+    enum JobStatus
+    {
+        jobHasFinished = 0,     /**< indicates that the job has finished and can be
+                                     removed from the pool. */
+
+        jobNeedsRunningAgain    /**< indicates that the job would like to be called
+                                     again when a thread is free. */
+    };
+
+    /** Peforms the actual work that this job needs to do.
+
+        Your subclass must implement this method, in which is does its work.
+
+        If the code in this method takes a significant time to run, it must repeatedly check
+        the shouldExit() method to see if something is trying to interrupt the job.
+        If shouldExit() ever returns true, the runJob() method must return immediately.
+
+        If this method returns jobHasFinished, then the job will be removed from the pool
+        immediately. If it returns jobNeedsRunningAgain, then the job will be left in the
+        pool and will get a chance to run again as soon as a thread is free.
+
+        @see shouldExit()
+    */
+    virtual JobStatus runJob() = 0;
+
+
+    //==============================================================================
+    /** Returns true if this job is currently running its runJob() method. */
+    bool isRunning() const noexcept                     { return isActive; }
+
+    /** Returns true if something is trying to interrupt this job and make it stop.
+
+        Your runJob() method must call this whenever it gets a chance, and if it ever
+        returns true, the runJob() method must return immediately.
+
+        @see signalJobShouldExit()
+    */
+    bool shouldExit() const noexcept                    { return shouldStop; }
+
+    /** Calling this will cause the shouldExit() method to return true, and the job
+        should (if it's been implemented correctly) stop as soon as possible.
+
+        @see shouldExit()
+    */
+    void signalJobShouldExit();
+
+    //==============================================================================
+    /** If the calling thread is being invoked inside a runJob() method, this will
+        return the ThreadPoolJob that it belongs to.
+    */
+    static ThreadPoolJob* getCurrentThreadPoolJob();
+
+    //==============================================================================
+private:
+    friend class ThreadPool;
+    friend class ThreadPoolThread;
+    String jobName;
+    ThreadPool* pool;
+    bool shouldStop, isActive, shouldBeDeleted;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolJob)
+};
+
+
+//==============================================================================
+/**
+    A set of threads that will run a list of jobs.
+
+    When a ThreadPoolJob object is added to the ThreadPool's list, its runJob() method
+    will be called by the next pooled thread that becomes free.
+
+    @see ThreadPoolJob, Thread
+*/
+class JUCE_API  ThreadPool
+{
+public:
+    //==============================================================================
+    /** Creates a thread pool.
+        Once you've created a pool, you can give it some jobs by calling addJob().
+        @param numberOfThreads  the number of threads to run. These will be started
+                                immediately, and will run until the pool is deleted.
+    */
+    ThreadPool (int numberOfThreads);
+
+    /** Creates a thread pool with one thread per CPU core.
+        Once you've created a pool, you can give it some jobs by calling addJob().
+        If you want to specify the number of threads, use the other constructor; this
+        one creates a pool which has one thread for each CPU core.
+        @see SystemStats::getNumCpus()
+    */
+    ThreadPool();
+
+    /** Destructor.
+
+        This will attempt to remove all the jobs before deleting, but if you want to
+        specify a timeout, you should call removeAllJobs() explicitly before deleting
+        the pool.
+    */
+    ~ThreadPool();
+
+    //==============================================================================
+    /** A callback class used when you need to select which ThreadPoolJob objects are suitable
+        for some kind of operation.
+        @see ThreadPool::removeAllJobs
+    */
+    class JUCE_API  JobSelector
+    {
+    public:
+        virtual ~JobSelector() {}
+
+        /** Should return true if the specified thread matches your criteria for whatever
+            operation that this object is being used for.
+
+            Any implementation of this method must be extremely fast and thread-safe!
+        */
+        virtual bool isJobSuitable (ThreadPoolJob* job) = 0;
+    };
+
+    //==============================================================================
+    /** Adds a job to the queue.
+
+        Once a job has been added, then the next time a thread is free, it will run
+        the job's ThreadPoolJob::runJob() method. Depending on the return value of the
+        runJob() method, the pool will either remove the job from the pool or add it to
+        the back of the queue to be run again.
+
+        If deleteJobWhenFinished is true, then the job object will be owned and deleted by
+        the pool when not needed - if you do this, make sure that your object's destructor
+        is thread-safe.
+
+        If deleteJobWhenFinished is false, the pointer will be used but not deleted, and
+        the caller is responsible for making sure the object is not deleted before it has
+        been removed from the pool.
+    */
+    void addJob (ThreadPoolJob* job,
+                 bool deleteJobWhenFinished);
+
+    /** Tries to remove a job from the pool.
+
+        If the job isn't yet running, this will simply remove it. If it is running, it
+        will wait for it to finish.
+
+        If the timeout period expires before the job finishes running, then the job will be
+        left in the pool and this will return false. It returns true if the job is successfully
+        stopped and removed.
+
+        @param job                  the job to remove
+        @param interruptIfRunning   if true, then if the job is currently busy, its
+                                    ThreadPoolJob::signalJobShouldExit() method will be called to try
+                                    to interrupt it. If false, then if the job will be allowed to run
+                                    until it stops normally (or the timeout expires)
+        @param timeOutMilliseconds  the length of time this method should wait for the job to finish
+                                    before giving up and returning false
+    */
+    bool removeJob (ThreadPoolJob* job,
+                    bool interruptIfRunning,
+                    int timeOutMilliseconds);
+
+    /** Tries to remove all jobs from the pool.
+
+        @param interruptRunningJobs if true, then all running jobs will have their ThreadPoolJob::signalJobShouldExit()
+                                    methods called to try to interrupt them
+        @param timeOutMilliseconds  the length of time this method should wait for all the jobs to finish
+                                    before giving up and returning false
+        @param selectedJobsToRemove if this is non-zero, the JobSelector object is asked to decide which
+                                    jobs should be removed. If it is zero, all jobs are removed
+        @returns    true if all jobs are successfully stopped and removed; false if the timeout period
+                    expires while waiting for one or more jobs to stop
+    */
+    bool removeAllJobs (bool interruptRunningJobs,
+                        int timeOutMilliseconds,
+                        JobSelector* selectedJobsToRemove = nullptr);
+
+    /** Returns the number of jobs currently running or queued.
+    */
+    int getNumJobs() const;
+
+    /** Returns one of the jobs in the queue.
+
+        Note that this can be a very volatile list as jobs might be continuously getting shifted
+        around in the list, and this method may return nullptr if the index is currently out-of-range.
+    */
+    ThreadPoolJob* getJob (int index) const;
+
+    /** Returns true if the given job is currently queued or running.
+
+        @see isJobRunning()
+    */
+    bool contains (const ThreadPoolJob* job) const;
+
+    /** Returns true if the given job is currently being run by a thread.
+    */
+    bool isJobRunning (const ThreadPoolJob* job) const;
+
+    /** Waits until a job has finished running and has been removed from the pool.
+
+        This will wait until the job is no longer in the pool - i.e. until its
+        runJob() method returns ThreadPoolJob::jobHasFinished.
+
+        If the timeout period expires before the job finishes, this will return false;
+        it returns true if the job has finished successfully.
+    */
+    bool waitForJobToFinish (const ThreadPoolJob* job,
+                             int timeOutMilliseconds) const;
+
+    /** Returns a list of the names of all the jobs currently running or queued.
+        If onlyReturnActiveJobs is true, only the ones currently running are returned.
+    */
+    StringArray getNamesOfAllJobs (bool onlyReturnActiveJobs) const;
+
+    /** Changes the priority of all the threads.
+
+        This will call Thread::setPriority() for each thread in the pool.
+        May return false if for some reason the priority can't be changed.
+    */
+    bool setThreadPriorities (int newPriority);
+
+
+private:
+    //==============================================================================
+    Array <ThreadPoolJob*> jobs;
+
+    class ThreadPoolThread;
+    friend class ThreadPoolJob;
+    friend class ThreadPoolThread;
+    friend struct ContainerDeletePolicy<ThreadPoolThread>;
+    OwnedArray<ThreadPoolThread> threads;
+
+    CriticalSection lock;
+    WaitableEvent jobFinishedSignal;
+
+    bool runNextJob (ThreadPoolThread&);
+    ThreadPoolJob* pickNextJobToRun();
+    void addToDeleteList (OwnedArray<ThreadPoolJob>&, ThreadPoolJob*) const;
+    void createThreads (int numThreads);
+    void stopThreads();
+
+    // Note that this method has changed, and no longer has a parameter to indicate
+    // whether the jobs should be deleted - see the new method for details.
+    void removeAllJobs (bool, int, bool);
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPool)
+};
+
+
+#endif   // JUCE_THREADPOOL_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_TimeSliceThread.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_TimeSliceThread.cpp
new file mode 100644
index 0000000..f055a15
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_TimeSliceThread.cpp
@@ -0,0 +1,171 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+TimeSliceThread::TimeSliceThread (const String& name)
+    : Thread (name),
+      clientBeingCalled (nullptr)
+{
+}
+
+TimeSliceThread::~TimeSliceThread()
+{
+    stopThread (2000);
+}
+
+//==============================================================================
+void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client, int millisecondsBeforeStarting)
+{
+    if (client != nullptr)
+    {
+        const ScopedLock sl (listLock);
+        client->nextCallTime = Time::getCurrentTime() + RelativeTime::milliseconds (millisecondsBeforeStarting);
+        clients.addIfNotAlreadyThere (client);
+        notify();
+    }
+}
+
+void TimeSliceThread::removeTimeSliceClient (TimeSliceClient* const client)
+{
+    const ScopedLock sl1 (listLock);
+
+    // if there's a chance we're in the middle of calling this client, we need to
+    // also lock the outer lock..
+    if (clientBeingCalled == client)
+    {
+        const ScopedUnlock ul (listLock); // unlock first to get the order right..
+
+        const ScopedLock sl2 (callbackLock);
+        const ScopedLock sl3 (listLock);
+
+        clients.removeFirstMatchingValue (client);
+    }
+    else
+    {
+        clients.removeFirstMatchingValue (client);
+    }
+}
+
+void TimeSliceThread::moveToFrontOfQueue (TimeSliceClient* client)
+{
+    const ScopedLock sl (listLock);
+
+    if (clients.contains (client))
+    {
+        client->nextCallTime = Time::getCurrentTime();
+        notify();
+    }
+}
+
+int TimeSliceThread::getNumClients() const
+{
+    return clients.size();
+}
+
+TimeSliceClient* TimeSliceThread::getClient (const int i) const
+{
+    const ScopedLock sl (listLock);
+    return clients [i];
+}
+
+//==============================================================================
+TimeSliceClient* TimeSliceThread::getNextClient (int index) const
+{
+    Time soonest;
+    TimeSliceClient* client = nullptr;
+
+    for (int i = clients.size(); --i >= 0;)
+    {
+        TimeSliceClient* const c = clients.getUnchecked ((i + index) % clients.size());
+
+        if (client == nullptr || c->nextCallTime < soonest)
+        {
+            client = c;
+            soonest = c->nextCallTime;
+        }
+    }
+
+    return client;
+}
+
+void TimeSliceThread::run()
+{
+    int index = 0;
+
+    while (! threadShouldExit())
+    {
+        int timeToWait = 500;
+
+        {
+            Time nextClientTime;
+
+            {
+                const ScopedLock sl2 (listLock);
+
+                index = clients.size() > 0 ? ((index + 1) % clients.size()) : 0;
+
+                if (TimeSliceClient* const firstClient = getNextClient (index))
+                    nextClientTime = firstClient->nextCallTime;
+            }
+
+            const Time now (Time::getCurrentTime());
+
+            if (nextClientTime > now)
+            {
+                timeToWait = (int) jmin ((int64) 500, (nextClientTime - now).inMilliseconds());
+            }
+            else
+            {
+                timeToWait = index == 0 ? 1 : 0;
+
+                const ScopedLock sl (callbackLock);
+
+                {
+                    const ScopedLock sl2 (listLock);
+                    clientBeingCalled = getNextClient (index);
+                }
+
+                if (clientBeingCalled != nullptr)
+                {
+                    const int msUntilNextCall = clientBeingCalled->useTimeSlice();
+
+                    const ScopedLock sl2 (listLock);
+
+                    if (msUntilNextCall >= 0)
+                        clientBeingCalled->nextCallTime = now + RelativeTime::milliseconds (msUntilNextCall);
+                    else
+                        clients.removeFirstMatchingValue (clientBeingCalled);
+
+                    clientBeingCalled = nullptr;
+                }
+            }
+        }
+
+        if (timeToWait > 0)
+            wait (timeToWait);
+    }
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_TimeSliceThread.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_TimeSliceThread.h
new file mode 100644
index 0000000..8c30567
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_TimeSliceThread.h
@@ -0,0 +1,149 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_TIMESLICETHREAD_H_INCLUDED
+#define JUCE_TIMESLICETHREAD_H_INCLUDED
+
+class TimeSliceThread;
+
+
+//==============================================================================
+/**
+    Used by the TimeSliceThread class.
+
+    To register your class with a TimeSliceThread, derive from this class and
+    use the TimeSliceThread::addTimeSliceClient() method to add it to the list.
+
+    Make sure you always call TimeSliceThread::removeTimeSliceClient() before
+    deleting your client!
+
+    @see TimeSliceThread
+*/
+class JUCE_API  TimeSliceClient
+{
+public:
+    /** Destructor. */
+    virtual ~TimeSliceClient()   {}
+
+    /** Called back by a TimeSliceThread.
+
+        When you register this class with it, a TimeSliceThread will repeatedly call
+        this method.
+
+        The implementation of this method should use its time-slice to do something that's
+        quick - never block for longer than absolutely necessary.
+
+        @returns    Your method should return the number of milliseconds which it would like to wait before being called
+                    again. Returning 0 will make the thread call again as soon as possible (after possibly servicing
+                    other busy clients). If you return a value below zero, your client will be removed from the list of clients,
+                    and won't be called again. The value you specify isn't a guaranteee, and is only used as a hint by the
+                    thread - the actual time before the next callback may be more or less than specified.
+                    You can force the TimeSliceThread to wake up and poll again immediately by calling its notify() method.
+    */
+    virtual int useTimeSlice() = 0;
+
+
+private:
+    friend class TimeSliceThread;
+    Time nextCallTime;
+};
+
+
+//==============================================================================
+/**
+    A thread that keeps a list of clients, and calls each one in turn, giving them
+    all a chance to run some sort of short task.
+
+    @see TimeSliceClient, Thread
+*/
+class JUCE_API  TimeSliceThread   : public Thread
+{
+public:
+    //==============================================================================
+    /**
+        Creates a TimeSliceThread.
+
+        When first created, the thread is not running. Use the startThread()
+        method to start it.
+    */
+    explicit TimeSliceThread (const String& threadName);
+
+    /** Destructor.
+
+        Deleting a Thread object that is running will only give the thread a
+        brief opportunity to stop itself cleanly, so it's recommended that you
+        should always call stopThread() with a decent timeout before deleting,
+        to avoid the thread being forcibly killed (which is a Bad Thing).
+    */
+    ~TimeSliceThread();
+
+    //==============================================================================
+    /** Adds a client to the list.
+
+        The client's callbacks will start after the number of milliseconds specified
+        by millisecondsBeforeStarting (and this may happen before this method has returned).
+    */
+    void addTimeSliceClient (TimeSliceClient* client, int millisecondsBeforeStarting = 0);
+
+    /** Removes a client from the list.
+
+        This method will make sure that all callbacks to the client have completely
+        finished before the method returns.
+    */
+    void removeTimeSliceClient (TimeSliceClient* client);
+
+    /** If the given client is waiting in the queue, it will be moved to the front
+        and given a time-slice as soon as possible.
+        If the specified client has not been added, nothing will happen.
+    */
+    void moveToFrontOfQueue (TimeSliceClient* client);
+
+    /** Returns the number of registered clients. */
+    int getNumClients() const;
+
+    /** Returns one of the registered clients. */
+    TimeSliceClient* getClient (int index) const;
+
+    //==============================================================================
+   #ifndef DOXYGEN
+    void run() override;
+   #endif
+
+    //==============================================================================
+private:
+    CriticalSection callbackLock, listLock;
+    Array <TimeSliceClient*> clients;
+    TimeSliceClient* clientBeingCalled;
+
+    TimeSliceClient* getNextClient (int index) const;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimeSliceThread)
+};
+
+
+#endif   // JUCE_TIMESLICETHREAD_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_WaitableEvent.h b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_WaitableEvent.h
new file mode 100644
index 0000000..83f6f06
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/threads/juce_WaitableEvent.h
@@ -0,0 +1,118 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_WAITABLEEVENT_H_INCLUDED
+#define JUCE_WAITABLEEVENT_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Allows threads to wait for events triggered by other threads.
+
+    A thread can call wait() on a WaitableObject, and this will suspend the
+    calling thread until another thread wakes it up by calling the signal()
+    method.
+*/
+class JUCE_API  WaitableEvent
+{
+public:
+    //==============================================================================
+    /** Creates a WaitableEvent object.
+
+        The object is initially in an unsignalled state.
+
+        @param manualReset  If this is false, the event will be reset automatically when the wait()
+                            method is called. If manualReset is true, then once the event is signalled,
+                            the only way to reset it will be by calling the reset() method.
+    */
+    explicit WaitableEvent (bool manualReset = false) noexcept;
+
+    /** Destructor.
+
+        If other threads are waiting on this object when it gets deleted, this
+        can cause nasty errors, so be careful!
+    */
+    ~WaitableEvent() noexcept;
+
+    //==============================================================================
+    /** Suspends the calling thread until the event has been signalled.
+
+        This will wait until the object's signal() method is called by another thread,
+        or until the timeout expires.
+
+        After the event has been signalled, this method will return true and if manualReset
+        was set to false in the WaitableEvent's constructor, then the event will be reset.
+
+        @param timeOutMilliseconds  the maximum time to wait, in milliseconds. A negative
+                                    value will cause it to wait forever.
+
+        @returns    true if the object has been signalled, false if the timeout expires first.
+        @see signal, reset
+    */
+    bool wait (int timeOutMilliseconds = -1) const noexcept;
+
+    //==============================================================================
+    /** Wakes up any threads that are currently waiting on this object.
+
+        If signal() is called when nothing is waiting, the next thread to call wait()
+        will return immediately and reset the signal.
+
+        If the WaitableEvent is manual reset, all current and future threads that wait upon this
+        object will be woken, until reset() is explicitly called.
+
+        If the WaitableEvent is automatic reset, and one or more threads is waiting upon the object,
+        then one of them will be woken up. If no threads are currently waiting, then the next thread
+        to call wait() will be woken up. As soon as a thread is woken, the signal is automatically
+        reset.
+
+        @see wait, reset
+    */
+    void signal() const noexcept;
+
+    //==============================================================================
+    /** Resets the event to an unsignalled state.
+        If it's not already signalled, this does nothing.
+    */
+    void reset() const noexcept;
+
+
+private:
+    //==============================================================================
+   #if JUCE_WINDOWS
+    void* handle;
+   #else
+    mutable pthread_cond_t condition;
+    mutable pthread_mutex_t mutex;
+    mutable bool triggered, manualReset;
+   #endif
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WaitableEvent)
+};
+
+
+#endif   // JUCE_WAITABLEEVENT_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_PerformanceCounter.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_PerformanceCounter.cpp
new file mode 100644
index 0000000..b22d5e4
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_PerformanceCounter.cpp
@@ -0,0 +1,132 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+static void appendToFile (const File& f, const String& s)
+{
+    if (f.getFullPathName().isNotEmpty())
+    {
+        FileOutputStream out (f);
+
+        if (! out.failedToOpen())
+            out << s << newLine;
+    }
+}
+
+PerformanceCounter::PerformanceCounter (const String& name, int runsPerPrintout, const File& loggingFile)
+    : runsPerPrint (runsPerPrintout), startTime (0), outputFile (loggingFile)
+{
+    stats.name = name;
+    appendToFile (outputFile, "**** Counter for \"" + name + "\" started at: " + Time::getCurrentTime().toString (true, true));
+}
+
+PerformanceCounter::~PerformanceCounter()
+{
+    printStatistics();
+}
+
+PerformanceCounter::Statistics::Statistics() noexcept
+    : averageSeconds(), maximumSeconds(), minimumSeconds(), totalSeconds(), numRuns()
+{
+}
+
+void PerformanceCounter::Statistics::clear() noexcept
+{
+    averageSeconds = maximumSeconds = minimumSeconds = totalSeconds = 0;
+    numRuns = 0;
+}
+
+void PerformanceCounter::Statistics::addResult (double elapsed) noexcept
+{
+    if (numRuns == 0)
+    {
+        maximumSeconds = elapsed;
+        minimumSeconds = elapsed;
+    }
+    else
+    {
+        maximumSeconds = jmax (maximumSeconds, elapsed);
+        minimumSeconds = jmin (minimumSeconds, elapsed);
+    }
+
+    ++numRuns;
+    totalSeconds += elapsed;
+}
+
+static String timeToString (double secs)
+{
+    return String ((int64) (secs * (secs < 0.01 ? 1000000.0 : 1000.0) + 0.5))
+                    + (secs < 0.01 ? " microsecs" : " millisecs");
+}
+
+String PerformanceCounter::Statistics::toString() const
+{
+    MemoryOutputStream s;
+
+    s << "Performance count for \"" << name << "\" over " << numRuns << " run(s)" << newLine
+      << "Average = "   << timeToString (averageSeconds)
+      << ", minimum = " << timeToString (minimumSeconds)
+      << ", maximum = " << timeToString (maximumSeconds)
+      << ", total = "   << timeToString (totalSeconds);
+
+    return s.toString();
+}
+
+void PerformanceCounter::start() noexcept
+{
+    startTime = Time::getHighResolutionTicks();
+}
+
+bool PerformanceCounter::stop()
+{
+    stats.addResult (Time::highResolutionTicksToSeconds (Time::getHighResolutionTicks() - startTime));
+
+    if (stats.numRuns < runsPerPrint)
+        return false;
+
+    printStatistics();
+    return true;
+}
+
+void PerformanceCounter::printStatistics()
+{
+    const String desc (getStatisticsAndReset().toString());
+
+    Logger::outputDebugString (desc);
+    appendToFile (outputFile, desc);
+}
+
+PerformanceCounter::Statistics PerformanceCounter::getStatisticsAndReset()
+{
+    Statistics s (stats);
+    stats.clear();
+
+    if (s.numRuns > 0)
+        s.averageSeconds = s.totalSeconds / s.numRuns;
+
+    return s;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_PerformanceCounter.h b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_PerformanceCounter.h
new file mode 100644
index 0000000..aac50d2
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_PerformanceCounter.h
@@ -0,0 +1,127 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_PERFORMANCECOUNTER_H_INCLUDED
+#define JUCE_PERFORMANCECOUNTER_H_INCLUDED
+
+
+//==============================================================================
+/** A timer for measuring performance of code and dumping the results to a file.
+
+    e.g. @code
+
+        PerformanceCounter pc ("fish", 50, "/temp/myfishlog.txt");
+
+        for (;;)
+        {
+            pc.start();
+
+            doSomethingFishy();
+
+            pc.stop();
+        }
+    @endcode
+
+    In this example, the time of each period between calling start/stop will be
+    measured and averaged over 50 runs, and the results printed to a file
+    every 50 times round the loop.
+*/
+class JUCE_API  PerformanceCounter
+{
+public:
+    //==============================================================================
+    /** Creates a PerformanceCounter object.
+
+        @param counterName      the name used when printing out the statistics
+        @param runsPerPrintout  the number of start/stop iterations before calling
+                                printStatistics()
+        @param loggingFile      a file to dump the results to - if this is File::nonexistent,
+                                the results are just written to the debugger output
+    */
+    PerformanceCounter (const String& counterName,
+                        int runsPerPrintout = 100,
+                        const File& loggingFile = File());
+
+    /** Destructor. */
+    ~PerformanceCounter();
+
+    //==============================================================================
+    /** Starts timing.
+        @see stop
+    */
+    void start() noexcept;
+
+    /** Stops timing and prints out the results.
+
+        The number of iterations before doing a printout of the
+        results is set in the constructor.
+
+        @see start
+    */
+    bool stop();
+
+    /** Dumps the current metrics to the debugger output and to a file.
+
+        As well as using Logger::outputDebugString to print the results,
+        this will write then to the file specified in the constructor (if
+        this was valid).
+    */
+    void printStatistics();
+
+    /** Holds the current statistics. */
+    struct Statistics
+    {
+        Statistics() noexcept;
+
+        void clear() noexcept;
+        String toString() const;
+
+        void addResult (double elapsed) noexcept;
+
+        String name;
+        double averageSeconds;
+        double maximumSeconds;
+        double minimumSeconds;
+        double totalSeconds;
+        int64 numRuns;
+    };
+
+    /** Returns a copy of the current stats, and resets the internal counter. */
+    Statistics getStatisticsAndReset();
+
+private:
+    //==============================================================================
+    Statistics stats;
+    int64 runsPerPrint, startTime;
+    File outputFile;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PerformanceCounter)
+};
+
+
+#endif   // JUCE_PERFORMANCECOUNTER_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_RelativeTime.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_RelativeTime.cpp
new file mode 100644
index 0000000..6fca4fe
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_RelativeTime.cpp
@@ -0,0 +1,139 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+RelativeTime::RelativeTime (const double secs) noexcept           : numSeconds (secs) {}
+RelativeTime::RelativeTime (const RelativeTime& other) noexcept   : numSeconds (other.numSeconds) {}
+RelativeTime::~RelativeTime() noexcept {}
+
+//==============================================================================
+RelativeTime RelativeTime::milliseconds (const int milliseconds) noexcept   { return RelativeTime (milliseconds * 0.001); }
+RelativeTime RelativeTime::milliseconds (const int64 milliseconds) noexcept { return RelativeTime (milliseconds * 0.001); }
+RelativeTime RelativeTime::seconds (double s) noexcept                      { return RelativeTime (s); }
+RelativeTime RelativeTime::minutes (const double numberOfMinutes) noexcept  { return RelativeTime (numberOfMinutes * 60.0); }
+RelativeTime RelativeTime::hours (const double numberOfHours) noexcept      { return RelativeTime (numberOfHours * (60.0 * 60.0)); }
+RelativeTime RelativeTime::days (const double numberOfDays) noexcept        { return RelativeTime (numberOfDays  * (60.0 * 60.0 * 24.0)); }
+RelativeTime RelativeTime::weeks (const double numberOfWeeks) noexcept      { return RelativeTime (numberOfWeeks * (60.0 * 60.0 * 24.0 * 7.0)); }
+
+//==============================================================================
+int64 RelativeTime::inMilliseconds() const noexcept { return (int64) (numSeconds * 1000.0); }
+double RelativeTime::inMinutes() const noexcept     { return numSeconds / 60.0; }
+double RelativeTime::inHours() const noexcept       { return numSeconds / (60.0 * 60.0); }
+double RelativeTime::inDays() const noexcept        { return numSeconds / (60.0 * 60.0 * 24.0); }
+double RelativeTime::inWeeks() const noexcept       { return numSeconds / (60.0 * 60.0 * 24.0 * 7.0); }
+
+//==============================================================================
+RelativeTime& RelativeTime::operator= (const RelativeTime& other) noexcept      { numSeconds = other.numSeconds; return *this; }
+
+RelativeTime RelativeTime::operator+= (RelativeTime t) noexcept     { numSeconds += t.numSeconds; return *this; }
+RelativeTime RelativeTime::operator-= (RelativeTime t) noexcept     { numSeconds -= t.numSeconds; return *this; }
+RelativeTime RelativeTime::operator+= (const double secs) noexcept  { numSeconds += secs; return *this; }
+RelativeTime RelativeTime::operator-= (const double secs) noexcept  { numSeconds -= secs; return *this; }
+
+RelativeTime operator+ (RelativeTime t1, RelativeTime t2) noexcept  { return t1 += t2; }
+RelativeTime operator- (RelativeTime t1, RelativeTime t2) noexcept  { return t1 -= t2; }
+
+bool operator== (RelativeTime t1, RelativeTime t2) noexcept       { return t1.inSeconds() == t2.inSeconds(); }
+bool operator!= (RelativeTime t1, RelativeTime t2) noexcept       { return t1.inSeconds() != t2.inSeconds(); }
+bool operator>  (RelativeTime t1, RelativeTime t2) noexcept       { return t1.inSeconds() >  t2.inSeconds(); }
+bool operator<  (RelativeTime t1, RelativeTime t2) noexcept       { return t1.inSeconds() <  t2.inSeconds(); }
+bool operator>= (RelativeTime t1, RelativeTime t2) noexcept       { return t1.inSeconds() >= t2.inSeconds(); }
+bool operator<= (RelativeTime t1, RelativeTime t2) noexcept       { return t1.inSeconds() <= t2.inSeconds(); }
+
+//==============================================================================
+static void translateTimeField (String& result, int n, const char* singular, const char* plural)
+{
+    result << TRANS (n == 1 ? singular : plural)
+                .replace (n == 1 ? "1" : "2", String (n))
+           << ' ';
+}
+
+String RelativeTime::getDescription (const String& returnValueForZeroTime) const
+{
+    if (numSeconds < 0.001 && numSeconds > -0.001)
+        return returnValueForZeroTime;
+
+    String result;
+    result.preallocateBytes (32);
+
+    if (numSeconds < 0)
+        result << '-';
+
+    int fieldsShown = 0;
+    int n = std::abs ((int) inWeeks());
+    if (n > 0)
+    {
+        translateTimeField (result, n, NEEDS_TRANS("1 week"), NEEDS_TRANS("2 weeks"));
+        ++fieldsShown;
+    }
+
+    n = std::abs ((int) inDays()) % 7;
+    if (n > 0)
+    {
+        translateTimeField (result, n, NEEDS_TRANS("1 day"), NEEDS_TRANS("2 days"));
+        ++fieldsShown;
+    }
+
+    if (fieldsShown < 2)
+    {
+        n = std::abs ((int) inHours()) % 24;
+        if (n > 0)
+        {
+            translateTimeField (result, n, NEEDS_TRANS("1 hr"), NEEDS_TRANS("2 hrs"));
+            ++fieldsShown;
+        }
+
+        if (fieldsShown < 2)
+        {
+            n = std::abs ((int) inMinutes()) % 60;
+            if (n > 0)
+            {
+                translateTimeField (result, n, NEEDS_TRANS("1 min"), NEEDS_TRANS("2 mins"));
+                ++fieldsShown;
+            }
+
+            if (fieldsShown < 2)
+            {
+                n = std::abs ((int) inSeconds()) % 60;
+                if (n > 0)
+                {
+                    translateTimeField (result, n, NEEDS_TRANS("1 sec"), NEEDS_TRANS("2 secs"));
+                    ++fieldsShown;
+                }
+
+                if (fieldsShown == 0)
+                {
+                    n = std::abs ((int) inMilliseconds()) % 1000;
+                    if (n > 0)
+                        result << n << ' ' << TRANS ("ms");
+                }
+            }
+        }
+    }
+
+    return result.trimEnd();
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_RelativeTime.h b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_RelativeTime.h
new file mode 100644
index 0000000..7e39d21
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_RelativeTime.h
@@ -0,0 +1,184 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_RELATIVETIME_H_INCLUDED
+#define JUCE_RELATIVETIME_H_INCLUDED
+
+
+//==============================================================================
+/** A relative measure of time.
+
+    The time is stored as a number of seconds, at double-precision floating
+    point accuracy, and may be positive or negative.
+
+    If you need an absolute time, (i.e. a date + time), see the Time class.
+*/
+class JUCE_API  RelativeTime
+{
+public:
+    //==============================================================================
+    /** Creates a RelativeTime.
+
+        @param seconds  the number of seconds, which may be +ve or -ve.
+        @see milliseconds, minutes, hours, days, weeks
+    */
+    explicit RelativeTime (double seconds = 0.0) noexcept;
+
+    /** Copies another relative time. */
+    RelativeTime (const RelativeTime& other) noexcept;
+
+    /** Copies another relative time. */
+    RelativeTime& operator= (const RelativeTime& other) noexcept;
+
+    /** Destructor. */
+    ~RelativeTime() noexcept;
+
+    //==============================================================================
+    /** Creates a new RelativeTime object representing a number of milliseconds.
+        @see seconds, minutes, hours, days, weeks
+    */
+    static RelativeTime milliseconds (int milliseconds) noexcept;
+
+    /** Creates a new RelativeTime object representing a number of milliseconds.
+        @see seconds, minutes, hours, days, weeks
+    */
+    static RelativeTime milliseconds (int64 milliseconds) noexcept;
+
+    /** Creates a new RelativeTime object representing a number of seconds.
+        @see milliseconds, minutes, hours, days, weeks
+    */
+    static RelativeTime seconds (double seconds) noexcept;
+
+    /** Creates a new RelativeTime object representing a number of minutes.
+        @see milliseconds, hours, days, weeks
+    */
+    static RelativeTime minutes (double numberOfMinutes) noexcept;
+
+    /** Creates a new RelativeTime object representing a number of hours.
+        @see milliseconds, minutes, days, weeks
+    */
+    static RelativeTime hours (double numberOfHours) noexcept;
+
+    /** Creates a new RelativeTime object representing a number of days.
+        @see milliseconds, minutes, hours, weeks
+    */
+    static RelativeTime days (double numberOfDays) noexcept;
+
+    /** Creates a new RelativeTime object representing a number of weeks.
+        @see milliseconds, minutes, hours, days
+    */
+    static RelativeTime weeks (double numberOfWeeks) noexcept;
+
+    //==============================================================================
+    /** Returns the number of milliseconds this time represents.
+        @see milliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks
+    */
+    int64 inMilliseconds() const noexcept;
+
+    /** Returns the number of seconds this time represents.
+        @see inMilliseconds, inMinutes, inHours, inDays, inWeeks
+    */
+    double inSeconds() const noexcept       { return numSeconds; }
+
+    /** Returns the number of minutes this time represents.
+        @see inMilliseconds, inSeconds, inHours, inDays, inWeeks
+    */
+    double inMinutes() const noexcept;
+
+    /** Returns the number of hours this time represents.
+        @see inMilliseconds, inSeconds, inMinutes, inDays, inWeeks
+    */
+    double inHours() const noexcept;
+
+    /** Returns the number of days this time represents.
+        @see inMilliseconds, inSeconds, inMinutes, inHours, inWeeks
+    */
+    double inDays() const noexcept;
+
+    /** Returns the number of weeks this time represents.
+        @see inMilliseconds, inSeconds, inMinutes, inHours, inDays
+    */
+    double inWeeks() const noexcept;
+
+    /** Returns a readable textual description of the time.
+
+        The exact format of the string returned will depend on
+        the magnitude of the time - e.g.
+
+        "1 min 4 secs", "1 hr 45 mins", "2 weeks 5 days", "140 ms"
+
+        so that only the two most significant units are printed.
+
+        The returnValueForZeroTime value is the result that is returned if the
+        length is zero. Depending on your application you might want to use this
+        to return something more relevant like "empty" or "0 secs", etc.
+
+        @see inMilliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks
+    */
+    String getDescription (const String& returnValueForZeroTime = "0") const;
+
+
+    //==============================================================================
+    /** Adds another RelativeTime to this one. */
+    RelativeTime operator+= (RelativeTime timeToAdd) noexcept;
+    /** Subtracts another RelativeTime from this one. */
+    RelativeTime operator-= (RelativeTime timeToSubtract) noexcept;
+
+    /** Adds a number of seconds to this time. */
+    RelativeTime operator+= (double secondsToAdd) noexcept;
+    /** Subtracts a number of seconds from this time. */
+    RelativeTime operator-= (double secondsToSubtract) noexcept;
+
+private:
+    //==============================================================================
+    double numSeconds;
+};
+
+//==============================================================================
+/** Compares two RelativeTimes. */
+bool operator== (RelativeTime t1, RelativeTime t2) noexcept;
+/** Compares two RelativeTimes. */
+bool operator!= (RelativeTime t1, RelativeTime t2) noexcept;
+/** Compares two RelativeTimes. */
+bool operator>  (RelativeTime t1, RelativeTime t2) noexcept;
+/** Compares two RelativeTimes. */
+bool operator<  (RelativeTime t1, RelativeTime t2) noexcept;
+/** Compares two RelativeTimes. */
+bool operator>= (RelativeTime t1, RelativeTime t2) noexcept;
+/** Compares two RelativeTimes. */
+bool operator<= (RelativeTime t1, RelativeTime t2) noexcept;
+
+//==============================================================================
+/** Adds two RelativeTimes together. */
+RelativeTime  operator+  (RelativeTime t1, RelativeTime t2) noexcept;
+/** Subtracts two RelativeTimes. */
+RelativeTime  operator-  (RelativeTime t1, RelativeTime t2) noexcept;
+
+
+
+#endif   // JUCE_RELATIVETIME_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_Time.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_Time.cpp
new file mode 100644
index 0000000..fabcfde
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_Time.cpp
@@ -0,0 +1,469 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+namespace TimeHelpers
+{
+    static struct tm millisToLocal (const int64 millis) noexcept
+    {
+        struct tm result;
+        const int64 seconds = millis / 1000;
+
+        if (seconds < 86400LL || seconds >= 2145916800LL)
+        {
+            // use extended maths for dates beyond 1970 to 2037..
+            const int timeZoneAdjustment = 31536000 - (int) (Time (1971, 0, 1, 0, 0).toMilliseconds() / 1000);
+            const int64 jdm = seconds + timeZoneAdjustment + 210866803200LL;
+
+            const int days = (int) (jdm / 86400LL);
+            const int a = 32044 + days;
+            const int b = (4 * a + 3) / 146097;
+            const int c = a - (b * 146097) / 4;
+            const int d = (4 * c + 3) / 1461;
+            const int e = c - (d * 1461) / 4;
+            const int m = (5 * e + 2) / 153;
+
+            result.tm_mday  = e - (153 * m + 2) / 5 + 1;
+            result.tm_mon   = m + 2 - 12 * (m / 10);
+            result.tm_year  = b * 100 + d - 6700 + (m / 10);
+            result.tm_wday  = (days + 1) % 7;
+            result.tm_yday  = -1;
+
+            int t = (int) (jdm % 86400LL);
+            result.tm_hour  = t / 3600;
+            t %= 3600;
+            result.tm_min   = t / 60;
+            result.tm_sec   = t % 60;
+            result.tm_isdst = -1;
+        }
+        else
+        {
+            time_t now = static_cast <time_t> (seconds);
+
+          #if JUCE_WINDOWS
+           #ifdef _INC_TIME_INL
+            if (now >= 0 && now <= 0x793406fff)
+                localtime_s (&result, &now);
+            else
+                zerostruct (result);
+           #else
+            result = *localtime (&now);
+           #endif
+          #else
+
+            localtime_r (&now, &result); // more thread-safe
+          #endif
+        }
+
+        return result;
+    }
+
+    static int extendedModulo (const int64 value, const int modulo) noexcept
+    {
+        return (int) (value >= 0 ? (value % modulo)
+                                 : (value - ((value / modulo) + 1) * modulo));
+    }
+
+    static inline String formatString (const String& format, const struct tm* const tm)
+    {
+       #if JUCE_ANDROID
+        typedef CharPointer_UTF8  StringType;
+       #elif JUCE_WINDOWS
+        typedef CharPointer_UTF16 StringType;
+       #else
+        typedef CharPointer_UTF32 StringType;
+       #endif
+
+        for (size_t bufferSize = 256; ; bufferSize += 256)
+        {
+            HeapBlock<StringType::CharType> buffer (bufferSize);
+
+           #if JUCE_ANDROID
+            const size_t numChars = strftime (buffer, bufferSize - 1, format.toUTF8(), tm);
+           #elif JUCE_WINDOWS
+            const size_t numChars = wcsftime (buffer, bufferSize - 1, format.toWideCharPointer(), tm);
+           #else
+            const size_t numChars = wcsftime (buffer, bufferSize - 1, format.toUTF32(), tm);
+           #endif
+
+            if (numChars > 0 || format.isEmpty())
+                return String (StringType (buffer),
+                               StringType (buffer) + (int) numChars);
+        }
+    }
+
+    static uint32 lastMSCounterValue = 0;
+}
+
+//==============================================================================
+Time::Time() noexcept
+    : millisSinceEpoch (0)
+{
+}
+
+Time::Time (const Time& other) noexcept
+    : millisSinceEpoch (other.millisSinceEpoch)
+{
+}
+
+Time::Time (const int64 ms) noexcept
+    : millisSinceEpoch (ms)
+{
+}
+
+Time::Time (const int year,
+            const int month,
+            const int day,
+            const int hours,
+            const int minutes,
+            const int seconds,
+            const int milliseconds,
+            const bool useLocalTime) noexcept
+{
+    jassert (year > 100); // year must be a 4-digit version
+
+    if (year < 1971 || year >= 2038 || ! useLocalTime)
+    {
+        // use extended maths for dates beyond 1970 to 2037..
+        const int timeZoneAdjustment = useLocalTime ? (31536000 - (int) (Time (1971, 0, 1, 0, 0).toMilliseconds() / 1000))
+                                                    : 0;
+        const int a = (13 - month) / 12;
+        const int y = year + 4800 - a;
+        const int jd = day + (153 * (month + 12 * a - 2) + 2) / 5
+                           + (y * 365) + (y /  4) - (y / 100) + (y / 400)
+                           - 32045;
+
+        const int64 s = ((int64) jd) * 86400LL - 210866803200LL;
+
+        millisSinceEpoch = 1000 * (s + (hours * 3600 + minutes * 60 + seconds - timeZoneAdjustment))
+                             + milliseconds;
+    }
+    else
+    {
+        struct tm t;
+        t.tm_year   = year - 1900;
+        t.tm_mon    = month;
+        t.tm_mday   = day;
+        t.tm_hour   = hours;
+        t.tm_min    = minutes;
+        t.tm_sec    = seconds;
+        t.tm_isdst  = -1;
+
+        millisSinceEpoch = 1000 * (int64) mktime (&t);
+
+        if (millisSinceEpoch < 0)
+            millisSinceEpoch = 0;
+        else
+            millisSinceEpoch += milliseconds;
+    }
+}
+
+Time::~Time() noexcept
+{
+}
+
+Time& Time::operator= (const Time& other) noexcept
+{
+    millisSinceEpoch = other.millisSinceEpoch;
+    return *this;
+}
+
+//==============================================================================
+int64 Time::currentTimeMillis() noexcept
+{
+  #if JUCE_WINDOWS
+    struct _timeb t;
+   #ifdef _INC_TIME_INL
+    _ftime_s (&t);
+   #else
+    _ftime (&t);
+   #endif
+    return ((int64) t.time) * 1000 + t.millitm;
+  #else
+    struct timeval tv;
+    gettimeofday (&tv, nullptr);
+    return ((int64) tv.tv_sec) * 1000 + tv.tv_usec / 1000;
+  #endif
+}
+
+Time JUCE_CALLTYPE Time::getCurrentTime() noexcept
+{
+    return Time (currentTimeMillis());
+}
+
+//==============================================================================
+uint32 juce_millisecondsSinceStartup() noexcept;
+
+uint32 Time::getMillisecondCounter() noexcept
+{
+    const uint32 now = juce_millisecondsSinceStartup();
+
+    if (now < TimeHelpers::lastMSCounterValue)
+    {
+        // in multi-threaded apps this might be called concurrently, so
+        // make sure that our last counter value only increases and doesn't
+        // go backwards..
+        if (now < TimeHelpers::lastMSCounterValue - 1000)
+            TimeHelpers::lastMSCounterValue = now;
+    }
+    else
+    {
+        TimeHelpers::lastMSCounterValue = now;
+    }
+
+    return now;
+}
+
+uint32 Time::getApproximateMillisecondCounter() noexcept
+{
+    if (TimeHelpers::lastMSCounterValue == 0)
+        getMillisecondCounter();
+
+    return TimeHelpers::lastMSCounterValue;
+}
+
+void Time::waitForMillisecondCounter (const uint32 targetTime) noexcept
+{
+    for (;;)
+    {
+        const uint32 now = getMillisecondCounter();
+
+        if (now >= targetTime)
+            break;
+
+        const int toWait = (int) (targetTime - now);
+
+        if (toWait > 2)
+        {
+            Thread::sleep (jmin (20, toWait >> 1));
+        }
+        else
+        {
+            // xxx should consider using mutex_pause on the mac as it apparently
+            // makes it seem less like a spinlock and avoids lowering the thread pri.
+            for (int i = 10; --i >= 0;)
+                Thread::yield();
+        }
+    }
+}
+
+//==============================================================================
+double Time::highResolutionTicksToSeconds (const int64 ticks) noexcept
+{
+    return ticks / (double) getHighResolutionTicksPerSecond();
+}
+
+int64 Time::secondsToHighResolutionTicks (const double seconds) noexcept
+{
+    return (int64) (seconds * (double) getHighResolutionTicksPerSecond());
+}
+
+//==============================================================================
+String Time::toString (const bool includeDate,
+                       const bool includeTime,
+                       const bool includeSeconds,
+                       const bool use24HourClock) const noexcept
+{
+    String result;
+
+    if (includeDate)
+    {
+        result << getDayOfMonth() << ' '
+               << getMonthName (true) << ' '
+               << getYear();
+
+        if (includeTime)
+            result << ' ';
+    }
+
+    if (includeTime)
+    {
+        const int mins = getMinutes();
+
+        result << (use24HourClock ? getHours() : getHoursInAmPmFormat())
+               << (mins < 10 ? ":0" : ":") << mins;
+
+        if (includeSeconds)
+        {
+            const int secs = getSeconds();
+            result << (secs < 10 ? ":0" : ":") << secs;
+        }
+
+        if (! use24HourClock)
+            result << (isAfternoon() ? "pm" : "am");
+    }
+
+    return result.trimEnd();
+}
+
+String Time::formatted (const String& format) const
+{
+    struct tm t (TimeHelpers::millisToLocal (millisSinceEpoch));
+    return TimeHelpers::formatString (format, &t);
+}
+
+//==============================================================================
+int Time::getYear() const noexcept          { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_year + 1900; }
+int Time::getMonth() const noexcept         { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_mon; }
+int Time::getDayOfYear() const noexcept     { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_yday; }
+int Time::getDayOfMonth() const noexcept    { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_mday; }
+int Time::getDayOfWeek() const noexcept     { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_wday; }
+int Time::getHours() const noexcept         { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_hour; }
+int Time::getMinutes() const noexcept       { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_min; }
+int Time::getSeconds() const noexcept       { return TimeHelpers::extendedModulo (millisSinceEpoch / 1000, 60); }
+int Time::getMilliseconds() const noexcept  { return TimeHelpers::extendedModulo (millisSinceEpoch, 1000); }
+
+int Time::getHoursInAmPmFormat() const noexcept
+{
+    const int hours = getHours();
+
+    if (hours == 0)  return 12;
+    if (hours <= 12) return hours;
+
+    return hours - 12;
+}
+
+bool Time::isAfternoon() const noexcept
+{
+    return getHours() >= 12;
+}
+
+bool Time::isDaylightSavingTime() const noexcept
+{
+    return TimeHelpers::millisToLocal (millisSinceEpoch).tm_isdst != 0;
+}
+
+String Time::getTimeZone() const noexcept
+{
+    String zone[2];
+
+  #if JUCE_WINDOWS
+    _tzset();
+
+   #ifdef _INC_TIME_INL
+    for (int i = 0; i < 2; ++i)
+    {
+        char name[128] = { 0 };
+        size_t length;
+        _get_tzname (&length, name, 127, i);
+        zone[i] = name;
+    }
+   #else
+    const char** const zonePtr = (const char**) _tzname;
+    zone[0] = zonePtr[0];
+    zone[1] = zonePtr[1];
+   #endif
+  #else
+    tzset();
+    const char** const zonePtr = (const char**) tzname;
+    zone[0] = zonePtr[0];
+    zone[1] = zonePtr[1];
+  #endif
+
+    if (isDaylightSavingTime())
+    {
+        zone[0] = zone[1];
+
+        if (zone[0].length() > 3
+             && zone[0].containsIgnoreCase ("daylight")
+             && zone[0].contains ("GMT"))
+            zone[0] = "BST";
+    }
+
+    return zone[0].substring (0, 3);
+}
+
+String Time::getMonthName (const bool threeLetterVersion) const
+{
+    return getMonthName (getMonth(), threeLetterVersion);
+}
+
+String Time::getWeekdayName (const bool threeLetterVersion) const
+{
+    return getWeekdayName (getDayOfWeek(), threeLetterVersion);
+}
+
+static const char* const shortMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+static const char* const longMonthNames[]  = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
+
+String Time::getMonthName (int monthNumber, const bool threeLetterVersion)
+{
+    monthNumber %= 12;
+
+    return TRANS (threeLetterVersion ? shortMonthNames [monthNumber]
+                                     : longMonthNames [monthNumber]);
+}
+
+String Time::getWeekdayName (int day, const bool threeLetterVersion)
+{
+    static const char* const shortDayNames[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+    static const char* const longDayNames[]  = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
+
+    day %= 7;
+
+    return TRANS (threeLetterVersion ? shortDayNames [day]
+                                     : longDayNames [day]);
+}
+
+//==============================================================================
+Time& Time::operator+= (RelativeTime delta) noexcept           { millisSinceEpoch += delta.inMilliseconds(); return *this; }
+Time& Time::operator-= (RelativeTime delta) noexcept           { millisSinceEpoch -= delta.inMilliseconds(); return *this; }
+
+Time operator+ (Time time, RelativeTime delta) noexcept        { Time t (time); return t += delta; }
+Time operator- (Time time, RelativeTime delta) noexcept        { Time t (time); return t -= delta; }
+Time operator+ (RelativeTime delta, Time time) noexcept        { Time t (time); return t += delta; }
+const RelativeTime operator- (Time time1, Time time2) noexcept { return RelativeTime::milliseconds (time1.toMilliseconds() - time2.toMilliseconds()); }
+
+bool operator== (Time time1, Time time2) noexcept      { return time1.toMilliseconds() == time2.toMilliseconds(); }
+bool operator!= (Time time1, Time time2) noexcept      { return time1.toMilliseconds() != time2.toMilliseconds(); }
+bool operator<  (Time time1, Time time2) noexcept      { return time1.toMilliseconds() <  time2.toMilliseconds(); }
+bool operator>  (Time time1, Time time2) noexcept      { return time1.toMilliseconds() >  time2.toMilliseconds(); }
+bool operator<= (Time time1, Time time2) noexcept      { return time1.toMilliseconds() <= time2.toMilliseconds(); }
+bool operator>= (Time time1, Time time2) noexcept      { return time1.toMilliseconds() >= time2.toMilliseconds(); }
+
+static int getMonthNumberForCompileDate (const String& m) noexcept
+{
+    for (int i = 0; i < 12; ++i)
+        if (m.equalsIgnoreCase (shortMonthNames[i]))
+            return i;
+
+    // If you hit this because your compiler has a non-standard __DATE__ format,
+    // let me know so we can add support for it!
+    jassertfalse;
+    return 0;
+}
+
+Time Time::getCompilationDate()
+{
+    StringArray dateTokens;
+    dateTokens.addTokens (__DATE__, true);
+    dateTokens.removeEmptyStrings (true);
+
+    return Time (dateTokens[2].getIntValue(),
+                 getMonthNumberForCompileDate (dateTokens[0]),
+                 dateTokens[1].getIntValue(), 12, 0);
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_Time.h b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_Time.h
new file mode 100644
index 0000000..4a35e08
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/time/juce_Time.h
@@ -0,0 +1,404 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_TIME_H_INCLUDED
+#define JUCE_TIME_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Holds an absolute date and time.
+
+    Internally, the time is stored at millisecond precision.
+
+    @see RelativeTime
+*/
+class JUCE_API  Time
+{
+public:
+    //==============================================================================
+    /** Creates a Time object.
+
+        This default constructor creates a time of 1st January 1970, (which is
+        represented internally as 0ms).
+
+        To create a time object representing the current time, use getCurrentTime().
+
+        @see getCurrentTime
+    */
+    Time() noexcept;
+
+    /** Creates a time based on a number of milliseconds.
+
+        The internal millisecond count is set to 0 (1st January 1970). To create a
+        time object set to the current time, use getCurrentTime().
+
+        @param millisecondsSinceEpoch   the number of milliseconds since the unix
+                                        'epoch' (midnight Jan 1st 1970).
+        @see getCurrentTime, currentTimeMillis
+    */
+    explicit Time (int64 millisecondsSinceEpoch) noexcept;
+
+    /** Creates a time from a set of date components.
+
+        The timezone is assumed to be whatever the system is using as its locale.
+
+        @param year             the year, in 4-digit format, e.g. 2004
+        @param month            the month, in the range 0 to 11
+        @param day              the day of the month, in the range 1 to 31
+        @param hours            hours in 24-hour clock format, 0 to 23
+        @param minutes          minutes 0 to 59
+        @param seconds          seconds 0 to 59
+        @param milliseconds     milliseconds 0 to 999
+        @param useLocalTime     if true, encode using the current machine's local time; if
+                                false, it will always work in GMT.
+    */
+    Time (int year,
+          int month,
+          int day,
+          int hours,
+          int minutes,
+          int seconds = 0,
+          int milliseconds = 0,
+          bool useLocalTime = true) noexcept;
+
+    /** Creates a copy of another Time object. */
+    Time (const Time& other) noexcept;
+
+    /** Destructor. */
+    ~Time() noexcept;
+
+    /** Copies this time from another one. */
+    Time& operator= (const Time& other) noexcept;
+
+    //==============================================================================
+    /** Returns a Time object that is set to the current system time.
+
+        @see currentTimeMillis
+    */
+    static Time JUCE_CALLTYPE getCurrentTime() noexcept;
+
+    /** Returns the time as a number of milliseconds.
+
+        @returns    the number of milliseconds this Time object represents, since
+                    midnight jan 1st 1970.
+        @see getMilliseconds
+    */
+    int64 toMilliseconds() const noexcept                           { return millisSinceEpoch; }
+
+    /** Returns the year.
+
+        A 4-digit format is used, e.g. 2004.
+    */
+    int getYear() const noexcept;
+
+    /** Returns the number of the month.
+
+        The value returned is in the range 0 to 11.
+        @see getMonthName
+    */
+    int getMonth() const noexcept;
+
+    /** Returns the name of the month.
+
+        @param threeLetterVersion   if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false
+                                    it'll return the long form, e.g. "January"
+        @see getMonth
+    */
+    String getMonthName (bool threeLetterVersion) const;
+
+    /** Returns the day of the month.
+        The value returned is in the range 1 to 31.
+    */
+    int getDayOfMonth() const noexcept;
+
+    /** Returns the number of the day of the week.
+        The value returned is in the range 0 to 6 (0 = sunday, 1 = monday, etc).
+    */
+    int getDayOfWeek() const noexcept;
+
+    /** Returns the number of the day of the year.
+        The value returned is in the range 0 to 365.
+    */
+    int getDayOfYear() const noexcept;
+
+    /** Returns the name of the weekday.
+
+        @param threeLetterVersion   if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if
+                                    false, it'll return the full version, e.g. "Tuesday".
+    */
+    String getWeekdayName (bool threeLetterVersion) const;
+
+    /** Returns the number of hours since midnight.
+
+        This is in 24-hour clock format, in the range 0 to 23.
+
+        @see getHoursInAmPmFormat, isAfternoon
+    */
+    int getHours() const noexcept;
+
+    /** Returns true if the time is in the afternoon.
+
+        So it returns true for "PM", false for "AM".
+
+        @see getHoursInAmPmFormat, getHours
+    */
+    bool isAfternoon() const noexcept;
+
+    /** Returns the hours in 12-hour clock format.
+
+        This will return a value 1 to 12 - use isAfternoon() to find out
+        whether this is in the afternoon or morning.
+
+        @see getHours, isAfternoon
+    */
+    int getHoursInAmPmFormat() const noexcept;
+
+    /** Returns the number of minutes, 0 to 59. */
+    int getMinutes() const noexcept;
+
+    /** Returns the number of seconds, 0 to 59. */
+    int getSeconds() const noexcept;
+
+    /** Returns the number of milliseconds, 0 to 999.
+
+        Unlike toMilliseconds(), this just returns the position within the
+        current second rather than the total number since the epoch.
+
+        @see toMilliseconds
+    */
+    int getMilliseconds() const noexcept;
+
+    /** Returns true if the local timezone uses a daylight saving correction. */
+    bool isDaylightSavingTime() const noexcept;
+
+    /** Returns a 3-character string to indicate the local timezone. */
+    String getTimeZone() const noexcept;
+
+    //==============================================================================
+    /** Quick way of getting a string version of a date and time.
+
+        For a more powerful way of formatting the date and time, see the formatted() method.
+
+        @param includeDate      whether to include the date in the string
+        @param includeTime      whether to include the time in the string
+        @param includeSeconds   if the time is being included, this provides an option not to include
+                                the seconds in it
+        @param use24HourClock   if the time is being included, sets whether to use am/pm or 24
+                                hour notation.
+        @see formatted
+    */
+    String toString (bool includeDate,
+                     bool includeTime,
+                     bool includeSeconds = true,
+                     bool use24HourClock = false) const noexcept;
+
+    /** Converts this date/time to a string with a user-defined format.
+
+        This uses the C strftime() function to format this time as a string. To save you
+        looking it up, these are the escape codes that strftime uses (other codes might
+        work on some platforms and not others, but these are the common ones):
+
+        %a  is replaced by the locale's abbreviated weekday name.
+        %A  is replaced by the locale's full weekday name.
+        %b  is replaced by the locale's abbreviated month name.
+        %B  is replaced by the locale's full month name.
+        %c  is replaced by the locale's appropriate date and time representation.
+        %d  is replaced by the day of the month as a decimal number [01,31].
+        %H  is replaced by the hour (24-hour clock) as a decimal number [00,23].
+        %I  is replaced by the hour (12-hour clock) as a decimal number [01,12].
+        %j  is replaced by the day of the year as a decimal number [001,366].
+        %m  is replaced by the month as a decimal number [01,12].
+        %M  is replaced by the minute as a decimal number [00,59].
+        %p  is replaced by the locale's equivalent of either a.m. or p.m.
+        %S  is replaced by the second as a decimal number [00,61].
+        %U  is replaced by the week number of the year (Sunday as the first day of the week) as a decimal number [00,53].
+        %w  is replaced by the weekday as a decimal number [0,6], with 0 representing Sunday.
+        %W  is replaced by the week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0.
+        %x  is replaced by the locale's appropriate date representation.
+        %X  is replaced by the locale's appropriate time representation.
+        %y  is replaced by the year without century as a decimal number [00,99].
+        %Y  is replaced by the year with century as a decimal number.
+        %Z  is replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists.
+        %%  is replaced by %.
+
+        @see toString
+    */
+    String formatted (const String& format) const;
+
+    //==============================================================================
+    /** Adds a RelativeTime to this time. */
+    Time& operator+= (RelativeTime delta) noexcept;
+    /** Subtracts a RelativeTime from this time. */
+    Time& operator-= (RelativeTime delta) noexcept;
+
+    //==============================================================================
+    /** Tries to set the computer's clock.
+
+        @returns    true if this succeeds, although depending on the system, the
+                    application might not have sufficient privileges to do this.
+    */
+    bool setSystemTimeToThisTime() const;
+
+    //==============================================================================
+    /** Returns the name of a day of the week.
+
+        @param dayNumber            the day, 0 to 6 (0 = sunday, 1 = monday, etc)
+        @param threeLetterVersion   if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if
+                                    false, it'll return the full version, e.g. "Tuesday".
+    */
+    static String getWeekdayName (int dayNumber, bool threeLetterVersion);
+
+    /** Returns the name of one of the months.
+
+        @param monthNumber  the month, 0 to 11
+        @param threeLetterVersion   if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false
+                                    it'll return the long form, e.g. "January"
+    */
+    static String getMonthName (int monthNumber, bool threeLetterVersion);
+
+    //==============================================================================
+    // Static methods for getting system timers directly..
+
+    /** Returns the current system time.
+
+        Returns the number of milliseconds since midnight jan 1st 1970.
+
+        Should be accurate to within a few millisecs, depending on platform,
+        hardware, etc.
+    */
+    static int64 currentTimeMillis() noexcept;
+
+    /** Returns the number of millisecs since a fixed event (usually system startup).
+
+        This returns a monotonically increasing value which it unaffected by changes to the
+        system clock. It should be accurate to within a few millisecs, depending on platform,
+        hardware, etc.
+
+        Being a 32-bit return value, it will of course wrap back to 0 after 2^32 seconds of
+        uptime, so be careful to take that into account. If you need a 64-bit time, you can
+        use currentTimeMillis() instead.
+
+        @see getApproximateMillisecondCounter
+    */
+    static uint32 getMillisecondCounter() noexcept;
+
+    /** Returns the number of millisecs since a fixed event (usually system startup).
+
+        This has the same function as getMillisecondCounter(), but returns a more accurate
+        value, using a higher-resolution timer if one is available.
+
+        @see getMillisecondCounter
+    */
+    static double getMillisecondCounterHiRes() noexcept;
+
+    /** Waits until the getMillisecondCounter() reaches a given value.
+
+        This will make the thread sleep as efficiently as it can while it's waiting.
+    */
+    static void waitForMillisecondCounter (uint32 targetTime) noexcept;
+
+    /** Less-accurate but faster version of getMillisecondCounter().
+
+        This will return the last value that getMillisecondCounter() returned, so doesn't
+        need to make a system call, but is less accurate - it shouldn't be more than
+        100ms away from the correct time, though, so is still accurate enough for a
+        lot of purposes.
+
+        @see getMillisecondCounter
+    */
+    static uint32 getApproximateMillisecondCounter() noexcept;
+
+    //==============================================================================
+    // High-resolution timers..
+
+    /** Returns the current high-resolution counter's tick-count.
+
+        This is a similar idea to getMillisecondCounter(), but with a higher
+        resolution.
+
+        @see getHighResolutionTicksPerSecond, highResolutionTicksToSeconds,
+             secondsToHighResolutionTicks
+    */
+    static int64 getHighResolutionTicks() noexcept;
+
+    /** Returns the resolution of the high-resolution counter in ticks per second.
+
+        @see getHighResolutionTicks, highResolutionTicksToSeconds,
+             secondsToHighResolutionTicks
+    */
+    static int64 getHighResolutionTicksPerSecond() noexcept;
+
+    /** Converts a number of high-resolution ticks into seconds.
+
+        @see getHighResolutionTicks, getHighResolutionTicksPerSecond,
+             secondsToHighResolutionTicks
+    */
+    static double highResolutionTicksToSeconds (int64 ticks) noexcept;
+
+    /** Converts a number seconds into high-resolution ticks.
+
+        @see getHighResolutionTicks, getHighResolutionTicksPerSecond,
+             highResolutionTicksToSeconds
+    */
+    static int64 secondsToHighResolutionTicks (double seconds) noexcept;
+
+    /** Returns a Time based on the value of the __DATE__ macro when this module was compiled */
+    static Time getCompilationDate();
+
+private:
+    //==============================================================================
+    int64 millisSinceEpoch;
+};
+
+//==============================================================================
+/** Adds a RelativeTime to a Time. */
+JUCE_API Time operator+ (Time time, RelativeTime delta) noexcept;
+/** Adds a RelativeTime to a Time. */
+JUCE_API Time operator+ (RelativeTime delta, Time time) noexcept;
+
+/** Subtracts a RelativeTime from a Time. */
+JUCE_API Time operator- (Time time, RelativeTime delta) noexcept;
+/** Returns the relative time difference between two times. */
+JUCE_API const RelativeTime operator- (Time time1, Time time2) noexcept;
+
+/** Compares two Time objects. */
+JUCE_API bool operator== (Time time1, Time time2) noexcept;
+/** Compares two Time objects. */
+JUCE_API bool operator!= (Time time1, Time time2) noexcept;
+/** Compares two Time objects. */
+JUCE_API bool operator<  (Time time1, Time time2) noexcept;
+/** Compares two Time objects. */
+JUCE_API bool operator<= (Time time1, Time time2) noexcept;
+/** Compares two Time objects. */
+JUCE_API bool operator>  (Time time1, Time time2) noexcept;
+/** Compares two Time objects. */
+JUCE_API bool operator>= (Time time1, Time time2) noexcept;
+
+
+#endif   // JUCE_TIME_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/unit_tests/juce_UnitTest.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/unit_tests/juce_UnitTest.cpp
new file mode 100644
index 0000000..f5a60c1
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/unit_tests/juce_UnitTest.cpp
@@ -0,0 +1,260 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+UnitTest::UnitTest (const String& nm)
+    : name (nm), runner (nullptr)
+{
+    getAllTests().add (this);
+}
+
+UnitTest::~UnitTest()
+{
+    getAllTests().removeFirstMatchingValue (this);
+}
+
+Array<UnitTest*>& UnitTest::getAllTests()
+{
+    static Array<UnitTest*> tests;
+    return tests;
+}
+
+void UnitTest::initialise()  {}
+void UnitTest::shutdown()   {}
+
+void UnitTest::performTest (UnitTestRunner* const newRunner)
+{
+    jassert (newRunner != nullptr);
+    runner = newRunner;
+
+    initialise();
+    runTest();
+    shutdown();
+}
+
+void UnitTest::logMessage (const String& message)
+{
+    // This method's only valid while the test is being run!
+    jassert (runner != nullptr);
+
+    runner->logMessage (message);
+}
+
+void UnitTest::beginTest (const String& testName)
+{
+    // This method's only valid while the test is being run!
+    jassert (runner != nullptr);
+
+    runner->beginNewTest (this, testName);
+}
+
+void UnitTest::expect (const bool result, const String& failureMessage)
+{
+    // This method's only valid while the test is being run!
+    jassert (runner != nullptr);
+
+    if (result)
+        runner->addPass();
+    else
+        runner->addFail (failureMessage);
+}
+
+Random UnitTest::getRandom() const
+{
+    // This method's only valid while the test is being run!
+    jassert (runner != nullptr);
+
+    return runner->randomForTest;
+}
+
+//==============================================================================
+UnitTestRunner::UnitTestRunner()
+    : currentTest (nullptr),
+      assertOnFailure (true),
+      logPasses (false)
+{
+}
+
+UnitTestRunner::~UnitTestRunner()
+{
+}
+
+void UnitTestRunner::setAssertOnFailure (bool shouldAssert) noexcept
+{
+    assertOnFailure = shouldAssert;
+}
+
+void UnitTestRunner::setPassesAreLogged (bool shouldDisplayPasses) noexcept
+{
+    logPasses = shouldDisplayPasses;
+}
+
+int UnitTestRunner::getNumResults() const noexcept
+{
+    return results.size();
+}
+
+const UnitTestRunner::TestResult* UnitTestRunner::getResult (int index) const noexcept
+{
+    return results [index];
+}
+
+void UnitTestRunner::resultsUpdated()
+{
+}
+
+void UnitTestRunner::runTests (const Array<UnitTest*>& tests, int64 randomSeed)
+{
+    results.clear();
+    resultsUpdated();
+
+    if (randomSeed == 0)
+        randomSeed = Random().nextInt (0x7ffffff);
+
+    randomForTest = Random (randomSeed);
+    logMessage ("Random seed: 0x" + String::toHexString (randomSeed));
+
+    for (int i = 0; i < tests.size(); ++i)
+    {
+        if (shouldAbortTests())
+            break;
+
+        try
+        {
+            tests.getUnchecked(i)->performTest (this);
+        }
+        catch (...)
+        {
+            addFail ("An unhandled exception was thrown!");
+        }
+    }
+
+    endTest();
+}
+
+void UnitTestRunner::runAllTests (int64 randomSeed)
+{
+    runTests (UnitTest::getAllTests(), randomSeed);
+}
+
+void UnitTestRunner::logMessage (const String& message)
+{
+    Logger::writeToLog (message);
+}
+
+bool UnitTestRunner::shouldAbortTests()
+{
+    return false;
+}
+
+void UnitTestRunner::beginNewTest (UnitTest* const test, const String& subCategory)
+{
+    endTest();
+    currentTest = test;
+
+    TestResult* const r = new TestResult();
+    results.add (r);
+    r->unitTestName = test->getName();
+    r->subcategoryName = subCategory;
+    r->passes = 0;
+    r->failures = 0;
+
+    logMessage ("-----------------------------------------------------------------");
+    logMessage ("Starting test: " + r->unitTestName + " / " + subCategory + "...");
+
+    resultsUpdated();
+}
+
+void UnitTestRunner::endTest()
+{
+    if (results.size() > 0)
+    {
+        TestResult* const r = results.getLast();
+
+        if (r->failures > 0)
+        {
+            String m ("FAILED!!  ");
+            m << r->failures << (r->failures == 1 ? " test" : " tests")
+              << " failed, out of a total of " << (r->passes + r->failures);
+
+            logMessage (String::empty);
+            logMessage (m);
+            logMessage (String::empty);
+        }
+        else
+        {
+            logMessage ("All tests completed successfully");
+        }
+    }
+}
+
+void UnitTestRunner::addPass()
+{
+    {
+        const ScopedLock sl (results.getLock());
+
+        TestResult* const r = results.getLast();
+        jassert (r != nullptr); // You need to call UnitTest::beginTest() before performing any tests!
+
+        r->passes++;
+
+        if (logPasses)
+        {
+            String message ("Test ");
+            message << (r->failures + r->passes) << " passed";
+            logMessage (message);
+        }
+    }
+
+    resultsUpdated();
+}
+
+void UnitTestRunner::addFail (const String& failureMessage)
+{
+    {
+        const ScopedLock sl (results.getLock());
+
+        TestResult* const r = results.getLast();
+        jassert (r != nullptr); // You need to call UnitTest::beginTest() before performing any tests!
+
+        r->failures++;
+
+        String message ("!!! Test ");
+        message << (r->failures + r->passes) << " failed";
+
+        if (failureMessage.isNotEmpty())
+            message << ": " << failureMessage;
+
+        r->messages.add (message);
+
+        logMessage (message);
+    }
+
+    resultsUpdated();
+
+    if (assertOnFailure) { jassertfalse; }
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/unit_tests/juce_UnitTest.h b/src/htio2/JUCE-3.0.8/modules/juce_core/unit_tests/juce_UnitTest.h
new file mode 100644
index 0000000..f5908c1
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/unit_tests/juce_UnitTest.h
@@ -0,0 +1,311 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_UNITTEST_H_INCLUDED
+#define JUCE_UNITTEST_H_INCLUDED
+
+class UnitTestRunner;
+
+
+//==============================================================================
+/**
+    This is a base class for classes that perform a unit test.
+
+    To write a test using this class, your code should look something like this:
+
+    @code
+    class MyTest  : public UnitTest
+    {
+    public:
+        MyTest()  : UnitTest ("Foobar testing") {}
+
+        void runTest()
+        {
+            beginTest ("Part 1");
+
+            expect (myFoobar.doesSomething());
+            expect (myFoobar.doesSomethingElse());
+
+            beginTest ("Part 2");
+
+            expect (myOtherFoobar.doesSomething());
+            expect (myOtherFoobar.doesSomethingElse());
+
+            ...etc..
+        }
+    };
+
+    // Creating a static instance will automatically add the instance to the array
+    // returned by UnitTest::getAllTests(), so the test will be included when you call
+    // UnitTestRunner::runAllTests()
+    static MyTest test;
+    @endcode
+
+    To run a test, use the UnitTestRunner class.
+
+    @see UnitTestRunner
+*/
+class JUCE_API  UnitTest
+{
+public:
+    //==============================================================================
+    /** Creates a test with the given name. */
+    explicit UnitTest (const String& name);
+
+    /** Destructor. */
+    virtual ~UnitTest();
+
+    /** Returns the name of the test. */
+    const String& getName() const noexcept       { return name; }
+
+    /** Runs the test, using the specified UnitTestRunner.
+        You shouldn't need to call this method directly - use
+        UnitTestRunner::runTests() instead.
+    */
+    void performTest (UnitTestRunner* runner);
+
+    /** Returns the set of all UnitTest objects that currently exist. */
+    static Array<UnitTest*>& getAllTests();
+
+    //==============================================================================
+    /** You can optionally implement this method to set up your test.
+        This method will be called before runTest().
+    */
+    virtual void initialise();
+
+    /** You can optionally implement this method to clear up after your test has been run.
+        This method will be called after runTest() has returned.
+    */
+    virtual void shutdown();
+
+    /** Implement this method in your subclass to actually run your tests.
+
+        The content of your implementation should call beginTest() and expect()
+        to perform the tests.
+    */
+    virtual void runTest() = 0;
+
+    //==============================================================================
+    /** Tells the system that a new subsection of tests is beginning.
+        This should be called from your runTest() method, and may be called
+        as many times as you like, to demarcate different sets of tests.
+    */
+    void beginTest (const String& testName);
+
+    //==============================================================================
+    /** Checks that the result of a test is true, and logs this result.
+
+        In your runTest() method, you should call this method for each condition that
+        you want to check, e.g.
+
+        @code
+        void runTest()
+        {
+            beginTest ("basic tests");
+            expect (x + y == 2);
+            expect (getThing() == someThing);
+            ...etc...
+        }
+        @endcode
+
+        If testResult is true, a pass is logged; if it's false, a failure is logged.
+        If the failure message is specified, it will be written to the log if the test fails.
+    */
+    void expect (bool testResult, const String& failureMessage = String::empty);
+
+    /** Compares two values, and if they don't match, prints out a message containing the
+        expected and actual result values.
+    */
+    template <class ValueType>
+    void expectEquals (ValueType actual, ValueType expected, String failureMessage = String::empty)
+    {
+        const bool result = (actual == expected);
+
+        if (! result)
+        {
+            if (failureMessage.isNotEmpty())
+                failureMessage << " -- ";
+
+            failureMessage << "Expected value: " << expected << ", Actual value: " << actual;
+        }
+
+        expect (result, failureMessage);
+    }
+
+    //==============================================================================
+    /** Writes a message to the test log.
+        This can only be called from within your runTest() method.
+    */
+    void logMessage (const String& message);
+
+    /** Returns a shared RNG that all unit tests should use.
+        If a test needs random numbers, it's important that when an error is found, the
+        exact circumstances can be re-created in order to re-test the problem, by
+        repeating the test with the same random seed value.
+        To make this possible, the UnitTestRunner class creates a master seed value
+        for the run, writes this number to the log, and then this method returns a
+        Random object based on that seed. All tests should only use this method to
+        create any Random objects that they need.
+
+        Note that this method will return an identical object each time it's called
+        for a given run, so if you need several different Random objects, the best
+        way to do that is to call Random::combineSeed() on the result to permute it
+        with a constant value.
+    */
+    Random getRandom() const;
+
+private:
+    //==============================================================================
+    const String name;
+    UnitTestRunner* runner;
+
+    JUCE_DECLARE_NON_COPYABLE (UnitTest)
+};
+
+
+//==============================================================================
+/**
+    Runs a set of unit tests.
+
+    You can instantiate one of these objects and use it to invoke tests on a set of
+    UnitTest objects.
+
+    By using a subclass of UnitTestRunner, you can intercept logging messages and
+    perform custom behaviour when each test completes.
+
+    @see UnitTest
+*/
+class JUCE_API  UnitTestRunner
+{
+public:
+    //==============================================================================
+    /** */
+    UnitTestRunner();
+
+    /** Destructor. */
+    virtual ~UnitTestRunner();
+
+    /** Runs a set of tests.
+
+        The tests are performed in order, and the results are logged. To run all the
+        registered UnitTest objects that exist, use runAllTests().
+
+        If you want to run the tests with a predetermined seed, you can pass that into
+        the randomSeed argument, or pass 0 to have a randomly-generated seed chosen.
+    */
+    void runTests (const Array<UnitTest*>& tests, int64 randomSeed = 0);
+
+    /** Runs all the UnitTest objects that currently exist.
+        This calls runTests() for all the objects listed in UnitTest::getAllTests().
+
+        If you want to run the tests with a predetermined seed, you can pass that into
+        the randomSeed argument, or pass 0 to have a randomly-generated seed chosen.
+    */
+    void runAllTests (int64 randomSeed = 0);
+
+    /** Sets a flag to indicate whether an assertion should be triggered if a test fails.
+        This is true by default.
+    */
+    void setAssertOnFailure (bool shouldAssert) noexcept;
+
+    /** Sets a flag to indicate whether successful tests should be logged.
+        By default, this is set to false, so that only failures will be displayed in the log.
+    */
+    void setPassesAreLogged (bool shouldDisplayPasses) noexcept;
+
+    //==============================================================================
+    /** Contains the results of a test.
+
+        One of these objects is instantiated each time UnitTest::beginTest() is called, and
+        it contains details of the number of subsequent UnitTest::expect() calls that are
+        made.
+    */
+    struct TestResult
+    {
+        /** The main name of this test (i.e. the name of the UnitTest object being run). */
+        String unitTestName;
+        /** The name of the current subcategory (i.e. the name that was set when UnitTest::beginTest() was called). */
+        String subcategoryName;
+
+        /** The number of UnitTest::expect() calls that succeeded. */
+        int passes;
+        /** The number of UnitTest::expect() calls that failed. */
+        int failures;
+
+        /** A list of messages describing the failed tests. */
+        StringArray messages;
+    };
+
+    /** Returns the number of TestResult objects that have been performed.
+        @see getResult
+    */
+    int getNumResults() const noexcept;
+
+    /** Returns one of the TestResult objects that describes a test that has been run.
+        @see getNumResults
+    */
+    const TestResult* getResult (int index) const noexcept;
+
+protected:
+    /** Called when the list of results changes.
+        You can override this to perform some sort of behaviour when results are added.
+    */
+    virtual void resultsUpdated();
+
+    /** Logs a message about the current test progress.
+        By default this just writes the message to the Logger class, but you could override
+        this to do something else with the data.
+    */
+    virtual void logMessage (const String& message);
+
+    /** This can be overridden to let the runner know that it should abort the tests
+        as soon as possible, e.g. because the thread needs to stop.
+    */
+    virtual bool shouldAbortTests();
+
+private:
+    //==============================================================================
+    friend class UnitTest;
+
+    UnitTest* currentTest;
+    String currentSubCategory;
+    OwnedArray <TestResult, CriticalSection> results;
+    bool assertOnFailure, logPasses;
+    Random randomForTest;
+
+    void beginNewTest (UnitTest* test, const String& subCategory);
+    void endTest();
+
+    void addPass();
+    void addFail (const String& failureMessage);
+
+    JUCE_DECLARE_NON_COPYABLE (UnitTestRunner)
+};
+
+
+#endif   // JUCE_UNITTEST_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlDocument.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlDocument.cpp
new file mode 100644
index 0000000..2eab527
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlDocument.cpp
@@ -0,0 +1,891 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+XmlDocument::XmlDocument (const String& documentText)
+    : originalText (documentText),
+      input (nullptr),
+      outOfData (false),
+      errorOccurred (false),
+      needToLoadDTD (false),
+      ignoreEmptyTextElements (true)
+{
+}
+
+XmlDocument::XmlDocument (const File& file)
+    : input (nullptr),
+      outOfData (false),
+      errorOccurred (false),
+      needToLoadDTD (false),
+      ignoreEmptyTextElements (true),
+      inputSource (new FileInputSource (file))
+{
+}
+
+XmlDocument::~XmlDocument()
+{
+}
+
+XmlElement* XmlDocument::parse (const File& file)
+{
+    XmlDocument doc (file);
+    return doc.getDocumentElement();
+}
+
+XmlElement* XmlDocument::parse (const String& xmlData)
+{
+    XmlDocument doc (xmlData);
+    return doc.getDocumentElement();
+}
+
+void XmlDocument::setInputSource (InputSource* const newSource) noexcept
+{
+    inputSource = newSource;
+}
+
+void XmlDocument::setEmptyTextElementsIgnored (const bool shouldBeIgnored) noexcept
+{
+    ignoreEmptyTextElements = shouldBeIgnored;
+}
+
+namespace XmlIdentifierChars
+{
+    static bool isIdentifierCharSlow (const juce_wchar c) noexcept
+    {
+        return CharacterFunctions::isLetterOrDigit (c)
+                 || c == '_' || c == '-' || c == ':' || c == '.';
+    }
+
+    static bool isIdentifierChar (const juce_wchar c) noexcept
+    {
+        static const uint32 legalChars[] = { 0, 0x7ff6000, 0x87fffffe, 0x7fffffe, 0 };
+
+        return ((int) c < (int) numElementsInArray (legalChars) * 32) ? ((legalChars [c >> 5] & (1 << (c & 31))) != 0)
+                                                                      : isIdentifierCharSlow (c);
+    }
+
+    /*static void generateIdentifierCharConstants()
+    {
+        uint32 n[8] = { 0 };
+        for (int i = 0; i < 256; ++i)
+            if (isIdentifierCharSlow (i))
+                n[i >> 5] |= (1 << (i & 31));
+
+        String s;
+        for (int i = 0; i < 8; ++i)
+            s << "0x" << String::toHexString ((int) n[i]) << ", ";
+
+        DBG (s);
+    }*/
+
+    static String::CharPointerType findEndOfToken (String::CharPointerType p)
+    {
+        while (isIdentifierChar (*p))
+            ++p;
+
+        return p;
+    }
+}
+
+XmlElement* XmlDocument::getDocumentElement (const bool onlyReadOuterDocumentElement)
+{
+    if (originalText.isEmpty() && inputSource != nullptr)
+    {
+        ScopedPointer<InputStream> in (inputSource->createInputStream());
+
+        if (in != nullptr)
+        {
+            MemoryOutputStream data;
+            data.writeFromInputStream (*in, onlyReadOuterDocumentElement ? 8192 : -1);
+
+           #if JUCE_STRING_UTF_TYPE == 8
+            if (data.getDataSize() > 2)
+            {
+                data.writeByte (0);
+                const char* text = static_cast<const char*> (data.getData());
+
+                if (CharPointer_UTF16::isByteOrderMarkBigEndian (text)
+                      || CharPointer_UTF16::isByteOrderMarkLittleEndian (text))
+                {
+                    originalText = data.toString();
+                }
+                else
+                {
+                    if (CharPointer_UTF8::isByteOrderMark (text))
+                        text += 3;
+
+                    // parse the input buffer directly to avoid copying it all to a string..
+                    return parseDocumentElement (String::CharPointerType (text), onlyReadOuterDocumentElement);
+                }
+            }
+           #else
+            originalText = data.toString();
+           #endif
+        }
+    }
+
+    return parseDocumentElement (originalText.getCharPointer(), onlyReadOuterDocumentElement);
+}
+
+const String& XmlDocument::getLastParseError() const noexcept
+{
+    return lastError;
+}
+
+void XmlDocument::setLastError (const String& desc, const bool carryOn)
+{
+    lastError = desc;
+    errorOccurred = ! carryOn;
+}
+
+String XmlDocument::getFileContents (const String& filename) const
+{
+    if (inputSource != nullptr)
+    {
+        const ScopedPointer<InputStream> in (inputSource->createInputStreamFor (filename.trim().unquoted()));
+
+        if (in != nullptr)
+            return in->readEntireStreamAsString();
+    }
+
+    return String::empty;
+}
+
+juce_wchar XmlDocument::readNextChar() noexcept
+{
+    const juce_wchar c = input.getAndAdvance();
+
+    if (c == 0)
+    {
+        outOfData = true;
+        --input;
+    }
+
+    return c;
+}
+
+XmlElement* XmlDocument::parseDocumentElement (String::CharPointerType textToParse,
+                                               const bool onlyReadOuterDocumentElement)
+{
+    input = textToParse;
+    errorOccurred = false;
+    outOfData = false;
+    needToLoadDTD = true;
+
+    if (textToParse.isEmpty())
+    {
+        lastError = "not enough input";
+    }
+    else if (! parseHeader())
+    {
+        lastError = "malformed header";
+    }
+    else if (! parseDTD())
+    {
+        lastError = "malformed DTD";
+    }
+    else
+    {
+        lastError.clear();
+
+        ScopedPointer<XmlElement> result (readNextElement (! onlyReadOuterDocumentElement));
+
+        if (! errorOccurred)
+            return result.release();
+    }
+
+    return nullptr;
+}
+
+bool XmlDocument::parseHeader()
+{
+    skipNextWhiteSpace();
+
+    if (CharacterFunctions::compareUpTo (input, CharPointer_ASCII ("<?xml"), 5) == 0)
+    {
+        const String::CharPointerType headerEnd (CharacterFunctions::find (input, CharPointer_ASCII ("?>")));
+
+        if (headerEnd.isEmpty())
+            return false;
+
+       #if JUCE_DEBUG
+        const String encoding (String (input, headerEnd)
+                                 .fromFirstOccurrenceOf ("encoding", false, true)
+                                 .fromFirstOccurrenceOf ("=", false, false)
+                                 .fromFirstOccurrenceOf ("\"", false, false)
+                                 .upToFirstOccurrenceOf ("\"", false, false).trim());
+
+        /* If you load an XML document with a non-UTF encoding type, it may have been
+           loaded wrongly.. Since all the files are read via the normal juce file streams,
+           they're treated as UTF-8, so by the time it gets to the parser, the encoding will
+           have been lost. Best plan is to stick to utf-8 or if you have specific files to
+           read, use your own code to convert them to a unicode String, and pass that to the
+           XML parser.
+        */
+        jassert (encoding.isEmpty() || encoding.startsWithIgnoreCase ("utf-"));
+       #endif
+
+        input = headerEnd + 2;
+        skipNextWhiteSpace();
+    }
+
+    return true;
+}
+
+bool XmlDocument::parseDTD()
+{
+    if (CharacterFunctions::compareUpTo (input, CharPointer_ASCII ("<!DOCTYPE"), 9) == 0)
+    {
+        input += 9;
+        const String::CharPointerType dtdStart (input);
+
+        for (int n = 1; n > 0;)
+        {
+            const juce_wchar c = readNextChar();
+
+            if (outOfData)
+                return false;
+
+            if (c == '<')
+                ++n;
+            else if (c == '>')
+                --n;
+        }
+
+        dtdText = String (dtdStart, input - 1).trim();
+    }
+
+    return true;
+}
+
+void XmlDocument::skipNextWhiteSpace()
+{
+    for (;;)
+    {
+        input = input.findEndOfWhitespace();
+
+        if (input.isEmpty())
+        {
+            outOfData = true;
+            break;
+        }
+
+        if (*input == '<')
+        {
+            if (input[1] == '!'
+                 && input[2] == '-'
+                 && input[3] == '-')
+            {
+                input += 4;
+                const int closeComment = input.indexOf (CharPointer_ASCII ("-->"));
+
+                if (closeComment < 0)
+                {
+                    outOfData = true;
+                    break;
+                }
+
+                input += closeComment + 3;
+                continue;
+            }
+
+            if (input[1] == '?')
+            {
+                input += 2;
+                const int closeBracket = input.indexOf (CharPointer_ASCII ("?>"));
+
+                if (closeBracket < 0)
+                {
+                    outOfData = true;
+                    break;
+                }
+
+                input += closeBracket + 2;
+                continue;
+            }
+        }
+
+        break;
+    }
+}
+
+void XmlDocument::readQuotedString (String& result)
+{
+    const juce_wchar quote = readNextChar();
+
+    while (! outOfData)
+    {
+        const juce_wchar c = readNextChar();
+
+        if (c == quote)
+            break;
+
+        --input;
+
+        if (c == '&')
+        {
+            readEntity (result);
+        }
+        else
+        {
+            const String::CharPointerType start (input);
+
+            for (;;)
+            {
+                const juce_wchar character = *input;
+
+                if (character == quote)
+                {
+                    result.appendCharPointer (start, input);
+                    ++input;
+                    return;
+                }
+                else if (character == '&')
+                {
+                    result.appendCharPointer (start, input);
+                    break;
+                }
+                else if (character == 0)
+                {
+                    setLastError ("unmatched quotes", false);
+                    outOfData = true;
+                    break;
+                }
+
+                ++input;
+            }
+        }
+    }
+}
+
+XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements)
+{
+    XmlElement* node = nullptr;
+
+    skipNextWhiteSpace();
+    if (outOfData)
+        return nullptr;
+
+    if (*input == '<')
+    {
+        ++input;
+        String::CharPointerType endOfToken (XmlIdentifierChars::findEndOfToken (input));
+
+        if (endOfToken == input)
+        {
+            // no tag name - but allow for a gap after the '<' before giving an error
+            skipNextWhiteSpace();
+            endOfToken = XmlIdentifierChars::findEndOfToken (input);
+
+            if (endOfToken == input)
+            {
+                setLastError ("tag name missing", false);
+                return node;
+            }
+        }
+
+        node = new XmlElement (input, endOfToken);
+        input = endOfToken;
+        LinkedListPointer<XmlElement::XmlAttributeNode>::Appender attributeAppender (node->attributes);
+
+        // look for attributes
+        for (;;)
+        {
+            skipNextWhiteSpace();
+
+            const juce_wchar c = *input;
+
+            // empty tag..
+            if (c == '/' && input[1] == '>')
+            {
+                input += 2;
+                break;
+            }
+
+            // parse the guts of the element..
+            if (c == '>')
+            {
+                ++input;
+
+                if (alsoParseSubElements)
+                    readChildElements (*node);
+
+                break;
+            }
+
+            // get an attribute..
+            if (XmlIdentifierChars::isIdentifierChar (c))
+            {
+                String::CharPointerType attNameEnd (XmlIdentifierChars::findEndOfToken (input));
+
+                if (attNameEnd != input)
+                {
+                    const String::CharPointerType attNameStart (input);
+                    input = attNameEnd;
+
+                    skipNextWhiteSpace();
+
+                    if (readNextChar() == '=')
+                    {
+                        skipNextWhiteSpace();
+
+                        const juce_wchar nextChar = *input;
+
+                        if (nextChar == '"' || nextChar == '\'')
+                        {
+                            XmlElement::XmlAttributeNode* const newAtt
+                                = new XmlElement::XmlAttributeNode (attNameStart, attNameEnd);
+
+                            readQuotedString (newAtt->value);
+                            attributeAppender.append (newAtt);
+                            continue;
+                        }
+                    }
+                    else
+                    {
+                        setLastError ("expected '=' after attribute '"
+                                        + String (attNameStart, attNameEnd) + "'", false);
+                        return node;
+                    }
+                }
+            }
+            else
+            {
+                if (! outOfData)
+                    setLastError ("illegal character found in " + node->getTagName() + ": '" + c + "'", false);
+            }
+
+            break;
+        }
+    }
+
+    return node;
+}
+
+void XmlDocument::readChildElements (XmlElement& parent)
+{
+    LinkedListPointer<XmlElement>::Appender childAppender (parent.firstChildElement);
+
+    for (;;)
+    {
+        const String::CharPointerType preWhitespaceInput (input);
+        skipNextWhiteSpace();
+
+        if (outOfData)
+        {
+            setLastError ("unmatched tags", false);
+            break;
+        }
+
+        if (*input == '<')
+        {
+            const juce_wchar c1 = input[1];
+
+            if (c1 == '/')
+            {
+                // our close tag..
+                const int closeTag = input.indexOf ((juce_wchar) '>');
+
+                if (closeTag >= 0)
+                    input += closeTag + 1;
+
+                break;
+            }
+
+            if (c1 == '!' && CharacterFunctions::compareUpTo (input + 2, CharPointer_ASCII ("[CDATA["), 7) == 0)
+            {
+                input += 9;
+                const String::CharPointerType inputStart (input);
+
+                for (;;)
+                {
+                    const juce_wchar c0 = *input;
+
+                    if (c0 == 0)
+                    {
+                        setLastError ("unterminated CDATA section", false);
+                        outOfData = true;
+                        break;
+                    }
+                    else if (c0 == ']'
+                              && input[1] == ']'
+                              && input[2] == '>')
+                    {
+                        childAppender.append (XmlElement::createTextElement (String (inputStart, input)));
+                        input += 3;
+                        break;
+                    }
+
+                    ++input;
+                }
+            }
+            else
+            {
+                // this is some other element, so parse and add it..
+                if (XmlElement* const n = readNextElement (true))
+                    childAppender.append (n);
+                else
+                    break;
+            }
+        }
+        else  // must be a character block
+        {
+            input = preWhitespaceInput; // roll back to include the leading whitespace
+            String textElementContent;
+
+            for (;;)
+            {
+                const juce_wchar c = *input;
+
+                if (c == '<')
+                {
+                    if (input[1] == '!' && input[2] == '-' && input[3] == '-')
+                    {
+                        input += 4;
+                        const int closeComment = input.indexOf (CharPointer_ASCII ("-->"));
+
+                        if (closeComment < 0)
+                        {
+                            setLastError ("unterminated comment", false);
+                            outOfData = true;
+                            return;
+                        }
+
+                        input += closeComment + 3;
+                        continue;
+                    }
+
+                    break;
+                }
+
+                if (c == 0)
+                {
+                    setLastError ("unmatched tags", false);
+                    outOfData = true;
+                    return;
+                }
+
+                if (c == '&')
+                {
+                    String entity;
+                    readEntity (entity);
+
+                    if (entity.startsWithChar ('<') && entity [1] != 0)
+                    {
+                        const String::CharPointerType oldInput (input);
+                        const bool oldOutOfData = outOfData;
+
+                        input = entity.getCharPointer();
+                        outOfData = false;
+
+                        for (;;)
+                        {
+                            XmlElement* const n = readNextElement (true);
+
+                            if (n == nullptr)
+                                break;
+
+                            childAppender.append (n);
+                        }
+
+                        input = oldInput;
+                        outOfData = oldOutOfData;
+                    }
+                    else
+                    {
+                        textElementContent += entity;
+                    }
+                }
+                else
+                {
+                    const String::CharPointerType start (input);
+
+                    for (;;)
+                    {
+                        const juce_wchar nextChar = *input;
+
+                        if (nextChar == '<' || nextChar == '&')
+                            break;
+
+                        if (nextChar == 0)
+                        {
+                            setLastError ("unmatched tags", false);
+                            outOfData = true;
+                            return;
+                        }
+
+                        ++input;
+                    }
+
+                    textElementContent.appendCharPointer (start, input);
+                }
+            }
+
+            if ((! ignoreEmptyTextElements) || textElementContent.containsNonWhitespaceChars())
+                childAppender.append (XmlElement::createTextElement (textElementContent));
+        }
+    }
+}
+
+void XmlDocument::readEntity (String& result)
+{
+    // skip over the ampersand
+    ++input;
+
+    if (input.compareIgnoreCaseUpTo (CharPointer_ASCII ("amp;"), 4) == 0)
+    {
+        input += 4;
+        result += '&';
+    }
+    else if (input.compareIgnoreCaseUpTo (CharPointer_ASCII ("quot;"), 5) == 0)
+    {
+        input += 5;
+        result += '"';
+    }
+    else if (input.compareIgnoreCaseUpTo (CharPointer_ASCII ("apos;"), 5) == 0)
+    {
+        input += 5;
+        result += '\'';
+    }
+    else if (input.compareIgnoreCaseUpTo (CharPointer_ASCII ("lt;"), 3) == 0)
+    {
+        input += 3;
+        result += '<';
+    }
+    else if (input.compareIgnoreCaseUpTo (CharPointer_ASCII ("gt;"), 3) == 0)
+    {
+        input += 3;
+        result += '>';
+    }
+    else if (*input == '#')
+    {
+        int charCode = 0;
+        ++input;
+
+        if (*input == 'x' || *input == 'X')
+        {
+            ++input;
+            int numChars = 0;
+
+            while (input[0] != ';')
+            {
+                const int hexValue = CharacterFunctions::getHexDigitValue (input[0]);
+
+                if (hexValue < 0 || ++numChars > 8)
+                {
+                    setLastError ("illegal escape sequence", true);
+                    break;
+                }
+
+                charCode = (charCode << 4) | hexValue;
+                ++input;
+            }
+
+            ++input;
+        }
+        else if (input[0] >= '0' && input[0] <= '9')
+        {
+            int numChars = 0;
+
+            while (input[0] != ';')
+            {
+                if (++numChars > 12)
+                {
+                    setLastError ("illegal escape sequence", true);
+                    break;
+                }
+
+                charCode = charCode * 10 + ((int) input[0] - '0');
+                ++input;
+            }
+
+            ++input;
+        }
+        else
+        {
+            setLastError ("illegal escape sequence", true);
+            result += '&';
+            return;
+        }
+
+        result << (juce_wchar) charCode;
+    }
+    else
+    {
+        const String::CharPointerType entityNameStart (input);
+        const int closingSemiColon = input.indexOf ((juce_wchar) ';');
+
+        if (closingSemiColon < 0)
+        {
+            outOfData = true;
+            result += '&';
+        }
+        else
+        {
+            input += closingSemiColon + 1;
+
+            result += expandExternalEntity (String (entityNameStart, (size_t) closingSemiColon));
+        }
+    }
+}
+
+String XmlDocument::expandEntity (const String& ent)
+{
+    if (ent.equalsIgnoreCase ("amp"))   return String::charToString ('&');
+    if (ent.equalsIgnoreCase ("quot"))  return String::charToString ('"');
+    if (ent.equalsIgnoreCase ("apos"))  return String::charToString ('\'');
+    if (ent.equalsIgnoreCase ("lt"))    return String::charToString ('<');
+    if (ent.equalsIgnoreCase ("gt"))    return String::charToString ('>');
+
+    if (ent[0] == '#')
+    {
+        const juce_wchar char1 = ent[1];
+
+        if (char1 == 'x' || char1 == 'X')
+            return String::charToString (static_cast <juce_wchar> (ent.substring (2).getHexValue32()));
+
+        if (char1 >= '0' && char1 <= '9')
+            return String::charToString (static_cast <juce_wchar> (ent.substring (1).getIntValue()));
+
+        setLastError ("illegal escape sequence", false);
+        return String::charToString ('&');
+    }
+
+    return expandExternalEntity (ent);
+}
+
+String XmlDocument::expandExternalEntity (const String& entity)
+{
+    if (needToLoadDTD)
+    {
+        if (dtdText.isNotEmpty())
+        {
+            dtdText = dtdText.trimCharactersAtEnd (">");
+            tokenisedDTD.addTokens (dtdText, true);
+
+            if (tokenisedDTD [tokenisedDTD.size() - 2].equalsIgnoreCase ("system")
+                 && tokenisedDTD [tokenisedDTD.size() - 1].isQuotedString())
+            {
+                const String fn (tokenisedDTD [tokenisedDTD.size() - 1]);
+
+                tokenisedDTD.clear();
+                tokenisedDTD.addTokens (getFileContents (fn), true);
+            }
+            else
+            {
+                tokenisedDTD.clear();
+                const int openBracket = dtdText.indexOfChar ('[');
+
+                if (openBracket > 0)
+                {
+                    const int closeBracket = dtdText.lastIndexOfChar (']');
+
+                    if (closeBracket > openBracket)
+                        tokenisedDTD.addTokens (dtdText.substring (openBracket + 1,
+                                                                   closeBracket), true);
+                }
+            }
+
+            for (int i = tokenisedDTD.size(); --i >= 0;)
+            {
+                if (tokenisedDTD[i].startsWithChar ('%')
+                     && tokenisedDTD[i].endsWithChar (';'))
+                {
+                    const String parsed (getParameterEntity (tokenisedDTD[i].substring (1, tokenisedDTD[i].length() - 1)));
+                    StringArray newToks;
+                    newToks.addTokens (parsed, true);
+
+                    tokenisedDTD.remove (i);
+
+                    for (int j = newToks.size(); --j >= 0;)
+                        tokenisedDTD.insert (i, newToks[j]);
+                }
+            }
+        }
+
+        needToLoadDTD = false;
+    }
+
+    for (int i = 0; i < tokenisedDTD.size(); ++i)
+    {
+        if (tokenisedDTD[i] == entity)
+        {
+            if (tokenisedDTD[i - 1].equalsIgnoreCase ("<!entity"))
+            {
+                String ent (tokenisedDTD [i + 1].trimCharactersAtEnd (">").trim().unquoted());
+
+                // check for sub-entities..
+                int ampersand = ent.indexOfChar ('&');
+
+                while (ampersand >= 0)
+                {
+                    const int semiColon = ent.indexOf (i + 1, ";");
+
+                    if (semiColon < 0)
+                    {
+                        setLastError ("entity without terminating semi-colon", false);
+                        break;
+                    }
+
+                    const String resolved (expandEntity (ent.substring (i + 1, semiColon)));
+
+                    ent = ent.substring (0, ampersand)
+                           + resolved
+                           + ent.substring (semiColon + 1);
+
+                    ampersand = ent.indexOfChar (semiColon + 1, '&');
+                }
+
+                return ent;
+            }
+        }
+    }
+
+    setLastError ("unknown entity", true);
+
+    return entity;
+}
+
+String XmlDocument::getParameterEntity (const String& entity)
+{
+    for (int i = 0; i < tokenisedDTD.size(); ++i)
+    {
+        if (tokenisedDTD[i] == entity
+             && tokenisedDTD [i - 1] == "%"
+             && tokenisedDTD [i - 2].equalsIgnoreCase ("<!entity"))
+        {
+            const String ent (tokenisedDTD [i + 1].trimCharactersAtEnd (">"));
+
+            if (ent.equalsIgnoreCase ("system"))
+                return getFileContents (tokenisedDTD [i + 2].trimCharactersAtEnd (">"));
+
+            return ent.trim().unquoted();
+        }
+    }
+
+    return entity;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlDocument.h b/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlDocument.h
new file mode 100644
index 0000000..d2a5b49
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlDocument.h
@@ -0,0 +1,181 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_XMLDOCUMENT_H_INCLUDED
+#define JUCE_XMLDOCUMENT_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Parses a text-based XML document and creates an XmlElement object from it.
+
+    The parser will parse DTDs to load external entities but won't
+    check the document for validity against the DTD.
+
+    e.g.
+    @code
+
+    XmlDocument myDocument (File ("myfile.xml"));
+    XmlElement* mainElement = myDocument.getDocumentElement();
+
+    if (mainElement == nullptr)
+    {
+        String error = myDocument.getLastParseError();
+    }
+    else
+    {
+        ..use the element
+    }
+
+    @endcode
+
+    Or you can use the static helper methods for quick parsing..
+
+    @code
+    XmlElement* xml = XmlDocument::parse (myXmlFile);
+
+    if (xml != nullptr && xml->hasTagName ("foobar"))
+    {
+        ...etc
+    @endcode
+
+    @see XmlElement
+*/
+class JUCE_API  XmlDocument
+{
+public:
+    //==============================================================================
+    /** Creates an XmlDocument from the xml text.
+        The text doesn't actually get parsed until the getDocumentElement() method is called.
+    */
+    XmlDocument (const String& documentText);
+
+    /** Creates an XmlDocument from a file.
+        The text doesn't actually get parsed until the getDocumentElement() method is called.
+    */
+    XmlDocument (const File& file);
+
+    /** Destructor. */
+    ~XmlDocument();
+
+    //==============================================================================
+    /** Creates an XmlElement object to represent the main document node.
+
+        This method will do the actual parsing of the text, and if there's a
+        parse error, it may returns nullptr (and you can find out the error using
+        the getLastParseError() method).
+
+        See also the parse() methods, which provide a shorthand way to quickly
+        parse a file or string.
+
+        @param onlyReadOuterDocumentElement     if true, the parser will only read the
+                                                first section of the file, and will only
+                                                return the outer document element - this
+                                                allows quick checking of large files to
+                                                see if they contain the correct type of
+                                                tag, without having to parse the entire file
+        @returns    a new XmlElement which the caller will need to delete, or null if
+                    there was an error.
+        @see getLastParseError
+    */
+    XmlElement* getDocumentElement (bool onlyReadOuterDocumentElement = false);
+
+    /** Returns the parsing error that occurred the last time getDocumentElement was called.
+
+        @returns the error, or an empty string if there was no error.
+    */
+    const String& getLastParseError() const noexcept;
+
+    /** Sets an input source object to use for parsing documents that reference external entities.
+
+        If the document has been created from a file, this probably won't be needed, but
+        if you're parsing some text and there might be a DTD that references external
+        files, you may need to create a custom input source that can retrieve the
+        other files it needs.
+
+        The object that is passed-in will be deleted automatically when no longer needed.
+
+        @see InputSource
+    */
+    void setInputSource (InputSource* newSource) noexcept;
+
+    /** Sets a flag to change the treatment of empty text elements.
+
+        If this is true (the default state), then any text elements that contain only
+        whitespace characters will be ingored during parsing. If you need to catch
+        whitespace-only text, then you should set this to false before calling the
+        getDocumentElement() method.
+    */
+    void setEmptyTextElementsIgnored (bool shouldBeIgnored) noexcept;
+
+    //==============================================================================
+    /** A handy static method that parses a file.
+        This is a shortcut for creating an XmlDocument object and calling getDocumentElement() on it.
+        @returns    a new XmlElement which the caller will need to delete, or null if there was an error.
+    */
+    static XmlElement* parse (const File& file);
+
+    /** A handy static method that parses some XML data.
+        This is a shortcut for creating an XmlDocument object and calling getDocumentElement() on it.
+        @returns    a new XmlElement which the caller will need to delete, or null if there was an error.
+    */
+    static XmlElement* parse (const String& xmlData);
+
+
+    //==============================================================================
+private:
+    String originalText;
+    String::CharPointerType input;
+    bool outOfData, errorOccurred;
+
+    String lastError, dtdText;
+    StringArray tokenisedDTD;
+    bool needToLoadDTD, ignoreEmptyTextElements;
+    ScopedPointer<InputSource> inputSource;
+
+    XmlElement* parseDocumentElement (String::CharPointerType, bool outer);
+    void setLastError (const String&, bool carryOn);
+    bool parseHeader();
+    bool parseDTD();
+    void skipNextWhiteSpace();
+    juce_wchar readNextChar() noexcept;
+    XmlElement* readNextElement (bool alsoParseSubElements);
+    void readChildElements (XmlElement&);
+    void readQuotedString (String&);
+    void readEntity (String&);
+
+    String getFileContents (const String&) const;
+    String expandEntity (const String&);
+    String expandExternalEntity (const String&);
+    String getParameterEntity (const String&);
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XmlDocument)
+};
+
+
+#endif   // JUCE_XMLDOCUMENT_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlElement.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlElement.cpp
new file mode 100644
index 0000000..000df15
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlElement.cpp
@@ -0,0 +1,888 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+XmlElement::XmlAttributeNode::XmlAttributeNode (const XmlAttributeNode& other) noexcept
+    : name (other.name),
+      value (other.value)
+{
+}
+
+XmlElement::XmlAttributeNode::XmlAttributeNode (const Identifier& n, const String& v) noexcept
+    : name (n), value (v)
+{
+   #if JUCE_DEBUG
+    // this checks whether the attribute name string contains any illegal characters..
+    for (String::CharPointerType t (name.getCharPointer()); ! t.isEmpty(); ++t)
+        jassert (t.isLetterOrDigit() || *t == '_' || *t == '-' || *t == ':');
+   #endif
+}
+
+XmlElement::XmlAttributeNode::XmlAttributeNode (String::CharPointerType nameStart, String::CharPointerType nameEnd)
+    : name (nameStart, nameEnd)
+{
+}
+
+//==============================================================================
+static void sanityCheckTagName (const String& tag)
+{
+    (void) tag;
+
+    // the tag name mustn't be empty, or it'll look like a text element!
+    jassert (tag.containsNonWhitespaceChars())
+
+    // The tag can't contain spaces or other characters that would create invalid XML!
+    jassert (! tag.containsAnyOf (" <>/&(){}"));
+}
+
+XmlElement::XmlElement (const String& tag)
+    : tagName (StringPool::getGlobalPool().getPooledString (tag))
+{
+    sanityCheckTagName (tagName);
+}
+
+XmlElement::XmlElement (const char* tag)
+    : tagName (StringPool::getGlobalPool().getPooledString (tag))
+{
+    sanityCheckTagName (tagName);
+}
+
+XmlElement::XmlElement (StringRef tag)
+    : tagName (StringPool::getGlobalPool().getPooledString (tag))
+{
+    sanityCheckTagName (tagName);
+}
+
+XmlElement::XmlElement (const Identifier& tag)
+    : tagName (tag.toString())
+{
+    sanityCheckTagName (tagName);
+}
+
+XmlElement::XmlElement (String::CharPointerType tagNameStart, String::CharPointerType tagNameEnd)
+    : tagName (StringPool::getGlobalPool().getPooledString (tagNameStart, tagNameEnd))
+{
+    sanityCheckTagName (tagName);
+}
+
+XmlElement::XmlElement (int /*dummy*/) noexcept
+{
+}
+
+XmlElement::XmlElement (const XmlElement& other)
+    : tagName (other.tagName)
+{
+    copyChildrenAndAttributesFrom (other);
+}
+
+XmlElement& XmlElement::operator= (const XmlElement& other)
+{
+    if (this != &other)
+    {
+        removeAllAttributes();
+        deleteAllChildElements();
+        tagName = other.tagName;
+        copyChildrenAndAttributesFrom (other);
+    }
+
+    return *this;
+}
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+XmlElement::XmlElement (XmlElement&& other) noexcept
+    : nextListItem      (static_cast<LinkedListPointer<XmlElement>&&> (other.nextListItem)),
+      firstChildElement (static_cast<LinkedListPointer<XmlElement>&&> (other.firstChildElement)),
+      attributes        (static_cast<LinkedListPointer<XmlAttributeNode>&&> (other.attributes)),
+      tagName           (static_cast<String&&> (other.tagName))
+{
+}
+
+XmlElement& XmlElement::operator= (XmlElement&& other) noexcept
+{
+    jassert (this != &other); // hopefully the compiler should make this situation impossible!
+
+    removeAllAttributes();
+    deleteAllChildElements();
+
+    nextListItem      = static_cast<LinkedListPointer<XmlElement>&&> (other.nextListItem);
+    firstChildElement = static_cast<LinkedListPointer<XmlElement>&&> (other.firstChildElement);
+    attributes        = static_cast<LinkedListPointer<XmlAttributeNode>&&> (other.attributes);
+    tagName           = static_cast<String&&> (other.tagName);
+
+    return *this;
+}
+#endif
+
+void XmlElement::copyChildrenAndAttributesFrom (const XmlElement& other)
+{
+    jassert (firstChildElement.get() == nullptr);
+    firstChildElement.addCopyOfList (other.firstChildElement);
+
+    jassert (attributes.get() == nullptr);
+    attributes.addCopyOfList (other.attributes);
+}
+
+XmlElement::~XmlElement() noexcept
+{
+    firstChildElement.deleteAll();
+    attributes.deleteAll();
+}
+
+//==============================================================================
+namespace XmlOutputFunctions
+{
+   #if 0 // (These functions are just used to generate the lookup table used below)
+    bool isLegalXmlCharSlow (const juce_wchar character) noexcept
+    {
+        if ((character >= 'a' && character <= 'z')
+             || (character >= 'A' && character <= 'Z')
+                || (character >= '0' && character <= '9'))
+            return true;
+
+        const char* t = " .,;:-()_+=?!'#@[]/\\*%~{}$|";
+
+        do
+        {
+            if (((juce_wchar) (uint8) *t) == character)
+                return true;
+        }
+        while (*++t != 0);
+
+        return false;
+    }
+
+    void generateLegalCharLookupTable()
+    {
+        uint8 n[32] = { 0 };
+        for (int i = 0; i < 256; ++i)
+            if (isLegalXmlCharSlow (i))
+                n[i >> 3] |= (1 << (i & 7));
+
+        String s;
+        for (int i = 0; i < 32; ++i)
+            s << (int) n[i] << ", ";
+
+        DBG (s);
+    }
+   #endif
+
+    static bool isLegalXmlChar (const uint32 c) noexcept
+    {
+        static const unsigned char legalChars[] = { 0, 0, 0, 0, 187, 255, 255, 175, 255,
+                                                    255, 255, 191, 254, 255, 255, 127 };
+        return c < sizeof (legalChars) * 8
+                 && (legalChars [c >> 3] & (1 << (c & 7))) != 0;
+    }
+
+    static void escapeIllegalXmlChars (OutputStream& outputStream, const String& text, const bool changeNewLines)
+    {
+        String::CharPointerType t (text.getCharPointer());
+
+        for (;;)
+        {
+            const uint32 character = (uint32) t.getAndAdvance();
+
+            if (character == 0)
+                break;
+
+            if (isLegalXmlChar (character))
+            {
+                outputStream << (char) character;
+            }
+            else
+            {
+                switch (character)
+                {
+                case '&':   outputStream << "&"; break;
+                case '"':   outputStream << """; break;
+                case '>':   outputStream << ">"; break;
+                case '<':   outputStream << "<"; break;
+
+                case '\n':
+                case '\r':
+                    if (! changeNewLines)
+                    {
+                        outputStream << (char) character;
+                        break;
+                    }
+                    // Note: deliberate fall-through here!
+                default:
+                    outputStream << "&#" << ((int) character) << ';';
+                    break;
+                }
+            }
+        }
+    }
+
+    static void writeSpaces (OutputStream& out, const size_t numSpaces)
+    {
+        out.writeRepeatedByte (' ', numSpaces);
+    }
+}
+
+void XmlElement::writeElementAsText (OutputStream& outputStream,
+                                     const int indentationLevel,
+                                     const int lineWrapLength) const
+{
+    using namespace XmlOutputFunctions;
+
+    if (indentationLevel >= 0)
+        writeSpaces (outputStream, (size_t) indentationLevel);
+
+    if (! isTextElement())
+    {
+        outputStream.writeByte ('<');
+        outputStream << tagName;
+
+        {
+            const size_t attIndent = (size_t) (indentationLevel + tagName.length() + 1);
+            int lineLen = 0;
+
+            for (const XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem)
+            {
+                if (lineLen > lineWrapLength && indentationLevel >= 0)
+                {
+                    outputStream << newLine;
+                    writeSpaces (outputStream, attIndent);
+                    lineLen = 0;
+                }
+
+                const int64 startPos = outputStream.getPosition();
+                outputStream.writeByte (' ');
+                outputStream << att->name;
+                outputStream.write ("=\"", 2);
+                escapeIllegalXmlChars (outputStream, att->value, true);
+                outputStream.writeByte ('"');
+                lineLen += (int) (outputStream.getPosition() - startPos);
+            }
+        }
+
+        if (firstChildElement != nullptr)
+        {
+            outputStream.writeByte ('>');
+
+            bool lastWasTextNode = false;
+
+            for (XmlElement* child = firstChildElement; child != nullptr; child = child->nextListItem)
+            {
+                if (child->isTextElement())
+                {
+                    escapeIllegalXmlChars (outputStream, child->getText(), false);
+                    lastWasTextNode = true;
+                }
+                else
+                {
+                    if (indentationLevel >= 0 && ! lastWasTextNode)
+                        outputStream << newLine;
+
+                    child->writeElementAsText (outputStream,
+                                               lastWasTextNode ? 0 : (indentationLevel + (indentationLevel >= 0 ? 2 : 0)), lineWrapLength);
+                    lastWasTextNode = false;
+                }
+            }
+
+            if (indentationLevel >= 0 && ! lastWasTextNode)
+            {
+                outputStream << newLine;
+                writeSpaces (outputStream, (size_t) indentationLevel);
+            }
+
+            outputStream.write ("</", 2);
+            outputStream << tagName;
+            outputStream.writeByte ('>');
+        }
+        else
+        {
+            outputStream.write ("/>", 2);
+        }
+    }
+    else
+    {
+        escapeIllegalXmlChars (outputStream, getText(), false);
+    }
+}
+
+String XmlElement::createDocument (StringRef dtdToUse,
+                                   const bool allOnOneLine,
+                                   const bool includeXmlHeader,
+                                   StringRef encodingType,
+                                   const int lineWrapLength) const
+{
+    MemoryOutputStream mem (2048);
+    writeToStream (mem, dtdToUse, allOnOneLine, includeXmlHeader, encodingType, lineWrapLength);
+
+    return mem.toUTF8();
+}
+
+void XmlElement::writeToStream (OutputStream& output,
+                                StringRef dtdToUse,
+                                const bool allOnOneLine,
+                                const bool includeXmlHeader,
+                                StringRef encodingType,
+                                const int lineWrapLength) const
+{
+    using namespace XmlOutputFunctions;
+
+    if (includeXmlHeader)
+    {
+        output << "<?xml version=\"1.0\" encoding=\"" << encodingType << "\"?>";
+
+        if (allOnOneLine)
+            output.writeByte (' ');
+        else
+            output << newLine << newLine;
+    }
+
+    if (dtdToUse.isNotEmpty())
+    {
+        output << dtdToUse;
+
+        if (allOnOneLine)
+            output.writeByte (' ');
+        else
+            output << newLine;
+    }
+
+    writeElementAsText (output, allOnOneLine ? -1 : 0, lineWrapLength);
+
+    if (! allOnOneLine)
+        output << newLine;
+}
+
+bool XmlElement::writeToFile (const File& file,
+                              StringRef dtdToUse,
+                              StringRef encodingType,
+                              const int lineWrapLength) const
+{
+    TemporaryFile tempFile (file);
+
+    {
+        FileOutputStream out (tempFile.getFile());
+
+        if (! out.openedOk())
+            return false;
+
+        writeToStream (out, dtdToUse, false, true, encodingType, lineWrapLength);
+    }
+
+    return tempFile.overwriteTargetFileWithTemporary();
+}
+
+//==============================================================================
+bool XmlElement::hasTagName (StringRef possibleTagName) const noexcept
+{
+    const bool matches = tagName.equalsIgnoreCase (possibleTagName);
+
+    // XML tags should be case-sensitive, so although this method allows a
+    // case-insensitive match to pass, you should try to avoid this.
+    jassert ((! matches) || tagName == possibleTagName);
+
+    return matches;
+}
+
+String XmlElement::getNamespace() const
+{
+    return tagName.upToFirstOccurrenceOf (":", false, false);
+}
+
+String XmlElement::getTagNameWithoutNamespace() const
+{
+    return tagName.fromLastOccurrenceOf (":", false, false);
+}
+
+bool XmlElement::hasTagNameIgnoringNamespace (StringRef possibleTagName) const
+{
+    return hasTagName (possibleTagName) || getTagNameWithoutNamespace() == possibleTagName;
+}
+
+XmlElement* XmlElement::getNextElementWithTagName (StringRef requiredTagName) const
+{
+    XmlElement* e = nextListItem;
+
+    while (e != nullptr && ! e->hasTagName (requiredTagName))
+        e = e->nextListItem;
+
+    return e;
+}
+
+//==============================================================================
+int XmlElement::getNumAttributes() const noexcept
+{
+    return attributes.size();
+}
+
+const String& XmlElement::getAttributeName (const int index) const noexcept
+{
+    if (const XmlAttributeNode* const att = attributes [index])
+        return att->name.toString();
+
+    return String::empty;
+}
+
+const String& XmlElement::getAttributeValue (const int index) const noexcept
+{
+    if (const XmlAttributeNode* const att = attributes [index])
+        return att->value;
+
+    return String::empty;
+}
+
+XmlElement::XmlAttributeNode* XmlElement::getAttribute (StringRef attributeName) const noexcept
+{
+    for (XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem)
+        if (att->name == attributeName)
+            return att;
+
+    return nullptr;
+}
+
+bool XmlElement::hasAttribute (StringRef attributeName) const noexcept
+{
+    return getAttribute (attributeName) != nullptr;
+}
+
+//==============================================================================
+const String& XmlElement::getStringAttribute (StringRef attributeName) const noexcept
+{
+    if (const XmlAttributeNode* att = getAttribute (attributeName))
+        return att->value;
+
+    return String::empty;
+}
+
+String XmlElement::getStringAttribute (StringRef attributeName, const String& defaultReturnValue) const
+{
+    if (const XmlAttributeNode* att = getAttribute (attributeName))
+        return att->value;
+
+    return defaultReturnValue;
+}
+
+int XmlElement::getIntAttribute (StringRef attributeName, const int defaultReturnValue) const
+{
+    if (const XmlAttributeNode* att = getAttribute (attributeName))
+        return att->value.getIntValue();
+
+    return defaultReturnValue;
+}
+
+double XmlElement::getDoubleAttribute (StringRef attributeName, const double defaultReturnValue) const
+{
+    if (const XmlAttributeNode* att = getAttribute (attributeName))
+        return att->value.getDoubleValue();
+
+    return defaultReturnValue;
+}
+
+bool XmlElement::getBoolAttribute (StringRef attributeName, const bool defaultReturnValue) const
+{
+    if (const XmlAttributeNode* att = getAttribute (attributeName))
+    {
+        const juce_wchar firstChar = *(att->value.getCharPointer().findEndOfWhitespace());
+
+        return firstChar == '1'
+            || firstChar == 't'
+            || firstChar == 'y'
+            || firstChar == 'T'
+            || firstChar == 'Y';
+    }
+
+    return defaultReturnValue;
+}
+
+bool XmlElement::compareAttribute (StringRef attributeName,
+                                   StringRef stringToCompareAgainst,
+                                   const bool ignoreCase) const noexcept
+{
+    if (const XmlAttributeNode* att = getAttribute (attributeName))
+        return ignoreCase ? att->value.equalsIgnoreCase (stringToCompareAgainst)
+                          : att->value == stringToCompareAgainst;
+
+    return false;
+}
+
+//==============================================================================
+void XmlElement::setAttribute (const Identifier& attributeName, const String& value)
+{
+    if (attributes == nullptr)
+    {
+        attributes = new XmlAttributeNode (attributeName, value);
+    }
+    else
+    {
+        for (XmlAttributeNode* att = attributes; ; att = att->nextListItem)
+        {
+            if (att->name == attributeName)
+            {
+                att->value = value;
+                break;
+            }
+
+            if (att->nextListItem == nullptr)
+            {
+                att->nextListItem = new XmlAttributeNode (attributeName, value);
+                break;
+            }
+        }
+    }
+}
+
+void XmlElement::setAttribute (const Identifier& attributeName, const int number)
+{
+    setAttribute (attributeName, String (number));
+}
+
+void XmlElement::setAttribute (const Identifier& attributeName, const double number)
+{
+    setAttribute (attributeName, String (number, 20));
+}
+
+void XmlElement::removeAttribute (const Identifier& attributeName) noexcept
+{
+    for (LinkedListPointer<XmlAttributeNode>* att = &attributes;
+         att->get() != nullptr;
+         att = &(att->get()->nextListItem))
+    {
+        if (att->get()->name == attributeName)
+        {
+            delete att->removeNext();
+            break;
+        }
+    }
+}
+
+void XmlElement::removeAllAttributes() noexcept
+{
+    attributes.deleteAll();
+}
+
+//==============================================================================
+int XmlElement::getNumChildElements() const noexcept
+{
+    return firstChildElement.size();
+}
+
+XmlElement* XmlElement::getChildElement (const int index) const noexcept
+{
+    return firstChildElement [index].get();
+}
+
+XmlElement* XmlElement::getChildByName (StringRef childName) const noexcept
+{
+    jassert (! childName.isEmpty());
+
+    for (XmlElement* child = firstChildElement; child != nullptr; child = child->nextListItem)
+        if (child->hasTagName (childName))
+            return child;
+
+    return nullptr;
+}
+
+XmlElement* XmlElement::getChildByAttribute (StringRef attributeName, StringRef attributeValue) const noexcept
+{
+    jassert (! attributeName.isEmpty());
+
+    for (XmlElement* child = firstChildElement; child != nullptr; child = child->nextListItem)
+        if (child->compareAttribute (attributeName, attributeValue))
+            return child;
+
+    return nullptr;
+}
+
+void XmlElement::addChildElement (XmlElement* const newNode) noexcept
+{
+    if (newNode != nullptr)
+    {
+        // The element being added must not be a child of another node!
+        jassert (newNode->nextListItem == nullptr);
+
+        firstChildElement.append (newNode);
+    }
+}
+
+void XmlElement::insertChildElement (XmlElement* const newNode, int indexToInsertAt) noexcept
+{
+    if (newNode != nullptr)
+    {
+        // The element being added must not be a child of another node!
+        jassert (newNode->nextListItem == nullptr);
+
+        firstChildElement.insertAtIndex (indexToInsertAt, newNode);
+    }
+}
+
+void XmlElement::prependChildElement (XmlElement* newNode) noexcept
+{
+    if (newNode != nullptr)
+    {
+        // The element being added must not be a child of another node!
+        jassert (newNode->nextListItem == nullptr);
+
+        firstChildElement.insertNext (newNode);
+    }
+}
+
+XmlElement* XmlElement::createNewChildElement (StringRef childTagName)
+{
+    XmlElement* const newElement = new XmlElement (childTagName);
+    addChildElement (newElement);
+    return newElement;
+}
+
+bool XmlElement::replaceChildElement (XmlElement* const currentChildElement,
+                                      XmlElement* const newNode) noexcept
+{
+    if (newNode != nullptr)
+    {
+        if (LinkedListPointer<XmlElement>* const p = firstChildElement.findPointerTo (currentChildElement))
+        {
+            if (currentChildElement != newNode)
+                delete p->replaceNext (newNode);
+
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void XmlElement::removeChildElement (XmlElement* const childToRemove,
+                                     const bool shouldDeleteTheChild) noexcept
+{
+    if (childToRemove != nullptr)
+    {
+        firstChildElement.remove (childToRemove);
+
+        if (shouldDeleteTheChild)
+            delete childToRemove;
+    }
+}
+
+bool XmlElement::isEquivalentTo (const XmlElement* const other,
+                                 const bool ignoreOrderOfAttributes) const noexcept
+{
+    if (this != other)
+    {
+        if (other == nullptr || tagName != other->tagName)
+            return false;
+
+        if (ignoreOrderOfAttributes)
+        {
+            int totalAtts = 0;
+
+            for (const XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem)
+            {
+                if (! other->compareAttribute (att->name, att->value))
+                    return false;
+
+                ++totalAtts;
+            }
+
+            if (totalAtts != other->getNumAttributes())
+                return false;
+        }
+        else
+        {
+            const XmlAttributeNode* thisAtt = attributes;
+            const XmlAttributeNode* otherAtt = other->attributes;
+
+            for (;;)
+            {
+                if (thisAtt == nullptr || otherAtt == nullptr)
+                {
+                    if (thisAtt == otherAtt) // both 0, so it's a match
+                        break;
+
+                    return false;
+                }
+
+                if (thisAtt->name != otherAtt->name
+                     || thisAtt->value != otherAtt->value)
+                {
+                    return false;
+                }
+
+                thisAtt = thisAtt->nextListItem;
+                otherAtt = otherAtt->nextListItem;
+            }
+        }
+
+        const XmlElement* thisChild = firstChildElement;
+        const XmlElement* otherChild = other->firstChildElement;
+
+        for (;;)
+        {
+            if (thisChild == nullptr || otherChild == nullptr)
+            {
+                if (thisChild == otherChild) // both 0, so it's a match
+                    break;
+
+                return false;
+            }
+
+            if (! thisChild->isEquivalentTo (otherChild, ignoreOrderOfAttributes))
+                return false;
+
+            thisChild = thisChild->nextListItem;
+            otherChild = otherChild->nextListItem;
+        }
+    }
+
+    return true;
+}
+
+void XmlElement::deleteAllChildElements() noexcept
+{
+    firstChildElement.deleteAll();
+}
+
+void XmlElement::deleteAllChildElementsWithTagName (StringRef name) noexcept
+{
+    for (XmlElement* child = firstChildElement; child != nullptr;)
+    {
+        XmlElement* const nextChild = child->nextListItem;
+
+        if (child->hasTagName (name))
+            removeChildElement (child, true);
+
+        child = nextChild;
+    }
+}
+
+bool XmlElement::containsChildElement (const XmlElement* const possibleChild) const noexcept
+{
+    return firstChildElement.contains (possibleChild);
+}
+
+XmlElement* XmlElement::findParentElementOf (const XmlElement* const elementToLookFor) noexcept
+{
+    if (this == elementToLookFor || elementToLookFor == nullptr)
+        return nullptr;
+
+    for (XmlElement* child = firstChildElement; child != nullptr; child = child->nextListItem)
+    {
+        if (elementToLookFor == child)
+            return this;
+
+        if (XmlElement* const found = child->findParentElementOf (elementToLookFor))
+            return found;
+    }
+
+    return nullptr;
+}
+
+void XmlElement::getChildElementsAsArray (XmlElement** elems) const noexcept
+{
+    firstChildElement.copyToArray (elems);
+}
+
+void XmlElement::reorderChildElements (XmlElement** const elems, const int num) noexcept
+{
+    XmlElement* e = firstChildElement = elems[0];
+
+    for (int i = 1; i < num; ++i)
+    {
+        e->nextListItem = elems[i];
+        e = e->nextListItem;
+    }
+
+    e->nextListItem = nullptr;
+}
+
+//==============================================================================
+bool XmlElement::isTextElement() const noexcept
+{
+    return tagName.isEmpty();
+}
+
+static const String juce_xmltextContentAttributeName ("text");
+
+const String& XmlElement::getText() const noexcept
+{
+    jassert (isTextElement());  // you're trying to get the text from an element that
+                                // isn't actually a text element.. If this contains text sub-nodes, you
+                                // probably want to use getAllSubText instead.
+
+    return getStringAttribute (juce_xmltextContentAttributeName);
+}
+
+void XmlElement::setText (const String& newText)
+{
+    if (isTextElement())
+        setAttribute (juce_xmltextContentAttributeName, newText);
+    else
+        jassertfalse; // you can only change the text in a text element, not a normal one.
+}
+
+String XmlElement::getAllSubText() const
+{
+    if (isTextElement())
+        return getText();
+
+    if (getNumChildElements() == 1)
+        return firstChildElement.get()->getAllSubText();
+
+    MemoryOutputStream mem (1024);
+
+    for (const XmlElement* child = firstChildElement; child != nullptr; child = child->nextListItem)
+        mem << child->getAllSubText();
+
+    return mem.toUTF8();
+}
+
+String XmlElement::getChildElementAllSubText (StringRef childTagName, const String& defaultReturnValue) const
+{
+    if (const XmlElement* const child = getChildByName (childTagName))
+        return child->getAllSubText();
+
+    return defaultReturnValue;
+}
+
+XmlElement* XmlElement::createTextElement (const String& text)
+{
+    XmlElement* const e = new XmlElement ((int) 0);
+    e->setAttribute (juce_xmltextContentAttributeName, text);
+    return e;
+}
+
+void XmlElement::addTextElement (const String& text)
+{
+    addChildElement (createTextElement (text));
+}
+
+void XmlElement::deleteAllTextElements() noexcept
+{
+    for (XmlElement* child = firstChildElement; child != nullptr;)
+    {
+        XmlElement* const next = child->nextListItem;
+
+        if (child->isTextElement())
+            removeChildElement (child, true);
+
+        child = next;
+    }
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlElement.h b/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlElement.h
new file mode 100644
index 0000000..4ab4d08
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/xml/juce_XmlElement.h
@@ -0,0 +1,763 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_XMLELEMENT_H_INCLUDED
+#define JUCE_XMLELEMENT_H_INCLUDED
+
+
+//==============================================================================
+/** A handy macro to make it easy to iterate all the child elements in an XmlElement.
+
+    The parentXmlElement should be a reference to the parent XML, and the childElementVariableName
+    will be the name of a pointer to each child element.
+
+    E.g. @code
+    XmlElement* myParentXml = createSomeKindOfXmlDocument();
+
+    forEachXmlChildElement (*myParentXml, child)
+    {
+        if (child->hasTagName ("FOO"))
+            doSomethingWithXmlElement (child);
+    }
+
+    @endcode
+
+    @see forEachXmlChildElementWithTagName
+*/
+#define forEachXmlChildElement(parentXmlElement, childElementVariableName) \
+\
+    for (juce::XmlElement* childElementVariableName = (parentXmlElement).getFirstChildElement(); \
+         childElementVariableName != nullptr; \
+         childElementVariableName = childElementVariableName->getNextElement())
+
+/** A macro that makes it easy to iterate all the child elements of an XmlElement
+    which have a specified tag.
+
+    This does the same job as the forEachXmlChildElement macro, but only for those
+    elements that have a particular tag name.
+
+    The parentXmlElement should be a reference to the parent XML, and the childElementVariableName
+    will be the name of a pointer to each child element. The requiredTagName is the
+    tag name to match.
+
+    E.g. @code
+    XmlElement* myParentXml = createSomeKindOfXmlDocument();
+
+    forEachXmlChildElementWithTagName (*myParentXml, child, "MYTAG")
+    {
+        // the child object is now guaranteed to be a <MYTAG> element..
+        doSomethingWithMYTAGElement (child);
+    }
+
+    @endcode
+
+    @see forEachXmlChildElement
+*/
+#define forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \
+\
+    for (juce::XmlElement* childElementVariableName = (parentXmlElement).getChildByName (requiredTagName); \
+         childElementVariableName != nullptr; \
+         childElementVariableName = childElementVariableName->getNextElementWithTagName (requiredTagName))
+
+
+//==============================================================================
+/** Used to build a tree of elements representing an XML document.
+
+    An XML document can be parsed into a tree of XmlElements, each of which
+    represents an XML tag structure, and which may itself contain other
+    nested elements.
+
+    An XmlElement can also be converted back into a text document, and has
+    lots of useful methods for manipulating its attributes and sub-elements,
+    so XmlElements can actually be used as a handy general-purpose data
+    structure.
+
+    Here's an example of parsing some elements: @code
+    // check we're looking at the right kind of document..
+    if (myElement->hasTagName ("ANIMALS"))
+    {
+        // now we'll iterate its sub-elements looking for 'giraffe' elements..
+        forEachXmlChildElement (*myElement, e)
+        {
+            if (e->hasTagName ("GIRAFFE"))
+            {
+                // found a giraffe, so use some of its attributes..
+
+                String giraffeName  = e->getStringAttribute ("name");
+                int giraffeAge      = e->getIntAttribute ("age");
+                bool isFriendly     = e->getBoolAttribute ("friendly");
+            }
+        }
+    }
+    @endcode
+
+    And here's an example of how to create an XML document from scratch: @code
+    // create an outer node called "ANIMALS"
+    XmlElement animalsList ("ANIMALS");
+
+    for (int i = 0; i < numAnimals; ++i)
+    {
+        // create an inner element..
+        XmlElement* giraffe = new XmlElement ("GIRAFFE");
+
+        giraffe->setAttribute ("name", "nigel");
+        giraffe->setAttribute ("age", 10);
+        giraffe->setAttribute ("friendly", true);
+
+        // ..and add our new element to the parent node
+        animalsList.addChildElement (giraffe);
+    }
+
+    // now we can turn the whole thing into a text document..
+    String myXmlDoc = animalsList.createDocument (String::empty);
+    @endcode
+
+    @see XmlDocument
+*/
+class JUCE_API  XmlElement
+{
+public:
+    //==============================================================================
+    /** Creates an XmlElement with this tag name. */
+    explicit XmlElement (const String& tagName);
+
+    /** Creates an XmlElement with this tag name. */
+    explicit XmlElement (const char* tagName);
+
+    /** Creates an XmlElement with this tag name. */
+    explicit XmlElement (const Identifier& tagName);
+
+    /** Creates an XmlElement with this tag name. */
+    explicit XmlElement (StringRef tagName);
+
+    /** Creates an XmlElement with this tag name. */
+    XmlElement (String::CharPointerType tagNameBegin, String::CharPointerType tagNameEnd);
+
+    /** Creates a (deep) copy of another element. */
+    XmlElement (const XmlElement&);
+
+    /** Creates a (deep) copy of another element. */
+    XmlElement& operator= (const XmlElement&);
+
+   #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+    XmlElement (XmlElement&&) noexcept;
+    XmlElement& operator= (XmlElement&&) noexcept;
+   #endif
+
+    /** Deleting an XmlElement will also delete all of its child elements. */
+    ~XmlElement() noexcept;
+
+    //==============================================================================
+    /** Compares two XmlElements to see if they contain the same text and attiributes.
+
+        The elements are only considered equivalent if they contain the same attiributes
+        with the same values, and have the same sub-nodes.
+
+        @param other                    the other element to compare to
+        @param ignoreOrderOfAttributes  if true, this means that two elements with the
+                                        same attributes in a different order will be
+                                        considered the same; if false, the attributes must
+                                        be in the same order as well
+    */
+    bool isEquivalentTo (const XmlElement* other,
+                         bool ignoreOrderOfAttributes) const noexcept;
+
+    //==============================================================================
+    /** Returns an XML text document that represents this element.
+
+        The string returned can be parsed to recreate the same XmlElement that
+        was used to create it.
+
+        @param dtdToUse         the DTD to add to the document
+        @param allOnOneLine     if true, this means that the document will not contain any
+                                linefeeds, so it'll be smaller but not very easy to read.
+        @param includeXmlHeader whether to add the "<?xml version..etc" line at the start of the
+                                document
+        @param encodingType     the character encoding format string to put into the xml
+                                header
+        @param lineWrapLength   the line length that will be used before items get placed on
+                                a new line. This isn't an absolute maximum length, it just
+                                determines how lists of attributes get broken up
+        @see writeToStream, writeToFile
+    */
+    String createDocument (StringRef dtdToUse,
+                           bool allOnOneLine = false,
+                           bool includeXmlHeader = true,
+                           StringRef encodingType = "UTF-8",
+                           int lineWrapLength = 60) const;
+
+    /** Writes the document to a stream as UTF-8.
+
+        @param output           the stream to write to
+        @param dtdToUse         the DTD to add to the document
+        @param allOnOneLine     if true, this means that the document will not contain any
+                                linefeeds, so it'll be smaller but not very easy to read.
+        @param includeXmlHeader whether to add the "<?xml version..etc" line at the start of the
+                                document
+        @param encodingType     the character encoding format string to put into the xml
+                                header
+        @param lineWrapLength   the line length that will be used before items get placed on
+                                a new line. This isn't an absolute maximum length, it just
+                                determines how lists of attributes get broken up
+        @see writeToFile, createDocument
+    */
+    void writeToStream (OutputStream& output,
+                        StringRef dtdToUse,
+                        bool allOnOneLine = false,
+                        bool includeXmlHeader = true,
+                        StringRef encodingType = "UTF-8",
+                        int lineWrapLength = 60) const;
+
+    /** Writes the element to a file as an XML document.
+
+        To improve safety in case something goes wrong while writing the file, this
+        will actually write the document to a new temporary file in the same
+        directory as the destination file, and if this succeeds, it will rename this
+        new file as the destination file (overwriting any existing file that was there).
+
+        @param destinationFile  the file to write to. If this already exists, it will be
+                                overwritten.
+        @param dtdToUse         the DTD to add to the document
+        @param encodingType     the character encoding format string to put into the xml
+                                header
+        @param lineWrapLength   the line length that will be used before items get placed on
+                                a new line. This isn't an absolute maximum length, it just
+                                determines how lists of attributes get broken up
+        @returns    true if the file is written successfully; false if something goes wrong
+                    in the process
+        @see createDocument
+    */
+    bool writeToFile (const File& destinationFile,
+                      StringRef dtdToUse,
+                      StringRef encodingType = "UTF-8",
+                      int lineWrapLength = 60) const;
+
+    //==============================================================================
+    /** Returns this element's tag type name.
+        E.g. for an element such as \<MOOSE legs="4" antlers="2">, this would return "MOOSE".
+        @see hasTagName
+    */
+    const String& getTagName() const noexcept            { return tagName; }
+
+    /** Returns the namespace portion of the tag-name, or an empty string if none is specified. */
+    String getNamespace() const;
+
+    /** Returns the part of the tag-name that follows any namespace declaration. */
+    String getTagNameWithoutNamespace() const;
+
+    /** Tests whether this element has a particular tag name.
+        @param possibleTagName  the tag name you're comparing it with
+        @see getTagName
+    */
+    bool hasTagName (StringRef possibleTagName) const noexcept;
+
+    /** Tests whether this element has a particular tag name, ignoring any XML namespace prefix.
+        So a test for e.g. "xyz" will return true for "xyz" and also "foo:xyz", "bar::xyz", etc.
+        @see getTagName
+    */
+    bool hasTagNameIgnoringNamespace (StringRef possibleTagName) const;
+
+    //==============================================================================
+    /** Returns the number of XML attributes this element contains.
+
+        E.g. for an element such as \<MOOSE legs="4" antlers="2">, this would
+        return 2.
+    */
+    int getNumAttributes() const noexcept;
+
+    /** Returns the name of one of the elements attributes.
+
+        E.g. for an element such as \<MOOSE legs="4" antlers="2">, then
+        getAttributeName(1) would return "antlers".
+
+        @see getAttributeValue, getStringAttribute
+    */
+    const String& getAttributeName (int attributeIndex) const noexcept;
+
+    /** Returns the value of one of the elements attributes.
+
+        E.g. for an element such as \<MOOSE legs="4" antlers="2">, then
+        getAttributeName(1) would return "2".
+
+        @see getAttributeName, getStringAttribute
+    */
+    const String& getAttributeValue (int attributeIndex) const noexcept;
+
+    //==============================================================================
+    // Attribute-handling methods..
+
+    /** Checks whether the element contains an attribute with a certain name. */
+    bool hasAttribute (StringRef attributeName) const noexcept;
+
+    /** Returns the value of a named attribute.
+        @param attributeName        the name of the attribute to look up
+    */
+    const String& getStringAttribute (StringRef attributeName) const noexcept;
+
+    /** Returns the value of a named attribute.
+        @param attributeName        the name of the attribute to look up
+        @param defaultReturnValue   a value to return if the element doesn't have an attribute
+                                    with this name
+    */
+    String getStringAttribute (StringRef attributeName, const String& defaultReturnValue) const;
+
+    /** Compares the value of a named attribute with a value passed-in.
+
+        @param attributeName            the name of the attribute to look up
+        @param stringToCompareAgainst   the value to compare it with
+        @param ignoreCase               whether the comparison should be case-insensitive
+        @returns    true if the value of the attribute is the same as the string passed-in;
+                    false if it's different (or if no such attribute exists)
+    */
+    bool compareAttribute (StringRef attributeName,
+                           StringRef stringToCompareAgainst,
+                           bool ignoreCase = false) const noexcept;
+
+    /** Returns the value of a named attribute as an integer.
+
+        This will try to find the attribute and convert it to an integer (using
+        the String::getIntValue() method).
+
+        @param attributeName        the name of the attribute to look up
+        @param defaultReturnValue   a value to return if the element doesn't have an attribute
+                                    with this name
+        @see setAttribute
+    */
+    int getIntAttribute (StringRef attributeName, int defaultReturnValue = 0) const;
+
+    /** Returns the value of a named attribute as floating-point.
+
+        This will try to find the attribute and convert it to an integer (using
+        the String::getDoubleValue() method).
+
+        @param attributeName        the name of the attribute to look up
+        @param defaultReturnValue   a value to return if the element doesn't have an attribute
+                                    with this name
+        @see setAttribute
+    */
+    double getDoubleAttribute (StringRef attributeName, double defaultReturnValue = 0.0) const;
+
+    /** Returns the value of a named attribute as a boolean.
+
+        This will try to find the attribute and interpret it as a boolean. To do this,
+        it'll return true if the value is "1", "true", "y", etc, or false for other
+        values.
+
+        @param attributeName        the name of the attribute to look up
+        @param defaultReturnValue   a value to return if the element doesn't have an attribute
+                                    with this name
+    */
+    bool getBoolAttribute (StringRef attributeName, bool defaultReturnValue = false) const;
+
+    /** Adds a named attribute to the element.
+
+        If the element already contains an attribute with this name, it's value will
+        be updated to the new value. If there's no such attribute yet, a new one will
+        be added.
+
+        Note that there are other setAttribute() methods that take integers,
+        doubles, etc. to make it easy to store numbers.
+
+        @param attributeName        the name of the attribute to set
+        @param newValue             the value to set it to
+        @see removeAttribute
+    */
+    void setAttribute (const Identifier& attributeName, const String& newValue);
+
+    /** Adds a named attribute to the element, setting it to an integer value.
+
+        If the element already contains an attribute with this name, it's value will
+        be updated to the new value. If there's no such attribute yet, a new one will
+        be added.
+
+        Note that there are other setAttribute() methods that take integers,
+        doubles, etc. to make it easy to store numbers.
+
+        @param attributeName        the name of the attribute to set
+        @param newValue             the value to set it to
+    */
+    void setAttribute (const Identifier& attributeName, int newValue);
+
+    /** Adds a named attribute to the element, setting it to a floating-point value.
+
+        If the element already contains an attribute with this name, it's value will
+        be updated to the new value. If there's no such attribute yet, a new one will
+        be added.
+
+        Note that there are other setAttribute() methods that take integers,
+        doubles, etc. to make it easy to store numbers.
+
+        @param attributeName        the name of the attribute to set
+        @param newValue             the value to set it to
+    */
+    void setAttribute (const Identifier& attributeName, double newValue);
+
+    /** Removes a named attribute from the element.
+
+        @param attributeName    the name of the attribute to remove
+        @see removeAllAttributes
+    */
+    void removeAttribute (const Identifier& attributeName) noexcept;
+
+    /** Removes all attributes from this element. */
+    void removeAllAttributes() noexcept;
+
+    //==============================================================================
+    // Child element methods..
+
+    /** Returns the first of this element's sub-elements.
+        see getNextElement() for an example of how to iterate the sub-elements.
+        @see forEachXmlChildElement
+    */
+    XmlElement* getFirstChildElement() const noexcept       { return firstChildElement; }
+
+    /** Returns the next of this element's siblings.
+
+        This can be used for iterating an element's sub-elements, e.g.
+        @code
+        XmlElement* child = myXmlDocument->getFirstChildElement();
+
+        while (child != nullptr)
+        {
+            ...do stuff with this child..
+
+            child = child->getNextElement();
+        }
+        @endcode
+
+        Note that when iterating the child elements, some of them might be
+        text elements as well as XML tags - use isTextElement() to work this
+        out.
+
+        Also, it's much easier and neater to use this method indirectly via the
+        forEachXmlChildElement macro.
+
+        @returns    the sibling element that follows this one, or zero if this is the last
+                    element in its parent
+
+        @see getNextElement, isTextElement, forEachXmlChildElement
+    */
+    inline XmlElement* getNextElement() const noexcept          { return nextListItem; }
+
+    /** Returns the next of this element's siblings which has the specified tag
+        name.
+
+        This is like getNextElement(), but will scan through the list until it
+        finds an element with the given tag name.
+
+        @see getNextElement, forEachXmlChildElementWithTagName
+    */
+    XmlElement* getNextElementWithTagName (StringRef requiredTagName) const;
+
+    /** Returns the number of sub-elements in this element.
+        @see getChildElement
+    */
+    int getNumChildElements() const noexcept;
+
+    /** Returns the sub-element at a certain index.
+
+        It's not very efficient to iterate the sub-elements by index - see
+        getNextElement() for an example of how best to iterate.
+
+        @returns the n'th child of this element, or nullptr if the index is out-of-range
+        @see getNextElement, isTextElement, getChildByName
+    */
+    XmlElement* getChildElement (int index) const noexcept;
+
+    /** Returns the first sub-element with a given tag-name.
+
+        @param tagNameToLookFor     the tag name of the element you want to find
+        @returns the first element with this tag name, or nullptr if none is found
+        @see getNextElement, isTextElement, getChildElement, getChildByAttribute
+    */
+    XmlElement* getChildByName (StringRef tagNameToLookFor) const noexcept;
+
+    /** Returns the first sub-element which has an attribute that matches the given value.
+
+        @param attributeName     the name of the attribute to check
+        @param attributeValue    the target value of the attribute
+        @returns the first element with this attribute value, or nullptr if none is found
+        @see getChildByName
+    */
+    XmlElement* getChildByAttribute (StringRef attributeName,
+                                     StringRef attributeValue) const noexcept;
+
+    //==============================================================================
+    /** Appends an element to this element's list of children.
+
+        Child elements are deleted automatically when their parent is deleted, so
+        make sure the object that you pass in will not be deleted by anything else,
+        and make sure it's not already the child of another element.
+
+        Note that due to the XmlElement using a singly-linked-list, prependChildElement()
+        is an O(1) operation, but addChildElement() is an O(N) operation - so if
+        you're adding large number of elements, you may prefer to do so in reverse order!
+
+        @see getFirstChildElement, getNextElement, getNumChildElements,
+             getChildElement, removeChildElement
+    */
+    void addChildElement (XmlElement* newChildElement) noexcept;
+
+    /** Inserts an element into this element's list of children.
+
+        Child elements are deleted automatically when their parent is deleted, so
+        make sure the object that you pass in will not be deleted by anything else,
+        and make sure it's not already the child of another element.
+
+        @param newChildElement  the element to add
+        @param indexToInsertAt  the index at which to insert the new element - if this is
+                                below zero, it will be added to the end of the list
+        @see addChildElement, insertChildElement
+    */
+    void insertChildElement (XmlElement* newChildElement,
+                             int indexToInsertAt) noexcept;
+
+    /** Inserts an element at the beginning of this element's list of children.
+
+        Child elements are deleted automatically when their parent is deleted, so
+        make sure the object that you pass in will not be deleted by anything else,
+        and make sure it's not already the child of another element.
+
+        Note that due to the XmlElement using a singly-linked-list, prependChildElement()
+        is an O(1) operation, but addChildElement() is an O(N) operation - so if
+        you're adding large number of elements, you may prefer to do so in reverse order!
+
+        @see addChildElement, insertChildElement
+    */
+    void prependChildElement (XmlElement* newChildElement) noexcept;
+
+    /** Creates a new element with the given name and returns it, after adding it
+        as a child element.
+
+        This is a handy method that means that instead of writing this:
+        @code
+        XmlElement* newElement = new XmlElement ("foobar");
+        myParentElement->addChildElement (newElement);
+        @endcode
+
+        ..you could just write this:
+        @code
+        XmlElement* newElement = myParentElement->createNewChildElement ("foobar");
+        @endcode
+    */
+    XmlElement* createNewChildElement (StringRef tagName);
+
+    /** Replaces one of this element's children with another node.
+
+        If the current element passed-in isn't actually a child of this element,
+        this will return false and the new one won't be added. Otherwise, the
+        existing element will be deleted, replaced with the new one, and it
+        will return true.
+    */
+    bool replaceChildElement (XmlElement* currentChildElement,
+                              XmlElement* newChildNode) noexcept;
+
+    /** Removes a child element.
+
+        @param childToRemove            the child to look for and remove
+        @param shouldDeleteTheChild     if true, the child will be deleted, if false it'll
+                                        just remove it
+    */
+    void removeChildElement (XmlElement* childToRemove,
+                             bool shouldDeleteTheChild) noexcept;
+
+    /** Deletes all the child elements in the element.
+        @see removeChildElement, deleteAllChildElementsWithTagName
+    */
+    void deleteAllChildElements() noexcept;
+
+    /** Deletes all the child elements with a given tag name.
+        @see removeChildElement
+    */
+    void deleteAllChildElementsWithTagName (StringRef tagName) noexcept;
+
+    /** Returns true if the given element is a child of this one. */
+    bool containsChildElement (const XmlElement* possibleChild) const noexcept;
+
+    /** Recursively searches all sub-elements to find one that contains the specified
+        child element.
+    */
+    XmlElement* findParentElementOf (const XmlElement* elementToLookFor) noexcept;
+
+    //==============================================================================
+    /** Sorts the child elements using a comparator.
+
+        This will use a comparator object to sort the elements into order. The object
+        passed must have a method of the form:
+        @code
+        int compareElements (const XmlElement* first, const XmlElement* second);
+        @endcode
+
+        ..and this method must return:
+          - a value of < 0 if the first comes before the second
+          - a value of 0 if the two objects are equivalent
+          - a value of > 0 if the second comes before the first
+
+        To improve performance, the compareElements() method can be declared as static or const.
+
+        @param comparator   the comparator to use for comparing elements.
+        @param retainOrderOfEquivalentItems     if this is true, then items which the comparator
+                            says are equivalent will be kept in the order in which they
+                            currently appear in the array. This is slower to perform, but
+                            may be important in some cases. If it's false, a faster algorithm
+                            is used, but equivalent elements may be rearranged.
+    */
+    template <class ElementComparator>
+    void sortChildElements (ElementComparator& comparator,
+                            bool retainOrderOfEquivalentItems = false)
+    {
+        const int num = getNumChildElements();
+
+        if (num > 1)
+        {
+            HeapBlock <XmlElement*> elems ((size_t) num);
+            getChildElementsAsArray (elems);
+            sortArray (comparator, (XmlElement**) elems, 0, num - 1, retainOrderOfEquivalentItems);
+            reorderChildElements (elems, num);
+        }
+    }
+
+    //==============================================================================
+    /** Returns true if this element is a section of text.
+
+        Elements can either be an XML tag element or a secton of text, so this
+        is used to find out what kind of element this one is.
+
+        @see getAllText, addTextElement, deleteAllTextElements
+    */
+    bool isTextElement() const noexcept;
+
+    /** Returns the text for a text element.
+
+        Note that if you have an element like this:
+
+        @code<xyz>hello</xyz>@endcode
+
+        then calling getText on the "xyz" element won't return "hello", because that is
+        actually stored in a special text sub-element inside the xyz element. To get the
+        "hello" string, you could either call getText on the (unnamed) sub-element, or
+        use getAllSubText() to do this automatically.
+
+        Note that leading and trailing whitespace will be included in the string - to remove
+        if, just call String::trim() on the result.
+
+        @see isTextElement, getAllSubText, getChildElementAllSubText
+    */
+    const String& getText() const noexcept;
+
+    /** Sets the text in a text element.
+
+        Note that this is only a valid call if this element is a text element. If it's
+        not, then no action will be performed. If you're trying to add text inside a normal
+        element, you probably want to use addTextElement() instead.
+    */
+    void setText (const String& newText);
+
+    /** Returns all the text from this element's child nodes.
+
+        This iterates all the child elements and when it finds text elements,
+        it concatenates their text into a big string which it returns.
+
+        E.g. @code<xyz>hello <x>there</x> world</xyz>@endcode
+        if you called getAllSubText on the "xyz" element, it'd return "hello there world".
+
+        Note that leading and trailing whitespace will be included in the string - to remove
+        if, just call String::trim() on the result.
+
+        @see isTextElement, getChildElementAllSubText, getText, addTextElement
+    */
+    String getAllSubText() const;
+
+    /** Returns all the sub-text of a named child element.
+
+        If there is a child element with the given tag name, this will return
+        all of its sub-text (by calling getAllSubText() on it). If there is
+        no such child element, this will return the default string passed-in.
+
+        @see getAllSubText
+    */
+    String getChildElementAllSubText (StringRef childTagName,
+                                      const String& defaultReturnValue) const;
+
+    /** Appends a section of text to this element.
+        @see isTextElement, getText, getAllSubText
+    */
+    void addTextElement (const String& text);
+
+    /** Removes all the text elements from this element.
+        @see isTextElement, getText, getAllSubText, addTextElement
+    */
+    void deleteAllTextElements() noexcept;
+
+    /** Creates a text element that can be added to a parent element. */
+    static XmlElement* createTextElement (const String& text);
+
+    //==============================================================================
+private:
+    struct XmlAttributeNode
+    {
+        XmlAttributeNode (const XmlAttributeNode&) noexcept;
+        XmlAttributeNode (const Identifier&, const String&) noexcept;
+        XmlAttributeNode (String::CharPointerType, String::CharPointerType);
+
+        LinkedListPointer<XmlAttributeNode> nextListItem;
+        Identifier name;
+        String value;
+
+    private:
+        XmlAttributeNode& operator= (const XmlAttributeNode&) JUCE_DELETED_FUNCTION;
+    };
+
+    friend class XmlDocument;
+    friend class LinkedListPointer<XmlAttributeNode>;
+    friend class LinkedListPointer<XmlElement>;
+    friend class LinkedListPointer<XmlElement>::Appender;
+    friend class NamedValueSet;
+
+    LinkedListPointer<XmlElement> nextListItem;
+    LinkedListPointer<XmlElement> firstChildElement;
+    LinkedListPointer<XmlAttributeNode> attributes;
+    String tagName;
+
+    XmlElement (int) noexcept;
+    void copyChildrenAndAttributesFrom (const XmlElement&);
+    void writeElementAsText (OutputStream&, int indentationLevel, int lineWrapLength) const;
+    void getChildElementsAsArray (XmlElement**) const noexcept;
+    void reorderChildElements (XmlElement**, int) noexcept;
+    XmlAttributeNode* getAttribute (StringRef) const noexcept;
+
+    // Sigh.. L"" or _T("") string literals are problematic in general, and really inappropriate
+    // for XML tags. Use a UTF-8 encoded literal instead, or if you're really determined to use
+    // UTF-16, cast it to a String and use the other constructor.
+    XmlElement (const wchar_t*) JUCE_DELETED_FUNCTION;
+
+    JUCE_LEAK_DETECTOR (XmlElement)
+};
+
+
+#endif   // JUCE_XMLELEMENT_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp
new file mode 100644
index 0000000..cb9a577
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp
@@ -0,0 +1,213 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+class GZIPCompressorOutputStream::GZIPCompressorHelper
+{
+public:
+    GZIPCompressorHelper (const int compressionLevel, const int windowBits)
+        : compLevel ((compressionLevel < 1 || compressionLevel > 9) ? -1 : compressionLevel),
+          isFirstDeflate (true),
+          streamIsValid (false),
+          finished (false)
+    {
+        using namespace zlibNamespace;
+        zerostruct (stream);
+
+        streamIsValid = (deflateInit2 (&stream, compLevel, Z_DEFLATED,
+                                       windowBits != 0 ? windowBits : MAX_WBITS,
+                                       8, strategy) == Z_OK);
+    }
+
+    ~GZIPCompressorHelper()
+    {
+        if (streamIsValid)
+            zlibNamespace::deflateEnd (&stream);
+    }
+
+    bool write (const uint8* data, size_t dataSize, OutputStream& out)
+    {
+        // When you call flush() on a gzip stream, the stream is closed, and you can
+        // no longer continue to write data to it!
+        jassert (! finished);
+
+        while (dataSize > 0)
+            if (! doNextBlock (data, dataSize, out, Z_NO_FLUSH))
+                return false;
+
+        return true;
+    }
+
+    void finish (OutputStream& out)
+    {
+        const uint8* data = nullptr;
+        size_t dataSize = 0;
+
+        while (! finished)
+            doNextBlock (data, dataSize, out, Z_FINISH);
+    }
+
+private:
+    enum { strategy = 0 };
+
+    zlibNamespace::z_stream stream;
+    const int compLevel;
+    bool isFirstDeflate, streamIsValid, finished;
+    zlibNamespace::Bytef buffer[32768];
+
+    bool doNextBlock (const uint8*& data, size_t& dataSize, OutputStream& out, const int flushMode)
+    {
+        using namespace zlibNamespace;
+
+        if (streamIsValid)
+        {
+            stream.next_in   = const_cast <uint8*> (data);
+            stream.next_out  = buffer;
+            stream.avail_in  = (z_uInt) dataSize;
+            stream.avail_out = (z_uInt) sizeof (buffer);
+
+            const int result = isFirstDeflate ? deflateParams (&stream, compLevel, strategy)
+                                              : deflate (&stream, flushMode);
+            isFirstDeflate = false;
+
+            switch (result)
+            {
+                case Z_STREAM_END:
+                    finished = true;
+                    // Deliberate fall-through..
+                case Z_OK:
+                {
+                    data += dataSize - stream.avail_in;
+                    dataSize = stream.avail_in;
+                    const ssize_t bytesDone = (ssize_t) sizeof (buffer) - (ssize_t) stream.avail_out;
+                    return bytesDone <= 0 || out.write (buffer, (size_t) bytesDone);
+                }
+
+                default:
+                    break;
+            }
+        }
+
+        return false;
+    }
+
+    JUCE_DECLARE_NON_COPYABLE (GZIPCompressorHelper)
+};
+
+//==============================================================================
+GZIPCompressorOutputStream::GZIPCompressorOutputStream (OutputStream* const out,
+                                                        const int compressionLevel,
+                                                        const bool deleteDestStream,
+                                                        const int windowBits)
+    : destStream (out, deleteDestStream),
+      helper (new GZIPCompressorHelper (compressionLevel, windowBits))
+{
+    jassert (out != nullptr);
+}
+
+GZIPCompressorOutputStream::~GZIPCompressorOutputStream()
+{
+    flush();
+}
+
+void GZIPCompressorOutputStream::flush()
+{
+    helper->finish (*destStream);
+    destStream->flush();
+}
+
+bool GZIPCompressorOutputStream::write (const void* destBuffer, size_t howMany)
+{
+    jassert (destBuffer != nullptr && (ssize_t) howMany >= 0);
+
+    return helper->write (static_cast <const uint8*> (destBuffer), howMany, *destStream);
+}
+
+int64 GZIPCompressorOutputStream::getPosition()
+{
+    return destStream->getPosition();
+}
+
+bool GZIPCompressorOutputStream::setPosition (int64 /*newPosition*/)
+{
+    jassertfalse; // can't do it!
+    return false;
+}
+
+//==============================================================================
+#if JUCE_UNIT_TESTS
+
+class GZIPTests  : public UnitTest
+{
+public:
+    GZIPTests()   : UnitTest ("GZIP") {}
+
+    void runTest()
+    {
+        beginTest ("GZIP");
+        Random rng = getRandom();
+
+        for (int i = 100; --i >= 0;)
+        {
+            MemoryOutputStream original, compressed, uncompressed;
+
+            {
+                GZIPCompressorOutputStream zipper (&compressed, rng.nextInt (10), false);
+
+                for (int j = rng.nextInt (100); --j >= 0;)
+                {
+                    MemoryBlock data ((unsigned int) (rng.nextInt (2000) + 1));
+
+                    for (int k = (int) data.getSize(); --k >= 0;)
+                        data[k] = (char) rng.nextInt (255);
+
+                    original << data;
+                    zipper   << data;
+                }
+            }
+
+            {
+                MemoryInputStream compressedInput (compressed.getData(), compressed.getDataSize(), false);
+                GZIPDecompressorInputStream unzipper (compressedInput);
+
+                uncompressed << unzipper;
+            }
+
+            expectEquals ((int) uncompressed.getDataSize(),
+                          (int) original.getDataSize());
+
+            if (original.getDataSize() == uncompressed.getDataSize())
+                expect (memcmp (uncompressed.getData(),
+                                original.getData(),
+                                original.getDataSize()) == 0);
+        }
+    }
+};
+
+static GZIPTests gzipTests;
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPCompressorOutputStream.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPCompressorOutputStream.h
new file mode 100644
index 0000000..3309486
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPCompressorOutputStream.h
@@ -0,0 +1,101 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_GZIPCOMPRESSOROUTPUTSTREAM_H_INCLUDED
+#define JUCE_GZIPCOMPRESSOROUTPUTSTREAM_H_INCLUDED
+
+
+//==============================================================================
+/**
+    A stream which uses zlib to compress the data written into it.
+
+    Important note: When you call flush() on a GZIPCompressorOutputStream,
+    the gzip data is closed - this means that no more data can be written to
+    it, and any subsequent attempts to call write() will cause an assertion.
+
+    @see GZIPDecompressorInputStream
+*/
+class JUCE_API  GZIPCompressorOutputStream  : public OutputStream
+{
+public:
+    //==============================================================================
+    /** Creates a compression stream.
+
+        @param destStream                       the stream into which the compressed data should
+                                                be written
+        @param compressionLevel                 how much to compress the data, between 1 and 9, where
+                                                1 is the fastest/lowest compression, and 9 is the
+                                                slowest/highest compression. Any value outside this range
+                                                indicates that a default compression level should be used.
+        @param deleteDestStreamWhenDestroyed    whether or not to delete the destStream object when
+                                                this stream is destroyed
+        @param windowBits                       this is used internally to change the window size used
+                                                by zlib - leave it as 0 unless you specifically need to set
+                                                its value for some reason
+    */
+    GZIPCompressorOutputStream (OutputStream* destStream,
+                                int compressionLevel = 0,
+                                bool deleteDestStreamWhenDestroyed = false,
+                                int windowBits = 0);
+
+    /** Destructor. */
+    ~GZIPCompressorOutputStream();
+
+    //==============================================================================
+    /** Flushes and closes the stream.
+        Note that unlike most streams, when you call flush() on a GZIPCompressorOutputStream,
+        the stream is closed - this means that no more data can be written to it, and any
+        subsequent attempts to call write() will cause an assertion.
+    */
+    void flush();
+
+    int64 getPosition() override;
+    bool setPosition (int64) override;
+    bool write (const void*, size_t) override;
+
+    /** These are preset values that can be used for the constructor's windowBits parameter.
+        For more info about this, see the zlib documentation for its windowBits parameter.
+    */
+    enum WindowBitsValues
+    {
+        windowBitsRaw = -15,
+        windowBitsGZIP = 15 + 16
+    };
+
+private:
+    //==============================================================================
+    OptionalScopedPointer<OutputStream> destStream;
+
+    class GZIPCompressorHelper;
+    friend struct ContainerDeletePolicy<GZIPCompressorHelper>;
+    ScopedPointer<GZIPCompressorHelper> helper;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPCompressorOutputStream)
+};
+
+#endif   // JUCE_GZIPCOMPRESSOROUTPUTSTREAM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPDecompressorInputStream.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPDecompressorInputStream.cpp
new file mode 100644
index 0000000..71e0850
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPDecompressorInputStream.cpp
@@ -0,0 +1,288 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#if JUCE_MSVC
+ #pragma warning (push)
+ #pragma warning (disable: 4309 4305 4365)
+#endif
+
+namespace zlibNamespace
+{
+ #if JUCE_INCLUDE_ZLIB_CODE
+  #if JUCE_CLANG
+   #pragma clang diagnostic push
+   #pragma clang diagnostic ignored "-Wconversion"
+   #pragma clang diagnostic ignored "-Wshadow"
+   #pragma clang diagnostic ignored "-Wdeprecated-register"
+  #endif
+
+  #undef OS_CODE
+  #undef fdopen
+  #define ZLIB_INTERNAL
+  #define NO_DUMMY_DECL
+  #include "zlib/zlib.h"
+  #include "zlib/adler32.c"
+  #include "zlib/compress.c"
+  #undef DO1
+  #undef DO8
+  #include "zlib/crc32.c"
+  #include "zlib/deflate.c"
+  #include "zlib/inffast.c"
+  #undef PULLBYTE
+  #undef LOAD
+  #undef RESTORE
+  #undef INITBITS
+  #undef NEEDBITS
+  #undef DROPBITS
+  #undef BYTEBITS
+  #include "zlib/inflate.c"
+  #include "zlib/inftrees.c"
+  #include "zlib/trees.c"
+  #include "zlib/zutil.c"
+  #undef Byte
+  #undef fdopen
+  #undef local
+  #undef Freq
+  #undef Code
+  #undef Dad
+  #undef Len
+
+  #if JUCE_CLANG
+   #pragma clang diagnostic pop
+  #endif
+ #else
+  #include JUCE_ZLIB_INCLUDE_PATH
+ #endif
+}
+
+#if JUCE_MSVC
+ #pragma warning (pop)
+#endif
+
+//==============================================================================
+// internal helper object that holds the zlib structures so they don't have to be
+// included publicly.
+class GZIPDecompressorInputStream::GZIPDecompressHelper
+{
+public:
+    GZIPDecompressHelper (const bool dontWrap)
+        : finished (true),
+          needsDictionary (false),
+          error (true),
+          streamIsValid (false),
+          data (nullptr),
+          dataSize (0)
+    {
+        using namespace zlibNamespace;
+        zerostruct (stream);
+        streamIsValid = (inflateInit2 (&stream, dontWrap ? -MAX_WBITS : MAX_WBITS) == Z_OK);
+        finished = error = ! streamIsValid;
+    }
+
+    ~GZIPDecompressHelper()
+    {
+        using namespace zlibNamespace;
+        if (streamIsValid)
+            inflateEnd (&stream);
+    }
+
+    bool needsInput() const noexcept        { return dataSize <= 0; }
+
+    void setInput (uint8* const data_, const size_t size) noexcept
+    {
+        data = data_;
+        dataSize = size;
+    }
+
+    int doNextBlock (uint8* const dest, const unsigned int destSize)
+    {
+        using namespace zlibNamespace;
+        if (streamIsValid && data != nullptr && ! finished)
+        {
+            stream.next_in  = data;
+            stream.next_out = dest;
+            stream.avail_in  = (z_uInt) dataSize;
+            stream.avail_out = (z_uInt) destSize;
+
+            switch (inflate (&stream, Z_PARTIAL_FLUSH))
+            {
+            case Z_STREAM_END:
+                finished = true;
+                // deliberate fall-through
+            case Z_OK:
+                data += dataSize - stream.avail_in;
+                dataSize = (z_uInt) stream.avail_in;
+                return (int) (destSize - stream.avail_out);
+
+            case Z_NEED_DICT:
+                needsDictionary = true;
+                data += dataSize - stream.avail_in;
+                dataSize = (size_t) stream.avail_in;
+                break;
+
+            case Z_DATA_ERROR:
+            case Z_MEM_ERROR:
+                error = true;
+
+            default:
+                break;
+            }
+        }
+
+        return 0;
+    }
+
+    bool finished, needsDictionary, error, streamIsValid;
+
+    enum { gzipDecompBufferSize = 32768 };
+
+private:
+    zlibNamespace::z_stream stream;
+    uint8* data;
+    size_t dataSize;
+
+    JUCE_DECLARE_NON_COPYABLE (GZIPDecompressHelper)
+};
+
+//==============================================================================
+GZIPDecompressorInputStream::GZIPDecompressorInputStream (InputStream* const source,
+                                                          const bool deleteSourceWhenDestroyed,
+                                                          const bool noWrap_,
+                                                          const int64 uncompressedStreamLength_)
+  : sourceStream (source, deleteSourceWhenDestroyed),
+    uncompressedStreamLength (uncompressedStreamLength_),
+    noWrap (noWrap_),
+    isEof (false),
+    activeBufferSize (0),
+    originalSourcePos (source->getPosition()),
+    currentPos (0),
+    buffer ((size_t) GZIPDecompressHelper::gzipDecompBufferSize),
+    helper (new GZIPDecompressHelper (noWrap_))
+{
+}
+
+GZIPDecompressorInputStream::GZIPDecompressorInputStream (InputStream& source)
+  : sourceStream (&source, false),
+    uncompressedStreamLength (-1),
+    noWrap (false),
+    isEof (false),
+    activeBufferSize (0),
+    originalSourcePos (source.getPosition()),
+    currentPos (0),
+    buffer ((size_t) GZIPDecompressHelper::gzipDecompBufferSize),
+    helper (new GZIPDecompressHelper (false))
+{
+}
+
+GZIPDecompressorInputStream::~GZIPDecompressorInputStream()
+{
+}
+
+int64 GZIPDecompressorInputStream::getTotalLength()
+{
+    return uncompressedStreamLength;
+}
+
+int GZIPDecompressorInputStream::read (void* destBuffer, int howMany)
+{
+    jassert (destBuffer != nullptr && howMany >= 0);
+
+    if (howMany > 0 && ! isEof)
+    {
+        int numRead = 0;
+        uint8* d = static_cast <uint8*> (destBuffer);
+
+        while (! helper->error)
+        {
+            const int n = helper->doNextBlock (d, (unsigned int) howMany);
+            currentPos += n;
+
+            if (n == 0)
+            {
+                if (helper->finished || helper->needsDictionary)
+                {
+                    isEof = true;
+                    return numRead;
+                }
+
+                if (helper->needsInput())
+                {
+                    activeBufferSize = sourceStream->read (buffer, (int) GZIPDecompressHelper::gzipDecompBufferSize);
+
+                    if (activeBufferSize > 0)
+                    {
+                        helper->setInput (buffer, (size_t) activeBufferSize);
+                    }
+                    else
+                    {
+                        isEof = true;
+                        return numRead;
+                    }
+                }
+            }
+            else
+            {
+                numRead += n;
+                howMany -= n;
+                d += n;
+
+                if (howMany <= 0)
+                    return numRead;
+            }
+        }
+    }
+
+    return 0;
+}
+
+bool GZIPDecompressorInputStream::isExhausted()
+{
+    return helper->error || isEof;
+}
+
+int64 GZIPDecompressorInputStream::getPosition()
+{
+    return currentPos;
+}
+
+bool GZIPDecompressorInputStream::setPosition (int64 newPos)
+{
+    if (newPos < currentPos)
+    {
+        // to go backwards, reset the stream and start again..
+        isEof = false;
+        activeBufferSize = 0;
+        currentPos = 0;
+        helper = new GZIPDecompressHelper (noWrap);
+
+        sourceStream->setPosition (originalSourcePos);
+    }
+
+    skipNextBytes (newPos - currentPos);
+    return true;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPDecompressorInputStream.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPDecompressorInputStream.h
new file mode 100644
index 0000000..78a0b77
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_GZIPDecompressorInputStream.h
@@ -0,0 +1,97 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_GZIPDECOMPRESSORINPUTSTREAM_H_INCLUDED
+#define JUCE_GZIPDECOMPRESSORINPUTSTREAM_H_INCLUDED
+
+
+//==============================================================================
+/**
+    This stream will decompress a source-stream using zlib.
+
+    Tip: if you're reading lots of small items from one of these streams, you
+         can increase the performance enormously by passing it through a
+         BufferedInputStream, so that it has to read larger blocks less often.
+
+    @see GZIPCompressorOutputStream
+*/
+class JUCE_API  GZIPDecompressorInputStream  : public InputStream
+{
+public:
+    //==============================================================================
+    /** Creates a decompressor stream.
+
+        @param sourceStream                 the stream to read from
+        @param deleteSourceWhenDestroyed    whether or not to delete the source stream
+                                            when this object is destroyed
+        @param noWrap                       this is used internally by the ZipFile class
+                                            and should be ignored by user applications
+        @param uncompressedStreamLength     if the creator knows the length that the
+                                            uncompressed stream will be, then it can supply this
+                                            value, which will be returned by getTotalLength()
+    */
+    GZIPDecompressorInputStream (InputStream* sourceStream,
+                                 bool deleteSourceWhenDestroyed,
+                                 bool noWrap = false,
+                                 int64 uncompressedStreamLength = -1);
+
+    /** Creates a decompressor stream.
+
+        @param sourceStream     the stream to read from - the source stream must not be
+                                deleted until this object has been destroyed
+    */
+    GZIPDecompressorInputStream (InputStream& sourceStream);
+
+    /** Destructor. */
+    ~GZIPDecompressorInputStream();
+
+    //==============================================================================
+    int64 getPosition() override;
+    bool setPosition (int64 pos) override;
+    int64 getTotalLength() override;
+    bool isExhausted() override;
+    int read (void* destBuffer, int maxBytesToRead) override;
+
+private:
+    //==============================================================================
+    OptionalScopedPointer<InputStream> sourceStream;
+    const int64 uncompressedStreamLength;
+    const bool noWrap;
+    bool isEof;
+    int activeBufferSize;
+    int64 originalSourcePos, currentPos;
+    HeapBlock <uint8> buffer;
+
+    class GZIPDecompressHelper;
+    friend struct ContainerDeletePolicy<GZIPDecompressHelper>;
+    ScopedPointer<GZIPDecompressHelper> helper;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPDecompressorInputStream)
+};
+
+#endif   // JUCE_GZIPDECOMPRESSORINPUTSTREAM_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_ZipFile.cpp b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_ZipFile.cpp
new file mode 100644
index 0000000..a76d8b8
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_ZipFile.cpp
@@ -0,0 +1,608 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+class ZipFile::ZipEntryHolder
+{
+public:
+    ZipEntryHolder (const char* const buffer, const int fileNameLen)
+    {
+        entry.filename = String::fromUTF8 (buffer + 46, fileNameLen);
+
+        const int time = ByteOrder::littleEndianShort (buffer + 12);
+        const int date = ByteOrder::littleEndianShort (buffer + 14);
+        entry.fileTime = getFileTimeFromRawEncodings (time, date);
+
+        compressed = ByteOrder::littleEndianShort (buffer + 10) != 0;
+        compressedSize = (size_t) ByteOrder::littleEndianInt (buffer + 20);
+        entry.uncompressedSize = ByteOrder::littleEndianInt (buffer + 24);
+
+        streamOffset = ByteOrder::littleEndianInt (buffer + 42);
+    }
+
+    struct FileNameComparator
+    {
+        static int compareElements (const ZipEntryHolder* first, const ZipEntryHolder* second)
+        {
+            return first->entry.filename.compare (second->entry.filename);
+        }
+    };
+
+    ZipEntry entry;
+    size_t streamOffset;
+    size_t compressedSize;
+    bool compressed;
+
+private:
+    static Time getFileTimeFromRawEncodings (int time, int date)
+    {
+        const int year      = 1980 + (date >> 9);
+        const int month     = ((date >> 5) & 15) - 1;
+        const int day       = date & 31;
+        const int hours     = time >> 11;
+        const int minutes   = (time >> 5) & 63;
+        const int seconds   = (time & 31) << 1;
+
+        return Time (year, month, day, hours, minutes, seconds);
+    }
+};
+
+//==============================================================================
+namespace
+{
+    int findEndOfZipEntryTable (InputStream& input, int& numEntries)
+    {
+        BufferedInputStream in (input, 8192);
+
+        in.setPosition (in.getTotalLength());
+        int64 pos = in.getPosition();
+        const int64 lowestPos = jmax ((int64) 0, pos - 1024);
+
+        char buffer [32] = { 0 };
+
+        while (pos > lowestPos)
+        {
+            in.setPosition (pos - 22);
+            pos = in.getPosition();
+            memcpy (buffer + 22, buffer, 4);
+
+            if (in.read (buffer, 22) != 22)
+                return 0;
+
+            for (int i = 0; i < 22; ++i)
+            {
+                if (ByteOrder::littleEndianInt (buffer + i) == 0x06054b50)
+                {
+                    in.setPosition (pos + i);
+                    in.read (buffer, 22);
+                    numEntries = ByteOrder::littleEndianShort (buffer + 10);
+
+                    return (int) ByteOrder::littleEndianInt (buffer + 16);
+                }
+            }
+        }
+
+        return 0;
+    }
+}
+
+//==============================================================================
+class ZipFile::ZipInputStream  : public InputStream
+{
+public:
+    ZipInputStream (ZipFile& zf, ZipFile::ZipEntryHolder& zei)
+        : file (zf),
+          zipEntryHolder (zei),
+          pos (0),
+          headerSize (0),
+          inputStream (zf.inputStream)
+    {
+        if (zf.inputSource != nullptr)
+        {
+            inputStream = streamToDelete = file.inputSource->createInputStream();
+        }
+        else
+        {
+           #if JUCE_DEBUG
+            zf.streamCounter.numOpenStreams++;
+           #endif
+        }
+
+        char buffer [30];
+
+        if (inputStream != nullptr
+             && inputStream->setPosition ((int64) zei.streamOffset)
+             && inputStream->read (buffer, 30) == 30
+             && ByteOrder::littleEndianInt (buffer) == 0x04034b50)
+        {
+            headerSize = 30 + ByteOrder::littleEndianShort (buffer + 26)
+                            + ByteOrder::littleEndianShort (buffer + 28);
+        }
+    }
+
+    ~ZipInputStream()
+    {
+       #if JUCE_DEBUG
+        if (inputStream != nullptr && inputStream == file.inputStream)
+            file.streamCounter.numOpenStreams--;
+       #endif
+    }
+
+    int64 getTotalLength()
+    {
+        return (int64) zipEntryHolder.compressedSize;
+    }
+
+    int read (void* buffer, int howMany)
+    {
+        if (headerSize <= 0)
+            return 0;
+
+        howMany = (int) jmin ((int64) howMany, ((int64) zipEntryHolder.compressedSize) - pos);
+
+        if (inputStream == nullptr)
+            return 0;
+
+        int num;
+
+        if (inputStream == file.inputStream)
+        {
+            const ScopedLock sl (file.lock);
+            inputStream->setPosition (pos + (int64) zipEntryHolder.streamOffset + headerSize);
+            num = inputStream->read (buffer, howMany);
+        }
+        else
+        {
+            inputStream->setPosition (pos + (int64) zipEntryHolder.streamOffset + headerSize);
+            num = inputStream->read (buffer, howMany);
+        }
+
+        pos += num;
+        return num;
+    }
+
+    bool isExhausted()
+    {
+        return headerSize <= 0 || pos >= (int64) zipEntryHolder.compressedSize;
+    }
+
+    int64 getPosition()
+    {
+        return pos;
+    }
+
+    bool setPosition (int64 newPos)
+    {
+        pos = jlimit ((int64) 0, (int64) zipEntryHolder.compressedSize, newPos);
+        return true;
+    }
+
+private:
+    ZipFile& file;
+    ZipEntryHolder zipEntryHolder;
+    int64 pos;
+    int headerSize;
+    InputStream* inputStream;
+    ScopedPointer<InputStream> streamToDelete;
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ZipInputStream)
+};
+
+
+//==============================================================================
+ZipFile::ZipFile (InputStream* const stream, const bool deleteStreamWhenDestroyed)
+   : inputStream (stream)
+{
+    if (deleteStreamWhenDestroyed)
+        streamToDelete = inputStream;
+
+    init();
+}
+
+ZipFile::ZipFile (InputStream& stream)
+   : inputStream (&stream)
+{
+    init();
+}
+
+ZipFile::ZipFile (const File& file)
+    : inputStream (nullptr),
+      inputSource (new FileInputSource (file))
+{
+    init();
+}
+
+ZipFile::ZipFile (InputSource* const source)
+    : inputStream (nullptr),
+      inputSource (source)
+{
+    init();
+}
+
+ZipFile::~ZipFile()
+{
+    entries.clear();
+}
+
+#if JUCE_DEBUG
+ZipFile::OpenStreamCounter::~OpenStreamCounter()
+{
+    /* If you hit this assertion, it means you've created a stream to read one of the items in the
+       zipfile, but you've forgotten to delete that stream object before deleting the file..
+       Streams can't be kept open after the file is deleted because they need to share the input
+       stream that is managed by the ZipFile object.
+    */
+    jassert (numOpenStreams == 0);
+}
+#endif
+
+//==============================================================================
+int ZipFile::getNumEntries() const noexcept
+{
+    return entries.size();
+}
+
+const ZipFile::ZipEntry* ZipFile::getEntry (const int index) const noexcept
+{
+    if (ZipEntryHolder* const zei = entries [index])
+        return &(zei->entry);
+
+    return nullptr;
+}
+
+int ZipFile::getIndexOfFileName (const String& fileName) const noexcept
+{
+    for (int i = 0; i < entries.size(); ++i)
+        if (entries.getUnchecked (i)->entry.filename == fileName)
+            return i;
+
+    return -1;
+}
+
+const ZipFile::ZipEntry* ZipFile::getEntry (const String& fileName) const noexcept
+{
+    return getEntry (getIndexOfFileName (fileName));
+}
+
+InputStream* ZipFile::createStreamForEntry (const int index)
+{
+    InputStream* stream = nullptr;
+
+    if (ZipEntryHolder* const zei = entries[index])
+    {
+        stream = new ZipInputStream (*this, *zei);
+
+        if (zei->compressed)
+        {
+            stream = new GZIPDecompressorInputStream (stream, true, true, (int64) zei->entry.uncompressedSize);
+
+            // (much faster to unzip in big blocks using a buffer..)
+            stream = new BufferedInputStream (stream, 32768, true);
+        }
+    }
+
+    return stream;
+}
+
+InputStream* ZipFile::createStreamForEntry (const ZipEntry& entry)
+{
+    for (int i = 0; i < entries.size(); ++i)
+        if (&entries.getUnchecked (i)->entry == &entry)
+            return createStreamForEntry (i);
+
+    return nullptr;
+}
+
+void ZipFile::sortEntriesByFilename()
+{
+    ZipEntryHolder::FileNameComparator sorter;
+    entries.sort (sorter);
+}
+
+//==============================================================================
+void ZipFile::init()
+{
+    ScopedPointer <InputStream> toDelete;
+    InputStream* in = inputStream;
+
+    if (inputSource != nullptr)
+    {
+        in = inputSource->createInputStream();
+        toDelete = in;
+    }
+
+    if (in != nullptr)
+    {
+        int numEntries = 0;
+        int pos = findEndOfZipEntryTable (*in, numEntries);
+
+        if (pos >= 0 && pos < in->getTotalLength())
+        {
+            const int size = (int) (in->getTotalLength() - pos);
+
+            in->setPosition (pos);
+            MemoryBlock headerData;
+
+            if (in->readIntoMemoryBlock (headerData, size) == (size_t) size)
+            {
+                pos = 0;
+
+                for (int i = 0; i < numEntries; ++i)
+                {
+                    if (pos + 46 > size)
+                        break;
+
+                    const char* const buffer = static_cast <const char*> (headerData.getData()) + pos;
+
+                    const int fileNameLen = ByteOrder::littleEndianShort (buffer + 28);
+
+                    if (pos + 46 + fileNameLen > size)
+                        break;
+
+                    entries.add (new ZipEntryHolder (buffer, fileNameLen));
+
+                    pos += 46 + fileNameLen
+                            + ByteOrder::littleEndianShort (buffer + 30)
+                            + ByteOrder::littleEndianShort (buffer + 32);
+                }
+            }
+        }
+    }
+}
+
+Result ZipFile::uncompressTo (const File& targetDirectory,
+                              const bool shouldOverwriteFiles)
+{
+    for (int i = 0; i < entries.size(); ++i)
+    {
+        Result result (uncompressEntry (i, targetDirectory, shouldOverwriteFiles));
+        if (result.failed())
+            return result;
+    }
+
+    return Result::ok();
+}
+
+Result ZipFile::uncompressEntry (const int index,
+                                 const File& targetDirectory,
+                                 bool shouldOverwriteFiles)
+{
+    const ZipEntryHolder* zei = entries.getUnchecked (index);
+
+   #if JUCE_WINDOWS
+    const String entryPath (zei->entry.filename);
+   #else
+    const String entryPath (zei->entry.filename.replaceCharacter ('\\', '/'));
+   #endif
+
+    const File targetFile (targetDirectory.getChildFile (entryPath));
+
+    if (entryPath.endsWithChar ('/') || entryPath.endsWithChar ('\\'))
+        return targetFile.createDirectory(); // (entry is a directory, not a file)
+
+    ScopedPointer<InputStream> in (createStreamForEntry (index));
+
+    if (in == nullptr)
+        return Result::fail ("Failed to open the zip file for reading");
+
+    if (targetFile.exists())
+    {
+        if (! shouldOverwriteFiles)
+            return Result::ok();
+
+        if (! targetFile.deleteFile())
+            return Result::fail ("Failed to write to target file: " + targetFile.getFullPathName());
+    }
+
+    if (! targetFile.getParentDirectory().createDirectory())
+        return Result::fail ("Failed to create target folder: " + targetFile.getParentDirectory().getFullPathName());
+
+    {
+        FileOutputStream out (targetFile);
+
+        if (out.failedToOpen())
+            return Result::fail ("Failed to write to target file: " + targetFile.getFullPathName());
+
+        out << *in;
+    }
+
+    targetFile.setCreationTime (zei->entry.fileTime);
+    targetFile.setLastModificationTime (zei->entry.fileTime);
+    targetFile.setLastAccessTime (zei->entry.fileTime);
+
+    return Result::ok();
+}
+
+
+//=============================================================================
+class ZipFile::Builder::Item
+{
+public:
+    Item (const File& f, InputStream* s, const int compression, const String& storedPath, Time time)
+        : file (f), stream (s), storedPathname (storedPath),
+          fileTime (time), compressionLevel (compression),
+          compressedSize (0), uncompressedSize (0), headerStart (0), checksum (0)
+    {
+    }
+
+    bool writeData (OutputStream& target, const int64 overallStartPosition)
+    {
+        MemoryOutputStream compressedData ((size_t) file.getSize());
+
+        if (compressionLevel > 0)
+        {
+            GZIPCompressorOutputStream compressor (&compressedData, compressionLevel, false,
+                                                   GZIPCompressorOutputStream::windowBitsRaw);
+            if (! writeSource (compressor))
+                return false;
+        }
+        else
+        {
+            if (! writeSource (compressedData))
+                return false;
+        }
+
+        compressedSize = (int) compressedData.getDataSize();
+        headerStart = (int) (target.getPosition() - overallStartPosition);
+
+        target.writeInt (0x04034b50);
+        writeFlagsAndSizes (target);
+        target << storedPathname
+               << compressedData;
+
+        return true;
+    }
+
+    bool writeDirectoryEntry (OutputStream& target)
+    {
+        target.writeInt (0x02014b50);
+        target.writeShort (20); // version written
+        writeFlagsAndSizes (target);
+        target.writeShort (0); // comment length
+        target.writeShort (0); // start disk num
+        target.writeShort (0); // internal attributes
+        target.writeInt (0); // external attributes
+        target.writeInt (headerStart);
+        target << storedPathname;
+
+        return true;
+    }
+
+private:
+    const File file;
+    ScopedPointer<InputStream> stream;
+    String storedPathname;
+    Time fileTime;
+    int compressionLevel, compressedSize, uncompressedSize, headerStart;
+    unsigned long checksum;
+
+    static void writeTimeAndDate (OutputStream& target, Time t)
+    {
+        target.writeShort ((short) (t.getSeconds() + (t.getMinutes() << 5) + (t.getHours() << 11)));
+        target.writeShort ((short) (t.getDayOfMonth() + ((t.getMonth() + 1) << 5) + ((t.getYear() - 1980) << 9)));
+    }
+
+    bool writeSource (OutputStream& target)
+    {
+        if (stream == nullptr)
+        {
+            stream = file.createInputStream();
+
+            if (stream == nullptr)
+                return false;
+        }
+
+        checksum = 0;
+        uncompressedSize = 0;
+        const int bufferSize = 4096;
+        HeapBlock<unsigned char> buffer (bufferSize);
+
+        while (! stream->isExhausted())
+        {
+            const int bytesRead = stream->read (buffer, bufferSize);
+
+            if (bytesRead < 0)
+                return false;
+
+            checksum = zlibNamespace::crc32 (checksum, buffer, (unsigned int) bytesRead);
+            target.write (buffer, (size_t) bytesRead);
+            uncompressedSize += bytesRead;
+        }
+
+        stream = nullptr;
+        return true;
+    }
+
+    void writeFlagsAndSizes (OutputStream& target) const
+    {
+        target.writeShort (10); // version needed
+        target.writeShort ((short) (1 << 11)); // this flag indicates UTF-8 filename encoding
+        target.writeShort (compressionLevel > 0 ? (short) 8 : (short) 0);
+        writeTimeAndDate (target, fileTime);
+        target.writeInt ((int) checksum);
+        target.writeInt (compressedSize);
+        target.writeInt (uncompressedSize);
+        target.writeShort ((short) storedPathname.toUTF8().sizeInBytes() - 1);
+        target.writeShort (0); // extra field length
+    }
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Item)
+};
+
+//=============================================================================
+ZipFile::Builder::Builder() {}
+ZipFile::Builder::~Builder() {}
+
+void ZipFile::Builder::addFile (const File& file, const int compression, const String& path)
+{
+    items.add (new Item (file, nullptr, compression,
+                         path.isEmpty() ? file.getFileName() : path,
+                         file.getLastModificationTime()));
+}
+
+void ZipFile::Builder::addEntry (InputStream* stream, int compression, const String& path, Time time)
+{
+    jassert (stream != nullptr); // must not be null!
+    jassert (path.isNotEmpty());
+    items.add (new Item (File(), stream, compression, path, time));
+}
+
+bool ZipFile::Builder::writeToStream (OutputStream& target, double* const progress) const
+{
+    const int64 fileStart = target.getPosition();
+
+    for (int i = 0; i < items.size(); ++i)
+    {
+        if (progress != nullptr)
+            *progress = (i + 0.5) / items.size();
+
+        if (! items.getUnchecked (i)->writeData (target, fileStart))
+            return false;
+    }
+
+    const int64 directoryStart = target.getPosition();
+
+    for (int i = 0; i < items.size(); ++i)
+        if (! items.getUnchecked (i)->writeDirectoryEntry (target))
+            return false;
+
+    const int64 directoryEnd = target.getPosition();
+
+    target.writeInt (0x06054b50);
+    target.writeShort (0);
+    target.writeShort (0);
+    target.writeShort ((short) items.size());
+    target.writeShort ((short) items.size());
+    target.writeInt ((int) (directoryEnd - directoryStart));
+    target.writeInt ((int) (directoryStart - fileStart));
+    target.writeShort (0);
+
+    if (progress != nullptr)
+        *progress = 1.0;
+
+    return true;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_ZipFile.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_ZipFile.h
new file mode 100644
index 0000000..ccf9064
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/juce_ZipFile.h
@@ -0,0 +1,259 @@
+/*
+  ==============================================================================
+
+   This file is part of the juce_core module of the JUCE library.
+   Copyright (c) 2013 - Raw Material Software Ltd.
+
+   Permission to use, copy, modify, and/or distribute this software for any purpose with
+   or without fee is hereby granted, provided that the above copyright notice and this
+   permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+   TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+   DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ------------------------------------------------------------------------------
+
+   NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
+   All other JUCE modules are covered by a dual GPL/commercial license, so if you are
+   using any other modules, be sure to check that you also comply with their license.
+
+   For more details, visit www.juce.com
+
+  ==============================================================================
+*/
+
+#ifndef JUCE_ZIPFILE_H_INCLUDED
+#define JUCE_ZIPFILE_H_INCLUDED
+
+
+//==============================================================================
+/**
+    Decodes a ZIP file from a stream.
+
+    This can enumerate the items in a ZIP file and can create suitable stream objects
+    to read each one.
+*/
+class JUCE_API  ZipFile
+{
+public:
+    /** Creates a ZipFile based for a file. */
+    explicit ZipFile (const File& file);
+
+    //==============================================================================
+    /** Creates a ZipFile for a given stream.
+
+        @param inputStream                  the stream to read from
+        @param deleteStreamWhenDestroyed    if set to true, the object passed-in
+                                            will be deleted when this ZipFile object is deleted
+    */
+    ZipFile (InputStream* inputStream, bool deleteStreamWhenDestroyed);
+
+    /** Creates a ZipFile for a given stream.
+        The stream will not be owned or deleted by this class - if you want the ZipFile to
+        manage the stream's lifetime, use the other constructor.
+    */
+    explicit ZipFile (InputStream& inputStream);
+
+    /** Creates a ZipFile for an input source.
+
+        The inputSource object will be owned by the zip file, which will delete
+        it later when not needed.
+    */
+    explicit ZipFile (InputSource* inputSource);
+
+    /** Destructor. */
+    ~ZipFile();
+
+    //==============================================================================
+    /**
+        Contains information about one of the entries in a ZipFile.
+
+        @see ZipFile::getEntry
+    */
+    struct ZipEntry
+    {
+        /** The name of the file, which may also include a partial pathname. */
+        String filename;
+
+        /** The file's original size. */
+        unsigned int uncompressedSize;
+
+        /** The last time the file was modified. */
+        Time fileTime;
+    };
+
+    //==============================================================================
+    /** Returns the number of items in the zip file. */
+    int getNumEntries() const noexcept;
+
+    /** Returns a structure that describes one of the entries in the zip file.
+
+        This may return zero if the index is out of range.
+
+        @see ZipFile::ZipEntry
+    */
+    const ZipEntry* getEntry (int index) const noexcept;
+
+    /** Returns the index of the first entry with a given filename.
+
+        This uses a case-sensitive comparison to look for a filename in the
+        list of entries. It might return -1 if no match is found.
+
+        @see ZipFile::ZipEntry
+    */
+    int getIndexOfFileName (const String& fileName) const noexcept;
+
+    /** Returns a structure that describes one of the entries in the zip file.
+
+        This uses a case-sensitive comparison to look for a filename in the
+        list of entries. It might return 0 if no match is found.
+
+        @see ZipFile::ZipEntry
+    */
+    const ZipEntry* getEntry (const String& fileName) const noexcept;
+
+    /** Sorts the list of entries, based on the filename.
+    */
+    void sortEntriesByFilename();
+
+    //==============================================================================
+    /** Creates a stream that can read from one of the zip file's entries.
+
+        The stream that is returned must be deleted by the caller (and
+        zero might be returned if a stream can't be opened for some reason).
+
+        The stream must not be used after the ZipFile object that created
+        has been deleted.
+    */
+    InputStream* createStreamForEntry (int index);
+
+    /** Creates a stream that can read from one of the zip file's entries.
+
+        The stream that is returned must be deleted by the caller (and
+        zero might be returned if a stream can't be opened for some reason).
+
+        The stream must not be used after the ZipFile object that created
+        has been deleted.
+    */
+    InputStream* createStreamForEntry (const ZipEntry& entry);
+
+    //==============================================================================
+    /** Uncompresses all of the files in the zip file.
+
+        This will expand all the entries into a target directory. The relative
+        paths of the entries are used.
+
+        @param targetDirectory      the root folder to uncompress to
+        @param shouldOverwriteFiles whether to overwrite existing files with similarly-named ones
+        @returns success if the file is successfully unzipped
+    */
+    Result uncompressTo (const File& targetDirectory,
+                         bool shouldOverwriteFiles = true);
+
+    /** Uncompresses one of the entries from the zip file.
+
+        This will expand the entry and write it in a target directory. The entry's path is used to
+        determine which subfolder of the target should contain the new file.
+
+        @param index                the index of the entry to uncompress - this must be a valid index
+                                    between 0 and (getNumEntries() - 1).
+        @param targetDirectory      the root folder to uncompress into
+        @param shouldOverwriteFiles whether to overwrite existing files with similarly-named ones
+        @returns success if all the files are successfully unzipped
+    */
+    Result uncompressEntry (int index,
+                            const File& targetDirectory,
+                            bool shouldOverwriteFiles = true);
+
+
+    //==============================================================================
+    /** Used to create a new zip file.
+
+        Create a ZipFile::Builder object, and call its addFile() method to add some files,
+        then you can write it to a stream with write().
+
+        Currently this just stores the files with no compression.. That will be added
+        soon!
+    */
+    class Builder
+    {
+    public:
+        Builder();
+        ~Builder();
+
+        /** Adds a file while should be added to the archive.
+            The file isn't read immediately, all the files will be read later when the writeToStream()
+            method is called.
+
+            The compressionLevel can be between 0 (no compression), and 9 (maximum compression).
+            If the storedPathName parameter is specified, you can customise the partial pathname that
+            will be stored for this file.
+        */
+        void addFile (const File& fileToAdd, int compressionLevel,
+                      const String& storedPathName = String::empty);
+
+        /** Adds a file while should be added to the archive.
+
+            @param streamToRead this stream isn't read immediately - a pointer to the stream is
+                                stored, then used later when the writeToStream() method is called, and
+                                deleted by the Builder object when no longer needed, so be very careful
+                                about its lifetime and the lifetime of any objects on which it depends!
+                                This must not be null.
+            @param compressionLevel     this can be between 0 (no compression), and 9 (maximum compression).
+            @param storedPathName       the partial pathname that will be stored for this file
+            @param fileModificationTime the timestamp that will be stored as the last modification time
+                                        of this entry
+        */
+        void addEntry (InputStream* streamToRead, int compressionLevel,
+                       const String& storedPathName, Time fileModificationTime);
+
+        /** Generates the zip file, writing it to the specified stream.
+            If the progress parameter is non-null, it will be updated with an approximate
+            progress status between 0 and 1.0
+        */
+        bool writeToStream (OutputStream& target, double* progress) const;
+
+        //==============================================================================
+    private:
+        class Item;
+        friend struct ContainerDeletePolicy<Item>;
+        OwnedArray<Item> items;
+
+        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Builder)
+    };
+
+private:
+    //==============================================================================
+    class ZipInputStream;
+    class ZipEntryHolder;
+    friend class ZipInputStream;
+    friend class ZipEntryHolder;
+
+    OwnedArray <ZipEntryHolder> entries;
+    CriticalSection lock;
+    InputStream* inputStream;
+    ScopedPointer <InputStream> streamToDelete;
+    ScopedPointer <InputSource> inputSource;
+
+   #if JUCE_DEBUG
+    struct OpenStreamCounter
+    {
+        OpenStreamCounter() : numOpenStreams (0) {}
+        ~OpenStreamCounter();
+
+        int numOpenStreams;
+    };
+
+    OpenStreamCounter streamCounter;
+   #endif
+
+    void init();
+
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ZipFile)
+};
+
+#endif   // JUCE_ZIPFILE_H_INCLUDED
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/README b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/README
new file mode 100644
index 0000000..758cc50
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/README
@@ -0,0 +1,125 @@
+ZLIB DATA COMPRESSION LIBRARY
+
+zlib 1.2.3 is a general purpose data compression library.  All the code is
+thread safe.  The data format used by the zlib library is described by RFCs
+(Request for Comments) 1950 to 1952 in the files
+http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format)
+and rfc1952.txt (gzip format). These documents are also available in other
+formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact zlib at gzip.org). A usage example
+of the library is given in the file example.c which also tests that the library
+is working correctly. Another example is given in the file minigzip.c. The
+compression library itself is composed of all source files except example.c and
+minigzip.c.
+
+To compile all files and run the test program, follow the instructions given at
+the top of Makefile. In short "make test; make install" should work for most
+machines. For Unix: "./configure; make test; make install". For MSDOS, use one
+of the special makefiles such as Makefile.msc. For VMS, use make_vms.com.
+
+Questions about zlib should be sent to <zlib at gzip.org>, or to Gilles Vollant
+<info at winimage.com> for the Windows DLL version. The zlib home page is
+http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem,
+please check this site to verify that you have the latest version of zlib;
+otherwise get the latest version and check whether the problem still exists or
+not.
+
+PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking
+for help.
+
+Mark Nelson <markn at ieee.org> wrote an article about zlib for the Jan. 1997
+issue of  Dr. Dobb's Journal; a copy of the article is available in
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+
+The changes made in version 1.2.3 are documented in the file ChangeLog.
+
+Unsupported third party contributions are provided in directory "contrib".
+
+A Java implementation of zlib is available in the Java Development Kit
+http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html
+See the zlib home page http://www.zlib.org for details.
+
+A Perl interface to zlib written by Paul Marquess <pmqs at cpan.org> is in the
+CPAN (Comprehensive Perl Archive Network) sites
+http://www.cpan.org/modules/by-module/Compress/
+
+A Python interface to zlib written by A.M. Kuchling <amk at amk.ca> is
+available in Python 1.5 and later versions, see
+http://www.python.org/doc/lib/module-zlib.html
+
+A zlib binding for TCL written by Andreas Kupries <a.kupries at westend.com> is
+availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html
+
+An experimental package to read and write files in .zip format, written on top
+of zlib by Gilles Vollant <info at winimage.com>, is available in the
+contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- For Windows DLL versions, please see win32/DLL_FAQ.txt
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization. With
+  -O, one libpng test fails. The test works in 32 bit mode (with the -n32
+  compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
+  when compiled with cc.
+
+- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+  necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
+  other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
+
+- For PalmOs, see http://palmzlib.sourceforge.net/
+
+- When building a shared, i.e. dynamic library on Mac OS X, the library must be
+  installed before testing (do "make install" before "make test"), since the
+  library location is specified in the library.
+
+
+Acknowledgments:
+
+  The deflate format used by zlib was defined by Phil Katz. The deflate
+  and zlib specifications were written by L. Peter Deutsch. Thanks to all the
+  people who reported problems and suggested various improvements in zlib;
+  they are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2004 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors 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 software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     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 software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup at gzip.org          madler at alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind.  The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes. Please
+read the FAQ for more information on the distribution of modified source
+versions.
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/adler32.c b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/adler32.c
new file mode 100644
index 0000000..bf5cbd2
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/adler32.c
@@ -0,0 +1,143 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: adler32.c,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL    /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+#  define MOD(a) \
+    do { \
+        if (a >= (BASE << 16)) a -= (BASE << 16); \
+        if (a >= (BASE << 15)) a -= (BASE << 15); \
+        if (a >= (BASE << 14)) a -= (BASE << 14); \
+        if (a >= (BASE << 13)) a -= (BASE << 13); \
+        if (a >= (BASE << 12)) a -= (BASE << 12); \
+        if (a >= (BASE << 11)) a -= (BASE << 11); \
+        if (a >= (BASE << 10)) a -= (BASE << 10); \
+        if (a >= (BASE << 9)) a -= (BASE << 9); \
+        if (a >= (BASE << 8)) a -= (BASE << 8); \
+        if (a >= (BASE << 7)) a -= (BASE << 7); \
+        if (a >= (BASE << 6)) a -= (BASE << 6); \
+        if (a >= (BASE << 5)) a -= (BASE << 5); \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#  define MOD4(a) \
+    do { \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#else
+#  define MOD(a) a %= BASE
+#  define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len)
+{
+    unsigned long sum2;
+    unsigned n;
+
+    /* split Adler-32 into component sums */
+    sum2 = (adler >> 16) & 0xffff;
+    adler &= 0xffff;
+
+    /* in case user likes doing a byte at a time, keep it fast */
+    if (len == 1) {
+        adler += buf[0];
+        if (adler >= BASE)
+            adler -= BASE;
+        sum2 += adler;
+        if (sum2 >= BASE)
+            sum2 -= BASE;
+        return adler | (sum2 << 16);
+    }
+
+    /* initial Adler-32 value (deferred check for len == 1 speed) */
+    if (buf == Z_NULL)
+        return 1L;
+
+    /* in case short lengths are provided, keep it somewhat fast */
+    if (len < 16) {
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        if (adler >= BASE)
+            adler -= BASE;
+        MOD4(sum2);             /* only added so many BASE's */
+        return adler | (sum2 << 16);
+    }
+
+    /* do length NMAX blocks -- requires just one modulo operation */
+    while (len >= NMAX) {
+        len -= NMAX;
+        n = NMAX / 16;          /* NMAX is divisible by 16 */
+        do {
+            DO16(buf);          /* 16 sums unrolled */
+            buf += 16;
+        } while (--n);
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* do remaining bytes (less than NMAX, still just one modulo) */
+    if (len) {                  /* avoid modulos if none remaining */
+        while (len >= 16) {
+            len -= 16;
+            DO16(buf);
+            buf += 16;
+        }
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* return recombined sums */
+    return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2)
+{
+    unsigned long sum1;
+    unsigned long sum2;
+    unsigned rem;
+
+    /* the derivation of this formula is left as an exercise for the reader */
+    rem = (unsigned)(len2 % BASE);
+    sum1 = adler1 & 0xffff;
+    sum2 = rem * sum1;
+    MOD(sum2);
+    sum1 += (adler2 & 0xffff) + BASE - 1;
+    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+    if (sum1 > BASE) sum1 -= BASE;
+    if (sum1 > BASE) sum1 -= BASE;
+    if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
+    if (sum2 > BASE) sum2 -= BASE;
+    return sum1 | (sum2 << 16);
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/compress.c b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/compress.c
new file mode 100644
index 0000000..05c49c5
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/compress.c
@@ -0,0 +1,70 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: compress.c,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (Bytef *dest, uLongf *destLen, const Bytef *source,
+                       uLong sourceLen, int level)
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+    stream.opaque = (voidpf)0;
+
+    err = deflateInit(&stream, level);
+    if (err != Z_OK) return err;
+
+    err = deflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        deflateEnd(&stream);
+        return err == Z_OK ? Z_BUF_ERROR : err;
+    }
+    *destLen = stream.total_out;
+
+    err = deflateEnd(&stream);
+    return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
+{
+    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+     If the default memLevel or windowBits for deflateInit() is changed, then
+   this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (uLong sourceLen)
+{
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/crc32.c b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/crc32.c
new file mode 100644
index 0000000..500d536
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/crc32.c
@@ -0,0 +1,407 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64 at csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors.  This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id: crc32.c,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */
+
+/*
+  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+  protection on the static variables used to control the first-use generation
+  of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+  first call get_crc_table() to initialize the tables before allowing more than
+  one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+#  include <stdio.h>
+#  ifndef DYNAMIC_CRC_TABLE
+#    define DYNAMIC_CRC_TABLE
+#  endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h"      /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+#  ifdef STDC           /* need ANSI C limits.h to determine sizes */
+#    include <limits.h>
+#    define BYFOUR
+#    if (UINT_MAX == 0xffffffffUL)
+       typedef unsigned int u4;
+#    else
+#      if (ULONG_MAX == 0xffffffffUL)
+         typedef unsigned long u4;
+#      else
+#        if (USHRT_MAX == 0xffffffffUL)
+           typedef unsigned short u4;
+#        else
+#          undef BYFOUR     /* can't find a four-byte integer type! */
+#        endif
+#      endif
+#    endif
+#  endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+#  define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+                (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+   local unsigned long crc32_little OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+   local unsigned long crc32_big OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+#  define TBLS 8
+#else
+#  define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+                                         unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+   local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The first table is simply the CRC of all possible eight bit values.  This is
+  all the information needed to generate CRCs on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.  The remaining tables
+  allow for word-at-a-time CRC calculation for both big-endian and little-
+  endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+    unsigned long c;
+    int n, k;
+    unsigned long poly;                 /* polynomial exclusive-or pattern */
+    /* terms of polynomial defining this crc (except x^32): */
+    static volatile int first = 1;      /* flag to limit concurrent making */
+    static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+    /* See if another task is already doing this (not thread-safe, but better
+       than nothing -- significantly reduces duration of vulnerability in
+       case the advice about DYNAMIC_CRC_TABLE is ignored) */
+    if (first) {
+        first = 0;
+
+        /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+        poly = 0UL;
+        for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+            poly |= 1UL << (31 - p[n]);
+
+        /* generate a crc for every 8-bit value */
+        for (n = 0; n < 256; n++) {
+            c = (unsigned long)n;
+            for (k = 0; k < 8; k++)
+                c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+            crc_table[0][n] = c;
+        }
+
+#ifdef BYFOUR
+        /* generate crc for each value followed by one, two, and three zeros,
+           and then the byte reversal of those as well as the first table */
+        for (n = 0; n < 256; n++) {
+            c = crc_table[0][n];
+            crc_table[4][n] = REV(c);
+            for (k = 1; k < 4; k++) {
+                c = crc_table[0][c & 0xff] ^ (c >> 8);
+                crc_table[k][n] = c;
+                crc_table[k + 4][n] = REV(c);
+            }
+        }
+#endif /* BYFOUR */
+
+        crc_table_empty = 0;
+    }
+    else {      /* not first */
+        /* wait for the other guy to finish (not efficient, but rare) */
+        while (crc_table_empty)
+            ;
+    }
+
+#ifdef MAKECRCH
+    /* write out CRC tables to crc32.h */
+    {
+        FILE *out;
+
+        out = fopen("crc32.h", "w");
+        if (out == NULL) return;
+        fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+        fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+        fprintf(out, "local const unsigned long FAR ");
+        fprintf(out, "crc_table[TBLS][256] =\n{\n  {\n");
+        write_table(out, crc_table[0]);
+#  ifdef BYFOUR
+        fprintf(out, "#ifdef BYFOUR\n");
+        for (k = 1; k < 8; k++) {
+            fprintf(out, "  },\n  {\n");
+            write_table(out, crc_table[k]);
+        }
+        fprintf(out, "#endif\n");
+#  endif /* BYFOUR */
+        fprintf(out, "  }\n};\n");
+        fclose(out);
+    }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+    FILE *out;
+    const unsigned long FAR *table;
+{
+    int n;
+
+    for (n = 0; n < 256; n++)
+        fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : "    ", table[n],
+                n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+    return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32 (unsigned long crc, const unsigned char FAR *buf, unsigned len)
+{
+    if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+    if (sizeof(void *) == sizeof(ptrdiff_t)) {
+        u4 endian;
+
+        endian = 1;
+        if (*((unsigned char *)(&endian)))
+            return crc32_little(crc, buf, len);
+        else
+            return crc32_big(crc, buf, len);
+    }
+#endif /* BYFOUR */
+    crc = crc ^ 0xffffffffUL;
+    while (len >= 8) {
+        DO8;
+        len -= 8;
+    }
+    if (len) do {
+        DO1;
+    } while (--len);
+    return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+        c = (u4) (crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+                  crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24])
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(unsigned long crc, const unsigned char FAR *buf, unsigned len)
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = (u4)crc;
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = (u4) (crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8));
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    while (len >= 32) {
+        DOLIT32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOLIT4;
+        len -= 4;
+    }
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = (u4) (crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8));
+    } while (--len);
+    c = ~c;
+    return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+        c = (u4) (crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+                  crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24])
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big (unsigned long crc, const unsigned char FAR *buf, unsigned len)
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = REV((u4)crc);
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = (u4) (crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8));
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    buf4--;
+    while (len >= 32) {
+        DOBIG32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOBIG4;
+        len -= 4;
+    }
+    buf4++;
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = (u4) (crc_table[4][(c >> 24) ^ (u4) *buf++] ^ (c << 8));
+    } while (--len);
+    c = ~c;
+    return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32      /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times (unsigned long *mat, unsigned long vec)
+{
+    unsigned long sum;
+
+    sum = 0;
+    while (vec) {
+        if (vec & 1)
+            sum ^= *mat;
+        vec >>= 1;
+        mat++;
+    }
+    return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square (unsigned long *square, unsigned long *mat)
+{
+    int n;
+
+    for (n = 0; n < GF2_DIM; n++)
+        square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine (uLong crc1, uLong crc2, z_off_t len2)
+{
+    int n;
+    unsigned long row;
+    unsigned long even[GF2_DIM];    /* even-power-of-two zeros operator */
+    unsigned long odd[GF2_DIM];     /* odd-power-of-two zeros operator */
+
+    /* degenerate case */
+    if (len2 == 0)
+        return crc1;
+
+    /* put operator for one zero bit in odd */
+    odd[0] = 0xedb88320L;           /* CRC-32 polynomial */
+    row = 1;
+    for (n = 1; n < GF2_DIM; n++) {
+        odd[n] = row;
+        row <<= 1;
+    }
+
+    /* put operator for two zero bits in even */
+    gf2_matrix_square(even, odd);
+
+    /* put operator for four zero bits in odd */
+    gf2_matrix_square(odd, even);
+
+    /* apply len2 zeros to crc1 (first square will put the operator for one
+       zero byte, eight zero bits, in even) */
+    do {
+        /* apply zeros operator for this bit of len2 */
+        gf2_matrix_square(even, odd);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(even, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+        if (len2 == 0)
+            break;
+
+        /* another iteration of the loop with odd and even swapped */
+        gf2_matrix_square(odd, even);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(odd, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+    } while (len2 != 0);
+
+    /* return combined crc */
+    crc1 ^= crc2;
+    return crc1;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/crc32.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/crc32.h
new file mode 100644
index 0000000..5de49bc
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+  {
+    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+    0x2d02ef8dUL
+#ifdef BYFOUR
+  },
+  {
+    0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+    0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+    0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+    0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+    0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+    0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+    0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+    0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+    0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+    0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+    0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+    0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+    0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+    0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+    0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+    0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+    0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+    0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+    0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+    0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+    0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+    0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+    0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+    0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+    0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+    0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+    0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+    0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+    0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+    0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+    0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+    0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+    0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+    0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+    0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+    0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+    0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+    0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+    0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+    0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+    0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+    0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+    0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+    0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+    0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+    0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+    0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+    0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+    0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+    0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+    0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+    0x9324fd72UL
+  },
+  {
+    0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+    0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+    0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+    0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+    0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+    0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+    0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+    0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+    0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+    0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+    0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+    0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+    0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+    0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+    0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+    0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+    0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+    0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+    0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+    0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+    0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+    0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+    0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+    0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+    0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+    0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+    0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+    0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+    0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+    0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+    0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+    0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+    0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+    0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+    0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+    0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+    0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+    0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+    0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+    0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+    0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+    0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+    0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+    0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+    0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+    0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+    0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+    0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+    0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+    0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+    0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+    0xbe9834edUL
+  },
+  {
+    0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+    0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+    0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+    0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+    0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+    0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+    0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+    0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+    0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+    0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+    0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+    0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+    0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+    0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+    0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+    0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+    0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+    0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+    0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+    0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+    0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+    0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+    0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+    0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+    0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+    0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+    0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+    0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+    0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+    0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+    0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+    0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+    0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+    0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+    0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+    0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+    0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+    0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+    0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+    0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+    0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+    0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+    0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+    0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+    0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+    0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+    0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+    0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+    0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+    0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+    0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+    0xde0506f1UL
+  },
+  {
+    0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+    0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+    0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+    0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+    0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+    0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+    0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+    0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+    0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+    0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+    0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+    0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+    0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+    0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+    0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+    0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+    0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+    0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+    0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+    0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+    0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+    0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+    0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+    0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+    0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+    0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+    0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+    0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+    0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+    0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+    0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+    0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+    0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+    0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+    0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+    0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+    0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+    0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+    0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+    0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+    0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+    0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+    0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+    0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+    0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+    0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+    0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+    0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+    0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+    0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+    0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+    0x8def022dUL
+  },
+  {
+    0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+    0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+    0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+    0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+    0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+    0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+    0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+    0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+    0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+    0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+    0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+    0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+    0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+    0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+    0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+    0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+    0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+    0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+    0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+    0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+    0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+    0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+    0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+    0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+    0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+    0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+    0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+    0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+    0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+    0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+    0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+    0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+    0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+    0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+    0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+    0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+    0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+    0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+    0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+    0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+    0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+    0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+    0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+    0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+    0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+    0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+    0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+    0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+    0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+    0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+    0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+    0x72fd2493UL
+  },
+  {
+    0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+    0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+    0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+    0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+    0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+    0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+    0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+    0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+    0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+    0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+    0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+    0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+    0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+    0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+    0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+    0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+    0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+    0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+    0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+    0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+    0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+    0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+    0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+    0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+    0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+    0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+    0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+    0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+    0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+    0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+    0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+    0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+    0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+    0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+    0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+    0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+    0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+    0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+    0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+    0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+    0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+    0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+    0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+    0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+    0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+    0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+    0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+    0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+    0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+    0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+    0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+    0xed3498beUL
+  },
+  {
+    0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+    0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+    0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+    0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+    0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+    0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+    0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+    0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+    0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+    0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+    0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+    0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+    0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+    0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+    0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+    0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+    0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+    0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+    0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+    0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+    0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+    0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+    0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+    0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+    0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+    0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+    0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+    0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+    0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+    0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+    0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+    0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+    0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+    0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+    0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+    0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+    0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+    0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+    0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+    0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+    0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+    0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+    0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+    0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+    0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+    0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+    0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+    0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+    0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+    0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+    0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+    0xf10605deUL
+#endif
+  }
+};
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/deflate.c b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/deflate.c
new file mode 100644
index 0000000..4b8bda5
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/deflate.c
@@ -0,0 +1,1679 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id: deflate.c,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+   " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+#endif
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifndef FASTEST
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+#endif
+local uInt longest_match_fast OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version, int stream_size)
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+                         Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_ (z_streamp strm, int  level, int  method, int  windowBits, int  memLevel, int  strategy, const char *version, int stream_size)
+{
+    deflate_state *s;
+    int wrap = 1;
+    static const char my_version[] = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+        return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+    if (windowBits < 0) { /* suppress zlib wrapper */
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+#ifdef GZIP
+    else if (windowBits > 15) {
+        wrap = 2;       /* write gzip wrapper instead */
+        windowBits -= 16;
+    }
+#endif
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+        strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->wrap = wrap;
+    s->gzhead = Z_NULL;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        s->status = FINISH_STATE;
+        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (z_streamp strm, const Bytef *dictionary, uInt  dictLength)
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+        strm->state->wrap == 2 ||
+        (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+        return Z_STREAM_ERROR;
+
+    s = strm->state;
+    if (s->wrap)
+        strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+        length = MAX_DIST(s);
+        dictionary += dictLength - length; /* use the tail of the dictionary */
+    }
+    zmemcpy(s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+        INSERT_STRING(s, n, hash_head);
+    }
+
+    (void) hash_head;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (z_streamp strm)
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+        return Z_STREAM_ERROR;
+    }
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->wrap < 0) {
+        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+    }
+    s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+    strm->adler =
+#ifdef GZIP
+        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+        adler32(0L, Z_NULL, 0);
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (z_streamp strm, gz_headerp head)
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+    strm->state->gzhead = head;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (z_streamp strm, int bits, int value)
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    strm->state->bi_valid = bits;
+    strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams (z_streamp strm, int level, int strategy)
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+        /* Flush the last buffer: */
+        err = deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+        s->level = level;
+        s->max_lazy_match   = configuration_table[level].max_lazy;
+        s->good_match       = configuration_table[level].good_length;
+        s->nice_match       = configuration_table[level].nice_length;
+        s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune (z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain)
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+    s->good_match = good_length;
+    s->max_lazy_match = max_lazy;
+    s->nice_match = nice_length;
+    s->max_chain_length = max_chain;
+    return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well.  The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds
+ * for every combination of windowBits and memLevel, as well as wrap.
+ * But even the conservative upper bound of about 14% expansion does not
+ * seem onerous for output buffer allocation.
+ */
+uLong ZEXPORT deflateBound (z_streamp strm, uLong sourceLen)
+{
+    deflate_state *s;
+    uLong destLen;
+
+    /* conservative upper bound */
+    destLen = sourceLen +
+              ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11;
+
+    /* if can't get parameters, return conservative bound */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return destLen;
+
+    /* if not default parameters, return conservative bound */
+    s = strm->state;
+    if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+        return destLen;
+
+    /* default settings: return tight bound for that case */
+    return compressBound(sourceLen);
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (deflate_state *s, uInt b)
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending (z_streamp strm)
+{
+    unsigned len = strm->state->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    zmemcpy(strm->next_out, strm->state->pending_out, len);
+    strm->next_out  += len;
+    strm->state->pending_out  += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    strm->state->pending -= len;
+    if (strm->state->pending == 0) {
+        strm->state->pending_out = strm->state->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (z_streamp strm, int flush)
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = strm->state;
+
+    if (strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+        (s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the header */
+    if (s->status == INIT_STATE) {
+#ifdef GZIP
+        if (s->wrap == 2) {
+            strm->adler = crc32(0L, Z_NULL, 0);
+            put_byte(s, 31);
+            put_byte(s, 139);
+            put_byte(s, 8);
+            if (s->gzhead == NULL) {
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, OS_CODE);
+                s->status = BUSY_STATE;
+            }
+            else {
+                put_byte(s, (s->gzhead->text ? 1 : 0) +
+                            (s->gzhead->hcrc ? 2 : 0) +
+                            (s->gzhead->extra == Z_NULL ? 0 : 4) +
+                            (s->gzhead->name == Z_NULL ? 0 : 8) +
+                            (s->gzhead->comment == Z_NULL ? 0 : 16)
+                        );
+                put_byte(s, (Byte)(s->gzhead->time & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, s->gzhead->os & 0xff);
+                if (s->gzhead->extra != NULL) {
+                    put_byte(s, s->gzhead->extra_len & 0xff);
+                    put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+                }
+                if (s->gzhead->hcrc)
+                    strm->adler = crc32(strm->adler, s->pending_buf,
+                                        s->pending);
+                s->gzindex = 0;
+                s->status = EXTRA_STATE;
+            }
+        }
+        else
+#endif
+        {
+            uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+            uInt level_flags;
+
+            if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+                level_flags = 0;
+            else if (s->level < 6)
+                level_flags = 1;
+            else if (s->level == 6)
+                level_flags = 2;
+            else
+                level_flags = 3;
+            header |= (level_flags << 6);
+            if (s->strstart != 0) header |= PRESET_DICT;
+            header += 31 - (header % 31);
+
+            s->status = BUSY_STATE;
+            putShortMSB(s, header);
+
+            /* Save the adler32 of the preset dictionary: */
+            if (s->strstart != 0) {
+                putShortMSB(s, (uInt)(strm->adler >> 16));
+                putShortMSB(s, (uInt)(strm->adler & 0xffff));
+            }
+            strm->adler = adler32(0L, Z_NULL, 0);
+        }
+    }
+#ifdef GZIP
+    if (s->status == EXTRA_STATE) {
+        if (s->gzhead->extra != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+
+            while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size)
+                        break;
+                }
+                put_byte(s, s->gzhead->extra[s->gzindex]);
+                s->gzindex++;
+            }
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (s->gzindex == s->gzhead->extra_len) {
+                s->gzindex = 0;
+                s->status = NAME_STATE;
+            }
+        }
+        else
+            s->status = NAME_STATE;
+    }
+    if (s->status == NAME_STATE) {
+        if (s->gzhead->name != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->name[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0) {
+                s->gzindex = 0;
+                s->status = COMMENT_STATE;
+            }
+        }
+        else
+            s->status = COMMENT_STATE;
+    }
+    if (s->status == COMMENT_STATE) {
+        if (s->gzhead->comment != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->comment[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0)
+                s->status = HCRC_STATE;
+        }
+        else
+            s->status = HCRC_STATE;
+    }
+    if (s->status == HCRC_STATE) {
+        if (s->gzhead->hcrc) {
+            if (s->pending + 2 > s->pending_buf_size)
+                flush_pending(strm);
+            if (s->pending + 2 <= s->pending_buf_size) {
+                put_byte(s, (Byte)(strm->adler & 0xff));
+                put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+                strm->adler = crc32(0L, Z_NULL, 0);
+                s->status = BUSY_STATE;
+            }
+        }
+        else
+            s->status = BUSY_STATE;
+    }
+#endif
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+            /* Since avail_out is 0, deflate will be called again with
+             * more output space, but possibly with both pending and
+             * avail_in equal to zero. There won't be anything to do,
+             * but this is not an error situation so make sure we
+             * return OK instead of BUF_ERROR at next call of deflate:
+             */
+            s->last_flush = -1;
+            return Z_OK;
+        }
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+               flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+        bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+            if (strm->avail_out == 0) {
+                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+            }
+            return Z_OK;
+            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+             * of deflate should use the same flush parameter to make sure
+             * that the flush is complete. So we don't have to output an
+             * empty block here, this will be done at next call. This also
+             * ensures that for a very small output buffer, we emit at most
+             * one empty block.
+             */
+        }
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+            } else { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                }
+            }
+            flush_pending(strm);
+            if (strm->avail_out == 0) {
+              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+              return Z_OK;
+            }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->wrap <= 0) return Z_STREAM_END;
+
+    /* Write the trailer */
+#ifdef GZIP
+    if (s->wrap == 2) {
+        put_byte(s, (Byte)(strm->adler & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+        put_byte(s, (Byte)(strm->total_in & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+    }
+    else
+#endif
+    {
+        putShortMSB(s, (uInt)(strm->adler >> 16));
+        putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    }
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (z_streamp strm)
+{
+    int status;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+    status = strm->state->status;
+    if (status != INIT_STATE &&
+        status != EXTRA_STATE &&
+        status != NAME_STATE &&
+        status != COMMENT_STATE &&
+        status != HCRC_STATE &&
+        status != BUSY_STATE &&
+        status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, strm->state->pending_buf);
+    TRY_FREE(strm, strm->state->head);
+    TRY_FREE(strm, strm->state->prev);
+    TRY_FREE(strm, strm->state->window);
+
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (z_streamp dest, z_streamp source)
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = source->state;
+
+    zmemcpy(dest, source, sizeof(z_stream));
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    zmemcpy(ds, ss, sizeof(deflate_state));
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* following zmemcpy do not work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf (z_streamp strm, Bytef *buf, unsigned size)
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (strm->state->wrap == 1) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+#ifdef GZIP
+    else if (strm->state->wrap == 2) {
+        strm->adler = crc32(strm->adler, strm->next_in, len);
+    }
+#endif
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (deflate_state *s)
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(deflate_state *s, IPos cur_match)
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2.  Note that the checks below
+         * for insufficient lookahead only occur occasionally for performance
+         * reasons.  Therefore uninitialized memory will be accessed, and
+         * conditional jumps will be made that depend on those values.
+         * However the length of the match is limited to the lookahead, so
+         * the output of deflate is not affected by the uninitialized values.
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+    return s->lookahead;
+}
+#endif /* ASMV */
+#endif /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 or strategy == Z_RLE only
+ */
+local uInt longest_match_fast (deflate_state *s, IPos cur_match)
+{
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    Assert(cur_match < s->strstart, "no future");
+
+    match = s->window + cur_match;
+
+    /* Return failure if the match length is less than 2:
+     */
+    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+    /* The check at best_len-1 can be removed because it will be made
+     * again later. (This heuristic is not always a win.)
+     * It is not necessary to compare scan[2] and match[2] since they
+     * are always equal when the other bytes match, given that
+     * the hash keys are equal and that HASH_BITS >= 8.
+     */
+    scan += 2, match += 2;
+    Assert(*scan == *match, "match[2]?");
+
+    /* We check for insufficient lookahead only every 8th comparison;
+     * the 256th check will be made at strstart+258.
+     */
+    do {
+    } while (*++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             scan < strend);
+
+    Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+    len = MAX_MATCH - (int)(strend - scan);
+
+    if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+    s->match_start = cur_match;
+    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(deflate_state *s, IPos start, IPos match, int length)
+{
+    /* check that the match is indeed a match */
+    if (zmemcmp(s->window + match,
+                s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+                start, match, length);
+        do {
+            fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+        } while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window (deflate_state *s)
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (sizeof(int) <= 2) {
+            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+                more = wsize;
+
+            } else if (more == (unsigned)(-1)) {
+                /* Very unlikely, but possible on 16 bit machine if
+                 * strstart == 0 && lookahead == 1 (input done a byte at time)
+                 */
+                more--;
+            }
+        }
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            /* %%% avoid this when Z_RLE */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+#ifndef FASTEST
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+#endif
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+   _tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+                (ulg)((long)s->strstart - s->block_start), \
+                (eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(deflate_state *s, int flush)
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+                   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+        Assert(s->block_start >= 0L, "block gone");
+
+        s->strstart += s->lookahead;
+        s->lookahead = 0;
+
+        /* Emit a stored block if pending_buf will be full: */
+        max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+            /* strstart == 0 is possible when wraparound on 16-bit machine */
+            s->lookahead = (uInt)(s->strstart - max_start);
+            s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+        }
+        /* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+        }
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(deflate_state *s, int flush)
+{
+    IPos hash_head = NIL; /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+#ifdef FASTEST
+            if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) ||
+                (s->strategy == Z_RLE && s->strstart - hash_head == 1)) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+#else
+            if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+                s->match_length = longest_match (s, hash_head);
+            } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+#endif
+            /* longest_match() or longest_match_fast() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            _tr_tally_dist(s, s->strstart - s->match_start,
+                           s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+#ifndef FASTEST
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++;
+            } else
+#endif
+            {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(deflate_state *s, int flush)
+{
+    IPos hash_head = NIL;    /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+                s->match_length = longest_match (s, hash_head);
+            } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+            /* longest_match() or longest_match_fast() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+                || (s->match_length == MIN_MATCH &&
+                    s->strstart - s->match_start > TOO_FAR)
+#endif
+                )) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+                           s->prev_length - MIN_MATCH, bflush);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+            if (bflush) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+#if 0
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one.  Do not maintain a hash table.  (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;         /* set if current block must be flushed */
+    uInt run;           /* length of run */
+    uInt max;           /* maximum length of run */
+    uInt prev;          /* byte at distance one to match */
+    Bytef *scan;        /* scan for end of run */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the longest encodable run.
+         */
+        if (s->lookahead < MAX_MATCH) {
+            fill_window(s);
+            if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* See how many times the previous byte repeats */
+        run = 0;
+        if (s->strstart > 0) {      /* if there is a previous byte, that is */
+            max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH;
+            scan = s->window + s->strstart - 1;
+            prev = *scan++;
+            do {
+                if (*scan++ != prev)
+                    break;
+            } while (++run < max);
+        }
+
+        /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+        if (run >= MIN_MATCH) {
+            check_match(s, s->strstart, s->strstart - 1, run);
+            _tr_tally_dist(s, 1, run - MIN_MATCH, bflush);
+            s->lookahead -= run;
+            s->strstart += run;
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/deflate.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/deflate.h
new file mode 100644
index 0000000..a3bae5f
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/deflate.h
@@ -0,0 +1,333 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2004 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: deflate.h,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer creation by deflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip encoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GZIP
+#endif
+
+#define NO_DUMMY_DECL
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define EXTRA_STATE   69
+#define NAME_STATE    73
+#define COMMENT_STATE 91
+#define HCRC_STATE   103
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    uInt   pending;      /* nb of bytes in the pending buffer */
+    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */
+    gz_headerp  gzhead;  /* gzip header information to write */
+    uInt   gzindex;      /* where in extra, name, or comment */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+    ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+        /* in trees.c */
+void _tr_init         OF((deflate_state *s));
+int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+void _tr_align        OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+
+#define d_code(dist) \
+   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+  extern uch _length_code[];
+  extern uch _dist_code[];
+#else
+  extern const uch _length_code[];
+  extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+  { uch cc = (c); \
+    s->d_buf[s->last_lit] = 0; \
+    s->l_buf[s->last_lit++] = cc; \
+    s->dyn_ltree[cc].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+   }
+# define _tr_tally_dist(s, distance, length, flush) \
+  { uch len = (length); \
+    ush dist = (distance); \
+    s->d_buf[s->last_lit] = dist; \
+    s->l_buf[s->last_lit++] = len; \
+    dist--; \
+    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+    s->dyn_dtree[d_code(dist)].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+  }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+              flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/infback.c b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/infback.c
new file mode 100644
index 0000000..c259d01
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/infback.c
@@ -0,0 +1,611 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+   This code is largely copied from inflate.c.  Normally either infback.o or
+   inflate.o would be linked into an application--not both.  The interface
+   with inffast.c is retained so that optimized assembler-coded versions of
+   inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables1 OF((struct inflate_state FAR *state));
+
+/*
+   strm provides memory allocation functions in zalloc and zfree, or
+   Z_NULL to use the library memory allocation functions.
+
+   windowBits is in the range 8..15, and window is a user-supplied
+   window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)
+{
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL || window == Z_NULL ||
+        windowBits < 8 || windowBits > 15)
+        return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+                                               sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    state->dmax = 32768U;
+    state->wbits = windowBits;
+    state->wsize = 1U << windowBits;
+    state->window = window;
+    state->write = 0;
+    state->whave = 0;
+    return Z_OK;
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables1 (struct inflate_state FAR *state)
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Assure that some input is available.  If input is requested, but denied,
+   then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+    do { \
+        if (have == 0) { \
+            have = in(in_desc, &next); \
+            if (have == 0) { \
+                next = Z_NULL; \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+   with an error if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        PULL(); \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflateBack() with
+   an error. */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Assure that some output space is available, by writing out the window
+   if it's full.  If the write fails, return from inflateBack() with a
+   Z_BUF_ERROR. */
+#define ROOM() \
+    do { \
+        if (left == 0) { \
+            put = state->window; \
+            left = state->wsize; \
+            state->whave = left; \
+            if (out(out_desc, put, left)) { \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/*
+   strm provides the memory allocation functions and window buffer on input,
+   and provides information on the unused input on return.  For Z_DATA_ERROR
+   returns, strm will also provide an error message.
+
+   in() and out() are the call-back input and output functions.  When
+   inflateBack() needs more input, it calls in().  When inflateBack() has
+   filled the window with output, or when it completes with data in the
+   window, it calls out() to write out the data.  The application must not
+   change the provided input until in() is called again or inflateBack()
+   returns.  The application must not change the window/output buffer until
+   inflateBack() returns.
+
+   in() and out() are called with a descriptor parameter provided in the
+   inflateBack() call.  This parameter can be a structure that provides the
+   information required to do the read or write, as well as accumulated
+   information on the input and output such as totals and check values.
+
+   in() should return zero on failure.  out() should return non-zero on
+   failure.  If either in() or out() fails, than inflateBack() returns a
+   Z_BUF_ERROR.  strm->next_in can be checked for Z_NULL to see whether it
+   was in() or out() that caused in the error.  Otherwise,  inflateBack()
+   returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+   error, or Z_MEM_ERROR if it could not allocate memory for the state.
+   inflateBack() can also return Z_STREAM_ERROR if the input parameters
+   are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code thisx;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    /* Check that the strm exists and that the state was initialized */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* Reset the state */
+    strm->msg = Z_NULL;
+    state->mode = TYPE;
+    state->last = 0;
+    state->whave = 0;
+    next = strm->next_in;
+    have = next != Z_NULL ? strm->avail_in : 0;
+    hold = 0;
+    bits = 0;
+    put = state->window;
+    left = state->wsize;
+
+    /* Inflate until end of block marked as last */
+    for (;;)
+        switch (state->mode) {
+        case TYPE:
+            /* determine and dispatch block type */
+            if (state->last) {
+                BYTEBITS();
+                state->mode = DONE;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables1(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+
+        case STORED:
+            /* get and verify stored block length */
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+
+            /* copy stored block from input to output */
+            while (state->length != 0) {
+                copy = state->length;
+                PULL();
+                ROOM();
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+
+        case TABLE:
+            /* get dynamic table entries descriptor */
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+
+            /* get code length code lengths (not a typo) */
+            state->have = 0;
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+
+            /* get length and distance code code lengths */
+            state->have = 0;
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    thisx = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(thisx.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (thisx.val < 16) {
+                    NEEDBITS(thisx.bits);
+                    DROPBITS(thisx.bits);
+                    state->lens[state->have++] = thisx.val;
+                }
+                else {
+                    if (thisx.val == 16) {
+                        NEEDBITS(thisx.bits + 2);
+                        DROPBITS(thisx.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = (unsigned)(state->lens[state->have - 1]);
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (thisx.val == 17) {
+                        NEEDBITS(thisx.bits + 3);
+                        DROPBITS(thisx.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(thisx.bits + 7);
+                        DROPBITS(thisx.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* build code tables */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN;
+
+        case LEN:
+            /* use inflate_fast() if we have enough input and output */
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                if (state->whave < state->wsize)
+                    state->whave = state->wsize - left;
+                inflate_fast(strm, state->wsize);
+                LOAD();
+                break;
+            }
+
+            /* get a literal, length, or end-of-block code */
+            for (;;) {
+                thisx = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(thisx.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (thisx.op && (thisx.op & 0xf0) == 0) {
+                last = thisx;
+                for (;;) {
+                    thisx = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + thisx.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(thisx.bits);
+            state->length = (unsigned)thisx.val;
+
+            /* process literal */
+            if (thisx.op == 0) {
+                Tracevv((stderr, thisx.val >= 0x20 && thisx.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", thisx.val));
+                ROOM();
+                *put++ = (unsigned char)(state->length);
+                left--;
+                state->mode = LEN;
+                break;
+            }
+
+            /* process end of block */
+            if (thisx.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->mode = TYPE;
+                break;
+            }
+
+            /* invalid code */
+            if (thisx.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+
+            /* length code -- get extra bits, if any */
+            state->extra = (unsigned)(thisx.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+
+            /* get distance code */
+            for (;;) {
+                thisx = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(thisx.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((thisx.op & 0xf0) == 0) {
+                last = thisx;
+                for (;;) {
+                    thisx = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + thisx.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(thisx.bits);
+            if (thisx.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)thisx.val;
+
+            /* get distance extra bits, if any */
+            state->extra = (unsigned)(thisx.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            if (state->offset > state->wsize - (state->whave < state->wsize ?
+                                                left : 0)) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+
+            /* copy match from window to output */
+            do {
+                ROOM();
+                copy = state->wsize - state->offset;
+                if (copy < left) {
+                    from = put + copy;
+                    copy = left - copy;
+                }
+                else {
+                    from = put - state->offset;
+                    copy = left;
+                }
+                if (copy > state->length) copy = state->length;
+                state->length -= copy;
+                left -= copy;
+                do {
+                    *put++ = *from++;
+                } while (--copy);
+            } while (state->length != 0);
+            break;
+
+        case DONE:
+            /* inflate stream terminated properly -- write leftover output */
+            ret = Z_STREAM_END;
+            if (left < state->wsize) {
+                if (out(out_desc, state->window, state->wsize - left))
+                    ret = Z_BUF_ERROR;
+            }
+            goto inf_leave;
+
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+
+        default:                /* can't happen, but makes compilers happy */
+            ret = Z_STREAM_ERROR;
+            goto inf_leave;
+        }
+
+    /* Return unused input */
+  inf_leave:
+    strm->next_in = next;
+    strm->avail_in = have;
+    return ret;
+}
+
+int ZEXPORT inflateBackEnd (z_streamp strm)
+{
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inffast.c b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inffast.c
new file mode 100644
index 0000000..6ac383d
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inffast.c
@@ -0,0 +1,316 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+   Based on testing to date,
+   Pre-increment preferred for:
+   - PowerPC G3 (Adler)
+   - MIPS R5000 (Randers-Pehrson)
+   Post-increment preferred for:
+   - none
+   No measurable difference:
+   - Pentium III (Anderson)
+   - M68060 (Nikl)
+ */
+#ifdef POSTINC
+#  define OFF 0
+#  define PUP(a) *(a)++
+#else
+#  define OFF 1
+#  define PUP(a) *++(a)
+#endif
+
+/*
+   Decode literal, length, and distance codes and write out the resulting
+   literal and match bytes until either not enough input or output is
+   available, an end-of-block is encountered, or a data error is encountered.
+   When large enough input and output buffers are supplied to inflate(), for
+   example, a 16K input buffer and a 64K output buffer, more than 95% of the
+   inflate execution time is spent in this routine.
+
+   Entry assumptions:
+
+        state->mode == LEN
+        strm->avail_in >= 6
+        strm->avail_out >= 258
+        start >= strm->avail_out
+        state->bits < 8
+
+   On return, state->mode is one of:
+
+        LEN -- ran out of enough output space or enough available input
+        TYPE -- reached end of block code, inflate() to interpret next block
+        BAD -- error in block data
+
+   Notes:
+
+    - The maximum input bits used by a length/distance pair is 15 bits for the
+      length code, 5 bits for the length extra, 15 bits for the distance code,
+      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
+      Therefore if strm->avail_in >= 6, then there is enough input to avoid
+      checking for available input while decoding.
+
+    - The maximum bytes that a single length/distance pair can output is 258
+      bytes, which is the maximum length that can be coded.  inflate_fast()
+      requires strm->avail_out >= 258 for each loop to avoid checking for
+      output space.
+ */
+void inflate_fast (z_streamp strm, unsigned start)
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *in;      /* local strm->next_in */
+    unsigned char FAR *last;    /* while in < last, enough input available */
+    unsigned char FAR *out;     /* local strm->next_out */
+    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
+    unsigned char FAR *end;     /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+    unsigned dmax;              /* maximum distance from zlib header */
+#endif
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
+    unsigned long hold;         /* local strm->hold */
+    unsigned bits;              /* local strm->bits */
+    code const FAR *lcode;      /* local strm->lencode */
+    code const FAR *dcode;      /* local strm->distcode */
+    unsigned lmask;             /* mask for first level of length codes */
+    unsigned dmask;             /* mask for first level of distance codes */
+    code thisx;                  /* retrieved table entry */
+    unsigned op;                /* code bits, operation, extra bits, or */
+                                /*  window position, window bytes to copy */
+    unsigned len;               /* match length, unused bytes */
+    unsigned dist;              /* match distance */
+    unsigned char FAR *from;    /* where to copy match from */
+
+    /* copy state to local variables */
+    state = (struct inflate_state FAR *)strm->state;
+    in = strm->next_in - OFF;
+    last = in + (strm->avail_in - 5);
+    out = strm->next_out - OFF;
+    beg = out - (start - strm->avail_out);
+    end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+    dmax = state->dmax;
+#endif
+    wsize = state->wsize;
+    whave = state->whave;
+    write = state->write;
+    window = state->window;
+    hold = state->hold;
+    bits = state->bits;
+    lcode = state->lencode;
+    dcode = state->distcode;
+    lmask = (1U << state->lenbits) - 1;
+    dmask = (1U << state->distbits) - 1;
+
+    /* decode literals and length/distances until end-of-block or not enough
+       input data or output space */
+    do {
+        if (bits < 15) {
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+        }
+        thisx = lcode[hold & lmask];
+      dolen:
+        op = (unsigned)(thisx.bits);
+        hold >>= op;
+        bits -= op;
+        op = (unsigned)(thisx.op);
+        if (op == 0) {                          /* literal */
+            Tracevv((stderr, thisx.val >= 0x20 && thisx.val < 0x7f ?
+                    "inflate:         literal '%c'\n" :
+                    "inflate:         literal 0x%02x\n", thisx.val));
+            PUP(out) = (unsigned char)(thisx.val);
+        }
+        else if (op & 16) {                     /* length base */
+            len = (unsigned)(thisx.val);
+            op &= 15;                           /* number of extra bits */
+            if (op) {
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                }
+                len += (unsigned)hold & ((1U << op) - 1);
+                hold >>= op;
+                bits -= op;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", len));
+            if (bits < 15) {
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+            }
+            thisx = dcode[hold & dmask];
+          dodist:
+            op = (unsigned)(thisx.bits);
+            hold >>= op;
+            bits -= op;
+            op = (unsigned)(thisx.op);
+            if (op & 16) {                      /* distance base */
+                dist = (unsigned)(thisx.val);
+                op &= 15;                       /* number of extra bits */
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                    if (bits < op) {
+                        hold += (unsigned long)(PUP(in)) << bits;
+                        bits += 8;
+                    }
+                }
+                dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+                if (dist > dmax) {
+                    strm->msg = (char *)"invalid distance too far back";
+                    state->mode = BAD;
+                    break;
+                }
+#endif
+                hold >>= op;
+                bits -= op;
+                Tracevv((stderr, "inflate:         distance %u\n", dist));
+                op = (unsigned)(out - beg);     /* max distance in output */
+                if (dist > op) {                /* see if copy from window */
+                    op = dist - op;             /* distance back in window */
+                    if (op > whave) {
+                        strm->msg = (char *)"invalid distance too far back";
+                        state->mode = BAD;
+                        break;
+                    }
+                    from = window - OFF;
+                    if (write == 0) {           /* very common case */
+                        from += wsize - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    else if (write < op) {      /* wrap around window */
+                        from += wsize + write - op;
+                        op -= write;
+                        if (op < len) {         /* some from end of window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = window - OFF;
+                            if (write < len) {  /* some from start of window */
+                                op = write;
+                                len -= op;
+                                do {
+                                    PUP(out) = PUP(from);
+                                } while (--op);
+                                from = out - dist;      /* rest from output */
+                            }
+                        }
+                    }
+                    else {                      /* contiguous in window */
+                        from += write - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    while (len > 2) {
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    }
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+                else {
+                    from = out - dist;          /* copy direct from output */
+                    do {                        /* minimum length is three */
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    } while (len > 2);
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+            }
+            else if ((op & 64) == 0) {          /* 2nd level distance code */
+                thisx = dcode[thisx.val + (hold & ((1U << op) - 1))];
+                goto dodist;
+            }
+            else {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+        }
+        else if ((op & 64) == 0) {              /* 2nd level length code */
+            thisx = lcode[thisx.val + (hold & ((1U << op) - 1))];
+            goto dolen;
+        }
+        else if (op & 32) {                     /* end-of-block */
+            Tracevv((stderr, "inflate:         end of block\n"));
+            state->mode = TYPE;
+            break;
+        }
+        else {
+            strm->msg = (char *)"invalid literal/length code";
+            state->mode = BAD;
+            break;
+        }
+    } while (in < last && out < end);
+
+    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+    len = bits >> 3;
+    in -= len;
+    bits -= len << 3;
+    hold &= (1U << bits) - 1;
+
+    /* update state and return */
+    strm->next_in = in + OFF;
+    strm->next_out = out + OFF;
+    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+    strm->avail_out = (unsigned)(out < end ?
+                                 257 + (end - out) : 257 - (out - end));
+    state->hold = hold;
+    state->bits = bits;
+    return;
+}
+
+/*
+   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+   - Using bit fields for code structure
+   - Different op definition to avoid & for extra bits (do & for table bits)
+   - Three separate decoding do-loops for direct, window, and write == 0
+   - Special case for distance > 1 copies to do overlapped load and store copy
+   - Explicit branch predictions (based on measured branch probabilities)
+   - Deferring match copy and interspersed it with decoding subsequent codes
+   - Swapping literal/length else
+   - Swapping window/direct else
+   - Larger unrolled copy loops (three is about right)
+   - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inffast.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inffast.h
new file mode 100644
index 0000000..614fa78
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inffixed.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inffixed.h
new file mode 100644
index 0000000..423d5c5
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inffixed.h
@@ -0,0 +1,94 @@
+    /* inffixed.h -- table for decoding fixed codes
+     * Generated automatically by makefixed().
+     */
+
+    /* WARNING: this file should *not* be used by applications. It
+       is part of the implementation of the compression library and
+       is subject to change. Applications should only use zlib.h.
+     */
+
+    static const code lenfix[512] = {
+        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+        {0,9,255}
+    };
+
+    static const code distfix[32] = {
+        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+        {22,5,193},{64,5,0}
+    };
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inflate.c b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inflate.c
new file mode 100644
index 0000000..eef0d37
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inflate.c
@@ -0,0 +1,1339 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0    24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ *   creation of window when not needed, minimize use of window when it is
+ *   needed, make inffast.c even faster, implement gzip decoding, and to
+ *   improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1    25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2    4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ *   to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3    22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ *   buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4    1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ *   source file infback.c to provide a call-back interface to inflate for
+ *   programs like gzip and unzip -- uses window as output buffer to avoid
+ *   window copying
+ *
+ * 1.2.beta5    1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ *   input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6    4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ *   make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7    27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0        9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ *   for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ *   and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+#  ifndef BUILDFIXED
+#    define BUILDFIXED
+#  endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+   void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+                              unsigned len));
+
+int ZEXPORT inflateReset (z_streamp strm)
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    strm->total_in = strm->total_out = state->total = 0;
+    strm->msg = Z_NULL;
+    strm->adler = 1;        /* to support ill-conceived Java test suite */
+    state->mode = HEAD;
+    state->last = 0;
+    state->havedict = 0;
+    state->dmax = 32768U;
+    state->head = Z_NULL;
+    state->wsize = 0;
+    state->whave = 0;
+    state->write = 0;
+    state->hold = 0;
+    state->bits = 0;
+    state->lencode = state->distcode = state->next = state->codes;
+    Tracev((stderr, "inflate: reset\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflatePrime (z_streamp strm, int bits, int value)
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+    value &= (1 << bits) - 1;
+    state->hold += value << state->bits;
+    state->bits += bits;
+    return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, const char *version, int stream_size)
+{
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)
+            ZALLOC(strm, 1, sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    if (windowBits < 0) {
+        state->wrap = 0;
+        windowBits = -windowBits;
+    }
+    else {
+        state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+        if (windowBits < 48) windowBits &= 15;
+#endif
+    }
+    if (windowBits < 8 || windowBits > 15) {
+        ZFREE(strm, state);
+        strm->state = Z_NULL;
+        return Z_STREAM_ERROR;
+    }
+    state->wbits = (unsigned)windowBits;
+    state->window = Z_NULL;
+    return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_ (z_streamp strm, const char *version, int stream_size)
+{
+    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables (struct inflate_state FAR *state)
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also
+   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes
+   those tables to stdout, which would be piped to inffixed.h.  A small program
+   can simply call makefixed to do this:
+
+    void makefixed(void);
+
+    int main(void)
+    {
+        makefixed();
+        return 0;
+    }
+
+   Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+    a.out > inffixed.h
+ */
+void makefixed()
+{
+    unsigned low, size;
+    struct inflate_state state;
+
+    fixedtables(&state);
+    puts("    /* inffixed.h -- table for decoding fixed codes");
+    puts("     * Generated automatically by makefixed().");
+    puts("     */");
+    puts("");
+    puts("    /* WARNING: this file should *not* be used by applications.");
+    puts("       It is part of the implementation of this library and is");
+    puts("       subject to change. Applications should only use zlib.h.");
+    puts("     */");
+    puts("");
+    size = 1U << 9;
+    printf("    static const code lenfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 7) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+               state.lencode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+    size = 1U << 5;
+    printf("\n    static const code distfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 6) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+               state.distcode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+}
+#endif /* MAKEFIXED */
+
+/*
+   Update the window with the last wsize (normally 32K) bytes written before
+   returning.  If window does not exist yet, create it.  This is only called
+   when a window is already in use, or when output has been written during this
+   inflate call, but the end of the deflate stream has not been reached yet.
+   It is also called to create a window for dictionary data when a dictionary
+   is loaded.
+
+   Providing output buffers larger than 32K to inflate() should provide a speed
+   advantage, since only the last 32K of output is copied to the sliding window
+   upon return from inflate(), and since all distances after the first 32K of
+   output will fall in the output data, making match copies simpler and faster.
+   The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow (z_streamp strm, unsigned out)
+{
+    struct inflate_state FAR *state;
+    unsigned copy, dist;
+
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* if it hasn't been done already, allocate space for the window */
+    if (state->window == Z_NULL) {
+        state->window = (unsigned char FAR *)
+                        ZALLOC(strm, 1U << state->wbits,
+                               sizeof(unsigned char));
+        if (state->window == Z_NULL) return 1;
+    }
+
+    /* if window not in use yet, initialize */
+    if (state->wsize == 0) {
+        state->wsize = 1U << state->wbits;
+        state->write = 0;
+        state->whave = 0;
+    }
+
+    /* copy state->wsize or less output bytes into the circular window */
+    copy = out - strm->avail_out;
+    if (copy >= state->wsize) {
+        zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+        state->write = 0;
+        state->whave = state->wsize;
+    }
+    else {
+        dist = state->wsize - state->write;
+        if (dist > copy) dist = copy;
+        zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+        copy -= dist;
+        if (copy) {
+            zmemcpy(state->window, strm->next_out - copy, copy);
+            state->write = copy;
+            state->whave = state->wsize;
+        }
+        else {
+            state->write += dist;
+            if (state->write == state->wsize) state->write = 0;
+            if (state->whave < state->wsize) state->whave += dist;
+        }
+    }
+    return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+#  define UPDATE(check, buf, len) \
+    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+#  define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+#  define CRC2(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        check = crc32(check, hbuf, 2); \
+    } while (0)
+
+#  define CRC4(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        hbuf[2] = (unsigned char)((word) >> 16); \
+        hbuf[3] = (unsigned char)((word) >> 24); \
+        check = crc32(check, hbuf, 4); \
+    } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+   if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        if (have == 0) goto inf_leave; \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+    ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+     (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+   inflate() uses a state machine to process as much input data and generate as
+   much output data as possible before returning.  The state machine is
+   structured roughly as follows:
+
+    for (;;) switch (state) {
+    ...
+    case STATEn:
+        if (not enough input data or output space to make progress)
+            return;
+        ... make progress ...
+        state = STATEm;
+        break;
+    ...
+    }
+
+   so when inflate() is called again, the same case is attempted again, and
+   if the appropriate resources are provided, the machine proceeds to the
+   next state.  The NEEDBITS() macro is usually the way the state evaluates
+   whether it can proceed or should return.  NEEDBITS() does the return if
+   the requested bits are not available.  The typical use of the BITS macros
+   is:
+
+        NEEDBITS(n);
+        ... do something with BITS(n) ...
+        DROPBITS(n);
+
+   where NEEDBITS(n) either returns from inflate() if there isn't enough
+   input left to load n bits into the accumulator, or it continues.  BITS(n)
+   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
+   the low n bits off the accumulator.  INITBITS() clears the accumulator
+   and sets the number of available bits to zero.  BYTEBITS() discards just
+   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
+   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+   if there is no input available.  The decoding of variable length codes uses
+   PULLBYTE() directly in order to pull just enough bytes to decode the next
+   code, and no more.
+
+   Some states loop until they get enough input, making sure that enough
+   state information is maintained to continue the loop where it left off
+   if NEEDBITS() returns in the loop.  For example, want, need, and keep
+   would all have to actually be part of the saved state in case NEEDBITS()
+   returns:
+
+    case STATEw:
+        while (want < need) {
+            NEEDBITS(n);
+            keep[want++] = BITS(n);
+            DROPBITS(n);
+        }
+        state = STATEx;
+    case STATEx:
+
+   As shown above, if the next state is also the next case, then the break
+   is omitted.
+
+   A state may also return if there is not enough output space available to
+   complete that state.  Those states are copying stored data, writing a
+   literal byte, and copying a matching string.
+
+   When returning, a "goto inf_leave" is used to update the total counters,
+   update the check value, and determine whether any progress has been made
+   during that inflate() call in order to return the proper return code.
+   Progress is defined as a change in either strm->avail_in or strm->avail_out.
+   When there is a window, goto inf_leave will update the window with the last
+   output written.  If a goto inf_leave occurs in the middle of decompression
+   and there is no window currently, goto inf_leave will create one and copy
+   output to the window for the next call of inflate().
+
+   In this implementation, the flush parameter of inflate() only affects the
+   return code (per zlib.h).  inflate() always writes as much as possible to
+   strm->next_out, given the space available and the provided input--the effect
+   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
+   the allocation of and copying into a sliding window until necessary, which
+   provides the effect documented in zlib.h for Z_FINISH when the entire input
+   stream available.  So the only thing the flush parameter actually does is:
+   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
+   will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate (z_streamp strm, int flush)
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned in, out;           /* save starting available input and output */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code thisx;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+#ifdef GUNZIP
+    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
+#endif
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0))
+        return Z_STREAM_ERROR;
+
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
+    LOAD();
+    in = have;
+    out = left;
+    ret = Z_OK;
+    for (;;)
+        switch (state->mode) {
+        case HEAD:
+            if (state->wrap == 0) {
+                state->mode = TYPEDO;
+                break;
+            }
+            NEEDBITS(16);
+#ifdef GUNZIP
+            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
+                state->check = crc32(0L, Z_NULL, 0);
+                CRC2(state->check, hold);
+                INITBITS();
+                state->mode = FLAGS;
+                break;
+            }
+            state->flags = 0;           /* expect zlib header */
+            if (state->head != Z_NULL)
+                state->head->done = -1;
+            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
+#else
+            if (
+#endif
+                ((BITS(8) << 8) + (hold >> 8)) % 31) {
+                strm->msg = (char *)"incorrect header check";
+                state->mode = BAD;
+                break;
+            }
+            if (BITS(4) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            DROPBITS(4);
+            len = BITS(4) + 8;
+            if (len > state->wbits) {
+                strm->msg = (char *)"invalid window size";
+                state->mode = BAD;
+                break;
+            }
+            state->dmax = 1U << len;
+            Tracev((stderr, "inflate:   zlib header ok\n"));
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = hold & 0x200 ? DICTID : TYPE;
+            INITBITS();
+            break;
+#ifdef GUNZIP
+        case FLAGS:
+            NEEDBITS(16);
+            state->flags = (int)(hold);
+            if ((state->flags & 0xff) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            if (state->flags & 0xe000) {
+                strm->msg = (char *)"unknown header flags set";
+                state->mode = BAD;
+                break;
+            }
+            if (state->head != Z_NULL)
+                state->head->text = (int)((hold >> 8) & 1);
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = TIME;
+        case TIME:
+            NEEDBITS(32);
+            if (state->head != Z_NULL)
+                state->head->time = hold;
+            if (state->flags & 0x0200) CRC4(state->check, hold);
+            INITBITS();
+            state->mode = OS;
+        case OS:
+            NEEDBITS(16);
+            if (state->head != Z_NULL) {
+                state->head->xflags = (int)(hold & 0xff);
+                state->head->os = (int)(hold >> 8);
+            }
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = EXLEN;
+        case EXLEN:
+            if (state->flags & 0x0400) {
+                NEEDBITS(16);
+                state->length = (unsigned)(hold);
+                if (state->head != Z_NULL)
+                    state->head->extra_len = (unsigned)hold;
+                if (state->flags & 0x0200) CRC2(state->check, hold);
+                INITBITS();
+            }
+            else if (state->head != Z_NULL)
+                state->head->extra = Z_NULL;
+            state->mode = EXTRA;
+        case EXTRA:
+            if (state->flags & 0x0400) {
+                copy = state->length;
+                if (copy > have) copy = have;
+                if (copy) {
+                    if (state->head != Z_NULL &&
+                        state->head->extra != Z_NULL) {
+                        len = state->head->extra_len - state->length;
+                        zmemcpy(state->head->extra + len, next,
+                                len + copy > state->head->extra_max ?
+                                state->head->extra_max - len : copy);
+                    }
+                    if (state->flags & 0x0200)
+                        state->check = crc32(state->check, next, copy);
+                    have -= copy;
+                    next += copy;
+                    state->length -= copy;
+                }
+                if (state->length) goto inf_leave;
+            }
+            state->length = 0;
+            state->mode = NAME;
+        case NAME:
+            if (state->flags & 0x0800) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->name != Z_NULL &&
+                            state->length < state->head->name_max)
+                        state->head->name[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->name = Z_NULL;
+            state->length = 0;
+            state->mode = COMMENT;
+        case COMMENT:
+            if (state->flags & 0x1000) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->comment != Z_NULL &&
+                            state->length < state->head->comm_max)
+                        state->head->comment[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->comment = Z_NULL;
+            state->mode = HCRC;
+        case HCRC:
+            if (state->flags & 0x0200) {
+                NEEDBITS(16);
+                if (hold != (state->check & 0xffff)) {
+                    strm->msg = (char *)"header crc mismatch";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+            }
+            if (state->head != Z_NULL) {
+                state->head->hcrc = (int)((state->flags >> 9) & 1);
+                state->head->done = 1;
+            }
+            strm->adler = state->check = crc32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+            break;
+#endif
+        case DICTID:
+            NEEDBITS(32);
+            strm->adler = state->check = REVERSE(hold);
+            INITBITS();
+            state->mode = DICT;
+        case DICT:
+            if (state->havedict == 0) {
+                RESTORE();
+                return Z_NEED_DICT;
+            }
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+        case TYPE:
+            if (flush == Z_BLOCK) goto inf_leave;
+        case TYPEDO:
+            if (state->last) {
+                BYTEBITS();
+                state->mode = CHECK;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+        case STORED:
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+            state->mode = COPY;
+        case COPY:
+            copy = state->length;
+            if (copy) {
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                if (copy == 0) goto inf_leave;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+                break;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+        case TABLE:
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+            state->have = 0;
+            state->mode = LENLENS;
+        case LENLENS:
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+            state->have = 0;
+            state->mode = CODELENS;
+        case CODELENS:
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    thisx = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(thisx.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (thisx.val < 16) {
+                    NEEDBITS(thisx.bits);
+                    DROPBITS(thisx.bits);
+                    state->lens[state->have++] = thisx.val;
+                }
+                else {
+                    if (thisx.val == 16) {
+                        NEEDBITS(thisx.bits + 2);
+                        DROPBITS(thisx.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = state->lens[state->have - 1];
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (thisx.val == 17) {
+                        NEEDBITS(thisx.bits + 3);
+                        DROPBITS(thisx.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(thisx.bits + 7);
+                        DROPBITS(thisx.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* build code tables */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN;
+        case LEN:
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                inflate_fast(strm, out);
+                LOAD();
+                break;
+            }
+            for (;;) {
+                thisx = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(thisx.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (thisx.op && (thisx.op & 0xf0) == 0) {
+                last = thisx;
+                for (;;) {
+                    thisx = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + thisx.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(thisx.bits);
+            state->length = (unsigned)thisx.val;
+            if ((int)(thisx.op) == 0) {
+                Tracevv((stderr, thisx.val >= 0x20 && thisx.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", thisx.val));
+                state->mode = LIT;
+                break;
+            }
+            if (thisx.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->mode = TYPE;
+                break;
+            }
+            if (thisx.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+            state->extra = (unsigned)(thisx.op) & 15;
+            state->mode = LENEXT;
+        case LENEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+            state->mode = DIST;
+        case DIST:
+            for (;;) {
+                thisx = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(thisx.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((thisx.op & 0xf0) == 0) {
+                last = thisx;
+                for (;;) {
+                    thisx = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + thisx.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(thisx.bits);
+            if (thisx.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)thisx.val;
+            state->extra = (unsigned)(thisx.op) & 15;
+            state->mode = DISTEXT;
+        case DISTEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+#ifdef INFLATE_STRICT
+            if (state->offset > state->dmax) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            if (state->offset > state->whave + out - left) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+            state->mode = MATCH;
+        case MATCH:
+            if (left == 0) goto inf_leave;
+            copy = out - left;
+            if (state->offset > copy) {         /* copy from window */
+                copy = state->offset - copy;
+                if (copy > state->write) {
+                    copy -= state->write;
+                    from = state->window + (state->wsize - copy);
+                }
+                else
+                    from = state->window + (state->write - copy);
+                if (copy > state->length) copy = state->length;
+            }
+            else {                              /* copy from output */
+                from = put - state->offset;
+                copy = state->length;
+            }
+            if (copy > left) copy = left;
+            left -= copy;
+            state->length -= copy;
+            do {
+                *put++ = *from++;
+            } while (--copy);
+            if (state->length == 0) state->mode = LEN;
+            break;
+        case LIT:
+            if (left == 0) goto inf_leave;
+            *put++ = (unsigned char)(state->length);
+            left--;
+            state->mode = LEN;
+            break;
+        case CHECK:
+            if (state->wrap) {
+                NEEDBITS(32);
+                out -= left;
+                strm->total_out += out;
+                state->total += out;
+                if (out)
+                    strm->adler = state->check =
+                        UPDATE(state->check, put - out, out);
+                out = left;
+                if ((
+#ifdef GUNZIP
+                     state->flags ? hold :
+#endif
+                     REVERSE(hold)) != state->check) {
+                    strm->msg = (char *)"incorrect data check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   check matches trailer\n"));
+            }
+#ifdef GUNZIP
+            state->mode = LENGTH;
+        case LENGTH:
+            if (state->wrap && state->flags) {
+                NEEDBITS(32);
+                if (hold != (state->total & 0xffffffffUL)) {
+                    strm->msg = (char *)"incorrect length check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   length matches trailer\n"));
+            }
+#endif
+            state->mode = DONE;
+        case DONE:
+            ret = Z_STREAM_END;
+            goto inf_leave;
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+        case MEM:
+            return Z_MEM_ERROR;
+        case SYNC:
+        default:
+            return Z_STREAM_ERROR;
+        }
+
+    /*
+       Return from inflate(), updating the total counts and the check value.
+       If there was no progress during the inflate() call, return a buffer
+       error.  Call updatewindow() to create and/or update the window state.
+       Note: a memory error from inflate() is non-recoverable.
+     */
+  inf_leave:
+    RESTORE();
+    if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+        if (updatewindow(strm, out)) {
+            state->mode = MEM;
+            return Z_MEM_ERROR;
+        }
+    in -= strm->avail_in;
+    out -= strm->avail_out;
+    strm->total_in += in;
+    strm->total_out += out;
+    state->total += out;
+    if (state->wrap && out)
+        strm->adler = state->check =
+            UPDATE(state->check, strm->next_out - out, out);
+    strm->data_type = state->bits + (state->last ? 64 : 0) +
+                      (state->mode == TYPE ? 128 : 0);
+    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+        ret = Z_BUF_ERROR;
+    return ret;
+}
+
+int ZEXPORT inflateEnd (z_streamp strm)
+{
+    struct inflate_state FAR *state;
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->window != Z_NULL) ZFREE(strm, state->window);
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary (z_streamp strm, const Bytef *dictionary, uInt dictLength)
+{
+    struct inflate_state FAR *state;
+    unsigned long id_;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->wrap != 0 && state->mode != DICT)
+        return Z_STREAM_ERROR;
+
+    /* check for correct dictionary id */
+    if (state->mode == DICT) {
+        id_ = adler32(0L, Z_NULL, 0);
+        id_ = adler32(id_, dictionary, dictLength);
+        if (id_ != state->check)
+            return Z_DATA_ERROR;
+    }
+
+    /* copy dictionary to window */
+    if (updatewindow(strm, strm->avail_out)) {
+        state->mode = MEM;
+        return Z_MEM_ERROR;
+    }
+    if (dictLength > state->wsize) {
+        zmemcpy(state->window, dictionary + dictLength - state->wsize,
+                state->wsize);
+        state->whave = state->wsize;
+    }
+    else {
+        zmemcpy(state->window + state->wsize - dictLength, dictionary,
+                dictLength);
+        state->whave = dictLength;
+    }
+    state->havedict = 1;
+    Tracev((stderr, "inflate:   dictionary set\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader (z_streamp strm, gz_headerp head)
+{
+    struct inflate_state FAR *state;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+    /* save header structure */
+    state->head = head;
+    head->done = 0;
+    return Z_OK;
+}
+
+/*
+   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
+   or when out of input.  When called, *have is the number of pattern bytes
+   found in order so far, in 0..3.  On return *have is updated to the new
+   state.  If on return *have equals four, then the pattern was found and the
+   return value is how many bytes were read including the last byte of the
+   pattern.  If *have is less than four, then the pattern has not been found
+   yet and the return value is len.  In the latter case, syncsearch() can be
+   called again with more data and the *have state.  *have is initialized to
+   zero for the first call.
+ */
+local unsigned syncsearch (unsigned FAR *have, unsigned char FAR *buf, unsigned len)
+{
+    unsigned got;
+    unsigned next;
+
+    got = *have;
+    next = 0;
+    while (next < len && got < 4) {
+        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+            got++;
+        else if (buf[next])
+            got = 0;
+        else
+            got = 4 - got;
+        next++;
+    }
+    *have = got;
+    return next;
+}
+
+int ZEXPORT inflateSync (z_streamp strm)
+{
+    unsigned len;               /* number of bytes to look at or looked at */
+    unsigned long in, out;      /* temporary to save total_in and total_out */
+    unsigned char buf[4];       /* to restore bit buffer to byte string */
+    struct inflate_state FAR *state;
+
+    /* check parameters */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+    /* if first time, start search in bit buffer */
+    if (state->mode != SYNC) {
+        state->mode = SYNC;
+        state->hold <<= state->bits & 7;
+        state->bits -= state->bits & 7;
+        len = 0;
+        while (state->bits >= 8) {
+            buf[len++] = (unsigned char)(state->hold);
+            state->hold >>= 8;
+            state->bits -= 8;
+        }
+        state->have = 0;
+        syncsearch(&(state->have), buf, len);
+    }
+
+    /* search available input */
+    len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+    strm->avail_in -= len;
+    strm->next_in += len;
+    strm->total_in += len;
+
+    /* return no joy or set up to restart inflate() on a new block */
+    if (state->have != 4) return Z_DATA_ERROR;
+    in = strm->total_in;  out = strm->total_out;
+    inflateReset(strm);
+    strm->total_in = in;  strm->total_out = out;
+    state->mode = TYPE;
+    return Z_OK;
+}
+
+/*
+   Returns true if inflate is currently at the end of a block generated by
+   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+   implementation to provide an additional safety check. PPP uses
+   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+   block. When decompressing, PPP checks that at the end of input packet,
+   inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint (z_streamp strm)
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(z_streamp dest, z_streamp source)
+{
+    struct inflate_state FAR *state;
+    struct inflate_state FAR *copy;
+    unsigned char FAR *window;
+    unsigned wsize;
+
+    /* check input */
+    if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+        source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)source->state;
+
+    /* allocate space */
+    copy = (struct inflate_state FAR *)
+           ZALLOC(source, 1, sizeof(struct inflate_state));
+    if (copy == Z_NULL) return Z_MEM_ERROR;
+    window = Z_NULL;
+    if (state->window != Z_NULL) {
+        window = (unsigned char FAR *)
+                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+        if (window == Z_NULL) {
+            ZFREE(source, copy);
+            return Z_MEM_ERROR;
+        }
+    }
+
+    /* copy state */
+    zmemcpy(dest, source, sizeof(z_stream));
+    zmemcpy(copy, state, sizeof(struct inflate_state));
+    if (state->lencode >= state->codes &&
+        state->lencode <= state->codes + ENOUGH - 1) {
+        copy->lencode = copy->codes + (state->lencode - state->codes);
+        copy->distcode = copy->codes + (state->distcode - state->codes);
+    }
+    copy->next = copy->codes + (state->next - state->codes);
+    if (window != Z_NULL) {
+        wsize = 1U << state->wbits;
+        zmemcpy(window, state->window, wsize);
+    }
+    copy->window = window;
+    dest->state = (struct internal_state FAR *)copy;
+    return Z_OK;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inflate.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inflate.h
new file mode 100644
index 0000000..31b1279
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inflate.h
@@ -0,0 +1,121 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFLATE_H_
+#define _INFLATE_H_
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer decoding by inflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip decoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+    HEAD,       /* i: waiting for magic header */
+    FLAGS,      /* i: waiting for method and flags (gzip) */
+    TIME,       /* i: waiting for modification time (gzip) */
+    OS,         /* i: waiting for extra flags and operating system (gzip) */
+    EXLEN,      /* i: waiting for extra length (gzip) */
+    EXTRA,      /* i: waiting for extra bytes (gzip) */
+    NAME,       /* i: waiting for end of file name (gzip) */
+    COMMENT,    /* i: waiting for end of comment (gzip) */
+    HCRC,       /* i: waiting for header crc (gzip) */
+    DICTID,     /* i: waiting for dictionary check value */
+    DICT,       /* waiting for inflateSetDictionary() call */
+        TYPE,       /* i: waiting for type bits, including last-flag bit */
+        TYPEDO,     /* i: same, but skip check to exit inflate on new block */
+        STORED,     /* i: waiting for stored size (length and complement) */
+        COPY,       /* i/o: waiting for input or output to copy stored block */
+        TABLE,      /* i: waiting for dynamic block table lengths */
+        LENLENS,    /* i: waiting for code length code lengths */
+        CODELENS,   /* i: waiting for length/lit and distance code lengths */
+            LEN,        /* i: waiting for length/lit code */
+            LENEXT,     /* i: waiting for length extra bits */
+            DIST,       /* i: waiting for distance code */
+            DISTEXT,    /* i: waiting for distance extra bits */
+            MATCH,      /* o: waiting for output space to copy string */
+            LIT,        /* o: waiting for output space to write literal */
+    CHECK,      /* i: waiting for 32-bit check value */
+    LENGTH,     /* i: waiting for 32-bit length (gzip) */
+    DONE,       /* finished check, done -- remain here until reset */
+    BAD,        /* got a data error -- remain here until reset */
+    MEM,        /* got an inflate() memory error -- remain here until reset */
+    SYNC        /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+    State transitions between above modes -
+
+    (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+    Process header:
+        HEAD -> (gzip) or (zlib)
+        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+        NAME -> COMMENT -> HCRC -> TYPE
+        (zlib) -> DICTID or TYPE
+        DICTID -> DICT -> TYPE
+    Read deflate blocks:
+            TYPE -> STORED or TABLE or LEN or CHECK
+            STORED -> COPY -> TYPE
+            TABLE -> LENLENS -> CODELENS -> LEN
+    Read deflate codes:
+                LEN -> LENEXT or LIT or TYPE
+                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+                LIT -> LEN
+    Process trailer:
+        CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls.  Approximately 7K bytes. */
+struct inflate_state {
+    inflate_mode mode;          /* current inflate mode */
+    int last;                   /* true if processing last block */
+    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip */
+    int havedict;               /* true if dictionary provided */
+    int flags;                  /* gzip header method and flags (0 if zlib) */
+    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
+    unsigned long check;        /* protected copy of check value */
+    unsigned long total;        /* protected copy of output count */
+    gz_headerp head;            /* where to save gzip header information */
+        /* sliding window */
+    unsigned wbits;             /* log base 2 of requested window size */
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if needed */
+        /* bit accumulator */
+    unsigned long hold;         /* input bit accumulator */
+    unsigned bits;              /* number of bits in "in" */
+        /* for string and stored block copying */
+    unsigned length;            /* literal or length of data to copy */
+    unsigned offset;            /* distance back to copy string from */
+        /* for table and code decoding */
+    unsigned extra;             /* extra bits needed */
+        /* fixed and dynamic code tables */
+    code const FAR *lencode;    /* starting table for length/literal codes */
+    code const FAR *distcode;   /* starting table for distance codes */
+    unsigned lenbits;           /* index bits for lencode */
+    unsigned distbits;          /* index bits for distcode */
+        /* dynamic table building */
+    unsigned ncode;             /* number of code length code lengths */
+    unsigned nlen;              /* number of length code lengths */
+    unsigned ndist;             /* number of distance code lengths */
+    unsigned have;              /* number of code lengths in lens[] */
+    code FAR *next;             /* next available space in codes[] */
+    unsigned short lens[320];   /* temporary storage for code lengths */
+    unsigned short work[288];   /* work area for code table building */
+    code codes[ENOUGH];         /* space for code tables */
+};
+
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inftrees.c b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inftrees.c
new file mode 100644
index 0000000..dfc0aa7
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inftrees.c
@@ -0,0 +1,328 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+   " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/*
+   Build a set of tables to decode the provided canonical Huffman code.
+   The code lengths are lens[0..codes-1].  The result starts at *table,
+   whose indices are 0..2^bits-1.  work is a writable array of at least
+   lens shorts, which is used as a work area.  type is the type of code
+   to be generated, CODES, LENS, or DISTS.  On return, zero is success,
+   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table
+   on return points to the next available entry's address.  bits is the
+   requested root table index bits, and on return it is the actual root
+   table index bits.  It will differ if the request is greater than the
+   longest code or if it is less than the shortest code.
+ */
+int inflate_table (codetype type,
+                   unsigned short FAR *lens,
+                   unsigned codes,
+                   code FAR * FAR *table,
+                   unsigned FAR *bits,
+                   unsigned short FAR *work)
+{
+    unsigned len;               /* a code's length in bits */
+    unsigned sym;               /* index of code symbols */
+    unsigned min, max;          /* minimum and maximum code lengths */
+    unsigned root;              /* number of index bits for root table */
+    unsigned curr;              /* number of index bits for current table */
+    unsigned drop;              /* code bits to drop for sub-table */
+    int left;                   /* number of prefix codes available */
+    unsigned used;              /* code entries in table used */
+    unsigned huff;              /* Huffman code */
+    unsigned incr;              /* for incrementing code, index */
+    unsigned fill;              /* index for replicating entries */
+    unsigned low;               /* low bits for current root entry */
+    unsigned mask;              /* mask for low root bits */
+    code thisx;                  /* table entry for duplication */
+    code FAR *next;             /* next available space in table */
+    const unsigned short FAR *base;     /* base value table to use */
+    const unsigned short FAR *extra;    /* extra bits table to use */
+    int end;                    /* use base and extra for symbol > end */
+    unsigned short count[MAXBITS+1];    /* number of codes of each length */
+    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
+    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577, 0, 0};
+    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+        28, 28, 29, 29, 64, 64};
+
+    /*
+       Process a set of code lengths to create a canonical Huffman code.  The
+       code lengths are lens[0..codes-1].  Each length corresponds to the
+       symbols 0..codes-1.  The Huffman code is generated by first sorting the
+       symbols by length from short to long, and retaining the symbol order
+       for codes with equal lengths.  Then the code starts with all zero bits
+       for the first code of the shortest length, and the codes are integer
+       increments for the same length, and zeros are appended as the length
+       increases.  For the deflate format, these bits are stored backwards
+       from their more natural integer increment ordering, and so when the
+       decoding tables are built in the large loop below, the integer codes
+       are incremented backwards.
+
+       This routine assumes, but does not check, that all of the entries in
+       lens[] are in the range 0..MAXBITS.  The caller must assure this.
+       1..MAXBITS is interpreted as that code length.  zero means that that
+       symbol does not occur in this code.
+
+       The codes are sorted by computing a count of codes for each length,
+       creating from that a table of starting indices for each length in the
+       sorted table, and then entering the symbols in order in the sorted
+       table.  The sorted table is work[], with that space being provided by
+       the caller.
+
+       The length counts are used for other purposes as well, i.e. finding
+       the minimum and maximum length codes, determining if there are any
+       codes at all, checking for a valid set of lengths, and looking ahead
+       at length counts to determine sub-table sizes when building the
+       decoding tables.
+     */
+
+    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+    for (len = 0; len <= MAXBITS; len++)
+        count[len] = 0;
+    for (sym = 0; sym < codes; sym++)
+        count[lens[sym]]++;
+
+    /* bound code lengths, force root to be within code lengths */
+    root = *bits;
+    for (max = MAXBITS; max >= 1; max--)
+        if (count[max] != 0) break;
+    if (root > max) root = max;
+    if (max == 0) {                     /* no symbols to code at all */
+        thisx.op = (unsigned char)64;    /* invalid code marker */
+        thisx.bits = (unsigned char)1;
+        thisx.val = (unsigned short)0;
+        *(*table)++ = thisx;             /* make a table to force an error */
+        *(*table)++ = thisx;
+        *bits = 1;
+        return 0;     /* no symbols, but wait for decoding to report error */
+    }
+    for (min = 1; min <= MAXBITS; min++)
+        if (count[min] != 0) break;
+    if (root < min) root = min;
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;
+        left -= count[len];
+        if (left < 0) return -1;        /* over-subscribed */
+    }
+    if (left > 0 && (type == CODES || max != 1))
+        return -1;                      /* incomplete set */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + count[len];
+
+    /* sort symbols by length, by symbol order within each length */
+    for (sym = 0; sym < codes; sym++)
+        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+    /*
+       Create and fill in decoding tables.  In this loop, the table being
+       filled is at next and has curr index bits.  The code being used is huff
+       with length len.  That code is converted to an index by dropping drop
+       bits off of the bottom.  For codes where len is less than drop + curr,
+       those top drop + curr - len bits are incremented through all values to
+       fill the table with replicated entries.
+
+       root is the number of index bits for the root table.  When len exceeds
+       root, sub-tables are created pointed to by the root entry with an index
+       of the low root bits of huff.  This is saved in low to check for when a
+       new sub-table should be started.  drop is zero when the root table is
+       being filled, and drop is root when sub-tables are being filled.
+
+       When a new sub-table is needed, it is necessary to look ahead in the
+       code lengths to determine what size sub-table is needed.  The length
+       counts are used for this, and so count[] is decremented as codes are
+       entered in the tables.
+
+       used keeps track of how many table entries have been allocated from the
+       provided *table space.  It is checked when a LENS table is being made
+       against the space in *table, ENOUGH, minus the maximum space needed by
+       the worst case distance code, MAXD.  This should never happen, but the
+       sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+       This assumes that when type == LENS, bits == 9.
+
+       sym increments through all symbols, and the loop terminates when
+       all codes of length max, i.e. all codes, have been processed.  This
+       routine permits incomplete codes, so another loop after this one fills
+       in the rest of the decoding tables with invalid code markers.
+     */
+
+    /* set up for code type */
+    switch (type) {
+    case CODES:
+        base = extra = work;    /* dummy value--not used */
+        end = 19;
+        break;
+    case LENS:
+        base = lbase;
+        base -= 257;
+        extra = lext;
+        extra -= 257;
+        end = 256;
+        break;
+    default:            /* DISTS */
+        base = dbase;
+        extra = dext;
+        end = -1;
+    }
+
+    /* initialize state for loop */
+    huff = 0;                   /* starting code */
+    sym = 0;                    /* starting code symbol */
+    len = min;                  /* starting code length */
+    next = *table;              /* current table to fill in */
+    curr = root;                /* current table index bits */
+    drop = 0;                   /* current bits to drop from code for index */
+    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
+    used = 1U << root;          /* use root table entries */
+    mask = used - 1;            /* mask for comparing low */
+
+    /* check available table space */
+    if (type == LENS && used >= ENOUGH - MAXD)
+        return 1;
+
+    /* process all codes and make table entries */
+    for (;;) {
+        /* create table entry */
+        thisx.bits = (unsigned char)(len - drop);
+        if ((int)(work[sym]) < end) {
+            thisx.op = (unsigned char)0;
+            thisx.val = work[sym];
+        }
+        else if ((int)(work[sym]) > end) {
+            thisx.op = (unsigned char)(extra[work[sym]]);
+            thisx.val = base[work[sym]];
+        }
+        else {
+            thisx.op = (unsigned char)(32 + 64);         /* end of block */
+            thisx.val = 0;
+        }
+
+        /* replicate for those indices with low len bits equal to huff */
+        incr = 1U << (len - drop);
+        fill = 1U << curr;
+        min = fill;                 /* save offset to next table */
+        do {
+            fill -= incr;
+            next[(huff >> drop) + fill] = thisx;
+        } while (fill != 0);
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+
+        /* go to next symbol, update count, len */
+        sym++;
+        if (--(count[len]) == 0) {
+            if (len == max) break;
+            len = lens[work[sym]];
+        }
+
+        /* create new sub-table if needed */
+        if (len > root && (huff & mask) != low) {
+            /* if first time, transition to sub-tables */
+            if (drop == 0)
+                drop = root;
+
+            /* increment past last table */
+            next += min;            /* here min is 1 << curr */
+
+            /* determine length of next table */
+            curr = len - drop;
+            left = (int)(1 << curr);
+            while (curr + drop < max) {
+                left -= count[curr + drop];
+                if (left <= 0) break;
+                curr++;
+                left <<= 1;
+            }
+
+            /* check for enough space */
+            used += 1U << curr;
+            if (type == LENS && used >= ENOUGH - MAXD)
+                return 1;
+
+            /* point entry in root table to sub-table */
+            low = huff & mask;
+            (*table)[low].op = (unsigned char)curr;
+            (*table)[low].bits = (unsigned char)root;
+            (*table)[low].val = (unsigned short)(next - *table);
+        }
+    }
+
+    /*
+       Fill in rest of table for incomplete codes.  This loop is similar to the
+       loop above in incrementing huff for table indices.  It is assumed that
+       len is equal to curr + drop, so there is no loop needed to increment
+       through high index bits.  When the current sub-table is filled, the loop
+       drops back to the root table to fill in any remaining entries there.
+     */
+    thisx.op = (unsigned char)64;                /* invalid code marker */
+    thisx.bits = (unsigned char)(len - drop);
+    thisx.val = (unsigned short)0;
+    while (huff != 0) {
+        /* when done with sub-table, drop back to root table */
+        if (drop != 0 && (huff & mask) != low) {
+            drop = 0;
+            len = root;
+            next = *table;
+            thisx.bits = (unsigned char)len;
+        }
+
+        /* put invalid code marker in table */
+        next[huff >> drop] = thisx;
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+    }
+
+    /* set return parameters */
+    *table += used;
+    *bits = root;
+    return 0;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inftrees.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inftrees.h
new file mode 100644
index 0000000..ea64af0
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/inftrees.h
@@ -0,0 +1,61 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFTREES_H_
+#define _INFTREES_H_
+
+/* Structure for decoding tables.  Each entry provides either the
+   information needed to do the operation requested by the code that
+   indexed that table entry, or it provides a pointer to another
+   table that indexes more bits of the code.  op indicates whether
+   the entry is a pointer to another table, a literal, a length or
+   distance, an end-of-block, or an invalid code.  For a table
+   pointer, the low four bits of op is the number of index bits of
+   that table.  For a length or distance, the low four bits of op
+   is the number of extra bits to get after the code.  bits is
+   the number of bits in this code or part of the code to drop off
+   of the bit buffer.  val is the actual byte to output in the case
+   of a literal, the base length or distance, or the offset from
+   the current table to the next table.  Each entry is four bytes. */
+typedef struct {
+    unsigned char op;           /* operation, extra bits, table bits */
+    unsigned char bits;         /* bits in this part of the code */
+    unsigned short val;         /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+    00000000 - literal
+    0000tttt - table link, tttt != 0 is the number of table index bits
+    0001eeee - length or distance, eeee is the number of extra bits
+    01100000 - end of block
+    01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1444 code structures (852 for length/literals
+   and 592 for distances, the latter actually the result of an
+   exhaustive search).  The true maximum is not known, but the value
+   below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+    CODES,
+    LENS,
+    DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+                             unsigned codes, code FAR * FAR *table,
+                             unsigned FAR *bits, unsigned short FAR *work));
+
+
+#endif
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/trees.c b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/trees.c
new file mode 100644
index 0000000..36a124d
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/trees.c
@@ -0,0 +1,1191 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2005 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id: trees.c,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN  512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+#  include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local void set_data_type  OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits (deflate_state *s, int value, int length)
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += (int) (length - Buf_size);
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* For some embedded targets, global variables are not initialized: */
+    static_l_desc.static_tree = static_ltree;
+    static_l_desc.extra_bits = extra_lbits;
+    static_d_desc.static_tree = static_dtree;
+    static_d_desc.extra_bits = extra_dbits;
+    static_bl_desc.extra_bits = extra_blbits;
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            _length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    _length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            _dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            _dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+
+#  ifdef GEN_TREES_H
+    gen_trees_header();
+#  endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+#  ifndef DEBUG
+#    include <stdio.h>
+#  endif
+
+#  define SEPARATOR(i, last, width) \
+      ((i) == (last)? "\n};\n\n" :    \
+       ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+    FILE *header = fopen("trees.h", "w");
+    int i;
+
+    Assert (header != NULL, "Can't open trees.h");
+    fprintf(header,
+            "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+    fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+    for (i = 0; i < L_CODES+2; i++) {
+        fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+    }
+
+    fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+    }
+
+    fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+    for (i = 0; i < DIST_CODE_LEN; i++) {
+        fprintf(header, "%2u%s", _dist_code[i],
+                SEPARATOR(i, DIST_CODE_LEN-1, 20));
+    }
+
+    fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+        fprintf(header, "%2u%s", _length_code[i],
+                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+    }
+
+    fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+    for (i = 0; i < LENGTH_CODES; i++) {
+        fprintf(header, "%1u%s", base_length[i],
+                SEPARATOR(i, LENGTH_CODES-1, 20));
+    }
+
+    fprintf(header, "local const int base_dist[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "%5u%s", base_dist[i],
+                SEPARATOR(i, D_CODES-1, 10));
+    }
+
+    fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(deflate_state *s)
+{
+    tr_static_init();
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+    s->compressed_len = 0L;
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block (deflate_state *s)
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap (deflate_state *s,
+                       ct_data *tree,  /* the tree to restore */
+                       int k)               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen (deflate_state *s, tree_desc *desc)
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if ((unsigned) tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (ct_data *tree,             /* the tree to decorate */
+                      int max_code,              /* largest code with non zero frequency */
+                      ushf *bl_count)            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree (deflate_state *s,
+                       tree_desc *desc) /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+                                s->depth[n] : s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (deflate_state *s,
+                      ct_data *tree,   /* the tree to be scanned */
+                      int max_code)    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (deflate_state *s,
+                      ct_data *tree, /* the tree to be scanned */
+                      int max_code)       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree (deflate_state *s)
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees (deflate_state *s,
+                           int lcodes, int dcodes, int blcodes) /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block (deflate_state *s, charf *buf, ulg stored_len, int eof)
+{
+    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
+#ifdef DEBUG
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+#endif
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align (deflate_state *s)
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+        s->compressed_len += 10L;
+#endif
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block (deflate_state *s,
+                      charf *buf,       /* input block, or NULL if too old */
+                      ulg stored_len,   /* length of input block */
+                      int eof)          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+        /* Check if the file is binary or text */
+        if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN)
+            set_data_type(s);
+
+        /* Construct the literal and distance trees */
+        build_tree(s, (tree_desc *)(&(s->l_desc)));
+        Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+
+        build_tree(s, (tree_desc *)(&(s->d_desc)));
+        Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+        /* At this point, opt_len and static_len are the total bit lengths of
+         * the compressed block data, excluding the tree representations.
+         */
+
+        /* Build the bit length tree for the above two trees, and get the index
+         * in bl_order of the last bit length code to send.
+         */
+        max_blindex = build_bl_tree(s);
+
+        /* Determine the best encoding. Compute the block lengths in bytes. */
+        opt_lenb = (s->opt_len+3+7)>>3;
+        static_lenb = (s->static_len+3+7)>>3;
+
+        Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+                s->last_lit));
+
+        if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->static_len;
+#endif
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->opt_len;
+#endif
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    /* The above check is made mod 2^32, for files larger than 512 MB
+     * and uLong implemented on 32 bits.
+     */
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+#ifdef DEBUG
+        s->compressed_len += 7;  /* align on byte boundary */
+#endif
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (deflate_state *s,
+               unsigned dist,  /* distance of matched string */
+               unsigned lc)    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+#ifdef TRUNCATE_BLOCK
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+#endif
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block (deflate_state *s,
+                           ct_data *ltree, /* literal tree */
+                           ct_data *dtree) /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = _length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+               "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to BINARY or TEXT, using a crude approximation:
+ * set it to Z_TEXT if all symbols are either printable characters (33 to 255)
+ * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise.
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local void set_data_type (deflate_state *s)
+{
+    int n;
+
+    for (n = 0; n < 9; n++)
+        if (s->dyn_ltree[n].Freq != 0)
+            break;
+    if (n == 9)
+        for (n = 14; n < 32; n++)
+            if (s->dyn_ltree[n].Freq != 0)
+                break;
+    s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse (unsigned code, int len)
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush (deflate_state *s)
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup (deflate_state *s)
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(deflate_state *s,
+                      charf    *buf,    /* the input data */
+                      unsigned len,     /* its length */
+                      int      header)  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);
+        put_short(s, (ush)~len);
+#ifdef DEBUG
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG
+    s->bits_sent += (ulg)len<<3;
+#endif
+    while (len--) {
+        put_byte(s, *buf++);
+    }
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/trees.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/trees.h
new file mode 100644
index 0000000..5ac45a7
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/trees.h
@@ -0,0 +1,127 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},
+{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},
+{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},
+{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},
+{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},
+{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},
+{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},
+{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},
+{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},
+{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},
+{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},
+{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},
+{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},
+{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},
+{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},
+{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},
+{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},
+{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},
+{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},
+{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},
+{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},
+{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},
+{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},
+{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},
+{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},
+{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},
+{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},
+{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},
+{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},
+{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},
+{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},
+{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},
+{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},
+{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},
+{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},
+{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},
+{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},
+{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},
+{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},
+{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},
+{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},
+{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},
+{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},
+{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},
+{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},
+{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},
+{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},
+{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},
+{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},
+{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},
+{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},
+{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},
+{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},
+{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},
+{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},
+{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},
+{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},
+{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+ 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
+   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
+ 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+};
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/uncompr.c b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/uncompr.c
new file mode 100644
index 0000000..839602f
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/uncompr.c
@@ -0,0 +1,60 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: uncompr.c,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (Bytef *dest,
+                        uLongf *destLen,
+                        const Bytef *source,
+                        uLong sourceLen)
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+
+    err = inflateInit(&stream);
+    if (err != Z_OK) return err;
+
+    err = inflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        inflateEnd(&stream);
+        if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+            return Z_DATA_ERROR;
+        return err;
+    }
+    *destLen = stream.total_out;
+
+    err = inflateEnd(&stream);
+    return err;
+}
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zconf.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zconf.h
new file mode 100644
index 0000000..f1e9e87
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zconf.h
@@ -0,0 +1,345 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zconf.h,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+// *** Just a few hacks here to make it compile nicely with Juce..
+#define Z_PREFIX 1
+#undef __MACTYPES__
+
+#ifdef _MSC_VER
+  #pragma warning (disable : 4131 4127 4244 4267)
+#endif
+
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_          z_deflateInit_
+#  define deflate               z_deflate
+#  define deflateEnd            z_deflateEnd
+#  define inflateInit_          z_inflateInit_
+#  define inflate               z_inflate
+#  define inflateEnd            z_inflateEnd
+#  define inflatePrime          z_inflatePrime
+#  define inflateGetHeader      z_inflateGetHeader
+#  define adler32_combine       z_adler32_combine
+#  define crc32_combine         z_crc32_combine
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateCopy           z_deflateCopy
+#  define deflateReset          z_deflateReset
+#  define deflateParams         z_deflateParams
+#  define deflateBound          z_deflateBound
+#  define deflatePrime          z_deflatePrime
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateCopy           z_inflateCopy
+#  define inflateReset          z_inflateReset
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define compress              z_compress
+#  define compress2             z_compress2
+#  define compressBound         z_compressBound
+#  define uncompress            z_uncompress
+#  define adler32               z_adler32
+#  define crc32                 z_crc32
+#  define get_crc_table         z_get_crc_table
+#  define zError                z_zError
+
+#  define alloc_func            z_alloc_func
+#  define free_func             z_free_func
+#  define in_func               z_in_func
+#  define out_func              z_out_func
+#  define Byte                  z_Byte
+#  define uInt                  z_uInt
+#  define uLong                 z_uLong
+#  define Bytef                 z_Bytef
+#  define charf                 z_charf
+#  define intf                  z_intf
+#  define uIntf                 z_uIntf
+#  define uLongf                z_uLongf
+#  define voidpf                z_voidpf
+#  define voidp                 z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if 0           /* HAVE_UNISTD_H -- this line is updated by ./configure */
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  ifdef VMS
+#    include <unixio.h>   /* for off_t */
+#  endif
+#  define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if defined(__OS400__)
+#  define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+#  define NO_vsnprintf
+#  ifdef FAR
+#    undef FAR
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#   pragma map(deflateInit_,"DEIN")
+#   pragma map(deflateInit2_,"DEIN2")
+#   pragma map(deflateEnd,"DEEND")
+#   pragma map(deflateBound,"DEBND")
+#   pragma map(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(compressBound,"CMBND")
+#   pragma map(inflate_table,"INTABL")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zconf.in.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zconf.in.h
new file mode 100644
index 0000000..018173a
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zconf.in.h
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zconf.in.h,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_          z_deflateInit_
+#  define deflate               z_deflate
+#  define deflateEnd            z_deflateEnd
+#  define inflateInit_          z_inflateInit_
+#  define inflate               z_inflate
+#  define inflateEnd            z_inflateEnd
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateCopy           z_deflateCopy
+#  define deflateReset          z_deflateReset
+#  define deflateParams         z_deflateParams
+#  define deflateBound          z_deflateBound
+#  define deflatePrime          z_deflatePrime
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateCopy           z_inflateCopy
+#  define inflateReset          z_inflateReset
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define compress              z_compress
+#  define compress2             z_compress2
+#  define compressBound         z_compressBound
+#  define uncompress            z_uncompress
+#  define adler32               z_adler32
+#  define crc32                 z_crc32
+#  define get_crc_table         z_get_crc_table
+#  define zError                z_zError
+
+#  define alloc_func            z_alloc_func
+#  define free_func             z_free_func
+#  define in_func               z_in_func
+#  define out_func              z_out_func
+#  define Byte                  z_Byte
+#  define uInt                  z_uInt
+#  define uLong                 z_uLong
+#  define Bytef                 z_Bytef
+#  define charf                 z_charf
+#  define intf                  z_intf
+#  define uIntf                 z_uIntf
+#  define uLongf                z_uLongf
+#  define voidpf                z_voidpf
+#  define voidp                 z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if 0           /* HAVE_UNISTD_H -- this line is updated by ./configure */
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  ifdef VMS
+#    include <unixio.h>   /* for off_t */
+#  endif
+#  define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if defined(__OS400__)
+#  define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+#  define NO_vsnprintf
+#  ifdef FAR
+#    undef FAR
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#   pragma map(deflateInit_,"DEIN")
+#   pragma map(deflateInit2_,"DEIN2")
+#   pragma map(deflateEnd,"DEEND")
+#   pragma map(deflateBound,"DEBND")
+#   pragma map(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(compressBound,"CMBND")
+#   pragma map(inflate_table,"INTABL")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zlib.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zlib.h
new file mode 100644
index 0000000..bdf8af7
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zlib.h
@@ -0,0 +1,1358 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.3, July 18th, 2005
+
+  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors 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 software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     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 software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup at gzip.org          madler at alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+//extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+
+/*
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+     This library can optionally read and write gzip streams in memory as well.
+
+     The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+//ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumualte before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  the value returned by deflateBound (see below). If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+  Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+  if and when it gets to the next deflate block boundary. When decoding the
+  zlib or gzip format, this will cause inflate() to return immediately after
+  the header and before the first block. When doing a raw inflate, inflate()
+  will go ahead and process the first block, and will return when it gets to
+  the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64
+  if inflate() is currently decoding the last block in the deflate stream,
+  plus 128 if inflate() returned immediately after decoding an end-of-block
+  code or decoding the complete header up to just before the first byte of the
+  deflate stream. The end-of-block will not be indicated until all of the
+  uncompressed data from that block has been written to strm->next_out.  The
+  number of unused bits may in general be greater than seven, except when
+  bit 7 of data_type is set, in which case the number of unused bits will be
+  less than eight.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster approach
+  may be used for the single inflate() call.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call. So the only effect of the flush parameter in this implementation
+  is on the return value of inflate(), as noted below, or when it returns early
+  because Z_BLOCK is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the adler32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the adler32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below. At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically.  Any information
+  contained in the gzip header is not retained, so applications that need that
+  information should instead use raw inflate, see inflateInit2() below, or
+  inflateBack() and perform their own processing of the gzip header and
+  trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing. If Z_DATA_ERROR is returned, the application may then
+  call inflateSync() to look for a good compression block if a partial recovery
+  of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer). It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+   determines the window size. deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding. Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper. The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero),
+   no header crc, and the operating system will be set to 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding). Filtered data consists mostly of small values with a somewhat
+   random distribution. In this case, the compression algorithm is tuned to
+   compress them better. The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+   Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+   parameter only affects the compression ratio but not the correctness of the
+   compressed output even if it is not set appropriately.  Z_FIXED prevents the
+   use of dynamic Huffman codes, allowing for a simpler decoder for special
+   applications.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front. In addition, the
+   current implementation of deflate will use at most the window size minus
+   262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit()
+   or deflateInit2().  This would be used to allocate an output buffer
+   for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+  is that this function is used to start off the deflate output with the
+  bits leftover from a previous deflate stream when appending to it.  As such,
+  this function can only be used for raw deflate, and must be used before the
+  first deflate() call after a deflateInit2() or deflateReset().  bits must be
+  less than or equal to 16, and that many of the least significant bits of
+  value will be inserted in the output.
+
+      deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+      If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+      deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used. If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+   determines the window size. inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream. This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values. If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is. Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding. Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is
+   a crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+   is set to null if there is no error message.  inflateInit2 does not perform
+   any decompression apart from reading the zlib header if present: this will
+   be done by inflate(). (So next_in and avail_in may be modified, but next_out
+   and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called
+   immediately after inflateInit2() or inflateReset() and before any call of
+   inflate() to set the dictionary.  The application must insure that the
+   dictionary that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+  that this function is used to start inflating at a bit position in the
+  middle of a byte.  The provided bits will be used before any bytes are used
+  from next_in.  This function should only be used with raw inflate, and
+  should be used before the first inflate() call after inflateInit2() or
+  inflateReset().  bits must be less than or equal to 16, and that many of the
+  least significant bits of value will be inserted in the input.
+
+      inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK can be used to
+   force inflate() to return immediately after header processing is complete
+   and before any actual data is decompressed.
+
+      The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.)  If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When
+   any of extra, name, or comment are not Z_NULL and the respective field is
+   not present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+      If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+      inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+   be allocated, or Z_VERSION_ERROR if the version of the library does not
+   match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is more efficient than inflate() for
+   file i/o applications in that it avoids copying between the output and the
+   sliding window by simply making the window itself the output buffer.  This
+   function trusts the application to not change the output buffer passed by
+   the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free
+   the allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects
+   only the raw deflate stream to decompress.  This is different from the
+   normal behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format
+   error in the deflate stream (in which case strm->msg is set to indicate the
+   nature of the error), or Z_STREAM_ERROR if the stream was not properly
+   initialized.  In the case of Z_BUF_ERROR, an input or output error can be
+   distinguished using strm->next_in which will be Z_NULL only if in() returned
+   an error.  If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+   out() returning non-zero.  (in() will always be called before out(), so
+   strm->next_in is assured to be defined if out() returns non-zero.)  Note
+   that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+//ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level and memory usage,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least the value returned
+   by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before
+   a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen  OF((const char *path, const char *mode));
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+   Huffman only compression as in "wb1h", or 'R' for run-length encoding
+   as in "wb1R". (See the description of deflateInit2 for more information
+   about the strategy parameter.)
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+ZEXTERN gzFile ZEXPORT gzdopen  OF((int fd, const char *mode));
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy. See the description
+   of deflateInit2 for the meaning of these parameters.
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT    gzwrite OF((gzFile file,
+                                   voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).  The number of
+   uncompressed bytes written is limited to 4095. The caller should assure that
+   this limit is not exceeded. If it is exceeded, then gzprintf() will return
+   return an error (0) with nothing written. In this case, there may also be a
+   buffer overflow with unpredictable consequences, which is possible only if
+   zlib was compiled with the insecure functions sprintf() or vsprintf()
+   because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+      Reads bytes from the compressed file until len-1 characters are read, or
+   a newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzputc OF((gzFile file, int c));
+/*
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzgetc OF((gzFile file));
+/*
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT    gzungetc OF((int c, gzFile file));
+/*
+      Push one character back onto the stream to be read again later.
+   Only one character of push-back is allowed.  gzungetc() returns the
+   character pushed, or -1 on failure.  gzungetc() will fail if a
+   character has been pushed but not read yet, or if c is -1. The pushed
+   character will be discarded if the stream is repositioned with gzseek()
+   or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT    gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT    gzseek OF((gzFile file,
+                                      z_off_t offset, int whence));
+/*
+      Sets the starting position for the next gzread or gzwrite on the
+   given compressed file. The offset represents a number of bytes in the
+   uncompressed data stream. The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow. If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+/*
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns 1 if file is being read directly without decompression, otherwise
+   zero.
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file. This is analogous to the
+   clearerr() function in stdio. This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+/*
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32. If buf is NULL, this function returns the required initial
+   value for the for the crc. Pre- and post-conditioning (one's complement) is
+   performed within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+        inflateBackInit_((strm), (windowBits), (window), \
+        ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+
+#ifdef __cplusplus
+//}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zutil.c b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zutil.c
new file mode 100644
index 0000000..630305c
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zutil.c
@@ -0,0 +1,311 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zutil.c,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state      {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary",     /* Z_NEED_DICT       2  */
+"stream end",          /* Z_STREAM_END      1  */
+"",                    /* Z_OK              0  */
+"file error",          /* Z_ERRNO         (-1) */
+"stream error",        /* Z_STREAM_ERROR  (-2) */
+"data error",          /* Z_DATA_ERROR    (-3) */
+"insufficient memory", /* Z_MEM_ERROR     (-4) */
+"buffer error",        /* Z_BUF_ERROR     (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+/*const char * ZEXPORT zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+    uLong flags;
+
+    flags = 0;
+    switch (sizeof(uInt)) {
+    case 2:     break;
+    case 4:     flags += 1;     break;
+    case 8:     flags += 2;     break;
+    default:    flags += 3;
+    }
+    switch (sizeof(uLong)) {
+    case 2:     break;
+    case 4:     flags += 1 << 2;        break;
+    case 8:     flags += 2 << 2;        break;
+    default:    flags += 3 << 2;
+    }
+    switch (sizeof(voidpf)) {
+    case 2:     break;
+    case 4:     flags += 1 << 4;        break;
+    case 8:     flags += 2 << 4;        break;
+    default:    flags += 3 << 4;
+    }
+    switch (sizeof(z_off_t)) {
+    case 2:     break;
+    case 4:     flags += 1 << 6;        break;
+    case 8:     flags += 2 << 6;        break;
+    default:    flags += 3 << 6;
+    }
+#ifdef DEBUG
+    flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+    flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+    flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+    flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+    flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+    flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+    flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+    flags += 1L << 20;
+#endif
+#ifdef FASTEST
+    flags += 1L << 21;
+#endif
+#ifdef STDC
+#  ifdef NO_vsnprintf
+        flags += 1L << 25;
+#    ifdef HAS_vsprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_vsnprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#else
+        flags += 1L << 24;
+#  ifdef NO_snprintf
+        flags += 1L << 25;
+#    ifdef HAS_sprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_snprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#endif
+    return flags;
+}*/
+
+#if 0
+
+#  ifndef verbose
+#    define verbose 0
+#  endif
+int z_verbose = verbose;
+
+void z_error (const char *m)
+{
+    fprintf(stderr, "%s\n", m);
+    exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(int err)
+{
+    return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+    /* The Microsoft C Run-Time Library for Windows CE doesn't have
+     * errno.  We define it as a global variable to simplify porting.
+     * Its value is always 0 and should not be used.
+     */
+    int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+    Bytef* dest;
+    const Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+    const Bytef* s1;
+    const Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf = opaque; /* just to make some compilers happy */
+    ulg bsize = (ulg)items*size;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  malloc OF((uInt size));
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+                              (voidpf)calloc(items, size);
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zutil.h b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zutil.h
new file mode 100644
index 0000000..3939858
--- /dev/null
+++ b/src/htio2/JUCE-3.0.8/modules/juce_core/zip/zlib/zutil.h
@@ -0,0 +1,271 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: zutil.h,v 1.1 2007/06/07 17:54:37 jules_rms Exp $ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+#  ifndef _WIN32_WCE
+#    include <stddef.h>
+#  endif
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+#   ifdef _WIN32_WCE
+      /* The Microsoft C Run-Time Library for Windows CE doesn't have
+       * errno.  We define it as a global variable to simplify porting.
+       * Its value is always 0 and should not be used.  We rename it to
+       * avoid conflict with other libraries that use the same workaround.
+       */
+#     define errno z_errno
+#   endif
+    extern int errno;
+#else
+#  ifndef _WIN32_WCE
+#    include <errno.h>
+#  endif
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+#  define OS_CODE  0x00
+#  if defined(__TURBOC__) || defined(__BORLANDC__)
+#    if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+       /* Allow compilation with ANSI keywords only enabled */
+       void _Cdecl farfree( void *block );
+       void *_Cdecl farmalloc( unsigned long nbytes );
+#    else
+#      include <alloc.h>
+#    endif
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define F_OPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#  ifdef M_I86
+     #include <malloc.h>
+#  endif
+#endif
+
+#if defined(MACOS) || TARGET_OS_MAC
+#  define OS_CODE  0x07
+#  if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#    include <unix.h> /* for fdopen */
+#  else
+#    ifndef fdopen
+#      define fdopen(fd,mode) NULL /* No fdopen() */
+#    endif
+#  endif
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#ifdef WIN32
+#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
+#    define OS_CODE  0x0b
+#  endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+#  if defined(_WIN32_WCE)
+#    define fdopen(fd,mode) NULL /* No fdopen() */
+#    ifndef _PTRDIFF_T_DEFINED
+       typedef int ptrdiff_t;
+#      define _PTRDIFF_T_DEFINED
+#    endif
+#  else
+#    define fdopen(fd,type)  _fdopen(fd,type)
+#  endif
+#endif
+
+        /* common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+#if defined(__CYGWIN__)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+#ifndef HAVE_VSNPRINTF
+#  ifdef MSDOS
+     /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+        but for now we just assume it doesn't. */
+#    define NO_vsnprintf
+#  endif
+#  ifdef __TURBOC__
+#    define NO_vsnprintf
+#  endif
+#  ifdef WIN32
+     /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+#    if !defined(vsnprintf) && !defined(NO_vsnprintf)
+#      define vsnprintf _vsnprintf
+#    endif
+#  endif
+#  ifdef __SASC
+#    define NO_vsnprintf
+#  endif
+#endif
+#ifdef VMS
+#  define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+#  define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  * The __SC__ check is for Symantec.
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   extern void zmemcpy  OF((Bytef* dest, const Bytef* source, uInt len));
+   extern int  zmemcmp  OF((const Bytef* s1, const Bytef* s2, uInt len));
+   extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#if 0
+#  include <stdio.h>
+   extern int z_verbose;
+   extern void z_error    OF((const char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
+#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
+#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#  define z_error(x)
+#  define z_verbose 0
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void   zcfree  OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */
diff --git a/src/htio2/Kmer.cpp b/src/htio2/Kmer.cpp
new file mode 100644
index 0000000..70ace8b
--- /dev/null
+++ b/src/htio2/Kmer.cpp
@@ -0,0 +1,436 @@
+#include "htio2/Kmer.h"
+#include "htio2/Error.h"
+
+#include <cmath>
+
+#include <cstdio>
+#include <limits>
+
+using namespace std;
+
+namespace htio2
+{
+
+void encode_nt5(const std::string& seq, EncodedSeq& encoded_seq)
+{
+    const size_t len = seq.length();
+    encoded_seq.resize(len);
+
+    for (size_t i = 0; i < len; i++)
+    {
+        EncodedType curr = encode_nt5(seq[i]);
+        encoded_seq[i] = curr;
+    }
+}
+
+void encode_nt4(const string &seq, EncodedSeq &encoded_seq)
+{
+    const size_t len = seq.length();
+    encoded_seq.resize(len);
+
+    for (size_t i = 0; i < len; i++)
+    {
+        EncodedType curr = encode_nt4(seq[i]);
+        encoded_seq[i] = curr;
+    }
+}
+
+void encode_aa(const std::string& seq, EncodedSeq& encoded_seq)
+{
+    const size_t len = seq.length();
+    encoded_seq.resize(len);
+
+    for (size_t i = 0; i < len; i++)
+    {
+        EncodedType curr = encode_aa(seq[i]);
+        encoded_seq[i] = curr;
+    }
+}
+
+void decode_nt5(const EncodedSeq& encoded_seq, std::string& seq)
+{
+    const size_t len = encoded_seq.size();
+    seq.resize(len);
+
+    for (size_t i = 0; i < len; i++)
+    {
+        char curr = decode_nt5(encoded_seq[i]);
+        seq[i] = curr;
+    }
+}
+
+void decode_nt4(const EncodedSeq &encoded_seq, string &seq)
+{
+    const size_t len = encoded_seq.size();
+    seq.resize(len);
+
+    for (size_t i = 0; i < len; i++)
+    {
+        char curr = decode_nt4(encoded_seq[i]);
+        seq[i] = curr;
+    }
+}
+
+void decode_aa(const EncodedSeq& encoded_seq, std::string& seq)
+{
+    const size_t len = encoded_seq.size();
+    seq.resize(len);
+
+    for (size_t i = 0; i < len; i++)
+    {
+        char curr = decode_aa(encoded_seq[i]);
+        seq[i] = curr;
+    }
+}
+
+template <EncodedType nary>
+inline void _revcom_(const EncodedSeq& in, EncodedSeq& out)
+{
+    const size_t len = in.size();
+    out.resize(len);
+    for (size_t i = 0; i < len; i++)
+    {
+        const EncodedType curr = in[i];
+        size_t i_out = len - i - 1;
+        if (curr == ENCODED_ERROR)
+            out[i_out] = ENCODED_ERROR;
+        else
+            out[i_out] = nary - curr;
+    }
+}
+
+void revcom_nt5(const EncodedSeq& in, EncodedSeq& out)
+{
+    _revcom_<5>(in, out);
+}
+
+void revcom_nt4(const EncodedSeq& in, EncodedSeq& out)
+{
+    _revcom_<4>(in, out);
+}
+
+bool operator==(const EncodedSeq& a, const EncodedSeq& b)
+{
+    const size_t len = a.size();
+    if (len == b.size())
+        return false;
+
+    for (size_t i = 0; i < len; i++)
+    {
+        if (a[i] != b[i]) return false;
+    }
+
+    return true;
+}
+
+template <typename kmer_type, int nary>
+inline bool gen_kmer_impl(const EncodedSeq& encoded_seq, vector<kmer_type>& result, size_t kmer_size)
+{
+    if (kmer_size > KmerTrait<nary, kmer_type>::max_size())
+        return false;
+
+    size_t len = encoded_seq.size();
+    if (len < kmer_size)
+        return false;
+
+    const size_t num_kmer = len - kmer_size + 1;
+    result.resize(num_kmer);
+
+    const size_t digit_base = std::pow(nary, kmer_size-1);
+    size_t i_begin = 0;
+    const size_t i_end = num_kmer;
+
+    for (;;)
+    {
+        if (i_begin >= i_end) break;
+
+        // build the first kmer
+        bool init_got_unusable = false;
+        size_t kmer = 0;
+
+        for (size_t k = 0; k < kmer_size; ++k)
+        {
+            size_t i = i_begin + k;
+            EncodedType curr = encoded_seq[i];
+
+            if (curr != ENCODED_ERROR)
+                kmer += curr * std::pow(nary, k);
+            else
+            {
+                // mark affected position as error
+                for (size_t i_error = i_begin;
+                     i_error <= i && i_error < i_end;
+                     ++i_error)
+                {
+                    result[i_error] = numeric_limits<kmer_type>::max();
+                }
+
+                // skip to the base next to unusable
+                i_begin += k + 1;
+                init_got_unusable = true;
+                break;
+            }
+        }
+
+        // if got unusable, build first kmer again again
+        if (init_got_unusable)
+            continue;
+
+        result[i_begin] = kmer;
+
+        // elongate kmer
+        // each time, read one base, and remove previoius base
+        bool elong_got_error = false;
+        for (size_t i = i_begin + 1; i < i_end; ++i)
+        {
+            size_t i_kmer_tail = i + kmer_size - 1;
+            EncodedType prev_enc = encoded_seq[i - 1];
+            EncodedType tail_enc = encoded_seq[i_kmer_tail];
+
+            if (tail_enc != ENCODED_ERROR)
+            {
+                kmer -= prev_enc;
+                kmer /= nary;
+                kmer += tail_enc * digit_base;
+                result[i] = kmer;
+            }
+            else
+            {
+                // mark affected position as error
+                for (size_t i_error = i;
+                     i_error <= i_kmer_tail && i_error < i_end;
+                     ++i_error)
+                {
+                    result[i_error] = numeric_limits<kmer_type>::max();
+                }
+
+                // skip to the base next to unusable
+                i_begin = i_kmer_tail + 1;
+                elong_got_error = true;
+                break;
+            }
+        }
+
+        // if we don't get any unusable base, we've finished everything
+        if (elong_got_error)
+            continue;
+        else
+            break;
+    }
+
+    return true;
+}
+
+typedef void (*encode_func) (const std::string& seq, EncodedSeq& encoded_seq);
+
+template<typename kmer_type, int nary>
+inline kmer_type gen_kmer_simple_impl(encode_func func, const std::string& seq)
+{
+    if (seq.length() > KmerTrait<nary, kmer_type>::max_size())
+        return numeric_limits<kmer_type>::max();
+
+    EncodedSeq enc;
+    func(seq, enc);
+
+    const size_t size = seq.length();
+    kmer_type kmer = 0;
+    kmer_type digit_base = 1;
+    for (size_t i = 0; i < size; i++)
+    {
+        if (enc[i] == ENCODED_ERROR)
+        {
+            kmer = numeric_limits<kmer_type>::max();
+            break;
+        }
+        kmer += enc[i] * digit_base;
+        digit_base *= nary;
+    }
+    return kmer;
+}
+
+template<>
+bool gen_kmer_nt5<uint64_t>(const EncodedSeq& encoded_seq, std::vector<uint64_t>& result, size_t kmer_size)
+{
+    return gen_kmer_impl<uint64_t, 5>(encoded_seq, result, kmer_size);
+}
+
+template<>
+bool gen_kmer_nt5<uint32_t>(const EncodedSeq& encoded_seq, std::vector<uint32_t>& result, size_t kmer_size)
+{
+    return gen_kmer_impl<uint32_t, 5>(encoded_seq, result, kmer_size);
+}
+
+template<>
+bool gen_kmer_nt5<uint16_t>(const EncodedSeq& encoded_seq, std::vector<uint16_t>& result, size_t kmer_size)
+{
+    return gen_kmer_impl<uint16_t, 5>(encoded_seq, result, kmer_size);
+}
+
+template<>
+uint64_t gen_kmer_nt5<uint64_t>(const std::string& seq)
+{
+    return gen_kmer_simple_impl<uint64_t, 5>(encode_nt5, seq);
+}
+
+template<>
+uint32_t gen_kmer_nt5<uint32_t>(const std::string& seq)
+{
+    return gen_kmer_simple_impl<uint32_t, 5>(encode_nt5, seq);
+}
+
+template<>
+uint16_t gen_kmer_nt5<uint16_t>(const std::string& seq)
+{
+    return gen_kmer_simple_impl<uint16_t, 5>(encode_nt5, seq);
+}
+
+template<>
+bool gen_kmer_nt4<uint64_t>(const EncodedSeq& encoded_seq, std::vector<uint64_t>& result, size_t kmer_size)
+{
+    return gen_kmer_impl<uint64_t, 4>(encoded_seq, result, kmer_size);
+}
+
+template<>
+bool gen_kmer_nt4<uint32_t>(const EncodedSeq& encoded_seq, std::vector<uint32_t>& result, size_t kmer_size)
+{
+    return gen_kmer_impl<uint32_t, 4>(encoded_seq, result, kmer_size);
+}
+
+template<>
+bool gen_kmer_nt4<uint16_t>(const EncodedSeq& encoded_seq, std::vector<uint16_t>& result, size_t kmer_size)
+{
+    return gen_kmer_impl<uint16_t, 4>(encoded_seq, result, kmer_size);
+}
+
+template<>
+uint64_t gen_kmer_nt4<uint64_t>(const std::string& seq)
+{
+    return gen_kmer_simple_impl<uint64_t, 4>(encode_nt4, seq);
+}
+
+template<>
+uint32_t gen_kmer_nt4<uint32_t>(const std::string& seq)
+{
+    return gen_kmer_simple_impl<uint32_t, 4>(encode_nt4, seq);
+}
+
+template<>
+uint16_t gen_kmer_nt4<uint16_t>(const std::string& seq)
+{
+    return gen_kmer_simple_impl<uint16_t, 4>(encode_nt4, seq);
+}
+
+template<>
+bool gen_kmer_aa<uint64_t>(const EncodedSeq& encoded_seq, std::vector<uint64_t>& result, size_t kmer_size)
+{
+    return gen_kmer_impl<uint64_t, 26>(encoded_seq, result, kmer_size);
+}
+
+template<>
+bool gen_kmer_aa<uint32_t>(const EncodedSeq& encoded_seq, std::vector<uint32_t>& result, size_t kmer_size)
+{
+    return gen_kmer_impl<uint32_t, 26>(encoded_seq, result, kmer_size);
+}
+
+template<>
+bool gen_kmer_aa<uint16_t>(const EncodedSeq& encoded_seq, std::vector<uint16_t>& result, size_t kmer_size)
+{
+    return gen_kmer_impl<uint16_t, 26>(encoded_seq, result, kmer_size);
+}
+
+template<>
+uint64_t gen_kmer_aa<uint64_t>(const std::string& seq)
+{
+    return gen_kmer_simple_impl<uint64_t, 26>(encode_aa, seq);
+}
+
+template<>
+uint32_t gen_kmer_aa<uint32_t>(const std::string& seq)
+{
+    return gen_kmer_simple_impl<uint32_t, 26>(encode_aa, seq);
+}
+
+template<>
+uint16_t gen_kmer_aa<uint16_t>(const std::string& seq)
+{
+    return gen_kmer_simple_impl<uint16_t, 26>(encode_aa, seq);
+}
+
+typedef char (*decode_func_type)(EncodedType input);
+
+template<typename kmer_type, int nary>
+inline string decode_kmer_impl(decode_func_type decode_func, kmer_type kmer, size_t kmer_size)
+{
+    string result;
+    if (kmer == numeric_limits<kmer_type>::max())
+        return result;
+//    printf("decode %d-ary %lu-mer %lu\n", nary, kmer_size, uint64_t(kmer));
+
+    for (size_t i=0; i<kmer_size; i++)
+    {
+        EncodedType enc = kmer % nary;
+        char dec = decode_func(enc);
+//        printf("  %lu: residue %c (%d) from %lu\n", i, dec, int(enc), uint64_t(kmer));
+        result.push_back(dec);
+        kmer -= enc;
+        kmer /= nary;
+    }
+
+    return result;
+}
+
+template<>
+std::string decode_kmer_nt5<uint64_t>(uint64_t kmer, size_t kmer_size)
+{
+    return decode_kmer_impl<uint64_t, 5>(decode_nt5, kmer, kmer_size);
+}
+
+template<>
+std::string decode_kmer_nt5<uint32_t>(uint32_t kmer, size_t kmer_size)
+{
+    return decode_kmer_impl<uint32_t, 5>(decode_nt5, kmer, kmer_size);
+}
+
+template<>
+std::string decode_kmer_nt5<uint16_t>(uint16_t kmer, size_t kmer_size)
+{
+    return decode_kmer_impl<uint16_t, 5>(decode_nt5, kmer, kmer_size);
+}
+
+template<>
+std::string decode_kmer_nt4<uint64_t>(uint64_t kmer, size_t kmer_size)
+{
+    return decode_kmer_impl<uint64_t, 4>(decode_nt4, kmer, kmer_size);
+}
+
+template<>
+std::string decode_kmer_nt4<uint32_t>(uint32_t kmer, size_t kmer_size)
+{
+    return decode_kmer_impl<uint32_t, 4>(decode_nt4, kmer, kmer_size);
+}
+
+template<>
+std::string decode_kmer_nt4<uint16_t>(uint16_t kmer, size_t kmer_size)
+{
+    return decode_kmer_impl<uint16_t, 4>(decode_nt4, kmer, kmer_size);
+}
+
+template<>
+std::string decode_kmer_aa<uint64_t>(uint64_t kmer, size_t kmer_size)
+{
+    return decode_kmer_impl<uint64_t, 26>(decode_aa, kmer, kmer_size);
+}
+
+template<>
+std::string decode_kmer_aa<uint32_t>(uint32_t kmer, size_t kmer_size)
+{
+    return decode_kmer_impl<uint32_t, 26>(decode_aa, kmer, kmer_size);
+}
+
+template<>
+std::string decode_kmer_aa<uint16_t>(uint16_t kmer, size_t kmer_size)
+{
+    return decode_kmer_impl<uint16_t, 26>(decode_aa, kmer, kmer_size);
+}
+
+} // namespace htio2
diff --git a/src/htio2/Kmer.h b/src/htio2/Kmer.h
new file mode 100644
index 0000000..277de23
--- /dev/null
+++ b/src/htio2/Kmer.h
@@ -0,0 +1,553 @@
+#ifndef HTIO2_KMER_H
+#define	HTIO2_KMER_H
+
+#include <vector>
+#include <map>
+
+#include <stdint.h>
+
+#include "htio2/Enum.h"
+
+namespace htio2
+{
+
+typedef enum
+{
+    SEQ_TYPE_NT4 = 0,
+    SEQ_TYPE_NT5 = 1,
+    SEQ_TYPE_AA  = 2,
+} SeqType;
+
+typedef uint8_t EncodedType;
+#define ENCODED_ERROR 255
+//#define RESIDUE_ERROR -1
+typedef std::vector<EncodedType> EncodedSeq;
+
+#define KMER_NT4_LIMIT_64 31
+#define KMER_NT4_LIMIT_32 15
+#define KMER_NT4_LIMIT_16 7
+#define KMER_NT5_LIMIT_64 27
+#define KMER_NT5_LIMIT_32 13
+#define KMER_NT5_LIMIT_16 6
+#define KMER_AA_LIMIT_64 13
+#define KMER_AA_LIMIT_32 6
+#define KMER_AA_LIMIT_16 3
+
+/**
+ * Properties for a N-ary kmer stored in a primitive data type of specific size.
+ */
+template<int nary, typename KmerType>
+struct KmerTrait;
+
+template<>
+struct KmerTrait<4, uint64_t>
+{
+    static size_t max_size() { return KMER_NT4_LIMIT_64; }
+};
+
+template<>
+struct KmerTrait<4, uint32_t>
+{
+    static size_t max_size() { return KMER_NT4_LIMIT_32; }
+};
+
+template<>
+struct KmerTrait<4, uint16_t>
+{
+    static size_t max_size() { return KMER_NT4_LIMIT_16; }
+};
+
+template<>
+struct KmerTrait<5, uint64_t>
+{
+    static size_t max_size() { return KMER_NT5_LIMIT_64; }
+};
+
+template<>
+struct KmerTrait<5, uint32_t>
+{
+    static size_t max_size() { return KMER_NT5_LIMIT_32; }
+};
+
+template<>
+struct KmerTrait<5, uint16_t>
+{
+    static size_t max_size() { return KMER_NT5_LIMIT_16; }
+};
+
+template<>
+struct KmerTrait<26, uint64_t>
+{
+    static size_t max_size() { return KMER_AA_LIMIT_64; }
+};
+
+template<>
+struct KmerTrait<26, uint32_t>
+{
+    static size_t max_size() { return KMER_AA_LIMIT_32; }
+};
+
+template<>
+struct KmerTrait<26, uint16_t>
+{
+    static size_t max_size() { return KMER_AA_LIMIT_16; }
+};
+
+
+#define ENCODED_NT5_A 0
+#define ENCODED_NT5_T 4
+#define ENCODED_NT5_G 1
+#define ENCODED_NT5_C 3
+#define ENCODED_NT5_N 2
+
+/**
+ * map ATGCN to numbers 0-4, and map all other characters to 255
+ * @param input a nucleotide in ATGCN
+ * @return a number from 0 to 4
+ */
+inline EncodedType encode_nt5(char input)
+{
+    switch (input)
+    {
+    case 'A':
+    case 'a':
+        return ENCODED_NT5_A;
+    case 'T':
+    case 't':
+        return ENCODED_NT5_T;
+    case 'G':
+    case 'g':
+        return ENCODED_NT5_G;
+    case 'C':
+    case 'c':
+        return ENCODED_NT5_C;
+    case 'N':
+    case 'n':
+        return ENCODED_NT5_N;
+    default:
+        return ENCODED_ERROR;
+    }
+}
+
+
+#define ENCODED_NT4_A 0
+#define ENCODED_NT4_T 3
+#define ENCODED_NT4_G 1
+#define ENCODED_NT4_C 2
+
+/**
+ * map ATGC to numbers 0-3, and map all other characters to 255
+ * @param input a nucleotide in ATGC
+ * @return a number from 0 to 3
+ */
+inline EncodedType encode_nt4(char input)
+{
+    switch (input)
+    {
+    case 'A':
+    case 'a':
+        return ENCODED_NT4_A;
+    case 'T':
+    case 't':
+        return ENCODED_NT4_T;
+    case 'G':
+    case 'g':
+        return ENCODED_NT4_G;
+    case 'C':
+    case 'c':
+        return ENCODED_NT4_C;
+    default:
+        return ENCODED_ERROR;
+    }
+}
+
+/**
+ * map amino acids residues to 0-25, "*" to 'O' minus 'A', and all other characters to 255
+ * @param input a amino acids residue
+ * @return numbers from 0 to 25.
+ */
+inline EncodedType encode_aa(char input)
+{
+    if (input == '*') input = 'O';
+
+    if ('a' <= input && input <= 'z') return input - 'a';
+    else if ('A' <= input && input <= 'Z') return input - 'A';
+    else return ENCODED_ERROR;
+}
+
+/**
+ * Map encoded nucleotides back to characters: 0-4 will be mapped to ATGCN;
+ * character '-' and '.' will be specially treated, which will be returned
+ * as-is; and all other characters will be mapped to 'N'.
+ *
+ * @param input encoded bases in 0-4
+ * @return bases in ATGCN.
+ *
+ * @see encode_nt5(char);
+ */
+inline char decode_nt5(EncodedType input)
+{
+    switch (input)
+    {
+    case ENCODED_NT5_A:
+        return 'A';
+    case ENCODED_NT5_T:
+        return 'T';
+    case ENCODED_NT5_G:
+        return 'G';
+    case 3:
+        return 'C';
+    case '-':
+    case '.':
+        return input;
+    case 2:
+    default:
+        return 'N';
+    }
+}
+
+/**
+ * Map encoded nucleotides back to characters: 0-3 will be mapped to ATGC;
+ * character '-' and '.' will be specially treated, which will be returned
+ * as-is; and all other characters will be mapped to 'N'.
+ *
+ * @param input encoded bases in 0-4
+ * @return bases in ATGCN.
+ *
+ * @see encode_nt4(char)
+ */
+inline char decode_nt4(EncodedType input)
+{
+    switch (input)
+    {
+    case 0:
+        return 'A';
+    case 3:
+        return 'T';
+    case 1:
+        return 'G';
+    case 2:
+        return 'C';
+    case '-':
+    case '.':
+        return input;
+    default:
+        return 'N';
+    }
+}
+
+/**
+ * Map encoded amino acids residues back to characters: nomal residues will
+ * be mapped back to characters; 'O' minus 'A' will be mapped to '*'; other
+ * things will be mapped to 'X'.
+ *
+ * @param input residues in 0-25
+ * @return residues in characters.
+ *
+ * @see encode_aa(char);
+ */
+inline char decode_aa(EncodedType input)
+{
+    char result;
+    if (0 <= input && input <= 25)
+        result = input + 'A';
+    else if (input == '-' || input == '.')
+        result = input;
+    else
+        result = 'X';
+
+    if (result == 'O') result = '*';
+
+    return result;
+}
+
+/**
+ * Encode a string of nucleotides, ATGCN are allowed.
+ * @param seq input sequence
+ * @param encoded_seq object to store encoded result
+ *
+ * @see encode_nt5(char)
+ */
+void encode_nt5(const std::string& seq, EncodedSeq& encoded_seq);
+
+/**
+ * Encode a string of nucleotides, ATGC are allowed.
+ * @param seq input sequence
+ * @param encoded_seq object to store encoded result
+ *
+ * @see encode_nt4(char)
+ */
+void encode_nt4(const std::string& seq, EncodedSeq& encoded_seq);
+
+/**
+ * Encode a string of amino acid residues.
+ * @param seq input sequence
+ * @param encoded_seq object to store encoded result
+ *
+ * @see encode_aa(char)
+ */
+void encode_aa(const std::string& seq, EncodedSeq& encoded_seq);
+
+/**
+ * Decode an array of encoded nucleotides.
+ *
+ * @param encoded_seq sequence to decode
+ * @param seq string object to store decoded result
+ *
+ * @see decode_nt5(EncodedType)
+ */
+void decode_nt5(const EncodedSeq& encoded_seq, std::string& seq);
+
+/**
+ * Decode an array of encoded nucleotides.
+ *
+ * @param encoded_seq sequence to decode
+ * @param seq string object to store decoded result
+ *
+ * @see decode_nt4(EncodedType)
+ */
+void decode_nt4(const EncodedSeq& encoded_seq, std::string& seq);
+
+/**
+ * Decode an array of encoded nucleotides.
+ *
+ * @param encoded_seq sequence to decode
+ * @param seq string object to store decoded result
+ *
+ * @see decode_aa(EncodedType)
+ */
+void decode_aa(const EncodedSeq& encoded_seq, std::string& seq);
+
+/**
+ * do reverse-complement for an encoded nucleotide sequence
+ * @param in input sequence containing encoded ATGCN
+ * @param out object to store result
+ */
+void revcom_nt5(const EncodedSeq& in, EncodedSeq& out);
+
+/**
+ * do reverse-complement for an encoded nucleotide sequence
+ * @param in input sequence containing encoded ATGC
+ * @param out object to store result
+ */
+void revcom_nt4(const EncodedSeq& in, EncodedSeq& out);
+
+/**
+ * test whether two encoded sequences are identical
+ * @param a
+ * @param b
+ * @return 
+ */
+bool operator==(const EncodedSeq& a, const EncodedSeq& b);
+
+/**
+ * Generate a series of kmers along encoded nucleotide sequence. Each kmer is
+ * generated as a 5-ary number of K digits, and is stored in an unsigned
+ * integer of specified size. On positions where kmer has invalid base,
+ * TYPE_MAX will be set.
+ *
+ * @param encoded_seq encoded nucleotide sequence
+ * @param result series of generated kmers
+ * @param kmer_size
+ * @return false if kmer size is larger than input sequence, or kmer size is
+ * larger than allowed kmer size limit for specified data type.
+ */
+template<typename KmerType>
+bool gen_kmer_nt5(const EncodedSeq& encoded_seq, std::vector<KmerType>& result, size_t kmer_size);
+
+template<>
+bool gen_kmer_nt5<uint64_t>(const EncodedSeq& encoded_seq, std::vector<uint64_t>& result, size_t kmer_size);
+template<>
+bool gen_kmer_nt5<uint32_t>(const EncodedSeq& encoded_seq, std::vector<uint32_t>& result, size_t kmer_size);
+template<>
+bool gen_kmer_nt5<uint16_t>(const EncodedSeq& encoded_seq, std::vector<uint16_t>& result, size_t kmer_size);
+
+/**
+ * Generate one kmer from nucleotide sequence in ATGCN. The kmer is generated
+ * as a 5-ary number of K digits, and is stored in an unsigned integer of
+ * specified size. The whole sequence is generated to one kmer, and sequence
+ * length is used as kmer size.
+ *
+ * @param seq input sequence
+ * @return generated kmer
+ */
+template<typename KmerType>
+KmerType gen_kmer_nt5(const std::string& seq);
+
+template<>
+uint64_t gen_kmer_nt5<uint64_t>(const std::string& seq);
+template<>
+uint32_t gen_kmer_nt5<uint32_t>(const std::string& seq);
+template<>
+uint16_t gen_kmer_nt5<uint16_t>(const std::string& seq);
+
+/**
+ * Generate a series of kmers along encoded nucleotide sequence. Each kmer is
+ * generated as a 4-ary number of K digits, and is stored in an unsigned
+ * integer of specified size. On positions where kmer has invalid base,
+ * TYPE_MAX will be set.
+ *
+ * @param encoded_seq encoded nucleotide sequence
+ * @param result series of generated kmers
+ * @param kmer_size
+ * @return false if kmer size is larger than input sequence, or kmer size is
+ * larger than allowed kmer size limit for specified data type.
+ */
+template<typename KmerType>
+bool gen_kmer_nt4(const EncodedSeq& encoded_seq, std::vector<KmerType>& result, size_t kmer_size);
+
+template<>
+bool gen_kmer_nt4<uint64_t>(const EncodedSeq& encoded_seq, std::vector<uint64_t>& result, size_t kmer_size);
+template<>
+bool gen_kmer_nt4<uint32_t>(const EncodedSeq& encoded_seq, std::vector<uint32_t>& result, size_t kmer_size);
+template<>
+bool gen_kmer_nt4<uint16_t>(const EncodedSeq& encoded_seq, std::vector<uint16_t>& result, size_t kmer_size);
+
+
+/**
+ * Generate one kmer from nucleotide sequence in ATGC. The kmer is generated
+ * as a 4-ary number of K digits, and is stored in an unsigned integer of
+ * specified size. The whole sequence is generated to one kmer, and sequence
+ * length is used as kmer size.
+ *
+ * @param seq input sequence
+ * @return generated kmer
+ */
+template<typename KmerType>
+KmerType gen_kmer_nt4(const std::string& seq);
+
+template<>
+uint64_t gen_kmer_nt4<uint64_t>(const std::string& seq);
+template<>
+uint32_t gen_kmer_nt4<uint32_t>(const std::string& seq);
+template<>
+uint16_t gen_kmer_nt4<uint16_t>(const std::string& seq);
+
+/**
+ * Generate a series of kmers along encoded amino acids sequence. Each kmer is
+ * generated as a 26-ary number of K digits, and is stored in an unsigned
+ * integer of specified size. On positions where kmer has invalid base,
+ * TYPE_MAX will be set.
+ *
+ * @param encoded_seq encoded amino acids sequence
+ * @param result series of generated kmers
+ * @param kmer_size
+ * @return false if kmer size is larger than input sequence, or kmer size is
+ * larger than allowed kmer size limit for specified data type.
+ */
+template<typename KmerType>
+bool gen_kmer_aa(const EncodedSeq& encoded_seq, std::vector<KmerType>& result, size_t kmer_size);
+
+template<>
+bool gen_kmer_aa<uint64_t>(const EncodedSeq& encoded_seq, std::vector<uint64_t>& result, size_t kmer_size);
+template<>
+bool gen_kmer_aa<uint32_t>(const EncodedSeq& encoded_seq, std::vector<uint32_t>& result, size_t kmer_size);
+template<>
+bool gen_kmer_aa<uint16_t>(const EncodedSeq& encoded_seq, std::vector<uint16_t>& result, size_t kmer_size);
+
+/**
+ * Generate one kmer from amino acids sequence. The kmer is generated as a
+ * 26-ary number of K digits, and is stored in an unsigned integer of specified
+ * size. The whole sequence is generated to one kmer, and sequence length is
+ * used as kmer size.
+ *
+ * @param seq input sequence
+ * @return generated kmer
+ */
+template<typename KmerType>
+KmerType gen_kmer_aa(const std::string& seq);
+
+template<>
+uint64_t gen_kmer_aa<uint64_t>(const std::string& seq);
+template<>
+uint32_t gen_kmer_aa<uint32_t>(const std::string& seq);
+template<>
+uint16_t gen_kmer_aa<uint16_t>(const std::string& seq);
+
+/**
+ * test whether two series of kmers are identical
+ * @param a
+ * @param b
+ * @return 
+ */
+template<typename KmerType>
+bool operator==(const std::vector<KmerType>& a, const std::vector<KmerType>& b)
+{
+    const size_t len = a.size();
+    if (len != b.size())
+        return false;
+
+    for (size_t i = 0; i < len; i++)
+    {
+        if (a[i] != b[i])
+            return false;
+    }
+
+    return true;
+}
+
+/**
+ * Generate mapping from kmer to position. Position is 0-based.
+ * @param kmer_list series of kmers
+ * @param kmer_pos a multimap with kmers as key.
+ */
+template<typename K, typename P>
+void summ_kmer_pos(const std::vector<K>& kmer_list, std::multimap<K, P>& result)
+{
+    for (P i = 0; i < kmer_list.size(); i++)
+        result.insert(std::make_pair(kmer_list[i], i));
+}
+
+/**
+ * decode nucleotide kmer to human-readable string
+ * @param kmer
+ * @param kmer_size
+ * @return 
+ */
+template<typename KmerType>
+std::string decode_kmer_nt5(KmerType kmer, size_t kmer_size);
+
+template<>
+std::string decode_kmer_nt5<uint64_t>(uint64_t kmer, size_t kmer_size);
+template<>
+std::string decode_kmer_nt5<uint32_t>(uint32_t kmer, size_t kmer_size);
+template<>
+std::string decode_kmer_nt5<uint16_t>(uint16_t kmer, size_t kmer_size);
+
+/**
+ * decode nucleotide kmer to human-readable string
+ * @param kmer
+ * @param kmer_size
+ * @return
+ */
+template<typename KmerType>
+std::string decode_kmer_nt4(KmerType kmer, size_t kmer_size);
+
+template<>
+std::string decode_kmer_nt4<uint64_t>(uint64_t kmer, size_t kmer_size);
+template<>
+std::string decode_kmer_nt4<uint32_t>(uint32_t kmer, size_t kmer_size);
+template<>
+std::string decode_kmer_nt4<uint16_t>(uint16_t kmer, size_t kmer_size);
+
+/**
+ * decode amino acids kmer to human-readable string
+ * @param kmer
+ * @param kmer_size
+ * @return 
+ */
+template<typename KmerType>
+std::string decode_kmer_aa(KmerType kmer, size_t kmer_size);
+
+template<>
+std::string decode_kmer_aa<uint64_t>(uint64_t kmer, size_t kmer_size);
+template<>
+std::string decode_kmer_aa<uint32_t>(uint32_t kmer, size_t kmer_size);
+template<>
+std::string decode_kmer_aa<uint16_t>(uint16_t kmer, size_t kmer_size);
+
+
+} // namespace htio2
+
+#endif	/* HTIO2_KMER_H */
+
diff --git a/src/htio2/MT19937.cpp b/src/htio2/MT19937.cpp
new file mode 100644
index 0000000..8bab239
--- /dev/null
+++ b/src/htio2/MT19937.cpp
@@ -0,0 +1,270 @@
+/*
+   A C-program for MT19937-64 (2014/2/23 version).
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   This is a 64-bit version of Mersenne Twister pseudorandom number
+   generator.
+
+   Before using, initialize the state by using init_genrand64(seed)
+   or init_by_array64(init_key, key_length).
+
+   Copyright (C) 2004, 2014, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.
+
+   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 names of its contributors may not be used to endorse or promote
+        products derived from this software without specific prior written
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   References:
+   T. Nishimura, ``Tables of 64-bit Mersenne Twisters''
+     ACM Transactions on Modeling and
+     Computer Simulation 10. (2000) 348--357.
+   M. Matsumoto and T. Nishimura,
+     ``Mersenne Twister: a 623-dimensionally equidistributed
+       uniform pseudorandom number generator''
+     ACM Transactions on Modeling and
+     Computer Simulation 8. (Jan. 1998) 3--30.
+
+   Any feedback is very welcome.
+   http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces)
+*/
+
+
+#include "MT19937.h"
+
+#include "JUCE-3.0.8/JuceHeader.h"
+#include <stdio.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <errno.h>
+
+using namespace std;
+using namespace htio2::juce;
+
+#define MM 156
+#define MATRIX_A 0xB5026F5AA96619E9ull
+#define UM 0xFFFFFFFF80000000ull /* Most significant 33 bits */
+#define LM 0x7FFFFFFFull /* Least significant 31 bits */
+
+namespace htio2
+{
+
+uint64_t _get_seed_from_time_()
+{
+    return Time::getCurrentTime().toMilliseconds();
+}
+
+uint64_t _get_seed_from_pid_()
+{
+    uint32_t pid = uint32_t(getpid());
+    uint32_t ppid = uint32_t(getppid());
+    uint64_t result = pid;
+    result <<= 32;
+    result += ppid;
+    return result;
+}
+
+#define RAND_DEV "/dev/urandom"
+
+void _get_seed_from_dev_random_(uint64_t* seeds, size_t len)
+{
+    FILE* fh = fopen(RAND_DEV, "rb");
+    if (!fh)
+    {
+        fprintf(stderr, "ERROR: MT19937 failed to open %s: %s\n",
+                RAND_DEV, strerror(errno));
+        abort();
+    }
+
+
+    if (fread(seeds, sizeof(uint64_t), len, fh) != len)
+    {
+        fprintf(stderr, "ERROR: MT19937 failed to read %s\n", RAND_DEV);
+        abort();
+    }
+}
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+void _get_seed_from_rand_s_(uint64_t* seeds, size_t len)
+{
+    for (size_t i = 0; i < len; i++)
+        rand_s(&seeds[i]);
+}
+#endif
+
+MT19937::MT19937()
+{
+    static bool has_dev_random = true;
+    if (has_dev_random)
+    {
+        File path_dev_random("/dev/random");
+        if (path_dev_random.existsAsFile())
+        {
+            uint64_t seeds[4];
+            _get_seed_from_dev_random_(seeds, 4);
+            set_seed_array(seeds, 4);
+        }
+        else
+        {
+            has_dev_random = false;
+        }
+    }
+
+    if (!has_dev_random)
+    {
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+        uint64_t seeds[4];
+        _get_seed_from_rand_s_(seeds, 4);
+        set_seed_array(seeds, 4);
+#else
+        uint64_t seeds[2];
+        seeds[0] = _get_seed_from_time_();
+        seeds[1] = _get_seed_from_pid_();
+        set_seed_array(seeds, 2);
+#endif
+    }
+}
+
+MT19937::MT19937(uint64_t seed)
+{
+    set_seed(seed);
+}
+
+MT19937::MT19937(uint64_t *seed_array, size_t len)
+{
+    set_seed_array(seed_array, len);
+}
+
+void MT19937::set_seed(uint64_t seed)
+{
+    mt[0] = seed;
+    for (mti=1; mti<NN; mti++)
+        mt[mti] =  (6364136223846793005ull * (mt[mti-1] ^ (mt[mti-1] >> 62)) + mti);
+}
+
+void MT19937::set_seed_array(uint64_t *seed_array, size_t len)
+{
+    unsigned int i, j;
+    uint64_t k;
+    set_seed(19650218ull);
+    i=1; j=0;
+    k = (NN > len ? NN : len);
+    for (; k; k--) {
+        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 62)) * 3935559000370003845ull))
+          + seed_array[j] + j; /* non linear */
+        i++; j++;
+        if (i>=NN) { mt[0] = mt[NN-1]; i=1; }
+        if (j>=len) j=0;
+    }
+    for (k=NN-1; k; k--) {
+        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 62)) * 2862933555777941757ull))
+          - i; /* non linear */
+        i++;
+        if (i>=NN) { mt[0] = mt[NN-1]; i=1; }
+    }
+
+    mt[0] = 1ull << 63; /* MSB is 1; assuring non-zero initial array */
+}
+
+bool MT19937::next_bool()
+{
+    return next_uint64() > 0x7fffffffffffffffuLL;
+}
+
+uint64_t MT19937::next_uint64()
+{
+    int i;
+    uint64_t x;
+    static uint64_t mag01[2]={0ull, MATRIX_A};
+
+    if (mti >= NN) { /* generate NN words at one time */
+
+        /* if init_genrand64() has not been called, */
+        /* a default initial seed is used     */
+        if (mti == NN+1)
+            set_seed(5489ull);
+
+        for (i=0;i<NN-MM;i++) {
+            x = (mt[i]&UM)|(mt[i+1]&LM);
+            mt[i] = mt[i+MM] ^ (x>>1) ^ mag01[int(x & 1ull)];
+        }
+        for (;i<NN-1;i++) {
+            x = (mt[i]&UM)|(mt[i+1]&LM);
+            mt[i] = mt[i+(MM-NN)] ^ (x>>1) ^ mag01[int(x & 1ull)];
+        }
+        x = (mt[NN-1]&UM)|(mt[0]&LM);
+        mt[NN-1] = mt[MM-1] ^ (x>>1) ^ mag01[int(x & 1ull)];
+
+        mti = 0;
+    }
+
+    x = mt[mti++];
+
+    x ^= (x >> 29) & 0x5555555555555555ull;
+    x ^= (x << 17) & 0x71D67FFFEDA60000ull;
+    x ^= (x << 37) & 0xFFF7EEE000000000ull;
+    x ^= (x >> 43);
+
+    return x;
+}
+
+uint64_t MT19937::next_uint64_in_range(uint64_t upper)
+{
+    uint64_t max64 = std::numeric_limits<uint64_t>::max();
+    uint64_t raw_upper = max64 - max64 % upper;
+
+    for (;;)
+    {
+        uint64_t re = next_uint64();
+        if (re < raw_upper)
+        {
+            return re % upper;
+        }
+    }
+}
+
+int64_t MT19937::next_int63()
+{
+    return (int64_t)(next_uint64() >> 1);
+}
+
+double MT19937::next_double_yy()
+{
+    return (next_uint64() >> 11) * (1.0/9007199254740991.0);
+}
+
+double MT19937::next_double_yn()
+{
+    return (next_uint64() >> 11) * (1.0/9007199254740992.0);
+}
+
+double MT19937::next_double_nn()
+{
+    return ((next_uint64() >> 12) + 0.5) * (1.0/4503599627370496.0);
+}
+
+} // namespace htio2
diff --git a/src/htio2/MT19937.h b/src/htio2/MT19937.h
new file mode 100644
index 0000000..1bcd4c1
--- /dev/null
+++ b/src/htio2/MT19937.h
@@ -0,0 +1,97 @@
+/*
+   A C-program for MT19937-64 (2014/2/23 version).
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   This is a 64-bit version of Mersenne Twister pseudorandom number
+   generator.
+
+   Before using, initialize the state by using init_genrand64(seed)
+   or init_by_array64(init_key, key_length).
+
+   Copyright (C) 2004, 2014, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.
+
+   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 names of its contributors may not be used to endorse or promote
+        products derived from this software without specific prior written
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   References:
+   T. Nishimura, ``Tables of 64-bit Mersenne Twisters''
+     ACM Transactions on Modeling and
+     Computer Simulation 10. (2000) 348--357.
+   M. Matsumoto and T. Nishimura,
+     ``Mersenne Twister: a 623-dimensionally equidistributed
+       uniform pseudorandom number generator''
+     ACM Transactions on Modeling and
+     Computer Simulation 8. (Jan. 1998) 3--30.
+
+   Any feedback is very welcome.
+   http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces)
+*/
+#ifndef HTIO2_MT19937_H
+#define HTIO2_MT19937_H
+
+
+#include <stdint.h>
+#include "htio2/RefCounted.h"
+
+namespace htio2
+{
+
+#define NN 312
+
+class MT19937: public RefCounted
+{
+    friend class ::TestFramework;
+public:
+    typedef SmartPtr<MT19937> Ptr;
+    typedef SmartPtr<const MT19937> ConstPtr;
+
+public:
+    MT19937();
+    MT19937(uint64_t seed);
+    MT19937(uint64_t* seed_array, size_t len);
+
+    void set_seed(uint64_t seed);
+    void set_seed_array(uint64_t* seed_array, size_t len);
+
+    bool next_bool();
+    uint64_t next_uint64();
+    uint64_t next_uint64_in_range(uint64_t upper);
+    int64_t next_int63();
+    double next_double_yy();
+    double next_double_yn();
+    double next_double_nn();
+
+protected:
+    uint64_t mt[NN];
+    int mti = NN + 1;
+}; // class MT19937
+
+} // namespace htio2
+
+#endif // HTIO2_MT19937_H
diff --git a/src/htio2/OptionParser.cpp b/src/htio2/OptionParser.cpp
new file mode 100644
index 0000000..066ee2a
--- /dev/null
+++ b/src/htio2/OptionParser.cpp
@@ -0,0 +1,609 @@
+#include "htio2/OptionParser.h"
+#include "htio2/StringUtil.h"
+
+
+#include <limits>
+#include <cstdio>
+
+#if defined _WIN32 || defined _WIN64
+#include <windows.h>
+#else
+#include <sys/ioctl.h>
+#endif
+
+using namespace std;
+
+namespace htio2
+{
+
+size_t get_terminal_width()
+{
+#if defined _WIN32 || defined _WIN64
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
+    size_t columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+    return columns;
+#else
+    struct winsize win_size;
+    ioctl(fileno(stdout), TIOCGWINSZ, &win_size);
+    return win_size.ws_col;
+#endif
+}
+
+void _break_desc_lines_(const string& input, size_t line_size, vector<string>& output)
+{
+    vector<string> paragraphs;
+    htio2::split(input, '\n', paragraphs);
+
+
+
+    for (size_t line_i = 0; line_i < paragraphs.size(); line_i++)
+    {
+        output.push_back(string());
+        const string& para = paragraphs[line_i];
+        vector<string> tokens;
+        htio2::split(para, ' ', tokens);
+
+        for (size_t i_token = 0; i_token < tokens.size(); i_token++)
+        {
+            const string& token = tokens[i_token];
+            if (output.back().size() + token.size() + 1 > line_size)
+                output.push_back(string());
+            if (output.back().length())
+                output.back() += " ";
+            output.back() += token;
+        }
+    }
+}
+
+
+ValueLimit::ValueLimit(size_t min, size_t max)
+    : min(min)
+    , max(max) {}
+
+ValueLimit ValueLimit::Fixed(size_t num)
+{
+    return ValueLimit(num, num);
+}
+
+ValueLimit ValueLimit::Ranged(size_t min, size_t max)
+{
+    return ValueLimit(min, max);
+}
+
+ValueLimit ValueLimit::Free()
+{
+    return ValueLimit(0, numeric_limits<size_t>::max());
+}
+
+Option::ValueBase::ValueBase(ValueLimit limit): limit(limit) {}
+
+
+Option::ValueBase::~ValueBase() {}
+
+Option::BoolSwitch::BoolSwitch(bool *value)
+    : ValueBase(ValueLimit(0,0))
+    , value(value) {}
+
+Option::BoolSwitch::~BoolSwitch() {}
+
+
+bool Option::BoolSwitch::cast_values(const std::vector<string> &values)
+{
+    if (values.size())
+        abort();
+    *value = true;
+    return true;
+}
+
+string Option::BoolSwitch::to_string()
+{
+    return "";
+}
+
+Option::~Option()
+{
+    delete store;
+}
+
+string Option::format_doc(size_t w_line, size_t w_key_left, size_t w_key, size_t w_key_right) const
+{
+    // validate key width
+    string doc_key = format_doc_key();
+
+    int32_t w_key_remain = w_key - doc_key.size();
+    if (w_key_remain < 0)
+    {
+        fprintf(stderr, "option key exceeds width limit %lu: %lu\n%s\n",
+                w_key, doc_key.size(), doc_key.c_str());
+        abort();
+    }
+
+    // get desc with default value
+    string full_desc;
+    string default_value_str = store->to_string();
+    if (default_value_str.length())
+        full_desc = "[" + default_value_str + "] " + option_desc;
+    else
+        full_desc = option_desc;
+
+    // format document
+    string result;
+    if (w_key_left + w_key + w_key_right > w_line / 2)
+    {
+        // key is too wide, put desc in new line
+        result = string(w_key_left, ' ') + doc_key + "\n";
+
+        vector<string> desc_lines;
+        _break_desc_lines_(full_desc, w_line - 4, desc_lines);
+
+        for (size_t i = 0; i < desc_lines.size(); i++)
+        {
+            result += "    " + desc_lines[i] + "\n";
+        }
+    }
+    else
+    {
+        vector<string> desc_lines;
+        _break_desc_lines_(full_desc, w_line - w_key_left - w_key - w_key_right, desc_lines);
+
+        string leading_space(w_key_left + w_key + w_key_right, ' ');
+
+        for (size_t i = 0; i < desc_lines.size(); i++)
+        {
+            if (i == 0)
+            {
+                result += string(w_key_left, ' ') + doc_key + string(w_key_remain, ' ') + string(w_key_right, ' ');
+            }
+            else
+            {
+                result += leading_space;
+            }
+            result += desc_lines[i] + "\n";
+        }
+    }
+
+    return result;
+}
+
+
+string Option::format_doc_key() const
+{
+    string result;
+    if (name_short)
+    {
+        result.push_back('-');
+        result.push_back(name_short);
+    }
+    if (name_long.length())
+    {
+        if (result.length())
+            result += "|";
+        result += "--" + name_long;
+    }
+    if (value_desc.length())
+    {
+        if (result.length())
+            result += " ";
+        result += value_desc;
+    }
+    return result;
+}
+
+bool OptionParser::add_option(Option& option)
+{
+    bool long_inserted = false;
+    bool short_inserted = false;
+
+    size_t idx = options.size();
+
+    if (option.name_long.size())
+    {
+        long_inserted = options_by_long.insert(make_pair(option.name_long, idx)).second;
+    }
+
+    if (option.name_short)
+    {
+        short_inserted = options_by_short.insert(make_pair(option.name_short, idx)).second;
+    }
+
+    if (long_inserted || short_inserted)
+    {
+        options.push_back(&option);
+
+        const string& group = option.group;
+        size_t id = group_id_seed++;
+
+        group_ids.insert(make_pair(group, id));
+
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+typedef pair<int, string> IndexedValue;
+typedef vector<IndexedValue> IndexedValueGroup;
+typedef map<Option*, vector<IndexedValueGroup> > OptionValueMap;
+
+int _groups_sum_(const vector<IndexedValueGroup>& groups)
+{
+    int re = 0;
+    for (size_t i = 0; i < groups.size(); i++)
+    {
+        re += groups[i].size();
+    }
+    return re;
+}
+
+inline void _dump_value_group_(OptionValueMap& store, Option* option, IndexedValueGroup& values)
+{
+    store[option].push_back(values);
+    values.clear();
+}
+
+void OptionParser::parse_options(int& argc, char** argv)
+{
+    //
+    // collect values by option
+    //
+    OptionValueMap values_by_option;
+    {
+        Option* curr_option = NULL;
+        IndexedValueGroup curr_value_group;
+        for (int i = 1; i < argc; i++)
+        {
+            string curr_token((argv)[i]);
+
+            // token is option key
+            if (curr_token[0] == '-' && curr_token.length() >= 2)
+            {
+                // long key in "--xxx" style
+                if (curr_token[1] == '-')
+                {
+                    // clear previous values
+                    _dump_value_group_(values_by_option, curr_option, curr_value_group);
+
+                    // find option object
+                    curr_option = find_option_long(curr_token);
+                }
+
+                // short key in "-x" style
+                else
+                {
+                    // clear previous values
+                    _dump_value_group_(values_by_option, curr_option, curr_value_group);
+
+                    // find option object
+                    curr_option = find_option_short(curr_token[1]);
+
+                    // short key contains a value
+                    if (curr_token.length() > 2)
+                    {
+                        string curr_token_value = curr_token.substr(2);
+
+                        // extra check for that the option must accept value
+                        if (curr_option->store->limit.max == 0)
+                        {
+                            fprintf(stderr, "ERROR: option -%c is bool switch, but a value \"%s\" is given via \"%s\"\n",
+                                    curr_option->name_short, curr_token_value.c_str(), curr_token.c_str());
+                            exit(EXIT_FAILURE);
+                        }
+
+                        curr_value_group.push_back(make_pair(i, curr_token_value));
+                    }
+                }
+            }
+            // token is not key
+            else
+            {
+                curr_value_group.push_back(make_pair(i, curr_token));
+            }
+        } // argv cycle
+
+        // lasting...
+       _dump_value_group_(values_by_option, curr_option, curr_value_group);
+    }
+
+    //
+    // set option values
+    //
+    vector<int> unused_indices;
+    for (OptionValueMap::iterator it = values_by_option.begin();
+         it != values_by_option.end();
+         ++it)
+    {
+        Option* option = it->first;
+        vector<IndexedValueGroup>& value_groups = it->second;
+
+        if (option)
+        {
+            vector<string> values_plain;
+
+            // a bool switch option, accept no values
+            if (option->store->limit.max == 0)
+            {
+                // it should appear only once
+                if (value_groups.size() > 1)
+                {
+                    fprintf(stderr, "ERROR: bool switch option \"%s\" appeared more than once\n",
+                            option->format_doc_key().c_str());
+                    exit(EXIT_FAILURE);
+                }
+
+                // all values are unused
+                for (size_t i_group = 0; i_group < value_groups.size(); i_group++)
+                {
+                    const IndexedValueGroup& value_group = value_groups[i_group];
+                    for (size_t i_value = 0; i_value < value_group.size(); i_value++)
+                    {
+                        unused_indices.push_back(value_group[i_value].first);
+                    }
+                }
+            }
+            // accept one value
+            else if (option->store->limit.min == 1 && option->store->limit.max == 1)
+            {
+                // it should appear only once
+                if (value_groups.size() > 1)
+                {
+                    fprintf(stderr, "ERROR: single value option \"%s\" appeared more than once\n",
+                            option->format_doc_key().c_str());
+                    exit(EXIT_FAILURE);
+                }
+
+                const IndexedValueGroup& first_group = value_groups[0];
+
+                // we should have value
+                if (!first_group.size())
+                {
+                    fprintf(stderr, "ERROR: single value option \"%s\" has no value\n",
+                            option->format_doc_key().c_str());
+                    exit(EXIT_FAILURE);
+                }
+
+                // first value is used, all following values are unused
+                for (size_t i_value = 0; i_value < first_group.size(); i_value++)
+                {
+                    if (i_value == 0)
+                        values_plain.push_back(first_group[i_value].second);
+                    else
+                        unused_indices.push_back(first_group[i_value].first);
+                }
+            }
+            // accept variable number of values
+            else
+            {
+                const char* TEMPLATE_LOWER_THAN_MIN = 0;
+                if (option->store->limit.min == option->store->limit.max)
+                    TEMPLATE_LOWER_THAN_MIN = "ERROR: option \"%s\" requires %lu values, but only %lu got\n";
+                else
+                    TEMPLATE_LOWER_THAN_MIN = "ERROR: option \"%s\" requires %lu values at least, but only %lu got\n";
+
+                // option can occur multiple times
+                if (option->flags & Option::FLAG_MULTI_KEY)
+                {
+                    for (size_t i_group = 0; i_group < value_groups.size(); i_group++)
+                    {
+                        const IndexedValueGroup& value_group = value_groups[i_group];
+                        for (size_t i_value = 0; i_value < value_group.size(); i_value++)
+                        {
+                            if (values_plain.size() < option->store->limit.max)
+                                values_plain.push_back(value_group[i_value].second);
+                            else
+                                unused_indices.push_back(value_group[i_value].first);
+                        }
+                    }
+
+                    // validate value number
+                    if (values_plain.size() < option->store->limit.min)
+                    {
+                        fprintf(stderr, TEMPLATE_LOWER_THAN_MIN,
+                                option->format_doc_key().c_str(), option->store->limit.min, values_plain.size());
+                        exit(EXIT_FAILURE);
+                    }
+                }
+                // option can occur only once
+                else
+                {
+                    if (value_groups.size() > 1)
+                    {
+                        fprintf(stderr, "ERROR: multi value option \"%s\" appeared more than once\n",
+                                option->format_doc_key().c_str());
+                        exit(EXIT_FAILURE);
+                    }
+
+                    const IndexedValueGroup& first_group = value_groups[0];
+
+                    // validate value number
+                    if (first_group.size() < option->store->limit.min)
+                    {
+
+                        fprintf(stderr, TEMPLATE_LOWER_THAN_MIN,
+                                option->format_doc_key().c_str(), option->store->limit.min, first_group.size());
+                        exit(EXIT_FAILURE);
+                    }
+
+                    // store
+                    for (size_t i_value = 0; i_value < first_group.size(); i_value++)
+                    {
+                        if (i_value < option->store->limit.max)
+                            values_plain.push_back(first_group[i_value].second);
+                        else
+                            unused_indices.push_back(first_group[i_value].first);
+                    }
+                }
+            }
+
+            if (!option->store->cast_values(values_plain))
+            {
+                fprintf(stderr, "ERROR: failed to cast values for option \"%s\"\n",
+                        option->format_doc_key().c_str());
+                for (size_t i = 0; i < values_plain.size(); i++)
+                {
+                    fprintf(stderr, "ERROR:   \"%s\"\n",
+                            values_plain[i].c_str());
+                }
+                exit(EXIT_FAILURE);
+            }
+        }
+        else
+        {
+            // ungrouped options, collect to unused
+            for (size_t i_group = 0; i_group < value_groups.size(); i_group++)
+            {
+                const IndexedValueGroup& value_group = value_groups[i_group];
+                for (size_t i_value = 0; i_value < value_group.size(); i_value++)
+                {
+                    unused_indices.push_back(value_group[i_value].first);
+                }
+            }
+        }
+    } // option cycle
+
+    // modify argument
+    // collect unprocessed names
+    vector<char*> buffer;
+    for (size_t i = 0; i < unused_indices.size(); i++)
+    {
+        int index = unused_indices[i];
+        if (index > 0)
+            buffer.push_back(argv[index]);
+    }
+
+    // modify argv
+    for (size_t i = 1; i < argc; i++)
+    {
+        if (i <= buffer.size())
+        {
+            argv[i] = buffer[i-1];
+        }
+        else
+        {
+            argv[i] = NULL;
+        }
+    }
+
+    argc = buffer.size() + 1;
+}
+
+Option* OptionParser::find_option_long(const string &key)
+{
+    string key_use = key.substr(2);
+
+    // find exact key
+    map<string, size_t>::iterator it = options_by_long.find(key_use);
+    if (it != options_by_long.end())
+        return options[it->second];
+
+    // find by prefix
+    vector<string> matched_keys;
+    vector<size_t> matched_i;
+
+    for (it = options_by_long.begin(); it != options_by_long.end(); it++)
+    {
+        const string& curr_key = it->first;
+
+        if (curr_key.find(key_use) == 0)
+        {
+            matched_keys.push_back("--"+curr_key);
+            matched_i.push_back(it->second);
+        }
+    }
+
+    if (matched_keys.size() == 0)
+    {
+        fprintf(stderr, "ERROR: unknown option \"%s\"\n", key.c_str());
+        exit(EXIT_FAILURE);
+    }
+    else if (matched_keys.size() == 1)
+    {
+        return options[matched_i[0]];
+    }
+    else
+    {
+        fprintf(stderr, "ERROR: ambiguous option prefix \"%s\", which matches:\n", key.c_str());
+        for (size_t i = 0; i < matched_keys.size(); i++)
+            fprintf(stderr, "ERROR:   %s\n", matched_keys[i].c_str());
+        exit(EXIT_FAILURE);
+    }
+}
+
+Option* OptionParser::find_option_short(char key)
+{
+    std::map<char, size_t>::iterator it = options_by_short.find(key);
+    if (it != options_by_short.end())
+        return options[it->second];
+    else
+    {
+        fprintf(stderr, "ERROR: unknown option \"-%c\"\n", key);
+        exit(EXIT_FAILURE);
+    }
+}
+
+struct GroupSort
+{
+    GroupSort(std::map<std::string, size_t>& ids): ids(ids) {}
+
+    bool operator () (const string& a, const string& b)
+    {
+        return ids[a] < ids[b];
+    }
+
+    std::map<std::string, size_t>& ids;
+};
+
+string OptionParser::format_document()
+{
+    size_t line_width = get_terminal_width();
+
+    // categorize by group
+    map<string, vector<Option*> > groups;
+    for (size_t i=0; i<options.size(); i++)
+    {
+        const string& group_name = options[i]->group;
+        groups[group_name].push_back(options[i]);
+    }
+
+    string result;
+
+    // get key length
+    size_t max_doc_key_len = 0;
+
+    for (size_t i = 0; i < options.size(); i++)
+    {
+        Option* opt = options[i];
+        string doc_key = opt->format_doc_key();
+        if (max_doc_key_len < doc_key.length())
+            max_doc_key_len = doc_key.length();
+    }
+
+    // sort groups by their occurance
+    vector<string> group_names;
+    for (pair<string, size_t> value : group_ids)
+        group_names.push_back(value.first);
+
+    sort(group_names.begin(), group_names.end(), GroupSort(group_ids));
+
+    // format document for each option group
+    for (const string& group_name : group_names)
+    {
+        vector<Option*>& group_options = groups[group_name];
+
+        if (group_name.length())
+            result += group_name + "\n\n";
+
+        for (size_t i = 0; i < group_options.size(); i++)
+        {
+            Option* opt = group_options[i];
+            result += opt->format_doc(line_width, 2, max_doc_key_len, 2);
+            result += "\n";
+        }
+    }
+
+    return result;
+}
+
+} // namespace tcrk2
diff --git a/src/htio2/OptionParser.h b/src/htio2/OptionParser.h
new file mode 100644
index 0000000..1b28b9a
--- /dev/null
+++ b/src/htio2/OptionParser.h
@@ -0,0 +1,231 @@
+#ifndef HTIO2_OPTION_PARSER
+#define HTIO2_OPTION_PARSER
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include <cstdio>
+#include <cstdlib>
+#include <stdint.h>
+
+#include "htio2/RefCounted.h"
+#include "htio2/Cast.h"
+
+namespace htio2
+{
+
+class OptionParser;
+class Option;
+
+class ValueLimit
+{
+    friend class OptionParser;
+    friend class Option;
+
+    ValueLimit(size_t min, size_t max);
+
+public:
+    static ValueLimit Fixed(size_t num);
+    static ValueLimit Ranged(size_t min, size_t max);
+    static ValueLimit Free();
+
+protected:
+    size_t min;
+    size_t max;
+};
+
+class Option
+{
+    friend class OptionParser;
+
+public:
+    enum OptionFlag
+    {
+        FLAG_NONE = 0,
+        FLAG_MULTI_KEY = 1,
+    };
+
+protected:
+    struct ValueBase
+    {
+        ValueBase(ValueLimit limit);
+        virtual ~ValueBase();
+        virtual bool cast_values(const std::vector<std::string>& values) = 0;
+        virtual std::string to_string() = 0;
+
+        ValueLimit limit;
+    };
+
+    struct BoolSwitch: public ValueBase
+    {
+        BoolSwitch(bool* value);
+        virtual ~BoolSwitch();
+
+        virtual bool cast_values(const std::vector<std::string>& values);
+        virtual std::string to_string();
+
+        bool* value;
+    };
+
+    template<typename T>
+    struct SingleValue: public ValueBase
+    {
+        SingleValue(T* value)
+            : ValueBase(ValueLimit(1,1))
+            , value(value) {}
+        virtual ~SingleValue() {}
+
+        virtual bool cast_values(const std::vector<std::string>& values)
+        {
+            if (values.size() != 1)
+                abort();
+            return htio2::from_string<T>(values[0], *value);
+        }
+
+        virtual std::string to_string()
+        {
+            return htio2::to_string<T>(*value);
+        }
+
+
+        T* value;
+    };
+
+    template<typename T>
+    struct MultiValue: public ValueBase
+    {
+        MultiValue(std::vector<T>* values, ValueLimit limit)
+            : ValueBase(limit)
+            , value_list(values) {}
+
+
+        virtual bool cast_values(const std::vector<std::string>& values)
+        {
+            for (size_t i = 0; i < values.size(); i++)
+            {
+                T tmp;
+                if (!from_string<T>(values[i], tmp))
+                    return false;
+                value_list->push_back(tmp);
+            }
+            return true;
+        }
+
+        virtual std::string to_string()
+        {
+            std::string result;
+            for (size_t i = 0; i < value_list->size(); i++)
+            {
+                if (i > 0) result += " ";
+                result += htio2::to_string((*value_list)[i]);
+            }
+            return result;
+        }
+
+        std::vector<T>* value_list;
+    };
+
+public:
+    Option(const std::string& name_long,
+           char               name_short,
+           const std::string& group,
+           bool*              value_store,
+           int32_t            flags,
+           const std::string& option_desc)
+        : name_long(name_long)
+        , name_short(name_short)
+        , group(group)
+        , store(new BoolSwitch(value_store))
+        , flags(flags)
+        , option_desc(option_desc)
+        , value_desc("")
+    {
+    }
+
+    template<typename T>
+    Option(const std::string& name_long,
+           char               name_short,
+           const std::string& group,
+           T*                 value_store,
+           int32_t            flags,
+           const std::string& option_desc,
+           const std::string& value_desc)
+        : name_long(name_long)
+        , name_short(name_short)
+        , group(group)
+        , store(new SingleValue<T>(value_store))
+        , flags(flags)
+        , option_desc(option_desc)
+        , value_desc(value_desc)
+    {
+    }
+
+    template<typename T>
+    Option(const std::string& name_long,
+           char               name_short,
+           const std::string& group,
+           std::vector<T>*    value_store,
+           int32_t            flags,
+           ValueLimit         value_num_limit,
+           const std::string& option_desc,
+           const std::string& value_desc)
+        : name_long(name_long)
+        , name_short(name_short)
+        , group(group)
+        , store(new MultiValue<T>(value_store, value_num_limit))
+        , flags(flags)
+        , option_desc(option_desc)
+        , value_desc(value_desc)
+    {
+    }
+
+    virtual ~Option();
+
+private:
+    Option(const Option& other);
+    Option& operator = (const Option& other);
+
+protected:
+    static bool validate_name(char name);
+    static bool validate_name(const std::string& name);
+    std::string format_doc(size_t w_line, size_t w_key_left, size_t w_key, size_t w_key_right) const;
+    std::string format_doc_key() const;
+
+protected:
+    std::string name_long;
+    char        name_short;
+    std::string group;
+    ValueBase*  store = nullptr;
+    uint32_t    flags = 0;
+    std::string option_desc;
+    std::string value_desc;
+};
+
+
+class OptionParser: public htio2::RefCounted
+{
+public:
+    typedef SmartPtr<OptionParser> Ptr;
+    typedef SmartPtr<const OptionParser> ConstPtr;
+
+public:
+    bool add_option(Option& option);
+    void parse_options(int& argc, char** argv);
+    std::string format_document();
+
+protected:
+    Option* find_option_long(const std::string& key);
+    Option* find_option_short(char key);
+
+protected:
+    size_t                          group_id_seed = 0;
+    std::map<std::string, size_t>   group_ids;
+    std::vector<Option*>            options;
+    std::map<char, size_t>          options_by_short;
+    std::map<std::string, size_t>   options_by_long;
+};
+
+} // namespace htio2
+
+#endif // HTIO2_OPTION_PARSER
diff --git a/src/htio2/PairedEndIO.cpp b/src/htio2/PairedEndIO.cpp
new file mode 100644
index 0000000..ecd5299
--- /dev/null
+++ b/src/htio2/PairedEndIO.cpp
@@ -0,0 +1,206 @@
+/* 
+ * File:   PairedEndIO.cpp
+ * Author: yangxi
+ * 
+ * Created on March 27, 2014, 9:15 AM
+ */
+
+#include "htio2/PairedEndIO.h"
+
+#include "htio2/Error.h"
+#include "htio2/FastqIO.h"
+#include "htio2/FastaIO.h"
+
+using namespace std;
+
+namespace htio2
+{
+
+PairedEndIO::PairedEndIO(const std::string& file,
+                         IOMode mode,
+                         Strand strand_r1_in_file,
+                         Strand strand_r2_in_file,
+                         CompressFormat comp,
+                         SeqFormat format)
+: fh1(0)
+, fh2(0)
+, interleave(true)
+, strand_r1_in_file(strand_r1_in_file)
+, strand_r2_in_file(strand_r2_in_file)
+{
+    switch (format)
+    {
+    case FORMAT_FASTQ:
+        fh1 = new FastqIO(file, mode, comp);
+        break;
+    case FORMAT_FASTA:
+        fh1 = new FastaIO(file, mode, comp);
+        break;
+    default:
+        fh1 = SeqIO::New(file, mode, comp);
+        break;
+    }
+}
+
+PairedEndIO::PairedEndIO(const std::string& file1,
+                         const std::string& file2,
+                         IOMode mode,
+                         Strand strand_r1_in_file,
+                         Strand strand_r2_in_file,
+                         CompressFormat comp,
+                         SeqFormat format)
+: fh1(0)
+, fh2(0)
+, interleave(false)
+, strand_r1_in_file(strand_r1_in_file)
+, strand_r2_in_file(strand_r2_in_file)
+{
+    switch (format)
+    {
+    case FORMAT_FASTQ:
+        fh1 = new FastqIO(file1, mode, comp);
+        fh2 = new FastqIO(file2, mode, comp);
+        break;
+    case FORMAT_FASTA:
+        fh1 = new FastaIO(file1, mode, comp);
+        fh2 = new FastaIO(file2, mode, comp);
+        break;
+    default:
+        fh1 = SeqIO::New(file1, mode, comp);
+        fh2 = SeqIO::New(file2, mode, comp);
+        break;
+    }
+}
+
+PairedEndIO::~PairedEndIO()
+{
+    delete fh1;
+    if (fh2) delete fh2;
+}
+
+bool PairedEndIO::next_pair(FastqSeq& seq1,
+                            FastqSeq& seq2,
+                            Strand strand_r1,
+                            Strand strand_r2)
+{
+    if (strand_r1 == strand_r1_in_file)
+    {
+        if (strand_r2 == strand_r2_in_file)
+        {
+            return _read_next_pair(seq1, seq2);
+        }
+        else
+        {
+            bool re = _read_next_pair(seq1, tmp2);
+            if (re)
+                tmp2.revcom(seq2);
+            return re;
+        }
+    }
+    else
+    {
+        if (strand_r2 == strand_r2_in_file)
+        {
+            bool re = _read_next_pair(tmp1, seq2);
+            if (re)
+                tmp1.revcom(seq1);
+            return re;
+        }
+        else
+        {
+            bool re = _read_next_pair(tmp1, tmp2);
+            if (re)
+            {
+                tmp1.revcom(seq1);
+                tmp2.revcom(seq2);
+            }
+            return re;
+        }
+    }
+}
+
+void PairedEndIO::write_pair(const FastqSeq& seq1,
+                             const FastqSeq& seq2,
+                             Strand strand_r1,
+                             Strand strand_r2)
+{
+    if (strand_r1 == strand_r1_in_file)
+    {
+        if (strand_r2 == strand_r2_in_file)
+        {
+            _write_pair(seq1, seq2);
+        }
+        else
+        {
+            seq2.revcom(tmp2);
+            _write_pair(seq1, tmp2);
+        }
+    }
+    else
+    {
+        if (strand_r2 == strand_r2_in_file)
+        {
+            seq1.revcom(tmp1);
+            _write_pair(tmp1, seq2);
+        }
+        else
+        {
+            seq1.revcom(tmp1);
+            seq2.revcom(tmp2);
+            _write_pair(tmp1, tmp2);
+        }
+    }
+}
+
+bool PairedEndIO::_read_next_pair(FastqSeq& seq1, FastqSeq& seq2)
+{
+    if (interleave)
+    {
+        bool re1 = fh1->next_seq(seq1);
+        bool re2 = fh1->next_seq(seq2);
+        if (re1)
+        {
+            if (re2)
+                return true;
+            else
+                throw InvalidFileContent("incomplete interleaved sequence file", fh1->tell());
+        }
+        else
+            return false;
+    }
+    else
+    {
+        bool re1 = fh1->next_seq(seq1);
+        bool re2 = fh2->next_seq(seq2);
+        if (re1)
+        {
+            if (re2)
+                return true;
+            else
+                throw InvalidFileContent("paired-end from two files: file 2 ended, but file 1 not", fh1->tell());
+        }
+        else
+        {
+            if (re2)
+                throw InvalidFileContent("paired-end from two files: file 1 ended, but file 2 not", fh2->tell());
+            else
+                return false;
+        }
+    }
+}
+
+void PairedEndIO::_write_pair(const FastqSeq& seq1, const FastqSeq& seq2)
+{
+    if (interleave)
+    {
+        fh1->write_seq(seq1);
+        fh1->write_seq(seq2);
+    }
+    else
+    {
+        fh1->write_seq(seq1);
+        fh2->write_seq(seq2);
+    }
+}
+
+} // namespace htio2
diff --git a/src/htio2/PairedEndIO.h b/src/htio2/PairedEndIO.h
new file mode 100644
index 0000000..857fa2e
--- /dev/null
+++ b/src/htio2/PairedEndIO.h
@@ -0,0 +1,133 @@
+/* 
+ * File:   PairedEndIO.h
+ * Author: yangxi
+ *
+ * Created on March 27, 2014, 9:15 AM
+ */
+
+#ifndef HTIO2_PAIRED_END_IO_H
+#define	HTIO2_PAIRED_END_IO_H
+
+#include "htio2/RefCounted.h"
+#include "htio2/Enum.h"
+#include "htio2/FastqSeq.h"
+
+namespace htio2
+{
+
+class SeqIO;
+class FastqSeq;
+
+/**
+ * A wrapper class that handle several paired-end reads read/write issues.
+ * 
+ * The PairedEndIO class is designed for handle several paired-end related
+ * issues:
+ * 
+ *  - they are stored in one interleaved file, or two files?
+ *  - the strand of the reads are Fwd-Rev (the most common), or Rev-Fwd (common for long insersion libraries)?
+ * 
+ * For the first issue, PairedEndIO provides two constructors: one with only one
+ * file parameter, and the other one with two file parameters. If the object is
+ * built with the one-file constructor, it is 
+ * 
+ * For the second issue, when PairedEndIO is being constructed, it requires the
+ * strand of reads in file being specified; and when read/write sequences, it
+ * require the strand of the sequence object being specified.
+ * 
+ * For example, if you specify the reads file is in FWD and REV format (the most
+ * common case), and you specify the reads you get is in FWD and FWD format when
+ * you call next_pair(), read 1 will be given as-is, while read 2 will be
+ * reverse-complemented.
+ */
+class PairedEndIO : public RefCounted
+{
+public:
+    typedef SmartPtr<PairedEndIO> Ptr;
+    typedef SmartPtr<const PairedEndIO> ConstPtr;
+public:
+    /**
+     * create PairedEndIO object. Both ends are stored in one interleaved file.
+     * @param file file for input reads.
+     * @param mode READ/WRITE/APPEND.
+     * @param strand_r1_in_file strand of read 1 in file.
+     * @param strand_r2_in_file strand of read 2 in file.
+     * @param comp compression format. COMPRESS_UNKNOWN for automatically guess by file name.
+     * @param format sequence format. FORMAT_UNKNOWN for automatically guess by file name and/or content.
+     */
+    PairedEndIO(const std::string& file,
+                IOMode mode,
+                Strand strand_r1_in_file = STRAND_FWD,
+                Strand strand_r2_in_file = STRAND_REV,
+                CompressFormat comp = COMPRESS_UNKNOWN,
+                SeqFormat format = FORMAT_UNKNOWN);
+
+    /**
+     * create PairedEndIO object. Two read ends are stored in two separate file.
+     * @param file1 file for read 1.
+     * @param file2 file for read 2.
+     * @param mode READ/WRITE/APPEND.
+     * @param strand_r1_in_file strand of read 1 in file.
+     * @param strand_r2_in_file strand of read 2 in file.
+     * @param comp compression format. COMPRESS_UNKNOWN for automatically guess by file name.
+     * @param format sequence format. FORMAT_UNKNOWN for automatically guess by file name and/or content.
+     */
+    PairedEndIO(const std::string& file1,
+                const std::string& file2,
+                IOMode mode,
+                Strand strand_r1_in_file = STRAND_FWD,
+                Strand strand_r2_in_file = STRAND_REV,
+                CompressFormat comp = COMPRESS_UNKNOWN,
+                SeqFormat format = FORMAT_UNKNOWN);
+
+    virtual ~PairedEndIO();
+
+    /**
+     * read one pair from file
+     * @param seq1
+     * @param seq2
+     * @param strand_r1 strand of read 1 you expect to get
+     * @param strand_r2 strand of read 2 you expect to get
+     * @return false if reached end of file, otherwise true.
+     */
+    bool next_pair(FastqSeq& seq1,
+                   FastqSeq& seq2,
+                   Strand strand_r1 = STRAND_FWD,
+                   Strand strand_r2 = STRAND_FWD);
+
+    /**
+     * 
+     * @param seq1 read 1 to be written
+     * @param seq2 read 2 to be written
+     * @param strand_r1 strand of read 1 you give
+     * @param strand_r2 strand of read 2 you give
+     */
+    void write_pair(const FastqSeq& seq1,
+                    const FastqSeq& seq2,
+                    Strand strand_r1 = STRAND_FWD,
+                    Strand strand_r2 = STRAND_FWD);
+
+protected:
+    SeqIO* fh1;
+    SeqIO* fh2;
+
+    FastqSeq tmp1;
+    FastqSeq tmp2;
+
+    Strand strand_r1_in_file;
+    Strand strand_r2_in_file;
+    bool interleave;
+
+private:
+    bool _read_next_pair(FastqSeq& seq1, FastqSeq& seq2);
+    void _write_pair(const FastqSeq& seq1, const FastqSeq& seq2);
+
+    PairedEndIO(const PairedEndIO& orig);
+    PairedEndIO& operator =(const PairedEndIO& orig);
+};
+
+} // namespace htio2
+
+#endif	/* HTIO2_PAIRED_END_IO_H */
+
+
diff --git a/src/htio2/PlainFileHandle.cpp b/src/htio2/PlainFileHandle.cpp
new file mode 100644
index 0000000..d9ebf35
--- /dev/null
+++ b/src/htio2/PlainFileHandle.cpp
@@ -0,0 +1,117 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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 "htio2/PlainFileHandle.h"
+#include <cstring>
+#include <cstdio>
+#include <cerrno>
+#include <stdexcept>
+
+using namespace std;
+
+namespace htio2
+{
+
+PlainFileHandle::PlainFileHandle(const std::string& file, IOMode mode) : auto_close(true)
+{
+    handle = fopen(file.c_str(), get_io_mode_str(mode));
+    if (handle == 0)
+    {
+        const char* msg = strerror(errno);
+        throw runtime_error(string(msg));
+    }
+
+    offset = ftell(handle);
+    curr_chr = fgetc(handle);
+}
+
+PlainFileHandle::PlainFileHandle(FILE* handle, bool auto_close) : handle(handle), auto_close(auto_close)
+{
+    offset = ftell(handle);
+    curr_chr = fgetc(handle);
+}
+
+PlainFileHandle::~PlainFileHandle()
+{
+    if (auto_close) fclose(handle);
+}
+
+bool PlainFileHandle::read_line(std::string& buffer)
+{
+    buffer.clear();
+    if (curr_chr == EOF) return false;
+
+    while (1)
+    {
+        switch (curr_chr)
+        {
+        case EOF:
+            goto END;
+        case LINE_END_CR:
+            curr_chr = fgetc(handle);
+            if (curr_chr == LINE_END_LF) curr_chr = fgetc(handle);
+            goto END;
+        case LINE_END_LF:
+            curr_chr = fgetc(handle);
+            goto END;
+        default:
+            buffer.push_back(curr_chr);
+            curr_chr = fgetc(handle);
+        }
+    }
+
+END:
+    offset = ftell(handle) - 1;
+    return true;
+}
+
+void PlainFileHandle::write_line(const std::string& content)
+{
+    fwrite(content.data(), 1, content.size(), handle);
+    fputc('\n', handle);
+    offset = ftell(handle);
+}
+
+void PlainFileHandle::seek(off_t offset, int whence)
+{
+    if (whence == SEEK_SET)
+    {
+        fseek(handle, offset, SEEK_SET);
+        this->offset = offset;
+    }
+    else if (whence == SEEK_CUR)
+    {
+        fseek(handle, this->offset, SEEK_SET);
+        fseek(handle, offset, SEEK_CUR);
+        this->offset += offset;
+    }
+    else if (whence == SEEK_END)
+    {
+        fseek(handle, 0, SEEK_END);
+        this->offset = ftell(handle) + offset;
+        fseek(handle, offset, SEEK_END);
+    }
+    else
+        throw runtime_error("invalid seek whence");
+
+    curr_chr = fgetc(handle);
+}
+
+off_t PlainFileHandle::tell() const
+{
+    return offset;
+}
+
+} // namespace htio2
diff --git a/src/htio2/PlainFileHandle.h b/src/htio2/PlainFileHandle.h
new file mode 100644
index 0000000..b975344
--- /dev/null
+++ b/src/htio2/PlainFileHandle.h
@@ -0,0 +1,86 @@
+//     HTIO - a high-throughput sequencing reads input/output library
+//
+//     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.
+//
+//     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/>.
+
+#ifndef HTIO2_PLAIN_FILE_HANDLE_H
+#define	HTIO2_PLAIN_FILE_HANDLE_H
+
+#include "htio2/FileHandle.h"
+
+namespace htio2
+{
+
+class PlainFileHandle : public FileHandle
+{
+    friend class ::TestFramework;
+public:
+    typedef SmartPtr<PlainFileHandle> Ptr;
+    typedef SmartPtr<const PlainFileHandle> ConstPtr;
+public:
+    /**
+     * create by file name and mode
+     * @param file file name
+     * @param mode "rb" for read, "wb" for write. See manual of stdio.h for more modes.
+     */
+    PlainFileHandle(const std::string& file, IOMode mode);
+
+    /**
+     * create from C standard file handle
+     * @param handle
+     * @param auto_close if set to true, the underlying FILE will be closed when the object is destroyed
+     */
+    PlainFileHandle(FILE* handle, bool auto_close = true);
+    virtual ~PlainFileHandle();
+
+    /**
+     * Read one line. The end-of-line character can be CR, LF and CRLF.
+     * @param buffer
+     * @return true if get a line, false if reached end of file.
+     */
+    virtual bool read_line(std::string& buffer);
+
+    /**
+     * Write one line. The end-of-line character is decided by the system.
+     * @param content
+     */
+    virtual void write_line(const std::string& content);
+
+    /**
+     * Seek to a file offset.
+     * The offset can be different with the wrapped FILE* or gzFile's offset.
+     * See implementation of read_line() for detail.
+     * @param offset
+     * @param whence 0 for absolute, 1 for relative
+     */
+    virtual void seek(off_t offset, int whence);
+
+    /**
+     * Get the current file offset.
+     * The offset can be different with the wrapped FILE* or gzFile's offset.
+     * See implementation of read_line() for detail.
+     * @return offset
+     */
+    virtual off_t tell() const;
+
+private:
+    FILE* handle;
+    bool auto_close;
+    off_t offset;
+    char curr_chr;
+};
+
+} // namespace htio2
+
+#endif	/* HTIO2_PLAIN_FILE_HANDLE_H */
+
diff --git a/src/htio2/QualityUtil.cpp b/src/htio2/QualityUtil.cpp
new file mode 100644
index 0000000..5a2330f
--- /dev/null
+++ b/src/htio2/QualityUtil.cpp
@@ -0,0 +1,149 @@
+#include "htio2/QualityUtil.h"
+#include "htio2/Error.h"
+#include "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+
+#include <map>
+
+using namespace std;
+
+namespace htio2
+{
+
+QualityEncode guess_quality_encode(char qual_ascii_min, char qual_ascii_max)
+{
+    if (qual_ascii_min > qual_ascii_max)
+        return ENCODE_UNKNOWN;
+
+    if (64 <= qual_ascii_min && qual_ascii_max <= 126)
+    {
+        // 0 to 62, 64 based
+        return ENCODE_ILLUMINA;
+    }
+    else if (59 <= qual_ascii_min && qual_ascii_max <= 126)
+    {
+        // -5 to 62, 64 based
+        return ENCODE_SOLEXA;
+    }
+    else if (33 <= qual_ascii_min && qual_ascii_max <= 74)
+    {
+        // 0 to 41, 33 based
+        return ENCODE_CASAVA_1_8;
+    }
+    else if (33 <= qual_ascii_min && qual_ascii_max <= 126)
+    {
+        // 0 to 93, 33 based
+        return ENCODE_SANGER;
+    }
+    else
+    {
+        return ENCODE_UNKNOWN;
+    }
+}
+
+QualityEncode guess_quality_encode(const std::string& quality)
+{
+    if (!quality.length()) return ENCODE_UNKNOWN;
+
+    char min = quality[0];
+    char max = quality[0];
+
+    for (size_t i = 1; i < quality.length(); i++)
+    {
+        const char curr = quality[i];
+        if (curr < min) min = curr;
+        if (max < curr) max = curr;
+    }
+
+    return guess_quality_encode(min, max);
+}
+
+QualityEncode guess_quality_encode(FastqIO& stream, size_t num_to_guess)
+{
+    FastqSeq seq;
+
+    char min = 127;
+    char max = 0;
+
+    for (size_t i = 0; i < num_to_guess; i++)
+    {
+        if (!stream.next_seq(seq)) break;
+        for (size_t i_qual = 0; i_qual < seq.quality.length(); i_qual++)
+        {
+            const char qual = seq.quality[i_qual];
+            if (qual < min) min = qual;
+            if (max < qual) max = qual;
+        }
+    }
+
+    return guess_quality_encode(min, max);
+}
+
+void get_quality_range(QualityEncode encode, int16_t& qual_from, int16_t& qual_to)
+{
+    if (encode == ENCODE_SANGER)
+    {
+        qual_from = 0;
+        qual_to = 93;
+    }
+    else if (encode == ENCODE_SOLEXA)
+    {
+        qual_from = -5;
+        qual_to = 62;
+    }
+    else if (encode == ENCODE_ILLUMINA)
+    {
+        qual_from = 0;
+        qual_to = 62;
+    }
+    else if (encode == ENCODE_CASAVA_1_8)
+    {
+        qual_from = 0;
+        qual_to = 41;
+    }
+    else
+    {
+        throw InvalidQualityEncode(encode);
+    }
+}
+
+void decode_quality(const std::string& input, std::vector<int16_t>& output, QualityEncode encode)
+{
+    int16_t offset = get_quality_offset(encode);
+    if (offset == -1) throw InvalidQualityEncode(encode);
+
+    const size_t sz = input.size();
+    output.resize(sz);
+    for (size_t i = 0; i < sz; i++)
+        output[i] = input[i] - offset;
+}
+
+void encode_quality(const std::vector<int16_t>& input, std::string& output, QualityEncode encode)
+{
+    int16_t offset = get_quality_offset(encode);
+    if (offset == -1) throw InvalidQualityEncode(encode);
+
+    const size_t sz = input.size();
+    output.resize(sz);
+    for (size_t i = 0; i < sz; i++)
+        output[i] = input[i] + offset;
+}
+
+void recode_quality(const std::string& input, std::string& output, QualityEncode encode_input, QualityEncode encode_output)
+{
+    size_t len = input.length();
+    vector<int16_t> qual_in(len);
+    vector<int16_t> qual_out(len);
+
+    decode_quality(input, qual_in, encode_input);
+
+    for (size_t i = 0; i < len; i++)
+    {
+        float p = quality_to_probability(qual_in[i], encode_input);
+        qual_out[i] = probability_to_quality(p, encode_output);
+    }
+
+    encode_quality(qual_out, output, encode_output);
+}
+
+} // namespace htio2
diff --git a/src/htio2/QualityUtil.h b/src/htio2/QualityUtil.h
new file mode 100644
index 0000000..e8c41bd
--- /dev/null
+++ b/src/htio2/QualityUtil.h
@@ -0,0 +1,150 @@
+/* 
+ * File:   QualityUtil.h
+ * Author: yangxi
+ *
+ * Created on September 26, 2013, 3:16 PM
+ */
+
+#ifndef HTIO2_QUALITY_UTIL_H
+#define	HTIO2_QUALITY_UTIL_H
+
+#include "htio2/Enum.h"
+#include <cmath>
+#include <stdint.h>
+#include <vector>
+
+namespace htio2
+{
+
+class FastqIO;
+
+
+/**
+ * guess quality encode from a range of quality
+ * @param qual_ascii_min minimum quality in ascii
+ * @param qual_ascii_max maximum quality in ascii
+ * @return
+ */
+QualityEncode guess_quality_encode(char qual_ascii_min, char qual_ascii_max);
+
+/**
+ * guess quality encode from a series of quality
+ * @param quality a series of quality in ascii
+ * @return 
+ */
+QualityEncode guess_quality_encode(const std::string& quality);
+
+QualityEncode guess_quality_encode(FastqIO& stream, size_t num_to_guess);
+
+/**
+ * get the possible range of decoded quality of a specific quality encoding
+ * @param encode
+ * @param qual_from output for minimum possible value of encode
+ * @param qual_to output for maximum possible value of encode
+ */
+void get_quality_range(QualityEncode encode, int16_t& qual_from, int16_t& qual_to);
+
+/**
+ * get the ascii offset of a specific quality encoding
+ * @param encode
+ * @return The offset. Currently there are only 33-based and 64-based. -1 for invalid encode.
+ */
+inline int16_t get_quality_offset(QualityEncode encode)
+{
+    switch (encode)
+    {
+    case ENCODE_SANGER:
+    case ENCODE_CASAVA_1_8:
+        return 33;
+    case ENCODE_SOLEXA:
+    case ENCODE_ILLUMINA:
+        return 64;
+    default:
+        return -1;
+    }
+}
+
+inline float quality_to_probability(int16_t qual, QualityEncode encode)
+{
+    float tmp = pow(10.0, float(qual) / -10.0);
+
+    switch (encode)
+    {
+    case ENCODE_SANGER:
+    case ENCODE_CASAVA_1_8:
+        return tmp;
+    case ENCODE_SOLEXA:
+    case ENCODE_ILLUMINA:
+        return tmp / (1.0 + tmp);
+    default:
+        return -1;
+    }
+}
+
+inline int16_t probability_to_quality(float p, QualityEncode encode)
+{
+    int16_t q = 0;
+    switch (encode)
+    {
+    case ENCODE_SANGER:
+    case ENCODE_CASAVA_1_8:
+        q = round(-10 * log10(p));
+        break;
+    case ENCODE_SOLEXA:
+    case ENCODE_ILLUMINA:
+        q = round(-10 * log10(p / (1.0 - p)));
+        break;
+    default:
+        q = -1;
+        break;
+    }
+
+    if (encode == ENCODE_CASAVA_1_8)
+    {
+        if (q < 2) q = 2;
+        else if (q > 41) q = 41;
+    }
+
+    return q;
+}
+
+/**
+ * decode ascii quality
+ * @param data quality in ascii
+ * @param encode
+ * @return decoded quality
+ */
+inline int16_t decode_quality(char data, QualityEncode encode)
+{
+    return data - get_quality_offset(encode);
+}
+
+/**
+ * decode a series of ascii quality
+ * @param input a series of quality in ascii
+ * @param output a series of decoded quality
+ * @param encode
+ */
+void decode_quality(const std::string& input, std::vector<int16_t>& output, QualityEncode encode);
+
+/**
+ * encode a series of quality to ascii
+ * @param input a series of quality
+ * @param output a series of quality in ascii
+ * @param encode
+ */
+void encode_quality(const std::vector<int16_t>& input, std::string& output, QualityEncode encode);
+
+/**
+ * 
+ * @param input
+ * @param output
+ * @param encode_input
+ * @param encode_output
+ */
+void recode_quality(const std::string& input, std::string& output, QualityEncode encode_input, QualityEncode encode_output);
+
+} // namespace htio2
+
+#endif	/* HTIO2_QUALITY_UTIL_H */
+
diff --git a/src/htio2/RefCounted.cpp b/src/htio2/RefCounted.cpp
new file mode 100644
index 0000000..1b46877
--- /dev/null
+++ b/src/htio2/RefCounted.cpp
@@ -0,0 +1,12 @@
+#include "htio2/RefCounted.h"
+
+namespace htio2
+{
+
+RefCounted::RefCounted(): counter() { }
+
+RefCounted::RefCounted(const RefCounted &other): counter() { }
+
+RefCounted::~RefCounted() { }
+
+} // namespace htio2
diff --git a/src/htio2/RefCounted.h b/src/htio2/RefCounted.h
new file mode 100644
index 0000000..1b69ddf
--- /dev/null
+++ b/src/htio2/RefCounted.h
@@ -0,0 +1,156 @@
+#ifndef HTIO2_REF_COUNTED_H
+#define	HTIO2_REF_COUNTED_H
+
+#include <stdint.h>
+#include "JUCE-3.0.8/JuceHeader.h"
+
+class TestFramework;
+
+namespace htio2
+{
+
+class RefCounted
+{
+    friend class ::TestFramework;
+public:
+    RefCounted();
+    RefCounted(const RefCounted& other);
+    virtual ~RefCounted();
+
+    RefCounted& operator=(const RefCounted& other);
+
+    inline void ref() const;
+    inline void unref() const;
+    inline uint32_t get_ref_count() const;
+
+private:
+    mutable juce::Atomic<uint32_t> counter;
+};
+
+inline RefCounted& RefCounted::operator=(const RefCounted& other)
+{
+    return *this;
+}
+
+inline void RefCounted::ref() const
+{
+    ++counter;
+}
+
+inline void RefCounted::unref() const
+{
+    if (--counter == 0)
+        delete this;
+}
+
+inline uint32_t RefCounted::get_ref_count() const
+{ return counter.get(); }
+
+inline void intrusive_ptr_add_ref(RefCounted* self)
+{ self->ref(); }
+
+inline void intrusive_ptr_release(RefCounted* self)
+{ self->unref(); }
+
+inline void smart_ref(const RefCounted* obj)
+{ obj->ref(); }
+
+inline void smart_unref(const RefCounted* obj)
+{ obj->unref(); }
+
+template <typename T>
+class SmartPtr
+{
+    friend class RefCounted;
+    friend class __tester__;
+    template<typename T1, typename T2>
+    friend bool operator == (const SmartPtr<T1>& a, const SmartPtr<T2>& b);
+    template<typename T1, typename T2>
+    friend bool operator < (const SmartPtr<T1>& a, const SmartPtr<T2>& b);
+public:
+    SmartPtr(): m_obj(0) {}
+
+    SmartPtr(T* obj): m_obj(obj)
+    {
+        if (m_obj)
+            smart_ref(m_obj);
+    }
+
+    SmartPtr(const SmartPtr& other): m_obj(other.m_obj)
+    {
+        if (m_obj)
+            smart_ref(m_obj);
+    }
+
+    ~SmartPtr()
+    {
+        if (m_obj)
+            smart_unref(m_obj);
+    }
+
+    SmartPtr& operator = (const SmartPtr& other)
+    {
+        if (m_obj)
+            smart_unref(m_obj);
+
+        m_obj = other.m_obj;
+
+        if (m_obj)
+            smart_ref(m_obj);
+
+        return *this;
+    }
+
+    SmartPtr& operator = (T* other)
+    {
+        if (m_obj)
+            smart_unref(m_obj);
+
+        m_obj = other;
+
+        if (m_obj)
+            smart_ref(m_obj);
+
+        return *this;
+    }
+
+    operator bool() const
+    {
+        return m_obj;
+    }
+
+    T* get() const
+    {
+        return m_obj;
+    }
+
+    T& operator*() const
+    {
+        return *m_obj;
+    }
+
+    T* operator->() const
+    {
+        return m_obj;
+    }
+
+protected:
+    T* m_obj;
+};
+
+template<typename T1, typename T2>
+bool operator == (const SmartPtr<T1>& a, const SmartPtr<T2>& b)
+{
+    return a.m_obj == b.m_obj;
+}
+
+template<typename T1, typename T2>
+bool operator < (const SmartPtr<T1>& a, const SmartPtr<T2>& b)
+{
+    return a.m_obj < b.m_obj;
+}
+
+} // namespace htio2
+
+#endif	/* HTIO2_REF_COUNTED_H */
+
diff --git a/src/htio2/RingBuffer.h b/src/htio2/RingBuffer.h
new file mode 100644
index 0000000..7445ff4
--- /dev/null
+++ b/src/htio2/RingBuffer.h
@@ -0,0 +1,95 @@
+#ifndef HTIO2_RING_BUFFER_H
+#define HTIO2_RING_BUFFER_H
+
+#include <stdint.h>
+#include <limits>
+#include "JUCE-3.0.8/JuceHeader.h"
+
+namespace htio2
+{
+
+/**
+ * A single-reader single-writer fixed-size ring buffer
+ */
+template <typename T>
+class RingBuffer
+{
+public:
+    RingBuffer(size_t capacity)
+        : _capacity(capacity)
+        , _size(0)
+        , _i_read_seed(0)
+        , _i_write_seed(0)
+        , _data(new T[capacity])
+    {}
+
+    ~RingBuffer()
+    {
+        delete[] _data;
+    }
+
+    bool push(T value)
+    {
+        if (_size.get() >= _capacity)
+            return false;
+
+        // modify data
+        ssize_t i_write = _i_write_seed;
+        _data[i_write] = value;
+
+        // move write index
+        _i_write_seed = (i_write + 1) % _capacity;
+
+        // update size at last
+        ++_size;
+
+        return true;
+    }
+
+    bool pop(T& result)
+    {
+        if (_size.get() <= 0)
+            return false;
+
+        // read data
+        ssize_t i_read = _i_read_seed;
+        result = _data[i_read];
+
+        // move read index
+        _i_read_seed = (i_read + 1) % _capacity;
+
+        // update size at last
+        --_size;
+
+        return true;
+    }
+
+    void push_sync(T value)
+    {
+        while (!push(value))
+            juce::Thread::yield();
+    }
+
+    void pop_sync(T& result)
+    {
+        while (!pop(result))
+            juce::Thread::yield();
+    }
+
+    ssize_t size()
+    {
+        return _size.value;
+    }
+
+
+protected:
+    T* _data;
+    const size_t _capacity;
+    juce::Atomic<ssize_t> _size;
+    size_t _i_read_seed;
+    size_t _i_write_seed;
+};
+
+} // namespace htio2
+
+#endif // HTIO2_RING_BUFFER_H
diff --git a/src/htio2/SeqIO.cpp b/src/htio2/SeqIO.cpp
new file mode 100644
index 0000000..e9a6033
--- /dev/null
+++ b/src/htio2/SeqIO.cpp
@@ -0,0 +1,99 @@
+#include "htio2/SeqIO.h"
+#include "htio2/Error.h"
+#include "htio2/FormatUtil.h"
+#include "htio2/GzipFileHandle.h"
+#include "htio2/PlainFileHandle.h"
+#include "htio2/FastqIO.h"
+#include "htio2/FastaIO.h"
+#include <zlib.h>
+#include <stdexcept>
+
+using namespace std;
+
+namespace htio2
+{
+
+SeqIO::SeqIO(const std::string& file, IOMode mode, CompressFormat comp)
+{
+    if (comp == COMPRESS_UNKNOWN)
+        comp = guess_compress_by_name(file);
+
+    if (comp == COMPRESS_GZIP)
+        handle = new GzipFileHandle(file.c_str(), mode);
+    else if (comp == COMPRESS_PLAIN)
+        handle = new PlainFileHandle(file.c_str(), mode);
+    else
+        throw InvalidCompressFormat(comp);
+}
+
+SeqIO::SeqIO(FileHandle* handle)
+: handle(handle)
+{
+}
+
+SeqIO::SeqIO(FILE* handle, bool auto_close)
+: handle(new PlainFileHandle(handle, auto_close))
+{
+}
+
+SeqIO::SeqIO(gzFile handle, bool auto_close)
+: handle(new GzipFileHandle(handle, auto_close))
+{
+}
+
+SeqIO* SeqIO::New(const std::string& file, IOMode mode, CompressFormat comp)
+{
+    SeqFormat format = htio2::FORMAT_UNKNOWN;
+    if (mode == htio2::READ)
+        format = guess_format_by_name_and_content(file, comp);
+    else
+        format = guess_format_by_name(file);
+
+    if (format == FORMAT_FASTQ)
+        return new FastqIO(file, mode, comp);
+    else if (format == FORMAT_FASTA)
+        return new FastaIO(file, mode, comp);
+    else
+        throw InvalidSeqFormat(format);
+}
+
+SeqIO* SeqIO::New(FileHandle* handle)
+{
+    SeqFormat format = guess_format_by_content(*handle);
+    switch (format)
+    {
+    case FORMAT_FASTA:
+        return new FastaIO(handle);
+    case FORMAT_FASTQ:
+        return new FastqIO(handle);
+    default:
+        throw InvalidSeqFormat(format);
+    }
+}
+
+SeqIO* SeqIO::New(FILE* handle, bool auto_close)
+{
+    return SeqIO::New(new PlainFileHandle(handle, auto_close));
+}
+
+SeqIO* SeqIO::New(gzFile handle, bool auto_close)
+{
+    return SeqIO::New(new GzipFileHandle(handle, auto_close));
+}
+
+SeqIO::~SeqIO()
+{
+    delete handle;
+}
+
+void SeqIO::seek(off_t offset, int whence)
+{
+    handle->seek(offset, whence);
+}
+
+off_t SeqIO::tell() const
+{
+    return handle->tell();
+}
+
+} // namespace htio2
diff --git a/src/htio2/SeqIO.h b/src/htio2/SeqIO.h
new file mode 100644
index 0000000..dccd50a
--- /dev/null
+++ b/src/htio2/SeqIO.h
@@ -0,0 +1,139 @@
+#ifndef HTIO2_SEQ_IO_H
+#define	HTIO2_SEQ_IO_H
+
+#include <zlib.h>
+
+#include "htio2/Enum.h"
+#include "htio2/RefCounted.h"
+
+
+namespace htio2
+{
+
+class SimpleSeq;
+class FastqSeq;
+class FileHandle;
+
+
+class SeqIO : public RefCounted
+{
+public:
+    typedef SmartPtr<SeqIO> Ptr;
+    typedef SmartPtr<const SeqIO> ConstPtr;
+
+public:
+    /**
+     * create sequence IO object by file name
+     * @param file file to open
+     * @param mode read/write/append
+     * @param comp compress format. COMPRESS_UNKNOWN for automatically guess.
+     */
+    SeqIO(const std::string& file, IOMode mode, CompressFormat comp = COMPRESS_UNKNOWN);
+
+    /**
+     * create sequence IO object from HTIO file handle object
+     * @param handle
+     */
+    SeqIO(FileHandle* handle);
+
+    /**
+     * create sequence IO object from C standard file handle
+     * @param handle
+     * @param auto_close if set to true, the underlying handle will be closed when sequence IO object is destroyed
+     */
+    SeqIO(FILE* handle, bool auto_close = true);
+
+    /**
+     * create sequence IO object from Zlib file handle
+     * @param handle
+     * @param auto_close if set to true, the underlying handle will be closed when sequence IO object is destroyed
+     */
+    SeqIO(gzFile handle, bool auto_close = true);
+
+    /**
+     * Create a sequence IO object. The sequence format is automatically guessed by file name and/or content.
+     * @param file filename
+     * @param mode READ/WRITE/APPEND
+     * @param comp compress format. COMPRESS_UNKNOWN for automatically guess.
+     * @return the newly created sequence IO object
+     */
+    static SeqIO* New(const std::string& file, IOMode mode, CompressFormat comp = COMPRESS_UNKNOWN);
+
+    /**
+     * Create a sequence IO object from HTIO FileHandle object. The sequence format is automatically guessed by file content.
+     * @param handle HTIO FileHandle object. Must be readable.
+     * @return the newly created sequence IO object
+     */
+    static SeqIO* New(FileHandle* handle);
+
+    /**
+     * Create a sequence IO object from C standard file handle. The sequence format is automatically guessed by file content.
+     * @param handle C standard file handle. Must be readable.
+     * @param auto_close If set to true, the underlying handle will be closed when the sequence IO object is destroyed.
+     * @return 
+     */
+    static SeqIO* New(FILE* handle, bool auto_close = true);
+
+    /**
+     * Create a sequence IO object from Zlib file handle. The sequence format is automatically guessed by file content.
+     * @param handle Zlib file handle
+     * @param auto_close If set to true, the underlying handle will be closed when the sequence IO object is destroyed.
+     * @return 
+     */
+    static SeqIO* New(gzFile handle, bool auto_close = true);
+
+    virtual ~SeqIO();
+
+    /**
+     * Seek to a file offset.
+     * @param offset
+     * @param whence 0 for absolute, 1 for relative
+     */
+    virtual void seek(off_t offset, int whence = SEEK_SET);
+
+    /**
+     * get the current file offset
+     * @return file offset.
+     */
+    virtual off_t tell() const;
+
+
+    /**
+     * read one sequence
+     * @param result
+     * @return true if got a seq, false if reached end of file
+     */
+    virtual bool next_seq(SimpleSeq& output) = 0;
+
+    /**
+     * read one sequence with quality
+     * @param result
+     * @return true if got a seq, false if reached end of file
+     */
+    virtual bool next_seq(FastqSeq& output) = 0;
+
+    /**
+     * write one sequence
+     * @param seq the sequence to be written
+     */
+    virtual void write_seq(const SimpleSeq& seq) = 0;
+
+    /**
+     * write one sequence
+     * @param seq the sequence to be written
+     */
+    virtual void write_seq(const FastqSeq& seq) = 0;
+
+protected:
+    FileHandle* handle;
+    std::string buffer;
+
+private:
+    SeqIO(const SeqIO& other);
+    SeqIO& operator =(const SeqIO& other);
+};
+
+} // namespace htio2
+
+#endif	/* HTIO2_SEQ_IO_H */
+
diff --git a/src/htio2/SimpleSeq.cpp b/src/htio2/SimpleSeq.cpp
new file mode 100644
index 0000000..320a191
--- /dev/null
+++ b/src/htio2/SimpleSeq.cpp
@@ -0,0 +1,89 @@
+/*
+ * File:   FastaSeq.cpp
+ * Author: yangxi
+ *
+ * Created on December 25, 2012, 3:15 PM
+ */
+
+#include "htio2/SimpleSeq.h"
+#include "Error.h"
+
+namespace htio2
+{
+
+void revcom(const std::string& in, std::string& out)
+{
+    out.clear();
+    out.reserve(in.size());
+    for (int i = in.size() - 1; i >= 0; i--)
+    {
+        char comp = 0;
+        switch (in[i])
+        {
+        case 'A':
+            comp = 'T';
+            break;
+        case 'a':
+            comp = 't';
+            break;
+        case 'T':
+            comp = 'A';
+            break;
+        case 't':
+            comp = 'a';
+            break;
+        case 'G':
+            comp = 'C';
+            break;
+        case 'g':
+            comp = 'c';
+            break;
+        case 'C':
+            comp = 'G';
+            break;
+        case 'c':
+            comp = 'g';
+            break;
+        case 'N':
+            comp = 'N';
+            break;
+        case 'n':
+            comp = 'n';
+            break;
+        }
+        if (!comp)
+            throw InvalidRevcom(in);
+        out.push_back(comp);
+    }
+}
+
+SimpleSeq::SimpleSeq()
+{
+}
+
+SimpleSeq::SimpleSeq(const std::string& id, const std::string& desc, const std::string& seq) :
+id(id),
+desc(desc),
+seq(seq)
+{
+}
+
+SimpleSeq::~SimpleSeq()
+{
+}
+
+void SimpleSeq::revcom(SimpleSeq& result) const
+{
+    result.id = id;
+    result.desc = desc;
+    htio2::revcom(seq, result.seq);
+}
+
+void SimpleSeq::subseq(SimpleSeq& result, size_t start, size_t length) const
+{
+    result.id = id;
+    result.desc = desc;
+    result.seq.assign(seq, start, length);
+}
+
+} // namespace htio2
diff --git a/src/htio2/SimpleSeq.h b/src/htio2/SimpleSeq.h
new file mode 100644
index 0000000..f726fc1
--- /dev/null
+++ b/src/htio2/SimpleSeq.h
@@ -0,0 +1,87 @@
+#ifndef HTIO2_SIMPLE_SEQ_H
+#define	HTIO2_SIMPLE_SEQ_H
+
+#include <string>
+
+#include "htio2/RefCounted.h"
+
+namespace htio2
+{
+
+/**
+ * generate reverse complement nucleotide sequence
+ * @param in input sequence
+ * @param out output result
+ */
+void revcom(const std::string& in, std::string& out);
+
+/**
+ * @brief a simple sequence class with ID, description and sequence content
+ */
+class SimpleSeq : public RefCounted
+{
+public:
+    typedef SmartPtr<SimpleSeq> Ptr;
+    typedef SmartPtr<const SimpleSeq> ConstPtr;
+
+public:
+    /**
+     * Create an empty sequence object
+     */
+    SimpleSeq();
+
+    /**
+     * create an sequence object with ID, description and sequence
+     * @param id
+     * @param desc
+     * @param seq
+     */
+    SimpleSeq(const std::string& id, const std::string& desc, const std::string& seq);
+    virtual ~SimpleSeq();
+
+    /**
+     * get sequence length
+     * @return sequence length
+     */
+    inline size_t length() const
+    {
+        return seq.length();
+    }
+    /**
+     * generate reverse complement sequence
+     * @param result
+     */
+    void revcom(SimpleSeq& result) const;
+
+    /**
+     * @brief subseq
+     * @param result
+     * @param start
+     * @param length
+     */
+    void subseq(std::string& result, size_t start, size_t length = std::string::npos) const;
+
+    /**
+     * get part of the sequence
+     * @param result
+     * @param start the start of sub sequence, 0 for the first base
+     * @param length the length of sub sequence
+     */
+    void subseq(SimpleSeq& result, size_t start, size_t length = std::string::npos) const;
+
+    std::string id;
+    std::string desc;
+    std::string seq;
+private:
+
+};
+
+inline void SimpleSeq::subseq(std::string& result, size_t start, size_t length) const
+{
+    result.assign(seq, start, length);
+}
+
+} // namespace htio2
+
+#endif	/* HTIO2_SIMPLE_SEQ_H */
+
diff --git a/src/htio2/StringUtil.cpp b/src/htio2/StringUtil.cpp
new file mode 100644
index 0000000..e5a0e96
--- /dev/null
+++ b/src/htio2/StringUtil.cpp
@@ -0,0 +1,34 @@
+#include "htio2/StringUtil.h"
+
+using namespace std;
+
+namespace htio2
+{
+
+string to_upper_case(const std::string& input)
+{
+    string result(input.size(), '\0');
+    for (size_t i = 0; i < input.size(); i++)
+    {
+        char chr = input[i];
+        if ('a' <= chr && chr <= 'z')
+            chr -= 'a' - 'A';
+        result[i] = chr;
+    }
+    return result;
+}
+
+string to_lower_case(const std::string& input)
+{
+    string result(input.size(), '\0');
+    for (size_t i = 0; i < input.size(); i++)
+    {
+        char chr = input[i];
+        if ('A' <= chr && chr <= 'Z')
+            chr += 'a' - 'A';
+        result[i] = chr;
+    }
+    return result;
+}
+
+} // namespace htio2
diff --git a/src/htio2/StringUtil.h b/src/htio2/StringUtil.h
new file mode 100644
index 0000000..713f6cf
--- /dev/null
+++ b/src/htio2/StringUtil.h
@@ -0,0 +1,55 @@
+#ifndef HTIO2_STRING_UTIL_H
+#define HTIO2_STRING_UTIL_H
+
+#include <string>
+#include <vector>
+
+namespace htio2
+{
+
+#define STRINGIFY(content) #content
+#define EXPAND_AND_STRINGIFY(input) STRINGIFY(input)
+
+std::string to_upper_case(const std::string& input);
+std::string to_lower_case(const std::string& input);
+
+template <typename iterator_t>
+std::string join(const std::string& delim, iterator_t input_begin, iterator_t input_end)
+{
+    std::string result;
+    for (iterator_t it = input_begin; it != input_end; it++)
+    {
+        if (it != input_begin)
+            result += delim;
+        result += *it;
+    }
+    return result;
+}
+
+template <typename container_t>
+void split(const std::string& input, char delim, container_t& output)
+{
+    if (!input.length())
+        return;
+
+    size_t search_from = 0;
+    for (;;)
+    {
+        size_t i_delim = input.find(delim, search_from);
+
+        if (i_delim == std::string::npos)
+        {
+            output.push_back(input.substr(search_from));
+            break;
+        }
+        else
+        {
+            output.push_back(input.substr(search_from, i_delim - search_from));
+            search_from = i_delim + 1;
+        }
+    }
+}
+
+} // namespace htio2
+
+#endif // HTIO2_STRING_UTIL_H
diff --git a/src/htio2/Version.cpp b/src/htio2/Version.cpp
new file mode 100644
index 0000000..fa443f0
--- /dev/null
+++ b/src/htio2/Version.cpp
@@ -0,0 +1,18 @@
+#include "htio2/Version.h"
+#include "htio2/config.h"
+
+#include <sstream>
+
+using namespace std;
+
+namespace htio2
+{
+
+std::string get_version_string()
+{
+    ostringstream result;
+    result << HTIO_VERSION_MAJOR << "." << HTIO_VERSION_MINOR << "." << HTIO_VERSION_PATCH;
+    return result.str();
+}
+
+} // namespace htio2
diff --git a/src/htio2/Version.h b/src/htio2/Version.h
new file mode 100644
index 0000000..d31b1a8
--- /dev/null
+++ b/src/htio2/Version.h
@@ -0,0 +1,18 @@
+#ifndef HTIO2_VERSION_H
+#define	HTIO2_VERSION_H
+
+#include <string>
+
+namespace htio2
+{
+
+/**
+ * get the version of HTIO library
+ * @return version string formatted in "MAJOR.MINOR.PATCH"
+ */
+std::string get_version_string();
+
+} // namespace htio2
+
+#endif	/* HTIO2_VERSION_H */
+
diff --git a/src/htio2/config.h.in b/src/htio2/config.h.in
new file mode 100644
index 0000000..d3f0583
--- /dev/null
+++ b/src/htio2/config.h.in
@@ -0,0 +1,8 @@
+#ifndef HTIO_CONFIG_H
+#define HTIO_CONFIG_H
+
+#define HTIO_VERSION_MAJOR @CPACK_PACKAGE_VERSION_MAJOR@
+#define HTIO_VERSION_MINOR @CPACK_PACKAGE_VERSION_MINOR@
+#define HTIO_VERSION_PATCH @CPACK_PACKAGE_VERSION_PATCH@
+
+#endif
diff --git a/src/htqc/App.cpp b/src/htqc/App.cpp
new file mode 100644
index 0000000..cde576b
--- /dev/null
+++ b/src/htqc/App.cpp
@@ -0,0 +1,41 @@
+#include "htqc/App.h"
+#include "htio2/Cast.h"
+
+using namespace htqc;
+using namespace std;
+
+int main(int argc, char** argv)
+{
+    // parse and validate options
+    parse_options(argc, argv);
+    validate_options();
+
+    // guess compression by input files
+    OPT_compress = guess_compress_format_by_files_name(OPT_files_in);
+    if (OPT_compress == htio2::COMPRESS_UNKNOWN)
+    {
+        cerr << "ERROR: failed to guess compress format from input files" << endl;
+        exit(EXIT_FAILURE);
+    }
+
+    // show options
+    if (!OPT_quiet)
+    {
+        std::cout << std::endl
+                  << "#---------------------------------#" << std::endl
+                  << "#" << std::endl
+                  << "# Options:" << std::endl
+                  << "#" << std::endl;
+        show_options();
+        std::cout << "# compress: " << htio2::to_string(OPT_compress) << std::endl
+                  << "#" << std::endl
+                  << "#---------------------------------#" << std::endl
+                  << std::endl;
+    }
+
+    // run
+    if (!OPT_quiet) std::cout << "start processing" << std::endl;
+    execute();
+    if (!OPT_quiet) std::cout << "done" << std::endl;
+}
+
diff --git a/src/htqc/App.h b/src/htqc/App.h
new file mode 100644
index 0000000..2ab1305
--- /dev/null
+++ b/src/htqc/App.h
@@ -0,0 +1,14 @@
+#ifndef HTQC_APP_H
+#define	HTQC_APP_H
+
+#include <iostream>
+
+#include "htqc/Options.h"
+
+void parse_options(int argc, char** argv);
+void validate_options();
+void show_options();
+void execute();
+
+#endif	/* HTQC_APP_H */
+
diff --git a/src/htqc/BaseQualCounter.cpp b/src/htqc/BaseQualCounter.cpp
new file mode 100644
index 0000000..9190d6a
--- /dev/null
+++ b/src/htqc/BaseQualCounter.cpp
@@ -0,0 +1,112 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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 "htqc/BaseQualCounter.h"
+#include "htio2/QualityUtil.h"
+
+using namespace htqc;
+using namespace std;
+
+BaseCounter& BaseCounter::operator+=(const htqc::BaseCounter& other)
+{
+    a += other.a;
+    t += other.t;
+    g += other.g;
+    c += other.c;
+    n += other.n;
+    mask += other.mask;
+    return *this;
+}
+
+TileQualCounter& TileQualCounter::operator+=(const htqc::TileQualCounter& other)
+{
+    num_reads_10 += other.num_reads_10;
+    num_reads_10_20 += other.num_reads_10_20;
+    num_reads_20_30 += other.num_reads_20_30;
+    num_reads_30 += other.num_reads_30;
+    return *this;
+}
+
+BaseQualCounter::BaseQualCounter(htio2::QualityEncode encode)
+: key_max(-1)
+, from(-1)
+, to(-1)
+{
+    htio2::get_quality_range(encode, from, to);
+    key_max = to - from;
+    counter.resize(key_max + 1, 0);
+}
+
+void BaseQualCounter::create_chart(BaseQualBoxChart& chart) const
+{
+    long num_seq = 0;
+    for (int qual = from; qual <= to; qual++)
+    {
+        num_seq += get_num(qual);
+    }
+
+    long i_dec_low = num_seq / 10;
+    long i_quat_low = num_seq / 4;
+    long i_median = num_seq / 2;
+    long i_quat_high = num_seq * 3 / 4;
+    long i_dec_high = num_seq * 9 / 10;
+
+    long seq_sum = 0;
+    long qual_sum = 0;
+    for (int qual = from; qual <= to; qual++)
+    {
+        long num = get_num(qual);
+        long seq_sum_next = seq_sum + num;
+        qual_sum += qual*num;
+
+        if (seq_sum < i_dec_low && i_dec_low <= seq_sum_next)
+        {
+            chart.dec_low = qual;
+        }
+        if (seq_sum < i_quat_low && i_quat_low <= seq_sum_next)
+        {
+            chart.quat_low = qual;
+        }
+        if (seq_sum < i_median && i_median <= seq_sum_next)
+        {
+            chart.median = qual;
+        }
+        if (seq_sum < i_quat_high && i_quat_high <= seq_sum_next)
+        {
+            chart.quat_high = qual;
+        }
+        if (seq_sum < i_dec_high && i_dec_high <= seq_sum_next)
+        {
+            chart.dec_high = qual;
+        }
+
+        seq_sum = seq_sum_next;
+    }
+
+    if (num_seq == 0)
+        chart.mean = 0;
+    else
+        chart.mean = double(qual_sum) / double(num_seq);
+}
+
+BaseQualCounter& BaseQualCounter::operator+=(const htqc::BaseQualCounter& other)
+{
+    for (int i = 0; i < other.counter.size(); i++)
+    {
+        counter[i] += other.counter[i];
+    }
+    return *this;
+}
diff --git a/src/htqc/BaseQualCounter.h b/src/htqc/BaseQualCounter.h
new file mode 100644
index 0000000..1e3b532
--- /dev/null
+++ b/src/htqc/BaseQualCounter.h
@@ -0,0 +1,112 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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/>.
+
+
+#ifndef HTQC_BASEQUALCOUNTER_H
+#define HTQC_BASEQUALCOUNTER_H
+
+#include "htqc/Common.h"
+
+namespace htqc
+{
+
+class BaseCounter
+{
+public:
+
+    BaseCounter(): a(0), t(0), g(0), c(0), n(0), mask(0) { }
+    long a;
+    long t;
+    long g;
+    long c;
+    long n;
+    long mask;
+
+    BaseCounter& operator+=(const BaseCounter& other);
+};
+
+class TileQualCounter
+{
+public:
+
+    TileQualCounter()
+    : num_reads_10(0)
+    , num_reads_10_20(0)
+    , num_reads_20_30(0)
+    , num_reads_30(0) { }
+
+    inline void record(int qual)
+    {
+        if (qual < 10) num_reads_10++;
+        else if (qual < 20) num_reads_10_20++;
+        else if (qual < 30) num_reads_20_30++;
+        else num_reads_30++;
+    }
+    long num_reads_10;
+    long num_reads_10_20;
+    long num_reads_20_30;
+    long num_reads_30;
+    TileQualCounter& operator+=(const TileQualCounter& other);
+};
+
+typedef struct
+{
+    int dec_low;
+    int quat_low;
+    int median;
+    int quat_high;
+    int dec_high;
+    float mean;
+} BaseQualBoxChart;
+
+class BaseQualCounter
+{
+public:
+
+    BaseQualCounter(htio2::QualityEncode encode);
+
+    inline void record(int qual)
+    {
+        int key = qual - from;
+        if (key > key_max || key < 0)
+        {
+            char err_msg[2048];
+            std::sprintf(err_msg, "invalid quality: %d (key %d), valid range %d - %d", qual, key, from, to);
+            throw std::runtime_error(std::string(err_msg));
+        }
+        counter[key]++;
+    }
+
+    inline long get_num(int qual) const
+    {
+        int key = qual - from;
+        return counter[key];
+    }
+
+    void create_chart(BaseQualBoxChart& chart) const;
+
+    BaseQualCounter& operator+=(const BaseQualCounter& other);
+
+protected:
+    std::vector<long> counter;
+
+    int key_max;
+    int16_t from;
+    int16_t to;
+};
+
+}
+
+#endif // HTQC_BASEQUALCOUNTER_H
diff --git a/src/htqc/Common.cpp b/src/htqc/Common.cpp
new file mode 100644
index 0000000..21e1ae9
--- /dev/null
+++ b/src/htqc/Common.cpp
@@ -0,0 +1,96 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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 "htqc/Common.h"
+#include "htio2/JUCE-3.0.8/JuceHeader.h"
+
+using namespace std;
+using namespace htio2;
+
+namespace htqc
+{
+const int LOG_BLOCK = 50000;
+const size_t NUM_GUESS = 500;
+
+std::string bool_to_string(bool value)
+{
+    return value ? "T" : "F";
+}
+
+void check_output_overwrite(const std::vector<std::string>& files_in,
+                            const std::string& file_out)
+{
+    for (size_t i = 0; i < files_in.size(); i++)
+    {
+        if (juce::File(files_in[i]) == juce::File(file_out))
+        {
+            cerr << "output file \"" << file_out << "\" will overwrite input file \"" << files_in[i] << "\"" << endl;
+            exit(EXIT_FAILURE);
+        }
+    }
+}
+
+void separate_paired_files(const std::vector<std::string>& in, std::vector<std::string>& names_a, std::vector<std::string>& names_b)
+{
+    size_t size = in.size();
+
+    if (size % 2)
+    {
+        cerr << "ERROR: odd number of files for paired-end mode: " << size << endl;
+        for (int i = 0; i < size; i++)
+        {
+            cerr << "  " << in[i] << endl;
+        }
+        exit(EXIT_FAILURE);
+    }
+
+    int half = size / 2;
+
+    for (int i = 0; i < half; i++)
+        names_a.push_back(in[i]);
+
+    for (int i = half; i < size; i++)
+        names_b.push_back(in[i]);
+}
+
+void add_fastq_suffix_se(const std::string& prefix,
+                         htio2::CompressFormat comp,
+                         std::string& file)
+{
+    file = prefix + ".fastq";
+    if (comp == htio2::COMPRESS_GZIP)
+        file += ".gz";
+}
+
+void add_fastq_suffix_pe(const std::string& prefix,
+                         htio2::CompressFormat comp,
+                         std::string& file1,
+                         std::string& file2)
+{
+    file1 = prefix + "_1.fastq";
+    file2 = prefix + "_2.fastq";
+    if (comp == htio2::COMPRESS_GZIP)
+    {
+        file1 += ".gz";
+        file2 += ".gz";
+    }
+}
+
+} // namespace htqc
+
+
+
+
+
+
diff --git a/src/htqc/Common.h b/src/htqc/Common.h
new file mode 100644
index 0000000..1ec41f8
--- /dev/null
+++ b/src/htqc/Common.h
@@ -0,0 +1,63 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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/>.
+#ifndef HTQC_COMMON_H
+#define HTQC_COMMON_H
+
+#include "ht_config.h"
+#include "htio2/Enum.h"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <stdexcept>
+#include <vector>
+#include <map>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <stdint.h>
+
+#define CACHE_LINE_ALIGNMENT __attribute__ ((aligned (32)))
+
+namespace htqc
+{
+
+extern const int LOG_BLOCK;
+extern const size_t NUM_GUESS;
+
+std::string bool_to_string(bool value);
+
+void check_output_overwrite(const std::vector<std::string>& files_in,
+                            const std::string& file_out);
+
+void separate_paired_files(const std::vector<std::string>& in,
+                           std::vector<std::string>& names_a,
+                           std::vector<std::string>& names_b);
+
+void add_fastq_suffix_se(const std::string& prefix,
+                         htio2::CompressFormat comp,
+                         std::string& file);
+
+void add_fastq_suffix_pe(const std::string& prefix,
+                         htio2::CompressFormat comp,
+                         std::string& file1,
+                         std::string& file2);
+
+}
+
+
+#endif
diff --git a/src/htqc/FastqStat.cpp b/src/htqc/FastqStat.cpp
new file mode 100644
index 0000000..cbc91d8
--- /dev/null
+++ b/src/htqc/FastqStat.cpp
@@ -0,0 +1,184 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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 <vector>
+
+#include "htqc/FastqStat.h"
+#include "htio2/QualityUtil.h"
+
+using namespace htio2;
+using namespace std;
+
+namespace htqc
+{
+
+FastqStat::FastqStat(bool mask, QualityEncode encode, HeaderFormat h_format, bool h_sra) :
+header_parser(h_format, h_sra),
+encode(encode),
+observed_max_len(0),
+qual_mask(mask),
+read_quals(),
+read_qual_counter(encode)
+{
+    get_quality_range(encode, qual_from, qual_to);
+}
+
+FastqStat::~FastqStat()
+{
+}
+
+void FastqStat::record_seq(FastqSeq& seq)
+{
+    // validate length
+    int len = seq.length();
+    if (len > observed_max_len)
+        try_expand_store(len);
+
+    //
+    // parse lane and tile
+    //
+    header_parser.parse(seq.id, seq.desc);
+
+    //
+    //
+    // traverse through bases
+    int valid_len = 0;
+    float qual_sum = 0;
+
+    for (int i = 0; i < len; i++)
+    {
+        // get quality
+        int qual = decode_quality(seq.quality[i], encode);
+        if (qual == 0)
+        {
+            printf("");
+        }
+
+        //base_qual_counter[i].record(qual);
+        base_qual_counter.at(i).record(qual);
+
+        // check mask
+        if (qual_mask)
+        {
+            if (qual < 2)
+            {
+                cerr << "for quality score with mask, values below 2 are not used, but we got " << qual << " in " << seq.id << endl;
+                throw runtime_error("invalid base quality");
+            }
+            else if (qual == 2)
+            {
+                base_compo_counter[i].mask++;
+                continue;
+            }
+        }
+
+        // add base quality to read quality
+        valid_len++;
+        qual_sum += qual;
+
+        // record base composition
+        switch (seq.seq[i])
+        {
+        case 'A':
+        case 'a':
+            base_compo_counter[i].a++;
+            break;
+        case 'T':
+        case 't':
+            base_compo_counter[i].t++;
+            break;
+        case 'G':
+        case 'g':
+            base_compo_counter[i].g++;
+            break;
+        case 'C':
+        case 'c':
+            base_compo_counter[i].c++;
+            break;
+        case 'N':
+        case 'n':
+            base_compo_counter[i].n++;
+            break;
+        }
+    }
+
+    // record length
+    read_len_counter.at(valid_len)++;
+
+    // calculate and record read quality
+    float read_qual = qual_sum / len;
+    read_quals.push_back(read_qual);
+    read_qual_counter.record(int(read_qual));
+    tile_read_qual_counter[header_parser.lane][header_parser.tile].record(int(read_qual));
+}
+
+FastqStat& FastqStat::operator+=(const htqc::FastqStat& other)
+{
+    if (observed_max_len < other.observed_max_len) try_expand_store(other.observed_max_len);
+    if (encode != other.encode) throw runtime_error("encode not same");
+    if (qual_mask != other.qual_mask) throw runtime_error("qual_mask not same");
+
+    read_quals.reserve(read_quals.size() + other.read_quals.size());
+    for (std::vector<float>::const_iterator it = other.read_quals.begin(); it != other.read_quals.end(); it++)
+    {
+        read_quals.push_back(*it);
+    }
+
+    for (int i = 0; i < observed_max_len; i++)
+    {
+        base_qual_counter[i] += other.base_qual_counter[i];
+        base_compo_counter[i] += other.base_compo_counter[i];
+    }
+
+    read_qual_counter += other.read_qual_counter;
+
+    for (int i = 0; i <= observed_max_len; i++)
+        read_len_counter[i] += other.read_len_counter[i];
+
+    for (
+         map< int, map<int, TileQualCounter> >::const_iterator it_lane = other.tile_read_qual_counter.begin();
+         it_lane != other.tile_read_qual_counter.end();
+         it_lane++
+         )
+    {
+        int lane = it_lane->first;
+        const map<int, TileQualCounter>* lane_quals = &(it_lane->second);
+
+        for (
+             map<int, TileQualCounter>::const_iterator it_tile = lane_quals->begin();
+             it_tile != lane_quals->end();
+             it_tile++
+             )
+        {
+            int tile = it_tile->first;
+            tile_read_qual_counter[lane][tile] += it_tile->second;
+        }
+    }
+
+    return *this;
+}
+
+void FastqStat::try_expand_store(size_t new_size)
+{
+    if (new_size > observed_max_len)
+    {
+        observed_max_len = new_size;
+        base_qual_counter.resize(new_size, BaseQualCounter(encode));
+        base_compo_counter.resize(new_size);
+        read_len_counter.resize(new_size + 1, 0);
+    }
+}
+
+} // namespace htqc
diff --git a/src/htqc/FastqStat.h b/src/htqc/FastqStat.h
new file mode 100644
index 0000000..b489d8c
--- /dev/null
+++ b/src/htqc/FastqStat.h
@@ -0,0 +1,63 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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/>.
+
+
+#ifndef HTQC_FASTQSTAT_H
+#define HTQC_FASTQSTAT_H
+
+
+#include <htio2/HeaderUtil.h>
+#include <htio2/FastqSeq.h>
+
+#include "htqc/Common.h"
+#include "htqc/BaseQualCounter.h"
+
+namespace htqc
+{
+
+class FastqStat
+{
+public:
+    FastqStat(bool mask, htio2::QualityEncode encode, htio2::HeaderFormat h_format, bool h_sra);
+
+    ~FastqStat();
+
+    void record_seq(htio2::FastqSeq& seq);
+    FastqStat& operator+=(const FastqStat& other);
+
+    void try_expand_store(size_t new_size);
+
+public:
+    htio2::HeaderParser header_parser;
+
+    htio2::QualityEncode encode;
+    int observed_max_len;
+    int16_t qual_from;
+    int16_t qual_to;
+    bool qual_mask;
+
+    std::vector<float> read_quals;
+    std::vector<BaseQualCounter> base_qual_counter; // cycle => object
+    std::vector<BaseCounter> base_compo_counter; // cycle => object
+    BaseQualCounter read_qual_counter;
+    std::vector<long> read_len_counter; // length => count
+    std::map< int, std::map<int, TileQualCounter> > tile_read_qual_counter; // lane => tile => quality_range => count
+
+
+} CACHE_LINE_ALIGNMENT;
+
+}
+
+#endif // HTQC_FASTQSTAT_H
diff --git a/src/htqc/MicroAssembler.cpp b/src/htqc/MicroAssembler.cpp
new file mode 100644
index 0000000..9128455
--- /dev/null
+++ b/src/htqc/MicroAssembler.cpp
@@ -0,0 +1,289 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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 "htqc/MicroAssembler.h"
+
+#include "htio2/QualityUtil.h"
+#include "htio2/Kmer.h"
+
+#include <sstream>
+
+#include "stdlib.h"
+
+using namespace std;
+
+namespace htqc
+{
+
+MicroAssembler::MicroAssembler(int kmer_size, int confident_quality, int aln_identity, int conflict_quality_diff)
+: km_sz(kmer_size)
+, conf_qual(confident_quality)
+, aln_iden(aln_identity)
+, qual_diff(conflict_quality_diff)
+{
+}
+
+MicroAssembler::~MicroAssembler()
+{
+}
+
+bool MicroAssembler::assemble(const std::string& seq1,
+                              const std::vector<int16_t>& qual_list_1,
+                              const std::string& seq2,
+                              const std::vector<int16_t>& qual_list_2)
+{
+    result_seq.clear();
+    result_qual.clear();
+    result_desc.clear();
+
+    size_t len_a = seq1.length();
+    size_t len_b = seq2.length();
+
+    // generate quality mask
+    vector<bool> qual_mask_a;
+    vector<bool> qual_mask_b;
+    gen_qual_mask(qual_list_1, qual_mask_a);
+    gen_qual_mask(qual_list_2, qual_mask_b);
+
+    // encode sequence
+    // generate kmer profile
+    htio2::EncodedSeq enc_a;
+    htio2::EncodedSeq enc_b;
+    vector<KmerT> kmers_a;
+    vector<KmerT> kmers_b;
+    multimap<KmerT, PosT> kmers_pos_b;
+
+    htio2::encode_nt5(seq1, enc_a);
+    htio2::encode_nt5(seq2, enc_b);
+    htio2::gen_kmer_nt5(enc_a, kmers_a, km_sz);
+    htio2::gen_kmer_nt5(enc_b, kmers_b, km_sz);
+    htio2::summ_kmer_pos(kmers_b, kmers_pos_b);
+
+    //
+    // perform alignment
+    //
+    const ssize_t nk_a = kmers_a.size();
+
+    bool success = false;
+
+    // traverse A position
+    for (PosT i_kmer_a = 0; i_kmer_a < nk_a; i_kmer_a++)
+    {
+        if (!qual_mask_a[i_kmer_a])
+        {
+            continue;
+        }
+
+        const KmerT kmer_a = kmers_a[i_kmer_a];
+        pair<multimap<KmerT,PosT>::const_iterator, multimap<KmerT,PosT>::const_iterator> kb_pos_bound = kmers_pos_b.equal_range(kmer_a);
+
+        // traverse B position
+        for (multimap<KmerT,PosT>::const_iterator it = kb_pos_bound.first; it != kb_pos_bound.second; it++)
+        {
+            const PosT i_kmer_b = it->second;
+            if (!qual_mask_b[i_kmer_b]) continue;
+
+            const size_t len_a_before = i_kmer_a;
+            const size_t len_b_before = i_kmer_b;
+            const size_t len_a_after = len_a - len_a_before;
+            const size_t len_b_after = len_b - len_b_before;
+
+
+            // skip if B lays on left of A
+            if (len_a_before < len_b_before && len_b_after < len_a_after)
+            {
+                continue;
+            }
+
+            // ib = ia + offset
+            const PosT offset = i_kmer_b - i_kmer_a;
+
+            //
+            // check sequence
+            //
+            PosT ia_from = 0;
+            PosT ib_from = 0;
+            if (len_a_before < len_b_before)
+                ib_from = ia_from + offset;
+
+            else
+                ia_from = ib_from - offset;
+
+            PosT ia_to = ia_from;
+            PosT ib_to = ib_from;
+
+            uint16_t iden = 0;
+            bool conflict = false;
+
+            string aligned_part;
+            vector<int16_t> aligned_part_qual;
+
+            while (1)
+            {
+                int16_t qual_a = qual_list_1[ia_to];
+                int16_t qual_b = qual_list_2[ib_to];
+
+                // check base
+                if (enc_a[ia_to] == enc_b[ib_to])
+                {
+                    if (qual_a >= conf_qual || qual_b >= conf_qual) iden++;
+                }
+                else
+                {
+                    // check quality
+                    int curr_qual_diff = abs(qual_a - qual_b);
+                    if (curr_qual_diff < qual_diff)
+                    {
+                        conflict = true;
+                        break;
+                    }
+                }
+
+                // store base and quality
+                if (qual_a >= qual_b)
+                {
+                    aligned_part.push_back(seq1[ia_to]);
+                    aligned_part_qual.push_back(qual_list_1[ia_to]);
+                }
+                else
+                {
+                    aligned_part.push_back(seq2[ib_to]);
+                    aligned_part_qual.push_back(qual_list_2[ib_to]);
+                }
+
+                ia_to++;
+                ib_to++;
+                if (ia_to == len_a || ib_to == len_b) break;
+            }
+
+            // record the assembled sequence
+            if (!conflict && iden >= aln_iden)
+            {
+                success = true;
+
+                ostringstream handle;
+                handle << "kmer_size=" << km_sz
+                    << " kmer_pos_a=" << i_kmer_a + 1
+                    << " kmer_pos_b=" << i_kmer_b + 1
+                    << " num_identical=" << iden;
+                result_desc = handle.str();
+
+                // content before alignment
+                if (ia_from > 0)
+                {
+                    result_seq.assign(seq1, 0, ia_from);
+                    result_qual.assign(qual_list_1.begin(), qual_list_1.begin() + ia_from);
+                }
+                else if (ib_from > 0)
+                {
+                    result_seq.assign(seq2, 0, ib_from);
+                    result_qual.assign(qual_list_2.begin(), qual_list_2.begin() + ib_from);
+                }
+
+                // contents that aligned
+                result_seq += aligned_part;
+                result_qual.insert(result_qual.end(), aligned_part_qual.begin(), aligned_part_qual.end());
+
+                // contents after alignment
+                if (ia_to != len_a)
+                {
+                    result_seq.append(seq1, ia_to, string::npos);
+                    result_qual.insert(result_qual.end(), qual_list_1.begin() + ia_to, qual_list_1.end());
+                }
+                else if (ib_to != len_b)
+                {
+                    result_seq.append(seq2, ib_to, string::npos);
+                    result_qual.insert(result_qual.end(), qual_list_2.begin() + ib_to, qual_list_2.end());
+                }
+
+                break;
+            }
+        }
+
+        if (success) break;
+    }
+
+    return success;
+}
+
+void MicroAssembler::gen_qual_mask(const vector<int16_t>& quality, std::vector<bool>& mask)
+{
+    // init mask
+    const size_t length = quality.size();
+
+    if (length < km_sz)
+    {
+        mask.resize(0);
+        return;
+    }
+
+    const size_t num_kmer = length - km_sz + 1;
+    mask.resize(num_kmer);
+
+    // check contents
+    size_t i = 0;
+
+    while (i < num_kmer)
+    {
+        // check the first kmer
+        bool ok = true;
+        size_t bad_i = 0;
+
+        for (size_t j = 0; j < km_sz; j++)
+        {
+            size_t i_check = i + j;
+            if (quality[i_check] < conf_qual)
+            {
+                ok = false;
+                bad_i = i_check;
+                break;
+            }
+        }
+
+        if (ok)
+        {
+            mask[i] = true;
+            // check next kmer
+            // actually only check one base on the tail
+            i++;
+            for (; i < num_kmer; i++)
+            {
+                size_t i_tail = i + km_sz - 1;
+                if (conf_qual <= quality[i_tail])
+                    mask[i] = true;
+                else
+                {
+                    // mark false within current kmer range
+                    for (; i <= i_tail && i < num_kmer; i++)
+                        mask[i] = false;
+                    // now i should point to the one after i_tail
+                    break;
+                }
+            }
+        }
+        else
+        {
+            // mark bad from i to bad_i
+            for (; i <= bad_i && i < num_kmer; i++)
+                mask[i] = false;
+            // now i should point to the one after bad_i
+        }
+
+    }
+}
+
+
+} // namespace htqc
+
diff --git a/src/htqc/MicroAssembler.h b/src/htqc/MicroAssembler.h
new file mode 100644
index 0000000..9943268
--- /dev/null
+++ b/src/htqc/MicroAssembler.h
@@ -0,0 +1,63 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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/>.
+
+#ifndef HTQC_MICROASSEMBLER_H
+#define	HTQC_MICROASSEMBLER_H
+
+#define USE_encode
+
+#include <string>
+#include <vector>
+
+#include <stdint.h>
+
+namespace htqc
+{
+
+typedef uint64_t KmerT;
+typedef int16_t PosT;
+
+class MicroAssembler
+{
+public:
+    MicroAssembler(int kmer_size, int confident_quality, int aln_identity, int conflict_quality_diff);
+    ~MicroAssembler();
+
+    /// @return true if assembled
+    bool assemble(const std::string& seq1,
+                  const std::vector<int16_t>& qual_list_1,
+                  const std::string& seq2,
+                  const std::vector<int16_t>& qual_list_2);
+
+
+    std::string result_seq;
+    std::vector<int16_t> result_qual;
+    std::string result_desc;
+private:
+    MicroAssembler();
+    MicroAssembler(const MicroAssembler& orig);
+    MicroAssembler& operator=(const MicroAssembler& orig);
+
+    void gen_qual_mask(const std::vector<int16_t>& quality, std::vector<bool>& mask);
+
+    int km_sz;
+    int conf_qual;
+    int aln_iden;
+    int qual_diff;
+};
+
+} // namespace htqc
+#endif	/* HTQC_MICROASSEMBLER_H */
+
diff --git a/src/htqc/MultiSeqFile.cpp b/src/htqc/MultiSeqFile.cpp
new file mode 100644
index 0000000..2f4149b
--- /dev/null
+++ b/src/htqc/MultiSeqFile.cpp
@@ -0,0 +1,122 @@
+#include "htqc/MultiSeqFile.h"
+
+#include "htio2/FastqSeq.h"
+#include "htio2/SeqIO.h"
+
+namespace htqc
+{
+
+MultiSeqFileSE::MultiSeqFileSE(const std::vector<std::string>& files,
+                               htio2::CompressFormat comp)
+: files(files)
+, fh(htio2::SeqIO::New(files[0], htio2::READ, comp))
+, comp(comp)
+, curr_file_i(0)
+{
+}
+
+MultiSeqFileSE::~MultiSeqFileSE() {}
+
+bool MultiSeqFileSE::next_seq(htio2::FastqSeq& seq)
+{
+    // early out if we have reached the end
+    if (curr_file_i >= files.size())
+        return false;
+
+    while (true)
+    {
+        // try to get next sequence
+        bool re = fh->next_seq(seq);
+        if (re)
+            return true;
+
+        // try the next file
+        fh = nullptr;
+        curr_file_i++;
+        if (curr_file_i >= files.size())
+            return false;
+
+        fh = htio2::SeqIO::New(files[curr_file_i], htio2::READ, comp);
+    }
+}
+
+MultiSeqFilePE::MultiSeqFilePE(const std::vector<std::string>& files,
+                               htio2::Strand strand_r1_in_file,
+                               htio2::Strand strand_r2_in_file,
+                               htio2::CompressFormat comp)
+: files_a(files)
+, fh(new htio2::PairedEndIO(files[0],
+                           htio2::READ,
+                           strand_r1_in_file,
+                           strand_r2_in_file,
+                           comp,
+                           htio2::FORMAT_UNKNOWN))
+, interleave(true)
+, strand_r1_in_file(strand_r1_in_file)
+, strand_r2_in_file(strand_r2_in_file)
+, comp(comp)
+, curr_file_i(0)
+{
+}
+
+MultiSeqFilePE::MultiSeqFilePE(const std::vector<std::string>& files_a,
+                               const std::vector<std::string>& files_b,
+                               htio2::Strand strand_r1_in_file,
+                               htio2::Strand strand_r2_in_file,
+                               htio2::CompressFormat comp)
+: files_a(files_a)
+, files_b(files_b)
+, fh(new htio2::PairedEndIO(files_a[0],
+                           files_b[0],
+                           htio2::READ,
+                           strand_r1_in_file,
+                           strand_r2_in_file,
+                           comp,
+                           htio2::FORMAT_UNKNOWN))
+, interleave(false)
+, strand_r1_in_file(strand_r1_in_file)
+, strand_r2_in_file(strand_r2_in_file)
+, comp(comp)
+, curr_file_i(0)
+{
+}
+
+MultiSeqFilePE::~MultiSeqFilePE() {}
+
+bool MultiSeqFilePE::next_pair(htio2::FastqSeq& seq1,
+                               htio2::FastqSeq& seq2,
+                               htio2::Strand strand_r1,
+                               htio2::Strand strand_r2)
+{
+    if (curr_file_i >= files_a.size())
+        return false;
+
+    while (true)
+    {
+        bool re = fh->next_pair(seq1, seq2, strand_r1, strand_r2);
+        if (re)
+            return true;
+
+        delete fh;
+        curr_file_i++;
+        if (curr_file_i >= files_a.size())
+            return false;
+
+        fh = interleave
+            ? new htio2::PairedEndIO(files_a[curr_file_i],
+                                    htio2::READ,
+                                    strand_r1_in_file,
+                                    strand_r2_in_file,
+                                    comp,
+                                    htio2::FORMAT_UNKNOWN)
+            : new htio2::PairedEndIO(files_a[curr_file_i],
+                                    files_b[curr_file_i],
+                                    htio2::READ,
+                                    strand_r1_in_file,
+                                    strand_r2_in_file,
+                                    comp,
+                                    htio2::FORMAT_UNKNOWN);
+    }
+}
+} // namespace htqc
+
diff --git a/src/htqc/MultiSeqFile.h b/src/htqc/MultiSeqFile.h
new file mode 100644
index 0000000..0d8a605
--- /dev/null
+++ b/src/htqc/MultiSeqFile.h
@@ -0,0 +1,75 @@
+#ifndef HTQC_MULTISEQFILEINPUT_H
+#define	HTQC_MULTISEQFILEINPUT_H
+
+#include "htio2/PairedEndIO.h"
+#include "htio2/SeqIO.h"
+
+#include <vector>
+
+namespace htqc
+{
+
+class MultiSeqFileSE: public htio2::RefCounted
+{
+public:
+    typedef htio2::SmartPtr<MultiSeqFileSE> Ptr;
+    typedef htio2::SmartPtr<const MultiSeqFileSE> ConstPtr;
+
+public:
+    MultiSeqFileSE(const std::vector<std::string>& files, htio2::CompressFormat comp);
+    virtual ~MultiSeqFileSE();
+    bool next_seq(htio2::FastqSeq& seq);
+
+protected:
+    std::vector<std::string> files;
+    htio2::SeqIO::Ptr fh;
+    htio2::CompressFormat comp;
+    size_t curr_file_i;
+private:
+    MultiSeqFileSE(const MultiSeqFileSE& other);
+    MultiSeqFileSE& operator=(const MultiSeqFileSE& other);
+};
+
+class MultiSeqFilePE: public htio2::RefCounted
+{
+public:
+    typedef htio2::SmartPtr<MultiSeqFilePE> Ptr;
+    typedef htio2::SmartPtr<const MultiSeqFilePE> ConstPtr;
+
+public:
+    MultiSeqFilePE(const std::vector<std::string>& files,
+                   htio2::Strand strand_r1_in_file,
+                   htio2::Strand strand_r2_in_file,
+                   htio2::CompressFormat comp);
+
+    MultiSeqFilePE(const std::vector<std::string>& files_a,
+                   const std::vector<std::string>& files_b,
+                   htio2::Strand strand_r1_in_file,
+                   htio2::Strand strand_r2_in_file,
+                   htio2::CompressFormat comp);
+    virtual ~MultiSeqFilePE();
+
+    bool next_pair(htio2::FastqSeq& seq1,
+                   htio2::FastqSeq& seq2,
+                   htio2::Strand strand_r1,
+                   htio2::Strand strand_r2);
+
+protected:
+    std::vector<std::string> files_a;
+    std::vector<std::string> files_b;
+    size_t curr_file_i;
+    htio2::PairedEndIO* fh;
+
+    bool interleave;
+    htio2::Strand strand_r1_in_file;
+    htio2::Strand strand_r2_in_file;
+    htio2::CompressFormat comp;
+private:
+    MultiSeqFilePE(const MultiSeqFilePE& other);
+    MultiSeqFilePE& operator=(const MultiSeqFilePE& other);
+};
+
+} // namespace htqc
+
+#endif	/* HTQC_MULTISEQFILEINPUT_H */
+
diff --git a/src/htqc/Options.cpp b/src/htqc/Options.cpp
new file mode 100644
index 0000000..a37e066
--- /dev/null
+++ b/src/htqc/Options.cpp
@@ -0,0 +1,337 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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/>.
+
+#define USE_file_out
+#define USE_prefix_out
+#define USE_se_pe
+#define USE_encode
+#define USE_header_format
+#define USE_mask
+#include "htqc/Options.h"
+#include "htio2/Cast.h"
+#include "htio2/Version.h"
+#include "htio2/FastqIO.h"
+#include "htio2/FormatUtil.h"
+#include "htio2/HeaderUtil.h"
+#include "htio2/QualityUtil.h"
+
+using namespace std;
+using namespace htio2;
+
+namespace htqc
+{
+
+bool OPT_help;
+htio2::Option OPT_help_ENTRY("help", 'h', OPTION_GROUP_MISC,
+                             &OPT_help, htio2::Option::FLAG_NONE,
+                             "Show help.");
+
+vector<string> OPT_files_in;
+htio2::Option OPT_files_in_ENTRY("in", 'i', OPTION_GROUP_IO,
+                                 &OPT_files_in, htio2::Option::FLAG_MULTI_KEY, htio2::ValueLimit::Free(),
+                                 "Input files.", "FILE1 [FILE2 ...]");
+
+std::string OPT_prefix_out;
+htio2::Option OPT_prefix_out_ENTRY("out", 'o', OPTION_GROUP_IO,
+                                   &OPT_prefix_out, htio2::Option::FLAG_NONE,
+                                   "Output file prefix.", "FILE_PREFIX");
+
+htio2::QualityEncode OPT_encode(htio2::ENCODE_UNKNOWN);
+htio2::Option OPT_encode_ENTRY("encode", '\0', OPTION_GROUP_FORMAT,
+                               &OPT_encode, htio2::Option::FLAG_NONE,
+                               "Quality score encode.\n"
+                               "sanger: 0 - 93 using ASCII 33 - 126\n"
+                               "solexa: -5 - 62 using ASCII 59 - 126\n"
+                               "illumina: 0 - 62 using ASCII 64 - 126\n"
+                               "casava1.8: 0 - 62 using ASCII 33 - 95; 0 1 not used; values >40 rarely used",
+                               "STRING");
+
+htio2::HeaderFormat OPT_header_format(htio2::HEADER_1_8);
+htio2::Option OPT_header_format_ENTRY("header-format", '\0', OPTION_GROUP_FORMAT,
+                                      &OPT_header_format, htio2::Option::FLAG_NONE,
+                                      "FASTQ header format.\n"
+                                      "casava1.8: produced by Illumina CASAVA version 1.8\n"
+                                      "pri_casava1.8: \tproduced by Illumina CASAVA version 1.7 or lower",
+                                      "STRING");
+
+bool OPT_header_sra(false);
+htio2::Option OPT_header_sra_ENTRY("header-sra", '\0', OPTION_GROUP_FORMAT,
+                                   &OPT_header_sra, htio2::Option::FLAG_NONE,
+                                   "Whether FASTQ header has NCBI SRA addon.");
+
+bool OPT_mask(false);
+htio2::Option OPT_mask_ENTRY("quality-mask", '\0', OPTION_GROUP_FORMAT,
+                             &OPT_mask, htio2::Option::FLAG_NONE,
+                             "Treat quality score 2 as a mask.");
+
+bool OPT_version(false);
+htio2::Option OPT_version_ENTRY("version", 'v', OPTION_GROUP_MISC,
+                                &OPT_version, htio2::Option::FLAG_NONE,
+                                "Show version.");
+
+bool OPT_quiet(false);
+htio2::Option OPT_quiet_ENTRY("quiet", 'q', OPTION_GROUP_MISC,
+                              &OPT_quiet, htio2::Option::FLAG_NONE,
+                              "Do not print information during program run.");
+
+bool OPT_se(false);
+htio2::Option OPT_se_ENTRY("se", 'S', OPTION_GROUP_FORMAT,
+                           &OPT_se, htio2::Option::FLAG_NONE,
+                           "Single-end reads.");
+bool OPT_pe(false);
+htio2::Option OPT_pe_ENTRY("pe", 'P', OPTION_GROUP_FORMAT,
+                           &OPT_pe, htio2::Option::FLAG_NONE,
+                           "Paired-end reads.");
+
+bool OPT_pe_itlv(false);
+htio2::Option OPT_pe_itlv_ENTRY("pe-itlv", '\0', OPTION_GROUP_FORMAT,
+                                &OPT_pe_itlv, htio2::Option::FLAG_NONE,
+                                "Paired-end reads are stored in interleaved format.");
+
+std::string _OPT_pe_strand("FR");
+htio2::Option OPT_pe_strand_ENTRY("pe-strand", '\0', OPTION_GROUP_FORMAT,
+                                  &_OPT_pe_strand, htio2::Option::FLAG_NONE,
+                                  "The strand of paired-end reads. \"F\" for forward, \"R\" for reverse. 1st character for read 1, 2nd character for read 2.",
+                                  "FF|FR|RF|RR");
+
+htio2::CompressFormat OPT_compress = htio2::COMPRESS_UNKNOWN;
+
+void show_files_in()
+{
+    cout << "# input files:" << endl;
+    if (OPT_se)
+    {
+        for (size_t i = 0; i < OPT_files_in.size(); i++)
+            cout << "#   " << OPT_files_in[i] << endl;
+    }
+    else if (OPT_pe)
+    {
+        if (OPT_pe_itlv)
+        {
+            for (size_t i = 0; i < OPT_files_in.size(); i++)
+                cout << "#   " << OPT_files_in[i] << endl;
+        }
+        else
+        {
+            if (OPT_files_in.size() % 2)
+                throw runtime_error("odd number of input files");
+            size_t hf_sz = OPT_files_in.size() / 2;
+            for (size_t i = 0; i < hf_sz; i++)
+                cout << "#   " << OPT_files_in[i] << " and " << OPT_files_in[i + hf_sz] << endl;
+        }
+    }
+}
+
+void ensure_files_in()
+{
+    if (!OPT_files_in.size())
+    {
+        cerr << "ERROR: input files not specified" << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+void show_prefix_out()
+{
+    cout << "# output prefix: " << OPT_prefix_out << endl;
+}
+
+void ensure_prefix_out()
+{
+    tidy_prefix_out(OPT_prefix_out);
+    if (!OPT_prefix_out.length())
+    {
+        cerr << "ERROR: output file prefix not specified" << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+htio2::Strand _cast_strand_chr(char value)
+{
+    switch (value)
+    {
+    case 'F':
+    case 'f':
+        return htio2::STRAND_FWD;
+    case 'R':
+    case 'r':
+        return htio2::STRAND_REV;
+    default:
+        cerr << "ERROR: invalid strand character representation: " << value << ". Only F/R/f/r allowed." << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+htio2::Strand OPT_pe_strand1()
+{
+    return _cast_strand_chr(_OPT_pe_strand[0]);
+}
+
+htio2::Strand OPT_pe_strand2()
+{
+    return _cast_strand_chr(_OPT_pe_strand[1]);
+}
+
+void show_se_pe()
+{
+    if (OPT_se)
+    {
+        cout << "# single-end" << endl;
+    }
+    else if (OPT_pe)
+    {
+        cout << "# paired-end" << endl;
+        if (OPT_pe_itlv)
+            cout << "#   interleave file" << endl;
+        else
+            cout << "#   file pair" << endl;
+        cout << "#   strand: " << _OPT_pe_strand << endl;
+    }
+    else
+    {
+        cerr << "ERROR: neither single nor paired" << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+void ensure_se_pe()
+{
+    if ((OPT_se && OPT_pe) ||
+        !(OPT_se || OPT_pe))
+    {
+        cerr << "ERROR: single-end (--se, -S) or paired-end (--pe, -P)?" << endl;
+        exit(EXIT_FAILURE);
+    }
+
+    if (OPT_pe_itlv && !OPT_pe)
+    {
+        cerr << "WARNING: implicitly enabled paired-end mode, because interleave mode was selected" << endl;
+        OPT_pe = true;
+    }
+
+    if (_OPT_pe_strand.length() != 2
+        || !check_strand_chr(_OPT_pe_strand[0])
+        || !check_strand_chr(_OPT_pe_strand[1]))
+    {
+        cerr << "ERROR: invalid paired-end strand: \"" << _OPT_pe_strand << "\". Valid values: FF/FR/RF/RR (lower case allowed)." << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+void show_encode()
+{
+    cout << "# quality encode: " << htio2::to_string(OPT_encode) << endl;
+}
+
+void ensure_encode()
+{
+    if (OPT_encode == htio2::ENCODE_UNKNOWN)
+    {
+        if (!OPT_quiet) cout << "guess encode from front " << NUM_GUESS << " sequences of file " << OPT_files_in[0] << endl;
+
+        FastqIO fh(OPT_files_in[0], htio2::READ);
+        OPT_encode = guess_quality_encode(fh, NUM_GUESS);
+        if (OPT_encode == htio2::ENCODE_UNKNOWN)
+        {
+            cerr << "ERROR: failed to guess quality encode from input file " << OPT_files_in[0] << endl;
+            exit(EXIT_FAILURE);
+        }
+
+        if (!OPT_quiet)
+            cout << "encode is: " << htio2::to_string(OPT_encode) << endl;
+    }
+}
+
+void show_header_format()
+{
+    cout << "# header format: " << htio2::to_string(OPT_header_format) << endl;
+}
+
+void ensure_header_format()
+{
+    if (OPT_header_format == htio2::HEADER_UNKNOWN)
+    {
+        if (!OPT_quiet) cout << "guess header format from front " << NUM_GUESS << " sequences of file " << OPT_files_in[0] << endl;
+        htio2::FastqIO fh(OPT_files_in[0], htio2::READ);
+        htio2::guess_header_format(fh, NUM_GUESS, OPT_header_format, OPT_header_sra);
+        if (OPT_header_format == htio2::HEADER_UNKNOWN)
+        {
+            cerr << "ERROR: failed to guess header format from input file " << OPT_files_in[0] << endl;
+            exit(EXIT_FAILURE);
+        }
+        if (!OPT_quiet)
+        {
+            cout << "header format is " << to_string(OPT_header_format);
+            if (OPT_header_sra) cout << ", with SRA" << endl;
+            else cout << ", without SRA" << endl;
+        }
+    }
+}
+
+void show_mask()
+{
+    cout << "# quality has mask: " << bool_to_string(OPT_mask) << endl;
+}
+
+htio2::CompressFormat guess_compress_format_by_files_name(const std::vector<std::string>& files)
+{
+    htio2::CompressFormat comp = htio2::COMPRESS_UNKNOWN;
+    string prev_file;
+    for (size_t i=0; i<files.size(); i++)
+    {
+        htio2::CompressFormat curr_comp = guess_compress_by_name(files[i]);
+
+        if (curr_comp == htio2::COMPRESS_UNKNOWN)
+            continue;
+
+        if (comp == htio2::COMPRESS_UNKNOWN)
+        {
+            comp = curr_comp;
+            prev_file = files[i];
+        }
+        else
+        {
+            if (comp != curr_comp)
+            {
+                cerr << "ERROR: conflict compress format by \"" << prev_file << "\" and \"" << files[i] << "\"" << endl;
+                exit(EXIT_FAILURE);
+            }
+        }
+    }
+
+    return comp;
+}
+
+void tidy_prefix_out(std::string & prefix)
+{
+    remove_suffix(prefix, ".gz");
+    remove_suffix(prefix, ".fq");
+    remove_suffix(prefix, ".fastq");
+}
+
+void show_version_and_exit()
+{
+    cout << htio2::get_version_string() << endl;
+    exit(EXIT_SUCCESS);
+}
+
+void remove_suffix(std::string& name, const std::string & suffix)
+{
+    size_t suffix_pos = name.rfind(suffix);
+    if (suffix_pos != string::npos)
+        name.erase(suffix_pos);
+}
+
+} // namespace htqc
diff --git a/src/htqc/Options.h b/src/htqc/Options.h
new file mode 100644
index 0000000..e63bae4
--- /dev/null
+++ b/src/htqc/Options.h
@@ -0,0 +1,121 @@
+//     HTQC - a high-throughput sequencing quality control toolkit
+//
+//     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.
+//
+//     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/>.
+
+#ifndef HTQC_OPTIONS_H
+#define	HTQC_OPTIONS_H
+
+#include "htqc/Common.h"
+#include "htio2/QualityUtil.h"
+#include "htio2/HeaderUtil.h"
+#include "htio2/OptionParser.h"
+
+
+namespace htqc
+{
+
+#define OPTION_GROUP_IO "Input/Output Options"
+#define OPTION_GROUP_MISC "Miscellaneous Options"
+#define OPTION_GROUP_FORMAT "Sequence Format Options"
+
+extern std::vector<std::string> OPT_files_in;
+extern htio2::Option OPT_files_in_ENTRY;
+void show_files_in();
+void ensure_files_in();
+
+
+#ifdef USE_prefix_out
+extern std::string OPT_prefix_out;
+extern htio2::Option OPT_prefix_out_ENTRY;
+void show_prefix_out();
+void ensure_prefix_out();
+#endif
+
+#ifdef USE_se_pe
+extern bool OPT_se;
+extern bool OPT_pe;
+extern bool OPT_pe_itlv;
+extern std::string _OPT_pe_strand;
+
+extern htio2::Option OPT_se_ENTRY;
+extern htio2::Option OPT_pe_ENTRY;
+extern htio2::Option OPT_pe_itlv_ENTRY;
+extern htio2::Option OPT_pe_strand_ENTRY;
+
+htio2::Strand _cast_strand_chr(char value);
+htio2::Strand OPT_pe_strand1();
+htio2::Strand OPT_pe_strand2();
+
+
+inline bool check_strand_chr(char value)
+{
+    switch (value)
+    {
+    case 'F':
+    case 'f':
+    case 'R':
+    case 'r':
+        return true;
+    default:
+        return false;
+    }
+}
+
+void show_se_pe();
+void ensure_se_pe();
+#endif
+
+#ifdef USE_encode
+extern htio2::QualityEncode OPT_encode;
+extern bool OPT_mask;
+extern htio2::Option OPT_encode_ENTRY;
+extern htio2::Option OPT_mask_ENTRY;
+void show_encode();
+void ensure_encode();
+void show_mask();
+#endif
+
+#ifdef USE_header_format
+extern htio2::HeaderFormat OPT_header_format;
+extern bool OPT_header_sra;
+extern htio2::Option OPT_header_format_ENTRY;
+extern htio2::Option OPT_header_sra_ENTRY;
+void show_header_format();
+void ensure_header_format();
+#endif
+
+extern bool OPT_quiet;
+extern htio2::Option OPT_quiet_ENTRY;
+
+extern htio2::CompressFormat OPT_compress;
+htio2::CompressFormat guess_compress_format_by_files_name(const std::vector<std::string>& files);
+
+extern bool OPT_help;
+extern htio2::Option OPT_help_ENTRY;
+
+extern bool OPT_version;
+extern htio2::Option OPT_version_ENTRY;
+
+void tidy_prefix_out(std::string& prefix);
+
+void show_version_and_exit();
+
+void separate_paired_files(const std::vector<std::string>& in, std::vector<std::string>& names_a, std::vector<std::string>& names_b);
+
+void remove_suffix(std::string& name, const std::string& suffix);
+
+} // namespace htqc
+
+#endif	/* HTQC_OPTIONS_H */
+
diff --git a/src/htqc/Primer.cpp b/src/htqc/Primer.cpp
new file mode 100644
index 0000000..922738d
--- /dev/null
+++ b/src/htqc/Primer.cpp
@@ -0,0 +1,127 @@
+#include "htqc/Primer.h"
+
+#include "htio2/SimpleSeq.h"
+
+using namespace std;
+
+namespace htqc
+{
+
+Primer::Primer(const std::string& id, const std::string& seq, size_t k)
+    : id(id)
+    , seq_fwd(seq)
+{
+    htio2::revcom(seq_fwd, seq_rev);
+    htio2::EncodedSeq enc_fwd;
+    htio2::EncodedSeq enc_rev;
+    htio2::encode_nt5(seq_fwd, enc_fwd);
+    htio2::encode_nt5(seq_rev, enc_rev);
+    htio2::gen_kmer_nt5(enc_fwd, klist_fwd, k);
+    htio2::gen_kmer_nt5(enc_rev, klist_rev, k);
+    htio2::summ_kmer_pos(klist_fwd, kpos_fwd);
+    htio2::summ_kmer_pos(klist_rev, kpos_rev);
+}
+
+bool align_primer(const string& read, const vector<int16_t>& read_qual, const KmerList& seq_km_list,
+                  const string& primer, const KmerList& primer_km_list, const KmerPosMap& primer_km_pos,
+                  int cut_qual, int cut_mis_high, int cut_mis_total,
+                  PosT& seq_start, PosT& seq_end,
+                  PosT& primer_start, PosT& primer_end)
+{
+    const size_t len_seq = read.length();
+    const size_t len_primer = primer.length();
+    const size_t nk_seq = seq_km_list.size();
+
+    bool success = false;
+
+    // traverse sequence kmer position
+    for (PosT i_seq_km = 0; i_seq_km < nk_seq; i_seq_km++)
+    {
+        const KmerT seq_km = seq_km_list[i_seq_km];
+        pair<KmerPosMap::const_iterator, KmerPosMap::const_iterator> primer_km_pos_bound = primer_km_pos.equal_range(seq_km);
+
+        // traverse primer kmer position
+        for (KmerPosMap::const_iterator primer_km_pos_it = primer_km_pos_bound.first;
+             primer_km_pos_it != primer_km_pos_bound.second;
+             primer_km_pos_it++)
+        {
+            const PosT i_primer_km = primer_km_pos_it->second;
+
+            const size_t len_seq_before = i_seq_km;
+            const size_t len_primer_before = i_primer_km;
+
+            // i_primer = i_seq + offset
+            const PosT offset = i_primer_km - i_seq_km;
+
+            // get alignment start position
+            PosT i_seq_start = 0;
+            PosT i_primer_start = 0;
+            if (len_seq_before < len_primer_before)
+                i_primer_start = i_seq_start + offset;
+            else
+                i_seq_start = i_primer_start - offset;
+
+            // traverse bases
+            PosT i_seq_end = i_seq_start;
+            PosT i_primer_end = i_primer_start;
+
+            uint16_t mis_high = 0;
+            uint16_t mis_total = 0;
+
+            while (1)
+            {
+                if (read[i_seq_end] != primer[i_primer_end])
+                {
+                    mis_total++;
+                    if (read_qual[i_seq_end] >= cut_qual)
+                        mis_high++;
+                }
+
+                i_seq_end++;
+                i_primer_end++;
+                if (i_seq_end == len_seq || i_primer_end == len_primer) break;
+            }
+
+            // check status
+            if (mis_high <= cut_mis_high && mis_total <= cut_mis_total)
+            {
+                success = true;
+                seq_start = i_seq_start;
+                seq_end = i_seq_end - 1;
+                primer_start = i_primer_start;
+                primer_end = i_primer_end - 1;
+                break;
+            }
+        }
+
+        if (success) break;
+    }
+
+    return success;
+}
+
+bool Primer::align_fwd(const std::string &seq, const std::vector<int16_t> qual, const KmerList &seq_kmer,
+                       int cut_qual, int cut_mis_high, int cut_mis_total,
+                       PosT &seq_start, PosT &seq_end, PosT &primer_start, PosT &primer_end) const
+{
+    return align_primer(seq, qual, seq_kmer,
+                        seq_fwd, klist_fwd, kpos_fwd,
+                        cut_qual, cut_mis_high, cut_mis_total,
+                        seq_start, seq_end,
+                        primer_start, primer_end);
+}
+
+bool Primer::align_rev(const std::string &seq, const std::vector<int16_t> qual, const KmerList &seq_kmer,
+                       int cut_qual, int cut_mis_high, int cut_mis_total,
+                       PosT &seq_start, PosT &seq_end, PosT &primer_start, PosT &primer_end) const
+{
+    return align_primer(seq, qual, seq_kmer,
+                        seq_rev, klist_rev, kpos_rev,
+                        cut_qual, cut_mis_high, cut_mis_total,
+                        seq_start, seq_end,
+                        primer_start, primer_end);
+}
+
+PrimerGroup::PrimerGroup(const string &name): name(name) {}
+
+} // namespace htqc
diff --git a/src/htqc/Primer.h b/src/htqc/Primer.h
new file mode 100644
index 0000000..b2435c0
--- /dev/null
+++ b/src/htqc/Primer.h
@@ -0,0 +1,47 @@
+#ifndef PRIMER_H
+#define PRIMER_H
+
+#include "htio2/Kmer.h"
+
+namespace htqc
+{
+
+typedef uint32_t KmerT;
+typedef int16_t PosT;
+typedef std::vector<KmerT> KmerList;
+typedef std::multimap<KmerT, PosT> KmerPosMap;
+
+struct Primer
+{
+    Primer(const std::string& id, const std::string& seq, size_t k);
+
+    size_t length() const { return seq_fwd.length(); }
+    bool align_fwd(const std::string& seq, const std::vector<int16_t> qual, const KmerList& seq_kmer,
+                   int cut_qual, int cut_mis_high, int cut_mis_total,
+                   PosT& seq_start, PosT& seq_end,
+                   PosT& primer_start, PosT& primer_end) const;
+    bool align_rev(const std::string& seq, const std::vector<int16_t> qual, const KmerList& seq_kmer,
+                   int cut_qual, int cut_mis_high, int cut_mis_total,
+                   PosT& seq_start, PosT& seq_end,
+                   PosT& primer_start, PosT& primer_end) const;
+
+    std::string id;
+    std::string seq_fwd;
+    std::string seq_rev;
+    KmerList klist_fwd;
+    KmerList klist_rev;
+    KmerPosMap kpos_fwd;
+    KmerPosMap kpos_rev;
+};
+
+struct PrimerGroup
+{
+    PrimerGroup(const std::string& name);
+    std::string name;
+    std::vector<Primer> primers_left;
+    std::vector<Primer> primers_right;
+};
+
+} // namespace htqc
+
+#endif // PRIMER_H
diff --git a/t/CMakeLists.txt b/t/CMakeLists.txt
new file mode 100644
index 0000000..6ca515a
--- /dev/null
+++ b/t/CMakeLists.txt
@@ -0,0 +1,275 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+configure_file(TestConfig.h.in TestConfig.h ESCAPE_QUOTES)
+
+add_library(TestFramework TestFramework.cpp)
+
+add_executable(t_text_file_equal t_text_file_equal.cpp)
+target_link_libraries(t_text_file_equal
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(text_file_equal t_text_file_equal)
+
+add_executable(t_kmer_nt5_16 t_kmer_nt5_16.cpp)
+target_link_libraries(t_kmer_nt5_16
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(kmer_nt5_16 t_kmer_nt5_16)
+
+add_executable(t_kmer_nt5_32 t_kmer_nt5_32.cpp)
+target_link_libraries(t_kmer_nt5_32
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(kmer_nt5_32 t_kmer_nt5_32)
+
+add_executable(t_kmer_nt5_64 t_kmer_nt5_64.cpp)
+target_link_libraries(t_kmer_nt5_64
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(kmer_nt5_64 t_kmer_nt5_64)
+
+add_executable(t_kmer_nt4_16 t_kmer_nt4_16.cpp)
+target_link_libraries(t_kmer_nt4_16
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(kmer_nt4_16 t_kmer_nt4_16)
+
+add_executable(t_kmer_nt4_32 t_kmer_nt4_32.cpp)
+target_link_libraries(t_kmer_nt4_32
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(kmer_nt4_32 t_kmer_nt4_32)
+
+add_executable(t_kmer_nt4_64 t_kmer_nt4_64.cpp)
+target_link_libraries(t_kmer_nt4_64
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(kmer_nt4_64 t_kmer_nt4_64)
+
+add_executable(t_kmer_aa t_kmer_aa.cpp)
+target_link_libraries(t_kmer_aa
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(kmer_aa t_kmer_aa)
+
+add_executable(t_ref_counted t_ref_counted.cpp)
+target_link_libraries(t_ref_counted
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(ref_counted t_ref_counted)
+
+add_executable(t_simple_seq t_simple_seq.cpp)
+target_link_libraries(t_simple_seq
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(simple_seq t_simple_seq)
+
+add_executable(t_plain_file_handle t_plain_file_handle.cpp)
+target_link_libraries(t_plain_file_handle
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(plain_file_handle t_plain_file_handle)
+
+add_executable(t_gzip_file_handle t_gzip_file_handle.cpp)
+target_link_libraries(t_gzip_file_handle
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(gzip_file_handle t_gzip_file_handle)
+
+add_executable(t_fastq_io t_fastq_io.cpp)
+target_link_libraries(t_fastq_io
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(fastq_io t_fastq_io)
+
+add_executable(t_fasta_io t_fasta_io.cpp)
+target_link_libraries(t_fasta_io
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(fasta_io t_fasta_io)
+
+add_executable(t_header_util t_header_util.cpp)
+target_link_libraries(t_header_util
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(header_util t_header_util)
+
+add_executable(t_multi_seq_file_se t_multi_seq_file_se.cpp)
+target_link_libraries(t_multi_seq_file_se
+    TestFramework
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(multi_seq_file_se t_multi_seq_file_se)
+
+add_executable(t_multi_seq_file_pe t_multi_seq_file_pe.cpp)
+target_link_libraries(t_multi_seq_file_pe
+    TestFramework
+    ht_common
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(multi_seq_file_pe t_multi_seq_file_pe)
+
+add_executable(t_ht_sample t_ht_sample.cpp)
+target_link_libraries(t_ht_sample
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(ht_sample t_ht_sample)
+
+add_executable(t_ht_trim t_ht_trim.cpp)
+target_link_libraries(t_ht_trim
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(ht_trim t_ht_trim)
+
+add_executable(t_ht_rename t_ht_rename.cpp)
+target_link_libraries(t_ht_rename
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(ht_rename t_ht_rename)
+
+add_executable(t_ht_overlap t_ht_overlap.cpp)
+target_link_libraries(t_ht_overlap
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(ht_overlap t_ht_overlap)
+
+add_executable(t_ht_filter t_ht_filter.cpp)
+target_link_libraries(t_ht_filter
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(ht_filter t_ht_filter)
+
+add_executable(t_ht_convert t_ht_convert.cpp)
+target_link_libraries(t_ht_convert
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(ht_convert t_ht_convert)
+
+add_executable(t_ht_demul t_ht_demul.cpp)
+target_link_libraries(t_ht_demul
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(ht_demul t_ht_demul)
+
+add_executable(t_ht_lane_tile t_ht_lane_tile.cpp)
+target_link_libraries(t_ht_lane_tile
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(ht_lane_tile t_ht_lane_tile)
+
+add_executable(t_string t_string.cpp)
+target_link_libraries(t_string
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(string t_string)
+
+add_executable(t_cast t_cast.cpp)
+target_link_libraries(t_cast
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(cast t_cast)
+
+add_executable(option_parser option_parser.cpp)
+target_link_libraries(option_parser
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+
+add_executable(t_ring_buffer t_ring_buffer.cpp)
+target_link_libraries(t_ring_buffer
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(ring_buffer t_ring_buffer)
+
+add_executable(t_mt19937 t_mt19937.cpp)
+target_link_libraries(t_mt19937
+    TestFramework
+    htio2
+    ${juce_dep_libs}
+    ${ZLIB_LIBRARIES}
+)
+add_test(mt19937 t_mt19937)
+
diff --git a/t/TestConfig.h.in b/t/TestConfig.h.in
new file mode 100644
index 0000000..bba6c5e
--- /dev/null
+++ b/t/TestConfig.h.in
@@ -0,0 +1,6 @@
+#ifndef TESTCONFIG_H_IN
+#define TESTCONFIG_H_IN
+
+#define TEST_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
+
+#endif // TESTCONFIG_H_IN
diff --git a/t/TestFramework.cpp b/t/TestFramework.cpp
new file mode 100644
index 0000000..62f16a8
--- /dev/null
+++ b/t/TestFramework.cpp
@@ -0,0 +1,164 @@
+#include "TestFramework.h"
+#include "htio2/SeqIO.h"
+#include "htio2/FastqSeq.h"
+#include "htio2/PlainFileHandle.h"
+#include "htio2/GzipFileHandle.h"
+
+#include <iostream>
+
+using namespace std;
+
+TestFramework::TestFramework(): n_planned(0), n_got(0), n_fail(0)
+{
+}
+
+TestFramework::TestFramework(size_t n_tests): n_planned(n_tests), n_got(0), n_fail(0)
+{
+    if (!n_tests)
+    {
+        cerr << "zero number of planned tests" << endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+TestFramework::~TestFramework()
+{
+}
+
+bool TestFramework::run()
+{
+    content();
+    if (n_planned && n_planned != n_got)
+    {
+        cerr << "planned " << n_planned << ", but only run " << n_got << endl;
+        return false;
+    }
+    else
+    {
+        cout << n_got << " tests, " << n_fail << " failed" << endl;
+        return (n_fail == 0);
+    }
+}
+
+void TestFramework::ok(bool value, const char *desc)
+{
+    n_got++;
+    if (value)
+    {
+        cout << "ok " << n_got << " - " << desc << endl;
+    }
+    else
+    {
+        cout << "NOT ok " << n_got << " - " << desc << endl;
+        n_fail++;
+    }
+}
+
+bool text_file_eq(const char* file1, const char* file2)
+{
+    string _file1_(file1);
+    string _file2_(file2);
+    bool success = true;
+
+    htio2::FileHandle::Ptr fh1 = NULL;
+    htio2::FileHandle::Ptr fh2 = NULL;
+
+    if (_file1_.rfind(".gz") == _file1_.length()-3)
+        fh1 = new htio2::GzipFileHandle(_file1_, htio2::READ);
+    else
+        fh1 = new htio2::PlainFileHandle(_file1_, htio2::READ);
+
+    if (_file2_.rfind(".gz") == _file2_.length()-3)
+        fh2 = new htio2::GzipFileHandle(_file2_, htio2::READ);
+    else
+        fh2 = new htio2::PlainFileHandle(_file2_, htio2::READ);
+
+    string line1;
+    string line2;
+
+    while (1)
+    {
+        bool re1 = fh1->read_line(line1);
+        bool re2 = fh2->read_line(line2);
+        if (re1)
+        {
+            if (!re2)
+            {
+                success = false;
+                break;
+            }
+        }
+        else
+        {
+            if (re2)
+            {
+                success = false;
+                break;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        if (line1 != line2)
+        {
+            success = false;
+            break;
+        }
+    }
+
+    return success;
+}
+
+bool seq_file_id_eq(const char* file1, const char* file2)
+{
+    htio2::SeqIO::Ptr fh1(htio2::SeqIO::New(file1, htio2::READ));
+    htio2::SeqIO::Ptr fh2(htio2::SeqIO::New(file2, htio2::READ));
+
+    htio2::FastqSeq seq1, seq2;
+
+
+    bool success = true;
+    while (1)
+    {
+        bool re1 = fh1->next_seq(seq1);
+        bool re2 = fh2->next_seq(seq2);
+
+        if (re1)
+        {
+            if (!re2)
+            {
+                success = false;
+                break;
+            }
+        }
+        else
+        {
+            if (re2)
+            {
+                success = false;
+                break;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        if (seq1.id != seq2.id)
+        {
+            success = false;
+            break;
+        }
+    }
+
+    return success;
+}
+
+int main(int argc, char** argv)
+{
+    TestFramework t;
+    bool t_re = t.run();
+    exit(!t_re);
+}
diff --git a/t/TestFramework.h b/t/TestFramework.h
new file mode 100644
index 0000000..be204f8
--- /dev/null
+++ b/t/TestFramework.h
@@ -0,0 +1,155 @@
+#ifndef HTQC_TEST_FRAMEWORK
+#define HTQC_TEST_FRAMEWORK
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <iostream>
+#include <cmath>
+
+#include "htio2/StringUtil.h"
+
+#define OK(arg) ok(arg, EXPAND_AND_STRINGIFY(arg))
+#define IS(arg1, arg2) is(arg1, arg2, EXPAND_AND_STRINGIFY(arg1) " == " EXPAND_AND_STRINGIFY(arg2))
+#define IS_EPSILON(arg1, arg2) is_epsilon(arg1, arg2, EXPAND_AND_STRINGIFY(arg1) " ~~ " EXPAND_AND_STRINGIFY(arg2))
+#define GT(arg1, arg2) gt(arg1, arg2, EXPAND_AND_STRINGIFY(arg1) " > " EXPAND_AND_STRINGIFY(arg2))
+#define GE(arg1, arg2) ge(arg1, arg2, EXPAND_AND_STRINGIFY(arg1) " >= " EXPAND_AND_STRINGIFY(arg2))
+#define LT(arg1, arg2) lt(arg1, arg2, EXPAND_AND_STRINGIFY(arg1) " < " EXPAND_AND_STRINGIFY(arg2))
+#define LE(arg1, arg2) le(arg1, arg2, EXPAND_AND_STRINGIFY(arg1) " <= " EXPAND_AND_STRINGIFY(arg2))
+
+class TestFramework
+{
+public:
+    TestFramework();
+    TestFramework(size_t n_tests);
+    ~TestFramework();
+
+    void ok(bool value, const char* desc);
+
+    template<typename T1, typename T2>
+    void is(T1 value, T2 expect, const char* desc);
+
+    template<typename T>
+    void is_epsilon(T value, T expect, const char* desc, T rate = 10000);
+
+    template<typename T1, typename T2>
+    void gt(T1 a, T2 b, const char* desc);
+
+    template<typename T1, typename T2>
+    void ge(T1 a, T2 b, const char* desc);
+
+    template<typename T1, typename T2>
+    void lt(T1 a, T2 b, const char* desc);
+
+    template<typename T1, typename T2>
+    void le(T1 a, T2 b, const char* desc);
+
+    bool run();
+
+protected:
+    void content();
+    size_t n_planned;
+    size_t n_got;
+    size_t n_fail;
+};
+
+bool text_file_eq(const char* file1, const char* file2);
+bool seq_file_id_eq(const char* file1, const char* file2);
+
+template<typename T1, typename T2>
+void TestFramework::is(T1 value, T2 expect, const char* desc)
+{
+    n_got++;
+    if (value == expect)
+    {
+        std::cout << "ok " << n_got << " - " << desc << std::endl;
+    }
+    else
+    {
+        std::cout << "NOT ok " << n_got << " - " << desc << std::endl
+                  <<"  got " << value <<", expect "<< expect << "  " << std::endl;
+        n_fail++;
+    }
+}
+
+template<typename T>
+void TestFramework::is_epsilon(T value, T expect, const char* desc, T rate)
+{
+    n_got++;
+    if (std::abs(value-expect) <= std::abs(expect/rate))
+    {
+        std::cout << "ok " << n_got << " - " << desc << std::endl;
+    }
+    else
+    {
+        std::cout << "NOT ok " << n_got << " - " << desc << std::endl
+                  <<"  got " << value <<", expect "<< expect << "  " << std::endl;
+        n_fail++;
+    }
+}
+
+template<typename T1, typename T2>
+void TestFramework::gt(T1 a, T2 b, const char* desc)
+{
+    n_got++;
+    if (a > b)
+    {
+        std::cout << "ok " << n_got << " - " << desc << std::endl;
+    }
+    else
+    {
+        std::cout << "NOT ok " << n_got << " - " << desc << std::endl
+                  << "  got " << a << " and " << b << std::endl;
+        n_fail++;
+    }
+}
+
+template<typename T1, typename T2>
+void TestFramework::ge(T1 a, T2 b, const char* desc)
+{
+    n_got++;
+    if (a >= b)
+    {
+        std::cout << "ok " << n_got << " - " << desc << std::endl;
+    }
+    else
+    {
+        std::cout << "NOT ok " << n_got << " - " << desc << std::endl
+                  << "  got " << a << " and " << b << std::endl;
+        n_fail++;
+    }
+}
+
+template<typename T1, typename T2>
+void TestFramework::lt(T1 a, T2 b, const char* desc)
+{
+    n_got++;
+    if (a < b)
+    {
+        std::cout << "ok " << n_got << " - " << desc << std::endl;
+    }
+    else
+    {
+        std::cout << "NOT ok " << n_got << " - " << desc << std::endl
+                  << "  got " << a << " and " << b << std::endl;
+        n_fail++;
+    }
+}
+
+template<typename T1, typename T2>
+void TestFramework::le(T1 a, T2 b, const char* desc)
+{
+    n_got++;
+    if (a <= b)
+    {
+        std::cout << "ok " << n_got << " - " << desc << std::endl;
+    }
+    else
+    {
+        std::cout << "NOT ok " << n_got << " - " << desc << std::endl
+                  << "  got " << a << " and " << b << std::endl;
+        n_fail++;
+    }
+}
+
+#endif
diff --git a/t/barcodes.tab b/t/barcodes.tab
new file mode 100644
index 0000000..639d45e
--- /dev/null
+++ b/t/barcodes.tab
@@ -0,0 +1,66 @@
+Bgenome	XB-47	CCGTCC
+plasmid	E161p-1	TACAGC
+plasmid	E161p-4	TCATTC
+plasmid	E31p-7	TCGAAG
+plasmid	S13p-5	TCGGCA
+plasmid	E31p-6	ATGTCA
+16S_PCR	gut_20	TAGCTT
+16S_PCR.Plasmid-All	gut_23.S13p	CTTGTA
+16S_PCR	gut_25	AGTACG
+16S_PCR	gut_27	TCAGTC
+16S_PCR	gut_29	TTGAGC
+16S_PCR	gut_31	AAGCGA
+16S_PCR	gut_33	TCCTCA
+16S_PCR	gut_35	GGTTGT
+16S_PCR	gut_38	TGAGGT
+16S_PCR.Meta	gut_1.gut-37	ATCACG
+16S_PCR	gut_41	AGAGAG
+16S_PCR	gut_43	CACTTG
+16S_PCR	gut_47	AGTGGT
+16S_PCR	gut_50	GGATAA
+16S_PCR	gut_51	GTTGAA
+16S_PCR	gut_53	CGAATA
+16S_PCR	gut_55	TTGGTA
+16S_PCR.Bgenome	gut_3.XB-49	CGATGT
+16S_PCR	gut_57	CATCTA
+16S_PCR	gut_83	CTCAAT
+16S_PCR	gut_85	TGGATT
+16S_PCR	gut_87	AGTGTT
+16S_PCR	gut_90	CAATGT
+16S_PCR	gut_91	ACTTCT
+16S_PCR	gut_94	AAGATG
+16S_PCR	gut_59	TAATCG
+16S_PCR	gut_95	ATACAC
+16S_PCR.Meta	gut_5.gut-52	TTAGGC
+16S_PCR	gut_63	CTGTCA
+16S_PCR	gut_66	GAACCT
+16S_PCR	gut_67	AAGTCC
+16S_PCR	gut_69	CGCTGA
+16S_PCR	gut_71	GGCCTT
+16S_PCR	gut_97	GTCGCT
+16S_PCR	gut_99	CTACGG
+16S_PCR	gut_74	CAGCAC
+16S_PCR	gut_103	CCTTAA
+16S_PCR.Bgenome	gut_8.XB-51	TGACCA
+16S_PCR	gut_34	CAAGAA
+16S_PCR	gut_52	TCACAA
+16S_PCR	gut_106	CGTCAA
+16S_PCR	gut_89	GACACT
+16S_PCR	gut_110	CCTTCT
+16S_PCR	gut_9	ACAGTG
+16S_PCR.plasmid	gut_11.E161p-6	GCCAAT
+16S_PCR.Bgenome	gut_14.E161	CAGATC
+16S_PCR.Bgenome	gut_15.E31	ACTTGA
+16S_PCR	gut_17	GATCAG
+ITS_PCR	ITS_3	GCCTAA
+ITS_PCR	ITS_4	TGGTCA
+ITS_PCR	ITS_13_1	TTGACT
+ITS_PCR	ITS_14_1	GGAACT
+ITS_PCR	ITS_15_1	TGACAT
+ITS_PCR	ITS_16_1	GGACGG
+ITS_PCR	ITS_18_1	TTTCAC
+ITS_PCR	ITS_21_1	CGTACG
+ITS_PCR	ITS_23_1	ATCAGT
+ITS_PCR	ITS_10	AAGCTA
+ITS_PCR	ITS_19	GGCCAC
+ITS_PCR	ITS_22	CCACTC
diff --git a/t/double_1.fastq b/t/double_1.fastq
new file mode 100644
index 0000000..d1058bc
--- /dev/null
+++ b/t/double_1.fastq
@@ -0,0 +1,8 @@
+ at HISEQ:478:HB47HADXX:1:2111:14982:13660 1:N:0:CGATGT
+TGAGGAATCTTGCGCAATGGGGGAAACCCTGACGCAGCAACGCCGCGTGAGTGAGGAAGGTCTTCGGATCGTAAAGCTCTGTCAGATGGGAAGAAATGCCTGGGGGTTAATAGCCCCTCTGCTTGACGGTAC
++
+AG9DGFFAF?DFFFIDD?BFD(;@EFEEAEDBBD>C>BB;<B at B<@@BBB<4>>@?BBBBABBABBBBB at 5<@<BBBBAA>>:4:BBAB19A@?BBBBBBBBBBBB>>BBEE at A@B>?BB3(4>>@BB9<@B
+ at HISEQ:478:HB47HADXX:1:2111:15037:13522 1:N:0:CGATGT
+CAGTTAGGAATTTTGCGCAATGGACGAAAGTCTGACGCAGCGACATCGCGTGTGGGATGACAGCCTTAGGGTTGTAAACCACTTTTTGGGAGCCATGAAGGCGCCCAGAATAAGGAACTACTAACTACGTG
++
+IGJIGIIIJIJJJJJJJJGIIJGJJJJJIJEHHHHHFFDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCBDDDDEDDDDDDDDDBBDABDDDDDDDDABBDDDDDDDDDDCDCDDCDDDDDDDDDBDD
diff --git a/t/double_2.fastq b/t/double_2.fastq
new file mode 100644
index 0000000..bad308d
--- /dev/null
+++ b/t/double_2.fastq
@@ -0,0 +1,8 @@
+ at HISEQ:478:HB47HADXX:1:2111:14982:13660 2:N:0:CGATGT
+CACGGAGTTAGCCGGTGCTTCCTCTGATGGTACCGTCAAGCAGAGGGGCTATTAACCCCCAGGCATTTCTTCCCATCTGACAGAGCTTTACGATCCGAAGACCTTCCTCACTCACGCGGCGTTGCTGCGTC
++
+CBFD<6?B*?DFH>@FHGEHEA;AEH=?CCD at DC<A?B:@@BCCBBBBBBBCCACCCBBBBBBBBCC at ACACACACCCCCCCACC>4>CCCBB<B<BB?59>CCCCCAAC?AC??BBBBBBBBBBCCCB59
+ at HISEQ:478:HB47HADXX:1:2111:15037:13522 2:N:0:CGATGT
+CACGTAGTTAGTAGTTCCTTATTCTGGGCGCCTTCATGGCTCCCAAAAAGTGGTTTACAACCCTAAGGCTGTCATCCCACACGCGATGTCGCTGCGTCAGACTTTCGTCCATTGCGCAAAATTCCTAACTGC
++
+JIJJJJJJJJIHIJJIJJJJIJJJJIIJJHJHHFFFFFEEEEDDDDDDDDCDDDDDDDDDDDBDDDDDDDBBDDDDDDDDDDDBBDDDACDDDDDDDDBDDDDDDDDDDDDEEDDBDDDDDDDDDDDDDDDD
diff --git a/t/double_ovlp.fastq b/t/double_ovlp.fastq
new file mode 100644
index 0000000..4a89973
Binary files /dev/null and b/t/double_ovlp.fastq differ
diff --git a/t/filt.fastq.gz b/t/filt.fastq.gz
new file mode 100644
index 0000000..7a3ba74
Binary files /dev/null and b/t/filt.fastq.gz differ
diff --git a/t/filt_1.fastq.gz b/t/filt_1.fastq.gz
new file mode 100644
index 0000000..5bbb150
Binary files /dev/null and b/t/filt_1.fastq.gz differ
diff --git a/t/filt_2.fastq.gz b/t/filt_2.fastq.gz
new file mode 100644
index 0000000..946f6df
Binary files /dev/null and b/t/filt_2.fastq.gz differ
diff --git a/t/filt_fail.fastq.gz b/t/filt_fail.fastq.gz
new file mode 100644
index 0000000..1e6637e
Binary files /dev/null and b/t/filt_fail.fastq.gz differ
diff --git a/t/filt_fail_1.fastq.gz b/t/filt_fail_1.fastq.gz
new file mode 100644
index 0000000..31f2f97
Binary files /dev/null and b/t/filt_fail_1.fastq.gz differ
diff --git a/t/filt_fail_2.fastq.gz b/t/filt_fail_2.fastq.gz
new file mode 100644
index 0000000..6a9d03c
Binary files /dev/null and b/t/filt_fail_2.fastq.gz differ
diff --git a/t/filt_fail_s.fastq.gz b/t/filt_fail_s.fastq.gz
new file mode 100644
index 0000000..2e40b91
Binary files /dev/null and b/t/filt_fail_s.fastq.gz differ
diff --git a/t/filt_s.fastq.gz b/t/filt_s.fastq.gz
new file mode 100644
index 0000000..58310ce
Binary files /dev/null and b/t/filt_s.fastq.gz differ
diff --git a/t/option_parser.cpp b/t/option_parser.cpp
new file mode 100644
index 0000000..c152976
--- /dev/null
+++ b/t/option_parser.cpp
@@ -0,0 +1,54 @@
+#include "htio2/OptionParser.h"
+
+#include <vector>
+#include <string>
+#include <iostream>
+
+using namespace std;
+using namespace htio2;
+
+
+int main(int argc, char** argv)
+{
+    bool opt1 = false;
+    string opt2 = "opt2_default";
+    vector<int> opt3;
+
+    Option opt1_entry("foo", 'f', "help doc group 1",
+                      &opt1, Option::FLAG_NONE,
+                      "boolean option foo the quick brown fox jumps over a lazy dog, the quick brown fox jumps over a lazy dog.");
+
+    Option opt2_entry("bar", '\0', "help doc group 2",
+                      &opt2, Option::FLAG_NONE,
+                      "string option bar", "STR");
+
+    Option opt3_entry("baz", 'b', "group2",
+                      &opt3, Option::FLAG_NONE, ValueLimit::Fixed(3),
+                      "int list option baz", "INT INT INT");
+
+    OptionParser parser;
+    parser.add_option(opt1_entry);
+    parser.add_option(opt2_entry);
+    parser.add_option(opt3_entry);
+    parser.parse_options(argc, argv);
+
+    cout << parser.format_document() << endl;
+    cout << "after parse" << endl
+         << "  opt1: " << opt1 << endl
+         << "  opt2: " << opt2 << endl
+         << "  opt3: ";
+    for (size_t i=0; i< opt3.size(); i++)
+    {
+        cout << opt3[i] << " ";
+    }
+    cout << endl;
+
+    cout << "remaining options: " << argc << endl;
+    for (int i=0; i<argc; i++)
+    {
+        cout << "  " << argv[i] << endl;
+    }
+}
+
+
+
diff --git a/t/primers.fasta b/t/primers.fasta
new file mode 100644
index 0000000..45f7b6a
--- /dev/null
+++ b/t/primers.fasta
@@ -0,0 +1,13 @@
+>left1 16S
+ACTCCTACGGGAGGCAG
+>left2 16S
+CTCCTACGGGAGGCAGC
+>left3 16S
+TCCTACGGGAGGCAGCA
+>left4 16S
+CCTACGGGAGGCAGCAG
+>left5 16S
+CTACGGGAGGCAGCAGT 
+>right1 16S
+ATTACCGCGGCTGCTGG
+
diff --git a/t/single_1.fastq b/t/single_1.fastq
new file mode 100644
index 0000000..cefc352
--- /dev/null
+++ b/t/single_1.fastq
@@ -0,0 +1,4 @@
+ at HISEQ:478:HB47HADXX:1:2111:15037:13522 1:N:0:CGATGT
+CAGTTAGGAATTTTGCGCAATGGACGAAAGTCTGACGCAGCGACATCGCGTGTGGGATGACAGCCTTAGGGTTGTAAACCACTTTTTGGGAGCCATGAAGGCGCCCAGAATAAGGAACTACTAACTACGTG
++
+IGJIGIIIJIJJJJJJJJGIIJGJJJJJIJEHHHHHFFDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCBDDDDEDDDDDDDDDBBDABDDDDDDDDABBDDDDDDDDDDCDCDDCDDDDDDDDDBDD
diff --git a/t/single_2.fastq b/t/single_2.fastq
new file mode 100644
index 0000000..6304c88
--- /dev/null
+++ b/t/single_2.fastq
@@ -0,0 +1,4 @@
+ at HISEQ:478:HB47HADXX:1:2111:15037:13522 2:N:0:CGATGT
+CACGTAGTTAGTAGTTCCTTATTCTGGGCGCCTTCATGGCTCCCAAAAAGTGGTTTACAACCCTAAGGCTGTCATCCCACACGCGATGTCGCTGCGTCAGACTTTCGTCCATTGCGCAAAATTCCTAACTGC
++
+JIJJJJJJJJIHIJJIJJJJIJJJJIIJJHJHHFFFFFEEEEDDDDDDDDCDDDDDDDDDDDBDDDDDDDBBDDDDDDDDDDDBBDDDACDDDDDDDDBDDDDDDDDDDDDEEDDBDDDDDDDDDDDDDDDD
diff --git a/t/t_cast.cpp b/t/t_cast.cpp
new file mode 100644
index 0000000..585c581
--- /dev/null
+++ b/t/t_cast.cpp
@@ -0,0 +1,80 @@
+#include <TestConfig.h>
+#include <TestFramework.h>
+
+#include "htio2/Cast.h"
+#include "htio2/StringUtil.h"
+
+#include <limits.h>
+#include <limits>
+
+#include <sstream>
+
+using namespace htio2;
+using namespace std;
+
+#define FROM_STRING_TEST(__type__, __value__) {\
+        ostringstream tmp_input;\
+        tmp_input << " \t" << (__value__) << "  ";\
+        __type__ tmp_output = 0;\
+        ok(from_string<__type__>(tmp_input.str(), tmp_output), ("cast \""+tmp_input.str()+"\"").c_str());\
+        IS(tmp_output, __value__);\
+    }\
+
+#define FROM_STRING_TEST_EPSILON(__type__, __value__, __epsilon__) {\
+        ostringstream tmp_input;\
+        tmp_input << " \t " << (__value__) << "  ";\
+        __type__ tmp_output = 0;\
+        ok(from_string<__type__>(tmp_input.str(), tmp_output), ("cast \""+tmp_input.str()+"\"").c_str());\
+        is_epsilon(tmp_output, __value__, EXPAND_AND_STRINGIFY(tmp_output) " ~~ " EXPAND_AND_STRINGIFY(__value__), __epsilon__);\
+    }\
+
+#define FROM_STRING_TEST_ENUM(__type__, __input_str__, __value__) {\
+        __type__ tmp_output;\
+        ok(from_string<__type__>(__input_str__, tmp_output), (string("cast \"")+__input_str__+"\"").c_str());\
+        IS(tmp_output, __value__);\
+    }\
+
+void TestFramework::content()
+{
+    // integer types
+    FROM_STRING_TEST(short, SHRT_MIN);
+    FROM_STRING_TEST(short, SHRT_MAX);
+    FROM_STRING_TEST(int, INT_MIN);
+    FROM_STRING_TEST(int, INT_MAX);
+    FROM_STRING_TEST(long, LONG_MIN);
+    FROM_STRING_TEST(long, LONG_MAX);
+    FROM_STRING_TEST(long long, LONG_LONG_MIN);
+    FROM_STRING_TEST(long long, LONG_LONG_MAX);
+
+    FROM_STRING_TEST(unsigned short, 0);
+    FROM_STRING_TEST(unsigned short, USHRT_MAX);
+    FROM_STRING_TEST(unsigned int, 0);
+    FROM_STRING_TEST(unsigned int, UINT_MAX);
+    FROM_STRING_TEST(unsigned long, 0);
+    FROM_STRING_TEST(unsigned long, ULONG_MAX);
+    FROM_STRING_TEST(unsigned long long, 0);
+    FROM_STRING_TEST(unsigned long long, ULONG_LONG_MAX);
+
+    // floating point types
+    FROM_STRING_TEST_EPSILON(float, numeric_limits<float>::min(), 10000.0f);
+    FROM_STRING_TEST_EPSILON(float, numeric_limits<float>::max(), 10000.0f);
+    FROM_STRING_TEST_EPSILON(double, numeric_limits<double>::min(), 10000.0);
+    FROM_STRING_TEST_EPSILON(double, numeric_limits<double>::max(), 10000.0);
+
+    // enum types
+    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "unknown", htio2::COMPRESS_UNKNOWN);
+    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "plain", htio2::COMPRESS_PLAIN);
+    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "xz", htio2::COMPRESS_LZMA);
+    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "lzma", htio2::COMPRESS_LZMA);
+    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "gz", htio2::COMPRESS_GZIP);
+    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "gzip", htio2::COMPRESS_GZIP);
+    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "bz2", htio2::COMPRESS_BZIP2);
+    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "bzip2", htio2::COMPRESS_BZIP2);
+
+    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fastq", htio2::FORMAT_FASTQ);
+    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fq", htio2::FORMAT_FASTQ);
+    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fasta", htio2::FORMAT_FASTA);
+    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fas", htio2::FORMAT_FASTA);
+    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fa", htio2::FORMAT_FASTA);
+    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fna", htio2::FORMAT_FASTA);
+}
diff --git a/t/t_fasta_io.cpp b/t/t_fasta_io.cpp
new file mode 100644
index 0000000..cedcc49
--- /dev/null
+++ b/t/t_fasta_io.cpp
@@ -0,0 +1,72 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+#include "htio2/SeqIO.h"
+#include "htio2/FastqSeq.h"
+#include <stdio.h>
+
+using namespace std;
+using namespace htio2;
+
+void TestFramework::content()
+{
+    htio2::SeqIO* fh = SeqIO::New(TEST_SOURCE_DIR"/test1.fasta", htio2::READ);
+
+    FastqSeq seq1;
+
+    off_t off1 = fh->tell();
+    IS(off1, 0);
+
+    OK(fh->next_seq(seq1));
+    IS(seq1.id, "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+    IS(seq1.desc, "1:N:0:CTTGTA");
+    IS(seq1.seq,     "AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCTCCCACGTGTGGGAGCTTGTATGTACCTTAT");
+    IS(seq1.quality, "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII");
+
+    FastqSeq seq2;
+
+    off_t off2 = fh->tell();
+    IS(off2, 209);
+
+    OK(fh->next_seq(seq2));
+    IS(seq2.id, "HWI-ST1106:815:H154GADXX:1:1101:1197:2208");
+    IS(seq2.desc, "1:N:0:TTGGTA");
+    IS(seq2.seq,     "AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTGGTTCGCTATGTAAAGCTCTATCAGCAGGGAAGATNNTGACGGTACCTGACTAAGAAGCTCCGGCTAACTA");
+    IS(seq2.quality, "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII");
+
+    // absolute seek
+    {
+        FastqSeq seq;
+        fh->seek(off1);
+        OK(fh->next_seq(seq));
+        IS(seq.id, seq1.id);
+        IS(seq.desc, seq1.desc);
+        IS(seq.seq, seq1.seq);
+        IS(seq.quality, seq1.quality);
+    }
+
+    // relative seek
+    {
+        FastqSeq seq;
+        fh->seek(off1);
+        fh->seek(off2-off1, SEEK_CUR);
+        OK(fh->next_seq(seq));
+        IS(seq.id, seq2.id);
+        IS(seq.desc, seq2.desc);
+        IS(seq.seq, seq2.seq);
+        IS(seq.quality, seq2.quality);
+    }
+
+    // end seek
+    {
+        FastqSeq seq;
+        fh->seek(-209, SEEK_END);
+        OK(fh->next_seq(seq));
+        IS(seq.id, "HWI-ST1106:815:H154GADXX:1:1101:3431:2221");
+        IS(seq.desc, "1:N:0:TTAGGC");
+        IS(seq.seq,     "ATCGCAAATCATGGTGGGGATGATACGGCGTTTCATTGCGGAGCAGGAAATTGTTATGTTCTTATCAGGAGATTATAATTGGCCTGACAAATGGATGTGATTTATTTATTGGGCTCAATTGGGCTAGGTTGGGGATCTTCATTTGTCCAC");
+        IS(seq.quality, "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII");
+    }
+
+    delete fh;
+}
+
diff --git a/t/t_fastq_io.cpp b/t/t_fastq_io.cpp
new file mode 100644
index 0000000..7c60d52
--- /dev/null
+++ b/t/t_fastq_io.cpp
@@ -0,0 +1,72 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+#include "htio2/SeqIO.h"
+#include "htio2/FastqSeq.h"
+#include <stdio.h>
+
+using namespace std;
+using namespace htio2;
+
+void TestFramework::content()
+{
+    htio2::SeqIO* fh = SeqIO::New(TEST_SOURCE_DIR"/test1.fastq", htio2::READ);
+
+    FastqSeq seq1;
+
+    off_t off1 = fh->tell();
+    IS(off1, 0);
+
+    OK(fh->next_seq(seq1));
+    IS(seq1.id, "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+    IS(seq1.desc, "1:N:0:CTTGTA");
+    IS(seq1.seq, "AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCTCCCACGTGTGGGAGCTTGTATGTACCTTAT");
+    IS(seq1.quality, "=?@DFADDHHAHDGGBGGGIGHBEGGHEI>FGIIGCGGCH3?@FEB@@@FGICHG==AHFFEFEEDDDDDDC<>A>A:ACDCC>C<@BB>C at ACC@CACAC at ACCDDDCA?ABCAC at 9@AA8??8><ADB<>B8<B:C?>@>>34>:@CD");
+
+    FastqSeq seq2;
+
+    off_t off2 = fh->tell();
+    IS(off2, 360);
+
+    OK(fh->next_seq(seq2));
+    IS(seq2.id, "HWI-ST1106:815:H154GADXX:1:1101:1197:2208");
+    IS(seq2.desc, "1:N:0:TTGGTA");
+    IS(seq2.seq, "AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTGGTTCGCTATGTAAAGCTCTATCAGCAGGGAAGATNNTGACGGTACCTGACTAAGAAGCTCCGGCTAACTA");
+    IS(seq2.quality, "@@CFFDFFGHHHHJJHFHGHHGIIHIJJJJIHHJJJJGIGIJHIJGIICFC at ECEHAB@4=;@DBB8B at B:@:>C>>CCCD:?CDDDDBDEEEDCCDCDDCCCC@@ADD?BDBD##++8?@B9A9CDCCCCCDDCDCCD at C>BBDDCDDD");
+
+    // absolute seek
+    {
+        FastqSeq seq;
+        fh->seek(off1);
+        OK(fh->next_seq(seq));
+        IS(seq.id, seq1.id);
+        IS(seq.desc, seq1.desc);
+        IS(seq.seq, seq1.seq);
+        IS(seq.quality, seq1.quality);
+    }
+
+    // relative seek
+    {
+        FastqSeq seq;
+        fh->seek(off1);
+        fh->seek(off2-off1, SEEK_CUR);
+        OK(fh->next_seq(seq));
+        IS(seq.id, seq2.id);
+        IS(seq.desc, seq2.desc);
+        IS(seq.seq, seq2.seq);
+        IS(seq.quality, seq2.quality);
+    }
+
+    // end seek
+    {
+        FastqSeq seq;
+        fh->seek(-360, SEEK_END);
+        OK(fh->next_seq(seq));
+        IS(seq.id, "HWI-ST1106:815:H154GADXX:1:1101:3431:2221");
+        IS(seq.desc, "1:N:0:TTAGGC");
+        IS(seq.seq, "ATCGCAAATCATGGTGGGGATGATACGGCGTTTCATTGCGGAGCAGGAAATTGTTATGTTCTTATCAGGAGATTATAATTGGCCTGACAAATGGATGTGATTTATTTATTGGGCTCAATTGGGCTAGGTTGGGGATCTTCATTTGTCCAC");
+        IS(seq.quality, "@<BFFFFFHGHHHJCFGIIFIJIGJJJJJJIJJGIIJJJJJJHFFFFFCCEDECDDEDFEEEDCDCCDDABDDCDDEEEEDDDDDBCDDDDDDD(:@AACDDDDEDDDEDDDDBDAACCDCDDDDBDDCDDDDD0<BDCDEEEEEE at CDD");
+    }
+
+    delete fh;
+}
+
diff --git a/t/t_gzip_file_handle.cpp b/t/t_gzip_file_handle.cpp
new file mode 100644
index 0000000..a80de54
--- /dev/null
+++ b/t/t_gzip_file_handle.cpp
@@ -0,0 +1,56 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+#include "htio2/GzipFileHandle.h"
+#include <stdio.h>
+
+
+using namespace std;
+using namespace htio2;
+
+void TestFramework::content()
+{
+    GzipFileHandle fh(TEST_SOURCE_DIR"/test1.fastq", htio2::READ);
+    string line1;
+    string line2;
+    string line3;
+    string line4;
+
+    OK(fh.read_line(line1));
+    off_t off1 = fh.tell();
+    OK(fh.read_line(line2));
+    off_t off2 = fh.tell();
+    OK(fh.read_line(line3));
+    off_t off3 = fh.tell();
+    OK(fh.read_line(line4));
+    off_t off4 = fh.tell();
+
+    IS(line1, "@HWI-ST1106:815:H154GADXX:1:1101:1244:2196 1:N:0:CTTGTA");
+    IS(off1, 56);
+    IS(line2, "AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCTCCCACGTGTGGGAGCTTGTATGTACCTTAT");
+    IS(off2, 207);
+    IS(line3, "+");
+    IS(off3, 209);
+    IS(line4, "=?@DFADDHHAHDGGBGGGIGHBEGGHEI>FGIIGCGGCH3?@FEB@@@FGICHG==AHFFEFEEDDDDDDC<>A>A:ACDCC>C<@BB>C at ACC@CACAC at ACCDDDCA?ABCAC at 9@AA8??8><ADB<>B8<B:C?>@>>34>:@CD");
+    IS(off4, 360);
+    IS(gztell(fh.handle), 361);
+
+    fh.seek(off3, 0);
+    string line4again;
+    OK(fh.read_line(line4again));
+    IS(line4again, line4);
+
+    fh.seek(off1, 0);
+    string line2again;
+    OK(fh.read_line(line2again));
+    IS(line2again, line2);
+
+    fh.seek(off2, SEEK_SET);
+    fh.seek(off3-off2, SEEK_CUR);
+    IS(fh.tell(), off3);
+    IS(gztell(fh.handle), off3+1);
+    {
+        string line;
+        OK(fh.read_line(line));
+        IS(line, line4);
+    }
+}
diff --git a/t/t_header_util.cpp b/t/t_header_util.cpp
new file mode 100644
index 0000000..5452162
--- /dev/null
+++ b/t/t_header_util.cpp
@@ -0,0 +1,37 @@
+#include "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+#include "htio2/HeaderUtil.h"
+#include "TestFramework.h"
+#include "TestConfig.h"
+
+void TestFramework::content()
+{
+    htio2::FastqIO io(TEST_SOURCE_DIR"/test1.fastq", htio2::READ, htio2::COMPRESS_PLAIN);
+    htio2::FastqSeq seq;
+    OK(io.next_seq(seq));
+
+    htio2::HeaderFormat format = htio2::HEADER_UNKNOWN;
+    bool with_ncbi = false;
+    htio2::guess_header_format(seq.id+" "+seq.desc, format, with_ncbi);
+    IS(format, htio2::HEADER_1_8);
+    OK(!with_ncbi);
+
+    htio2::guess_header_format("SRR000000 "+seq.id+" "+seq.desc+" length=100", format, with_ncbi);
+    IS(format, htio2::HEADER_1_8);
+    OK(with_ncbi);
+
+    format = htio2::HEADER_UNKNOWN;
+    with_ncbi = false;
+    htio2::guess_header_format(io, 5, format, with_ncbi);
+    IS(format, htio2::HEADER_1_8);
+    OK(!with_ncbi);
+
+    {
+        htio2::HeaderParser header_parser(htio2::HEADER_1_8, false);
+        header_parser.parse(seq.id, seq.desc);
+        IS(header_parser.lane, 1);
+        IS(header_parser.tile, 1101);
+        IS(header_parser.barcode, "CTTGTA");
+    }
+
+}
diff --git a/t/t_ht_convert.cpp b/t/t_ht_convert.cpp
new file mode 100644
index 0000000..d2e1deb
--- /dev/null
+++ b/t/t_ht_convert.cpp
@@ -0,0 +1,17 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+
+void TestFramework::content()
+{
+    {
+        const char* cmd = "../src/ht2-convert -q -P --out-pe-itlv -i " TEST_SOURCE_DIR "/test1.fastq.gz " TEST_SOURCE_DIR "/test2.fastq.gz -o interleave";
+        ok(!system(cmd), cmd);
+        OK(text_file_eq(TEST_SOURCE_DIR "/test_interleave.fastq.gz", "interleave.fastq.gz"));
+    }
+    {
+        const char* cmd = "../src/ht2-convert -q -P --pe-itlv -i " TEST_SOURCE_DIR "/test_interleave.fastq.gz -o non_interleave";
+        ok(!system(cmd), cmd);
+        OK(text_file_eq(TEST_SOURCE_DIR "/test1.fastq.gz", "non_interleave_1.fastq.gz"));
+        OK(text_file_eq(TEST_SOURCE_DIR "/test2.fastq.gz", "non_interleave_2.fastq.gz"));
+    }
+}
diff --git a/t/t_ht_demul.cpp b/t/t_ht_demul.cpp
new file mode 100644
index 0000000..b9751a0
--- /dev/null
+++ b/t/t_ht_demul.cpp
@@ -0,0 +1,126 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+
+#include "htio2/PlainFileHandle.h"
+#include "htio2/FastqSeq.h"
+#include "htio2/FastqIO.h"
+
+#include "htio2/JUCE-3.0.8/JuceHeader.h"
+
+#include <vector>
+#include <map>
+
+using namespace std;
+using namespace htio2::juce;
+
+#define FILE1 TEST_SOURCE_DIR "/test1.fastq.gz"
+#define FILE2 TEST_SOURCE_DIR "/test2.fastq.gz"
+#define BARCODE TEST_SOURCE_DIR "/barcodes.tab"
+
+typedef map<string, pair<string,string> > BarcodeMap;
+
+void read_barcode(BarcodeMap& barcodes)
+{
+    htio2::PlainFileHandle fh_barcode(BARCODE, htio2::READ);
+    string line;
+
+    while (fh_barcode.read_line(line))
+    {
+        size_t tab1 = line.find_first_of('\t');
+        if (tab1 == string::npos)
+        {
+            cerr << "line contain no TAB" << endl
+                 << line << endl;
+            exit(EXIT_FAILURE);
+        }
+
+        size_t tab2 = line.find_first_of('\t', tab1+1);
+        if (tab2 == string::npos)
+        {
+            cerr << "line contain no 2nd TAB" << endl
+                 << line << endl;
+            exit(EXIT_FAILURE);
+        }
+
+        string proj(line.substr(0, tab1));
+        string sample(line.substr(tab1 + 1, tab2 - tab1 - 1));
+        string barcode(line.substr(tab2 + 1));
+
+        barcodes.insert(make_pair(barcode, make_pair(proj, sample)));
+    }
+
+}
+
+void TestFramework::content()
+{
+    const char* cmd =
+            "../src/ht2-demul -q -P"
+            " -i " FILE1 " " FILE2
+            " --barcode " BARCODE
+            " -o demul";
+    ok(!system(cmd), cmd);
+
+    BarcodeMap barcodes;
+    read_barcode(barcodes);
+
+    File dir_out("demul");
+    size_t n_seq = 0;
+
+    // traverse projects
+    Array<File> dirs_project;
+    dir_out.findChildFiles(dirs_project, File::findDirectories, false);
+
+    htio2::FastqSeq seq;
+
+    for (int i_proj = 0; i_proj < dirs_project.size(); i_proj++)
+    {
+        const File& dir_proj = dirs_project[i_proj];
+        String proj_name = dir_proj.getFileName();
+
+        Array<File> seq_files;
+        dir_proj.findChildFiles(seq_files, File::findFiles, false);
+
+        for (int i_file = 0; i_file < seq_files.size(); i_file++)
+        {
+            const File& seq_file = seq_files[i_file];
+            String file_base = seq_file.getFileName();
+            int i_suffix = file_base.indexOf(".fastq");
+            String sample_name = file_base.substring(0, i_suffix-2);
+
+            // check the content of this file
+            htio2::FastqIO fh(seq_file.getFullPathName().toStdString(), htio2::READ);
+            while (fh.next_seq(seq))
+            {
+                n_seq++;
+                string barcode = seq.desc.substr(seq.desc.find_last_of(':')+1);
+                BarcodeMap::iterator it_barcode = barcodes.find(barcode);
+                ok(it_barcode != barcodes.end(), (barcode + " barcode exist").c_str());
+                const string& barcode_proj = it_barcode->second.first;
+                const string& barcode_sample = it_barcode->second.second;
+
+                IS(file_base[i_suffix-1], seq.desc[0]);
+                is(barcode_proj,   proj_name.toStdString(),   ("project " + barcode_proj + " is " + proj_name.toStdString()).c_str());
+                is(barcode_sample, sample_name.toStdString(), ("sample " + barcode_sample + " is " + sample_name.toStdString()).c_str());
+            }
+        }
+    }
+
+    // traverse demul failed files
+    Array<File> files_fail;
+    dir_out.findChildFiles(files_fail, File::findFiles, false, "demul_failed*.fastq.gz");
+    IS(files_fail.size(), 2);
+
+    for (int i_file = 0; i_file < files_fail.size(); i_file++)
+    {
+        htio2::FastqIO fh(files_fail[i_file].getFullPathName().toStdString(), htio2::READ);
+        while (fh.next_seq(seq))
+        {
+            n_seq++;
+            string barcode = seq.desc.substr(seq.desc.find_last_of(':')+1);
+            BarcodeMap::iterator it = barcodes.find(barcode);
+            ok(it == barcodes.end(), (barcode + " unknown").c_str());
+        }
+    }
+
+    IS(n_seq, 200);
+}
diff --git a/t/t_ht_filter.cpp b/t/t_ht_filter.cpp
new file mode 100644
index 0000000..49dee7e
--- /dev/null
+++ b/t/t_ht_filter.cpp
@@ -0,0 +1,101 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+
+#include "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+
+#define BIN "../src/ht2-filter"
+#define FILE1 TEST_SOURCE_DIR "/test1.fastq.gz"
+#define FILE2 TEST_SOURCE_DIR "/test2.fastq.gz"
+
+#include "htio2/JUCE-3.0.8/JuceHeader.h"
+
+using namespace std;
+using namespace htio2::juce;
+
+size_t high_qual_len(const string& qual)
+{
+    size_t num = 0;
+
+    for (size_t i = 0; i < qual.length(); i++)
+    {
+        // 33-based, quality cutoff 30
+        if (qual[i] >= 33 + 30)
+            num++;
+    }
+
+    return num;
+}
+
+void TestFramework::content()
+{
+    // paired-end test
+    {
+        const char* cmd =
+                BIN
+                " -q -P"
+                " -Q 30 -L 120"
+                " -i " FILE1 " " FILE2
+                " -o filt"
+                " -u filt_fail";
+        ok(!system(cmd), cmd);
+        OK(text_file_eq(TEST_SOURCE_DIR "/filt_1.fastq.gz", "filt_1.fastq.gz"));
+        OK(text_file_eq(TEST_SOURCE_DIR "/filt_2.fastq.gz", "filt_2.fastq.gz"));
+        OK(text_file_eq(TEST_SOURCE_DIR "/filt_s.fastq.gz", "filt_s.fastq.gz"));
+        // ID match
+        OK(seq_file_id_eq("filt_1.fastq.gz", "filt_2.fastq.gz"));
+        OK(seq_file_id_eq("filt_fail_1.fastq.gz", "filt_fail_2.fastq.gz"));
+        OK(seq_file_id_eq("filt_s.fastq.gz", "filt_fail_s.fastq.gz"));
+    }
+
+    {
+        const char* cmd =
+                BIN
+                " -q -S"
+                " -Q 30 -L 120"
+                " -i " TEST_SOURCE_DIR "/test_interleave.fastq.gz"
+                " -o filt -u filt_fail";
+        ok(!system(cmd), cmd);
+        OK(text_file_eq(TEST_SOURCE_DIR "/filt.fastq.gz", "filt.fastq.gz"));
+        OK(text_file_eq(TEST_SOURCE_DIR "/filt_fail.fastq.gz", "filt_fail.fastq.gz"));
+    }
+
+    {
+        vector<string> files_accepted;
+        files_accepted.push_back("filt_1.fastq.gz");
+        files_accepted.push_back("filt_2.fastq.gz");
+        files_accepted.push_back("filt_s.fastq.gz");
+        files_accepted.push_back("filt.fastq.gz");
+
+        vector<string> files_rejected;
+        files_rejected.push_back("filt_fail_1.fastq.gz");
+        files_rejected.push_back("filt_fail_2.fastq.gz");
+        files_rejected.push_back("filt_fail_s.fastq.gz");
+        files_rejected.push_back("filt_fail.fastq.gz");
+
+        size_t num = 0;
+        htio2::FastqSeq seq;
+
+        for (size_t i = 0; i < files_accepted.size(); i++)
+        {
+            htio2::FastqIO fh(files_accepted[i], htio2::READ, htio2::COMPRESS_GZIP);
+            while (fh.next_seq(seq))
+            {
+                GE(high_qual_len(seq.quality), 120);
+                num++;
+            }
+        }
+
+        for (size_t i = 0; i < files_rejected.size(); i++)
+        {
+            htio2::FastqIO fh(files_rejected[i], htio2::READ, htio2::COMPRESS_GZIP);
+            while (fh.next_seq(seq))
+            {
+                LT(high_qual_len(seq.quality), 120);
+                num++;
+            }
+        }
+
+        is(num, 400, "400 sequences in total");
+    }
+}
diff --git a/t/t_ht_lane_tile.cpp b/t/t_ht_lane_tile.cpp
new file mode 100644
index 0000000..b45e372
--- /dev/null
+++ b/t/t_ht_lane_tile.cpp
@@ -0,0 +1,38 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+
+#include "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+
+using namespace std;
+
+#define BIN "../src/ht2-lane-tile"
+#define INPUT TEST_SOURCE_DIR"/test_interleave.fastq.gz"
+
+size_t count_seq(const string& file)
+{
+    size_t result = 0;
+    htio2::FastqIO fh_accept(file, htio2::READ);
+    htio2::FastqSeq seq;
+    while (fh_accept.next_seq(seq))
+        result++;
+    return result;
+}
+
+void TestFramework::content()
+{
+    const char* cmd = BIN
+            " -q"
+            " -i " INPUT
+            " -o lane_tile"
+            " -u lane_tile_reject"
+            " -T 1101";
+
+    ok(!system(cmd), cmd);
+
+    size_t n_accept = count_seq("lane_tile.fastq.gz");
+    size_t n_reject = count_seq("lane_tile_reject.fastq.gz");
+
+    IS(n_accept, 0);
+    IS(n_reject, 200);
+}
diff --git a/t/t_ht_overlap.cpp b/t/t_ht_overlap.cpp
new file mode 100644
index 0000000..83a171c
--- /dev/null
+++ b/t/t_ht_overlap.cpp
@@ -0,0 +1,11 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+
+void TestFramework::content()
+{
+    const char* cmd = "../src/ht2-overlap -q -i " TEST_SOURCE_DIR "/test1.fastq.gz " TEST_SOURCE_DIR "/test2.fastq.gz -o ovlp -u novlp";
+    ok(!system(cmd), cmd);
+    OK(text_file_eq("ovlp.fastq.gz", TEST_SOURCE_DIR "/test_ovlp.fastq.gz"));
+    OK(text_file_eq("novlp_1.fastq.gz", TEST_SOURCE_DIR "/test_novlp_1.fastq.gz"));
+    OK(text_file_eq("novlp_2.fastq.gz", TEST_SOURCE_DIR "/test_novlp_2.fastq.gz"));
+}
diff --git a/t/t_ht_rename.cpp b/t/t_ht_rename.cpp
new file mode 100644
index 0000000..cf10afe
--- /dev/null
+++ b/t/t_ht_rename.cpp
@@ -0,0 +1,37 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+#include "htio2/FastqIO.h"
+#include "htio2/FastqSeq.h"
+
+void TestFramework::content()
+{
+    const char* cmd = "../src/ht2-rename --quiet -i " TEST_SOURCE_DIR "/test1.fastq.gz -o rename --prefix aaa_ --suffix _bbb";
+    ok(!system(cmd), cmd);
+
+    htio2::FastqIO fh("rename.fastq.gz", htio2::READ, htio2::COMPRESS_GZIP);
+    htio2::FastqSeq seq;
+
+    size_t n = 0;
+    while (fh.next_seq(seq))
+    {
+        n++;
+        if (n==1)
+        {
+            IS(seq.id, "aaa_1_bbb");
+            IS(seq.seq,     "AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCTCCCACGTGTGGGAGCTTGTATGTACCTTAT");
+            IS(seq.quality, "=?@DFADDHHAHDGGBGGGIGHBEGGHEI>FGIIGCGGCH3?@FEB@@@FGICHG==AHFFEFEEDDDDDDC<>A>A:ACDCC>C<@BB>C at ACC@CACAC at ACCDDDCA?ABCAC at 9@AA8??8><ADB<>B8<B:C?>@>>34>:@CD");
+        }
+        else if (n==2)
+        {
+            IS(seq.id, "aaa_2_bbb");
+            IS(seq.seq,     "AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTGGTTCGCTATGTAAAGCTCTATCAGCAGGGAAGATNNTGACGGTACCTGACTAAGAAGCTCCGGCTAACTA");
+            IS(seq.quality, "@@CFFDFFGHHHHJJHFHGHHGIIHIJJJJIHHJJJJGIGIJHIJGIICFC at ECEHAB@4=;@DBB8B at B:@:>C>>CCCD:?CDDDDBDEEEDCCDCDDCCCC@@ADD?BDBD##++8?@B9A9CDCCCCCDDCDCCD at C>BBDDCDDD");
+        }
+        else if (n==100)
+        {
+            IS(seq.id, "aaa_100_bbb");
+            IS(seq.seq,     "ATCGCAAATCATGGTGGGGATGATACGGCGTTTCATTGCGGAGCAGGAAATTGTTATGTTCTTATCAGGAGATTATAATTGGCCTGACAAATGGATGTGATTTATTTATTGGGCTCAATTGGGCTAGGTTGGGGATCTTCATTTGTCCAC");
+            IS(seq.quality, "@<BFFFFFHGHHHJCFGIIFIJIGJJJJJJIJJGIIJJJJJJHFFFFFCCEDECDDEDFEEEDCDCCDDABDDCDDEEEEDDDDDBCDDDDDDD(:@AACDDDDEDDDEDDDDBDAACCDCDDDDBDDCDDDDD0<BDCDEEEEEE at CDD");
+        }
+    }
+}
diff --git a/t/t_ht_sample.cpp b/t/t_ht_sample.cpp
new file mode 100644
index 0000000..1a8020d
--- /dev/null
+++ b/t/t_ht_sample.cpp
@@ -0,0 +1,81 @@
+#include "TestConfig.h"
+#include "TestFramework.h"
+
+#include "htio2/PairedEndIO.h"
+#include "htio2/PlainFileHandle.h"
+#include "htio2/Cast.h"
+
+#include <set>
+
+using namespace std;
+
+void read_idx(const string& file, vector<int64_t>& result)
+{
+    htio2::PlainFileHandle fh(file, htio2::READ);
+    string line;
+    while (fh.read_line(line))
+    {
+        int64_t idx;
+        if (!htio2::from_string<int64_t>(line, idx))
+        {
+            fprintf(stderr, "failed to parse line to integer: \"%s\"\n", line.c_str());
+            abort();
+        }
+        printf("  %ld\n", idx);
+        result.push_back(idx);
+    }
+}
+
+bool operator == (htio2::FastqSeq& seq1, htio2::FastqSeq& seq2)
+{
+    return seq1.id == seq2.id && seq1.desc == seq2.desc && seq1.seq == seq2.seq && seq1.quality == seq2.quality;
+}
+
+void TestFramework::content()
+{
+    const char* cmd = "../src/ht2-sample -P"
+                      " -i " TEST_SOURCE_DIR "/test1.fastq.gz " TEST_SOURCE_DIR "/test2.fastq.gz"
+                      " -o sample"
+                      " --out-id sample_id"
+                      " --seed 3 --num 15";
+    ok(!system(cmd), cmd);
+
+    vector<int64_t> idx_used;
+    read_idx("sample_id", idx_used);
+    IS(idx_used.size(), 15);
+
+    htio2::PairedEndIO fh_input(TEST_SOURCE_DIR "/test1.fastq.gz",
+                                TEST_SOURCE_DIR "/test2.fastq.gz",
+                                htio2::READ,
+                                htio2::STRAND_FWD,
+                                htio2::STRAND_REV);
+
+    htio2::FastqSeq seq1;
+    htio2::FastqSeq seq2;
+    vector<htio2::FastqSeq> seqs_1;
+    vector<htio2::FastqSeq> seqs_2;
+
+    while (fh_input.next_pair(seq1, seq2, htio2::STRAND_FWD, htio2::STRAND_REV))
+    {
+        seqs_1.push_back(seq1);
+        seqs_2.push_back(seq2);
+    }
+
+    htio2::PairedEndIO fh_result("sample_1.fastq.gz",
+                                 "sample_2.fastq.gz",
+                                 htio2::READ,
+                                 htio2::STRAND_FWD,
+                                 htio2::STRAND_REV);
+
+
+    size_t n = 0;
+    while (fh_result.next_pair(seq1, seq2, htio2::STRAND_FWD, htio2::STRAND_REV))
+    {
+        IS(seq1.desc[0], '1');
+        IS(seq2.desc[0], '2');
+        OK(seqs_1[idx_used[n]] == seq1);
+        OK(seqs_2[idx_used[n]] == seq2);
+        n++;
+    }
+
+}
diff --git a/t/t_ht_trim.cpp b/t/t_ht_trim.cpp
new file mode 100644
index 0000000..76821c4
--- /dev/null
+++ b/t/t_ht_trim.cpp
@@ -0,0 +1,24 @@
+#include "TestConfig.h"
+#include "TestFramework.h"
+
+void TestFramework::content()
+{
+    {
+        const char* cmd = "../src/ht2-trim --quiet -i " TEST_SOURCE_DIR "/test1.fastq.gz -S head -o trim_head";
+        ok(!system(cmd), cmd);
+        OK(text_file_eq(TEST_SOURCE_DIR "/trim_head.fastq.gz", "trim_head.fastq.gz"));
+    }
+
+    {
+        const char* cmd = "../src/ht2-trim --quiet -i " TEST_SOURCE_DIR "/test1.fastq.gz -S tail -o trim_tail";
+        ok(!system(cmd), cmd);
+        OK(text_file_eq(TEST_SOURCE_DIR "/trim_tail.fastq.gz", "trim_tail.fastq.gz"));
+    }
+
+    {
+        const char* cmd = "../src/ht2-trim --quiet -i " TEST_SOURCE_DIR "/test1.fastq.gz -o trim_both";
+        ok(!system(cmd), cmd);
+        OK(text_file_eq(TEST_SOURCE_DIR "/trim_both.fastq.gz", "trim_both.fastq.gz"));
+    }
+}
+
diff --git a/t/t_kmer_aa.cpp b/t/t_kmer_aa.cpp
new file mode 100644
index 0000000..a3e57cf
--- /dev/null
+++ b/t/t_kmer_aa.cpp
@@ -0,0 +1,60 @@
+#include "TestFramework.h"
+#include "htio2/Kmer.h"
+
+using namespace htio2;
+using namespace std;
+
+void TestFramework::content()
+{
+    for (char c = 'A'; c <= 'Z'; c++)
+    {
+        cout << "encode " << c << endl;
+        IS(encode_aa(c), EncodedType(c-'A'));
+    }
+
+    for (EncodedType enc = 0; enc <= 25; enc++)
+    {
+        cout << "decode " << int(enc) << endl;
+        IS(decode_aa(enc), 'A'+enc=='O' ? '*' : char('A'+enc));
+    }
+
+    {
+        uint64_t manual_kmer =
+                ('A'-'A') +
+                ('F'-'A') * 26 +
+                ('O'-'A') * 26 * 26 +
+                ('C'-'A') * 26 * 26 * 26 +
+                ('Z'-'A') * 26 * 26 * 26 * 26;
+        IS(gen_kmer_aa<uint64_t>("AF*CZ"), manual_kmer);
+    }
+
+    {
+        EncodedSeq enc;
+        encode_aa("AF*KZ", enc);
+        IS(enc.size(), size_t(5));
+        IS(enc[0], EncodedType('A'-'A'));
+        IS(enc[1], EncodedType('F'-'A'));
+        IS(enc[2], EncodedType('O'-'A'));
+        IS(enc[3], EncodedType('K'-'A'));
+        IS(enc[4], EncodedType('Z'-'A'));
+
+        vector<uint16_t> kmers;
+        gen_kmer_aa(enc, kmers, 3);
+        IS(kmers.size(), size_t(3));
+        IS(kmers[0], uint16_t( ('A'-'A') + ('F'-'A')*26 + ('O'-'A')*26*26 ));
+        IS(kmers[1], uint16_t( ('F'-'A') + ('O'-'A')*26 + ('K'-'A')*26*26 ));
+        IS(kmers[2], uint16_t( ('O'-'A') + ('K'-'A')*26 + ('Z'-'A')*26*26 ));
+
+
+        string dec;
+        decode_aa(enc, dec);
+        IS(dec, string("AF*KZ"));
+
+        encode_aa("*", enc);
+        IS(enc.size(), size_t(1));
+        IS(enc[0], EncodedType('O'-'A'));
+
+        decode_aa(enc, dec);
+        IS(dec, string("*"));
+    }
+}
diff --git a/t/t_kmer_nt4_16.cpp b/t/t_kmer_nt4_16.cpp
new file mode 100644
index 0000000..62974b1
--- /dev/null
+++ b/t/t_kmer_nt4_16.cpp
@@ -0,0 +1,96 @@
+#include "TestFramework.h"
+#include "htio2/Kmer.h"
+
+#include <limits>
+
+using namespace htio2;
+using namespace std;
+
+typedef uint16_t KmerType;
+
+void TestFramework::content()
+{
+    IS(ENCODED_NT4_A, 0);
+    IS(ENCODED_NT4_T, 3);
+    IS(ENCODED_NT4_G, 1);
+    IS(ENCODED_NT4_C, 2);
+
+    IS(encode_nt4('N'), ENCODED_ERROR);
+    IS(encode_nt4('A'), ENCODED_NT4_A);
+    IS(encode_nt4('T'), ENCODED_NT4_T);
+    IS(encode_nt4('G'), ENCODED_NT4_G);
+    IS(encode_nt4('C'), ENCODED_NT4_C);
+    IS(encode_nt4('Z'), ENCODED_ERROR);
+    IS(encode_nt4('B'), ENCODED_ERROR);
+
+    IS(decode_nt4(ENCODED_ERROR), 'N');
+    IS(decode_nt4(ENCODED_NT4_A), 'A');
+    IS(decode_nt4(ENCODED_NT4_T), 'T');
+    IS(decode_nt4(ENCODED_NT4_G), 'G');
+    IS(decode_nt4(ENCODED_NT4_C), 'C');
+
+    // encode
+    EncodedSeq enc;
+    encode_nt4("ATGXCATA", enc);
+    IS(enc.size(), 8);
+    IS(enc[0], ENCODED_NT4_A);
+    IS(enc[1], ENCODED_NT4_T);
+    IS(enc[2], ENCODED_NT4_G);
+    IS(enc[3], ENCODED_ERROR);
+    IS(enc[4], ENCODED_NT4_C);
+    IS(enc[5], ENCODED_NT4_A);
+    IS(enc[6], ENCODED_NT4_T);
+    IS(enc[7], ENCODED_NT4_A);
+
+    {
+        // generate kmer
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt4(enc, kmers, 3));
+        IS(kmers.size(), 6);
+        IS(kmers[0], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_G*4*4);
+        IS(kmers[1], numeric_limits<KmerType>::max());
+        IS(kmers[2], numeric_limits<KmerType>::max());
+        IS(kmers[3], numeric_limits<KmerType>::max());
+        IS(kmers[4], ENCODED_NT4_C + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
+        IS(kmers[5], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_A*4*4);
+
+        // decode kmer
+        IS(decode_kmer_nt4(kmers[0], 3), "ATG");
+        IS(decode_kmer_nt4(kmers[1], 3), "");
+        IS(decode_kmer_nt4(kmers[2], 3), "");
+        IS(decode_kmer_nt4(kmers[3], 3), "");
+        IS(decode_kmer_nt4(kmers[4], 3), "CAT");
+        IS(decode_kmer_nt4(kmers[5], 3), "ATA");
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt4(enc, kmers, 7));
+        IS(kmers.size(), 2);
+
+        KmerType kmer =
+                ENCODED_NT4_A +
+                ENCODED_NT4_T *4 +
+                ENCODED_NT4_G *4*4 +
+                ENCODED_NT4_C *4*4*4 +
+                ENCODED_NT4_A *4*4*4*4 +
+                ENCODED_NT4_T *4*4*4*4*4 +
+                ENCODED_NT4_A *4*4*4*4*4*4;
+        IS(gen_kmer_nt4<KmerType>("ATGCATA"), kmer);
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(!gen_kmer_nt4(enc, kmers, 8));
+        IS(kmers.size(), 0);
+
+        IS(gen_kmer_nt4<KmerType>("ATGCATAA"), numeric_limits<KmerType>::max());
+    }
+
+    // decode
+    {
+        string dec;
+        decode_nt4(enc, dec);
+        IS(dec, "ATGNCATA");
+    }
+}
diff --git a/t/t_kmer_nt4_32.cpp b/t/t_kmer_nt4_32.cpp
new file mode 100644
index 0000000..db90c01
--- /dev/null
+++ b/t/t_kmer_nt4_32.cpp
@@ -0,0 +1,109 @@
+#include "TestFramework.h"
+#include "htio2/Kmer.h"
+
+#include <limits>
+
+using namespace htio2;
+using namespace std;
+
+typedef uint32_t KmerType;
+
+void TestFramework::content()
+{
+    // encode
+    EncodedSeq enc;
+    encode_nt4("ATGXCATAATGXCATA", enc);
+    IS(enc.size(), 16);
+    IS(enc[0], ENCODED_NT4_A);
+    IS(enc[1], ENCODED_NT4_T);
+    IS(enc[2], ENCODED_NT4_G);
+    IS(enc[3], ENCODED_ERROR);
+    IS(enc[4], ENCODED_NT4_C);
+    IS(enc[5], ENCODED_NT4_A);
+    IS(enc[6], ENCODED_NT4_T);
+    IS(enc[7], ENCODED_NT4_A);
+    IS(enc[8], ENCODED_NT4_A);
+    IS(enc[9], ENCODED_NT4_T);
+    IS(enc[10], ENCODED_NT4_G);
+    IS(enc[11], ENCODED_ERROR);
+    IS(enc[12], ENCODED_NT4_C);
+    IS(enc[13], ENCODED_NT4_A);
+    IS(enc[14], ENCODED_NT4_T);
+    IS(enc[15], ENCODED_NT4_A);
+
+    {
+        // generate kmer
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt4(enc, kmers, 3));
+        IS(kmers.size(), 14);
+        IS(kmers[0], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_G*4*4);
+        IS(kmers[1], numeric_limits<KmerType>::max());
+        IS(kmers[2], numeric_limits<KmerType>::max());
+        IS(kmers[3], numeric_limits<KmerType>::max());
+        IS(kmers[4], ENCODED_NT4_C + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
+        IS(kmers[5], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_A*4*4);
+        IS(kmers[6], ENCODED_NT4_T + ENCODED_NT4_A*4 + ENCODED_NT4_A*4*4);
+        IS(kmers[7], ENCODED_NT4_A + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
+        IS(kmers[8], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_G*4*4);
+        IS(kmers[9], numeric_limits<KmerType>::max());
+        IS(kmers[10], numeric_limits<KmerType>::max());
+        IS(kmers[11], numeric_limits<KmerType>::max());
+        IS(kmers[12], ENCODED_NT4_C + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
+        IS(kmers[13], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_A*4*4);
+
+        // decode kmer
+        IS(decode_kmer_nt4(kmers[0], 3), "ATG");
+        IS(decode_kmer_nt4(kmers[1], 3), "");
+        IS(decode_kmer_nt4(kmers[2], 3), "");
+        IS(decode_kmer_nt4(kmers[3], 3), "");
+        IS(decode_kmer_nt4(kmers[4], 3), "CAT");
+        IS(decode_kmer_nt4(kmers[5], 3), "ATA");
+        IS(decode_kmer_nt4(kmers[6], 3), "TAA");
+        IS(decode_kmer_nt4(kmers[7], 3), "AAT");
+        IS(decode_kmer_nt4(kmers[8], 3), "ATG");
+        IS(decode_kmer_nt4(kmers[9], 3), "");
+        IS(decode_kmer_nt4(kmers[10], 3), "");
+        IS(decode_kmer_nt4(kmers[11], 3), "");
+        IS(decode_kmer_nt4(kmers[12], 3), "CAT");
+        IS(decode_kmer_nt4(kmers[13], 3), "ATA");
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt4(enc, kmers, 15));
+        IS(kmers.size(), 2);
+
+        KmerType kmer =
+                ENCODED_NT4_A +
+                ENCODED_NT4_T *4 +
+                ENCODED_NT4_G *4*4 +
+                ENCODED_NT4_C *4*4*4 +
+                ENCODED_NT4_A *4*4*4*4 +
+                ENCODED_NT4_T *4*4*4*4*4 +
+                ENCODED_NT4_A *4*4*4*4*4*4 +
+                ENCODED_NT4_A *4*4*4*4*4*4*4 +
+                ENCODED_NT4_T *4*4*4*4*4*4*4*4 +
+                ENCODED_NT4_G *4*4*4*4*4*4*4*4*4 +
+                ENCODED_NT4_C *4*4*4*4*4*4*4*4*4*4 +
+                ENCODED_NT4_A *4*4*4*4*4*4*4*4*4*4*4 +
+                ENCODED_NT4_T *4*4*4*4*4*4*4*4*4*4*4*4 +
+                ENCODED_NT4_A *4*4*4*4*4*4*4*4*4*4*4*4*4 +
+                ENCODED_NT4_A *4*4*4*4*4*4*4*4*4*4*4*4*4*4;
+        IS(gen_kmer_nt4<KmerType>("ATGCATAATGCATAA"), kmer);
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(!gen_kmer_nt4(enc, kmers, 16));
+        IS(kmers.size(), 0);
+
+        IS(gen_kmer_nt4<KmerType>("ATGCATAATGCATAAA"), numeric_limits<KmerType>::max());
+    }
+
+    // decode
+    {
+        string dec;
+        decode_nt4(enc, dec);
+        IS(dec, "ATGNCATAATGNCATA");
+    }
+}
diff --git a/t/t_kmer_nt4_64.cpp b/t/t_kmer_nt4_64.cpp
new file mode 100644
index 0000000..8f31773
--- /dev/null
+++ b/t/t_kmer_nt4_64.cpp
@@ -0,0 +1,173 @@
+#include "TestFramework.h"
+#include "htio2/Kmer.h"
+
+#include <limits>
+
+using namespace htio2;
+using namespace std;
+
+typedef uint64_t KmerType;
+
+void TestFramework::content()
+{
+    // encode
+    EncodedSeq enc;
+    encode_nt4("ATGXCATAATGXCATAATGXCATAATGXCATA", enc);
+    IS(enc.size(), 32);
+    IS(enc[0], ENCODED_NT4_A);
+    IS(enc[1], ENCODED_NT4_T);
+    IS(enc[2], ENCODED_NT4_G);
+    IS(enc[3], ENCODED_ERROR);
+    IS(enc[4], ENCODED_NT4_C);
+    IS(enc[5], ENCODED_NT4_A);
+    IS(enc[6], ENCODED_NT4_T);
+    IS(enc[7], ENCODED_NT4_A);
+    IS(enc[8], ENCODED_NT4_A);
+    IS(enc[9], ENCODED_NT4_T);
+    IS(enc[10], ENCODED_NT4_G);
+    IS(enc[11], ENCODED_ERROR);
+    IS(enc[12], ENCODED_NT4_C);
+    IS(enc[13], ENCODED_NT4_A);
+    IS(enc[14], ENCODED_NT4_T);
+    IS(enc[15], ENCODED_NT4_A);
+    IS(enc[16], ENCODED_NT4_A);
+    IS(enc[17], ENCODED_NT4_T);
+    IS(enc[18], ENCODED_NT4_G);
+    IS(enc[19], ENCODED_ERROR);
+    IS(enc[20], ENCODED_NT4_C);
+    IS(enc[21], ENCODED_NT4_A);
+    IS(enc[22], ENCODED_NT4_T);
+    IS(enc[23], ENCODED_NT4_A);
+    IS(enc[24], ENCODED_NT4_A);
+    IS(enc[25], ENCODED_NT4_T);
+    IS(enc[26], ENCODED_NT4_G);
+    IS(enc[27], ENCODED_ERROR);
+    IS(enc[28], ENCODED_NT4_C);
+    IS(enc[29], ENCODED_NT4_A);
+    IS(enc[30], ENCODED_NT4_T);
+    IS(enc[31], ENCODED_NT4_A);
+
+    {
+        // generate kmer
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt4(enc, kmers, 3));
+        IS(kmers.size(), 30);
+        IS(kmers[0], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_G*4*4);
+        IS(kmers[1], numeric_limits<KmerType>::max());
+        IS(kmers[2], numeric_limits<KmerType>::max());
+        IS(kmers[3], numeric_limits<KmerType>::max());
+        IS(kmers[4], ENCODED_NT4_C + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
+        IS(kmers[5], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_A*4*4);
+        IS(kmers[6], ENCODED_NT4_T + ENCODED_NT4_A*4 + ENCODED_NT4_A*4*4);
+        IS(kmers[7], ENCODED_NT4_A + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
+        IS(kmers[8], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_G*4*4);
+        IS(kmers[9], numeric_limits<KmerType>::max());
+        IS(kmers[10], numeric_limits<KmerType>::max());
+        IS(kmers[11], numeric_limits<KmerType>::max());
+        IS(kmers[12], ENCODED_NT4_C + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
+        IS(kmers[13], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_A*4*4);
+        IS(kmers[14], ENCODED_NT4_T + ENCODED_NT4_A*4 + ENCODED_NT4_A*4*4);
+        IS(kmers[15], ENCODED_NT4_A + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
+        IS(kmers[16], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_G*4*4);
+        IS(kmers[17], numeric_limits<KmerType>::max());
+        IS(kmers[18], numeric_limits<KmerType>::max());
+        IS(kmers[19], numeric_limits<KmerType>::max());
+        IS(kmers[20], ENCODED_NT4_C + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
+        IS(kmers[21], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_A*4*4);
+        IS(kmers[22], ENCODED_NT4_T + ENCODED_NT4_A*4 + ENCODED_NT4_A*4*4);
+        IS(kmers[23], ENCODED_NT4_A + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
+        IS(kmers[24], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_G*4*4);
+        IS(kmers[25], numeric_limits<KmerType>::max());
+        IS(kmers[26], numeric_limits<KmerType>::max());
+        IS(kmers[27], numeric_limits<KmerType>::max());
+        IS(kmers[28], ENCODED_NT4_C + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
+        IS(kmers[29], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_A*4*4);
+
+        // decode kmer
+        IS(decode_kmer_nt4(kmers[0], 3), "ATG");
+        IS(decode_kmer_nt4(kmers[1], 3), "");
+        IS(decode_kmer_nt4(kmers[2], 3), "");
+        IS(decode_kmer_nt4(kmers[3], 3), "");
+        IS(decode_kmer_nt4(kmers[4], 3), "CAT");
+        IS(decode_kmer_nt4(kmers[5], 3), "ATA");
+        IS(decode_kmer_nt4(kmers[6], 3), "TAA");
+        IS(decode_kmer_nt4(kmers[7], 3), "AAT");
+        IS(decode_kmer_nt4(kmers[8], 3), "ATG");
+        IS(decode_kmer_nt4(kmers[9], 3), "");
+        IS(decode_kmer_nt4(kmers[10], 3), "");
+        IS(decode_kmer_nt4(kmers[11], 3), "");
+        IS(decode_kmer_nt4(kmers[12], 3), "CAT");
+        IS(decode_kmer_nt4(kmers[13], 3), "ATA");
+        IS(decode_kmer_nt4(kmers[14], 3), "TAA");
+        IS(decode_kmer_nt4(kmers[15], 3), "AAT");
+        IS(decode_kmer_nt4(kmers[16], 3), "ATG");
+        IS(decode_kmer_nt4(kmers[17], 3), "");
+        IS(decode_kmer_nt4(kmers[18], 3), "");
+        IS(decode_kmer_nt4(kmers[19], 3), "");
+        IS(decode_kmer_nt4(kmers[20], 3), "CAT");
+        IS(decode_kmer_nt4(kmers[21], 3), "ATA");
+        IS(decode_kmer_nt4(kmers[22], 3), "TAA");
+        IS(decode_kmer_nt4(kmers[23], 3), "AAT");
+        IS(decode_kmer_nt4(kmers[24], 3), "ATG");
+        IS(decode_kmer_nt4(kmers[25], 3), "");
+        IS(decode_kmer_nt4(kmers[26], 3), "");
+        IS(decode_kmer_nt4(kmers[27], 3), "");
+        IS(decode_kmer_nt4(kmers[28], 3), "CAT");
+        IS(decode_kmer_nt4(kmers[29], 3), "ATA");
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt4(enc, kmers, 31));
+        IS(kmers.size(), 2);
+
+        KmerType kmer =
+                ENCODED_NT4_A +
+                ENCODED_NT4_T *4L +
+                ENCODED_NT4_G *4L*4L +
+                ENCODED_NT4_C *4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L +
+                ENCODED_NT4_T *4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_G *4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_C *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_G *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_C *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_G *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_C *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
+                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L;
+        IS(gen_kmer_nt4<KmerType>("ATGCATAATGCATAAATGCATAATGCATAAA"), kmer);
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(!gen_kmer_nt4(enc, kmers, 32));
+        IS(kmers.size(), 0);
+
+        IS(gen_kmer_nt4<KmerType>("ATGCATAATGCATAAAATGCATAATGCATAAA"), numeric_limits<KmerType>::max());
+    }
+
+    // decode
+    {
+        string dec;
+        decode_nt4(enc, dec);
+        IS(dec, "ATGNCATAATGNCATAATGNCATAATGNCATA");
+    }
+}
diff --git a/t/t_kmer_nt5_16.cpp b/t/t_kmer_nt5_16.cpp
new file mode 100644
index 0000000..6457f6c
--- /dev/null
+++ b/t/t_kmer_nt5_16.cpp
@@ -0,0 +1,96 @@
+#include "TestFramework.h"
+#include "htio2/Kmer.h"
+
+#include <limits>
+
+using namespace htio2;
+using namespace std;
+
+typedef uint16_t KmerType;
+
+void TestFramework::content()
+{
+    IS(ENCODED_NT5_A, 0);
+    IS(ENCODED_NT5_T, 4);
+    IS(ENCODED_NT5_G, 1);
+    IS(ENCODED_NT5_C, 3);
+    IS(ENCODED_NT5_N, 2);
+
+    IS(encode_nt5('N'), ENCODED_NT5_N);
+    IS(encode_nt5('A'), ENCODED_NT5_A);
+    IS(encode_nt5('T'), ENCODED_NT5_T);
+    IS(encode_nt5('G'), ENCODED_NT5_G);
+    IS(encode_nt5('C'), ENCODED_NT5_C);
+    IS(encode_nt5('Z'), ENCODED_ERROR);
+    IS(encode_nt5('B'), ENCODED_ERROR);
+
+    IS(decode_nt5(ENCODED_NT5_N), 'N');
+    IS(decode_nt5(ENCODED_NT5_A), 'A');
+    IS(decode_nt5(ENCODED_NT5_T), 'T');
+    IS(decode_nt5(ENCODED_NT5_G), 'G');
+    IS(decode_nt5(ENCODED_NT5_C), 'C');
+
+    // encode
+    EncodedSeq enc;
+    encode_nt5("ATGXCNTA", enc);
+    IS(enc.size(), 8);
+    IS(enc[0], ENCODED_NT5_A);
+    IS(enc[1], ENCODED_NT5_T);
+    IS(enc[2], ENCODED_NT5_G);
+    IS(enc[3], ENCODED_ERROR);
+    IS(enc[4], ENCODED_NT5_C);
+    IS(enc[5], ENCODED_NT5_N);
+    IS(enc[6], ENCODED_NT5_T);
+    IS(enc[7], ENCODED_NT5_A);
+
+    {
+        // generate kmer
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt5(enc, kmers, 3));
+        IS(kmers.size(), 6);
+        IS(kmers[0], ENCODED_NT5_A + ENCODED_NT5_T*5 + ENCODED_NT5_G*5*5);
+        IS(kmers[1], numeric_limits<KmerType>::max());
+        IS(kmers[2], numeric_limits<KmerType>::max());
+        IS(kmers[3], numeric_limits<KmerType>::max());
+        IS(kmers[4], ENCODED_NT5_C + ENCODED_NT5_N*5 + ENCODED_NT5_T*5*5);
+        IS(kmers[5], ENCODED_NT5_N + ENCODED_NT5_T*5 + ENCODED_NT5_A*5*5);
+
+        // decode kmer
+        IS(decode_kmer_nt5(kmers[0], 3), "ATG");
+        IS(decode_kmer_nt5(kmers[1], 3), "");
+        IS(decode_kmer_nt5(kmers[2], 3), "");
+        IS(decode_kmer_nt5(kmers[3], 3), "");
+        IS(decode_kmer_nt5(kmers[4], 3), "CNT");
+        IS(decode_kmer_nt5(kmers[5], 3), "NTA");
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt5(enc, kmers, 6));
+        IS(kmers.size(), 3);
+
+        KmerType kmer =
+                ENCODED_NT5_A +
+                ENCODED_NT5_T *5 +
+                ENCODED_NT5_G *5*5 +
+                ENCODED_NT5_C *5*5*5 +
+                ENCODED_NT5_N *5*5*5*5 +
+                ENCODED_NT5_T *5*5*5*5*5 ;
+        IS(gen_kmer_nt5<KmerType>("ATGCNT"), kmer);
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(!gen_kmer_nt5(enc, kmers, 7));
+        IS(kmers.size(), 0);
+
+        IS(gen_kmer_nt5<KmerType>("ATGCNTT"), numeric_limits<KmerType>::max());
+    }
+
+    // decode
+    {
+        string dec;
+        decode_nt5(enc, dec);
+        IS(dec, "ATGNCNTA");
+    }
+}
diff --git a/t/t_kmer_nt5_32.cpp b/t/t_kmer_nt5_32.cpp
new file mode 100644
index 0000000..4cd0cde
--- /dev/null
+++ b/t/t_kmer_nt5_32.cpp
@@ -0,0 +1,100 @@
+#include "TestFramework.h"
+#include "htio2/Kmer.h"
+
+#include <limits>
+
+using namespace htio2;
+using namespace std;
+
+typedef uint32_t KmerType;
+
+void TestFramework::content()
+{
+    // encode
+    EncodedSeq enc;
+    encode_nt5("ATGXCNTAATGXCNTA", enc);
+    IS(enc.size(), 16);
+    IS(enc[0], ENCODED_NT5_A);
+    IS(enc[1], ENCODED_NT5_T);
+    IS(enc[2], ENCODED_NT5_G);
+    IS(enc[3], ENCODED_ERROR);
+    IS(enc[4], ENCODED_NT5_C);
+    IS(enc[5], ENCODED_NT5_N);
+    IS(enc[6], ENCODED_NT5_T);
+    IS(enc[7], ENCODED_NT5_A);
+    IS(enc[8], ENCODED_NT5_A);
+    IS(enc[9], ENCODED_NT5_T);
+    IS(enc[10], ENCODED_NT5_G);
+    IS(enc[11], ENCODED_ERROR);
+    IS(enc[12], ENCODED_NT5_C);
+    IS(enc[13], ENCODED_NT5_N);
+    IS(enc[14], ENCODED_NT5_T);
+    IS(enc[15], ENCODED_NT5_A);
+
+    {
+        // generate kmer
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt5(enc, kmers, 3));
+        IS(kmers.size(), 14);
+        IS(kmers[0], ENCODED_NT5_A + ENCODED_NT5_T*5 + ENCODED_NT5_G*5*5);
+        IS(kmers[1], numeric_limits<KmerType>::max());
+        IS(kmers[2], numeric_limits<KmerType>::max());
+        IS(kmers[3], numeric_limits<KmerType>::max());
+        IS(kmers[4], ENCODED_NT5_C + ENCODED_NT5_N*5 + ENCODED_NT5_T*5*5);
+        IS(kmers[5], ENCODED_NT5_N + ENCODED_NT5_T*5 + ENCODED_NT5_A*5*5);
+        IS(kmers[6], ENCODED_NT5_T + ENCODED_NT5_A*5 + ENCODED_NT5_A*5*5);
+        IS(kmers[7], ENCODED_NT5_A + ENCODED_NT5_A*5 + ENCODED_NT5_T*5*5);
+        IS(kmers[8], ENCODED_NT5_A + ENCODED_NT5_T*5 + ENCODED_NT5_G*5*5);
+        IS(kmers[9], numeric_limits<KmerType>::max());
+        IS(kmers[10], numeric_limits<KmerType>::max());
+        IS(kmers[11], numeric_limits<KmerType>::max());
+        IS(kmers[12], ENCODED_NT5_C + ENCODED_NT5_N*5 + ENCODED_NT5_T*5*5);
+        IS(kmers[13], ENCODED_NT5_N + ENCODED_NT5_T*5 + ENCODED_NT5_A*5*5);
+
+        // decode kmer
+        IS(decode_kmer_nt5(kmers[0], 3), "ATG");
+        IS(decode_kmer_nt5(kmers[1], 3), "");
+        IS(decode_kmer_nt5(kmers[2], 3), "");
+        IS(decode_kmer_nt5(kmers[3], 3), "");
+        IS(decode_kmer_nt5(kmers[4], 3), "CNT");
+        IS(decode_kmer_nt5(kmers[5], 3), "NTA");
+        IS(decode_kmer_nt5(kmers[6], 3), "TAA");
+        IS(decode_kmer_nt5(kmers[7], 3), "AAT");
+        IS(decode_kmer_nt5(kmers[8], 3), "ATG");
+        IS(decode_kmer_nt5(kmers[9], 3), "");
+        IS(decode_kmer_nt5(kmers[10], 3), "");
+        IS(decode_kmer_nt5(kmers[11], 3), "");
+        IS(decode_kmer_nt5(kmers[12], 3), "CNT");
+        IS(decode_kmer_nt5(kmers[13], 3), "NTA");
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt5(enc, kmers, 13));
+        IS(kmers.size(), 4);
+
+        KmerType kmer =
+                ENCODED_NT5_A +
+                ENCODED_NT5_T *5 +
+                ENCODED_NT5_G *5*5 +
+                ENCODED_NT5_C *5*5*5 +
+                ENCODED_NT5_N *5*5*5*5 +
+                ENCODED_NT5_T *5*5*5*5*5 +
+                ENCODED_NT5_A *5*5*5*5*5*5 +
+                ENCODED_NT5_T *5*5*5*5*5*5*5 +
+                ENCODED_NT5_G *5*5*5*5*5*5*5*5 +
+                ENCODED_NT5_C *5*5*5*5*5*5*5*5*5 +
+                ENCODED_NT5_N *5*5*5*5*5*5*5*5*5*5 +
+                ENCODED_NT5_T *5*5*5*5*5*5*5*5*5*5*5 +
+                ENCODED_NT5_A *5*5*5*5*5*5*5*5*5*5*5*5;
+        IS(gen_kmer_nt5<KmerType>("ATGCNTATGCNTA"), kmer);
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(!gen_kmer_nt5(enc, kmers, 14));
+        IS(kmers.size(), 0);
+
+        IS(gen_kmer_nt5<KmerType>("ATGCNTTATGCNTT"), numeric_limits<KmerType>::max());
+    }
+}
diff --git a/t/t_kmer_nt5_64.cpp b/t/t_kmer_nt5_64.cpp
new file mode 100644
index 0000000..3815171
--- /dev/null
+++ b/t/t_kmer_nt5_64.cpp
@@ -0,0 +1,162 @@
+#include "TestFramework.h"
+#include "htio2/Kmer.h"
+
+#include <limits>
+
+using namespace htio2;
+using namespace std;
+
+typedef uint64_t KmerType;
+
+void TestFramework::content()
+{
+    // encode
+    EncodedSeq enc;
+    encode_nt5("ATGXCNTAATGXCNTAATGXCNTAATGXCNTAATGXCNTAATGXCNTAATGXCNTAATGXCNTA", enc);
+    IS(enc.size(), 64);
+    IS(enc[0], ENCODED_NT5_A);
+    IS(enc[1], ENCODED_NT5_T);
+    IS(enc[2], ENCODED_NT5_G);
+    IS(enc[3], ENCODED_ERROR);
+    IS(enc[4], ENCODED_NT5_C);
+    IS(enc[5], ENCODED_NT5_N);
+    IS(enc[6], ENCODED_NT5_T);
+    IS(enc[7], ENCODED_NT5_A);
+    IS(enc[8], ENCODED_NT5_A);
+    IS(enc[9], ENCODED_NT5_T);
+    IS(enc[10], ENCODED_NT5_G);
+    IS(enc[11], ENCODED_ERROR);
+    IS(enc[12], ENCODED_NT5_C);
+    IS(enc[13], ENCODED_NT5_N);
+    IS(enc[14], ENCODED_NT5_T);
+    IS(enc[15], ENCODED_NT5_A);
+    IS(enc[16], ENCODED_NT5_A);
+    IS(enc[17], ENCODED_NT5_T);
+    IS(enc[18], ENCODED_NT5_G);
+    IS(enc[19], ENCODED_ERROR);
+    IS(enc[20], ENCODED_NT5_C);
+    IS(enc[21], ENCODED_NT5_N);
+    IS(enc[22], ENCODED_NT5_T);
+    IS(enc[23], ENCODED_NT5_A);
+    IS(enc[24], ENCODED_NT5_A);
+    IS(enc[25], ENCODED_NT5_T);
+    IS(enc[26], ENCODED_NT5_G);
+    IS(enc[27], ENCODED_ERROR);
+    IS(enc[28], ENCODED_NT5_C);
+    IS(enc[29], ENCODED_NT5_N);
+    IS(enc[30], ENCODED_NT5_T);
+    IS(enc[31], ENCODED_NT5_A);
+
+    {
+        // generate kmer
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt5(enc, kmers, 3));
+        IS(kmers.size(), 62);
+        IS(kmers[0], ENCODED_NT5_A + ENCODED_NT5_T*5 + ENCODED_NT5_G*5*5);
+        IS(kmers[1], numeric_limits<KmerType>::max());
+        IS(kmers[2], numeric_limits<KmerType>::max());
+        IS(kmers[3], numeric_limits<KmerType>::max());
+        IS(kmers[4], ENCODED_NT5_C + ENCODED_NT5_N*5 + ENCODED_NT5_T*5*5);
+        IS(kmers[5], ENCODED_NT5_N + ENCODED_NT5_T*5 + ENCODED_NT5_A*5*5);
+        IS(kmers[6], ENCODED_NT5_T + ENCODED_NT5_A*5 + ENCODED_NT5_A*5*5);
+        IS(kmers[7], ENCODED_NT5_A + ENCODED_NT5_A*5 + ENCODED_NT5_T*5*5);
+        IS(kmers[8], ENCODED_NT5_A + ENCODED_NT5_T*5 + ENCODED_NT5_G*5*5);
+        IS(kmers[9], numeric_limits<KmerType>::max());
+        IS(kmers[10], numeric_limits<KmerType>::max());
+        IS(kmers[11], numeric_limits<KmerType>::max());
+        IS(kmers[12], ENCODED_NT5_C + ENCODED_NT5_N*5 + ENCODED_NT5_T*5*5);
+        IS(kmers[13], ENCODED_NT5_N + ENCODED_NT5_T*5 + ENCODED_NT5_A*5*5);
+        IS(kmers[14], ENCODED_NT5_T + ENCODED_NT5_A*5 + ENCODED_NT5_A*5*5);
+        IS(kmers[15], ENCODED_NT5_A + ENCODED_NT5_A*5 + ENCODED_NT5_T*5*5);
+        IS(kmers[16], ENCODED_NT5_A + ENCODED_NT5_T*5 + ENCODED_NT5_G*5*5);
+        IS(kmers[17], numeric_limits<KmerType>::max());
+        IS(kmers[18], numeric_limits<KmerType>::max());
+        IS(kmers[19], numeric_limits<KmerType>::max());
+        IS(kmers[20], ENCODED_NT5_C + ENCODED_NT5_N*5 + ENCODED_NT5_T*5*5);
+        IS(kmers[21], ENCODED_NT5_N + ENCODED_NT5_T*5 + ENCODED_NT5_A*5*5);
+        IS(kmers[22], ENCODED_NT5_T + ENCODED_NT5_A*5 + ENCODED_NT5_A*5*5);
+        IS(kmers[23], ENCODED_NT5_A + ENCODED_NT5_A*5 + ENCODED_NT5_T*5*5);
+        IS(kmers[24], ENCODED_NT5_A + ENCODED_NT5_T*5 + ENCODED_NT5_G*5*5);
+        IS(kmers[25], numeric_limits<KmerType>::max());
+        IS(kmers[26], numeric_limits<KmerType>::max());
+        IS(kmers[27], numeric_limits<KmerType>::max());
+        IS(kmers[28], ENCODED_NT5_C + ENCODED_NT5_N*5 + ENCODED_NT5_T*5*5);
+        IS(kmers[29], ENCODED_NT5_N + ENCODED_NT5_T*5 + ENCODED_NT5_A*5*5);
+
+        // decode kmer
+        IS(decode_kmer_nt5(kmers[0], 3), "ATG");
+        IS(decode_kmer_nt5(kmers[1], 3), "");
+        IS(decode_kmer_nt5(kmers[2], 3), "");
+        IS(decode_kmer_nt5(kmers[3], 3), "");
+        IS(decode_kmer_nt5(kmers[4], 3), "CNT");
+        IS(decode_kmer_nt5(kmers[5], 3), "NTA");
+        IS(decode_kmer_nt5(kmers[6], 3), "TAA");
+        IS(decode_kmer_nt5(kmers[7], 3), "AAT");
+        IS(decode_kmer_nt5(kmers[8], 3), "ATG");
+        IS(decode_kmer_nt5(kmers[9], 3), "");
+        IS(decode_kmer_nt5(kmers[10], 3), "");
+        IS(decode_kmer_nt5(kmers[11], 3), "");
+        IS(decode_kmer_nt5(kmers[12], 3), "CNT");
+        IS(decode_kmer_nt5(kmers[13], 3), "NTA");
+        IS(decode_kmer_nt5(kmers[14], 3), "TAA");
+        IS(decode_kmer_nt5(kmers[15], 3), "AAT");
+        IS(decode_kmer_nt5(kmers[16], 3), "ATG");
+        IS(decode_kmer_nt5(kmers[17], 3), "");
+        IS(decode_kmer_nt5(kmers[18], 3), "");
+        IS(decode_kmer_nt5(kmers[19], 3), "");
+        IS(decode_kmer_nt5(kmers[20], 3), "CNT");
+        IS(decode_kmer_nt5(kmers[21], 3), "NTA");
+        IS(decode_kmer_nt5(kmers[22], 3), "TAA");
+        IS(decode_kmer_nt5(kmers[23], 3), "AAT");
+        IS(decode_kmer_nt5(kmers[24], 3), "ATG");
+        IS(decode_kmer_nt5(kmers[25], 3), "");
+        IS(decode_kmer_nt5(kmers[26], 3), "");
+        IS(decode_kmer_nt5(kmers[27], 3), "");
+        IS(decode_kmer_nt5(kmers[28], 3), "CNT");
+        IS(decode_kmer_nt5(kmers[29], 3), "NTA");
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(gen_kmer_nt5(enc, kmers, 27));
+        IS(kmers.size(), 38);
+
+        KmerType kmer =
+                KmerType(ENCODED_NT5_A) +
+                KmerType(ENCODED_NT5_T *5L) +
+                KmerType(ENCODED_NT5_G *5L*5L) +
+                KmerType(ENCODED_NT5_C *5L*5L*5L) +
+                KmerType(ENCODED_NT5_N *5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_T *5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_A *5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_T *5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_G *5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_C *5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_N *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_T *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_A *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_A *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_T *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_G *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_C *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_N *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_T *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_A *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_T *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_G *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_C *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_N *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_T *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_A *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L) +
+                KmerType(ENCODED_NT5_A *5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L*5L);
+        IS(gen_kmer_nt5<KmerType>("ATGCNTATGCNTAATGCNTATGCNTAA"), kmer);
+    }
+
+    {
+        vector<KmerType> kmers;
+        OK(!gen_kmer_nt5(enc, kmers, 28));
+        IS(kmers.size(), 0);
+
+        IS(gen_kmer_nt5<KmerType>("ATGCNTATGCNTAATGCNTATGCNTAAA"), numeric_limits<KmerType>::max());
+    }
+}
diff --git a/t/t_mt19937.cpp b/t/t_mt19937.cpp
new file mode 100644
index 0000000..112c53d
--- /dev/null
+++ b/t/t_mt19937.cpp
@@ -0,0 +1,167 @@
+#include "htio2/MT19937.h"
+#include "TestFramework.h"
+
+#include <vector>
+#include <cstring>
+
+using namespace htio2::juce;
+
+//
+// the reference implementation of 64-bit MT19937 by Takuji Nishimura and Makoto Matsumoto.
+// Copyright (C) 2004, 2014, Makoto Matsumoto and Takuji Nishimura, All rights reserved.
+//
+
+#define NN 312
+#define MM 156
+#define MATRIX_A 0xB5026F5AA96619E9ull
+#define UM 0xFFFFFFFF80000000ull
+#define LM 0x7FFFFFFFull
+
+static uint64_t mt[NN];
+static int mti=NN+1;
+
+void init_genrand64(uint64_t seed)
+{
+    mt[0] = seed;
+    for (mti=1; mti<NN; mti++)
+        mt[mti] =  (6364136223846793005ull * (mt[mti-1] ^ (mt[mti-1] >> 62)) + mti);
+}
+
+void init_by_array64(uint64_t init_key[],
+                                    uint64_t key_length)
+{
+    unsigned int i, j;
+    uint64_t k;
+    init_genrand64(19650218ull);
+    i=1; j=0;
+    k = (NN>key_length ? NN : key_length);
+    for (; k; k--) {
+        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 62)) * 3935559000370003845ull))
+          + init_key[j] + j; /* non linear */
+        i++; j++;
+        if (i>=NN) { mt[0] = mt[NN-1]; i=1; }
+        if (j>=key_length) j=0;
+    }
+    for (k=NN-1; k; k--) {
+        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 62)) * 2862933555777941757ull))
+          - i; /* non linear */
+        i++;
+        if (i>=NN) { mt[0] = mt[NN-1]; i=1; }
+    }
+
+    mt[0] = 1ull << 63; /* MSB is 1; assuring non-zero initial array */
+}
+
+uint64_t genrand64_int64(void)
+{
+    int i;
+    uint64_t x;
+    static uint64_t mag01[2]={0ull, MATRIX_A};
+
+    if (mti >= NN) { /* generate NN words at one time */
+
+        /* if init_genrand64() has not been called, */
+        /* a default initial seed is used     */
+        if (mti == NN+1)
+            init_genrand64(5489ull);
+
+        for (i=0;i<NN-MM;i++) {
+            x = (mt[i]&UM)|(mt[i+1]&LM);
+            mt[i] = mt[i+MM] ^ (x>>1) ^ mag01[(int)(x & 1ull)];
+        }
+        for (;i<NN-1;i++) {
+            x = (mt[i]&UM)|(mt[i+1]&LM);
+            mt[i] = mt[i+(MM-NN)] ^ (x>>1) ^ mag01[(int)(x & 1ull)];
+        }
+        x = (mt[NN-1]&UM)|(mt[0]&LM);
+        mt[NN-1] = mt[MM-1] ^ (x>>1) ^ mag01[(int)(x & 1ull)];
+
+        mti = 0;
+    }
+
+    x = mt[mti++];
+
+    x ^= (x >> 29) & 0x5555555555555555ull;
+    x ^= (x << 17) & 0x71D67FFFEDA60000ull;
+    x ^= (x << 37) & 0xFFF7EEE000000000ull;
+    x ^= (x >> 43);
+
+    return x;
+}
+
+int64_t genrand64_int63(void)
+{
+    return (int64_t)(genrand64_int64() >> 1);
+}
+
+double genrand64_real1(void)
+{
+    return (genrand64_int64() >> 11) * (1.0/9007199254740991.0);
+}
+
+double genrand64_real2(void)
+{
+    return (genrand64_int64() >> 11) * (1.0/9007199254740992.0);
+}
+
+double genrand64_real3(void)
+{
+    return ((genrand64_int64() >> 12) + 0.5) * (1.0/4503599627370496.0);
+}
+
+
+void TestFramework::content()
+{
+    uint64_t seed = Time::getCurrentTime().toMilliseconds();
+    printf("seed: %lu\n", seed);
+
+    htio2::MT19937 prng(seed);
+    init_genrand64(seed);
+
+    OK(std::memcmp(mt, prng.mt, sizeof(mt)) == 0);
+    IS(mti, prng.mti);
+
+    is(genrand64_int64(), prng.next_uint64(), "uint64");
+    OK(std::memcmp(mt, prng.mt, sizeof(mt)) == 0);
+    IS(mti, prng.mti);
+
+    is(genrand64_int63(), prng.next_int63(), "positive int64");
+    OK(std::memcmp(mt, prng.mt, sizeof(mt)) == 0);
+    IS(mti, prng.mti);
+
+    is(genrand64_real1(), prng.next_double_yy(), "double inclusive");
+    OK(std::memcmp(mt, prng.mt, sizeof(mt)) == 0);
+    IS(mti, prng.mti);
+
+    is(genrand64_real2(), prng.next_double_yn(), "double right exclusive");
+    OK(std::memcmp(mt, prng.mt, sizeof(mt)) == 0);
+    IS(mti, prng.mti);
+
+    is(genrand64_real3(), prng.next_double_nn(), "double both exclusive");
+    OK(std::memcmp(mt, prng.mt, sizeof(mt)) == 0);
+    IS(mti, prng.mti);
+
+#define NUM_CYCLE 1000000
+    {
+        int32_t sum = 0;
+        for (int32_t i = 0; i < NUM_CYCLE; i++)
+        {
+            sum += prng.next_bool();
+        }
+
+        printf("%d of %d\n", sum, NUM_CYCLE);
+    }
+
+    {
+        std::vector<size_t> sum(10);
+        for (size_t i = 0; i < NUM_CYCLE; i++)
+        {
+            sum[prng.next_uint64_in_range(10)]++;
+        }
+
+        for (int i = 0; i < 10; i++)
+        {
+            printf("%lu\n", sum[i]);
+        }
+    }
+}
diff --git a/t/t_multi_seq_file_pe.cpp b/t/t_multi_seq_file_pe.cpp
new file mode 100644
index 0000000..a2968b2
--- /dev/null
+++ b/t/t_multi_seq_file_pe.cpp
@@ -0,0 +1,141 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+#include "htqc/MultiSeqFile.h"
+
+using namespace std;
+
+void TestFramework::content()
+{
+    {
+        OK("test file pairs");
+        vector<string> files1;
+        files1.push_back(TEST_SOURCE_DIR"/test1.fastq.gz");
+        files1.push_back(TEST_SOURCE_DIR"/test1.fastq.gz");
+        vector<string> files2;
+        files2.push_back(TEST_SOURCE_DIR"/test2.fastq.gz");
+        files2.push_back(TEST_SOURCE_DIR"/test2.fastq.gz");
+
+        htqc::MultiSeqFilePE fh(files1, files2, htio2::STRAND_FWD, htio2::STRAND_REV, htio2::COMPRESS_GZIP);
+
+        htio2::FastqSeq seq1;
+        htio2::FastqSeq seq2;
+
+        size_t count = 0;
+
+        while (fh.next_pair(seq1, seq2, htio2::STRAND_FWD, htio2::STRAND_REV))
+        {
+            count++;
+            if (count == 1)
+            {
+                IS(seq1.id,      "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+                IS(seq1.desc,    "1:N:0:CTTGTA");
+                IS(seq1.seq,     "AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCTCCCACGTGTGGGAGCTTGTATGTACCTTAT");
+                IS(seq1.quality, "=\?@DFADDHHAHDGGBGGGIGHBEGGHEI>FGIIGCGGCH3\?@FEB@@@FGICHG==AHFFEFEEDDDDDDC<>A>A:ACDCC>C<@BB>C at ACC@CACAC at ACCDDDCA\?ABCAC at 9@AA8\?\?8><ADB<>B8<B:C\?>@>>34>:@CD");
+                IS(seq2.id,      "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+                IS(seq2.desc,    "2:N:0:CTTGTA");
+                IS(seq2.seq,     "CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATGCTTATTCATAAGGTACATACAAGCTCCCACACGTGGGAGGGTTTATTCCCTTATAAAAGAAGTTTACAATCCGTAGGACCTTCATCCTTCACGCTACTTGGCTGGTTCAGACTC");
+                IS(seq2.quality, "=+=+<\?7@\?C0CACAABABABBAA=:<AABBBAAAAABBAABBBBAAAAA;\?@>>75>>=@>\?======;9;=8255+88=:\?\?\?\?\?\?\?\?\?=::=;<\?8883::8;8;;=;<=\?\?7<\?\?\?\?3;\?\?\?\?\?8;===\?\?\?\?\?\?###########");
+            }
+            else if (count==100)
+            {
+                IS(seq1.id,      "HWI-ST1106:815:H154GADXX:1:1101:3431:2221");
+                IS(seq2.id,      "HWI-ST1106:815:H154GADXX:1:1101:3431:2221");
+                IS(seq1.desc,    "1:N:0:TTAGGC");
+                IS(seq2.desc,    "2:N:0:TTAGGC");
+                IS(seq1.seq,     "ATCGCAAATCATGGTGGGGATGATACGGCGTTTCATTGCGGAGCAGGAAATTGTTATGTTCTTATCAGGAGATTATAATTGGCCTGACAAATGGATGTGATTTATTTATTGGGCTCAATTGGGCTAGGTTGGGGATCTTCATTTGTCCAC");
+                IS(seq2.seq,     "ATGCTACCTACTCTGAAATTGACGGTACAGCAACAAGCGAAATTGCGACAAGCAGTAATGCATTAATGTTAATCCCTCAGAATGATCTATCGTCAGTCAAGATTACTGTTACTTATTCCACGACTAATGATAATGGCAAAGTATTTGAAG");
+                IS(seq1.quality, "@<BFFFFFHGHHHJCFGIIFIJIGJJJJJJIJJGIIJJJJJJHFFFFFCCEDECDDEDFEEEDCDCCDDABDDCDDEEEEDDDDDBCDDDDDDD(:@AACDDDDEDDDEDDDDBDAACCDCDDDDBDDCDDDDD0<BDCDEEEEEE at CDD");
+                IS(seq2.quality, "\?==BBDFFGFHHGGIIIIFDCFC at FGHIIIIIIGIIIGHHGIFIIHIIIIIIGIIIGHFHHHGFFFFEEEEEEECECCDDDDDCDDCDCCCB\?ABDDDCDDDDACCDA>CCCDDDCEAA at ABBBB<>A>CCDCCDCBC><CAABC@@:@:");
+            }
+            else if (count==101)
+            {
+                IS(seq1.id,      "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+                IS(seq2.id,      "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+                IS(seq1.desc,    "1:N:0:CTTGTA");
+                IS(seq2.desc,    "2:N:0:CTTGTA");
+                IS(seq1.seq,     "AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCTCCCACGTGTGGGAGCTTGTATGTACCTTAT");
+                IS(seq2.seq,     "CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATGCTTATTCATAAGGTACATACAAGCTCCCACACGTGGGAGGGTTTATTCCCTTATAAAAGAAGTTTACAATCCGTAGGACCTTCATCCTTCACGCTACTTGGCTGGTTCAGACTC");
+                IS(seq1.quality, "=\?@DFADDHHAHDGGBGGGIGHBEGGHEI>FGIIGCGGCH3\?@FEB@@@FGICHG==AHFFEFEEDDDDDDC<>A>A:ACDCC>C<@BB>C at ACC@CACAC at ACCDDDCA\?ABCAC at 9@AA8\?\?8><ADB<>B8<B:C\?>@>>34>:@CD");
+                IS(seq2.quality, "=+=+<\?7@\?C0CACAABABABBAA=:<AABBBAAAAABBAABBBBAAAAA;\?@>>75>>=@>\?======;9;=8255+88=:\?\?\?\?\?\?\?\?\?=::=;<\?8883::8;8;;=;<=\?\?7<\?\?\?\?3;\?\?\?\?\?8;===\?\?\?\?\?\?###########");
+            }
+            else if (count==200)
+            {
+                IS(seq1.id, "HWI-ST1106:815:H154GADXX:1:1101:3431:2221");
+                IS(seq2.id, "HWI-ST1106:815:H154GADXX:1:1101:3431:2221");
+                IS(seq1.desc, "1:N:0:TTAGGC");
+                IS(seq2.desc, "2:N:0:TTAGGC");
+                IS(seq1.seq, "ATCGCAAATCATGGTGGGGATGATACGGCGTTTCATTGCGGAGCAGGAAATTGTTATGTTCTTATCAGGAGATTATAATTGGCCTGACAAATGGATGTGATTTATTTATTGGGCTCAATTGGGCTAGGTTGGGGATCTTCATTTGTCCAC");
+                IS(seq2.seq, "ATGCTACCTACTCTGAAATTGACGGTACAGCAACAAGCGAAATTGCGACAAGCAGTAATGCATTAATGTTAATCCCTCAGAATGATCTATCGTCAGTCAAGATTACTGTTACTTATTCCACGACTAATGATAATGGCAAAGTATTTGAAG");
+                IS(seq1.quality, "@<BFFFFFHGHHHJCFGIIFIJIGJJJJJJIJJGIIJJJJJJHFFFFFCCEDECDDEDFEEEDCDCCDDABDDCDDEEEEDDDDDBCDDDDDDD(:@AACDDDDEDDDEDDDDBDAACCDCDDDDBDDCDDDDD0<BDCDEEEEEE at CDD");
+                IS(seq2.quality, "\?==BBDFFGFHHGGIIIIFDCFC at FGHIIIIIIGIIIGHHGIFIIHIIIIIIGIIIGHFHHHGFFFFEEEEEEECECCDDDDDCDDCDCCCB\?ABDDDCDDDDACCDA>CCCDDDCEAA at ABBBB<>A>CCDCCDCBC><CAABC@@:@:");
+            }
+        }
+
+        IS(count, 200);
+    }
+
+    {
+        OK("test interleaved files");
+        vector<string> files;
+        files.push_back(TEST_SOURCE_DIR"/test_interleave.fastq.gz");
+        files.push_back(TEST_SOURCE_DIR"/test_interleave.fastq.gz");
+
+        htqc::MultiSeqFilePE fh(files, htio2::STRAND_FWD, htio2::STRAND_REV, htio2::COMPRESS_GZIP);
+
+        htio2::FastqSeq seq1;
+        htio2::FastqSeq seq2;
+
+        size_t count = 0;
+
+        while (fh.next_pair(seq1, seq2, htio2::STRAND_FWD, htio2::STRAND_REV))
+        {
+            count++;
+            if (count == 1)
+            {
+                IS(seq1.id, "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+                IS(seq1.desc, "1:N:0:CTTGTA");
+                IS(seq1.seq,     "AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCTCCCACGTGTGGGAGCTTGTATGTACCTTAT");
+                IS(seq1.quality, "=\?@DFADDHHAHDGGBGGGIGHBEGGHEI>FGIIGCGGCH3\?@FEB@@@FGICHG==AHFFEFEEDDDDDDC<>A>A:ACDCC>C<@BB>C at ACC@CACAC at ACCDDDCA\?ABCAC at 9@AA8\?\?8><ADB<>B8<B:C\?>@>>34>:@CD");
+                IS(seq2.id, "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+                IS(seq2.desc, "2:N:0:CTTGTA");
+                IS(seq2.seq,     "CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATGCTTATTCATAAGGTACATACAAGCTCCCACACGTGGGAGGGTTTATTCCCTTATAAAAGAAGTTTACAATCCGTAGGACCTTCATCCTTCACGCTACTTGGCTGGTTCAGACTC");
+                IS(seq2.quality, "=+=+<\?7@\?C0CACAABABABBAA=:<AABBBAAAAABBAABBBBAAAAA;\?@>>75>>=@>\?======;9;=8255+88=:\?\?\?\?\?\?\?\?\?=::=;<\?8883::8;8;;=;<=\?\?7<\?\?\?\?3;\?\?\?\?\?8;===\?\?\?\?\?\?###########");
+            }
+            else if (count==100)
+            {
+                IS(seq1.id, "HWI-ST1106:815:H154GADXX:1:1101:3431:2221");
+                IS(seq1.desc, "1:N:0:TTAGGC");
+                IS(seq1.seq, "ATCGCAAATCATGGTGGGGATGATACGGCGTTTCATTGCGGAGCAGGAAATTGTTATGTTCTTATCAGGAGATTATAATTGGCCTGACAAATGGATGTGATTTATTTATTGGGCTCAATTGGGCTAGGTTGGGGATCTTCATTTGTCCAC");
+                IS(seq1.quality, "@<BFFFFFHGHHHJCFGIIFIJIGJJJJJJIJJGIIJJJJJJHFFFFFCCEDECDDEDFEEEDCDCCDDABDDCDDEEEEDDDDDBCDDDDDDD(:@AACDDDDEDDDEDDDDBDAACCDCDDDDBDDCDDDDD0<BDCDEEEEEE at CDD");
+                IS(seq2.id, "HWI-ST1106:815:H154GADXX:1:1101:3431:2221");
+                IS(seq2.desc, "2:N:0:TTAGGC");
+                IS(seq2.seq, "ATGCTACCTACTCTGAAATTGACGGTACAGCAACAAGCGAAATTGCGACAAGCAGTAATGCATTAATGTTAATCCCTCAGAATGATCTATCGTCAGTCAAGATTACTGTTACTTATTCCACGACTAATGATAATGGCAAAGTATTTGAAG");
+                IS(seq2.quality, "\?==BBDFFGFHHGGIIIIFDCFC at FGHIIIIIIGIIIGHHGIFIIHIIIIIIGIIIGHFHHHGFFFFEEEEEEECECCDDDDDCDDCDCCCB\?ABDDDCDDDDACCDA>CCCDDDCEAA at ABBBB<>A>CCDCCDCBC><CAABC@@:@:");
+            }
+            else if (count==101)
+            {
+                IS(seq1.id, "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+                IS(seq1.desc, "1:N:0:CTTGTA");
+                IS(seq1.seq,     "AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCTCCCACGTGTGGGAGCTTGTATGTACCTTAT");
+                IS(seq1.quality, "=\?@DFADDHHAHDGGBGGGIGHBEGGHEI>FGIIGCGGCH3\?@FEB@@@FGICHG==AHFFEFEEDDDDDDC<>A>A:ACDCC>C<@BB>C at ACC@CACAC at ACCDDDCA\?ABCAC at 9@AA8\?\?8><ADB<>B8<B:C\?>@>>34>:@CD");
+                IS(seq2.id, "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+                IS(seq2.desc, "2:N:0:CTTGTA");
+                IS(seq2.seq,     "CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATGCTTATTCATAAGGTACATACAAGCTCCCACACGTGGGAGGGTTTATTCCCTTATAAAAGAAGTTTACAATCCGTAGGACCTTCATCCTTCACGCTACTTGGCTGGTTCAGACTC");
+                IS(seq2.quality, "=+=+<\?7@\?C0CACAABABABBAA=:<AABBBAAAAABBAABBBBAAAAA;\?@>>75>>=@>\?======;9;=8255+88=:\?\?\?\?\?\?\?\?\?=::=;<\?8883::8;8;;=;<=\?\?7<\?\?\?\?3;\?\?\?\?\?8;===\?\?\?\?\?\?###########");
+            }
+            else if (count==200)
+            {
+                IS(seq1.id, "HWI-ST1106:815:H154GADXX:1:1101:3431:2221");
+                IS(seq1.desc, "1:N:0:TTAGGC");
+                IS(seq1.seq, "ATCGCAAATCATGGTGGGGATGATACGGCGTTTCATTGCGGAGCAGGAAATTGTTATGTTCTTATCAGGAGATTATAATTGGCCTGACAAATGGATGTGATTTATTTATTGGGCTCAATTGGGCTAGGTTGGGGATCTTCATTTGTCCAC");
+                IS(seq1.quality, "@<BFFFFFHGHHHJCFGIIFIJIGJJJJJJIJJGIIJJJJJJHFFFFFCCEDECDDEDFEEEDCDCCDDABDDCDDEEEEDDDDDBCDDDDDDD(:@AACDDDDEDDDEDDDDBDAACCDCDDDDBDDCDDDDD0<BDCDEEEEEE at CDD");
+                IS(seq2.id, "HWI-ST1106:815:H154GADXX:1:1101:3431:2221");
+                IS(seq2.desc, "2:N:0:TTAGGC");
+                IS(seq2.seq, "ATGCTACCTACTCTGAAATTGACGGTACAGCAACAAGCGAAATTGCGACAAGCAGTAATGCATTAATGTTAATCCCTCAGAATGATCTATCGTCAGTCAAGATTACTGTTACTTATTCCACGACTAATGATAATGGCAAAGTATTTGAAG");
+                IS(seq2.quality, "\?==BBDFFGFHHGGIIIIFDCFC at FGHIIIIIIGIIIGHHGIFIIHIIIIIIGIIIGHFHHHGFFFFEEEEEEECECCDDDDDCDDCDCCCB\?ABDDDCDDDDACCDA>CCCDDDCEAA at ABBBB<>A>CCDCCDCBC><CAABC@@:@:");
+            }
+        }
+
+        IS(count, 200);
+    }
+}
diff --git a/t/t_multi_seq_file_se.cpp b/t/t_multi_seq_file_se.cpp
new file mode 100644
index 0000000..38bd1ed
--- /dev/null
+++ b/t/t_multi_seq_file_se.cpp
@@ -0,0 +1,52 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+#include "htqc/MultiSeqFile.h"
+
+using namespace std;
+
+void TestFramework::content()
+{
+    vector<string> files;
+    files.push_back(TEST_SOURCE_DIR"/test1.fastq");
+    files.push_back(TEST_SOURCE_DIR"/test2.fastq");
+    files.push_back(TEST_SOURCE_DIR"/test2.fastq");
+    files.push_back(TEST_SOURCE_DIR"/test1.fastq");
+    htqc::MultiSeqFileSE fh(files, htio2::COMPRESS_PLAIN);
+
+    htio2::FastqSeq seq;
+    size_t n_seq = 0;
+    while (fh.next_seq(seq))
+    {
+        n_seq++;
+        if (n_seq==1)
+        {
+            IS(seq.id, "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+            IS(seq.desc, "1:N:0:CTTGTA");
+        }
+        else if (n_seq == 101)
+        {
+            IS(seq.id, "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+            IS(seq.desc, "2:N:0:CTTGTA");
+        }
+        else if (n_seq == 201)
+        {
+            IS(seq.id, "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+            IS(seq.desc, "2:N:0:CTTGTA");
+        }
+        else if (n_seq == 301)
+        {
+            IS(seq.id, "HWI-ST1106:815:H154GADXX:1:1101:1244:2196");
+            IS(seq.desc, "1:N:0:CTTGTA");
+        }
+        else if (n_seq == 302)
+        {
+            IS(seq.id, "HWI-ST1106:815:H154GADXX:1:1101:1197:2208");
+            IS(seq.desc, "1:N:0:TTGGTA");
+        }
+    }
+
+    IS(n_seq, 400);
+}
+
+
+
diff --git a/t/t_plain_file_handle.cpp b/t/t_plain_file_handle.cpp
new file mode 100644
index 0000000..ddd3906
--- /dev/null
+++ b/t/t_plain_file_handle.cpp
@@ -0,0 +1,64 @@
+#include "TestFramework.h"
+#include "TestConfig.h"
+#include "htio2/PlainFileHandle.h"
+#include <stdio.h>
+
+
+using namespace std;
+using namespace htio2;
+
+void TestFramework::content()
+{
+    PlainFileHandle fh(TEST_SOURCE_DIR"/test1.fastq", htio2::READ);
+    string line1;
+    string line2;
+    string line3;
+    string line4;
+
+    OK(fh.read_line(line1));
+    off_t off1 = fh.tell();
+    OK(fh.read_line(line2));
+    off_t off2 = fh.tell();
+    OK(fh.read_line(line3));
+    off_t off3 = fh.tell();
+    OK(fh.read_line(line4));
+    off_t off4 = fh.tell();
+
+    IS(line1, "@HWI-ST1106:815:H154GADXX:1:1101:1244:2196 1:N:0:CTTGTA");
+    IS(off1, 56);
+    IS(line2, "AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCTCCCACGTGTGGGAGCTTGTATGTACCTTAT");
+    IS(off2, 207);
+    IS(line3, "+");
+    IS(off3, 209);
+    IS(line4, "=?@DFADDHHAHDGGBGGGIGHBEGGHEI>FGIIGCGGCH3?@FEB@@@FGICHG==AHFFEFEEDDDDDDC<>A>A:ACDCC>C<@BB>C at ACC@CACAC at ACCDDDCA?ABCAC at 9@AA8??8><ADB<>B8<B:C?>@>>34>:@CD");
+    IS(off4, 360);
+    IS(ftell(fh.handle), 361);
+
+    fh.seek(off3, 0);
+    string line4again;
+    OK(fh.read_line(line4again));
+    IS(line4again, line4);
+
+    fh.seek(off1, 0);
+    string line2again;
+    OK(fh.read_line(line2again));
+    IS(line2again, line2);
+
+    fh.seek(off2, SEEK_SET);
+    fh.seek(off3-off2, SEEK_CUR);
+    IS(fh.tell(), off3);
+    IS(ftell(fh.handle), off3+1);
+    {
+        string line;
+        OK(fh.read_line(line));
+        IS(line, line4);
+    }
+
+    fh.seek(-151, SEEK_END);
+    IS(fh.tell(), 36000-151);
+    {
+        string line;
+        OK(fh.read_line(line));
+        IS(line, "@<BFFFFFHGHHHJCFGIIFIJIGJJJJJJIJJGIIJJJJJJHFFFFFCCEDECDDEDFEEEDCDCCDDABDDCDDEEEEDDDDDBCDDDDDDD(:@AACDDDDEDDDEDDDDBDAACCDCDDDDBDDCDDDDD0<BDCDEEEEEE at CDD");
+    }
+}
diff --git a/t/t_ref_counted.cpp b/t/t_ref_counted.cpp
new file mode 100644
index 0000000..44ec7a8
--- /dev/null
+++ b/t/t_ref_counted.cpp
@@ -0,0 +1,42 @@
+#include "TestFramework.h"
+#include "htio2/RefCounted.h"
+
+using namespace htio2;
+
+class TestType: public RefCounted
+{
+public:
+    TestType(bool* flag): flag(flag) { *flag = true; }
+    virtual ~TestType() { *flag = false; }
+    bool* flag;
+};
+
+typedef SmartPtr<TestType> TestTypePtr;
+
+void TestFramework::content()
+{
+    bool live_flag = false;
+    TestType* obj = new TestType(&live_flag);
+
+    IS(obj->get_ref_count(), size_t(0));
+    IS(obj->get_ref_count(), obj->counter.get());
+    OK(live_flag);
+
+    obj->ref();
+    IS(obj->get_ref_count(), size_t(1));
+
+    {
+        TestTypePtr p1(obj);
+        IS(obj->get_ref_count(), size_t(2));
+        TestTypePtr p2(p1);
+        IS(obj->get_ref_count(), size_t(3));
+        TestTypePtr p3(obj);
+        IS(obj->get_ref_count(), size_t(4));
+    }
+
+    IS(obj->get_ref_count(), size_t(1));
+    OK(live_flag);
+
+    obj->unref();
+    OK(!live_flag);
+}
diff --git a/t/t_ring_buffer.cpp b/t/t_ring_buffer.cpp
new file mode 100644
index 0000000..dbe2259
--- /dev/null
+++ b/t/t_ring_buffer.cpp
@@ -0,0 +1,67 @@
+#include "TestFramework.h"
+#include "htio2/RingBuffer.h"
+
+#include <vector>
+#include <limits>
+
+using namespace htio2::juce;
+using namespace std;
+
+#define NUM_DATA 10
+
+htio2::RingBuffer<int> buffer(NUM_DATA * 2);
+
+struct MyWorker: public Thread
+{
+    MyWorker(const String& name): Thread(name)
+    {
+        result.reserve(4096);
+    }
+
+    virtual void run() override
+    {
+        for (;;)
+        {
+            int value = numeric_limits<int>::max();
+
+            if (buffer.pop(value))
+            {
+                printf("worker got %d\n", value);
+                if (value == -1)
+                    return;
+
+                result.push_back(value);
+            }
+
+            yield();
+        }
+    }
+
+    vector<int> result;
+};
+
+
+void TestFramework::content()
+{
+    MyWorker worker("worker");
+    worker.startThread();
+
+    for (int value = 0; value < NUM_DATA; value++)
+    {
+        while (!buffer.push(value)) {Thread::yield();}
+        printf("pushed %d\n", value);
+    }
+
+    while (!buffer.push(-1)) {Thread::yield();}
+
+    worker.waitForThreadToExit(-1);
+
+    for (int value = 0; value < NUM_DATA; value++)
+    {
+        if (worker.result[value] != value)
+        {
+            fprintf(stderr, "expect %d, got %d\n", value, worker.result[value]);
+            exit(EXIT_FAILURE);
+        }
+    }
+}
diff --git a/t/t_simple_seq.cpp b/t/t_simple_seq.cpp
new file mode 100644
index 0000000..41d9703
--- /dev/null
+++ b/t/t_simple_seq.cpp
@@ -0,0 +1,49 @@
+#include "TestFramework.h"
+#include "htio2/SimpleSeq.h"
+
+using namespace htio2;
+using namespace std;
+
+const char* SEQ = "TGGACGCAGCT";
+
+void TestFramework::content()
+{
+    {
+        string rev;
+        revcom(SEQ, rev);
+        IS(rev, string("AGCTGCGTCCA"));
+    }
+
+    SimpleSeq seq("seq1", "the quick brown fox jumps over a lazy dog", SEQ);
+    IS(seq.id, string("seq1"));
+    IS(seq.desc, string("the quick brown fox jumps over a lazy dog"));
+    IS(seq.seq, string(SEQ));
+    IS(seq.length(), size_t(11));
+
+    {
+        SimpleSeq rev;
+        seq.revcom(rev);
+        IS(rev.id, string("seq1"));
+        IS(rev.desc, string("the quick brown fox jumps over a lazy dog"));
+        IS(rev.seq, string("AGCTGCGTCCA"));
+    }
+
+    {
+        string sub;
+        seq.subseq(sub, 3);
+        IS(sub, string("ACGCAGCT"));
+        seq.subseq(sub, 3, 4);
+        IS(sub, string("ACGC"));
+    }
+
+    {
+        SimpleSeq sub;
+        seq.subseq(sub, 3);
+        IS(sub.id, string("seq1"));
+        IS(sub.desc, string("the quick brown fox jumps over a lazy dog"));
+        IS(sub.seq, string("ACGCAGCT"));
+
+        seq.subseq(sub, 3, 4);
+        IS(sub.seq, string("ACGC"));
+    }
+}
diff --git a/t/t_string.cpp b/t/t_string.cpp
new file mode 100644
index 0000000..f86b79c
--- /dev/null
+++ b/t/t_string.cpp
@@ -0,0 +1,58 @@
+#include "TestFramework.h"
+#include "htio2/StringUtil.h"
+
+#include <vector>
+
+using namespace std;
+
+void TestFramework::content()
+{
+    {
+        vector<string> result;
+        htio2::split("aaa\tbbb\tccc", '\t', result);
+        IS(result.size(), 3);
+        IS(result[0], "aaa");
+        IS(result[1], "bbb");
+        IS(result[2], "ccc");
+    }
+
+    {
+        vector<string> result;
+        htio2::split("\taaa\tbbb\t", '\t', result);
+        IS(result.size(), 4);
+        IS(result[0], "");
+        IS(result[1], "aaa");
+        IS(result[2], "bbb");
+        IS(result[3], "");
+    }
+
+    {
+        vector<string> result;
+        htio2::split("\t", '\t', result);
+        IS(result.size(), 2);
+        IS(result[0], "");
+        IS(result[1], "");
+    }
+
+    {
+        vector<string> result;
+        htio2::split("aaa", '\t', result);
+        IS(result.size(), 1);
+        IS(result[0], "aaa");
+    }
+
+    {
+        vector<string> result;
+        htio2::split("", '\t', result);
+        IS(result.size(), 0);
+    }
+
+    {
+        vector<string> input;
+        input.push_back("aaa");
+        input.push_back("bbb");
+        input.push_back("ccc");
+        string result = htio2::join("abc", input.begin(), input.end());
+        IS(result, "aaaabcbbbabcccc");
+    }
+}
diff --git a/t/t_text_file_equal.cpp b/t/t_text_file_equal.cpp
new file mode 100644
index 0000000..9192905
--- /dev/null
+++ b/t/t_text_file_equal.cpp
@@ -0,0 +1,14 @@
+#include "TestConfig.h"
+#include "TestFramework.h"
+
+using namespace std;
+
+void TestFramework::content()
+{
+    const char* file1 = TEST_SOURCE_DIR"/test1.fastq.gz";
+    const char* file2 = TEST_SOURCE_DIR"/test2.fastq";
+
+    OK(text_file_eq(file1, file1));
+    OK(text_file_eq(file2, file2));
+    OK(!text_file_eq(file1, file2));
+}
diff --git a/t/test1.fasta b/t/test1.fasta
new file mode 100644
index 0000000..ca10f46
--- /dev/null
+++ b/t/test1.fasta
@@ -0,0 +1,400 @@
+>HWI-ST1106:815:H154GADXX:1:1101:1244:2196 1:N:0:CTTGTA
+AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAA
+GTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCT
+CCCACGTGTGGGAGCTTGTATGTACCTTAT
+>HWI-ST1106:815:H154GADXX:1:1101:1197:2208 1:N:0:TTGGTA
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGAC
+GCCGCGTGAGTGAAGAAGTGGTTCGCTATGTAAAGCTCTATCAGCAGGGAAGATNNTGAC
+GGTACCTGACTAAGAAGCTCCGGCTAACTA
+>HWI-ST1106:815:H154GADXX:1:1101:1231:2209 1:N:0:ATCACG
+TAATTTTTTGTGTTTTGTTTTGTTATTTTCTTTGTTTTAAAATAAAAGCTCATCGCTGAA
+GCCACAGAAGCACATCACGTACCCTATGATTCTATAGAGAAGCTCAGTTTGTTTTTAAGT
+TTGTTTCTGAATAAGTAGAGCACCACATAG
+>HWI-ST1106:815:H154GADXX:1:1101:1225:2231 1:N:0:GTCGCT
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCG
+ACGCCGCGTGAGTGAAGAAGTATCTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAATG
+ACGGTACCTGACTAAGAAGCCCCGGCTAAC
+>HWI-ST1106:815:H154GADXX:1:1101:1245:2247 1:N:0:ATCACG
+ACTCGTTATGATGCTTTAAAGCTTGCATATACGACATTACGTCAGGACGTCGTTGTCCAG
+AGTAGTACAAACGTAGGTCTATACTACTTTCATGTAGATTTACATCGAAAGAAGTTTAAT
+GCTGAAATCTATGACGTTCATGATTTAGCA
+>HWI-ST1106:815:H154GADXX:1:1101:1416:2204 1:N:0:GAACCT
+ATCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGAC
+GCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAATGAC
+GGTACCTAACAAGAAAGCACCGGCTAACTA
+>HWI-ST1106:815:H154GADXX:1:1101:1397:2205 1:N:0:TTAGGC
+AGCTCCTACGGGAGGCAGCAGGGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCG
+ACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAAA
+TGACGGTACCTGACTAAGAAGCACCGGCTA
+>HWI-ST1106:815:H154GADXX:1:1101:1258:2210 1:N:0:CAAGAA
+AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGCCAA
+GTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAGTCG
+GGTATGGATACCCGTTTGCATGTACTTTAT
+>HWI-ST1106:815:H154GADXX:1:1101:1454:2212 1:N:0:TGAGGT
+CAGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGC
+GACGCCGCGTGAGTGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAAT
+GACGGTACCTGACTAAGAAGCCCCGGCTAA
+>HWI-ST1106:815:H154GADXX:1:1101:1323:2213 1:N:0:CTACGG
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGAC
+GCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAATGA
+CGGTACCTGACTAAGAAGCACCGGCTAAAT
+>HWI-ST1106:815:H154GADXX:1:1101:1432:2216 1:N:0:GACACT
+GACTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGATG
+CCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTAAGGGAAGAGGAAGGAC
+TGTACCTTACAAGAAAGCTCCGGCTAACTA
+>HWI-ST1106:815:H154GADXX:1:1101:1340:2224 1:N:0:CCTTAA
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCG
+ACGCCGCGTGAGTGAAGAAGTAATTCGTTATGTAAAGCTCTATCAGCAGGGAAGATAGTG
+ACGGTACCTGACTAAGAAGCTCCGGCTAAA
+>HWI-ST1106:815:H154GADXX:1:1101:1400:2224 1:N:0:TTAGGC
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCG
+ACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAAA
+TGACGGTACCTGACTAAGAAGCACCGGCTA
+>HWI-ST1106:815:H154GADXX:1:1101:1493:2225 1:N:0:GTCGCT
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGCCGAGAGGCTGAACCAGCCAAG
+TCGCGTGAGGGATGAAGGTTCTATGGATCGTAAACCTCTTTTATAAGGGAATAAAGTGCG
+GGACGTGTCCCGTTTTGTATGTACCTTATG
+>HWI-ST1106:815:H154GADXX:1:1101:1376:2226 1:N:0:CCTTAA
+GACTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGACG
+CCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAATGACG
+GTACCTAACAAGAAAGCACCGGCTAACTAC
+>HWI-ST1106:815:H154GADXX:1:1101:1296:2233 1:N:0:TCATTC
+AAAAAACTGGAACAAGAAAGAAAACGTAAAATTGTTCCGCCGGAAATAACGACATGGTGG
+CGACTAGAATTGCAGTTACGAAGGGGAAAAGCAACTGATTGGCATGAGATGGTTCATGAA
+AGTTTGGATAGCTTTGCTAGTCCACAAGAT
+>HWI-ST1106:815:H154GADXX:1:1101:1467:2241 1:N:0:ATCACG
+CTGAATGCCTACAAAGGCTTCCTGTCGGATTATGCCTCCCTGCTGGACGAATTTGAAAAC
+GACAACCCCTTCAAAGCCAACTACCGGGTCTCGCTGAGCGTCATATGTGCCTGTTCTTCC
+TGCCATGACATTGGAATCAACATATACAGG
+>HWI-ST1106:815:H154GADXX:1:1101:1493:2245 1:N:0:GGCCTT
+GATCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCA
+AGTAGCGTGCAGGAAGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTG
+AGTCTCGTGAGACTTTTTGCATGTACCTTA
+>HWI-ST1106:815:H154GADXX:1:1101:1696:2195 1:N:0:CCTTAA
+AGCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGAC
+GCCGCGTGGAGGAAGAAGGTTTTCGGAGTTTAAACTCCTGTCGTTAGGGACGATAATGAC
+GGTACCTAACAAGAAAGCACCGGCTAACTA
+>HWI-ST1106:815:H154GADXX:1:1101:1646:2204 1:N:0:CATCTA
+CAACTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGC
+CAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAG
+TCGGGTATGCATACCCGTTTGCATGTACTT
+>HWI-ST1106:815:H154GADXX:1:1101:1502:2205 1:N:0:TTAGGC
+ATGATTTGCGCTCCCATATCTATCAGCTTGTCCACAAAGAACAAACGGCTTTCGAACATT
+TTCTGATGAATGAGTACACTGCCTTTTGCCTGGGTGGCAACCACCAGCAGCACACTGAGC
+AAGTCTGGTGTCAGTCCGGGCCAGGGTGCG
+>HWI-ST1106:815:H154GADXX:1:1101:1742:2207 1:N:0:CATCTA
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAG
+TAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGTGAG
+CCACGTGTGGCTTTTTGTATGTACCGTATG
+>HWI-ST1106:815:H154GADXX:1:1101:1683:2207 1:N:0:CCTTAA
+AGCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGAC
+GCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAATGAC
+GGTACATAACAAGAAAGAACCGGCTCACAA
+>HWI-ST1106:815:H154GADXX:1:1101:1541:2208 1:N:0:ATCACG
+AATTCTAGAAATCACTCGCTGGTTTCGCCTAAAAATAGTAACTTTGCACCCAACAAAAAG
+AAACCAAAGACATTATGAACATTAAGAATATCCATTTGGCCTATTTTAGTGCCACTTTCT
+CCACCAAACGTATCGTTCGTGAGATAGCAT
+>HWI-ST1106:815:H154GADXX:1:1101:1564:2216 1:N:0:CAGATC
+AAAACGCCAAAGATAGTATTGACAGAACGCTAGCAAACGAAGCAGGTGTATCTTTAGAAG
+TATTGACTCCTTTGGAAGGATTGACGAATGAACAAATAGAAAATGGAGAAAACTATCTTT
+CTATCATGGAAGCAAACCTCGAAGCGAGAT
+>HWI-ST1106:815:H154GADXX:1:1101:1719:2228 1:N:0:CTACGG
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAG
+TAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGTGAG
+GCACGTGTGCCTTTTTGTATGTAACGTATG
+>HWI-ST1106:815:H154GADXX:1:1101:1844:2204 1:N:0:CACTTG
+GACTACGGGAGGCAGCAGTGGGGAATCTTCCGCAATGGGCGAAAGCCTGACGGAGCAACG
+CCGCGTGAGTGAAGAAGGTCTTCGGATTGTAAAGCTCTGTTGTACATGACGAATGTGCCG
+GTTGTGAATAATGGCTGGCAATGACGGTAG
+>HWI-ST1106:815:H154GADXX:1:1101:1890:2219 1:N:0:GCCAAT
+GACTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGACG
+CCGCGTGAGTGAAGAAGTAGTTCGCTATGTAAAGCTCTATCAGCAGGGAAGATAGTGACG
+GTACCTGACTAAGAAGCTCCGGCTAAATAC
+>HWI-ST1106:815:H154GADXX:1:1101:1802:2224 1:N:0:CGTCAA
+GACTACGGGAGGCAGCAGTGGGGAATATTGGGCAATGGGGGAAACCCTGACCCAGCAACG
+CCGCGTGAAGGAAGAAGGCTTTCGGGTTGTAAACTTCTTTTACCAGGGACGAAGGGCGTG
+ACGGTACCTGGAGAAAAAGCCACGGCTAAC
+>HWI-ST1106:815:H154GADXX:1:1101:1840:2224 1:N:0:GTCGCT
+GGTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGATGGCCTGAACCAGCCA
+AGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAGTC
+GGGTATGCATACCCGTTTGCATGTACTTTA
+>HWI-ST1106:815:H154GADXX:1:1101:1923:2228 1:N:0:AAGCGA
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGA
+CGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAAAT
+GACGGTACCTGACTAAGAAGCACCGGCTAA
+>HWI-ST1106:815:H154GADXX:1:1101:1769:2229 1:N:0:TTAGGC
+AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAA
+GTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCT
+CCCACGTGTGGGAGCTTGTATGTACCTTAT
+>HWI-ST1106:815:H154GADXX:1:1101:1997:2231 1:N:0:TAGAAG
+GACTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAAGTCTGATGCAGCGACG
+CCGCGTGAGCGAAGAAGTAGTTCGGTATGTAAAGCTCTATCAGCAGGGAAGATAGTGACG
+GTACCTGACTAAGAAGCACCGGCTAAATAC
+>HWI-ST1106:815:H154GADXX:1:1101:1965:2235 1:N:0:CCACTC
+GTCATTTAGAGGAAGTAAAAGTCGTAACAAGGTTTCCGTAGGTGAACCTGCGGAAGGATC
+ATTACCGGGTGCGGGCCCTCTGGGTCCAACCTCCCATCCGTGTCTATCTGTACCCTGTTG
+CTTCGGCGTGGCCACGGCCCGCCGAAGACT
+>HWI-ST1106:815:H154GADXX:1:1101:1871:2243 1:N:0:GTCGCT
+AGCTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCC
+AAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGT
+GAGGCACGTGTGCCTTTTTGTATGTACCGT
+>HWI-ST1106:815:H154GADXX:1:1101:2118:2199 1:N:0:CAGCAC
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGA
+CGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGATAATGA
+CGGTACCTGACTAAGAAGCCCCGGCTAACT
+>HWI-ST1106:815:H154GADXX:1:1101:2145:2206 1:N:0:CTATGG
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGA
+CGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAATG
+ACGGTACCTGACTAAGAAGCACCGGCTAAA
+>HWI-ST1106:815:H154GADXX:1:1101:2188:2208 1:N:0:TGACCA
+GACTACGGGAGGCAGCAGTGGGGAATATTGGGCAATGGGCGCAAGCCTGACCCAGCAACG
+CCGCGTGAAGGAAGAAGGCTTTCGGGTTGTAAACTTCTTTTGTCGGGGACGAGTAGAAGA
+CGGTACCTGGCGAATAAGCCACGGCTAACT
+>HWI-ST1106:815:H154GADXX:1:1101:2116:2218 1:N:0:GAACCT
+GAACTCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGGAACCCTGATGCAGC
+GACGCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAAT
+GACGGTACCTAACAAGAAAGCACCGGCTAA
+>HWI-ST1106:815:H154GADXX:1:1101:2046:2228 1:N:0:TTAGGC
+GGATATGAAAACATCGCTCCCGGTGATGCCATTTTCTTCGATTGGGATCTGGATGGTTCC
+GCAGACCATGTGGGAATTGTTGTCGGCACCGATGGCAGCCGTGTTTATACCGTGGAGGGA
+AATTCCGGCGATGCCTGCAAGATCAAAAGT
+>HWI-ST1106:815:H154GADXX:1:1101:2092:2229 1:N:0:AGTCAA
+AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGCCAA
+GTAGCGTGCAGGATGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTGA
+GTCTCGTGAGACTTTTTGCATGTACCTTAT
+>HWI-ST1106:815:H154GADXX:1:1101:2195:2237 1:N:0:GTCGCT
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCG
+ACGCCGCGTGAGTGAAGAAGTAATTCGTTATGTAAATCTCTATCAGCGGGGAAGATAGTG
+ACGGTACCTGATTAAGAAGCTCCGGCTAAA
+>HWI-ST1106:815:H154GADXX:1:1101:2147:2238 1:N:0:CTACGG
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGCGAAAGCCTGATGCAGCGAC
+GCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGATAATGAC
+GGTACCTGACTAAGAAGCACCGGCTAAATA
+>HWI-ST1106:815:H154GADXX:1:1101:2498:2195 1:N:0:CTACGG
+ATCTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGCTAGCCTGAACCAGCC
+AAGTAGCGTGAAGGATGAAGGCTCTATGGGTCGTAAACTTCTTTTATATAAGAATAAAGT
+GCAGTATGTATACTGTTTTGTATGTATTAT
+>HWI-ST1106:815:H154GADXX:1:1101:2263:2198 1:N:0:ACTTGA
+GATCCTGAAGCAGAATTATCTGGTGTTTACCGGTATATCGGGGCTGGCGGTACAGTAAAA
+CGTCCGACTCAAGAAGGACCAGCTATTACTTTCAACAATATCAAAGGATTCCCCTGCACA
+CGGGTGAACATCGGAACAATGGCTAATCGT
+>HWI-ST1106:815:H154GADXX:1:1101:2307:2201 1:N:0:TGGATT
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGCGAAAGCCTGATGCAGCG
+ACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGATAATG
+ACGGTACCTGACTAAGAAGCACCGGCTAAA
+>HWI-ST1106:815:H154GADXX:1:1101:2283:2204 1:N:0:CTACGG
+CGCTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGCGAGCCTGAACCAGCC
+AAGTAGCGTGAAGGATGACGGCCCTATGGGTTGTAAACTTCTTTTATATGGGAATAAAGT
+TTGGTATGCATACCATTTTGTATGTACCAT
+>HWI-ST1106:815:H154GADXX:1:1101:2453:2206 1:N:0:ATACAC
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAG
+TAGCGTGCAGGAAGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTTAG
+TCTCGTGAGACTTTTTGCATGTACCTTATG
+>HWI-ST1106:815:H154GADXX:1:1101:2336:2209 1:N:0:GTCGCT
+GATCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGATGGCCTGAACCAGCCA
+AGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATATTAGAATAAAGTG
+CAGTATGTATACTGTTTTGTATGTATAATA
+>HWI-ST1106:815:H154GADXX:1:1101:2378:2210 1:N:0:CTACGG
+CAACTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGCAGGCCTGAACCAGC
+CAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAG
+TCGGGTATGTATACCCGTTTGCATGTACTT
+>HWI-ST1106:815:H154GADXX:1:1101:2470:2220 1:N:0:ATCACG
+TCTAACTGGGGCCGTAAGCGTTCGCTGATCTTTGCGGGTGTGATGTTCTTCATCTCTGCA
+TGGGGATCTATGTGTCCTGAGTCTTTGGTGTTGCCAAAGGGCGAACCTAATCTTACGCTT
+CTCATCGTGTTCAACCTCTATCGTGTGATT
+>HWI-ST1106:815:H154GADXX:1:1101:2434:2220 1:N:0:CGATGT
+GTAGAAGGTACTTATTTGTATAGTAAGAAAGATAATAATAGTTCACCTTTTATAATACGA
+ATTCATGCATATGCTGGAAAATCATATATTCGAGTGCTTCATACAATAACTTATACTGGT
+ATTCCTGACAAGCATAAAATAGAAAAGGGA
+>HWI-ST1106:815:H154GADXX:1:1101:2285:2223 1:N:0:CGAATA
+GATCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCA
+AGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGTT
+AGCCACGTGTGGCTTTTTGTATGTACCGTA
+>HWI-ST1106:815:H154GADXX:1:1101:2390:2234 1:N:0:ATACAC
+CAACTCCTCGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCA
+ACGCCGCGTGAGTGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGAAAGAAAATG
+ACGGTACCTGACTAAGAAGCCCCGGCTAAC
+>HWI-ST1106:815:H154GADXX:1:1101:2331:2236 1:N:0:CAGCAC
+AGCTCCTACGGGAGGCAGCAGTCGGGAATATTGCGCAATGGAGGAAACTCTGACGCAGTG
+ACGCCGCGTGCAGGAAGAAGGCTTTCGGATTGTAAACTGCTTTAGACAGGGAAGAAACAA
+GACAGTACCTGTAGAATAAGCTCCGGCTAA
+>HWI-ST1106:815:H154GADXX:1:1101:2413:2237 1:N:0:CAGATC
+GTTAGAAGAAATAGCGGATCAATCGAGTGACACTCTTTCAGGCGGTCAACTCCAACGTGC
+GTATATTGCAATGGTGCTAGCGCAAGACACGGATTATATTTTACTGGATGAACCTTTGAA
+CAATCTAGATATGAATTTTGCGGTTCAAAT
+>HWI-ST1106:815:H154GADXX:1:1101:2368:2242 1:N:0:TCCTCA
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGAC
+GCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAAATG
+ACGGTACCTGACTAAGAAGCACCGGCTAAA
+>HWI-ST1106:815:H154GADXX:1:1101:2491:2246 1:N:0:CCTTAA
+AGCCTACGGGAGGCAGCAGTTAGGAATATTCGTCAATGGGGGAAACCCTGAACGAGCAAT
+GCCGCGTGAAGGATGACGGTCCTTTGGATTGTAAACTTCTGTTGGTAGGGAAGAACAAAC
+TGTATAGGAAATGATACAGTTCTGACGGTA
+>HWI-ST1106:815:H154GADXX:1:1101:2525:2193 1:N:0:CAGATC
+TCTAGAAAGCGCGTCTGTTTCATGTGCTTTCTATTATTTATCTTATGCCAATCCATTTCT
+TTGCTTTCCACAATTATATTGTGTAAAATTCAATTGTATAAAATATAATTAAAGGTGGTA
+ATTTTATGAAAAAAATGTATTCTACGAAAA
+>HWI-ST1106:815:H154GADXX:1:1101:2680:2193 1:N:0:GAACCT
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGCCAAG
+TAGCGTGCAGGAAGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTTAG
+TCTCGTGAGACTTTTTGCATGTACCTTATG
+>HWI-ST1106:815:H154GADXX:1:1101:2516:2210 1:N:0:TAGCTT
+GACTACGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGT
+AGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATATGGGAATAAAGTTTTC
+CACGTGTGGAATTTTGTATGTACCATATGA
+>HWI-ST1106:815:H154GADXX:1:1101:2713:2212 1:N:0:TGACCA
+ACCGGCGTTATTAGTGGAACACAAACTATATGTGCAGGAAGTAGTACTACATTAAGTATC
+GCTGTAACCGGAACAGGTCCATGGAGCGGAACATTATCAAACGGTGATCCATTCAGTGGC
+AGCAGCAGCCCAATCAGTGTGTCAGTCAAT
+>HWI-ST1106:815:H154GADXX:1:1101:2678:2222 1:N:0:CGCTGA
+CAACTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGC
+CAAGTAGCGTGCAGGATGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAG
+TGAGTCTCGTGAGATTTTTTGCATGTACCT
+>HWI-ST1106:815:H154GADXX:1:1101:2588:2225 1:N:0:CCTTCT
+CAACTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGATGGCCTGAACCAGC
+CAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAG
+TCGGGTATGCATACCCGTTTGCATGTACTT
+>HWI-ST1106:815:H154GADXX:1:1101:2713:2231 1:N:0:TGACCA
+ACCGGCGTTATTAGTGGAACACAAACTATATGTGCAGGAAGTAGTACTACATTAAGTATC
+GCTGTAACCGGAACAGGTCCATGGAGCGGAACATTATCAAACGGTGATCCATTCAGTGGC
+AGCAGCAGCCCAATCAGTGTGTCAGTCAAT
+>HWI-ST1106:815:H154GADXX:1:1101:2557:2232 1:N:0:CAAGAA
+AAACTCCTTCGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGC
+CAAGGAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAG
+TCGGGCATGGATACCCGTTTGCATGTACTT
+>HWI-ST1106:815:H154GADXX:1:1101:2740:2237 1:N:0:AGTTCC
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGA
+CGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAAAT
+GACGGTACCTGACTAAGAAGCACCGGCTAA
+>HWI-ST1106:815:H154GADXX:1:1101:2527:2244 1:N:0:GTTGAA
+CAACTCCTACGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCC
+AAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGT
+GAGGCACGCGTGCCTTTTTGTATGTACCGT
+>HWI-ST1106:815:H154GADXX:1:1101:2603:2248 1:N:0:CAGCAC
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCAAC
+GCCGCGTGAAGGATGACGGTTTTCGGATTGTAAACTTCTTTTCTTAGTGACGAAGACAGT
+GACGGTAGCTAAGGAATAAGCATCGGCTAA
+>HWI-ST1106:815:H154GADXX:1:1101:2853:2195 1:N:0:ACTTGA
+AATCGACAACAGGAACTGAAAAATGTTCTGAGAATTCTTTGATTTGCGGAAATCCGTTTC
+GCGTTCCTTGACCAACATAAAGAACTGGTTTTTTTGCTTTTTCAAGATAAGGCAAAGCAG
+CTAGCAAATCTTTTTCTTCTGGTAATATCA
+>HWI-ST1106:815:H154GADXX:1:1101:2884:2198 1:N:0:TGGATT
+CAACTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGC
+CAAGTAGCGTGCAGGAAGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAG
+TGAGTCTCGTGAGACTTTTTGCATGTACCT
+>HWI-ST1106:815:H154GADXX:1:1101:2751:2204 1:N:0:AAGCTT
+TTTGTCATTTAGAGGAAGTAAAAGTCGTAACAAGGTTTCCGTAGGTGAACCTGCGGAAGG
+ATCATTACCGAGTGAGGGCCCTTTGGGTCCAACCTCCCACCCGTGTTTATTTTACCTTGT
+TGCTTCGGCGGGCCCGCCTTTACTGGCCGC
+>HWI-ST1106:815:H154GADXX:1:1101:2785:2207 1:N:0:AAGAAG
+AGCTCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCG
+ACGCCGCGTGGGGGAAGAAGGATTTCGGAATGTAAAGTCCTGTCGGCAGGGAAGAAGATA
+ACGGTGCATCAGAAGAAGGAACAGGCGCAA
+>HWI-ST1106:815:H154GADXX:1:1101:2938:2209 1:N:0:CAGATC
+TATCACTTCGGAAAGTCCCTAACTGGCTACCGTCAAGATACTCCTGTTTTGCAAAACGAT
+TACCGGAGATAACTACTGTTCCTGCTCCCACAAGTTTAAAATTGGATAATCTGCTTTCTA
+TATATTCATCATATCTTCCTTCTTTTACTA
+>HWI-ST1106:815:H154GADXX:1:1101:2969:2210 1:N:0:CGTCAA
+AGCCTACGGGAGGCAGCAGGGAGGAATATTGGTCAATGGGCGCAGGCCTGAACCAGCCAA
+GTAGCGTGAAGGATGACTGCCCTATGGGGTGTAAACTTCTTTTATAAAGGAATAAAGTCG
+GGTATGTATACCCGTTTGCATGTACTTTAT
+>HWI-ST1106:815:H154GADXX:1:1101:2909:2214 1:N:0:CCGTCC
+ATTGCCTTTACCGATGGCATAATCTCAAAATATTCCACACCTACTATTACAACCGTAAGT
+CAGAGTGGAATAAAAATGGGAAATAAAGCGGCAAAAATGCTAATAGAAAGACTCGAATCT
+GAGGAAAATGAAGAAGATGAAAACTATAAA
+>HWI-ST1106:815:H154GADXX:1:1101:2888:2222 1:N:0:GTCGCT
+GACTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGCGAAAGCCTGATGCAGCAACG
+CCGCGTGAGTGAAGAAGTATCTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAATGACG
+GTACCTGACTAAGAAGCCCCGGCTAACTAC
+>HWI-ST1106:815:H154GADXX:1:1101:2873:2233 1:N:0:ACTTGA
+CTAGAACAAGCAATAACAACTGTAAAACAAACAGTTACAGAGCTAAATGAAAAACAAGAG
+AAGAACCAGTCAGTTATCAAAAGTTTGGACGATCAACTTTCAAAAGGAATACTAAAAGCT
+CCTGTATCTGGAACGGTTCATTTAAATGAA
+>HWI-ST1106:815:H154GADXX:1:1101:2990:2243 1:N:0:GTCGCT
+AGCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGAGGAAACTCTGATGCAGCGAC
+GCCGCGTGAGTGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAATGAC
+GGTACCTGACTAAGAAGCCCCGGCTAACTA
+>HWI-ST1106:815:H154GADXX:1:1101:2791:2243 1:N:0:CAGATC
+ATCCAAAAATCCGCCACCCCATATCCAGTGGCAAACAGGGAAATAAATCAGCAGATTCCA
+AAAAATAACAAGTATAATATAGCCTTTTAAATTCAATCTCCCTGCAAAAGCTCCTGTCAT
+CAAAGGAACGGTAATCACGATAAACATCAG
+>HWI-ST1106:815:H154GADXX:1:1101:3046:2196 1:N:0:AGTTCC
+CAACTCCTCGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGCGAGTCTGAACCAGCC
+AAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATATGGGAATAAAGT
+TATCCACGTGTGGATTTTTGTATGTACCAT
+>HWI-ST1106:815:H154GADXX:1:1101:3147:2203 1:N:0:GGCCTT
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGA
+CGCCGCGTGAGTGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGACAGTGA
+CGGTACCTGACTAAGAAGCTCCGGCTAAAT
+>HWI-ST1106:815:H154GADXX:1:1101:3211:2211 1:N:0:AGTGGT
+GATCCTCGGGAGGCAGCAGTGAGGAATATTGGTCGATGGACGAGAGTCTGAACCAGCCAA
+GTAGCGTGCAGGAAGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTGA
+GTCTCGTGAGACTTTTTGCATGCACCTTAT
+>HWI-ST1106:815:H154GADXX:1:1101:3127:2215 1:N:0:ATCACG
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGAC
+GCCGCGTGAGTGAAGAAGTAATTCGTTATGTAAAGCTCTATCAGCAGGGAAGATAGTGAC
+GGTACCTGACTAAGAAGCTCCGGCTAAATA
+>HWI-ST1106:815:H154GADXX:1:1101:3233:2216 1:N:0:TTGGTA
+AGCCTACGGGAGGCAGCAGTAGGGAATCTTCCGCAATGGACGCAAGTCTGACGGAGCAAC
+GCCGCGTGAGTGAAGAAGGTTTTCGGATCGTAAAACTCTGTTGTTAGAGAAGAACAAGTG
+CTAGAGTAACTGTTAGCGCCTTGACGGAAT
+>HWI-ST1106:815:H154GADXX:1:1101:3185:2216 1:N:0:TTGGTA
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCAA
+CGCCGCGTGAGTGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAATGA
+CGGTACCTGACTAAGAAGCCCCGGCTAACT
+>HWI-ST1106:815:H154GADXX:1:1101:3012:2219 1:N:0:GTCGCT
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGCGAAAGCCTGATGCAGCA
+ACGCCGCGTGAGTGAAGAAGTATCTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAATG
+ACGGTACCTGACTAAGAAGCCCCGGCTAAC
+>HWI-ST1106:815:H154GADXX:1:1101:3071:2234 1:N:0:CTACGG
+AGCTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCC
+AAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGT
+GGAGTATGCATACTCCTTTGTATGTACCGT
+>HWI-ST1106:815:H154GADXX:1:1101:3245:2235 1:N:0:CCTTAA
+AGCTCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCG
+ACGCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAATG
+ACGGTACCTAACAAGAAAGCACCGGCTAAC
+>HWI-ST1106:815:H154GADXX:1:1101:3136:2239 1:N:0:TTGGTA
+AGCTCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCG
+ACGCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAATG
+ACGGTACCTAACAAGAAAGCACCGGCTAAC
+>HWI-ST1106:815:H154GADXX:1:1101:3036:2243 1:N:0:CAAGAA
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGCCAAG
+TAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAGTCGG
+GTATGGATACCCGTTTGCATGTACTTTATG
+>HWI-ST1106:815:H154GADXX:1:1101:3201:2246 1:N:0:CTGTCA
+CGCTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGCAGGCCTGAACCAGCC
+AAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATATGGGAATAAAGT
+TTTCCACGTGTGGAATTTTGTATGTACCAT
+>HWI-ST1106:815:H154GADXX:1:1101:3089:2248 1:N:0:ACTTGA
+GAACCCATATGTTCTTTTCTGCAATATTCCTCGAGCCATCGTTGTGATATTGGTCAAGTC
+AATAAAAGCAATGACTTCTGTCAGCAATTCTTGATATCCTAGCTTATCGGCAAGCCGTCG
+CTGCTCTGTCAAAAACTGTCGATCATAAAT
+>HWI-ST1106:815:H154GADXX:1:1101:3466:2192 1:N:0:CGATGT
+ATCGCGCCTTTAAGTCAGCCTGCAGGAAACAGTACGTTGACTTTAACCTCCTTTGATAAT
+GACCAACACCATGAAGTAGATCTGGTAAACATAGCTCGATTGGGCCGTCAATGGTTTGGC
+GAATCATTTGAGGTTAAAAACGAACAGGAA
+>HWI-ST1106:815:H154GADXX:1:1101:3490:2192 1:N:0:TAATCG
+GACTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACG
+CCGCGTGAGCGAAGAAGTATTTCGGGATGTAAAGCTCTATCAGCAGGGAAGAAGAAATGA
+CGGTACCTGACTAAGAAGCACCGGCTAAAT
+>HWI-ST1106:815:H154GADXX:1:1101:3418:2203 1:N:0:TCACAA
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGTCGGCAGACTGAACCAGCCAAG
+TCGCGTGAGGGAAGACGGCCCTACGGGTTGTAAACCTCTTTTGTCGGAGAGTAAAGTACG
+CTACGTGTAGTGTATTGCAAGTATCCGAAG
+>HWI-ST1106:815:H154GADXX:1:1101:3308:2210 1:N:0:TTGGTA
+AGCCTCGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGACGC
+CGCGTGGAGGAAGAAGGTTTTCGGATTGCAAACTCCTGTCGTTAGGGACGATAATGACGG
+TACCTAACAAGAAAGCACCGGCTAACTACG
+>HWI-ST1106:815:H154GADXX:1:1101:3481:2217 1:N:0:ATCACG
+GGGTAAAAGACTGGGCTAAGGAGAATGATTGCTGGATTGAAAATCCGGAATCATTAGGTG
+TGTTCTCTGACCGAGGTTCAGAGAACGAGGTTTATATGGCCTATGATGGAATACACGTTT
+ATAAACTTTACGACTTCCGTTATTCTGACG
+>HWI-ST1106:815:H154GADXX:1:1101:3392:2219 1:N:0:ATCACG
+GGGTACGACGCACATAACGCCCAGGGTGGAGAACTTGCCGAAATTCTTAGGTCCTACGAG
+GCTGATCGTAGCAGCGGCCAGAAGGACGCCGATTGTAGCCAGGCAGACTTCAACCGGATC
+AAGGTTGAAACCGAAAACATAAGAACCGTA
+>HWI-ST1106:815:H154GADXX:1:1101:3431:2221 1:N:0:TTAGGC
+ATCGCAAATCATGGTGGGGATGATACGGCGTTTCATTGCGGAGCAGGAAATTGTTATGTT
+CTTATCAGGAGATTATAATTGGCCTGACAAATGGATGTGATTTATTTATTGGGCTCAATT
+GGGCTAGGTTGGGGATCTTCATTTGTCCAC
diff --git a/t/test1.fastq b/t/test1.fastq
new file mode 100644
index 0000000..f42a110
--- /dev/null
+++ b/t/test1.fastq
@@ -0,0 +1,400 @@
+ at HWI-ST1106:815:H154GADXX:1:1101:1244:2196 1:N:0:CTTGTA
+AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCTCCCACGTGTGGGAGCTTGTATGTACCTTAT
++
+=?@DFADDHHAHDGGBGGGIGHBEGGHEI>FGIIGCGGCH3?@FEB@@@FGICHG==AHFFEFEEDDDDDDC<>A>A:ACDCC>C<@BB>C at ACC@CACAC at ACCDDDCA?ABCAC at 9@AA8??8><ADB<>B8<B:C?>@>>34>:@CD
+ at HWI-ST1106:815:H154GADXX:1:1101:1197:2208 1:N:0:TTGGTA
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTGGTTCGCTATGTAAAGCTCTATCAGCAGGGAAGATNNTGACGGTACCTGACTAAGAAGCTCCGGCTAACTA
++
+@@CFFDFFGHHHHJJHFHGHHGIIHIJJJJIHHJJJJGIGIJHIJGIICFC at ECEHAB@4=;@DBB8B at B:@:>C>>CCCD:?CDDDDBDEEEDCCDCDDCCCC@@ADD?BDBD##++8?@B9A9CDCCCCCDDCDCCD at C>BBDDCDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:1231:2209 1:N:0:ATCACG
+TAATTTTTTGTGTTTTGTTTTGTTATTTTCTTTGTTTTAAAATAAAAGCTCATCGCTGAAGCCACAGAAGCACATCACGTACCCTATGATTCTATAGAGAAGCTCAGTTTGTTTTTAAGTTTGTTTCTGAATAAGTAGAGCACCACATAG
++
++:?DDDDDDHAFDHI at FGEGGGHGIIIHIIEGIGIIIGHIGIIIHIGICGGIIIICFFGIIIIAHHEAE@?BCCCCCCCBCBBCCCCCCDCDCEDCAACCC<CCCCCCDDCBCCCBBCCDDC>?CCACC>:@CCCDCCCCCC<ABBBCCC
+ at HWI-ST1106:815:H154GADXX:1:1101:1225:2231 1:N:0:GTCGCT
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTATCTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAATGACGGTACCTGACTAAGAAGCCCCGGCTAAC
++
+=1=BBDDDHH)@?187EFEFH:CDHHGFHGIIIIIIGIIHIICFG<CHHEDECCECCCCBB?=@BBBB7BBB3+>@CCCC:ADDECBBBBBCEECDCCCCC at CCCC>C?BBBBBBCCCC:>C at BBBBCCACCCCCCCCCABBB.9<BBCC
+ at HWI-ST1106:815:H154GADXX:1:1101:1245:2247 1:N:0:ATCACG
+ACTCGTTATGATGCTTTAAAGCTTGCATATACGACATTACGTCAGGACGTCGTTGTCCAGAGTAGTACAAACGTAGGTCTATACTACTTTCATGTAGATTTACATCGAAAGAAGTTTAATGCTGAAATCTATGACGTTCATGATTTAGCA
++
++BBFFDFFHHHHHJJJJIJJIHIJJJIIHIJIIJJJJJJJGIJGIJJJJAHIJIIGIJJHGHHHHFFFFFFDDEEDDDDDDEDDEDDDDEDDEDEEDCDDDCDDEDDDDDDDDDDDCCCCCCC at CCDCDDDEECDDDDDDEDCCDEDCDD
+ at HWI-ST1106:815:H154GADXX:1:1101:1416:2204 1:N:0:GAACCT
+ATCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAATGACGGTACCTAACAAGAAAGCACCGGCTAACTA
++
+1+14=ADDFFFFFII7EBCFGIIIIIEIIIFFIIIIFFIIIBEFDDDDCCCBBBBBBBB at BBBBBBBBB<?@?BBBBBB>BBBBBBBBBBBEEDBBBBBBB at B?>@BBBB?>>?BBBBBB<@>BBBBBBB at B??BB:AB<?><><?BBBB
+ at HWI-ST1106:815:H154GADXX:1:1101:1397:2205 1:N:0:TTAGGC
+AGCTCCTACGGGAGGCAGCAGGGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAAATGACGGTACCTGACTAAGAAGCACCGGCTA
++
+=@;=4BBB?F<D at FE:EA?FH)CFGBBBBC8>ACCCC@>CCB at 6@BBCB<AC9>@:A at C7&005;@BB508?A5-9<>?C:>CA@>AB<?@C>CDECCC:::>ACCCCBBB0?@BCA9CCACCA89<<5@>C?9 at ACAC@399<8.99<B
+ at HWI-ST1106:815:H154GADXX:1:1101:1258:2210 1:N:0:CAAGAA
+AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAGTCGGGTATGGATACCCGTTTGCATGTACTTTAT
++
+BCCFFFFFFFFHHIJJJJJIJGGIJJIJIHIJIIIJJJIHGIJJJJJJJJHHHHHFFFFEDEEEDBDDDDDDDDDDDDDDDDDDDCDBCBDDDEEDCDDDC>CDDEEDCCDDDDDDCBCBBD<>CCCCCCACDD5ACDCEEDDDDBCDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:1454:2212 1:N:0:TGAGGT
+CAGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAATGACGGTACCTGACTAAGAAGCCCCGGCTAA
++
+1=+4AAD?FFDHHHFHGIII at BFGHIEIGI<?GGIIIGGHDH at BEAHFHEFFDFFEECE@@@BCC at 55>@B<@CCCDC>CC>CCCC at CBB??@DDDECCCCACCCCCCCBB@<ABBAC(>CAA at B>B<CCCCAC>AC>CA?8<<<BBBBC
+ at HWI-ST1106:815:H154GADXX:1:1101:1323:2213 1:N:0:CTACGG
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAATGACGGTACCTGACTAAGAAGCACCGGCTAAAT
++
+:?@DDDDDHAFFAGIBEECH at G=DHHIGIGBHCHIIGHIICBHHGIFHFHEEEDECCCBBBBBBBBB7???BBBBBCCCCEEE at C@<ABA at CDDAAACCCC>CACCBB>818AC?CCA>ACBBBB>@@ACCCACCC at 3>A9<9<<>BCCA
+ at HWI-ST1106:815:H154GADXX:1:1101:1432:2216 1:N:0:GACACT
+GACTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGATGCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTAAGGGAAGAGGAAGGACTGTACCTTACAAGAAAGCTCCGGCTAACTA
++
+=1+ADDDDF>FFDIFEEFCEF:CGE6??DBDFF==FFA at FFEE?@D?A at ACCBBBABB@B?BB;BBB;<@BB?<<BBBBBB?A at B?BBBADE>@ABBBABB<<?B at AB@BBB?B(8<?@BBBBBBBBBAA>ABBBBBABBB09 at B<B?AB
+ at HWI-ST1106:815:H154GADXX:1:1101:1340:2224 1:N:0:CCTTAA
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTAATTCGTTATGTAAAGCTCTATCAGCAGGGAAGATAGTGACGGTACCTGACTAAGAAGCTCCGGCTAAA
++
+B@@DDDFDHHDDFHIJIJJJJ?HHJJJIIJJJIJJJJIIJJJJJJJJJJJJJIJJIHHHFDDDDDDDDDDDD:@CDDDDDCCD:BCB+>ABDDEEEDDCDDAACDEDDDDDDDDDDDDDEEDDDBABDDDDDDDDDDDCCDCDDDDBDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:1400:2224 1:N:0:TTAGGC
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAAATGACGGTACCTGACTAAGAAGCACCGGCTA
++
+11:BBDDBFHHHFIIIIIIIIDGIIEGGIGGIIGIIIIIIIIIFGGHHHHEEEEECCCCB?BB at BBBBBBBBCBBBBBCCCCEEDECBBBBCDDEECCCCCCCCCECCBBBBBBBCCCCCCCCCBBB?<CCCCACCCCCCCC?A?B at BBB
+ at HWI-ST1106:815:H154GADXX:1:1101:1493:2225 1:N:0:GTCGCT
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGCCGAGAGGCTGAACCAGCCAAGTCGCGTGAGGGATGAAGGTTCTATGGATCGTAAACCTCTTTTATAAGGGAATAAAGTGCGGGACGTGTCCCGTTTTGTATGTACCTTATG
++
+ at C<DFFFFHHHDHIGAFGGIIIIIIIIIIIIHIGFG at FHIADAHIICGDDHEHHHFFFFDEDDBDDBBBBBBCDDDDCCACAADDCDDDDD?A?A?CDDCD>CCEEDCDA?8 at CDC>CCB>BBDDBDCAAC>8ACBB<@@ADECCCCDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:1376:2226 1:N:0:CCTTAA
+GACTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAATGACGGTACCTAACAAGAAAGCACCGGCTAACTAC
++
+@@CFFFFFHHHHHJJJJIHGIJIIIIJJJJJJJJJJJJJJJHHFFFFEEEEEEDDDDDDDDDDDDDDDDDDBDDDDDD>ACDDDDBDDDDEEEDDCDDDCC88>BDDDCDBDDDDDDDDDD9ABCCCCDDCDCDDCCCAA at DB@BCCDAC
+ at HWI-ST1106:815:H154GADXX:1:1101:1296:2233 1:N:0:TCATTC
+AAAAAACTGGAACAAGAAAGAAAACGTAAAATTGTTCCGCCGGAAATAACGACATGGTGGCGACTAGAATTGCAGTTACGAAGGGGAAAAGCAACTGATTGGCATGAGATGGTTCATGAAAGTTTGGATAGCTTTGCTAGTCCACAAGAT
++
+1:?DDDD;D?FHHGIDBBGFHGHGEFHIIIIFIGIIIIEGGD8FHHHHCHEHEC>CC>>?@?8=@B34 at CC:AACCC at C@?BBBBBBBBCCBCCBC>:>>A<>AC at A>A@>@:>CCA>(4::@>C48@@>ACCCC:>@::@A>ACCBBCA
+ at HWI-ST1106:815:H154GADXX:1:1101:1467:2241 1:N:0:ATCACG
+CTGAATGCCTACAAAGGCTTCCTGTCGGATTATGCCTCCCTGCTGGACGAATTTGAAAACGACAACCCCTTCAAAGCCAACTACCGGGTCTCGCTGAGCGTCATATGTGCCTGTTCTTCCTGCCATGACATTGGAATCAACATATACAGG
++
+1=144=BDFHFHHEIEGHHGIFFEFHIIGEGEIIJIGIJIGIIIIIGIJJIGGIIGHEIEGEHFDAC>B=BDCDDCDDDDDCCCCDBB59CCCDBBDDD@>?@ADCCDBCCCDCCCCCCCACCDCCDDDDDDDCCDCDDCCDDDEEDEDD
+ at HWI-ST1106:815:H154GADXX:1:1101:1493:2245 1:N:0:GGCCTT
+GATCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGCAGGAAGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTGAGTCTCGTGAGACTTTTTGCATGTACCTTA
++
+CCCFFFFFHHHHHJJJJJGIFGGIJJIJJIJJJJJJJJJIJJJJJJJJJIJIJJJHHGGFFFFFFEDDDDDDDDBDDDBDDDDDDDCDDC at DDDEEDDCCD@CDDDDDCDDBDDCCDDEDDDDDDCDDDDDDDDDDDDDDDCCCEDDDCD
+ at HWI-ST1106:815:H154GADXX:1:1101:1696:2195 1:N:0:CCTTAA
+AGCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGGAGGAAGAAGGTTTTCGGAGTTTAAACTCCTGTCGTTAGGGACGATAATGACGGTACCTAACAAGAAAGCACCGGCTAACTA
++
+B@@DFDEFGHGHHIJEHIIIJCGIIIJIJJJIJIJJJJJJFH>D?@DDEEE>ACDDDBD;B<BDBDDD;BDDDABBC3?3>@?C-9?-<((+>CC::44 at A4229A<<?AB>BBDDD:>CBDBA at CCDCBCD<<CC3>A?<@9@<?CDDA
+ at HWI-ST1106:815:H154GADXX:1:1101:1646:2204 1:N:0:CATCTA
+CAACTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAGTCGGGTATGCATACCCGTTTGCATGTACTT
++
+=:+A?DD;F?6<8)8CGEFEFF@?GGAF at BFIIDFBDFCFFC@B<FFE;=DEFEE>D>?DC>A=AA;A>?@?<A>?BBAAAABBB:@A@:<BB<@@A>A4>:::ABBBDEDBA<BBBAB>BAB<@@>@ABDEBABB55?B?BBABBDDBD
+ at HWI-ST1106:815:H154GADXX:1:1101:1502:2205 1:N:0:TTAGGC
+ATGATTTGCGCTCCCATATCTATCAGCTTGTCCACAAAGAACAAACGGCTTTCGAACATTTTCTGATGAATGAGTACACTGCCTTTTGCCTGGGTGGCAACCACCAGCAGCACACTGAGCAAGTCTGGTGTCAGTCCGGGCCAGGGTGCG
++
+1=+44,=DDDDDDDE3ACFF at EICFI>EEEE>DDADIIACD at DDDDDDA:@7@;@=CDCDDEDAD at AD;@AA>A;AAAAAA>;>AA>AA>A>9<,09?<><<<<<>??<<<<8<<>AA>:A<<::>A>:9244>AAA>9?;>>28><<<;
+ at HWI-ST1106:815:H154GADXX:1:1101:1742:2207 1:N:0:CATCTA
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGTGAGCCACGTGTGGCTTTTTGTATGTACCGTATG
++
+@@@AD?DDHHFFHIIIIIIIIEGCGGFCCHGBGD?DHGIGHIIAHAHIIIIICGHHHHHEEEECCACBBCCBCCCCCC?C at ACCCCB9?B>CDDCCCCCCCCACDCBBBBBBC>CADCCCCCACB?BCBBBBBCCCBA:AD:>>C>@BAC
+ at HWI-ST1106:815:H154GADXX:1:1101:1683:2207 1:N:0:CCTTAA
+AGCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAATGACGGTACATAACAAGAAAGAACCGGCTCACAA
++
+@@?DDDDDFGHFFJJGAFAEFHIJDIIIIGI?4BFGHGGI?HADE)6?AAA6;@CCABDD;@BDDD;B>B?B?BB<CC@(+4?AB<+2<CCDCCDC+:>>@32(0<@CBABBD<?B:A################################
+ at HWI-ST1106:815:H154GADXX:1:1101:1541:2208 1:N:0:ATCACG
+AATTCTAGAAATCACTCGCTGGTTTCGCCTAAAAATAGTAACTTTGCACCCAACAAAAAGAAACCAAAGACATTATGAACATTAAGAATATCCATTTGGCCTATTTTAGTGCCACTTTCTCCACCAAACGTATCGTTCGTGAGATAGCAT
++
++=;DDD8DBHHBFICBHIIGIEFHIIFHEDFF at GIIDC9BCGHG<FHIBGIIIIGIIIIIII>E>C2?);.>A6;AAA>CCCCCCCCCCCDDECCDE(:ACCCCC4>:3:@CA@@>CCACCCCCBBBBB<@2>?<9<B9<BCB(:A>@AD
+ at HWI-ST1106:815:H154GADXX:1:1101:1564:2216 1:N:0:CAGATC
+AAAACGCCAAAGATAGTATTGACAGAACGCTAGCAAACGAAGCAGGTGTATCTTTAGAAGTATTGACTCCTTTGGAAGGATTGACGAATGAACAAATAGAAAATGGAGAAAACTATCTTTCTATCATGGAAGCAAACCTCGAAGCGAGAT
++
+11=DD?DDDDDDDEEEEEDA2+<F21:1:)1CDBD4?B?DDD6BCC(=8=@8ADEII)====7A?C);?@@AA>@;@55;>-;A:3<'5:AAAA38::>>>4++44>83<><>4(:AA>::A::::::>:>3<3>><?A?##########
+ at HWI-ST1106:815:H154GADXX:1:1101:1719:2228 1:N:0:CTACGG
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGTGAGGCACGTGTGCCTTTTTGTATGTAACGTATG
++
+ at CCFFFFFHHDHHGBB;AFHH at GGHGBCGHIFFGHIIIHA?FBAFFDFHIICHIGFHGHDBD at CACDDDCDDACCC;ACDD:?:ACDAB at D@DE>:@>>CDCC@>:<@D<B?4 at C@@C>+<???08<A<:>>ACDDB844>C:(42<8:?
+ at HWI-ST1106:815:H154GADXX:1:1101:1844:2204 1:N:0:CACTTG
+GACTACGGGAGGCAGCAGTGGGGAATCTTCCGCAATGGGCGAAAGCCTGACGGAGCAACGCCGCGTGAGTGAAGAAGGTCTTCGGATTGTAAAGCTCTGTTGTACATGACGAATGTGCCGGTTGTGAATAATGGCTGGCAATGACGGTAG
++
+B?@FFFFFHHHGHJIFIGHIJJIJJJIJJJJJJIJIIJJJJJJGHEFFEFFDCBB at BCDDBDDCDDDDDCCDDDDDDBDDDDDDDDDDDDEEECCCDDDCD@CCDEDCDDDDDDC>AAC5>9<<<B at CCDDDACAC@>?9CCCA:8<<A9
+ at HWI-ST1106:815:H154GADXX:1:1101:1890:2219 1:N:0:GCCAAT
+GACTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTAGTTCGCTATGTAAAGCTCTATCAGCAGGGAAGATAGTGACGGTACCTGACTAAGAAGCTCCGGCTAAATAC
++
+ at CCFFFFFHHHHHIIJJJJIJJJIIJJJJJHJJJJJJJJJIJIJJJIJJJJIJJJIHHFDDDBDDDDDDDCDEDDDDDDDDDEDDDDBDEEEEDDDDDDCDCDDCDDDDDDDDDDCDEDDDDDDDCDDCDDDDDDCCDDDBBBBDDDCED
+ at HWI-ST1106:815:H154GADXX:1:1101:1802:2224 1:N:0:CGTCAA
+GACTACGGGAGGCAGCAGTGGGGAATATTGGGCAATGGGGGAAACCCTGACCCAGCAACGCCGCGTGAAGGAAGAAGGCTTTCGGGTTGTAAACTTCTTTTACCAGGGACGAAGGGCGTGACGGTACCTGGAGAAAAAGCCACGGCTAAC
++
+<@?DDBDDHA:FFGB at EA<EHIIIIICFHGH@@GIIGIIIIIIIFHHFD;?D at AA;@;=>3?;780)2?C>8?8(>?BB at CCC8@BB<>5CDEC at CC>C3@@:+:(<@8<0&5<>&25@@BBBBBBBCCCB@@CBACBBBBCCBBBBBC>
+ at HWI-ST1106:815:H154GADXX:1:1101:1840:2224 1:N:0:GTCGCT
+GGTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGATGGCCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAGTCGGGTATGCATACCCGTTTGCATGTACTTTA
++
+=+:BDF?BFFHFFIIIIIGICFFHIIIIIIIIGHIGCHIIIIIIIIGIGIHHIIGHHHFFFFACECDDDDBDDDDDDDDDDDBCCCCCDDDDDDDDDDDDD at CDDDADDCDDDDDDCDDDDD<<@CDCDCD at CDBBDCBDEDCDEADDEC
+ at HWI-ST1106:815:H154GADXX:1:1101:1923:2228 1:N:0:AAGCGA
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAAATGACGGTACCTGACTAAGAAGCACCGGCTAA
++
+CC at FFFFFHHHGHJJJJJJICGHIJIGJJJJJJJJJJJJJJJJIJJHHHHFFFFFFEEDDDDDDDDDDDDDDDDDDDDDCCEDEDDD@BBDCDEDCCDDDDDDDECCDDD?@B?CA>CDCDCDDD>BBDCDCCCCCCCDDCDCDDDBD at D
+ at HWI-ST1106:815:H154GADXX:1:1101:1769:2229 1:N:0:TTAGGC
+AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGTCCTACGGATTGTAAACTTCTTTTATAAGGGAATAAACCCTCCCACGTGTGGGAGCTTGTATGTACCTTAT
++
+@@@DDFFFFHDFHIGHIEHFHGIJJJJJJIJJFHIJJJEGIJJJJJHGIIJJJJJHHHGFFFCDEDDDDDCDB at CCDDD:@ACCCBDD5<?:@DEDCDDCDCACDEEDDDBBDDDDDDDDDDDDDDDDDDDDBDBACDADEEDDEDCDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:1997:2231 1:N:0:TAGAAG
+GACTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAAGTCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTAGTTCGGTATGTAAAGCTCTATCAGCAGGGAAGATAGTGACGGTACCTGACTAAGAAGCACCGGCTAAATAC
++
+?@@FFFFFGHHHHJJJIIIJJIIJJIJJJJJJJJJJJJ*(7CHI2.=FGHIJJJJJHHFDDDDDDDDDD9;@DDDDDCD3>CDD3?BDDEEEEDDDDDDDDCDDDDDDBDDBDD>CDEDDD at BBCDDDDDCCDDDDD(9A at B>BDDDDED
+ at HWI-ST1106:815:H154GADXX:1:1101:1965:2235 1:N:0:CCACTC
+GTCATTTAGAGGAAGTAAAAGTCGTAACAAGGTTTCCGTAGGTGAACCTGCGGAAGGATCATTACCGGGTGCGGGCCCTCTGGGTCCAACCTCCCATCCGTGTCTATCTGTACCCTGTTGCTTCGGCGTGGCCACGGCCCGCCGAAGACT
++
+?=BDFFFFHHHHHJJFGIIJHGIJJJJHJIJIIGHHHHJJHEHHIJGIJJJJGJJJDHIHHHHHEFBBADBB=?BDDDDDDCDCCDDDDDDDDDDDCDBD88ABDEECCCCDDDDCDDDDDDDD<<BBBBDBA?BBDDDD>BB>BBBBC@
+ at HWI-ST1106:815:H154GADXX:1:1101:1871:2243 1:N:0:GTCGCT
+AGCTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGTGAGGCACGTGTGCCTTTTTGTATGTACCGT
++
+?@BDADDDHHHHHJJJJJJJJEGIIIHIIIIIIGHIGHIJIJJJJJGH=FHIIJJEEHHFFFFFEEECBDDDDDDDDDDDDDDDCDDDCB??B9CDED at ACCDDCDDEDDDD>BBCCDD at CDCDDDD@ABCBACCDDDDD<CDECDDDB<
+ at HWI-ST1106:815:H154GADXX:1:1101:2118:2199 1:N:0:CAGCAC
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGATAATGACGGTACCTGACTAAGAAGCCCCGGCTAACT
++
+1=?DD?DFFFHFHIIIGBFDCGGHGHICHIEH>DGG;/9BGIIAGGA>E>;?@CEDCCC8?@B at 7>BBBBBCBBBBCCC:ACDDAC5<A8 at DCCD>44>44:@C>>AB?B8?8(>CC::>C?############################
+ at HWI-ST1106:815:H154GADXX:1:1101:2145:2206 1:N:0:CTATGG
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAATGACGGTACCTGACTAAGAAGCACCGGCTAAA
++
++:?DDFFDHHDFHIIIEHGDCGHIIIIIIIIIIIIIIGIIGIIIHIHHHHFFFFFFEECBB at BB@B;;BBBCCCCBCAC at CADDDCC2<?CCDEECCCCCCCCCDCCBBCBBBCCC>CCCCCBBCBBCCCCCCCCCCCCCCCB at BBCBCC
+ at HWI-ST1106:815:H154GADXX:1:1101:2188:2208 1:N:0:TGACCA
+GACTACGGGAGGCAGCAGTGGGGAATATTGGGCAATGGGCGCAAGCCTGACCCAGCAACGCCGCGTGAAGGAAGAAGGCTTTCGGGTTGTAAACTTCTTTTGTCGGGGACGAGTAGAAGACGGTACCTGGCGAATAAGCCACGGCTAACT
++
+8=?DDFFFHGHHHIIIIIIIIIIIIIIIIGIIIIIIIIIIIIIIIHHHGFFFFFDEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDBDDDDEEDCDDDDDD at ADBBDDBDDDBBBCCDDDDDD@DDDDDDDDBDDDDDDDDDDDDDDDCD
+ at HWI-ST1106:815:H154GADXX:1:1101:2116:2218 1:N:0:GAACCT
+GAACTCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGGAACCCTGATGCAGCGACGCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAATGACGGTACCTAACAAGAAAGCACCGGCTAA
++
++:=DDDDDDDDDDEE@=EE?DE:CDDAADDABB at CEICC@CIIID85:??<???AA>>A:57<;8>?>???>???>??>AA?AAA?A??>>?<>AABA>:>>::>><9??><><?3<<8::AA?>5<9:AAA<AA???>4>9<?;>?###
+ at HWI-ST1106:815:H154GADXX:1:1101:2046:2228 1:N:0:TTAGGC
+GGATATGAAAACATCGCTCCCGGTGATGCCATTTTCTTCGATTGGGATCTGGATGGTTCCGCAGACCATGTGGGAATTGTTGTCGGCACCGATGGCAGCCGTGTTTATACCGTGGAGGGAAATTCCGGCGATGCCTGCAAGATCAAAAGT
++
++=@DFFFFHHFHHJJJJJIGIEGCFHIGIJGIJIJHIJJJGGGIJJIHHIJJHJIJFIIGHIHHFFDCCCCEEDBCDDDCCBCABB>BBDDBB<BCCB?BBD>8ACDDDCDD?BD?BDD5ABDD>CCDDD9BB?CCCBCDCACCACDDC3
+ at HWI-ST1106:815:H154GADXX:1:1101:2092:2229 1:N:0:AGTCAA
+AGCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGCCAAGTAGCGTGCAGGATGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTGAGTCTCGTGAGACTTTTTGCATGTACCTTAT
++
+CCCFFFFFHHGHHIJIJJJJJJJJIIJGIIJIHIIIJIJJFIIJJJIIIIHHHHFFFFFEDEDEEDDDDDDBDD at CCBDDDBDDCDDDA?BDDEECCDDDDACDDEDDDDBDDDDDDEDDDDDDDDDDDDDCDDDDDDDED@@CDDDCDA
+ at HWI-ST1106:815:H154GADXX:1:1101:2195:2237 1:N:0:GTCGCT
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTAATTCGTTATGTAAATCTCTATCAGCGGGGAAGATAGTGACGGTACCTGATTAAGAAGCTCCGGCTAAA
++
+1:=DDEFABHCFADFDGFGHI?GHIHGIIIGHGIIII>DHIGGCFGGIIHIE at DECEHHE<B>;BDBDBBDDAC at CCACCDCDECA@C>8A3(4:4(++::>((4+(&09&00((++(+++:?@&8>::43AADC at CC>A:CCD<39 at C@
+ at HWI-ST1106:815:H154GADXX:1:1101:2147:2238 1:N:0:CTACGG
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGCGAAAGCCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGATAATGACGGTACCTGACTAAGAAGCACCGGCTAAATA
++
+ at B?DDEFFDHFHFJJGEGGGIIGHJIJJJIHJIJJJJJGGEHIIFHHHHHHFFFFFFDCDDDD<@DB>BBDDDDDDDDCCDEDDDDDDDDCDADDDCDDDAACCCDDDDDBDDDDDD at CDBBBB>CCDDDDCDDDC>CCCB>@BDBDDDE
+ at HWI-ST1106:815:H154GADXX:1:1101:2498:2195 1:N:0:CTACGG
+ATCTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGCTAGCCTGAACCAGCCAAGTAGCGTGAAGGATGAAGGCTCTATGGGTCGTAAACTTCTTTTATATAAGAATAAAGTGCAGTATGTATACTGTTTTGTATGTATTAT
++
+@@@FFFFFHFHHHJGGIEHIH at FFHIJJJIGIHGI@HIGGEHGBGIGIIIJHIFHHH?DFFEDEEEEDDDDDDDDDCCDCDBDDDDD>CBCC9>BBBCDCCCCDDDDDEEDACD=C>CC>>CC>CCCDDEEDEEEDCDDDBDEACCDCAB
+ at HWI-ST1106:815:H154GADXX:1:1101:2263:2198 1:N:0:ACTTGA
+GATCCTGAAGCAGAATTATCTGGTGTTTACCGGTATATCGGGGCTGGCGGTACAGTAAAACGTCCGACTCAAGAAGGACCAGCTATTACTTTCAACAATATCAAAGGATTCCCCTGCACACGGGTGAACATCGGAACAATGGCTAATCGT
++
+111=D?DDDDFB;AEFEECE<3AEG+A9E?<?)1?8D<DGI).-7A;54/='';A.;6;5('(((,''504>:4?3<?@B1(8444(+:>@A((:4@<:>:::@A(3(4::(:<(229(489&5 at 3?:>A@###################
+ at HWI-ST1106:815:H154GADXX:1:1101:2307:2201 1:N:0:TGGATT
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGCGAAAGCCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGATAATGACGGTACCTGACTAAGAAGCACCGGCTAAA
++
+??@DDFDFDH@:FHGG at GIIH@EHII<D?D at DEDGCGGEIIEGGIBB<CCEFCFEDECAABBBB@@;@8 at BBCC9<<BCC:@C:BCCB8<@C>@:BCC at CCACCCACCBAB?B at A:>@CCCCBCBAB at ACCACCCCCCA>CC?BBB<?@@
+ at HWI-ST1106:815:H154GADXX:1:1101:2283:2204 1:N:0:CTACGG
+CGCTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGCGAGCCTGAACCAGCCAAGTAGCGTGAAGGATGACGGCCCTATGGGTTGTAAACTTCTTTTATATGGGAATAAAGTTTGGTATGCATACCATTTTGTATGTACCAT
++
++11ADDDDHHHDHIAAG=EFGG at FHCHHBBDDH@B*BBFHBBFHG8 at EEDEDCCCACAB@BCB at CCCBB=@BCCBCC4>B>BBBBCCCCBCBB9CD>>C:@@CCCC>3>CCAC?<CCCAD>C3<+(:>>CD>CCACCEC at 8:@A>:@@>4
+ at HWI-ST1106:815:H154GADXX:1:1101:2453:2206 1:N:0:ATACAC
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGCAGGAAGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTTAGTCTCGTGAGACTTTTTGCATGTACCTTATG
++
+CCCFFFFDFAHHG at GGIIFFAFIIDEHDHC?GGHIIIIIGIEGEIHIGIIIIIIIGF>CDCEFFACC;AC=(9ABD at BDBDDDDCCD9?BDCDDC@>CC@@>CDDE@@BDDDDCCC at C@ACCCCDBDDDDDCDCCCBDECCDEECDCDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2336:2209 1:N:0:GTCGCT
+GATCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGATGGCCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATATTAGAATAAAGTGCAGTATGTATACTGTTTTGTATGTATAATA
++
+;:?DDDDDFHHHFIIGIG at G?FFHIGIIIGIIIEGGIGIIIIEGGHGGIIIIHGHEEHEEED at A;@>BBBBCC at CCCCCCCCBACC>CB9?B0:ADA>CC@@CCCCDDDEECCC>CCCCCCCCCCED at DDDDECBCCCB<CCC>BBCDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2378:2210 1:N:0:CTACGG
+CAACTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGCAGGCCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAGTCGGGTATGTATACCCGTTTGCATGTACTT
++
+ at C+BDDFDHFHHHIJJJJJJGGFHHJJJJJIIJJJIJJIIIIIEHEIJIGIHHHHEFFFFCEEDDDDCDDDDD:ABDD at CCDDDDD@CDDDCBDDDEDACDDCDDDDDE3 at ACBCDCCDCDDBDD2<CC>>CCBCCD0?A@>AAC>CDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2470:2220 1:N:0:ATCACG
+TCTAACTGGGGCCGTAAGCGTTCGCTGATCTTTGCGGGTGTGATGTTCTTCATCTCTGCATGGGGATCTATGTGTCCTGAGTCTTTGGTGTTGCCAAAGGGCGAACCTAATCTTACGCTTCTCATCGTGTTCAACCTCTATCGTGTGATT
++
+@@BFFFFFFHHFHJJJJJJGHGIIIIHEGIJIJIIGHIBHHHFFFFFDEFDEEEEEEDDDDCBDB?@BCDEEEFEDDDCDDCDADDCDBBDBDDDDDDDCDB at BDDDCCDDDDDDDDBDDDDDEEDDBDBBCDEDDDDCCDCD<AABDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2434:2220 1:N:0:CGATGT
+GTAGAAGGTACTTATTTGTATAGTAAGAAAGATAATAATAGTTCACCTTTTATAATACGAATTCATGCATATGCTGGAAAATCATATATTCGAGTGCTTCATACAATAACTTATACTGGTATTCCTGACAAGCATAAAATAGAAAAGGGA
++
++=?DDBDD2=<2CGEEBDCE:ACEHFIHIF?+CEFD?C:CEECD?D<?<<<<DG at F<?D7D?BDC=FGIGIB=CF:@;CEEED>;A;CEE>7;?)((.;>;>@@@(5>AAABB>A@@@3:@>@BAB at A?AA2?8 at B@BBDB>:+:??<@?
+ at HWI-ST1106:815:H154GADXX:1:1101:2285:2223 1:N:0:CGAATA
+GATCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGTTAGCCACGTGTGGCTTTTTGTATGTACCGTA
++
++1=DDDDDHHHHHIIIIIIIEHIIIIIIIIIIIIIDFHHIIIIIIIIIIIIIIIIHHHHEEEEEECCCBBBCCBCCCCCCCCBCCCCCBCBBBCEECCCCCCCCCCECBBBBBBCCCCDCECCCCCBBBCBBBBBCCCB<CDDDDDCB at B
+ at HWI-ST1106:815:H154GADXX:1:1101:2390:2234 1:N:0:ATACAC
+CAACTCCTCGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCAACGCCGCGTGAGTGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGAAAGAAAATGACGGTACCTGACTAAGAAGCCCCGGCTAAC
++
+=??=DBEFHH at HDHGIGGF@F9EFA at FHEHIEHIIIGFHIIIIGIIHHGHFFFEDEACA>CB>?BBBB@;?B>>CD@>A?::BAD>C528?C>CD34>A:@>:>:4 at AABBBC?9?CCCCC:8>@BB:>>CCCCCCCCCA8<>BBB>?@C
+ at HWI-ST1106:815:H154GADXX:1:1101:2331:2236 1:N:0:CAGCAC
+AGCTCCTACGGGAGGCAGCAGTCGGGAATATTGCGCAATGGAGGAAACTCTGACGCAGTGACGCCGCGTGCAGGAAGAAGGCTTTCGGATTGTAAACTGCTTTAGACAGGGAAGAAACAAGACAGTACCTGTAGAATAAGCTCCGGCTAA
++
+8??DFBEDGHFAHGG?FHGIIFFHGGIGGHGEHGD<FBHIIAEGHGHH9EECF at 8>CD;;@;?@BDDDDDDDDDDBBBCDB1(9?A?B?BBCCDDDD::>C>CCCDCCCB??B at BDD?C at CCCDCDE@@C(+:@@CCCCCC at 3>9995<@
+ at HWI-ST1106:815:H154GADXX:1:1101:2413:2237 1:N:0:CAGATC
+GTTAGAAGAAATAGCGGATCAATCGAGTGACACTCTTTCAGGCGGTCAACTCCAACGTGCGTATATTGCAATGGTGCTAGCGCAAGACACGGATTATATTTTACTGGATGAACCTTTGAACAATCTAGATATGAATTTTGCGGTTCAAAT
++
+?8?;BDDDAD8+?<C18CFFAADFF>):?DF>:<DDFFEIII9F at 5-;=?EE at EEB5;?BC=,(;B;(5>::>(,5>@B#######################################################################
+ at HWI-ST1106:815:H154GADXX:1:1101:2368:2242 1:N:0:TCCTCA
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAAATGACGGTACCTGACTAAGAAGCACCGGCTAAA
++
+?B at FDFFFGHHGHIIJJJGHHIIJJIJJJJJJJJJJJJIJJJDIIJHHHGFCEFFEEDBDDDDDDDBBDDDDDBBDDC@CCCDDCD?ABDEEEEDDDDDDDCDECDDDDBDDDDDDDDDDDDDDBBBDDDDDDDDDDDDDDCDDDDDDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2491:2246 1:N:0:CCTTAA
+AGCCTACGGGAGGCAGCAGTTAGGAATATTCGTCAATGGGGGAAACCCTGAACGAGCAATGCCGCGTGAAGGATGACGGTCCTTTGGATTGTAAACTTCTGTTGGTAGGGAAGAACAAACTGTATAGGAAATGATACAGTTCTGACGGTA
++
++:=DFDFFHH>AHGHI=GHHGFHIIIIIIIIIHIIIIIIIIIFIIIIIIH at HHDEFCCCCCCCBBBBB?B>C8ACCCBBBBBCCCCCCCCC at DDDCCCCCCECC+8ACCCCCBBCCCCBBCC:BDCCC<CCCCCCECCC:ACDCDCCB<?
+ at HWI-ST1106:815:H154GADXX:1:1101:2525:2193 1:N:0:CAGATC
+TCTAGAAAGCGCGTCTGTTTCATGTGCTTTCTATTATTTATCTTATGCCAATCCATTTCTTTGCTTTCCACAATTATATTGTGTAAAATTCAATTGTATAAAATATAATTAAAGGTGGTAATTTTATGAAAAAAATGTATTCTACGAAAA
++
+11+=BDDDFFFFFGIIIIIFIIFGIIFIEFIF*?GFGCFFEFIIFFFEEFFECFGIEIGIIIFIFFEEEEEEFECDEDEDD at A>BDECEBBBEDDB at DEED@BABEEEBD>ABAB:>?BABABDBBBBABBA?BBBB4@@BB>A:<BB@@
+ at HWI-ST1106:815:H154GADXX:1:1101:2680:2193 1:N:0:GAACCT
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGCCAAGTAGCGTGCAGGAAGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTTAGTCTCGTGAGACTTTTTGCATGTACCTTATG
++
+CCCFFFFFHGHHHJJIIIHIIIIJJJJJJJJFGIJJJJJJJJJJJJJJJJJHHHHFFFFDEEEEDDDDDDDDBDDDDDDDDDDDDDDABDDDEEDD at CDDDCDDEEDDDADDDDDDECDDACDCDBBDBDDDDDDDDDEEDDCDDDDDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2516:2210 1:N:0:TAGCTT
+GACTACGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATATGGGAATAAAGTTTTCCACGTGTGGAATTTTGTATGTACCATATGA
++
+;;@DDDD?DFHBFII;FHACBCFCGEGIHGCG at DFGGEHDGHABBCFG>FHGG at EDEEHFH@BBCC??;>BCCCC>>C?B:CCC>A9?<@CAD>C at CCC>A at CDC:@A?CBCCCC@@CC:>:>?BBCBBCCCCCCC(::>@DD>>4>4>C
+ at HWI-ST1106:815:H154GADXX:1:1101:2713:2212 1:N:0:TGACCA
+ACCGGCGTTATTAGTGGAACACAAACTATATGTGCAGGAAGTAGTACTACATTAAGTATCGCTGTAACCGGAACAGGTCCATGGAGCGGAACATTATCAAACGGTGATCCATTCAGTGGCAGCAGCAGCCCAATCAGTGTGTCAGTCAAT
++
+@@@FFFDFHHGHFIGIIHIJJHIIGJIJIIJJFIJJJJIJIIIJIJJJJJIJJIJJDHIIJHHHFFFDECCDDDDDBDDDDEDDDDDDDDDD at CDDEDEDDCBD<ABCDDDDEEDDDDDBDBDDABA?BDD?BCCDC at C:ABACCCACCD
+ at HWI-ST1106:815:H154GADXX:1:1101:2678:2222 1:N:0:CGCTGA
+CAACTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGCCAAGTAGCGTGCAGGATGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTGAGTCTCGTGAGATTTTTTGCATGTACCT
++
+B=@DDFFFHGFHHIGAFGEGHIGIIGIIJIIJJJIBHGIIIFJIJIJJIIJEEFH=BBFDDECDCDCDDDDDDDDBCDDCBDDB<BCDDDD?BBBDDEC at ACCDDDDDD@CDD<ABDCDDBCACACDCDBBDDCDDDDDDBDEECCEDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2588:2225 1:N:0:CCTTCT
+CAACTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGATGGCCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAGTCGGGTATGCATACCCGTTTGCATGTACTT
++
+BB at FFFFFHHHHHJJJJIGIJJJJJIJJJJJJJJJHIIJIIIIJJJJJJJJJIIHHHHFFFFEDECEDDDDDDCDDDDDDDDCDDDDDDDDDBDBCEEDDDDDDDDDDDEECDDDDDDDADA@DD?BDDDEEDDDDD<ACBDDCDDEDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2713:2231 1:N:0:TGACCA
+ACCGGCGTTATTAGTGGAACACAAACTATATGTGCAGGAAGTAGTACTACATTAAGTATCGCTGTAACCGGAACAGGTCCATGGAGCGGAACATTATCAAACGGTGATCCATTCAGTGGCAGCAGCAGCCCAATCAGTGTGTCAGTCAAT
++
+?@@FFFFFHHGHGJHGIJIIJJJJJJJJIJIJGEHGIJJJJHIIIJJJIJJJJIIJHIJIJHHEFFDEEDDDDDDCDDDDDEDDDDDDDDDDBDDCEDECD><@2?BCCDDDEDDCCDDDDDDDDD at BBDDADCCC>4 at 4>ACCCDACDC
+ at HWI-ST1106:815:H154GADXX:1:1101:2557:2232 1:N:0:CAAGAA
+AAACTCCTTCGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGCCAAGGAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAGTCGGGCATGGATACCCGTTTGCATGTACTT
++
+++:BDD>4=ADDDD at EEBE7C11:EDBED**?B?*B90??DDDCDDA<A9=;>CCC at D?;=A@@(;>=6,8?=:>>>A:A3:9+243>4:<3(&04(:3AAAA>:>A:(>A>A?AA##################################
+ at HWI-ST1106:815:H154GADXX:1:1101:2740:2237 1:N:0:AGTTCC
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAGAAATGACGGTACCTGACTAAGAAGCACCGGCTAA
++
++:?DDDDDDD@@DEEIE>FE:?BEDDD;?BDDAEEIDBDDII>@AD9?CD>@DDD;AA@>???65;;5>>?A???>?AA(:>BD3<-+8>>B:>BAAAA34>:>>>>28>8<88>A9>?AAAA??9>>AAAAAAAAAAAAA<??>>?>>A
+ at HWI-ST1106:815:H154GADXX:1:1101:2527:2244 1:N:0:GTTGAA
+CAACTCCTACGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGTGAGGCACGCGTGCCTTTTTGTATGTACCGT
++
+ at CCFFFFFHHGHHJIIGBHIJIJJJIIHIJJICEHIGHJJJJIIIIJJJJIIJGIJGHHHHFFFFFEDDDBDCCDCDDDDCDDDDDCCCDDBBDDDDDDACACDCDDEDA@BDDBDDDDCCDC@???DD>BDDDDCDDD@<CDDDDACDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2603:2248 1:N:0:CAGCAC
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCAACGCCGCGTGAAGGATGACGGTTTTCGGATTGTAAACTTCTTTTCTTAGTGACGAAGACAGTGACGGTAGCTAAGGAATAAGCATCGGCTAA
++
+?B+4=BDFHGHDDHIIJJJICFGGJJJIIIIJIGIIJJIFHGIIHIGHHCD>@DDEEDEABDDDDDDDDDDCBDDDDB at 5<>?CDDBDDDDEEED:ADCDDAC at CCD@ADDDDDDDDCCCCDD at D@B9AC>@CC>CDCDDDDAC>B at BBC
+ at HWI-ST1106:815:H154GADXX:1:1101:2853:2195 1:N:0:ACTTGA
+AATCGACAACAGGAACTGAAAAATGTTCTGAGAATTCTTTGATTTGCGGAAATCCGTTTCGCGTTCCTTGACCAACATAAAGAACTGGTTTTTTTGCTTTTTCAAGATAAGGCAAAGCAGCTAGCAAATCTTTTTCTTCTGGTAATATCA
++
+1:1BDDDDFH<BFHGIIIIIIEHHIIIGIIGHG at DHIIIIH>DHF?BGHGGIAHIIIIIIHBEECCCAC@;>ACB?BCCCCCA<?CCC>CBBBBBBC>CCCCCACCCCCCCCC?<A993?BC at AC>CCCCCCCCCCCC at CAC3:>C@@:@
+ at HWI-ST1106:815:H154GADXX:1:1101:2884:2198 1:N:0:TGGATT
+CAACTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGCAGGAAGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTGAGTCTCGTGAGACTTTTTGCATGTACCT
++
+@@@DDDDDFFHHHIIDD;FH?ECEEHGHIIGEBGEIIIIIIIIIIIIGHHIIGHIFEHHFEDEECCCCCBB6ACBB?ABCBBB>@B<CCCBA?@BCDDCCC3:>ACACDCCCA8AB at CACECCCCCCCABBCBC@@CC>ABC>AA@@D>>
+ at HWI-ST1106:815:H154GADXX:1:1101:2751:2204 1:N:0:AAGCTT
+TTTGTCATTTAGAGGAAGTAAAAGTCGTAACAAGGTTTCCGTAGGTGAACCTGCGGAAGGATCATTACCGAGTGAGGGCCCTTTGGGTCCAACCTCCCACCCGTGTTTATTTTACCTTGTTGCTTCGGCGGGCCCGCCTTTACTGGCCGC
++
+B?=DDDFFHHHHHJJJJJJJJJJJJJJJJJJJJJJIJJJJJJJJJJJJIIJJJJJJJJIJGHHHHHFEFFDDDDDDDBDDDDDDDDDBDDDDDDDDDDDDDB@<@<BDDDDEEEDDDDACCACDDD9BDDDD>BD59>09A(44+:1?50
+ at HWI-ST1106:815:H154GADXX:1:1101:2785:2207 1:N:0:AAGAAG
+AGCTCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGGGGGAAGAAGGATTTCGGAATGTAAAGTCCTGTCGGCAGGGAAGAAGATAACGGTGCATCAGAAGAAGGAACAGGCGCAA
++
+BCCDDFFDHHFFFIIIGHGIH at GGEI@GHIJJJGIJJIJIJIJHDEFFEDECCDDCDCCDDDDDDBDD at B7&&059BDDDD8ACCCDD+(2@>CDE>((4@(4 at 0&&5<BD72?####################################
+ at HWI-ST1106:815:H154GADXX:1:1101:2938:2209 1:N:0:CAGATC
+TATCACTTCGGAAAGTCCCTAACTGGCTACCGTCAAGATACTCCTGTTTTGCAAAACGATTACCGGAGATAACTACTGTTCCTGCTCCCACAAGTTTAAAATTGGATAATCTGCTTTCTATATATTCATCATATCTTCCTTCTTTTACTA
++
+=@1BBDDFGAHDHII:EG at DHGHEFHA?EFFAH:DGFHGIGCGIHIGGI;DGGHIGIGEGIHCEEB>CCCCCCCCACCDCC at CCCCCCCCB?ABCCEECCCDCAACACCC@:@:4 at C@CCDCCDEDC:A>:CACCDC>>A at CCCCCCCC3
+ at HWI-ST1106:815:H154GADXX:1:1101:2969:2210 1:N:0:CGTCAA
+AGCCTACGGGAGGCAGCAGGGAGGAATATTGGTCAATGGGCGCAGGCCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGGTGTAAACTTCTTTTATAAAGGAATAAAGTCGGGTATGTATACCCGTTTGCATGTACTTTAT
++
+;?@DDD>DHA?FDGEHIGG)?:CGIGIIICGIGEHD at FHICGGGGBHH>CDCEDC;;;??;5;A at B;?BBCCBCCCCCCCC?CCCCC8(5<BCDACCCCCC@@@CA>CAC?CCCCAC>CBBB at BCCCDEE>CA99?CBCCDC>4:@BDC@
+ at HWI-ST1106:815:H154GADXX:1:1101:2909:2214 1:N:0:CCGTCC
+ATTGCCTTTACCGATGGCATAATCTCAAAATATTCCACACCTACTATTACAACCGTAAGTCAGAGTGGAATAAAAATGGGAAATAAAGCGGCAAAAATGCTAATAGAAAGACTCGAATCTGAGGAAAATGAAGAAGATGAAAACTATAAA
++
+@<@FFFFFHFHHHIJJIJIIGJJJIJJJJJIIIJIJJFJJJJJIJIIG>GHJIJJGIGICGGIIGCHHHHGFFFFFFEEECCDDDADDDBBDDDDDBDDDDCDDDDDDDDDDDDDDDDDDEDDDDDDDDDDDDDDDDCD at CDDDDDDDDE
+ at HWI-ST1106:815:H154GADXX:1:1101:2888:2222 1:N:0:GTCGCT
+GACTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGCGAAAGCCTGATGCAGCAACGCCGCGTGAGTGAAGAAGTATCTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAATGACGGTACCTGACTAAGAAGCCCCGGCTAACTAC
++
+@@@DDBD>AF1?;F=132<?FF at GFCFEDDF?9?DGD?@F6AAB8AAEFFC;;?B;BCBCB at B=@;>?BB>BDBAAB4@>::@BBBBBB:@BBAAABBBBBA@@BBB>B?2(3??>>:A<@085A4:?AAABA at BBA@B><@BBBB?BB>
+ at HWI-ST1106:815:H154GADXX:1:1101:2873:2233 1:N:0:ACTTGA
+CTAGAACAAGCAATAACAACTGTAAAACAAACAGTTACAGAGCTAAATGAAAAACAAGAGAAGAACCAGTCAGTTATCAAAAGTTTGGACGATCAACTTTCAAAAGGAATACTAAAAGCTCCTGTATCTGGAACGGTTCATTTAAATGAA
++
+8:?=A=?D8F?<DFF:<:A3AFAFFEHEFB?FFACCF>>F4?BFGIIIIIEDGF<;CF at FFFI=;=CEIIEFF>?EB>DBDD>.;@BB(5;=?9?BBB5>:>A:ABB2>A>>ABBBB>?>@:AA:@@::@:@@B9<+2<A:B>BAABD@@
+ at HWI-ST1106:815:H154GADXX:1:1101:2990:2243 1:N:0:GTCGCT
+AGCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGAGGAAACTCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAATGACGGTACCTGACTAAGAAGCCCCGGCTAACTA
++
+CCCFFFFFHHGHHJJJJJIIIIJJJJJJJJJJIIJJJJJJJJJJJIJHHGHHHFFFFCCDDDDDCB at DDDDDCDDDDDCDEEDEDDBBDCDDCDDDDDDDDCDEDDDDDDDDDDDDDDDDDD<?@CDDDDDDDDDDCCDDDBDBDDDDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2791:2243 1:N:0:CAGATC
+ATCCAAAAATCCGCCACCCCATATCCAGTGGCAAACAGGGAAATAAATCAGCAGATTCCAAAAAATAACAAGTATAATATAGCCTTTTAAATTCAATCTCCCTGCAAAAGCTCCTGTCATCAAAGGAACGGTAATCACGATAAACATCAG
++
++=?DA??D:C:<C=BEEDEEEIDBCEEE9?DDADBDDD at B(9BDEEICC3=788A==ACEEC;A?@:A>@>@(65>BBA>DB<>AAAAAAAD>AADEAA>A>>A??AA?A?AAA>A>AA>AAAAA?>A>?>2<>AA>A<<8<>AAAAAAA
+ at HWI-ST1106:815:H154GADXX:1:1101:3046:2196 1:N:0:AGTTCC
+CAACTCCTCGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGCGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATATGGGAATAAAGTTATCCACGTGTGGATTTTTGTATGTACCAT
++
+CCCFFFFFHHHHHJJJJJJJJGIJJJJJJJJJJJJJJJJJJJJJJIJJHHHHFFFFFDDDEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCDDDDEEDDCDDDDDDDEEDDDDDDCDDDCCEECCCCDBDCDDCDDDDDDADDDEEEDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:3147:2203 1:N:0:GGCCTT
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGACAGTGACGGTACCTGACTAAGAAGCTCCGGCTAAAT
++
+@@@FFDDFHH8FDGBIGECHFGGGGIGIJIIGGIJIGGIGHGGFHECH at AGGDGIIIGHBEDDDDD@DDDDDCCDDDDD@@DECDDDDABA>@CCCCDCCCACDECCBDDDD?A?ACACCCDD at BBDDCDCDDD@CCAC at CCDBDBDDDC
+ at HWI-ST1106:815:H154GADXX:1:1101:3211:2211 1:N:0:AGTGGT
+GATCCTCGGGAGGCAGCAGTGAGGAATATTGGTCGATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGCAGGAAGACGGCCCTATGGGTTGTAAACTGCTTTTATAAGGGAATAAAGTGAGTCTCGTGAGACTTTTTGCATGCACCTTAT
++
+@@CFFFFFHFHHHJJJJJJJJJJJIJJIJJJJHHJIGIJJJJJIIIJJJJJGGHHFFFFEDEEEEBDDDDCDDDDDDBBDDDDCDDDDCBDDDEEDDDDDDCDDDEECDDBBDCDDD@>ACDDDDDDDDDDDCDDDDDDEEC:ACDDDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:3127:2215 1:N:0:ATCACG
+AGCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGAGGAAACTCTGATGCAGCGACGCCGCGTGAGTGAAGAAGTAATTCGTTATGTAAAGCTCTATCAGCAGGGAAGATAGTGACGGTACCTGACTAAGAAGCTCCGGCTAAATA
++
+1:?DBD8DFF@@FHA=7BF at GHIIGHCAHEEH@>GH9DHDEHHIIHIICGGDGID;==BBA?B8;>>BBB>CCD at CC?>ACDEC?3>??ACDECCA4>>CC>@DA>?@B8 at 78ACC:AACBB5@<>4:?9 at 4>:>C39:@>.559?CC:>
+ at HWI-ST1106:815:H154GADXX:1:1101:3233:2216 1:N:0:TTGGTA
+AGCCTACGGGAGGCAGCAGTAGGGAATCTTCCGCAATGGACGCAAGTCTGACGGAGCAACGCCGCGTGAGTGAAGAAGGTTTTCGGATCGTAAAACTCTGTTGTTAGAGAAGAACAAGTGCTAGAGTAACTGTTAGCGCCTTGACGGAAT
++
+@@@BDDD6?FADDI=BBHGFGGGG at BA?FBFEHII6:BDG at FGGGADG>?;CE6B8<?CA at BBBBB>BBBCCCCCCC929::<CB&(25 at CB?@C<:CCAC:C<BCCCCCC?9AC93(4@:4>AA:::A:A4+4>>@9.9>>CC>9@###
+ at HWI-ST1106:815:H154GADXX:1:1101:3185:2216 1:N:0:TTGGTA
+GATCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCAACGCCGCGTGAGTGAAGAAGTATTTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAATGACGGTACCTGACTAAGAAGCCCCGGCTAACT
++
+@@CFFFFFHHDFHGIGHIGGFGIIJJJIJJIIJIJJJGIJJJIJIIHHHGDFFDFDCEEECBDDBDBB at BD@CCDDDCD>CDEEEDD?BDDDEEECDDDDDCCDDDDDDDDDDDDDCDDDDDDDDDDDDDDCCDDDDDDDDDBBBBBDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:3012:2219 1:N:0:GTCGCT
+AGCTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGCGAAAGCCTGATGCAGCAACGCCGCGTGAGTGAAGAAGTATCTCGGTATGTAAAGCTCTATCAGCAGGGAAGAAAATGACGGTACCTGACTAAGAAGCCCCGGCTAAC
++
+CCCFFFFFGHHHHJJJIJJJJGIJJJJJJJJJJCGHIJJJJJJJJJJEHHHFFFFFFEEDEEDDDDDDDDDDCDDEDDCD>ADDEDDD?B at DDEEECDDDC>CDCDDCDDDB<BBACCDCDCBB0?@CCCDCDDDDCDCCABD>@D@<CC
+ at HWI-ST1106:815:H154GADXX:1:1101:3071:2234 1:N:0:CTACGG
+AGCTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGACGAGAGTCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATACGGGAATAAAGTGGAGTATGCATACTCCTTTGTATGTACCGT
++
++11ADDDDDDDDDII7E=CEI@@ECB@?<?DEICEIEDEEIIIDIIDDEIEEDIIDDDDDDDD?A at A@????AA?AA5>A>?A2>9:4:13895(>:A4>A>>AAAAA>88909<(++>:::>>A(>A>:>>A>AAAAA4>ADD>BDA><
+ at HWI-ST1106:815:H154GADXX:1:1101:3245:2235 1:N:0:CCTTAA
+AGCTCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAATGACGGTACCTAACAAGAAAGCACCGGCTAAC
++
+?=?DDEFFHHHHHJGIIJIJJBFIIIIHIJIJJIJJJJJJGIIHFFFFEDEECDDDCDDDDDDDDDDDDDDDDDDDDDDCB+>ABDDDDDDDDEEEDDDDDCDDD<BDDDDDCDDDDDCDDDDD>BDCDDDDDDDDDCCDDCD5<BDBDD
+ at HWI-ST1106:815:H154GADXX:1:1101:3136:2239 1:N:0:TTGGTA
+AGCTCCTACGGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGGAGGAAGAAGGTTTTCGGATTGTAAACTCCTGTCGTTAGGGACGATAATGACGGTACCTAACAAGAAAGCACCGGCTAAC
++
+BCBFFFFFHHHHHJJJJJJJJIJJJIJJJJJJJJJJJIJJJJJHFFFFEDEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDD>CDDDDDDDDDDEEEDDDDDCDDD<@DDDDDDBDDDDDDDDDDBDDDDDDDCDDDDDDDDDD at BDBBDD
+ at HWI-ST1106:815:H154GADXX:1:1101:3036:2243 1:N:0:CAAGAA
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGAGAGCCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATAAAGGAATAAAGTCGGGTATGGATACCCGTTTGCATGTACTTTATG
++
+:=?DDDDDHHHHHJJIJJHHFHIJJJJJJIJIJJJJJJJIJIJBHJJIJHIHFHEFEFFDCCEDDDBDDDDDDDDDDDDDDDDDDDDCBBBDEEDDDCDDDCDDEEDCDDDDDDDDCCDDD?BDDDDCEDDD at 5ACBCDCDCDDDDEDDC
+ at HWI-ST1106:815:H154GADXX:1:1101:3201:2246 1:N:0:CTGTCA
+CGCTCCTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGGCGCAGGCCTGAACCAGCCAAGTAGCGTGAAGGATGACTGCCCTATGGGTTGTAAACTTCTTTTATATGGGAATAAAGTTTTCCACGTGTGGAATTTTGTATGTACCAT
++
++1:ADDFFHHHHHIIIIIIIIHH at GHIIIGIIIIHHIIIIIIIIIIEGIIHFHFFFFEC;AAB;;CCB at BBCCCCACC@ACCCBC3:ACBCB at 0>C>CC>A at CCCCCEDDC<A>2:ACC4:ACCC:A88892?C3(+:>:<4>:4>@C at C
+ at HWI-ST1106:815:H154GADXX:1:1101:3089:2248 1:N:0:ACTTGA
+GAACCCATATGTTCTTTTCTGCAATATTCCTCGAGCCATCGTTGTGATATTGGTCAAGTCAATAAAAGCAATGACTTCTGTCAGCAATTCTTGATATCCTAGCTTATCGGCAAGCCGTCGCTGCTCTGTCAAAAACTGTCGATCATAAAT
++
+@@@DFDFDHGDHFHDBHIBHE at FDGHHEHEEFHHDGEHFHIHHIDFHGHIIIHIIIIII@@FGFHHCHGIIHCHAACBDBC at DFCCECECDE@ACEFCDDD:@:CA:CAB<<9B<?BD<B at BBDCCACCCCACCB<:A>@B?B at DDCDDE
+ at HWI-ST1106:815:H154GADXX:1:1101:3466:2192 1:N:0:CGATGT
+ATCGCGCCTTTAAGTCAGCCTGCAGGAAACAGTACGTTGACTTTAACCTCCTTTGATAATGACCAACACCATGAAGTAGATCTGGTAAACATAGCTCGATTGGGCCGTCAATGGTTTGGCGAATCATTTGAGGTTAAAAACGAACAGGAA
++
+=?+=D?DDHHGDHGFDHGHGDHIJJJIHHEGH?:??BDFAHIJJJJGI>GGHIIIH at HGA)=@HIFEFHFFFEFC;;@AEEDD at C5>CCDDDC:A at C?BCD?B?BBBBBDDA at A+>?<BDB@<BBC at AD@C?<38ACDDC<990<9?BBB
+ at HWI-ST1106:815:H154GADXX:1:1101:3490:2192 1:N:0:TAATCG
+GACTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGAGCGAAGAAGTATTTCGGGATGTAAAGCTCTATCAGCAGGGAAGAAGAAATGACGGTACCTGACTAAGAAGCACCGGCTAAAT
++
+ at 8@DDDDDFFFFFIIIIIIII;DFFIIFIF<GEFIIIIIIIIEFIIFFFFDDDDDDCBBBBBBBBB>BBBBBBBBBB:>>BDEBB&59<@ADDBBBBABBBBDBBBBB<@<?AABA?BBBBBBBBBBBBBBBBABBBBBBBBBBBBBBBB
+ at HWI-ST1106:815:H154GADXX:1:1101:3418:2203 1:N:0:TCACAA
+GACTACGGGAGGCAGCAGTGAGGAATATTGGTCAATGGTCGGCAGACTGAACCAGCCAAGTCGCGTGAGGGAAGACGGCCCTACGGGTTGTAAACCTCTTTTGTCGGAGAGTAAAGTACGCTACGTGTAGTGTATTGCAAGTATCCGAAG
++
++1=ADDDDHFFFFII=DG>EEHCHHGFDEHIH>GGHIIFGEGGGII at CEHIECHEHEE@B;ABCBBBBBAB;?BBC5<BBBBCB759>B<@CEDCCCCCC>>@?C5>@BBB4>ACC>CCBB?BBB???CC494>:B>CCC>>C>AAB?@<
+ at HWI-ST1106:815:H154GADXX:1:1101:3308:2210 1:N:0:TTGGTA
+AGCCTCGGAGGCAGCAGTGGGGGATATTGCACAATGGGGGAAACCCTGATGCAGCGACGCCGCGTGGAGGAAGAAGGTTTTCGGATTGCAAACTCCTGTCGTTAGGGACGATAATGACGGTACCTAACAAGAAAGCACCGGCTAACTACG
++
+BCCFFFFFHHHHHJJIJIGJJGFIJJJIGIGIJGIJIJJJHHHHFFFFEDEEEEDDDDBDDDDDBDDDA at BDDDDDD>CCDDDDB8<CDDDDDDDDDDCCDBBBDDDDDDDDDDCDDDDD>BDDDDDDDDDCDCDDDDDBBDDDDDDDDB
+ at HWI-ST1106:815:H154GADXX:1:1101:3481:2217 1:N:0:ATCACG
+GGGTAAAAGACTGGGCTAAGGAGAATGATTGCTGGATTGAAAATCCGGAATCATTAGGTGTGTTCTCTGACCGAGGTTCAGAGAACGAGGTTTATATGGCCTATGATGGAATACACGTTTATAAACTTTACGACTTCCGTTATTCTGACG
++
+=:8BDDEDHFG?HIFEHGIEIIGEIIFIEGCHIIIFGGIIIGGIIIGIIIGG9CGHCD83 at AEHIGIIEFH>BCAB at BCCCCC<ACBBB>08@?CD>C>8ACCCCADCCCCCCCCCCABCBCDDECCCCCC?<BBBAABAABBCDDEDCB
+ at HWI-ST1106:815:H154GADXX:1:1101:3392:2219 1:N:0:ATCACG
+GGGTACGACGCACATAACGCCCAGGGTGGAGAACTTGCCGAAATTCTTAGGTCCTACGAGGCTGATCGTAGCAGCGGCCAGAAGGACGCCGATTGTAGCCAGGCAGACTTCAACCGGATCAAGGTTGAAACCGAAAACATAAGAACCGTA
++
+B?8DDDFFHHHHHJJJJJJJJIIIIJDFGEIHIJJIIIJHHIHHHHHFFFBCDECEEDDBBDDDDDDBCBDDDCD<@B at BABDABDDBDDB>@@@ADDDDDABDDDDDCCDDDDDDBBDBDCCC>CCDDCCDBDBDDDDDDDCDCCDB?B
+ at HWI-ST1106:815:H154GADXX:1:1101:3431:2221 1:N:0:TTAGGC
+ATCGCAAATCATGGTGGGGATGATACGGCGTTTCATTGCGGAGCAGGAAATTGTTATGTTCTTATCAGGAGATTATAATTGGCCTGACAAATGGATGTGATTTATTTATTGGGCTCAATTGGGCTAGGTTGGGGATCTTCATTTGTCCAC
++
+@<BFFFFFHGHHHJCFGIIFIJIGJJJJJJIJJGIIJJJJJJHFFFFFCCEDECDDEDFEEEDCDCCDDABDDCDDEEEEDDDDDBCDDDDDDD(:@AACDDDDEDDDEDDDDBDAACCDCDDDDBDDCDDDDD0<BDCDEEEEEE at CDD
diff --git a/t/test1.fastq.gz b/t/test1.fastq.gz
new file mode 100644
index 0000000..9d409b9
Binary files /dev/null and b/t/test1.fastq.gz differ
diff --git a/t/test2.fasta b/t/test2.fasta
new file mode 100644
index 0000000..5a2ff72
--- /dev/null
+++ b/t/test2.fasta
@@ -0,0 +1,400 @@
+>HWI-ST1106:815:H154GADXX:1:1101:1244:2196 2:N:0:CTTGTA
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATGCTTATTCATAAGGTACATACAAGC
+TCCCACACGTGGGAGGGTTTATTCCCTTATAAAAGAAGTTTACAATCCGTAGGACCTTCA
+TCCTTCACGCTACTTGGCTGGTTCAGACTC
+>HWI-ST1106:815:H154GADXX:1:1101:1197:2208 2:N:0:TTGGTA
+CCATTACCGCGGCGGCTGGCACGTAGTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTA
+TCTTCCCTGCTGATAGAGCTTTACATAGCGAACCACTTCTTCACTCACGCGGCGTCGCTG
+CATCAGAGTTTCCTCCATTGTGCAATATTC
+>HWI-ST1106:815:H154GADXX:1:1101:1231:2209 2:N:0:ATCACG
+CTTCTGAGCCAGTTTCTATGGCTATCTCTTGCCGCTGATGCTGATGGTGATCGCTTTGGT
+GGGTGTACTGAAAGCTACTCACTCAGAGGGAGCCGCTGCGCTCTCGGCATTGGGCATTCT
+CATTCCATACTATGTGGTGCTCTACTTATT
+>HWI-ST1106:815:H154GADXX:1:1101:1225:2231 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTT
+TCTTCCCTGCTGATAGAGCTTTACATACCGAGATACTTCTTCACTCACGCGGCGTCGCTG
+CATCAGGGTTTCCCCCATTGTGCAATATTC
+>HWI-ST1106:815:H154GADXX:1:1101:1245:2247 2:N:0:ATCACG
+TAAAAAGACCTACTACTCAGTATACGCTGGATTGACAACTCACTTTTCATAGGTCTTTTA
+CTAAATAGAACTTCACAGCGGTATTTAGGTAATCGTTCTTTGAAAAGTACACATTCAACT
+ATGTTCTTATTTCCTTATAGATGTCATCTT
+>HWI-ST1106:815:H154GADXX:1:1101:1416:2204 2:N:0:GAACCT
+CCATTACCGCGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTAT
+CGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTGC
+ATCAGGGTTTCCCCCATTGTGCAATATCCC
+>HWI-ST1106:815:H154GADXX:1:1101:1397:2205 2:N:0:TTAGGC
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTT
+CTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGC
+TGCATCAGGGTTTCCCCCATTGTGCAATAT
+>HWI-ST1106:815:H154GADXX:1:1101:1258:2210 2:N:0:CAAGAA
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAAC
+GGGTATCCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCA
+TCCTTCACGCTACTTGGCTGGTTCAGGCTC
+>HWI-ST1106:815:H154GADXX:1:1101:1454:2212 2:N:0:TGAGGT
+CCATTACGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTTT
+CTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCACTCACGCGGCGTCGCTGC
+ATCAGGGTTTCCCCCATTGTGCAATATTCC
+>HWI-ST1106:815:H154GADXX:1:1101:1323:2213 2:N:0:CTACGG
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTCT
+TCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTG
+CATCAGGGTTTCCCCCATTGTGCAATATTC
+>HWI-ST1106:815:H154GADXX:1:1101:1432:2216 2:N:0:GACACT
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGAGCTTTCTTGTAAGGTACAGTCCTTCC
+TCTTCCCTTACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCATCGCTG
+CATCAGGGTTTCCCCCATTGTGCAATATCC
+>HWI-ST1106:815:H154GADXX:1:1101:1340:2224 2:N:0:CCTTAA
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTAT
+CTTCCCTGCTGATAGAGCTTTACATAACGAATTACTTCTTCACTCACGCGGCGTCGCTGC
+ATCAGAGTTTCCTCCATTGTGCAATATTCC
+>HWI-ST1106:815:H154GADXX:1:1101:1400:2224 2:N:0:TTAGGC
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTT
+CTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGC
+TGCATCAGGGTTTCCCCCATTGTGCAATAT
+>HWI-ST1106:815:H154GADXX:1:1101:1493:2225 2:N:0:GTCGCT
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAGGTACATACAAAAC
+GGGACACGTCCCGCACTTTATTCCCTTATAAAAGAGGTTTACGATCCATAGAACCTTCAT
+CCCTCACGCGACTTGGCTGGTTCAGCCTCT
+>HWI-ST1106:815:H154GADXX:1:1101:1376:2226 2:N:0:CCTTAA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTAT
+CGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTGC
+ATCAGGGTTTCCCCCATTGTGCAATATCCC
+>HWI-ST1106:815:H154GADXX:1:1101:1296:2233 2:N:0:TCATTC
+TGTGGACTAGCAAAGCTATCCAAACTTTCATGAACCATCTCATGCCAATCAGTTGCTTTT
+CCCCTTCGTAACTGCAATTCTAGTCGCCACCATGTCGTTATTTCCGGCGGAACAATTTTA
+CGTTTTCTTTCTTGTTCCAGTTTTTTAGAT
+>HWI-ST1106:815:H154GADXX:1:1101:1467:2241 2:N:0:ATCACG
+CGCTGTTACAGATCCTGTTTACCCTGTATATGTTGATTCCAATGTCATGGCAGGAAGAAC
+AGGCACATATGACGCTCAGCGAGACCCGGTAGTTGGCTTTGAAGGGGTTGTCGTTTTCAA
+ATTCGTCCAGCAGGGAGGCATAATCCGACA
+>HWI-ST1106:815:H154GADXX:1:1101:1493:2245 2:N:0:GGCCTT
+GCTTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAAA
+GTCTCACGAGACTCACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCTT
+CCTGCACGCTACTTGGCTGGTTCAGACTCT
+>HWI-ST1106:815:H154GADXX:1:1101:1696:2195 2:N:0:CCTTAA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTAT
+CGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTGC
+ATCAGGGTTTCCCCCATTGTGCAATATCCC
+>HWI-ST1106:815:H154GADXX:1:1101:1646:2204 2:N:0:CATCTA
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAAC
+GGGTATGCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCA
+TCCTTCACGCTACTTGGCTGGTTCAGGCTC
+>HWI-ST1106:815:H154GADXX:1:1101:1502:2205 2:N:0:TTAGGC
+TGATTGAAGTGGGCAGTTTCATTGGCATGGCAGCCATGACCCGTAGCGAACTGACCATCA
+AGAATGTCTCCTACGAGAACTTGGGAATTATCCCCGACAGTTTCCGTCGACTAGGCATCA
+AGATGGAGCAGTGGGGAGACGACATTTACG
+>HWI-ST1106:815:H154GADXX:1:1101:1742:2207 2:N:0:CATCTA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAAA
+GCCACACGTGGCTCACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCAT
+CCTTCACGCTACTTGGCTGGTTCAGACTCT
+>HWI-ST1106:815:H154GADXX:1:1101:1683:2207 2:N:0:CCTTAA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTAT
+CGTCCCTAACGACAGGAGATTACACTCCGAAAACCTTCTTCCCCCACGCGGCGTCGCTGC
+ATCAGGGTTTCCCCCATTGTGCAATATACC
+>HWI-ST1106:815:H154GADXX:1:1101:1541:2208 2:N:0:ATCACG
+GACTCTACCAGCATAGGAAGGTACGCCCACTATCAGCAGATCGCCATCACTTCCCAGCGA
+GACATCATCCTTCAGCACGTCTGAGGTAATGTCATACTCAATGACAGGCTTCTGAAACTG
+GGATGCTATCTCACGAACGATACGTTTGGT
+>HWI-ST1106:815:H154GADXX:1:1101:1564:2216 2:N:0:CAGATC
+CGCTTCGAGGTTTGCTTCCATGATAGAAAGATAGTTTTCTCCATTTTCTATTTGTTCATT
+CGTCAATCCTTCCAAAGGATTCAATACTTCTAAAGATACACCTGCTTCGTTTGCTAACGT
+TCTGGCAATACTATCTTTGGCGTTTTAGAT
+>HWI-ST1106:815:H154GADXX:1:1101:1719:2228 2:N:0:CTACGG
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAA
+AGGCACACGTGCCTCACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCA
+TCCTTCACGCTACTTGGCTGGTTCAGACTC
+>HWI-ST1106:815:H154GADXX:1:1101:1844:2204 2:N:0:CACTTG
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGTGGCTTCCTCGTACACTACCGTCATTG
+CCAGCCATTATTCACAACCGGCACATTCGTCATGTACAACAGAGCTTTACAATCCGAAGA
+CCTTCTTCACTCACGCGGCGTTGCTCCGTC
+>HWI-ST1106:815:H154GADXX:1:1101:1890:2219 2:N:0:GCCAAT
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTA
+TCTTCCCTGCTGATAGAGCTTTACATAGCGAACTACTTCTTCACTCACGCGGCGTCGCTG
+CATCAGAGTTTCCTCCATTGTGCAATATTC
+>HWI-ST1106:815:H154GADXX:1:1101:1802:2224 2:N:0:CGTCAA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGTGGCTTTTTCTCCAGGTACCGTCACGTC
+CTTCGTCCCTGGTAAAAGAAGTTTACAACCCGAAAGCCTTCTTCCTTCACGCGGCGTTGC
+TGGGTCAGGGTTTCCCCCATTGCCCAATAT
+>HWI-ST1106:815:H154GADXX:1:1101:1840:2224 2:N:0:GTCGCT
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACG
+GGTATGCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCAT
+CCTTCACGCTACTTGGCTGGTTCAGGCCAT
+>HWI-ST1106:815:H154GADXX:1:1101:1923:2228 2:N:0:AAGCGA
+CCATTACTGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTT
+CTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGC
+TGCATCAGGGTTTCCCCCATTGTGCAATAT
+>HWI-ST1106:815:H154GADXX:1:1101:1769:2229 2:N:0:TTAGGC
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATGCTTATTCATAAGGTACATACAAGC
+TCCCACACGTGGGAGGGTTTATTCCCTTATAAAAGAAGTTTACAATCCGTAGGACCTTCA
+TCCTTCACGCTACTTGGCTGGTTCAGACTC
+>HWI-ST1106:815:H154GADXX:1:1101:1997:2231 2:N:0:TAGAAG
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTAT
+CTTCCCTGCTGATAGAGCTTTACATAGCGAACTACTTCTTCACTCACGCGGCGTCGCTGC
+ATCAGAGTTTCGTCCATTGTGCAATATTCC
+>HWI-ST1106:815:H154GADXX:1:1101:1965:2235 2:N:0:CCACTC
+GCTGCGTTCTTCATCGATGCCGGAACCAAGAGATCCGTTGTTGAAAGTTTTAATTATTGT
+TTAACTAAAAACTCAGACTGCAAACTTCAGACAGTGTTCAAATGTTAGTCTTCGGCGGGC
+CGTGGCCACGCCGAAGCAACAGGGTACAGA
+>HWI-ST1106:815:H154GADXX:1:1101:1871:2243 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAA
+AGGCACACGTGCCTCACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCA
+TCCTTCACGCTACTTGGCTGGTTCAGACTC
+>HWI-ST1106:815:H154GADXX:1:1101:2118:2199 2:N:0:CAGCAC
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTAT
+CTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGC
+ATCAGGGTTTCCCCCATTGTGCAATATTCC
+>HWI-ST1106:815:H154GADXX:1:1101:2145:2206 2:N:0:CTATGG
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTCT
+TCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTG
+CATCAGGGTTTCCCCCATTGTGCAATATTC
+>HWI-ST1106:815:H154GADXX:1:1101:2188:2208 2:N:0:TGACCA
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGTGGCTTATTCGCCAGGTACCGTCTTCT
+ACTCGTCCCCGACAAAAGAAGTTTACAACCCGAAAGCCTTCTTCCTTCACGCGGCGTTGC
+TGGGTCAGGCTTGCGCCCATTGCCCAATAT
+>HWI-ST1106:815:H154GADXX:1:1101:2116:2218 2:N:0:GAACCT
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTAT
+CGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTGC
+ATCAGGGTTCCCCCCATTGTGCAATATCCC
+>HWI-ST1106:815:H154GADXX:1:1101:2046:2228 2:N:0:TTAGGC
+TTCAGGTCATAACTTTTGATCTTGCAGGCATCGCCGGAATTTCCCTCCACGGTATAAACA
+CGGCTGCCATCGGTGCCGACAACAATTCCCACATGGTCTGCGGAACCATCCAGATCCCAA
+TCGAAGAAAATGGCATCACCGGGAGCGATG
+>HWI-ST1106:815:H154GADXX:1:1101:2092:2229 2:N:0:AGTCAA
+CCATTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAA
+AGTCTCACGAGACTCACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCA
+TCCTGCACGCTACTTGGCTGGTTCAGGCTC
+>HWI-ST1106:815:H154GADXX:1:1101:2195:2237 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAATCAGGTACCGTCACTA
+TCTTCCCTGCTGATAGAGCTTTACATAACGAATTACTTCTTCACTCACGCGCCGTCGCGG
+CATCAGAGTTTCTTCCATTTTGCAATATTC
+>HWI-ST1106:815:H154GADXX:1:1101:2147:2238 2:N:0:CTACGG
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTAT
+CTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGC
+ATCAGGCTTTCGCCCATTGTGCAATATTCC
+>HWI-ST1106:815:H154GADXX:1:1101:2498:2195 2:N:0:CTACGG
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATAATACATACAAAA
+CAGTATACATACTGCACTTTATTCTTATATAAAAGAAGTTTACGACCCATAGAGCCTTCA
+TCCTTCACGCTACTTGGCTGGTTCAGGCTA
+>HWI-ST1106:815:H154GADXX:1:1101:2263:2198 2:N:0:ACTTGA
+TTCTACAGCGTCTTTCAAGAAACGACCAAGTGTTCGATAATCATGGTGCAAAATTTCACC
+TACACGGTTACGACTAGCCATTGTTCCGATGTTCACACGTGTGCCGGGGAAACCTTTGAT
+ATTGTTGAAAGTCATAGCTGGTCCTTCTTG
+>HWI-ST1106:815:H154GADXX:1:1101:2307:2201 2:N:0:TGGATT
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTAT
+CTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGC
+ATCAGGCTTTCGCCCATTGTGCAATATTCC
+>HWI-ST1106:815:H154GADXX:1:1101:2283:2204 2:N:0:CTACGG
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATGGTACATACAAAA
+TGGTATGCATACCAAACTTTATTCCCATATAAAAGAAGTTTACAACCCATAGGGCCGTCA
+TCCTTCACGCTACTTGGCTGGTTCAGGCTC
+>HWI-ST1106:815:H154GADXX:1:1101:2453:2206 2:N:0:ATACAC
+CCATTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAA
+AGTCTCACGAGACTAACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCT
+TCCTGCACGCTACTTGGCTGGTTCAGACTC
+>HWI-ST1106:815:H154GADXX:1:1101:2336:2209 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATTATACATACAAAA
+CAGTATACATACTGCACTTTATTCTAATATAAAAGAAGTTTACAACCCATAGGGCAGTCA
+TCCTTCACGCTACTTGGCTGGTTCAGGCCA
+>HWI-ST1106:815:H154GADXX:1:1101:2378:2210 2:N:0:CTACGG
+GCTTCCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACGG
+GTATACATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCATC
+CTTCACGCTACTTGGCTGGTTCAGGCCTGC
+>HWI-ST1106:815:H154GADXX:1:1101:2470:2220 2:N:0:ATCACG
+AAATTGACGAAATAAACCACCAGCTGACCGAAGATGATGGCAAACTGGTTCCAGCTGACC
+AACATACCACGGATGTTACTAGGCGCAATCTCACCGATATACATCGGACATACAGCAGAT
+GCCAGACCCACACCGATACCGCCAATCACA
+>HWI-ST1106:815:H154GADXX:1:1101:2434:2220 2:N:0:CGATGT
+TAGGCTGAGTCCATCCTGGATCATTTGTAGTTTCTTCAGAAAGTATATCTTTTCCCTGAG
+TAGCAATATTAGCATGTTCTCCCTTTTCTATTTTATGCTTGTCAGGAATACCAGTATAAG
+TTAATGTATGAAGCACTCGAATATATGATT
+>HWI-ST1106:815:H154GADXX:1:1101:2285:2223 2:N:0:CGAATA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAAA
+GCCACACGTGGCTAACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCAT
+CCTTCACGCTACTTGGCTGGTTCAGACTCT
+>HWI-ST1106:815:H154GADXX:1:1101:2390:2234 2:N:0:ATACAC
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTT
+TCTTTCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCACTCACGCGGCGTTGCTG
+CATCAGGGTTTCCCCCATTGTGCAATATTC
+>HWI-ST1106:815:H154GADXX:1:1101:2331:2236 2:N:0:CAGCAC
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGAGCTTATTCTACAGGTACTGTCTTGTT
+TCTTCCCTGTCTAAAGCAGTTTACAATCCGAAAACCTTCTTCCTGCACGCGGCGTCACTG
+CGTCAGAGTTTCCTCCATTGCGCAATATTC
+>HWI-ST1106:815:H154GADXX:1:1101:2413:2237 2:N:0:CAGATC
+TACATCTCTTCTCTCCTAATGTTAGTTTTAGAAATAAAGACAGAATCTGCGACCTTCAAT
+CTCACAAATTCGTATGTCCATTTCGTACAATTCGTCCAGTACATCTTTTTTTATCATTTC
+TTGGGTCGTTCCTTGCGTGAATAACTGCCC
+>HWI-ST1106:815:H154GADXX:1:1101:2368:2242 2:N:0:TCCTCA
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTT
+CTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGC
+TGCATCAGGGTTTCCCCCATTGTGCAATAT
+>HWI-ST1106:815:H154GADXX:1:1101:2491:2246 2:N:0:CCTTAA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGAGCTTTCTTGAAAGGTACCGTCAGAAC
+TGTATCATTTCCTATACAGTTTGTTCTTCCCTAACAACAGAAGTTTACAATCCAAAGGAC
+CGTCATCCTTCACGCGGCATTGCTCGTTCA
+>HWI-ST1106:815:H154GADXX:1:1101:2525:2193 2:N:0:CAGATC
+TTCTGAATAAAGGGAAACTTGTGCACTGACAGTAGAAGCCCCAGAGATATTTTTTTGCTG
+TTTGATCAATTCTAATGCACTGTTAAAACATGCACTGAAACCAGCTGCAAACAATTGTTC
+AGGGTTGGTTGCATTTTCGACGCGTTTACC
+>HWI-ST1106:815:H154GADXX:1:1101:2680:2193 2:N:0:GAACCT
+GCTTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAAA
+GTCTCACGAGACTAACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCTT
+CCTGCACGCTACTTGGCTGGTTCAGGCTCT
+>HWI-ST1106:815:H154GADXX:1:1101:2516:2210 2:N:0:TAGCTT
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATGGTACATACAAAAT
+TCCACACGTGGAAAACTTTATTCCCATATAAAAGAAGTTTACAACCCATAGGGCAGTCAT
+CCTTCACGCTACTTGGCTGGTTCAGACTCT
+>HWI-ST1106:815:H154GADXX:1:1101:2713:2212 2:N:0:TGACCA
+AGATTGCCACCTCCGTTGATATTATATGTCACTATTCCATTATTGGGACCACTAAACTTT
+ATTAAGGAAGAAGAACCTGAACAAATTGGACTAGCGCCATTAATTGAAATTGTAGCCGTT
+GGTGTTGAACGAACTGTTACAGCTGCGCTA
+>HWI-ST1106:815:H154GADXX:1:1101:2678:2222 2:N:0:CGCTGA
+GCTTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAAA
+ATCTCACGAGACTCACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCAT
+CCTGCACGCTACTTGGCTGGTTCAGGCTCT
+>HWI-ST1106:815:H154GADXX:1:1101:2588:2225 2:N:0:CCTTCT
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAAC
+GGGTATGCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCA
+TCCTTCACGCTACTTGGCTGGTTCAGGCCA
+>HWI-ST1106:815:H154GADXX:1:1101:2713:2231 2:N:0:TGACCA
+AGATTGCCACCTCCGTTGATATTATATGTCACTATTCCATTATTGGGACCACTAAACTTT
+ATTAAGGAAGAAGAACCTGAACAAATTGGACTAGCGCCATTAATTGAAATTGTAGCCGTT
+GGTGTTGAACGAACTGTTACAGCTGCGCTA
+>HWI-ST1106:815:H154GADXX:1:1101:2557:2232 2:N:0:CAAGAA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACG
+GGTATCCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCAT
+CCTTCACGCTACTTGGCTGGATCAGGCTCT
+>HWI-ST1106:815:H154GADXX:1:1101:2740:2237 2:N:0:AGTTCC
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTT
+CTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGC
+TGCATCAGGGTTTCCCCCATTGTGCAATAT
+>HWI-ST1106:815:H154GADXX:1:1101:2527:2244 2:N:0:GTTGAA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAAA
+GGCACGCGTGCCTCACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCAT
+CCTTCACGCTACTTGGCTGGTTCAGACTCT
+>HWI-ST1106:815:H154GADXX:1:1101:2603:2248 2:N:0:CAGCAC
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGATGCTTATTCCTTAGCTACCGTCACTGT
+CTTCGTCACTAAGAAAAGAAGTTTACAATCCGAAAACCGTCATCCTTCACGCGGCGTTGC
+TGCATCAGGGTTTCCCCCATTGTGCAATAT
+>HWI-ST1106:815:H154GADXX:1:1101:2853:2195 2:N:0:ACTTGA
+AACTATAACTCTTTCCAGGAACTAAATGAAAATCCTATTTTCGCAGATGTTAGCGTATAC
+AATCGTACAGTCATGACACCACAAAGTCTTCCGCATGTAGTAGATGAAGCCATTAAAGCC
+GCCTATGAGCATAAAGGCGTGGCTATCGTG
+>HWI-ST1106:815:H154GADXX:1:1101:2884:2198 2:N:0:TGGATT
+CCATTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAA
+AGTCTCACGAGACTCACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCT
+TCCTGCACGCTACTTGGCTGGTTCAGACTC
+>HWI-ST1106:815:H154GADXX:1:1101:2751:2204 2:N:0:AAGCTT
+GCTGCGTTCTTCATCGATGCCGGAACCAAGAGATCCGTTGTTGAAAGTTTTAAATAATTT
+ATATTTTCACTCAGACTTCAATCTTCAGACAGAGTTCGGGGGTGTCTTCGGCGGGCGCGG
+GCCCGGGGGCGTGAGCCCCCCGGCGGCCAG
+>HWI-ST1106:815:H154GADXX:1:1101:2785:2207 2:N:0:AAGAAG
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCCTAGTCAGGTACCGTCATTT
+CTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGC
+TGCATCAGGGTTTCCCCCATTGTGCAATAT
+>HWI-ST1106:815:H154GADXX:1:1101:2938:2209 2:N:0:CAGATC
+CCAAGAAGGAATCGATTATTTGGCAGGCCTGCCGGATAGCCATCCAAAGGTCTTGATAGT
+AAAAGAAGGAAGATATGATGAATATATAGAAAGCAGATTATCCAATTTTAAACTTGTGGG
+AGCAGGAACAGTAGTTATCTCCGGTAATCG
+>HWI-ST1106:815:H154GADXX:1:1101:2969:2210 2:N:0:CGTCAA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACG
+GGTATACATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCAT
+CCTTCACGCTACTTGGCTGGTTCAGGCCTG
+>HWI-ST1106:815:H154GADXX:1:1101:2909:2214 2:N:0:CCGTCC
+TTATCAAAACTTATCTTATTTTCGAAGTAAAAGTTGAAGCTTTGATGGGGTAAATATAAA
+AATATATTTCAGATTTTTATTTTTTAAAAACAAATAAAAGTAAAGAATTTCAACTACAAG
+GTTGTAGTAATGAATAAATTAACAAATAAA
+>HWI-ST1106:815:H154GADXX:1:1101:2888:2222 2:N:0:GTCGCT
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTTT
+CTTCCCTGCTGATAGAGCTTTACATACCGAGATACTTCTTCACTCACGCGGCGTTGCTGC
+ATCAGGCTTTCGCCCATTGTGCAATATTCC
+>HWI-ST1106:815:H154GADXX:1:1101:2873:2233 2:N:0:ACTTGA
+TCTGCAAGCACTGGTCCTTTGGCTAGTTCTGCTTGTCCCTTTGTTTCTTCATTTAAATGA
+ACCGTTCCAGATACAGGAGCTTTTAGTATTCCTTTTGAAAGTTGATCGTCCAAACTTTTG
+ATAACTGACTGGTTCTTCTCTTGTTTTTCA
+>HWI-ST1106:815:H154GADXX:1:1101:2990:2243 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTT
+TCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCACTCACGCGGCGTCGCTG
+CATCAGAGTTTCCTCCATTGTGCAATATCC
+>HWI-ST1106:815:H154GADXX:1:1101:2791:2243 2:N:0:CAGATC
+ATTTCTCAATCTTTTCTCTCCGTTGGGATAACAACGATTATGTGGGTATTTGGTGGATTC
+GGATTGGCCTTTGGACGGGATATCGGCGGTGTTATTTGTAAACCGGCGGGTTTTTTTTTG
+TTGAGGCATGTTACAAGCTTCCCCAACACG
+>HWI-ST1106:815:H154GADXX:1:1101:3046:2196 2:N:0:AGTTCC
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATGGTACATACAAAA
+ATCCACACGTGGATAACTTTATTCCCATATAAAAGAAGTTTACAACCCATAGGGCAGTCA
+TCCTTCACGCTACTTGGCTGGTTCAGACTC
+>HWI-ST1106:815:H154GADXX:1:1101:3147:2203 2:N:0:GGCCTT
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTGT
+CTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCACTCACGCGGCGTCGCTGC
+ATCAGAGTTTCCTCCATTGTGCAATATTCC
+>HWI-ST1106:815:H154GADXX:1:1101:3211:2211 2:N:0:AGTGGT
+CCATTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTGCATGCAAAA
+AGTCTCACGAGACTCACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCT
+TCCTGCACGCTACTTGGCTGGTTCAGACTC
+>HWI-ST1106:815:H154GADXX:1:1101:3127:2215 2:N:0:ATCACG
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTAT
+CTTCCCTGCTGATAGAGCGTTACATAACGAATTACTTCTTCACTCACGCGGCGTCGCTGC
+ATCAGAGTTTCCTCCATTGTGCAATATTCC
+>HWI-ST1106:815:H154GADXX:1:1101:3233:2216 2:N:0:TTGGTA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGTGGCTTTCTGGTTAGATACCGTCAAGGC
+GCTAACAGTTACTCTAGCACTTGTTCTTCTCTAACAACAGAGTTTTACGATCCGAAAACC
+TTCTTCACTCACGCGGCGTTGCTCCGTCAG
+>HWI-ST1106:815:H154GADXX:1:1101:3185:2216 2:N:0:TTGGTA
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTT
+TCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCACTCACGCGGCGTTGCTG
+CATCAGGGTTTCCCCCATTGTGCAATATTC
+>HWI-ST1106:815:H154GADXX:1:1101:3012:2219 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTT
+TCTTCCCTGCTGATAGAGCTTTACATACCGAGATACTTCTTCACTCACGCGGCGTTGCTG
+CATCAGGCTTTCGCCCATTGTGCAATATTC
+>HWI-ST1106:815:H154GADXX:1:1101:3071:2234 2:N:0:CTACGG
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAGG
+AGTATGCATACTCCACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCAT
+CCTTCACGCTACTTGGCTGGTTCAGACTCT
+>HWI-ST1106:815:H154GADXX:1:1101:3245:2235 2:N:0:CCTTAA
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTA
+TCGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTG
+CATCAGGGTTTCCCCCATTGTGCAATATCC
+>HWI-ST1106:815:H154GADXX:1:1101:3136:2239 2:N:0:TTGGTA
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTA
+TCGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTG
+CATCAGGGTTTCCCCCATTGTGCAATATCC
+>HWI-ST1106:815:H154GADXX:1:1101:3036:2243 2:N:0:CAAGAA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACG
+GGTATCCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCAT
+CCTTCACGCTACTTGGCTGGTTCAGGCTCT
+>HWI-ST1106:815:H154GADXX:1:1101:3201:2246 2:N:0:CTGTCA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATGGTACATACAAAAT
+TCCACACGTGGAAAACTTTATTCCCATATAAAAGAAGTTTACAACCCATAGGGCAGTCAT
+CCTTCACGCTACTTGGCTGGTTCAGGCCTG
+>HWI-ST1106:815:H154GADXX:1:1101:3089:2248 2:N:0:ACTTGA
+TCATACGCAAGTTTCAAATGAACTTCCTGAAAGCATTATGGACAGTATACGAGAAGTACG
+TGATTATTTTGAAGAGTCTACCATTCTTCAGGGAATTGACGTGATTTATGATCGACAGTT
+TTTGACAGAGCAGCGACGGCTTGCCGATAA
+>HWI-ST1106:815:H154GADXX:1:1101:3466:2192 2:N:0:CGATGT
+AAAACAAATTCAGTTTCTGAATTGTTATTCAGCGCAGGAAACGAGATGTTTCCGACTAAA
+ATTCCGTTTGCGGTCACAGTAAGTGAGGTAGGTGTAAAAGCTGCTGAGGCGGCTGTCAGC
+ATAATTTTAACGGTTGATGTGGCGTCAAAA
+>HWI-ST1106:815:H154GADXX:1:1101:3490:2192 2:N:0:TAATCG
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTT
+CTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGC
+TGCATCAGGGTTTCCCCCATTGTGCAATAT
+>HWI-ST1106:815:H154GADXX:1:1101:3418:2203 2:N:0:TCACAA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATGCTTTTTCTTCGGATACTTGCAATAC
+ACTACACGTAGCGTACTTTACTCTCCGACAAAAGAGGTTTACAACCCGTAGGGCCGTCTT
+CCCTCACGCGACTTGGCTGGTTCAGTCTGC
+>HWI-ST1106:815:H154GADXX:1:1101:3308:2210 2:N:0:TTGGTA
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTA
+TCGTCCCTAACGACAGGAGTTTGCAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTG
+CATCAGGGTTTCCCCCATTGTGCAATATCC
+>HWI-ST1106:815:H154GADXX:1:1101:3481:2217 2:N:0:ATCACG
+CGATTCTGCGAGAAACCGATGAGATCGTAGGGGCATGCTGTGAAGTATTGGTTGTGAGCA
+ACAATTCGTTCAAAGAAAGGAGTAAGGTTGTCGTCAGAATAACGGAAGTCGTAAAGTTTA
+TAAACGTGTATTCCATCATAGGCCATATAA
+>HWI-ST1106:815:H154GADXX:1:1101:3392:2219 2:N:0:ATCACG
+ATGGGCGGTTACGCAGAATACCGCTTCGGGAGAGCCGGCAATTTCCTCTCCAACTTCTGC
+TACACGATTTCTCTGATCATCGCCAACGTTGCTATTGCAAGCGGCGTTGTCAGCTACGGT
+TCTTATGTTTTCGGTTTCAACCTTGATCCG
+>HWI-ST1106:815:H154GADXX:1:1101:3431:2221 2:N:0:TTAGGC
+ATGCTACCTACTCTGAAATTGACGGTACAGCAACAAGCGAAATTGCGACAAGCAGTAATG
+CATTAATGTTAATCCCTCAGAATGATCTATCGTCAGTCAAGATTACTGTTACTTATTCCA
+CGACTAATGATAATGGCAAAGTATTTGAAG
diff --git a/t/test2.fastq b/t/test2.fastq
new file mode 100644
index 0000000..5e4944c
--- /dev/null
+++ b/t/test2.fastq
@@ -0,0 +1,400 @@
+ at HWI-ST1106:815:H154GADXX:1:1101:1244:2196 2:N:0:CTTGTA
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATGCTTATTCATAAGGTACATACAAGCTCCCACACGTGGGAGGGTTTATTCCCTTATAAAAGAAGTTTACAATCCGTAGGACCTTCATCCTTCACGCTACTTGGCTGGTTCAGACTC
++
+=+=+<?7@?C0CACAABABABBAA=:<AABBBAAAAABBAABBBBAAAAA;?@>>75>>=@>?======;9;=8255+88=:?????????=::=;<?8883::8;8;;=;<=??7<????3;?????8;===??????###########
+ at HWI-ST1106:815:H154GADXX:1:1101:1197:2208 2:N:0:TTGGTA
+CCATTACCGCGGCGGCTGGCACGTAGTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTATCTTCCCTGCTGATAGAGCTTTACATAGCGAACCACTTCTTCACTCACGCGGCGTCGCTGCATCAGAGTTTCCTCCATTGTGCAATATTC
++
+?:=BDDDBFDDFA)?;7AFEIII?=?ED7?@)9/3>?BB at AA@ABADBB9 at A>BBBBBBBBBBDEBBBA?@B>BBA>ABBBBBBBBDBBBBB>BBBBBABBB@>A>BBBBBBBBBBB9><BABBBBBBBAADBABB@>BBDBBDBBBBDE
+ at HWI-ST1106:815:H154GADXX:1:1101:1231:2209 2:N:0:ATCACG
+CTTCTGAGCCAGTTTCTATGGCTATCTCTTGCCGCTGATGCTGATGGTGATCGCTTTGGTGGGTGTACTGAAAGCTACTCACTCAGAGGGAGCCGCTGCGCTCTCGGCATTGGGCATTCTCATTCCATACTATGTGGTGCTCTACTTATT
++
+@@@D+=BBBFAFCG at GFFEHEIA<ACHHCFHIIEB at FFGFFIIFIEFFGFCIDFFFFGF6@DFEB=BDDD>@ACAC at CBBBBBBBBB>?BBBBBBBBB at B><>BB5?B at BABBBBBBBBEBDDEDEDB>?BB at ABBB9?:::@AA>B>AD
+ at HWI-ST1106:815:H154GADXX:1:1101:1225:2231 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTTTCTTCCCTGCTGATAGAGCTTTACATACCGAGATACTTCTTCACTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATTC
++
+@@@BDD>DFD at FFH@GHGG1DGHFHGHHGGCHGGFGHHCE?DDDECE6>@@A>;?BBBEDCACCCCCCCBCCCCCCCCCCACCCCEE at CBBBBB:ACCCCCCECCC9AAB9>BBBBBBBBBCCCC:@13<8 at CCCB@CCCECCDACC>@C
+ at HWI-ST1106:815:H154GADXX:1:1101:1245:2247 2:N:0:ATCACG
+TAAAAAGACCTACTACTCAGTATACGCTGGATTGACAACTCACTTTTCATAGGTCTTTTACTAAATAGAACTTCACAGCGGTATTTAGGTAATCGTTCTTTGAAAAGTACACATTCAACTATGTTCTTATTTCCTTATAGATGTCATCTT
++
+@?@DFFADHGFHHIJJJJJIHIJIJJIIJJIJIIIJJIIGIIJEHII@@FIEGF:CHIJJIIJJJJJDGHGJJJFHHGDFCACDEDDCCCDDEDDBDDDCCCCDCCDDDACCDDCDC>ADDCCAC>CC3>@@>>>CDA at AACCDDABAAA
+ at HWI-ST1106:815:H154GADXX:1:1101:1416:2204 2:N:0:GAACCT
+CCATTACCGCGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTATCGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATCCC
++
+@@?DFFFBDFHHFHIGIIJJIHHGFHJIFHIJJDFFHIJJIJJHIIIIHIJJEHH7BEDDDDEDDDA at CAB<@BBB<?(9>>C at CC?AB0?BB>?CDDCDDC at CCDCB<9@<>5>B at 9B<ACCDCCB3AB at CACB@CDCC4:ACCD@:@C
+ at HWI-ST1106:815:H154GADXX:1:1101:1397:2205 2:N:0:TTAGGC
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTTCTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATAT
++
+===AAAAAAAA8A)1:7?AA>*:00=AB<?B<A:-5<BABBBABBBAA>=AA;=@@@@>@B(;?>?=?:=>=>?:;>???????????=?===;;=????????=5;89:<======;;=;==??:?::;(8;??;8;9<=7:????::;
+ at HWI-ST1106:815:H154GADXX:1:1101:1258:2210 2:N:0:CAAGAA
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACGGGTATCCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGGCTC
++
+@?BDFFFFHHGHHJJIJJJJJJIIGHFHGHJJIJJIJJIJIHHHHHHHFCDFFFFEEEEEDDB8?CCDDDCDDDDDDDDDDDDEECDDDDEEEDDDDDACD>ACD>BDDDDDDBDDDDDDEDDDDDDDDCDDDDDDDCDDB<@CCDDCBD
+ at HWI-ST1106:815:H154GADXX:1:1101:1454:2212 2:N:0:TGAGGT
+CCATTACGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCACTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATTCC
++
+CCCFFFFFHHHHHIJJIIJJJJBFHHGIIIJJGHEHHHFEFFEFFFEEEEEE?BD=ADFE at C>@CCDDACDCACCA at CDDDDDDDDCCBBDBD>CD at CDDDECDDDDDDBD@BDDDDBBBDDDCCAB+<<>C4<5>CDDCCCDDC3>C@>
+ at HWI-ST1106:815:H154GADXX:1:1101:1323:2213 2:N:0:CTACGG
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTCTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATTC
++
+???DDD?DD at DD:@CEB>D9?@0BDEEDEEEIIDADEICEIIICICDDDD>A@??@@DADE>A>>A9;>?>AAAAAAAAAAAAAADEA??>>;>>>AAA>A:29>8>A?>?>7>??>>??>AAAAAA?+8<A::<9>?A<:AAD>AAAB>
+ at HWI-ST1106:815:H154GADXX:1:1101:1432:2216 2:N:0:GACACT
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGAGCTTTCTTGTAAGGTACAGTCCTTCCTCTTCCCTTACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCATCGCTGCATCAGGGTTTCCCCCATTGTGCAATATCC
++
+CCCFFDDFHGHHDGIJEEHIJIGHJHIIJJIJJFHIIJJAHHHHHHHFFFFFCCC:@C>;;;>C:ACAC::85380?B at ACCCDCCC399@?BDA0>CCDAA@:@(9??@@90553<?ABBCAA@@CB<A at D>@C>DCA at ACAC@ACCDD
+ at HWI-ST1106:815:H154GADXX:1:1101:1340:2224 2:N:0:CCTTAA
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTATCTTCCCTGCTGATAGAGCTTTACATAACGAATTACTTCTTCACTCACGCGGCGTCGCTGCATCAGAGTTTCCTCCATTGTGCAATATTCC
++
+@@@FFFFFHHHHHIGJJJFIJJHGHJIIIJJJJIIJJJJJJJHGHHHHHFFFFDDDDDDDDDEEDDDDDDCDDDDDDDADDCDDEEDDDDDDDDDDDDDDCCCCDCDDDDDDDDDDDDDDDDCDDAC>ACDDDDDDDDDDDDEDDCDEDE
+ at HWI-ST1106:815:H154GADXX:1:1101:1400:2224 2:N:0:TTAGGC
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTTCTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATAT
++
+@@@DDDDDHDFHFAGGIIIIIGII;DHIAFHGIGFHGHIIIIGHIIFHHHFHCBECCCEEEEFCCFCACCCBCCCCCCACCCCCCCCDECCBBBBACCCCCCCCB at BBBCBABBBBBBBBBBBCCACCAB3<@CCCABBCC at ACCEC@>C
+ at HWI-ST1106:815:H154GADXX:1:1101:1493:2225 2:N:0:GTCGCT
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAGGTACATACAAAACGGGACACGTCCCGCACTTTATTCCCTTATAAAAGAGGTTTACGATCCATAGAACCTTCATCCCTCACGCGACTTGGCTGGTTCAGCCTCT
++
+ at 7?DDFFFHHGGHIIGIBHHIIIBFHIIIIIIIGIGIIIIIHFHHHGGCDFFFFEEEECBBB>@BBCCBB?@BBBCCCCCCCEDCCCCCCCDCC09A at BCC@BBB?BCCCC at CC?CCCCDDCCCCBBCBCCCBCCCCCCBCCCCC:C?CC
+ at HWI-ST1106:815:H154GADXX:1:1101:1376:2226 2:N:0:CCTTAA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTATCGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATCCC
++
+@@@FFFFFFHHHHIIIJJHIJJFHHJJIIIIJJ at FBHJIJHJJIHHHGEHFFFFDCCDEEDDDDDDDDDDB@BBDDDDCDCDCDDDDDDBDDDDDDDDDDDDACCDCDDDDDDDDDDDDDDDDDDDDDD at CACDBDDDDEDCECCCCC>C
+ at HWI-ST1106:815:H154GADXX:1:1101:1296:2233 2:N:0:TCATTC
+TGTGGACTAGCAAAGCTATCCAAACTTTCATGAACCATCTCATGCCAATCAGTTGCTTTTCCCCTTCGTAACTGCAATTCTAGTCGCCACCATGTCGTTATTTCCGGCGGAACAATTTTACGTTTTCTTTCTTGTTCCAGTTTTTTAGAT
++
+??@DFE8DH>FBHEAFHGJGGHHIHHHIJIIHIGGGIGGGIIIJIIIIFFFGGGGGHEJI:=BFDHGEHIIJGHGFHH at CDD;??>CCDDBBDCEDDD:?9>ACD<>BBD at BBB9CC3>@CD?39B3+>CCCCDCCC>@CCDCD?@DDDC
+ at HWI-ST1106:815:H154GADXX:1:1101:1467:2241 2:N:0:ATCACG
+CGCTGTTACAGATCCTGTTTACCCTGTATATGTTGATTCCAATGTCATGGCAGGAAGAACAGGCACATATGACGCTCAGCGAGACCCGGTAGTTGGCTTTGAAGGGGTTGTCGTTTTCAAATTCGTCCAGCAGGGAGGCATAATCCGACA
++
+ at B@BA at DDHFDHHCHGIHHHHH@FDGAFHIIIFHIJIHGJ@>GHDGGGHBGGGBEGIFHIGFEAGHJCA=EHJFGA8=BEBDDBBBDBB8<>:>@C(4<CCDD at CBB)5<9@@8>@BCCCCCCC?>?<?@CCBDBB5@?<AACCCD>?>>
+ at HWI-ST1106:815:H154GADXX:1:1101:1493:2245 2:N:0:GGCCTT
+GCTTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAAAGTCTCACGAGACTCACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCTTCCTGCACGCTACTTGGCTGGTTCAGACTCT
++
+@@@FFDDFGHHHHGIJJEIIJHEHGJIIHIGJJJJJJJJJHHHHHGGFEFFFFFEEEEEDDCDEDEDDDDDDDDDDDDDDDDDDDDDDDDEEDDDDDDDEECDCDBDDCDCCBDDDDBDDDCCDDDCDDDDDDDDDDDDBCCCDDDCCCD
+ at HWI-ST1106:815:H154GADXX:1:1101:1696:2195 2:N:0:CCTTAA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTATCGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATCCC
++
+;@@DDDDDAFFA at 81CCFFFED:090B<0/B at F<5A at DEEDDA=AEC?7=?BBD9=@DDDBB=??@BBBBBBBBBB@@?BBDBBBB??BBBBBBBBBBBBB>@ABBBB at BBBBBBB9BBBBBBBB>?+2<A at BBBB@@BDBB@>AA:BDB
+ at HWI-ST1106:815:H154GADXX:1:1101:1646:2204 2:N:0:CATCTA
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACGGGTATGCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGGCTC
++
+@@@DD>BDHH:<F:EHC?DAGGF@:D/?8B?F6;FAEDGHACHHHDHF?DDDBCECCCCABBB;?CCCDD@>CCBB>BBCCCCDDCCCCCEECCC@@C:@C::AC>?BBCC>A at C@BCCCDCCCCCC>?B<BBCACC>A053:ACCCCBB
+ at HWI-ST1106:815:H154GADXX:1:1101:1502:2205 2:N:0:TTAGGC
+TGATTGAAGTGGGCAGTTTCATTGGCATGGCAGCCATGACCCGTAGCGAACTGACCATCAAGAATGTCTCCTACGAGAACTTGGGAATTATCCCCGACAGTTTCCGTCGACTAGGCATCAAGATGGAGCAGTGGGGAGACGACATTTACG
++
+;=?D7:BD?:C<FD:CCG@?<FHBF<ACFGFIEAF;FGF>BF:?DBBD;AE at DAE;D@?)7?;@;77?BCC3;>83>8;:@>>59,:5>B::(489>5>B(+++(+489@<?&399>49>(+:@>A>BB@####################
+ at HWI-ST1106:815:H154GADXX:1:1101:1742:2207 2:N:0:CATCTA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAAAGCCACACGTGGCTCACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGACTCT
++
+<@@DD;??@<F at DGBEHICHEFB@DIGHCGIIIIGIIIGGIECHHFEDCDCCD;>ACCBBB?<CC?8=?A at BBCCCCCACCC:@A>BBBCEDCC?A>@A:@@@C>?>BCCCCBC@>?>:>4 at CCCCCB?BBBCCCCCCBBC>@:>3(:>C
+ at HWI-ST1106:815:H154GADXX:1:1101:1683:2207 2:N:0:CCTTAA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTATCGTCCCTAACGACAGGAGATTACACTCCGAAAACCTTCTTCCCCCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATACC
++
+?@@FDFFFHHGHHIJJJJJJJJDGEHJJIJJJJFHIJJB at EEG7=EEHEHFFFFDD;C@;@=(55;@((5??39<((((+:@>A(((9<&+5992>4>@:>:(+0&95 at D@BB95><9959:>C>4?98<C(:(553+:ACD at 4>>C###
+ at HWI-ST1106:815:H154GADXX:1:1101:1541:2208 2:N:0:ATCACG
+GACTCTACCAGCATAGGAAGGTACGCCCACTATCAGCAGATCGCCATCACTTCCCAGCGAGACATCATCCTTCAGCACGTCTGAGGTAATGTCATACTCAATGACAGGCTTCTGAAACTGGGATGCTATCTCACGAACGATACGTTTGGT
++
+?;?DDD:AC<CDD<EEEEF>;+<FFDFEADDDD<@?BD at DEEBD@DBBBBCIDCC=AAA@'-=@ADDAFAABAAAA5=99??8>>8::A>A>DE(>AAAAA>A>A>3208>>A3:>A>A:><>A??A3>>AAAA>>>>3><89<4<<<<>
+ at HWI-ST1106:815:H154GADXX:1:1101:1564:2216 2:N:0:CAGATC
+CGCTTCGAGGTTTGCTTCCATGATAGAAAGATAGTTTTCTCCATTTTCTATTTGTTCATTCGTCAATCCTTCCAAAGGATTCAATACTTCTAAAGATACACCTGCTTCGTTTGCTAACGTTCTGGCAATACTATCTTTGGCGTTTTAGAT
++
+@<@B==D;;8 at A?ACF?AACB at CBH?+?FHBGGHHICHC*:*:?FFGGF9DB?DDDD?FE<B8;FFD;;CG)@=DEAE(7);;)77;>A;@66>@@A@>;A55>5:>:;9(883>>C9<+<(<:>AC(9A at C3>ACDCC>C><B><A34:
+ at HWI-ST1106:815:H154GADXX:1:1101:1719:2228 2:N:0:CTACGG
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAAAGGCACACGTGCCTCACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGACTC
++
+@@@DABDDAFHDFHGHIIG8CFDAGIBBDFIGHIGIGIIIIFFEEHHHEDD8 at CCCCCCBBBB??95<8 at 8?8:3+8AC>CCCDEC at 858@CDCABBCCC>>:@ACB><9>CCBCBB<9ACC at C:(+:2<5(5CCC>9ABBCC@@>4:>>
+ at HWI-ST1106:815:H154GADXX:1:1101:1844:2204 2:N:0:CACTTG
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGTGGCTTCCTCGTACACTACCGTCATTGCCAGCCATTATTCACAACCGGCACATTCGTCATGTACAACAGAGCTTTACAATCCGAAGACCTTCTTCACTCACGCGGCGTTGCTCCGTC
++
+C at CFFFFEFHGFHHHJJJEIIJGHGIHIJJJJJJJJJJIIGGHIHHHFDFFEEDDDDD@CCDCABB<:ACADEDDDD at D@BDDDDDDCECDDBDDDDDDDD<CACCCCCCCCCDDDDBD>CDDDDCCC>CACCCBB at BDD><B>A at C><A
+ at HWI-ST1106:815:H154GADXX:1:1101:1890:2219 2:N:0:GCCAAT
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTATCTTCCCTGCTGATAGAGCTTTACATAGCGAACTACTTCTTCACTCACGCGGCGTCGCTGCATCAGAGTTTCCTCCATTGTGCAATATTC
++
+ at CCFFFFDHHHHFGGHJGGIIIIIJGIJJIBHIGBHIIHIHIIHHHHHHFDFFFDDDDDDCDDDEDDDD@CDDDDDDDCCDDDDDDDCCDBDDDDDDDCCCCCCDCCDDDDBDDBDDDDDDDDDDDCDCDDEDCDDDACDCDDECDDDED
+ at HWI-ST1106:815:H154GADXX:1:1101:1802:2224 2:N:0:CGTCAA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGTGGCTTTTTCTCCAGGTACCGTCACGTCCTTCGTCCCTGGTAAAAGAAGTTTACAACCCGAAAGCCTTCTTCCTTCACGCGGCGTTGCTGGGTCAGGGTTTCCCCCATTGCCCAATAT
++
+@@?DDBDDAFF:@E;EGIEFGI8F>GHG@@HHGIGEGHIGIGI>EA?EAE>B<59AA>B at BBCCBCBBBCCBC(::>C8(+:>@DCCACBBB<<><?BCCA:@C:>CCCCBBBBBBB9@@>A38?CBCCB38?>CCCB<CCC at 3>@@CAC
+ at HWI-ST1106:815:H154GADXX:1:1101:1840:2224 2:N:0:GTCGCT
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACGGGTATGCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGGCCAT
++
+@@@FFFFFGHHGHIGJIJJJJJIFHBHGGIJIGIIIJJJJJHHHHHHHDDFFFFFEEEEDDD>@DDDEEDDCCDDDDDDDDDDEDDDDDEEECDBDDDDECCCDC?BDDDDCDDDDDDDDDDDDDDCDBDDDDDDDDDBBACCDDCDBDD
+ at HWI-ST1106:815:H154GADXX:1:1101:1923:2228 2:N:0:AAGCGA
+CCATTACTGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTTCTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATAT
++
+ at CCFDFFFHGHHHJJIIHJIJJGEGGIJJJHIIJIHGIIJIJJIJIJJJIDDGGHFHHHFFFFFFFACCCEDDC@CDDACCDDCDDDDCCCBDBBBCDDDCCCCBBDDDDDBBDDDDDBDDBDCDDCDCA+2<:>>AB<AA@>CCDC@>A
+ at HWI-ST1106:815:H154GADXX:1:1101:1769:2229 2:N:0:TTAGGC
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATGCTTATTCATAAGGTACATACAAGCTCCCACACGTGGGAGGGTTTATTCCCTTATAAAAGAAGTTTACAATCCGTAGGACCTTCATCCTTCACGCTACTTGGCTGGTTCAGACTC
++
+CCCFFEFFHHGHHIIJIJJJJJJJGJIIGJJJJIEHIJHJIJJHHHHHGHCFFFFEEEEDEDDDDBDDDBBDDDDDB+<@ADDCDCDDCDACDDDB<C>CD>@ACCCCDBD?BCAACCCDEDCCCDDDDBDDDCDCDDCBD?@CCCDDCD
+ at HWI-ST1106:815:H154GADXX:1:1101:1997:2231 2:N:0:TAGAAG
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTATCTTCCCTGCTGATAGAGCTTTACATAGCGAACTACTTCTTCACTCACGCGGCGTCGCTGCATCAGAGTTTCGTCCATTGTGCAATATTCC
++
+B at CFDFFFHHFHGIJJJJJJJIGHJJJJIIIJJ0@FHICGIJHHHHHGHDCFFCDD(>CDDDEEDDDDDDDDDDDDDDDDDDDDEE:AB>D9ACDDDDDDD3>CDCCDDDDDDDDDDDDDDDDDD:4 at CDE08@@DEEDDDDEDDCDDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:1965:2235 2:N:0:CCACTC
+GCTGCGTTCTTCATCGATGCCGGAACCAAGAGATCCGTTGTTGAAAGTTTTAATTATTGTTTAACTAAAAACTCAGACTGCAAACTTCAGACAGTGTTCAAATGTTAGTCTTCGGCGGGCCGTGGCCACGCCGAAGCAACAGGGTACAGA
++
+@@@DF<?DHHHHDIIJJJJIJJIJGHGIGIIIIIJJJIHIFFGIIJJGGHIEGIJIJIG?EFFCDEFFFDACEEDDDDDDDDCDDDDDDCDDDDDCDDCDD>>@BCCCC at CDDABDB9@>B at BB@>A?<>BB<<930>C?A8<???@>@>
+ at HWI-ST1106:815:H154GADXX:1:1101:1871:2243 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAAAGGCACACGTGCCTCACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGACTC
++
+??@DDEFFHHGHHHIGIIIIJJJJHHIGIIIJJGIHIIIJFHHHHHHHDDDDEEEDEDDDDDDDDDDDDBDDDDDDDACDDDDEEDBDDDDEECDBDD@>>:ACCC<<BDDDDBCDDCDDECDDDDDDDDDDDDCCDDDDDCCDCCDDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2118:2199 2:N:0:CAGCAC
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTATCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATTCC
++
+CCCFFFFFHHFHHJJJJJJJIJHHIJJIIIJJJJIJHHCCECDDDFEEEECEDDDDDEEEDCFEDDD:2+>C4 at A3::CDCCDD@>CDDDDD@(>CDDDDDA55?BCDDDDDDDDDDDDDDDDDDDDCBDDDDDDDDDDEDDECCCDCDE
+ at HWI-ST1106:815:H154GADXX:1:1101:2145:2206 2:N:0:CTATGG
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTCTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATTC
++
+@@@FDFFFHHGHHJJJIJJJJJ:DHHJJJJJJGIEIJJEIJJGIIFEEHHHFF?BDEDEA>>CDDDDDCBDDDCCDACDACCDDDDECCDDDB at DD@CDCD@?@DBDDBBDDDBBDBDDBBDDDDCA?3<<CC@<9 at CCDDCDD:A at CED
+ at HWI-ST1106:815:H154GADXX:1:1101:2188:2208 2:N:0:TGACCA
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGTGGCTTATTCGCCAGGTACCGTCTTCTACTCGTCCCCGACAAAAGAAGTTTACAACCCGAAAGCCTTCTTCCTTCACGCGGCGTTGCTGGGTCAGGCTTGCGCCCATTGCCCAATAT
++
+ at CCFFFFFHHGHHIJJJJJJIJJIJJIIJJJJJHIIJJJJIJJJHHHFFCDDEDDDDDDDDDEDDDDDDDDDDDBDDD@DD at CEEDDDDDDDDDDDDDDDDCCDCDDDDDDCDDBDBDDBDDDDDDDDDDDCDDDDDD@DCDCCDDDCCD
+ at HWI-ST1106:815:H154GADXX:1:1101:2116:2218 2:N:0:GAACCT
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTATCGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTGCATCAGGGTTCCCCCCATTGTGCAATATCCC
++
+@@<DDFFFHFHHHIJIJJJJJHHIGIJJIJJJJ at FHIJJJGJJJE??EHFFEBBBCDDCDA=A=?B@:<A?59;<BB?(+::(+>C9A5+89BAB?CCA@>4>@C<325090&055505<?@C::>A9??4 at AB@<<CDEC>>>AA:>@C
+ at HWI-ST1106:815:H154GADXX:1:1101:2046:2228 2:N:0:TTAGGC
+TTCAGGTCATAACTTTTGATCTTGCAGGCATCGCCGGAATTTCCCTCCACGGTATAAACACGGCTGCCATCGGTGCCGACAACAATTCCCACATGGTCTGCGGAACCATCCAGATCCCAATCGAAGAAAATGGCATCACCGGGAGCGATG
++
+@@@DADADFHHHHIIIIIIAHHGH at GGCAFIHIIIIIIIIIIHFGGCHIIGIHIHFEEHHFFFDDDBDDDCB@BDDCDDDDDDD?CDDDDDBDDDCCDCCCDB at B9@BC>ACCCCC at CCCDDDBDDB(9<>@ABC>?CAABB>9>@@>?<
+ at HWI-ST1106:815:H154GADXX:1:1101:2092:2229 2:N:0:AGTCAA
+CCATTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAAAGTCTCACGAGACTCACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCATCCTGCACGCTACTTGGCTGGTTCAGGCTC
++
+@@@FFDDDHHAHHGIIIII?BGIDHIGGDFHIIIIIIIHCEHEHHHHHFBEFBDCCEECABB at CDCECB?=@BCCCCC@:@CC4 at ACCCCCDC@>BCCC:@>:>A:<9 at CCC@???>9 at BBC:@CACCBBCBB>@@CCC<@+:@C at CCBB
+ at HWI-ST1106:815:H154GADXX:1:1101:2195:2237 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAATCAGGTACCGTCACTATCTTCCCTGCTGATAGAGCTTTACATAACGAATTACTTCTTCACTCACGCGCCGTCGCGGCATCAGAGTTTCTTCCATTTTGCAATATTC
++
+@@@DFFFFHHHHHIJJIHIJJJJJJIJJJJJJJJJJJJJJIJJFHHHHGFEFFFDDDDDDDDDFECDDDDDDD>CCDDCCCDDCDDE###############################################################
+ at HWI-ST1106:815:H154GADXX:1:1101:2147:2238 2:N:0:CTACGG
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTATCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGCTTTCGCCCATTGTGCAATATTCC
++
+@@CFFFFFHHGHHIIJIIJJJJ8BFHIFIJJJJGGIJJDGEHGGGEHHHAEDFFDDEEEE;ACACDDDDDDACDCCDCDDDDDDDEDCD<>>BDDDDDDDDDBDB>CDDDDDBDDDDDDDDDDDDDCACDDD7>BDDDDECCDAC>CD>@
+ at HWI-ST1106:815:H154GADXX:1:1101:2498:2195 2:N:0:CTACGG
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATAATACATACAAAACAGTATACATACTGCACTTTATTCTTATATAAAAGAAGTTTACGACCCATAGAGCCTTCATCCTTCACGCTACTTGGCTGGTTCAGGCTA
++
+@@@D;DDDDDFFFFEIIFE)?FDGD at FFFICFIIIIBEDFIEFFFFFEFEEDD@D>@;A at A??5>>D;AABABDBBBBBBBBBDDDBBBED at AB@B?B:>@@ABB<<BBBBB at B@<ABBBED at BABBBBBBBBBBB<ABB5?@@B>BB?B
+ at HWI-ST1106:815:H154GADXX:1:1101:2263:2198 2:N:0:ACTTGA
+TTCTACAGCGTCTTTCAAGAAACGACCAAGTGTTCGATAATCATGGTGCAAAATTTCACCTACACGGTTACGACTAGCCATTGTTCCGATGTTCACACGTGTGCCGGGGAAACCTTTGATATTGTTGAAAGTCATAGCTGGTCCTTCTTG
++
+1+1ABBD:20<:<E?EEBFCE;+CF??CDD4?:??B8B?DD>B<??CD4BCBDE@@@DA7 at 7)77545;=;;;9??;<=A:>>5:A>29?524>+4>45<2(+4455)0098>8>:>4(4>>:AA><((+:4>A>BAAAA?>A#######
+ at HWI-ST1106:815:H154GADXX:1:1101:2307:2201 2:N:0:TGGATT
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTATCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGCTTTCGCCCATTGTGCAATATTCC
++
+=;?DBDDDHH>DACHGIFHIII?DFEEGFHGIG7 at FEGIIIGGGCHEHCECE>;>BACC;@CD at C?C@?CCCCCCACC:@@ACCA>A999BBBCCCCC:>@8>>?@CBBBB<BBBBBBBBCCC at CC?BCCCB>99<C@@@CCDCCCC at C:
+ at HWI-ST1106:815:H154GADXX:1:1101:2283:2204 2:N:0:CTACGG
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATGGTACATACAAAATGGTATGCATACCAAACTTTATTCCCATATAAAAGAAGTTTACAACCCATAGGGCCGTCATCCTTCACGCTACTTGGCTGGTTCAGGCTC
++
+===A;2?<00?=AA?ABB*5??AA4=AAAABB<A<AABBBBABB>=AA>;77;))6>@@A>5--(--5;9;?:??59??9:?8=?88383;??:;<;???;88;:==.838:?;79;;;;<????((++8589???88====?#######
+ at HWI-ST1106:815:H154GADXX:1:1101:2453:2206 2:N:0:ATACAC
+CCATTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAAAGTCTCACGAGACTAACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCTTCCTGCACGCTACTTGGCTGGTTCAGACTC
++
+@=?DDDDDH8DHHGIFGGGGIIGGIIIIIIIIIII<AGI at CHFEHEHFEEEEEDCCACC@B?>CACDC??B@@CCCC33>CC at C@CACC at A:A:>ACCACD at C@C>25??C>@((25)0<0ACCCCCCBBB at B@CCC(:2<9 at CCC@:A:
+ at HWI-ST1106:815:H154GADXX:1:1101:2336:2209 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATTATACATACAAAACAGTATACATACTGCACTTTATTCTAATATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGGCCA
++
+@@@F1BDDFFDHHAGIIIGFGIGFIIHIEHIIIIIIIIIIIHHGFFFFHFFFFFFFEEEDCDCA@>BCD at CDDECDDDDDDDDECACCDEEEECDD?CCDC:CCDCDBDDDDDBCDDCDDECDCCCDDBDDBBCDDDCDDBCCCDDDA?D
+ at HWI-ST1106:815:H154GADXX:1:1101:2378:2210 2:N:0:CTACGG
+GCTTCCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACGGGTATACATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGGCCTGC
++
+ at CCFFFFDHGFHHGHIJDHIIJ6DDHIG?FFGIIJJJIIHHGHFGFH?CFDFFFECEEDDD>@CEEECDC?CDBDDDDCDDEDD:ACDCDEDD at BC:@CCCCDDDDBDDDCDCBDCDDEACCDCDAABDDDDDCDCCDD?ACC4:9?CB?
+ at HWI-ST1106:815:H154GADXX:1:1101:2470:2220 2:N:0:ATCACG
+AAATTGACGAAATAAACCACCAGCTGACCGAAGATGATGGCAAACTGGTTCCAGCTGACCAACATACCACGGATGTTACTAGGCGCAATCTCACCGATATACATCGGACATACAGCAGATGCCAGACCCACACCGATACCGCCAATCACA
++
+@<@DDADEHHHFHGHJJJJIIJIGGIIIIJJJIIJJJJIIIJJIJJCGHHHGIDCCGIHHEHFDFFFEEEDDDDBCDDDDEDCDDDDDDCCDCDDDBDB>D at ADCDBBDBDDCCDDDDDDDCCCCBBBBABDDDBBDBBCB@BBBCDA at A
+ at HWI-ST1106:815:H154GADXX:1:1101:2434:2220 2:N:0:CGATGT
+TAGGCTGAGTCCATCCTGGATCATTTGTAGTTTCTTCAGAAAGTATATCTTTTCCCTGAGTAGCAATATTAGCATGTTCTCCCTTTTCTATTTTATGCTTGTCAGGAATACCAGTATAAGTTAATGTATGAAGCACTCGAATATATGATT
++
+88+4=22ABDFDFDAFGIFGEFA at FIH?EHEHCEGFIB>CGGIBCFB at FFF?<BFCGEAF?BDFDBFICG=;=FFD at EECC7C>E3=CEDBBDD:@>@ADA6>>@?;?A:>@BB>A:;@A5>;AABEBDB3:@BA?@B<834?ADB at DA:
+ at HWI-ST1106:815:H154GADXX:1:1101:2285:2223 2:N:0:CGAATA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAAAGCCACACGTGGCTAACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGACTCT
++
+@@@FFFFFHHGGHJJJJJJJJJJJJJJJJJIJJJJJJJJJJHHHHHHFFFDEDFEEEDDDDDDDDDDDDDDDDDDDDEDDDDDEDDBBBDEEDDBDDCDEEACDDBDDDCCDDDDDDDDEDDDDDDDDDDDDDCCCDDDD?ACDDDDCDC
+ at HWI-ST1106:815:H154GADXX:1:1101:2390:2234 2:N:0:ATACAC
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTTTCTTTCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCACTCACGCGGCGTTGCTGCATCAGGGTTTCCCCCATTGTGCAATATTC
++
+@@@DADFFHHHHHGIIGFGGBHHHGJIGII at GIJJJHHHHFC@DFDFA@@CCE@?B@@DFEDDDD at A>:@CC>@ACDDDCCCCCC at C>?5<9>ACCA@>@CD at ACD?CDBDB9>59 at BDDDD>ACCCBCADD:ACDBCCDDCC at CCACEE
+ at HWI-ST1106:815:H154GADXX:1:1101:2331:2236 2:N:0:CAGCAC
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGAGCTTATTCTACAGGTACTGTCTTGTTTCTTCCCTGTCTAAAGCAGTTTACAATCCGAAAACCTTCTTCCTGCACGCGGCGTCACTGCGTCAGAGTTTCCTCCATTGCGCAATATTC
++
+@@CFDFFDFFFFHIJJJGHIGIIIGGIIIJIGIGB at GGGIJHCE=CECDCDF?AC;C;.65;(;A(=CCDCDDDDD::A53:@:>((+958?>BC?3>(4>A:@C:AC?30<B at BB5<:@AB at BDB@#######################
+ at HWI-ST1106:815:H154GADXX:1:1101:2413:2237 2:N:0:CAGATC
+TACATCTCTTCTCTCCTAATGTTAGTTTTAGAAATAAAGACAGAATCTGCGACCTTCAATCTCACAAATTCGTATGTCCATTTCGTACAATTCGTCCAGTACATCTTTTTTTATCATTTCTTGGGTCGTTCCTTGCGTGAATAACTGCCC
++
+;+1?1<+2<2?,<,2?+2A+<,,?@C?7A7?<=+?@?ABBBBB=7=0?:4?<)7:=7>AB>A4=AB;67===AA>>)>???#####################################################################
+ at HWI-ST1106:815:H154GADXX:1:1101:2368:2242 2:N:0:TCCTCA
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTTCTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATAT
++
+??BDDDDFHHFGHHJIHHHJGIJIGIJJJJIIJIABHHHIGHJIGIGFHAAABBFDDEEFEEDDDDDCDDDDDDDDDDCDDDDDDCDEEDDDDDDBDDDDDDCCDDDDBDBDDDDDDDDBBDDCDDDDCD3<@@CCC at BDDCACDDDDCC
+ at HWI-ST1106:815:H154GADXX:1:1101:2491:2246 2:N:0:CCTTAA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGAGCTTTCTTGAAAGGTACCGTCAGAACTGTATCATTTCCTATACAGTTTGTTCTTCCCTAACAACAGAAGTTTACAATCCAAAGGACCGTCATCCTTCACGCGGCATTGCTCGTTCA
++
+@@BDDDEFDHGHGIJJJJJIJJHIIIJJJJJJJBHIJJIJJHHEFHHFCBDFCCDB at ACCCCCDEDE@CC;@CCCCCDDBCDC?C:@A@:<CCCBCABAB>AACCDD at C:>C9:ACC98AABDD<A:>CCDCCBB>@D3>CC<@CBBDBC
+ at HWI-ST1106:815:H154GADXX:1:1101:2525:2193 2:N:0:CAGATC
+TTCTGAATAAAGGGAAACTTGTGCACTGACAGTAGAAGCCCCAGAGATATTTTTTTGCTGTTTGATCAATTCTAATGCACTGTTAAAACATGCACTGAAACCAGCTGCAAACAATTGTTCAGGGTTGGTTGCATTTTCGACGCGTTTACC
++
+@??DBDDD?F<ADEDGH;?+<FGFFHIE<FCGFGGGII<GGGHIII at HG?B8BD@;@DAHHA?A=?EC at CCB?DDAC>A at ACAC>C at CABC@A at ACC::@42<?BCC?+::82+4>C>@>@@AB329B2?<@>@>AC39<<>55509<C3
+ at HWI-ST1106:815:H154GADXX:1:1101:2680:2193 2:N:0:GAACCT
+GCTTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAAAGTCTCACGAGACTAACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCTTCCTGCACGCTACTTGGCTGGTTCAGGCTCT
++
+@@@FFFFFHHGHHJJJJJJJJJJIJJJJGGIIIEHIJJJJHHHHHHHFDDFFFFEEEEEDDDDEDEDDDD at BDCDDDEDDDDEEDDDDDDEEDDDDDDDDEACDDDDDDDDDDDDDDDDBCDCDDCDDDDDDDDDDDDDDACDDCCCDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2516:2210 2:N:0:TAGCTT
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATGGTACATACAAAATTCCACACGTGGAAAACTTTATTCCCATATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGACTCT
++
+<@<B?BA?DDFHFIIIHGGH9 at AFGCD>FGFH<;8DHI at G@EEEHBHF??BECDD66 at CCC:@CCCB?<<<@CCCCCCC at CCA>CCCCCD>@CABBCCCDD@@CA<>BC9>A<CBBCCCEAC at CCCCBBBBBCCCCCCB<?CCCA>@>CC
+ at HWI-ST1106:815:H154GADXX:1:1101:2713:2212 2:N:0:TGACCA
+AGATTGCCACCTCCGTTGATATTATATGTCACTATTCCATTATTGGGACCACTAAACTTTATTAAGGAAGAAGAACCTGAACAAATTGGACTAGCGCCATTAATTGAAATTGTAGCCGTTGGTGTTGAACGAACTGTTACAGCTGCGCTA
++
+?@@D?DFFGGHHGJJHGHGIIJJJJJJJIHIIGIJJIIIIIEHCHGIJJIIJJFHGIIJIJJJIEDEHIGECHHGEHFEBDEFDEEEEEEDDDDCBDDDBCCCADDCACDDCDECCDD at BDD?<<BBAACD<@@DDCACCDDCDCCBBDB
+ at HWI-ST1106:815:H154GADXX:1:1101:2678:2222 2:N:0:CGCTGA
+GCTTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAAAATCTCACGAGACTCACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCATCCTGCACGCTACTTGGCTGGTTCAGGCTCT
++
+@@@FFFFFHHGHHJJJJJJJJJJJIJJIIJJJJJJJJJJJHHHHHHHFFFFFFFEDEEEDDDDDDDDDDDDDCDDDDDDDDDDDDDDDDDDEDDDDDDDDCCCDCBDDDDCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCDCDADBDC
+ at HWI-ST1106:815:H154GADXX:1:1101:2588:2225 2:N:0:CCTTCT
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACGGGTATGCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGGCCA
++
+@@@DDFDFHHGGGIJJJJIIJJIIEHFHIJJJJJJJJJJJIHHHHFHBEDDFFFFEEEEEDDD>BDDDEEDCDDDDDDDDDDDEEDDDDDEEDDDDDDACD:ACDDDDDDDDDDDDDDDDEDDDDDCCDDDDDCDDDCDDDCCDDDDDBD
+ at HWI-ST1106:815:H154GADXX:1:1101:2713:2231 2:N:0:TGACCA
+AGATTGCCACCTCCGTTGATATTATATGTCACTATTCCATTATTGGGACCACTAAACTTTATTAAGGAAGAAGAACCTGAACAAATTGGACTAGCGCCATTAATTGAAATTGTAGCCGTTGGTGTTGAACGAACTGTTACAGCTGCGCTA
++
+@@@FFDDFHHHGGJJHIJJGJHJJJJJGHHIJIJJJIJFJJIGHIJJJJIJJJIIIEIIJIJJGHGHCAAGGGIFHHEHCDFEDEEDDEEDDDDC>?DDD at AC@DC>>@CCACDCCCB@<@D88<@B>@CA<BBDCCCDCCD at CDA<>BB
+ at HWI-ST1106:815:H154GADXX:1:1101:2557:2232 2:N:0:CAAGAA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACGGGTATCCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGATCAGGCTCT
++
+=1?DDBBAD@))@EEDDB;D*?DAADIEDD?AD at ACDEICDDDDCC>=.???D at A;AA63=?3,5(,>(;(55555>8>AAA:::3:>>DD>AA(894:>AAAAA85<>94:><?9?>>A(4:>4>>815<;AA>A>><>(4:2+49<?A
+ at HWI-ST1106:815:H154GADXX:1:1101:2740:2237 2:N:0:AGTTCC
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTTCTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATAT
++
+@?BDFDFFHHGHGIJIJJJJJJIJJJJJJJIJJJHHIJIJIJJJJJGHHGFHFFFDCEEFEEDDDDDCCCDDCCCCDD:CDDCDDDDEECDDDBDDDDDDDACCBBBDBDDBDDBBDBB at BDBCDCACCD<ABDCDCDDCCC at CDCCACC
+ at HWI-ST1106:815:H154GADXX:1:1101:2527:2244 2:N:0:GTTGAA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAAAGGCACGCGTGCCTCACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGACTCT
++
+BBBFDFFFHHGHHJJJJJJJJJGGIJIIJJJJJJJJJIJIJHHHHHHFFFDDEEEEDDDDDDDDDDBB>BDBDCDDDCDDDCD at C>?@BDEEDDBDDCDEECCCD?>DDDDCBDDDDDDECDDDDDDDDDBDDDDDDDDDDDDDDDDCDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2603:2248 2:N:0:CAGCAC
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGATGCTTATTCCTTAGCTACCGTCACTGTCTTCGTCACTAAGAAAAGAAGTTTACAATCCGAAAACCGTCATCCTTCACGCGGCGTTGCTGCATCAGGGTTTCCCCCATTGTGCAATAT
++
+B??DDDEDGHGHGIJJJIJJJIGHGGGGHIJJJJJJIJGJJJGIJJJHHHHHFFFCDEC at CDDDBCDDDDDDDCDDDDDDC:@DECDDDDDDDBDBC?@?B at BDDDDDCDDBDDDDDBBBDDDCCDDDCD(2<:4>ABBDDC at CCDD@@A
+ at HWI-ST1106:815:H154GADXX:1:1101:2853:2195 2:N:0:ACTTGA
+AACTATAACTCTTTCCAGGAACTAAATGAAAATCCTATTTTCGCAGATGTTAGCGTATACAATCGTACAGTCATGACACCACAAAGTCTTCCGCATGTAGTAGATGAAGCCATTAAAGCCGCCTATGAGCATAAAGGCGTGGCTATCGTG
++
+=++AB?A::CDADEEIIEEECF9CF at FEEFCEEIIEEEFIDEDIIIIIIIIAE9@ADDDEE at CCCDDDDC=ACDDDAA;=>?;5>>AAAAAA???=?AEED:::>>A>AA?9>>A4>>A<>>;;?AAAAAAAA(+4><;59?>>A>>8<>
+ at HWI-ST1106:815:H154GADXX:1:1101:2884:2198 2:N:0:TGGATT
+CCATTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTACATGCAAAAAGTCTCACGAGACTCACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCTTCCTGCACGCTACTTGGCTGGTTCAGACTC
++
+@@@DADDDDDADHIHBHHGDIIGGIIJIIGDFGGJJJEHHICAAEEHHD at DFDDCAAC>CA?CCEACCDDD@?CDD>ACDDCDDA at CC@CDEDCC8AACCC at ACCCDDDDCCCDCD@BBB?@CAC@?CDDBDBC@@CCDBDCACACACDD
+ at HWI-ST1106:815:H154GADXX:1:1101:2751:2204 2:N:0:AAGCTT
+GCTGCGTTCTTCATCGATGCCGGAACCAAGAGATCCGTTGTTGAAAGTTTTAAATAATTTATATTTTCACTCAGACTTCAATCTTCAGACAGAGTTCGGGGGTGTCTTCGGCGGGCGCGGGCCCGGGGGCGTGAGCCCCCCGGCGGCCAG
++
+ at B@FFFFFHHHHGIJJJJJJJJJJHIIIJJIJJIJJJIHJFHIGIIHHHIJCHIEDHHHHHHGHHFFFFFFFEEEEEEDCACDDDEEDDCDDACCDCBDDD at B@BCDDDDDDDDDDDDBBB<B>5<BDD>>@@BB?ABDBB<BB<B####
+ at HWI-ST1106:815:H154GADXX:1:1101:2785:2207 2:N:0:AAGAAG
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCCTAGTCAGGTACCGTCATTTCTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATAT
++
+?:??DDFDHFAFHCFHIIIIGEDBB0?BFFDFHHHEIFC@)>)=C>CAE?=;@DB?BBDCCD;;CCC>?C>2:>>(,,:ACCCACCCDEC<9<5<<@>CCC>C:A<@B3 at BA9@799<>BBD>C at CDCDD3<@DAAC9<<CCAA>4>@@>
+ at HWI-ST1106:815:H154GADXX:1:1101:2938:2209 2:N:0:CAGATC
+CCAAGAAGGAATCGATTATTTGGCAGGCCTGCCGGATAGCCATCCAAAGGTCTTGATAGTAAAAGAAGGAAGATATGATGAATATATAGAAAGCAGATTATCCAATTTTAAACTTGTGGGAGCAGGAACAGTAGTTATCTCCGGTAATCG
++
+@@@BDDADHD8<FH>FHG<3AFF9EHIGIFEHCFBFGEGAGIIEHIB<FH)@CEGDGHIGHH7=A-?@@;;@@>:>ACDCECDDDDD<A>CCCC??C3>CC>@CCCAAC>C::@@:A4852<>BC at B?18?@(:44:>A3(:5595?C@?
+ at HWI-ST1106:815:H154GADXX:1:1101:2969:2210 2:N:0:CGTCAA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACGGGTATACATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGGCCTG
++
+@@@FFFFAFDFHHGGDEHIIGGIEADGGEGII:;AHIICDE=9?7CEH;?>;>@CCEEAB at B>=CCCDDD at C@@5908C>ACCDDC>>@CDECC at BA:ACDCCDD09?ACCCA<?9C?CDCCACCCDDB>B<@CCCCCBD<AAAACCDD@
+ at HWI-ST1106:815:H154GADXX:1:1101:2909:2214 2:N:0:CCGTCC
+TTATCAAAACTTATCTTATTTTCGAAGTAAAAGTTGAAGCTTTGATGGGGTAAATATAAAAATATATTTCAGATTTTTATTTTTTAAAAACAAATAAAAGTAAAGAATTTCAACTACAAGGTTGTAGTAATGAATAAATTAACAAATAAA
++
+@@@FDDA;?CFDFFHIIBHHFFBE;FHGDHCFH?CFEFFDGGHGAFHGGDFFCGHIHGB at FCFFECGHIGIIGGEGHIGHHCA?BDA>A@@B?BC@>A:A>>@ACCBDDCCDCDDC@@>A?@:?<CCDDEDDCA:C>C:@>>CDCBDDC@
+ at HWI-ST1106:815:H154GADXX:1:1101:2888:2222 2:N:0:GTCGCT
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTTTCTTCCCTGCTGATAGAGCTTTACATACCGAGATACTTCTTCACTCACGCGGCGTTGCTGCATCAGGCTTTCGCCCATTGTGCAATATTCC
++
+<???BB3DDA:8DEEEE<;19 at 0??DDEDCDIIADADDCDDDDDD>AAAAAA?????DAD>AA>><>A>AA:>AAAAAAAAAA>DBA<?>>>?AAAAAA>A>>AA>A?<>>555;>>AAAAAAAAA><<A>>3)59AAA4>AAAAAAEEA
+ at HWI-ST1106:815:H154GADXX:1:1101:2873:2233 2:N:0:ACTTGA
+TCTGCAAGCACTGGTCCTTTGGCTAGTTCTGCTTGTCCCTTTGTTTCTTCATTTAAATGAACCGTTCCAGATACAGGAGCTTTTAGTATTCCTTTTGAAAGTTGATCGTCCAAACTTTTGATAACTGACTGGTTCTTCTCTTGTTTTTCA
++
+:>=2+27AC==<?+2222<33 at 3<3?C at 72?*:?A:1:?BBBA7?A4?A=A<7A=A*?*/99(7-;AA;>77;>>AAAA@@@@@@>>@>>@9=5=?>;;:5;;9=?3559(2(8;=??:38;:????((889?;????=?=??#######
+ at HWI-ST1106:815:H154GADXX:1:1101:2990:2243 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCACTCACGCGGCGTCGCTGCATCAGAGTTTCCTCCATTGTGCAATATCC
++
+@@@DDDFFHGFHGHIIJIJJJJIHIIGIIJJJJIJJHHHHFFFFEFFDDCCECDDDDDEFEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCDCDDDDDDDDDDBDDDBDDDDDDDDDCCCCCDCCDDDDEDDDDECDCDEC
+ at HWI-ST1106:815:H154GADXX:1:1101:2791:2243 2:N:0:CAGATC
+ATTTCTCAATCTTTTCTCTCCGTTGGGATAACAACGATTATGTGGGTATTTGGTGGATTCGGATTGGCCTTTGGACGGGATATCGGCGGTGTTATTTGTAAACCGGCGGGTTTTTTTTTGTTGAGGCATGTTACAAGCTTCCCCAACACG
++
+??=DDBDDHHFHHIIIIEHHIICFEEHGHIIHFHGGFHF=GE0BDG6?DGIH<F at F=CEG=(;EH36??D at BCCCCB@8?BCCCBBB###############################################################
+ at HWI-ST1106:815:H154GADXX:1:1101:3046:2196 2:N:0:AGTTCC
+CCATTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATGGTACATACAAAAATCCACACGTGGATAACTTTATTCCCATATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGACTC
++
+@@@DDFFDHGFHHHIJJJJJJIIIIIHHCHHJJJJJJIGGIHHHHHHHFB at DFFFEEEEDBDDDDDCBDBBDDDEDDDEDDDDDDDDDDDECEDDBBD@>C:ACDDBDDDDDCBDDDDDDEDCCCDDDDDDDD at CDCCDDDDDDDCDDC:
+ at HWI-ST1106:815:H154GADXX:1:1101:3147:2203 2:N:0:GGCCTT
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTGTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCACTCACGCGGCGTCGCTGCATCAGAGTTTCCTCCATTGTGCAATATTCC
++
+@@@DDDFFGHHFHGHJJIJJJJBDFHIIJIJEIGGGIJJJIJHGHGHGHEFFFDCBBDDDDCDDDDDDDDDDDDDDDDDCDDDDDD at CBB>@DDDDDDCDCCCDDDDDDDDDDDDDDDDDDDCDDCCADDECCCDDDDDDDDECCCDECA
+ at HWI-ST1106:815:H154GADXX:1:1101:3211:2211 2:N:0:AGTGGT
+CCATTACCGCGGCTGCTGGCACGGAATTAGCCGGTCCTTATTCATAAGGTGCATGCAAAAAGTCTCACGAGACTCACTTTATTCCCTTATAAAAGCAGTTTACAACCCATAGGGCCGTCTTCCTGCACGCTACTTGGCTGGTTCAGACTC
++
+@@CDFFFFHHHHHIIIJIJJJJIJJIGIJIHIJGIJJJJJIHHHHGH7??);@CECEEDCBD5 at CCDDBDDDDDDDDDCDDDDEEDDDDDDDEDDDDD@AD:ACCCBDDDDDCDD?BBBABDDDDDDDDDDDDCDDDCDDBCACCCCCCC
+ at HWI-ST1106:815:H154GADXX:1:1101:3127:2215 2:N:0:ATCACG
+GCTTACCGCGGCTGCTGGCACGTATTTAGCCGGAGCTTCTTAGTCAGGTACCGTCACTATCTTCCCTGCTGATAGAGCGTTACATAACGAATTACTTCTTCACTCACGCGGCGTCGCTGCATCAGAGTTTCCTCCATTGTGCAATATTCC
++
++=1AA+A<<)=?7?=<?BA=<:)00=BA?ABAAAAAAB>B>>A>A)=AA>;>',35;=3;;==;?==:;95:9(5::(&0;903:=3;229(8??8=83=:8;=?9(+2)95&00)&&503+(+88:5;?:????73;??:;:??:3;??
+ at HWI-ST1106:815:H154GADXX:1:1101:3233:2216 2:N:0:TTGGTA
+GCTTACCGCGGCTGCTGGCACGTAGTTAGCCGTGGCTTTCTGGTTAGATACCGTCAAGGCGCTAACAGTTACTCTAGCACTTGTTCTTCTCTAACAACAGAGTTTTACGATCCGAAAACCTTCTTCACTCACGCGGCGTTGCTCCGTCAG
++
+@@?DD?DDAAFHDFB?GHHGGG?FFBHH at FHEHGG8@FDGCEHCE>EHH>;C8,9?B>C<?B:8;C3>>@ACCCACCC at CCC@:>>@CCA>CCCC@>18@?9+:@:ACB8++<@7<3>9(9(3::>>:CC39??9<9B at B&&>::><?<>
+ at HWI-ST1106:815:H154GADXX:1:1101:3185:2216 2:N:0:TTGGTA
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCACTCACGCGGCGTTGCTGCATCAGGGTTTCCCCCATTGTGCAATATTC
++
+@@@DFDDFHGFHHJJIIJJJJIIDGHIIJJIIJJJJHHHGDFFFFFFEDCCEED at BBDEEDDDDDDDDDDDDDDDDCDCDDCCCDDDDCDBDDDCDDDDDDCDDCCDDDB>@BD@>BBDDCDDDDDDB38<@CDDBDCCDEDCECCCADD
+ at HWI-ST1106:815:H154GADXX:1:1101:3012:2219 2:N:0:GTCGCT
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGGGCTTCTTAGTCAGGTACCGTCATTTTCTTCCCTGCTGATAGAGCTTTACATACCGAGATACTTCTTCACTCACGCGGCGTTGCTGCATCAGGCTTTCGCCCATTGTGCAATATTC
++
+@@@FDFFFFHHHHJJIJIIIJIJIGHJIIJJJJIJJHGHHFFFFFFDCECEECDDBDBEDEDC at CDDCCBDDCDDC@C at ACCCDC>CCDB<BDDDDACC>A at CCDCDCBDBBDB<@@>@CCCCDCCA?<CCDDDDD<?CDDDCDCDDCDB
+ at HWI-ST1106:815:H154GADXX:1:1101:3071:2234 2:N:0:CTACGG
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATACGGTACATACAAAGGAGTATGCATACTCCACTTTATTCCCGTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGACTCT
++
+=>=AA77AA8AC<?A>**1)?AAA:/0?=?AAAAAABBA)=>A>AAA=@=/>>@>>@??===(5;:>??=??55;<??:?;??38)25;;?(8=<988;:;388(859=8:;=9<0838=:??????=<;;;:8=???############
+ at HWI-ST1106:815:H154GADXX:1:1101:3245:2235 2:N:0:CCTTAA
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTATCGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATCC
++
+@@BDFDDFHHHGHIJJJJJIIJIDGCHIJJIJJJIJJJJJJJIIHHHHHFCEFFDDCCEDDDDDBBBDCDDDB>@B?ABA?ACCC at CACBBBDDCBCCCCCCCCCCDDD<>@DDDDDBBBBACCDCD<38<>C>?@BCCCDDCD:@ACCC
+ at HWI-ST1106:815:H154GADXX:1:1101:3136:2239 2:N:0:TTGGTA
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTATCGTCCCTAACGACAGGAGTTTACAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATCC
++
+@@@BDDDFHHFHHGGIJGIIIIIHHIFHIIIIJJIGIIJJJIIJHHGHGFEFFFDCDEEDEDDDDDDDDDDDDDDDDDB?CCEDDDDDDDDDDDDDDDDACCCDDCDDDDDDDDDDDDDDDDDDDDDD9??CCDDDDCCCDDDECCDDCD
+ at HWI-ST1106:815:H154GADXX:1:1101:3036:2243 2:N:0:CAAGAA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATAAAGTACATGCAAACGGGTATCCATACCCGACTTTATTCCTTTATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGGCTCT
++
+@@CFFFFFHHHHGJJJJJJJJJJGJIJIJJJJIIJJJJJJIHHHHHGGFEFFFFFCCEEDDD;=CCCDDDDDDDDDDDDDDDCCDDDDCEEEDDBBDCDCAACCCDDDDDCDDDDDDDDECDDDDDDBDDBDDCDCDDBBCCDDDCDBDD
+ at HWI-ST1106:815:H154GADXX:1:1101:3201:2246 2:N:0:CTGTCA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATCCTTATTCATATGGTACATACAAAATTCCACACGTGGAAAACTTTATTCCCATATAAAAGAAGTTTACAACCCATAGGGCAGTCATCCTTCACGCTACTTGGCTGGTTCAGGCCTG
++
+BBCFDFFFHHGHHJJJJJIJJJIIIIJJJJJJHBAHIJJJJHHGHHHHFDFC>BDC6;?C@>CDCCBB99?8CCD?::::AD>3:AC94:(:C@??ACDAD::@C2<@?>:@BDBDDC at D@ACCDDDDDDD<>@ACD>?3(4>>@A?2@@
+ at HWI-ST1106:815:H154GADXX:1:1101:3089:2248 2:N:0:ACTTGA
+TCATACGCAAGTTTCAAATGAACTTCCTGAAAGCATTATGGACAGTATACGAGAAGTACGTGATTATTTTGAAGAGTCTACCATTCTTCAGGGAATTGACGTGATTTATGATCGACAGTTTTTGACAGAGCAGCGACGGCTTGCCGATAA
++
+@@@DDFDFH?D:DGGGIEEA<<CHH at EHEEGHIGGGGFGFH>HGGIGGIIIDAHIIEGGH at CEHGIGIIIIFECE??7?DE at C@@;@@A at AC??BBCACC=?<8ACDADCC@:?7<BB>>>A?BBCCC<??:CBB95.55<B@?######
+ at HWI-ST1106:815:H154GADXX:1:1101:3466:2192 2:N:0:CGATGT
+AAAACAAATTCAGTTTCTGAATTGTTATTCAGCGCAGGAAACGAGATGTTTCCGACTAAAATTCCGTTTGCGGTCACAGTAAGTGAGGTAGGTGTAAAAGCTGCTGAGGCGGCTGTCAGCATAATTTTAACGGTTGATGTGGCGTCAAAA
++
+@<@DDDDDFHHDDHGIIIIGIIGHHHHHGIEIFIIIIIDAH>D at FHHGGEHGGII<A at EAAHHHEEFF@AEAB?B?C at C>ACC;>3>A>>C?3:@A at BCCAC:?@CABBCCC<BBACCCCCCCCCBAC:>>?B(8<CACCCCBBBBB9>@
+ at HWI-ST1106:815:H154GADXX:1:1101:3490:2192 2:N:0:TAATCG
+CCATTACCGCGGCTGCTGGCACGTATTTAGCCGGTGCTTCTTAGTCAGGTACCGTCATTTCTTCTTCCCTGCTGATAGAGCTTTACATACCGAAATACTTCTTCGCTCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATAT
++
+@@@DDDDDFHDFDGA at BBD;CDA?DFHEIIDHIEAA at CF@CEGDDDA=C?==?BEACCDDCC at ACCC>CCCBCCCCC>@CCCCCCACEDCC>B5<8 at CC:>@C at B>985 at AB9@@<@BBB@>9ACCCC><3<?C34<9>CAC>CCCCCA@
+ at HWI-ST1106:815:H154GADXX:1:1101:3418:2203 2:N:0:TCACAA
+GCTTACCGCGGCTGCTGGCACGGAGTTAGCCGATGCTTTTTCTTCGGATACTTGCAATACACTACACGTAGCGTACTTTACTCTCCGACAAAAGAGGTTTACAACCCGTAGGGCCGTCTTCCCTCACGCGACTTGGCTGGTTCAGTCTGC
++
+?1 at DDDDDHFAHFIIIGIIGIII<DBGGFIIIGIIIIIIIIIFHH??DECCACACCCCCCCCCCCCCB?CBBBBBBBC@@CCCAC?B>BBB??>BCBCBCCCCCCB@@@5?@@?@BBBB at C@?CCB<?BB@@BBCCCC<>+:@:>>@>>C
+ at HWI-ST1106:815:H154GADXX:1:1101:3308:2210 2:N:0:TTGGTA
+CCATTACCGCGGCTGCTGGCACGTAGTTAGCCGGTGCTTTCTTGTTAGGTACCGTCATTATCGTCCCTAACGACAGGAGTTTGCAATCCGAAAACCTTCTTCCTCCACGCGGCGTCGCTGCATCAGGGTTTCCCCCATTGTGCAATATCC
++
+@@@DDDDFHFFHHGIJJHJIIIGGIIFGIIIEIEHHIIIJJJJJHGGHHE at DFFCACBEEEDDDDDDCDDDDDDDDBDD<?CCCDDDDDDB?BDDDDDDDDCCDDCDDDDDBDDDDDDDDDDDDDDDBA8?ADCCDD?ACEDDDCCCDDD
+ at HWI-ST1106:815:H154GADXX:1:1101:3481:2217 2:N:0:ATCACG
+CGATTCTGCGAGAAACCGATGAGATCGTAGGGGCATGCTGTGAAGTATTGGTTGTGAGCAACAATTCGTTCAAAGAAAGGAGTAAGGTTGTCGTCAGAATAACGGAAGTCGTAAAGTTTATAAACGTGTATTCCATCATAGGCCATATAA
++
+=7=AA,2<AA8A0=@CCA==AB*111:ABAAAAA=BAABAAAABB=ABBAA7=A-;>>AA@>@<>@356;=;;;;=5;?:====9;::39;:;8(9;=??78;<7(80+8989283+88=?;38:;288383:88888???;7:=7:;8?
+ at HWI-ST1106:815:H154GADXX:1:1101:3392:2219 2:N:0:ATCACG
+ATGGGCGGTTACGCAGAATACCGCTTCGGGAGAGCCGGCAATTTCCTCTCCAACTTCTGCTACACGATTTCTCTGATCATCGCCAACGTTGCTATTGCAAGCGGCGTTGTCAGCTACGGTTCTTATGTTTTCGGTTTCAACCTTGATCCG
++
+@@@FDFDFDF?FDHIGGIHIIJBEDHGGEGFBGIGHFF?CBCDDACCCD>CCCCDDDCCCDDDDDDBDDDCEDD>CDCCCCCDB at BD7<ABBCCDDDCDDDBB at BB<>BDDDDDDDCDDCBDDDDCD at D@?@<@8>@AB@><?ACCCAC@
+ at HWI-ST1106:815:H154GADXX:1:1101:3431:2221 2:N:0:TTAGGC
+ATGCTACCTACTCTGAAATTGACGGTACAGCAACAAGCGAAATTGCGACAAGCAGTAATGCATTAATGTTAATCCCTCAGAATGATCTATCGTCAGTCAAGATTACTGTTACTTATTCCACGACTAATGATAATGGCAAAGTATTTGAAG
++
+?==BBDFFGFHHGGIIIIFDCFC at FGHIIIIIIGIIIGHHGIFIIHIIIIIIGIIIGHFHHHGFFFFEEEEEEECECCDDDDDCDDCDCCCB?ABDDDCDDDDACCDA>CCCDDDCEAA at ABBBB<>A>CCDCCDCBC><CAABC@@:@:
diff --git a/t/test2.fastq.gz b/t/test2.fastq.gz
new file mode 100644
index 0000000..c1ac163
Binary files /dev/null and b/t/test2.fastq.gz differ
diff --git a/t/test_interleave.fastq.gz b/t/test_interleave.fastq.gz
new file mode 100644
index 0000000..511b8ac
Binary files /dev/null and b/t/test_interleave.fastq.gz differ
diff --git a/t/test_novlp_1.fastq.gz b/t/test_novlp_1.fastq.gz
new file mode 100644
index 0000000..0be8ceb
Binary files /dev/null and b/t/test_novlp_1.fastq.gz differ
diff --git a/t/test_novlp_2.fastq.gz b/t/test_novlp_2.fastq.gz
new file mode 100644
index 0000000..8696f9d
Binary files /dev/null and b/t/test_novlp_2.fastq.gz differ
diff --git a/t/test_ovlp.fastq.gz b/t/test_ovlp.fastq.gz
new file mode 100644
index 0000000..674c16e
Binary files /dev/null and b/t/test_ovlp.fastq.gz differ
diff --git a/t/trim_1.fastq.gz b/t/trim_1.fastq.gz
new file mode 100644
index 0000000..9b8ca34
Binary files /dev/null and b/t/trim_1.fastq.gz differ
diff --git a/t/trim_2.fastq.gz b/t/trim_2.fastq.gz
new file mode 100644
index 0000000..b676fed
Binary files /dev/null and b/t/trim_2.fastq.gz differ
diff --git a/t/trim_both.fastq.gz b/t/trim_both.fastq.gz
new file mode 100644
index 0000000..9b8ca34
Binary files /dev/null and b/t/trim_both.fastq.gz differ
diff --git a/t/trim_head.fastq.gz b/t/trim_head.fastq.gz
new file mode 100644
index 0000000..e275025
Binary files /dev/null and b/t/trim_head.fastq.gz differ
diff --git a/t/trim_tail.fastq.gz b/t/trim_tail.fastq.gz
new file mode 100644
index 0000000..2eb1cf1
Binary files /dev/null and b/t/trim_tail.fastq.gz differ

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



More information about the debian-med-commit mailing list