[mapguide-commits] r9523 - in sandbox/jng/mvt: . Oem Oem/protozero-1.6.7 Oem/protozero-1.6.7/bench Oem/protozero-1.6.7/bench/data Oem/protozero-1.6.7/cmake Oem/protozero-1.6.7/doc Oem/protozero-1.6.7/include Oem/protozero-1.6.7/include/protozero Oem/protozero-1.6.7/test Oem/protozero-1.6.7/test/catch Oem/protozero-1.6.7/test/include Oem/protozero-1.6.7/test/t Oem/protozero-1.6.7/test/t/alignment Oem/protozero-1.6.7/test/t/bool Oem/protozero-1.6.7/test/t/bytes Oem/protozero-1.6.7/test/t/complex Oem/protozero-1.6.7/test/t/double Oem/protozero-1.6.7/test/t/enum Oem/protozero-1.6.7/test/t/fixed32 Oem/protozero-1.6.7/test/t/fixed64 Oem/protozero-1.6.7/test/t/float Oem/protozero-1.6.7/test/t/int32 Oem/protozero-1.6.7/test/t/int64 Oem/protozero-1.6.7/test/t/message Oem/protozero-1.6.7/test/t/nested Oem/protozero-1.6.7/test/t/repeated Oem/protozero-1.6.7/test/t/repeated_packed_bool Oem/protozero-1.6.7/test/t/repeated_packed_double Oem/protozero-1.6.7/test/t/repeated_packed_enum Oem/protozero-1.6.7/tes t/t/repeated_packed_fixed32 Oem/protozero-1.6.7/test/t/repeated_packed_fixed64 Oem/protozero-1.6.7/test/t/repeated_packed_float Oem/protozero-1.6.7/test/t/repeated_packed_int32 Oem/protozero-1.6.7/test/t/repeated_packed_int64 Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32 Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64 Oem/protozero-1.6.7/test/t/repeated_packed_sint32 Oem/protozero-1.6.7/test/t/repeated_packed_sint64 Oem/protozero-1.6.7/test/t/repeated_packed_uint32 Oem/protozero-1.6.7/test/t/repeated_packed_uint64 Oem/protozero-1.6.7/test/t/rollback Oem/protozero-1.6.7/test/t/sfixed32 Oem/protozero-1.6.7/test/t/sfixed64 Oem/protozero-1.6.7/test/t/sint32 Oem/protozero-1.6.7/test/t/sint64 Oem/protozero-1.6.7/test/t/skip Oem/protozero-1.6.7/test/t/string Oem/protozero-1.6.7/test/t/tag_and_type Oem/protozero-1.6.7/test/t/tags Oem/protozero-1.6.7/test/t/uint32 Oem/protozero-1.6.7/test/t/uint64 Oem/protozero-1.6.7/test/t/vector_tile Oem/protozero-1.6.7/test/t/wrong_type_access O em/protozero-1.6.7/test/unit Oem/protozero-1.6.7/tools Oem/vtzero-1.0.3 Oem/vtzero-1.0.3/cmake Oem/vtzero-1.0.3/doc Oem/vtzero-1.0.3/examples Oem/vtzero-1.0.3/include Oem/vtzero-1.0.3/include/vtzero Oem/vtzero-1.0.3/include-external Oem/vtzero-1.0.3/test Oem/vtzero-1.0.3/test/catch Oem/vtzero-1.0.3/test/data Oem/vtzero-1.0.3/test/include Oem/vtzero-1.0.3/test/t

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Wed May 29 09:52:58 PDT 2019


Author: jng
Date: 2019-05-29 09:52:57 -0700 (Wed, 29 May 2019)
New Revision: 9523

Added:
   sandbox/jng/mvt/Oem/protozero-1.6.7/
   sandbox/jng/mvt/Oem/protozero-1.6.7/.clang-tidy
   sandbox/jng/mvt/Oem/protozero-1.6.7/.gitattributes
   sandbox/jng/mvt/Oem/protozero-1.6.7/.travis.yml
   sandbox/jng/mvt/Oem/protozero-1.6.7/CHANGELOG.md
   sandbox/jng/mvt/Oem/protozero-1.6.7/CMakeLists.txt
   sandbox/jng/mvt/Oem/protozero-1.6.7/CONTRIBUTING.md
   sandbox/jng/mvt/Oem/protozero-1.6.7/FUZZING.md
   sandbox/jng/mvt/Oem/protozero-1.6.7/LICENSE.from_folly
   sandbox/jng/mvt/Oem/protozero-1.6.7/LICENSE.md
   sandbox/jng/mvt/Oem/protozero-1.6.7/README.md
   sandbox/jng/mvt/Oem/protozero-1.6.7/UPGRADING.md
   sandbox/jng/mvt/Oem/protozero-1.6.7/appveyor.yml
   sandbox/jng/mvt/Oem/protozero-1.6.7/bench/
   sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/
   sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/README.md
   sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/enf-14-4824-6157.vector.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/mapbox-streets-v6-14-8714-8017.vector.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/cmake/
   sandbox/jng/mvt/Oem/protozero-1.6.7/cmake/FindProtozero.cmake
   sandbox/jng/mvt/Oem/protozero-1.6.7/doc/
   sandbox/jng/mvt/Oem/protozero-1.6.7/doc/CMakeLists.txt
   sandbox/jng/mvt/Oem/protozero-1.6.7/doc/Doxyfile.in
   sandbox/jng/mvt/Oem/protozero-1.6.7/doc/advanced.md
   sandbox/jng/mvt/Oem/protozero-1.6.7/doc/cheatsheet.md
   sandbox/jng/mvt/Oem/protozero-1.6.7/doc/tutorial.md
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/byteswap.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/config.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/data_view.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/exception.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/iterators.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_builder.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_message.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_reader.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_writer.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/types.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/varint.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/version.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/CMakeLists.txt
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/README.md
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/catch/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/catch/catch.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/create_pbf_test_data.sh
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/packed_access.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/scalar_access.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/test.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/testcase.hpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/reader_tests.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/alignment/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/alignment/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/bool_testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-also-true.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-false.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-still-true.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-true.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/writer_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/bytes_testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-binary.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-string.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/writer_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-all.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-minimal.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-some.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-neg.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/double_testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/writer_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-black.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-blue.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-min.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-neg.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/enum_testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/writer_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/fixed32_testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/writer_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-neg.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-min.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-pos200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/int32_testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/writer_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-min.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-pos200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/data-message.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/data-opt-element.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/data-opt-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/message_testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/writer_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/data-message.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/data-no-message.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/nested_testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/writer_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/repeated_testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/writer_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/repeated_packed_fixed32_testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/writer_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-many.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/rollback/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/rollback/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-min.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-neg.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-neg200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-min.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-neg.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-neg200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-min.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-neg.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-neg200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-pos200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-min.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-neg.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-neg200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-pos200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/skip/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/skip/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-empty.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-one.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-string.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/string_testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/writer_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-combined.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-not-packed.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-packed.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-1.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-200000.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-pos200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-max.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-pos.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-pos200.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-zero.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/testcase.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/testcase.proto
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/vector_tile/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/vector_tile/data.vector.pbf
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/vector_tile/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/wrong_type_access/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/wrong_type_access/reader_test_cases.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/CMakeLists.txt
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/main.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_basic.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_data_view.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_endian.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_exceptions.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_iterators.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_varint.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_zigzag.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/test/writer_tests.cpp
   sandbox/jng/mvt/Oem/protozero-1.6.7/tools/
   sandbox/jng/mvt/Oem/protozero-1.6.7/tools/CMakeLists.txt
   sandbox/jng/mvt/Oem/protozero-1.6.7/tools/pbf-decoder.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/.clang-tidy
   sandbox/jng/mvt/Oem/vtzero-1.0.3/.gitignore
   sandbox/jng/mvt/Oem/vtzero-1.0.3/.gitmodules
   sandbox/jng/mvt/Oem/vtzero-1.0.3/.travis.yml
   sandbox/jng/mvt/Oem/vtzero-1.0.3/.ycm_extra_conf.py
   sandbox/jng/mvt/Oem/vtzero-1.0.3/CHANGELOG.md
   sandbox/jng/mvt/Oem/vtzero-1.0.3/CMakeLists.txt
   sandbox/jng/mvt/Oem/vtzero-1.0.3/CONTRIBUTING.md
   sandbox/jng/mvt/Oem/vtzero-1.0.3/EXTERNAL_LICENSES.txt
   sandbox/jng/mvt/Oem/vtzero-1.0.3/LICENSE
   sandbox/jng/mvt/Oem/vtzero-1.0.3/README.md
   sandbox/jng/mvt/Oem/vtzero-1.0.3/appveyor.yml
   sandbox/jng/mvt/Oem/vtzero-1.0.3/build-appveyor.bat
   sandbox/jng/mvt/Oem/vtzero-1.0.3/build-msys2.bat
   sandbox/jng/mvt/Oem/vtzero-1.0.3/cmake/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/cmake/FindProtozero.cmake
   sandbox/jng/mvt/Oem/vtzero-1.0.3/codecov.yml
   sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/CMakeLists.txt
   sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/Doxyfile.in
   sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/advanced.md
   sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/doc.md
   sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/reading.md
   sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/tutorial.md
   sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/writing.md
   sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/CMakeLists.txt
   sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/utils.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/utils.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-check.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-create.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-encode-geom.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-filter.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-show.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-stats.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-streets.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include-external/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include-external/clara.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/builder.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/builder_impl.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/encoded_property_value.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/exception.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/feature.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/feature_builder_impl.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/geometry.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/index.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/layer.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/output.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property_mapper.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property_value.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/types.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/vector_tile.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/version.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/CMakeLists.txt
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/catch/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/catch/catch.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/data/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/data/mapbox-streets-v6-14-8714-8017.mvt
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/fixture_tests.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/include/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/include/test.hpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/mvt-fixtures/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_linestring.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_point.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_polygon.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_exceptions.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_feature.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_linestring.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_point.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_polygon.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_index.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_layer.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_output.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_point.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_property_map.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_property_value.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_types.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_vector_tile.cpp
   sandbox/jng/mvt/Oem/vtzero-1.0.3/test/test_main.cpp
Modified:
   sandbox/jng/mvt/License.txt
Log:
Add protozero 1.6.7 and vtzero 1.0.3

Modified: sandbox/jng/mvt/License.txt
===================================================================
--- sandbox/jng/mvt/License.txt	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/License.txt	2019-05-29 16:52:57 UTC (rev 9523)
@@ -1355,3 +1355,48 @@
 10 GOVERNING LAW
 Any action related to this Agreement will be governed by California law, excluding choice of law rules.
 �
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+protozero
+
+BSD 2-Clause License
+
+Copyright (c) 2017, Mapbox
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+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 HOLDER 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.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+vtzero
+
+protozero copyright (c) Mapbox.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in
+  the documentation and/or other materials provided with the
+  distribution.
+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.
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/.clang-tidy
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/.clang-tidy	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/.clang-tidy	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,37 @@
+---
+Checks: '*,-cert-dcl21-cpp,-cert-err60-cpp,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-type-reinterpret-cast,-fuchsia-*,-google-runtime-references,-hicpp-no-array-decay,-readability-implicit-bool-conversion'
+#
+#  Disabled checks:
+#
+#  cert-dcl21-cpp
+#    It is unclear whether this is still a good recommendation in modern C++.
+#
+#  cert-err60-cpp
+#    Reports std::runtime_error as broken which we can't do anything about.
+#
+#  cppcoreguidelines-pro-bounds-array-to-pointer-decay
+#    Limited use and many false positives including for all asserts.
+#
+#  cppcoreguidelines-pro-bounds-pointer-arithmetic
+#    This is a low-level library, it needs to do pointer arithmetic.
+#
+#  cppcoreguidelines-pro-type-reinterpret-cast
+#    This is a low-level library, it needs to do reinterpret-casts.
+#
+#  fuchsia-*
+#    Much too strict.
+#
+#  google-runtime-references
+#    This is just a matter of preference, and we can't change the interfaces
+#    now anyways.
+#
+#  hicpp-no-array-decay
+#    Limited use and many false positives including for all asserts.
+#
+#  readability-implicit-bool-conversion
+#    Not necessarily more readable.
+#
+WarningsAsErrors: '*'
+HeaderFilterRegex: '\/include\/'
+AnalyzeTemporaryDtors: false
+...

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/.gitattributes
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/.gitattributes	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/.gitattributes	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+*.pbf -text

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/.travis.yml
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/.travis.yml	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/.travis.yml	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,211 @@
+#-----------------------------------------------------------------------------
+#
+#  Configuration for continuous integration service at travis-ci.org
+#
+#-----------------------------------------------------------------------------
+
+language: generic
+
+dist: xenial
+
+#-----------------------------------------------------------------------------
+
+# Save common build configurations as shortcuts, so we can reference them later.
+addons_shortcuts:
+  addons_clang35: &clang35
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.5' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.5' ]
+  addons_clang38: &clang38
+    apt:
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.8' ]
+  addons_clang39: &clang39
+    apt:
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.9' ]
+  addons_clang40: &clang40
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-4.0' ]
+  addons_clang50: &clang50
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-5.0' ]
+  addons_clang60: &clang60
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-6.0', 'clang-tidy-6.0' ]
+  addons_gcc47: &gcc47
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.7', 'gcc-4.7' ]
+  addons_gcc48: &gcc48
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.8', 'gcc-4.8' ]
+  addons_gcc49: &gcc49
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.9', 'gcc-4.9' ]
+  addons_gcc5: &gcc5
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-5', 'gcc-5' ]
+  addons_gcc6: &gcc6
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-6', 'gcc-6' ]
+  addons_gcc7: &gcc7
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-7', 'gcc-7' ]
+
+#-----------------------------------------------------------------------------
+
+matrix:
+  include:
+    - os: linux
+      compiler: "clang-3.5"
+      env: BUILD='Debug' CC=clang-3.5 CXX=clang++-3.5
+      dist: trusty
+      addons: *clang35
+
+    - os: linux
+      compiler: "clang-3.8"
+      env: BUILD='Debug' CC=clang-3.8 CXX=clang++-3.8
+      addons: *clang38
+
+    - os: linux
+      compiler: "clang-3.9"
+      env: BUILD='Debug' CC=clang-3.9 CXX=clang++-3.9
+      addons: *clang39
+
+    - os: linux
+      compiler: "clang-4.0"
+      env: BUILD='Debug' CC=clang-4.0 CXX=clang++-4.0
+      addons: *clang40
+
+    - os: linux
+      compiler: "clang-5.0"
+      env: BUILD='Debug' CC=clang-5.0 CXX=clang++-5.0
+      addons: *clang50
+
+    - os: linux
+      compiler: "clang-6.0"
+      env: BUILD='Debug' CC=clang-6.0 CXX=clang++-6.0
+           CLANG_TIDY=clang-tidy-6.0
+      addons: *clang60
+
+    - os: linux
+      compiler: "clang-6.0"
+      env: BUILD='Debug' CC=clang-6.0 CXX=clang++-6.0
+           CXXFLAGS="-fsanitize=address,undefined,integer -fno-sanitize-recover=all -fno-omit-frame-pointer"
+           LDFLAGS="-fsanitize=address,undefined,integer"
+      addons: *clang60
+
+    - os: linux
+      compiler: "clang-6.0"
+      env: BUILD='Release' CC=clang-6.0 CXX=clang++-6.0
+      addons: *clang60
+
+    - os: linux
+      compiler: "gcc-4.7"
+      env: BUILD='Debug' CC=gcc-4.7 CXX=g++-4.7
+      dist: trusty
+      addons: *gcc47
+
+    - os: linux
+      compiler: "gcc-4.8"
+      env: BUILD='Debug' CC=gcc-4.8 CXX=g++-4.8
+      dist: trusty
+      addons: *gcc48
+
+    - os: linux
+      compiler: "gcc-4.9"
+      env: BUILD='Debug' CC=gcc-4.9 CXX=g++-4.9
+      dist: trusty
+      addons: *gcc49
+
+    - os: linux
+      compiler: "gcc-5"
+      env: BUILD='Debug' CC=gcc-5 CXX=g++-5
+           CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0"
+      dist: trusty
+      addons: *gcc5
+
+    - os: linux
+      compiler: "gcc-5"
+      env: BUILD='Debug' CC=gcc-5 CXX=g++-5
+           CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=1"
+      addons: *gcc5
+
+    - os: linux
+      compiler: "gcc-6"
+      env: BUILD='Debug' CC=gcc-6 CXX=g++-6
+      addons: *gcc6
+
+    - os: linux
+      compiler: "gcc-7"
+      env: BUILD='Debug' CC=gcc-7 CXX=g++-7
+           COVERAGE=gcov-7
+           CXXFLAGS="--coverage" LDFLAGS="--coverage"
+      addons: *gcc7
+
+    - os: linux
+      compiler: "gcc-7"
+      env: BUILD='Debug' CC=gcc-7 CXX=g++-7
+           PROTOZERO_DATA_VIEW=std::experimental::string_view
+      addons: *gcc7
+
+    - os: linux
+      compiler: "gcc-7"
+      env: BUILD='Release' CC=gcc-7 CXX=g++-7
+      addons: *gcc7
+
+    - os: osx
+      osx_image: xcode8.3
+      compiler: clang
+      env: BUILD='Debug'
+
+    - os: osx
+      osx_image: xcode9.4
+      compiler: clang
+      env: BUILD='Debug'
+
+    - os: osx
+      osx_image: xcode10.1
+      compiler: clang
+      env: BUILD='Debug'
+
+    - os: osx
+      osx_image: xcode10.1
+      compiler: clang
+      env: BUILD='Release'
+
+#-----------------------------------------------------------------------------
+
+install:
+  - |
+    if [[ $(uname -s) == 'Darwin' ]]; then
+      brew update
+      brew install protobuf
+      true
+    fi
+
+script:
+  - mkdir build
+  - cd build
+  - cmake .. -LA -DCMAKE_BUILD_TYPE=${BUILD} -DPROTOZERO_DATA_VIEW=$PROTOZERO_DATA_VIEW -DCLANG_TIDY=$(which ${CLANG_TIDY})
+  - make VERBOSE=1
+  - ctest --output-on-failure
+  - if [ -n "${CLANG_TIDY}" ]; then make clang-tidy; fi
+  - |
+    if [ -n "${COVERAGE}" ]; then
+      which ${COVERAGE}
+      curl -S -f https://codecov.io/bash -o codecov
+      chmod +x codecov
+      ${COVERAGE} -p $(find test/ tools/ -name '*.o')
+      ./codecov -Z -f '*protozero*' -f '*tools*' -f '!*catch*' -X search
+    fi
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/CHANGELOG.md
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/CHANGELOG.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/CHANGELOG.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,380 @@
+
+# Changelog
+
+All notable changes to this project will be documented in this file.
+The format is based on [Keep a Changelog](http://keepachangelog.com/)
+This project adheres to [Semantic Versioning](http://semver.org/).
+
+
+## [unreleased] -
+
+### Added
+
+### Changed
+
+### Fixed
+
+
+## [1.6.7] - 2018-02-21
+
+### Fixed
+
+- Signed-unsigned comparison on 32 bit systems.
+
+
+## [1.6.6] - 2018-02-20
+
+### Fixed
+
+- Fixed several place with possible undefined behaviour.
+
+
+## [1.6.5] - 2018-02-05
+
+### Fixed
+
+- Avoid UB: Do not calculate pointer outside array bounds.
+- Specify proto2 syntax in .proto files to appease protoc.
+
+
+## [1.6.4] - 2018-11-08
+
+### Added
+
+- Add function `data()` to get the not yet read data from a `pbf_reader`.
+- New `add_packed_fixed()` template function for `pbf_writer`.
+- New `length_of_varint()` helper function calculates how long a varint
+  would be for a specified value.
+
+### Changed
+
+- More consistent implementation of operators as free friend functions.
+
+### Fixed
+
+- Fixed some zigzag encoding tests on MSVC.
+- Add extra cast so we do an xor with unsigned ints.
+- No more bitwise operations on signed integers in varint decoder.
+- No more bitwise operations on signed integers in zigzag encoder/decoder.
+
+
+## [1.6.3] - 2018-07-17
+
+### Changed
+
+- Moved `byteswap_inplace` functions from detail into protozero namespace.
+  They can be useful outsize protozero.
+- More asserts and unit tests and small cleanups.
+
+
+## [1.6.2] - 2018-03-09
+
+### Changed
+
+- Update included catch.hpp to v1.12.0.
+- Move basic unit tests into their own directory (`test/unit`).
+- Improved clang-tidy config and fixed some code producing warnings.
+
+### Fixed
+
+- Buffer overflow in pbf-decoder tool.
+
+
+## [1.6.1] - 2017-11-16
+
+### Added
+
+- Document internal handling of varints.
+- Add aliases for fixed iterators, too.
+
+### Changed
+
+- The `const_fixed_iterator` is now a random access iterator making code
+  using it potentially more performant (for instance when using
+  `std::distance`)
+- Overloads `std::distance` for the varint and svarint iterators. This is
+  better than the workaround with the `rage_size` function used before.
+
+### Fixed
+
+- Rename `.proto` files in some tests to be unique. This solves a problem
+  when building with newer versions of the Google Protobuf library.
+- Floating point comparisons in tests are now always correctly done using
+  `Approx()`.
+
+
+## [1.6.0] - 2017-10-24
+
+### Added
+
+- Comparison functions (<, <=, >, >=) for `data_view`. Allows use in `std::map`
+  for instance.
+- Tool `pbf-decoder` for decoding raw messages. This has limited use for
+  normal users, but it can be used for fuzzing.
+
+### Changed
+
+- Protozero now uses CMake to build the tests etc. This does not affect
+  simple users of the library, but if you are using CMake yourself you might
+  want to use the `cmake/FindProtozero.cmake` module provided. The README
+  contains more information about build options.
+- Moved `data_view` class from `types.hpp` into its own header file
+  `data_view.hpp`.
+- Implementation of the `const_fixed_iterator` to use only a single pointer
+  instead of two.
+- Made `operator==` and `operator!=` on `data_view` constexpr.
+- The `pbf_reader` constructor taking a `std::pair` is deprecated. Use one
+  of the other constructors instead.
+
+### Fixed
+
+- Varints where the last byte was larger than what would fit in 64bit were
+  triggering undefined behaviour. This can only happen when the message
+  being decoded was corrupt in some way.
+- Do not assert when reading too long varints for bools any more. A valid
+  encoder should never generate varints with more than one byte for bools,
+  but if they are longer that's not really a problem, so just handle it.
+- Throw exception if the length of a packed repeated field of a fixed-length
+  type is invalid. The length must always be a multiple of the size of the
+  underlying type. This can only happen if the data is corrupted in some way,
+  a valid encoder would never generate data like this.
+- Throw an exception when reading invalid tags. This can only happen if the
+  data is corrupted in some way, a valid encoder would never generate invalid
+  tags.
+
+
+## [1.5.3] - 2017-09-22
+
+### Added
+
+- More documentation.
+- New `size()` method on iterator range used for packed repeated fields to
+  find out how many elements there are in the range. This is much faster
+  compared to the `std::difference()` call you had to do before, because the
+  varints don't have to be fully decoded. See [Advanced
+  Topics](doc/advanced.md) for details.
+
+### Changed
+
+- Updated clang-tidy settings in Makefiles and fixed a lot of minor issues
+  reported by clang-tidy.
+- Update included catch.hpp to version 1.10.0.
+- Miscellaneous code cleanups.
+- Support for invalid state in `pbf_writer` and `packed_repeated_fields`.
+  This fixes move construction and move assignement in `pbf_writer` and
+  disables the copy construction and copy assignement which don't have
+  clear semantics. It introduces an invalid or empty state in the
+  `pbf_writer`, `pbf_builder`, and `packed_repeated_fields` classes used for
+  default-constructed, moved from, or committed objects. There is a new
+  `commit()` function for `pbf_writer` and the `packed_repeated_fields` which
+  basically does the same as the destructor but can be called explicitly.
+
+### Fixed
+
+- The `empty()` method of the iterator range now returns a `bool` instead of
+  a `size_t`.
+
+
+## [1.5.2] - 2017-06-30
+
+### Added
+
+- Add missing two-parameter version of `pbf_message::next()` function.
+- Add `data_view::empty()` function.
+- Add missing versions of `add_bytes()`, `add_string()`, and `add_message()`
+  to `pbf_builder`.
+
+### Changed
+
+- Clarify include file usage in tutorial.
+- Updated included Catch unit test framework to version 1.9.6 and updated
+  tests to work with the current version.
+- Make some constructors explicit (best practice to avoid silent conversions).
+
+### Fixed
+
+- Important bugfix in `data_view` equality operator. The equality operator is
+  actually never used in the protozero code itself, but users of protozero
+  might use it. This is a serious bug that could lead to buffer overrun type
+  problems.
+
+
+## [1.5.1] - 2017-01-14
+
+### Added
+
+- Better documentation for `tag_and_type()` in doc/advanced.md.
+
+### Fixed
+
+- Fixed broken "make doc" build.
+
+
+## [1.5.0] - 2017-01-12
+
+### Added
+
+- Add `add_bytes_vectored()` methods to `pbf_writer` and `pbf_builder`. This
+  allows single-copy scatter-gather type adding of data that has been prepared
+  in pieces to a protobuf message.
+- New functions to check the tag and wire type at the same time: Two parameter
+  version of `pbf_reader::next()` and `pbf_reader::tag_and_type()` can be used
+  together with the free function `tag_and_type()` to easily and quickly check
+  that not only the tag but also the wire type is correct for a field.
+
+### Changed
+
+- `packed_field_*` classes now work with `pbf_builder`.
+- Reorganized documentation. Advanced docs are now under doc/advanced.md.
+
+### Fixed
+
+- `packed_field` class is now non-copyable because data can get corrupted if
+  you copy it around.
+- Comparison operators of `data_view` now have const& parameters.
+- Make zigzag encoding/decoding functions constexpr.
+
+
+## [1.4.5] - 2016-11-18
+
+### Fixed
+
+- Undefined behaviour in packed fixed iterator. As a result, the macro
+  `PROTOZERO_DO_NOT_USE_BARE_POINTER` is not used any more.
+
+
+## [1.4.4] - 2016-11-15
+
+### Fixed
+
+- Byteswap implementation.
+
+
+## [1.4.3] - 2016-11-15
+
+### Fixed
+
+- Undefined behaviour in byte swapping code.
+- Rename some parameters to avoid "shadow" warning from some compilers.
+
+
+## [1.4.2] - 2016-08-27
+
+### Fixed
+
+- Compile fix: Variable shadowing.
+
+
+## [1.4.1] - 2016-08-21
+
+### Fixed
+
+- GCC 4.8 compile fixed
+
+### Added
+
+- New ability to dynamically require the module as a node module to ease
+  building against from other node C++ modules.
+
+## [1.4.0] - 2016-07-22
+
+### Changed
+
+- Use more efficient new `skip_varint()` function when iterating over
+  packed varints.
+- Split `decode_varint()` function into two functions speeding up the
+  common case where a varint is only one byte long.
+- Introduce new class `iterator_range` used instead of `std::pair` of
+  iterators. This way the objects can be used in range-based for loops.
+  Read UPGRADING.md for details.
+- Introduce new class `data_view` and functions using and returning it.
+  Read UPGRADING.md for details.
+
+
+## [1.3.0] - 2016-02-18
+
+### Added
+
+- Added `config.hpp` header which now includes all the macro magic to
+  configure the library for different architectures etc.
+- New way to create repeated packed fields without using an iterator.
+- Add `rollback()` function to `pbf_writer` for "manual" rollback.
+
+### Changed
+
+- Various test and documentation cleanups.
+- Rename `pbf_types.hpp` to `types.hpp`.
+
+
+## [1.2.3] - 2015-11-30
+
+### Added
+
+- Added `config.hpp` header which now includes all the macro magic to
+  configure the library for different architectures etc.
+
+### Fixed
+
+- Unaligned access to floats/doubles on some ARM architectures.
+
+
+## [1.2.2] - 2015-10-13
+
+### Fixed
+
+- Fix the recently broken writing of bools on big-endian architectures.
+
+
+## [1.2.1] - 2015-10-12
+
+### Fixed
+
+- Removed unneeded code (1-byte "swap") which lead to test failures.
+
+
+## [1.2.0] - 2015-10-08
+
+### Added
+
+- `pbf_message` and `pbf_builder` template classes wrapping `pbf_reader`
+  and `pbf_writer`, respectively. The new classes are the preferred
+  interface now.
+
+### Changed
+
+- Improved byte swapping operation.
+- Detect some types of data corruption earlier and throw.
+
+
+## [1.1.0] - 2015-08-22
+
+### Changed
+
+- Make pbf reader and writer code endianess-aware.
+
+
+[unreleased]: https://github.com/osmcode/libosmium/compare/v1.6.6...HEAD
+[1.6.5]: https://github.com/osmcode/libosmium/compare/v1.6.5...v1.6.6
+[1.6.5]: https://github.com/osmcode/libosmium/compare/v1.6.4...v1.6.5
+[1.6.4]: https://github.com/osmcode/libosmium/compare/v1.6.3...v1.6.4
+[1.6.3]: https://github.com/osmcode/libosmium/compare/v1.6.2...v1.6.3
+[1.6.2]: https://github.com/osmcode/libosmium/compare/v1.6.1...v1.6.2
+[1.6.1]: https://github.com/osmcode/libosmium/compare/v1.6.0...v1.6.1
+[1.6.0]: https://github.com/osmcode/libosmium/compare/v1.5.3...v1.6.0
+[1.5.3]: https://github.com/osmcode/libosmium/compare/v1.5.2...v1.5.3
+[1.5.2]: https://github.com/osmcode/libosmium/compare/v1.5.1...v1.5.2
+[1.5.1]: https://github.com/osmcode/libosmium/compare/v1.5.0...v1.5.1
+[1.5.0]: https://github.com/osmcode/libosmium/compare/v1.4.5...v1.5.0
+[1.4.5]: https://github.com/osmcode/libosmium/compare/v1.4.4...v1.4.5
+[1.4.4]: https://github.com/osmcode/libosmium/compare/v1.4.3...v1.4.4
+[1.4.3]: https://github.com/osmcode/libosmium/compare/v1.4.2...v1.4.3
+[1.4.2]: https://github.com/osmcode/libosmium/compare/v1.4.1...v1.4.2
+[1.4.1]: https://github.com/osmcode/libosmium/compare/v1.4.0...v1.4.1
+[1.4.0]: https://github.com/osmcode/libosmium/compare/v1.3.0...v1.4.0
+[1.3.0]: https://github.com/osmcode/libosmium/compare/v1.2.3...v1.3.0
+[1.2.3]: https://github.com/osmcode/libosmium/compare/v1.2.2...v1.2.3
+[1.2.2]: https://github.com/osmcode/libosmium/compare/v1.2.1...v1.2.2
+[1.2.1]: https://github.com/osmcode/libosmium/compare/v1.2.0...v1.2.1
+[1.2.0]: https://github.com/osmcode/libosmium/compare/v1.1.0...v1.2.0
+[1.1.0]: https://github.com/osmcode/libosmium/compare/v1.0.0...v1.1.0
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/CMakeLists.txt
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/CMakeLists.txt	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/CMakeLists.txt	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,145 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake config
+#
+#  protozero
+#
+#-----------------------------------------------------------------------------
+
+cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
+
+#-----------------------------------------------------------------------------
+
+project(protozero)
+
+set(PROTOZERO_VERSION_MAJOR 1)
+set(PROTOZERO_VERSION_MINOR 6)
+set(PROTOZERO_VERSION_PATCH 7)
+
+set(PROTOZERO_VERSION
+    "${PROTOZERO_VERSION_MAJOR}.${PROTOZERO_VERSION_MINOR}.${PROTOZERO_VERSION_PATCH}")
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+#-----------------------------------------------------------------------------
+
+option(WERROR "Add -Werror flag to build (turns warnings into errors)" ON)
+
+if(MSVC)
+    add_definitions(/W3)
+    add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)
+else()
+    add_definitions(-std=c++11 -Wall -Wextra -pedantic -Wsign-compare -Wunused-parameter -Wno-float-equal -Wno-covered-switch-default)
+    if(WERROR)
+        add_definitions(-Werror)
+    endif()
+endif()
+
+include_directories("${CMAKE_SOURCE_DIR}/include")
+
+set(PROTOZERO_DATA_VIEW "" CACHE STRING "Type used for protozero::data_view")
+if(NOT PROTOZERO_DATA_VIEW STREQUAL "")
+    add_definitions(-DPROTOZERO_DATA_VIEW=${PROTOZERO_DATA_VIEW})
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+#  Find dependencies
+#
+#-----------------------------------------------------------------------------
+
+find_package(Protobuf)
+
+
+#-----------------------------------------------------------------------------
+#
+#  Optional "clang-tidy" target
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for clang-tidy")
+find_program(CLANG_TIDY NAMES clang-tidy clang-tidy-6.0 clang-tidy-5.0)
+
+if(CLANG_TIDY)
+    message(STATUS "Looking for clang-tidy - found ${CLANG_TIDY}")
+    add_custom_target(clang-tidy
+        ${CLANG_TIDY}
+        -p ${CMAKE_BINARY_DIR}
+        ${CMAKE_SOURCE_DIR}/test/*.cpp
+        ${CMAKE_SOURCE_DIR}/test/t/*/*.cpp
+        ${CMAKE_SOURCE_DIR}/test/unit/*.cpp
+        ${CMAKE_SOURCE_DIR}/tools/*.cpp
+    )
+    add_dependencies(clang-tidy writer_tests)
+else()
+    message(STATUS "Looking for clang-tidy - not found")
+    message(STATUS "  Build target 'clang-tidy' will not be available.")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+#  Optional "cppcheck" target
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for cppcheck")
+find_program(CPPCHECK NAMES cppcheck)
+
+if(CPPCHECK)
+    message(STATUS "Looking for cppcheck - found")
+    add_custom_target(cppcheck
+        ${CPPCHECK}
+        -Uassert --std=c++11 --enable=all
+        ${CMAKE_SOURCE_DIR}/include/protozero/*.hpp
+        ${CMAKE_SOURCE_DIR}/test/*.cpp
+        ${CMAKE_SOURCE_DIR}/test/include/*.hpp
+        ${CMAKE_SOURCE_DIR}/test/t/*/*.cpp
+        ${CMAKE_SOURCE_DIR}/test/unit/*.cpp
+        ${CMAKE_SOURCE_DIR}/tools/*.cpp
+    )
+else()
+    message(STATUS "Looking for cppcheck - not found")
+    message(STATUS "  Build target 'cppcheck' will not be available.")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+#  Include what you use
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for iwyu")
+find_program(IWYU_TOOL NAMES iwyu_tool)
+
+if(IWYU_TOOL)
+    message(STATUS "Looking for iwyu - found")
+    add_custom_target(iwyu
+        ${IWYU_TOOL} -p ${CMAKE_BINARY_DIR}
+    )
+else()
+    message(STATUS "Looking for iwyu - not found")
+    message(STATUS "  Build target 'iwyu' will not be available.")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+#  Installation
+#
+#-----------------------------------------------------------------------------
+
+install(DIRECTORY include/protozero DESTINATION include)
+
+
+#-----------------------------------------------------------------------------
+
+enable_testing()
+
+add_subdirectory(doc)
+
+add_subdirectory(tools)
+
+add_subdirectory(test)
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/CONTRIBUTING.md
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/CONTRIBUTING.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/CONTRIBUTING.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,21 @@
+# Contributing to protozero
+
+## Releasing
+
+To release a new protozero version:
+
+ - Make sure all tests are passing locally, on travis and on appveyor
+ - Make sure "make doc" builds
+ - Update version number in
+   - include/protozero/version.hpp (two places)
+   - CMakeLists.txt (one place)
+ - Update CHANGELOG.md
+   (don't forget links at the bottom of the file)
+ - Update UPGRADING.md if necessary
+ - `git commit -m "Release X.Y.Z" include/protozero/version.hpp CMakeLists.txt CHANGELOG.md UPGRADING.md`
+ - `git tag vX.Y.Z`
+ - `git push`
+ - `git push --tags`
+ - Go to https://github.com/mapbox/protozero/releases
+   and edit the new release. Put "Version x.y.z" in title and
+   cut-and-paste entry from CHANGELOG.md.

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/FUZZING.md
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/FUZZING.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/FUZZING.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,22 @@
+
+To do fuzz testing using [AFL](http://lcamtuf.coredump.cx/afl/) compile with
+the AFL compiler wrappers:
+
+    mkdir build
+    cd build
+    CC=afl-clang CXX=afl-clang++ cmake ..
+    mkdir testcase_dir
+
+You need some data to start the fuzzing. In this case I am using all the test
+messages from the unit tests:
+
+    find ../test/t/ -name data-\*.pbf -a -not -empty -exec cp {} testcase_dir/ \;
+
+Then do the actual fuzzing:
+
+    afl-fuzz -i testcase_dir -o findings_dir -- tools/pbf-decoder -
+
+See the AFL documentation for more information.
+
+This only checkes the reading side of Protozero!
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/LICENSE.from_folly
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/LICENSE.from_folly	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/LICENSE.from_folly	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,177 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/LICENSE.md
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/LICENSE.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/LICENSE.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,24 @@
+protozero copyright (c) Mapbox.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+
+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.

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/README.md
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/README.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/README.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,156 @@
+# protozero
+
+Minimalistic protocol buffer decoder and encoder in C++.
+
+Designed for high performance. Suitable for writing zero copy parsers and
+encoders with minimal need for run-time allocation of memory.
+
+Low-level: this is designed to be a building block for writing a very
+customized decoder for a stable protobuf schema. If your protobuf schema is
+changing frequently or lazy decoding is not critical for your application then
+this approach offers no value: just use the C++ API that can be generated with
+the Google Protobufs `protoc` program.
+
+[![Travis Build Status](https://travis-ci.org/mapbox/protozero.svg?branch=master)](https://travis-ci.org/mapbox/protozero)
+[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/mapbox/protozero?svg=true)](https://ci.appveyor.com/project/Mapbox/protozero)
+[![Coverage Status](https://codecov.io/gh/mapbox/protozero/branch/master/graph/badge.svg)](https://codecov.io/gh/mapbox/protozero)
+[![Packaging status](https://repology.org/badge/tiny-repos/protozero.svg)](https://repology.org/metapackage/protozero)
+
+## Depends
+
+* C++11 compiler
+* CMake
+* Some tests depend on the Google Protobuf library, but use of Protozero
+  doesn't need it
+
+
+## How it works
+
+The protozero code does **not** read `.proto` files used by the usual Protobuf
+implementations. The developer using protozero has to manually "translate" the
+`.proto` description into code. This means there is no way to access any of the
+information from the `.proto` description. This results in a few restrictions:
+
+* The names of the fields are not available.
+* Enum names are not available, you'll have to use the values they are defined
+  with.
+* Default values are not available.
+* Field types have to be hardcoded. The library does not know which types to
+  expect, so the user of the library has to supply the right types. Some checks
+  are made using `assert()`, but mostly the user has to take care of that.
+
+The library will make sure not to overrun the buffer it was given, but
+basically all other checks have to be made in user code!
+
+
+## Documentation
+
+You have to have a working knowledge of how
+[protocol buffer encoding works](https://developers.google.com/protocol-buffers/docs/encoding).
+
+* Read the [tutorial](doc/tutorial.md) for an introduction on how to use
+  Protozero.
+* Some advanced topics are described in an [extra document](doc/advanced.md).
+* There is a table of all types and functions in the
+  [cheat sheet](doc/cheatsheet.md).
+* Read the [upgrading instructions](UPGRADING.md) if you are upgrading from
+  an older version of Protozero.
+
+The build process will also build the Doxygen-based reference documentation
+if you have [Doxygen](http://www.stack.nl/~dimitri/doxygen/) installed. Then
+open `doc/html/index.html` in your browser to read it.
+
+
+## Endianness
+
+Protozero uses a very simplistic test to check the byte order of the system it
+compiles on. If this check is wrong, you'll get test failures. If this is the
+case, please [open an issue](https://github.com/mapbox/protozero/issues) and
+tell us about your system.
+
+
+## Building tests
+
+Extensive tests are included. Build them using CMake:
+
+    mkdir build
+    cd build
+    cmake ..
+    make
+
+Call `ctest` to run the tests.
+
+The unit and reader tests are always build, the writer tests are only build if
+the Google Protobuf library is found when running CMake.
+
+See `test/README.md` for more details about the test.
+
+
+## Coverage report
+
+To get a coverage report set `CXXFLAGS` and `LDFLAGS` before calling CMake:
+
+    CXXFLAGS="--coverage" LDFLAGS="--coverage" cmake ..
+
+Then call `make` as usual and run the tests using `ctest`.
+
+If you are using `g++` use `gcov` to generate a report (results are in `*.gcov`
+files):
+
+    gcov -lp $(find test/ -name '*.o')
+
+If you are using `clang++` use `llvm-cov` instead:
+
+    llvm-cov gcov -lp $(find test/ -name '*.o')
+
+If you are using `g++` you can use `gcovr` to generate nice HTML output:
+
+    mkdir -p coverage
+    gcovr . -r SRCDIR --html --html-details -o coverage/index.html
+
+Open `coverage/index.html` in your browser to see the report.
+
+
+## Clang-tidy
+
+After the CMake step, run
+
+    make clang-tidy
+
+to check the code with [clang-tidy](https://clang.llvm.org/extra/clang-tidy/).
+You might have to set `CLANG_TIDY` in CMake config.
+
+
+## Cppcheck
+
+For extra checks with [Cppcheck](http://cppcheck.sourceforge.net/) you can,
+after the CMake step, call
+
+    make cppcheck
+
+
+## Installation
+
+After the CMake step, call `make install` to install the include files in
+`/usr/local/include/protozero`.
+
+If you are using CMake to build your own software, you can copy the file
+`cmake/FindProtozero.cmake` and use it in your build. See the file for
+details.
+
+
+## Who is using Protozero?
+
+* [Carmen](https://github.com/mapbox/carmen-cache)
+* [Libosmium](https://github.com/osmcode/libosmium)
+* [Mapbox GL Native](https://github.com/mapbox/mapbox-gl-native)
+* [Mapbox Vector Tile library](https://github.com/mapbox/vector-tile)
+* [Mapnik](https://github.com/mapbox/mapnik-vector-tile)
+* [OSRM](https://github.com/Project-OSRM/osrm-backend)
+* [Tippecanoe](https://github.com/mapbox/tippecanoe)
+* [Vtzero](https://github.com/mapbox/vtzero)
+
+Are you using Protozero? Tell us! Send a pull request with changes to this
+README.
+
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/UPGRADING.md
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/UPGRADING.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/UPGRADING.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,96 @@
+
+# Upgrading
+
+This file contains instructions for users of Protozero who are upgrading from
+one version to another.
+
+You do not need to change anything if only the minor version changes, but it
+is better to keep up with changes if you can. The switch to the next major
+version will be easier then. And you might get some more convenient usage.
+
+To help you with upgrading to new versions, you can define the C++ preprocessor
+macro `PROTOZERO_STRICT_API` in which case Protozero will compile without the
+code used for backwards compatibilty. You will then get compile errors for
+older API usages.
+
+## Upgrading from *v1.5* to *v1.6.0*
+
+* The `data_view` class moved from `types.hpp` into its own header file
+  `data_view.hpp`. Most people should not include those headers directly,
+  but if you do, you might have to change your includes.
+* There are two new exceptions `invalid_tag_exception` and
+  `invalid_length_exception` which cover cases that were only checked by
+  `assert` before this version. If you catch specific exceptions in your code
+  you might have to amend it. But just catching `protozero::exception` is
+  usually fine for most code (if you catch exceptions at all).
+* The `pbf_reader` constructor taking a `std::pair` is now deprecated. If you
+  are compiling with `PROTOZERO_STRICT_API` it is not available any more. Use
+  one of the other constructors instead.
+
+## Upgrading from *v1.4.5* to *v1.5.0*
+
+* New functions for checking tag and type at the same time to make your
+  program more robust. Read the section "Repeated fields in messages" in
+  the new [Advanced Topics documentation](doc/advanced.md).
+
+## Upgrading from *v1.4.4* to *v1.4.5*
+
+* The macro `PROTOZERO_DO_NOT_USE_BARE_POINTER` is not used any more. If you
+  have been setting this, remove it.
+
+## Upgrading from *v1.4.0* to *v1.4.1*
+
+* You can now do `require('protozero')` in nodejs to print the path
+  to the include paths for the protozero headers.
+
+## Upgrading from *v1.3.0* to *v1.4.0*
+
+* Functions in `pbf_reader` (and the derived `pbf_message`) called
+  `get_packed_*()` now return an `iterator_range` instead of a `std::pair`.
+  The new class is derived from `std::pair`, so changes are usually not
+  strictly necessary. For future compatibility, you should change all
+  attribute accesses on the returned objects from `first` and `second` to
+  `begin()` and `end()`, respectively. So change something like this:
+
+      auto x = message.get_packed_int32();
+      for (auto it = x.first; it != x.second; ++it) {
+          ....
+      }
+
+  to:
+
+      auto x = message.get_packed_int32();
+      for (auto it = x.begin(); it != x.end(); ++it) {
+          ....
+      }
+
+  or even better use the range-based for loop:
+
+      auto x = message.get_packed_int32();
+      for (auto val : x) {
+          ....
+      }
+
+  Ranges can also be used in this way. This will change the range in-place:
+
+      auto range = message.get_packed_int32();
+      while (!range.empty()) {
+          auto value = range.front();
+          range.drop_front();
+          ....
+      }
+
+* The class `pbf_reader` has a new method `get_view()` returning an object
+  of the new `protozero::data_view` class. The `data_view` only has minimal
+  functionality, but what it has is compatible to the `std::string_view` class
+  which will be coming in C++17. The view autoconverts to a `std::string` if
+  needed. Use `get_view()` instead of `get_data()` giving you a more intuitive
+  interface (call `data()` and `size()` on the view instead of using `first`
+  and `second` on the `std::pair` returned by `get_data()`).
+
+  You can set the macro `PROTOZERO_USE_VIEW` (before including `types.hpp`) to
+  the name of any class that behaves like `protozero::data_view` and
+  `data_view` will be an alias to that class instead of the implementation
+  from protozero. This way you can use the C++17 `string_view` or a similar
+  class if it is already available on your system.
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/appveyor.yml
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/appveyor.yml	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/appveyor.yml	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,70 @@
+#-----------------------------------------------------------------------------
+#
+#  Configuration for continuous integration service at appveyor.com
+#
+#-----------------------------------------------------------------------------
+
+platform: x64
+
+image: Visual Studio 2017
+
+clone_depth: 1
+
+#-----------------------------------------------------------------------------
+
+environment:
+  matrix:
+  - config: MSYS2
+    autocrlf: true
+  - config: Debug
+    autocrlf: true
+  - config: RelWithDebInfo
+    autocrlf: true
+  - config: Debug
+    autocrlf: false
+  - config: RelWithDebInfo
+    autocrlf: false
+  - config: Debug
+    autocrlf: false
+    platform: x86
+
+#-----------------------------------------------------------------------------
+
+init:
+  - git config --global core.autocrlf %autocrlf%
+  - git config --get core.autocrlf
+
+# The option --ask=20 is a workaround for a problem with the MSYS2 update
+# process. Without it the following error is printed and the appveyor script
+# halts: "msys2-runtime and catgets are in conflict. Remove catgets?"
+# See also: https://github.com/Alexpux/MSYS2-packages/issues/1141
+install:
+  - if "%config%"=="MSYS2" (
+      set "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%" &&
+      pacman --noconfirm --sync --refresh --refresh --sysupgrade --sysupgrade --ask=20 &&
+      pacman -Rc --noconfirm mingw-w64-x86_64-gcc-libs &&
+      pacman -S --needed --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-doxygen mingw-w64-x86_64-protobuf
+    )
+
+build_script:
+  - cd c:\projects\protozero
+  - mkdir build
+  - cd build
+  - if "%platform%"=="x64" (
+      set vcvarsall_arg=amd64
+    ) else (
+      set vcvarsall_arg=x86
+    )
+  - if "%config%"=="MSYS2" (
+      cmake .. -LA -G "MSYS Makefiles" &&
+      make VERBOSE=1
+    ) else (
+      "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall" %vcvarsall_arg% &&
+      cmake .. -LA -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=%config% &&
+      nmake VERBOSE=1
+    )
+
+test_script:
+  - ctest --output-on-failure
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/README.md
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/README.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/README.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,13 @@
+
+
+mapbox-streets-v6/14/8714/8017.vector.pbf
+
+ - http://c.tile.openstreetmap.org/14/8714/8017.png
+ - https://a.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/14/8714/8017.vector.pbf
+ - https://www.mapbox.com/developers/vector-tiles/mapbox-streets/
+
+enf-14-4824-6157.vector.pbf
+
+ - enf.8k273nmi
+ - https://b.tiles.mapbox.com/v4/enf.c3a2de35/14/4824/6157@2x.png
+ - https://www.mapbox.com/blog/twitter-map-every-tweet/
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/enf-14-4824-6157.vector.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/enf-14-4824-6157.vector.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/enf-14-4824-6157.vector.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/enf-14-4824-6157.vector.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/enf-14-4824-6157.vector.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/mapbox-streets-v6-14-8714-8017.vector.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/mapbox-streets-v6-14-8714-8017.vector.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/mapbox-streets-v6-14-8714-8017.vector.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/mapbox-streets-v6-14-8714-8017.vector.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/bench/data/mapbox-streets-v6-14-8714-8017.vector.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/cmake/FindProtozero.cmake
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/cmake/FindProtozero.cmake	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/cmake/FindProtozero.cmake	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,63 @@
+#----------------------------------------------------------------------
+#
+#  FindProtozero.cmake
+#
+#  Find the protozero headers.
+#
+#----------------------------------------------------------------------
+#
+#  Usage:
+#
+#    Copy this file somewhere into your project directory, where cmake can
+#    find it. Usually this will be a directory called "cmake" which you can
+#    add to the CMake module search path with the following line in your
+#    CMakeLists.txt:
+#
+#      list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+#
+#    Then add the following in your CMakeLists.txt:
+#
+#      find_package(Protozero [version] [REQUIRED])
+#      include_directories(SYSTEM ${PROTOZERO_INCLUDE_DIR})
+#
+#    The version number is optional. If it is not set, any version of
+#    protozero will do.
+#
+#      if(NOT PROTOZERO_FOUND)
+#          message(WARNING "Protozero not found!\n")
+#      endif()
+#
+#----------------------------------------------------------------------
+#
+#  Variables:
+#
+#    PROTOZERO_FOUND        - True if Protozero was found.
+#    PROTOZERO_INCLUDE_DIR  - Where to find include files.
+#
+#----------------------------------------------------------------------
+
+# find include path
+find_path(PROTOZERO_INCLUDE_DIR protozero/version.hpp
+    PATH_SUFFIXES include
+    PATHS ${CMAKE_SOURCE_DIR}/../protozero
+)
+
+# Check version number
+if(Protozero_FIND_VERSION)
+    file(STRINGS "${PROTOZERO_INCLUDE_DIR}/protozero/version.hpp" _version_define REGEX "#define PROTOZERO_VERSION_STRING")
+    if("${_version_define}" MATCHES "#define PROTOZERO_VERSION_STRING \"([0-9.]+)\"")
+        set(_version "${CMAKE_MATCH_1}")
+    else()
+        set(_version "unknown")
+    endif()
+endif()
+
+#set(PROTOZERO_INCLUDE_DIRS "${PROTOZERO_INCLUDE_DIR}")
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Protozero
+                                  REQUIRED_VARS PROTOZERO_INCLUDE_DIR
+                                  VERSION_VAR _version)
+
+
+#----------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/doc/CMakeLists.txt
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/doc/CMakeLists.txt	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/doc/CMakeLists.txt	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,37 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake Config
+#
+#  protozero documentation
+#
+#-----------------------------------------------------------------------------
+
+message(STATUS "Configuring documentation")
+
+message(STATUS "Looking for doxygen")
+find_package(Doxygen)
+
+if(DOXYGEN_FOUND)
+    message(STATUS "Looking for doxygen - found")
+    configure_file(Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+
+    file(GLOB HEADER_FILES "${CMAKE_SOURCE_DIR}/include/protozero/*.hpp")
+    add_custom_command(OUTPUT html/index.html
+        COMMAND ${DOXYGEN_EXECUTABLE}
+        ARGS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+        DEPENDS Doxyfile.in advanced.md cheatsheet.md tutorial.md
+                ${HEADER_FILES}
+        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+        COMMENT "Generating API documentation with Doxygen" VERBATIM)
+    add_custom_target(doc ALL
+                      DEPENDS html/index.html)
+else()
+    message(STATUS "Looking for doxygen - not found")
+    message(STATUS "  Disabled making of documentation.")
+endif()
+
+#-----------------------------------------------------------------------------
+message(STATUS "Configuring documentation - done")
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/doc/Doxyfile.in
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/doc/Doxyfile.in	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/doc/Doxyfile.in	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2355 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "protozero"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = @PROTOZERO_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "Minimalistic protocol buffer decoder and encoder in C++."
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = "@PROJECT_BINARY_DIR@/doc"
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        = @PROJECT_SOURCE_DIR@
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = @PROJECT_SOURCE_DIR@/README.md \
+                         @PROJECT_SOURCE_DIR@/UPGRADING.md \
+                         @PROJECT_SOURCE_DIR@/doc \
+                         @PROJECT_SOURCE_DIR@/include/protozero
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        = protozero::detail protozero_assert PROTOZERO_*_ENDIAN PROTOZERO_BYTE_ORDER
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = @PROJECT_SOURCE_DIR@/README.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH      =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/doc/advanced.md
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/doc/advanced.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/doc/advanced.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,271 @@
+
+# Protozero Advanced Topics
+
+This documentation contains some mixed advanced topics for Protozero users.
+Read the [tutorial](tutorial.md) first if you are new to Protozero.
+
+
+## Limitations of Protozero
+
+* A protobuf message has to fit into memory completely, otherwise it can not
+  be parsed with this library. There is no streaming support.
+* The length of a string, bytes, or submessage can't be more than 2^31-1.
+* There is no specific support for maps but they can be used as described in
+  the "Backwards compatibility" section of
+  https://developers.google.com/protocol-buffers/docs/proto3#maps.
+
+
+## Checking the Protozero version number
+
+If `protozero/version.hpp` is included, the following macros are set:
+
+| Macro                      | Example | Description                                    |
+| -------------------------- | ------- | ---------------------------------------------- |
+| `PROTOZERO_VERSION_MAJOR`  | 1       | Major version number                           |
+| `PROTOZERO_VERSION_MINOR`  | 3       | Minor version number                           |
+| `PROTOZERO_VERSION_PATCH`  | 2       | Patch number                                   |
+| `PROTOZERO_VERSION_CODE`   | 10302   | Version (major * 10,000 + minor * 100 + patch) |
+| `PROTOZERO_VERSION_STRING` | "1.3.2" | Version string                                 |
+
+
+## Changing Protozero behaviour with macros
+
+The behaviour of Protozero can be changed by defining the following macros.
+They have to be set before including any of the Protozero headers.
+
+### `PROTOZERO_STRICT_API`
+
+If this is set, you will get some extra warnings or errors during compilation
+if you are using an old (deprecated) interface to Protozero. Enable this if
+you want to make sure your code will work with future versions of Protozero.
+
+### `PROTOZERO_USE_VIEW`
+
+Protozero uses the class `protozero::data_view` as the return type of the
+`pbf_reader::get_view()` method and a few other functions take a
+`protozero::data_view` as parameter.
+
+If `PROTOZERO_USE_VIEW` is unset, `protozero::data_view` is Protozero's own
+implementation of a *string view* class.
+
+Set this macro if you want to use a different implementation such as the C++17
+`std::string_view` class. In this case `protozero::data_view` will simply be
+an alias to the class you specify.
+
+    #define PROTOZERO_USE_VIEW std::string_view
+
+
+## Repeated fields in messages
+
+The Google Protobuf spec documents that a non-repeated field can actually
+appear several times in a message and the implementation is required to return
+the value of the last version of that field in this case. `pbf_reader.hpp` does
+not enforce this. If this feature is needed in your case, you have to do this
+yourself.
+
+The [spec also
+says](https://developers.google.com/protocol-buffers/docs/encoding#packed)
+that you must be able to read a packed repeated field where a not-packed
+repeated field is expected and vice versa. Also there can be several (packed or
+not-packed) repeated fields with the same tag and their contents must be
+concatenated. It is your responsibility to do this, Protozero doesn't do that
+for you.
+
+### Using `tag_and_type()`
+
+The `tag_and_type()` free function and the method of the same name on the
+`pbf_reader` and `pbf_message` classes can be used to access both packed and
+unpacked repeated fields. (It can also be used to check that you have the
+right type of encoding for other fields.)
+
+Here is the outline:
+
+```cpp
+enum class ExampleMsg : protozero::pbf_tag_type {
+    repeated_uint32_x = 1
+};
+
+std::string data = ...
+pbf_message<ExampleMsg> message{data};
+while (message.next()) {
+    switch (message.tag_and_type()) {
+        case tag_and_type(ExampleMsg::repeated_uint32_x, pbf_wire_type::length_delimited): {
+                auto xit = message.get_packed_uint32();
+                ... // handle the repeated field when it is packed
+            }
+            break;
+        case tag_and_type(ExampleMsg::repeated_uint32_x, pbf_wire_type::varint): {
+                auto x = message.get_uint32();
+                ... // handle the repeated field when it is not packed
+            }
+            break;
+        default:
+            message.skip();
+    }
+}
+```
+
+All this works on `pbf_reader` in the same way as with `pbf_message` with the
+usual difference that `pbf_reader` takes a numeric field tag and `pbf_message`
+an enum field.
+
+If you only want to check for one specific tag and type you can use the
+two-argument version of `pbf_reader::next()`. In this case `17` is the field
+tag we are looking for:
+
+```cpp
+std::string data = ...
+pbf_reader message{data};
+while (message.next(17, pbf_wire_type::varint)) {
+    auto foo = message.get_int32();
+    ...
+}
+```
+
+See the test under `test/t/tag_and_type/` for a complete example.
+
+
+## Reserving memory when writing messages
+
+If you know beforehand how large a message will become or can take an educated
+guess, you can call the usual `std::string::reserve()` on the underlying string
+before you give it to an `pbf_writer` or `pbf_builder` object.
+
+Or you can (at any time) call `reserve()` on the `pbf_writer` or `pbf_builder`.
+This will reserve the given amount of bytes *in addition to whatever is already
+in that message*. (Note that this behaviour is different then what `reserve()`
+does on `std::string` or `std::vector`.)
+
+In the general case it is not easy to figure out how much memory you will need
+because of the varint packing of integers. But sometimes you can make at least
+a rough estimate. Still, you should probably only use this facility if you have
+benchmarks proving that it actually makes your program faster.
+
+
+## Using the low-level varint and zigzag encoding and decoding functions
+
+Protozero gives you access to the low-level functions for encoding and
+decoding varint and zigzag integer encodings, because these functions can
+sometimes be useful outside the Protocol Buffer context.
+
+### Using low-level functions
+
+To use the low-level functions, add this include to your C++ program:
+
+```cpp
+#include <protozero/varint.hpp>
+```
+
+### Functions
+
+The following functions are then available:
+
+```cpp
+decode_varint()
+write_varint()
+encode_zigzag32()
+encode_zigzag64()
+decode_zigzag32()
+decode_zigzag64()
+```
+
+See the reference documentation created by `make doc` for details.
+
+
+## Vectored input for length-delimited fields
+
+Length-delimited fields (like string fields, byte fields and messages) are
+usually set by calling `add_string()`, `add_message()`, etc. These functions
+have several forms, but they basically all take a *tag*, a *size*, and a
+*pointer to the data*. They write the length of the data into the message
+and then copy the data over.
+
+Sometimes you have the data not in one place, but spread over several
+buffers. In this case you have to consolidate those buffers first, which needs
+an extra copy. Say you have two very long strings that should be concatenated
+into a message:
+
+```cpp
+std::string a{"very long string..."};
+std::string b{"another very long string..."};
+
+std::string data;
+protozero::pbf_writer writer{data};
+
+a.append(b); // expensive extra copy
+
+writer.add_string(1, a);
+```
+
+To avoid this, the function `add_bytes_vectored()` can be used which allows
+vectored (or scatter/gather) input like this:
+
+```cpp
+std::string a{"very long string..."};
+std::string b{"another very long string..."};
+
+std::string data;
+protozero::pbf_writer writer{data};
+
+writer.add_bytes_vectored(1, a, b);
+```
+
+`add_bytes_vectored()` will add up the sizes of all its arguments and copy over
+all the data only once.
+
+The function takes any number of arguments. The arguments must be of a type
+supporting the `data()` and `size()` methods like `protozero::data_view()`,
+`std::string` or the C++17 `std::string_view`.
+
+Note that there is only one version of the function which can be used for any
+length-delimited field including strings, bytes, messages and repeated packed
+fields.
+
+The function is also available in the `pbf_builder` class.
+
+
+## Internal handling of varints
+
+When varints are decoded they are always decoded as 64bit unsigned integers and
+after that casted to the type you are requesting (using `static_cast`). This
+means that if the protocol buffer message was created with a different integer
+type than what you are reading it with, you might get wrong results without any
+warning or error. This is the same behaviour as the Google Protocol Buffers
+library has.
+
+In normal use, this should never matter, because presumably you are using the
+same types to write that data as you are using to read it later. It can happen
+if the data is corrupted intentionally or unintentionally in some way. But
+this can't be used to feed you any data that it wasn't possible to feed you
+without this behaviour, so it doesn't open up any potential problems. You
+always have to check anyway that the integers are in the range you expected
+them to be in if the expected range is different than the range of the integer
+type. This is especially true for enums which protozero will return as
+`int32_t`.
+
+
+## How many items are there in a repeated packed field?
+
+Sometimes it is useful to know how many values there are in a repeated packed
+field. For instance when you want to reserve space in a `std::vector`.
+
+```cpp
+protozero::pbf_reader message{...};
+message.next(...);
+const auto range = message.get_packed_sint32();
+
+std::vector<int> myvalues;
+myvalues.reserve(range.size());
+
+for (auto value : range) {
+    myvalues.push_back(value);
+}
+```
+
+It depends on the type of range how expensive the `size()` call is. For ranges
+derived from packed repeated fixed sized values the effort will be constant,
+for ranges derived from packed repeated varints, the effort will be linear, but
+still considerably cheaper than decoding the varints. You have to benchmark
+your use case to see whether the `reserve()` (or whatever you are using the
+`size()` for) is worth it.
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/doc/cheatsheet.md
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/doc/cheatsheet.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/doc/cheatsheet.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,67 @@
+
+# Protozero Cheat Sheet
+
+See also this
+[handy table](https://developers.google.com/protocol-buffers/docs/proto#scalar)
+from the Google Protocol Buffers documentation.
+
+## Scalar types
+
+| PBF Type | Underlying Storage | C++ Type      | Getter           | Notes |
+| -------- | ------------------ | ------------- | ---------------- | ----- |
+| int32    | varint             | `int32_t`     | `get_int32()`    |       |
+| sint32   | varint (zigzag)    | `int32_t`     | `get_sint32()`   |       |
+| uint32   | varint             | `uint32_t`    | `get_uint32()`   |       |
+| int64    | varint             | `int64_t`     | `get_int64()`    |       |
+| sint64   | varint (zigzag)    | `int64_t`     | `get_sint64()`   |       |
+| uint64   | varint             | `uint64_t`    | `get_uint64()`   |       |
+| bool     | varint             | `bool`        | `get_bool()`     |       |
+| enum     | varint             | `int32_t`     | `get_enum()`     |       |
+| fixed32  | 32bit fixed        | `uint32_t`    | `get_fixed32()`  |       |
+| sfixed32 | 32bit fixed        | `int32_t`     | `get_sfixed32()` |       |
+| fixed64  | 64bit fixed        | `uint64_t`    | `get_fixed64()`  |       |
+| sfixed64 | 64bit fixed        | `int64_t`     | `get_sfixed64()` |       |
+| float    | 32bit fixed        | `float`       | `get_float()`    |       |
+| double   | 64bit fixed        | `double`      | `get_double()`   |       |
+| string   | length-delimited   | `data_view`   | `get_view()`     | (1)   |
+| string   | length-delimited   | pair          | `get_data()`     | (2)   |
+| string   | length-delimited   | `std::string` | `get_string()`   |       |
+| bytes    | length-delimited   | `data_view`   | `get_view()`     | (1)   |
+| bytes    | length-delimited   | pair          | `get_data()`     | (2)   |
+| bytes    | length-delimited   | `std::string` | `get_bytes()`    |       |
+| message  | length-delimited   | `data_view`   | `get_view()`     | (1)   |
+| message  | length-delimited   | pair          | `get_data()`     | (2)   |
+| message  | length-delimited   | `pbf_reader`  | `get_message()`  |       |
+
+### Notes:
+
+* (1) preferred form, returns `protozero::data_view` which is convertible to
+  `std::string` if needed.
+* (2) deprecated form, returns `std::pair<const char*, pbf_length_type>`,
+  use `get_view()` instead. This form is only available if
+  `PROTOZERO_STRICT_API` is not defined.
+* The setter function of `pbf_writer` is always `add_` + the PBF type. Several
+  overloads are available.
+
+
+## Packed repeated fields
+
+| PBF Type | Getter                  |
+| -------- | ----------------------- |
+| int32    | `get_packed_int32()`    |
+| sint32   | `get_packed_sint32()`   |
+| uint32   | `get_packed_uint32()`   |
+| int64    | `get_packed_int64()`    |
+| sint64   | `get_packed_sint64()`   |
+| uint64   | `get_packed_uint64()`   |
+| bool     | `get_packed_bool()`     |
+| enum     | `get_packed_enum()`     |
+| fixed32  | `get_packed_fixed32()`  |
+| sfixed32 | `get_packed_sfixed32()` |
+| fixed64  | `get_packed_fixed64()`  |
+| sfixed64 | `get_packed_sfixed64()` |
+| float    | `get_packed_float()`    |
+| double   | `get_packed_double()`   |
+
+Packed repeated fields for string, bytes, and message types are not possible.
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/doc/tutorial.md
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/doc/tutorial.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/doc/tutorial.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,626 @@
+
+# Protozero Tutorial
+
+## Getting to know Protocol Buffers
+
+Protozero is a very low level library. You really have to know some of the
+insides of Protocol Buffers to work with it!
+
+So before reading any further in this document, read the following from the
+Protocol Buffer documentation:
+
+* [Developer Guide - Overview](https://developers.google.com/protocol-buffers/docs/overview)
+* [Language Guide](https://developers.google.com/protocol-buffers/docs/proto)
+* [Encoding](https://developers.google.com/protocol-buffers/docs/encoding)
+
+Make sure you understand the basic types of values supported by Protocol
+Buffers. Refer to this
+[handy table](https://developers.google.com/protocol-buffers/docs/proto#scalar)
+and [the cheat sheet](cheatsheet.md) if you are getting lost.
+
+
+## Prerequisites
+
+You need a C++11-capable compiler for Protozero to work. Copy the files in the
+`include/protozero` directory somewhere where your build system can find them.
+Keep the `protozero` directory and include the files in the form
+
+```cpp
+#include <protozero/FILENAME.hpp>
+```
+
+
+## Parsing protobuf-encoded messages
+
+### Using `pbf_reader`
+
+To use the `pbf_reader` class, add this include to your C++ program:
+
+```cpp
+#include <protozero/pbf_reader.hpp>
+```
+
+The `pbf_reader` class contains asserts that will detect some programming
+errors. We encourage you to compile with asserts enabled in your debug builds.
+
+
+### An introductory example
+
+Lets say you have a protocol description in a `.proto` file like this:
+
+```cpp
+message Example1 {
+    required uint32 x  =  1;
+    optional string s  =  2;
+    repeated fixed64 r = 17;
+}
+```
+
+To read messages created according to that description, you will have code that
+looks somewhat like this:
+
+```cpp
+#include <protozero/pbf_reader.hpp>
+
+// get data from somewhere into the input string
+std::string input = get_input_data();
+
+// initialize pbf message with this data
+protozero::pbf_reader message{input};
+
+// iterate over fields in the message
+while (message.next()) {
+
+    // switch depending on the field tag (the field name is not available)
+    switch (message.tag()) {
+        case 1:
+            // get data for tag 1 (in this case an uint32)
+            auto x = message.get_uint32();
+            break;
+        case 2:
+            // get data for tag 2 (in this case a string)
+            std::string s = message.get_string();
+            break;
+        case 17:
+            // ignore data for tag 17
+            message.skip();
+            break;
+        default:
+            // ignore data for unknown tags to allow for future extensions
+            message.skip();
+    }
+}
+```
+
+You always have to call `next()` and then either one of the accessor functions
+(like `get_uint32()` or `get_string()`) to get the field value or `skip()` to
+ignore this field. Then call `next()` again, and so forth. Never call `next()`
+twice in a row or any if the accessor or skip functions twice in a row.
+
+Because the `pbf_reader` class doesn't know the `.proto` file it doesn't know
+which field names or tags there are and it doesn't known the types of the
+fields. You have to make sure to call the right `get_...()` function for each
+tag. Some `assert()s` are done to check you are calling the right functions,
+but not all errors can be detected.
+
+Note that it doesn't matter whether a field is defined as `required`,
+`optional`, or `repeated`. You always have to be prepared to get zero, one, or
+more instances of a field and you always have to be prepared to get other
+fields, too, unless you want your program to break if somebody adds a new
+field.
+
+
+### If you only need a single field
+
+If, out of a protocol buffer message, you only need the value of a single
+field, you can use the version of the `next()` function with a parameter:
+
+```cpp
+// same .proto file and initialization as above
+
+// get all fields with tag 17, skip all others
+while (message.next(17)) {
+    auto r = message.get_fixed64();
+    std::cout << r << "\n";
+}
+```
+
+### Handling scalar fields
+
+As you saw in the example, handling scalar field types is reasonably easy. You
+just check the `.proto` file for the type of a field and call the corresponding
+function called `get_` + _field type_.
+
+For `string` and `bytes` types the internal handling is exactly the same, but
+both `get_string()` and `get_bytes()` are provided to make the code
+self-documenting. Both theses calls allocate and return a `std::string` which
+can add some overhead. You can call the `get_view()` function instead which
+returns a `data_view` containing a pointer into the data (access with `data()`)
+and the length of the data (access with `size()`).
+
+
+### Handling repeated packed fields
+
+Fields that are marked as `[packed=true]` in the `.proto` file are handled
+somewhat differently. `get_packed_...()` functions returning an iterator range
+are used to access the data.
+
+So, for example, if you have a protocol description in a `.proto` file like
+this:
+
+```cpp
+message Example2 {
+    repeated sint32 i = 1 [packed=true];
+}
+```
+
+You can get to the data like this:
+
+```cpp
+protozero::pbf_reader message{input.data(), input.size()};
+
+// set current field
+message.next(1);
+
+// get an iterator range
+auto pi = message.get_packed_sint32();
+
+// iterate to get to all values
+for (auto it = pi.begin(); it != pi.end(); ++it) {
+    std::cout << *it << '\n';
+}
+```
+
+Or, with a range-based for-loop:
+
+```cpp
+for (auto value : pi) {
+    std::cout << v << '\n';
+}
+```
+
+So you are getting a pair of normal forward iterators wrapped in an iterator
+range object. The iterators can be used with any STL algorithms etc.
+
+Note that the previous only applies to repeated **packed** fields, normal
+repeated fields are handled in the usual way for scalar fields.
+
+
+### Handling embedded messages
+
+Protocol Buffers can embed any message inside another message. To access an
+embedded message use the `get_message()` function. So for this description:
+
+```cpp
+message Point {
+    required double x = 1;
+    required double y = 2;
+}
+
+message Example3 {
+    repeated Point point = 10;
+}
+```
+
+you can parse with this code:
+
+```cpp
+protozero::pbf_reader message{input};
+
+while (message.next(10)) {
+    protozero::pbf_reader point = message.get_message();
+    double x, y;
+    while (point.next()) {
+        switch (point.tag()) {
+            case 1:
+                x = point.get_double();
+                break;
+            case 2:
+                y = point.get_double();
+                break;
+            default:
+                point.skip();
+        }
+    }
+    std::cout << "x=" << x << " y=" << y << "\n";
+}
+```
+
+### Handling enums
+
+Enums are stored as varints and they can't be differentiated from them. Use
+the `get_enum()` function to get the value of the enum, you have to translate
+this into the symbolic name yourself. See the `enum` test case for an example.
+
+
+### Asserts and exceptions in the Protozero library
+
+Protozero uses `assert()` liberally to help you find bugs in your own code when
+compiled in debug mode (ie with `NDEBUG` not set). If such an assert "fires",
+this is a very strong indication that there is a bug in your code somewhere.
+
+(Protozero will disable those asserts and "convert" them into exception in its
+own test code. This is done to make sure the asserts actually work as intended.
+Your test code will not need this!)
+
+Exceptions, on the other hand, are thrown by Protozero if some kind of data
+corruption was detected while it is trying to parse the data. This could also
+be an indicator for a bug in the user code, but because it can happen if the
+data was (intentionally or not intentionally) been messed with, it is reported
+to the user code using exceptions.
+
+Most of the functions on the writer side can throw a `std::bad_alloc`
+exception if there is no space to grow a buffer. Other than that no exceptions
+can occur on the writer side.
+
+All exceptions thrown by the reader side derive from `protozero::exception`.
+
+Note that all exceptions can also happen if you are expecting a data field of
+a certain type in your code but the field actually has a different type. In
+that case the `pbf_reader` class might interpret the bytes in the buffer in
+the wrong way and anything can happen.
+
+#### `end_of_buffer_exception`
+
+This will be thrown whenever any of the functions "runs out of input data".
+It means you either have an incomplete message in your input or some other
+data corruption has taken place.
+
+#### `unknown_pbf_wire_type_exception`
+
+This will be thrown if an unsupported wire type is encountered. Either your
+input data is corrupted or it was written with an unsupported version of a
+Protocol Buffers implementation.
+
+#### `varint_too_long_exception`
+
+This exception indicates an illegal encoding of a varint. It means your input
+data is corrupted in some way.
+
+#### `invalid_tag_exception`
+
+This exception is thrown when a tag has an invalid value. Tags must be
+unsigned integers between 1 and 2^29-1. Tags between 19000 and 19999 are not
+allowed. See
+https://developers.google.com/protocol-buffers/docs/proto#assigning-tags
+
+#### `invalid_length_exception`
+
+This exception is thrown when a length field of a packed repeated field is
+invalid. For fixed size types the length must be a multiple of the size of
+the type.
+
+### The `pbf_reader` class
+
+The `pbf_reader` class behaves like a value type. Objects are reasonably small
+(two pointers and two `uint32_t`, so 24 bytes on a 64bit system) and they can
+be copied and moved around trivially.
+
+`pbf_reader` objects can be constructed from a `std::string` or a `const char*`
+and a length field (either supplied as separate arguments or as a `std::pair`).
+In all cases objects of the `pbf_reader` class store a pointer into the input
+data that was given to the constructor. You have to make sure this pointer
+stays valid for the duration of the objects lifetime.
+
+## Parsing protobuf-encoded messages using `pbf_message`
+
+One problem in the code above are the "magic numbers" used as tags for the
+different fields that you got from the `.proto` file. Instead of spreading
+these magic numbers around your code you can define them once in an `enum
+class` and then use the `pbf_message` template class instead of the
+`pbf_reader` class.
+
+Here is the first example again, this time using this new technique. So you
+have the following in a `.proto` file:
+
+```cpp
+message Example1 {
+    required uint32 x  =  1;
+    optional string s  =  2;
+    repeated fixed64 r = 17;
+}
+```
+
+Add the following declaration in one of your header files:
+
+```cpp
+enum class Example1 : protozero::pbf_tag_type {
+    required_uint32_x  =  1,
+    optional_string_s  =  2,
+    repeated_fixed64_r = 17
+};
+```
+
+The message name becomes the name of the `enum class` which is always built
+on top of the `protozero::pbf_tag_type` type. Each field in the message
+becomes one value of the enum. In this case the name is created from the
+type (including the modifiers like `required` or `optional`) and the name of
+the field. You can use any name you want, but this convention makes it easier
+later, to get everything right.
+
+To read messages created according to that description, you will have code that
+looks somewhat like this, this time using `pbf_message` instead of
+`pbf_reader`:
+
+```cpp
+#include <protozero/pbf_message.hpp>
+
+// get data from somewhere into the input string
+std::string input = get_input_data();
+
+// initialize pbf message with this data
+protozero::pbf_message<Example1> message{input};
+
+// iterate over fields in the message
+while (message.next()) {
+
+    // switch depending on the field tag (the field name is not available)
+    switch (message.tag()) {
+        case Example1::required_uint32_x:
+            auto x = message.get_uint32();
+            break;
+        case Example1::optional_string_s:
+            std::string s = message.get_string();
+            break;
+        case Example1::repeated_fixed64_r:
+            message.skip();
+            break;
+        default:
+            // ignore data for unknown tags to allow for future extensions
+            message.skip();
+    }
+}
+```
+
+Note the correspondance between the enum value (for instance
+`required_uint32_x`) and the name of the getter function (for instance
+`get_uint32()`). This makes it easier to get the correct types. Also the
+naming makes it easier to keep different message types apart if you have
+multiple (or embedded) messages.
+
+See the `test/t/complex` test case for a complete example using this interface.
+
+Using `pbf_message` in favour of `pbf_reader` is recommended for all code.
+Note that `pbf_message` derives from `pbf_reader`, so you can always fall
+back to the more generic interface if necessary.
+
+One problem you might run into is the following: The enum class lists all
+possible values you know about and you'll have lots of `switch` statements
+checking those values. Some compilers will know that your `switch` covers
+all possible cases and warn you if you have a `default` case that looks
+unneccessary to the compiler. But you still want that `default` case to allow
+for future extension of those messages (and maybe also to detect corrupted
+data). You can switch of this warning with `-Wno-covered-switch-default`).
+
+
+## Writing protobuf-encoded messages
+
+### Using `pbf_writer`
+
+To use the `pbf_writer` class, add this include to your C++ program:
+
+```cpp
+#include <protozero/pbf_writer.hpp>
+```
+
+The `pbf_writer` class contains asserts that will detect some programming
+errors. We encourage you to compile with asserts enabled in your debug builds.
+
+
+### An introductory example
+
+Lets say you have a protocol description in a `.proto` file like this:
+
+```cpp
+message Example {
+    required uint32 x = 1;
+    optional string s = 2;
+    repeated fixed64 r = 17;
+}
+```
+
+To write messages created according to that description, you will have code
+that looks somewhat like this:
+
+```cpp
+#include <protozero/pbf_writer.hpp>
+
+std::string data;
+protozero::pbf_writer pbf_example{data};
+
+pbf_example.add_uint32(1, 27);       // uint32_t x
+pbf_example.add_fixed64(17, 1);      // fixed64 r
+pbf_example.add_fixed64(17, 2);
+pbf_example.add_fixed64(17, 3);
+pbf_example.add_string(2, "foobar"); // string s
+```
+
+First you need a string which will be used as buffer to assemble the
+protobuf-formatted message. The `pbf_writer` object contains a reference to
+this string buffer and through it you add data to that buffer piece by piece.
+The buffer doesn't have to be empty, the `pbf_writer` will simply append its
+data to whatever is there already.
+
+
+### Handling scalar fields
+
+As you could see in the introductory example handling any kind of scalar field
+is easy. The type of field doesn't matter and it doesn't matter whether it is
+optional, required or repeated. You always call one of the `add_TYPE()` method
+on the pbf writer object.
+
+The first parameter of these methods is always the *tag* of the field (the
+field number) from the `.proto` file. The second parameter is the value you
+want to set. For the `bytes` and `string` types several versions of the add
+method are available taking a `const std::string&` or a `const char*` and a
+length.
+
+For `enum` types you have to use the numeric value as the symbolic names from
+the `.proto` file are not available.
+
+
+### Handling repeated packed fields
+
+Repeated packed fields can easily be set from a pair of iterators:
+
+```cpp
+std::string data;
+protozero::pbf_writer pw{data};
+
+std::vector<int> v = { 1, 4, 9, 16, 25, 36 };
+pw.add_packed_int32(1, std::begin(v), std::end(v));
+```
+
+If you don't have an iterator you can use the alternative form:
+
+```cpp
+std::string data;
+protozero::pbf_writer pw{data};
+{
+    protozero::packed_field_int32 field{pw, 1};
+    field.add_element(1);
+    field.add_element(10);
+    field.add_element(100);
+}
+```
+
+Of course you can add as many elements as you want. If you add no elements
+at all, this code will still work, Protozero detects this special case and
+pretends you never even initialized this field.
+
+The nested scope is important in this case, because the destructor of the
+`field` object will make sure the length stored inside the field is set to
+the right value. You must close that scope before adding other fields to the
+`pw` pbf writer.
+
+If you know how many elements you will add to the field and your field contains
+fixed length elements, you can tell Protozero and it can optimize this case:
+
+```cpp
+std::string data;
+protozero::pbf_writer pw{data};
+{
+    protozero::packed_field_fixed32 field{pw, 1, 2}; // exactly two elements
+    field.add_element(42);
+    field.add_element(13);
+}
+```
+
+In this case you have to supply exactly as many elements as you promised,
+otherwise you will get a broken protobuf message.
+
+This works for `packed_field_fixed32`, `packed_field_sfixed32`,
+`packed_field_fixed64`, `packed_field_sfixed64`, `packed_field_float`, and
+`packed_field_double`.
+
+You can abandon writing of the packed field if this becomes necessary by
+calling `rollback()`:
+
+```cpp
+std::string data;
+protozero::pbf_writer pw{data};
+{
+    protozero::packed_field_int32 field{pw, 1};
+    field.add_element(42);
+    // some error occurs, you don't want to have this field at all
+    field.rollback();
+}
+```
+
+The result is the same as if the lines inside the nested brackets had never
+been called. Do not try to call `add_element()` after a rollback.
+
+
+### Handling sub-messages
+
+Nested sub-messages can be handled by first creating the submessage and then
+adding to the parent message:
+
+```cpp
+std::string buffer_sub;
+protozero::pbf_writer pbf_sub{buffer_sub};
+
+// add fields to sub-message
+pbf_sub.add_...(...);
+// ...
+
+// sub-message is finished here
+
+std::string buffer_parent;
+protozero::pbf_writer pbf_parent{buffer_parent};
+pbf_parent.add_message(1, buffer_sub);
+```
+
+This is easy to do but it has the drawback of needing a separate `std::string`
+buffer. If this concerns you (and why would you use protozero and not the
+Google protobuf library if it doesn't?) there is another way:
+
+```cpp
+std::string data;
+protozero::pbf_writer pbf_parent{data};
+
+// optionally add fields to parent here
+pbf_parent.add_...(...);
+
+// open a new scope
+{
+    // create new pbf_writer with parent and the tag (field number)
+    // as parameters
+    protozero::pbf_writer pbf_sub{pbf_parent, 1};
+
+    // add fields to sub here...
+    pbf_sub.add_...(...);
+
+} // closing the scope will close the sub-message
+
+// optionally add more fields to parent here
+pbf_parent.add_...(...);
+```
+
+This can be nested arbitrarily deep.
+
+Internally the sub-message writer re-uses the buffer from the parent. It
+reserves enough space in the buffer to later write the length of the submessage
+into it. It then adds the contents of the submessage to the buffer. When the
+`pbf_sub` writer is destructed the length of the submessage is calculated and
+written in the reserved space. If less space was needed for the length field
+than was available, the rest of the buffer is moved over a few bytes.
+
+You can abandon writing of submessage if this becomes necessary by
+calling `rollback()`:
+
+```cpp
+std::string data;
+protozero::pbf_writer pbf_parent{data};
+
+// open a new scope
+{
+    // create new pbf_writer with parent and the tag (field number)
+    // as parameters
+    protozero::pbf_writer pbf_sub{pbf_parent, 1};
+
+    // add fields to sub here...
+    pbf_sub.add_...(...);
+
+    // some problem occurs and you want to abandon the submessage:
+    pbf_sub.rollback();
+}
+
+// optionally add more fields to parent here
+pbf_parent.add_...(...);
+```
+
+The result is the same as if the lines inside the nested brackets had never
+been called. Do not try to call any of the `add_*` functions on the submessage
+after a rollback.
+
+## Writing protobuf-encoded messages using `pbf_builder`
+
+Just like the `pbf_message` template class wraps the `pbf_reader` class, there
+is a `pbf_builder` template class wrapping the `pbf_writer` class. It is
+instantiated using the same `enum class` described above and used exactly
+like the `pbf_writer` class but using the values of the enum instead of bare
+integers.
+
+See the `test/t/complex` test case for a complete example using this interface.
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/byteswap.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/byteswap.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/byteswap.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,99 @@
+#ifndef PROTOZERO_BYTESWAP_HPP
+#define PROTOZERO_BYTESWAP_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file byteswap.hpp
+ *
+ * @brief Contains functions to swap bytes in values (for different endianness).
+ */
+
+#include <protozero/config.hpp>
+
+#include <cstdint>
+
+namespace protozero {
+namespace detail {
+
+inline uint32_t byteswap_impl(uint32_t value) noexcept {
+#ifdef PROTOZERO_USE_BUILTIN_BSWAP
+    return __builtin_bswap32(value);
+#else
+    return ((value & 0xff000000) >> 24) |
+           ((value & 0x00ff0000) >>  8) |
+           ((value & 0x0000ff00) <<  8) |
+           ((value & 0x000000ff) << 24);
+#endif
+}
+
+inline uint64_t byteswap_impl(uint64_t value) noexcept {
+#ifdef PROTOZERO_USE_BUILTIN_BSWAP
+    return __builtin_bswap64(value);
+#else
+    return ((value & 0xff00000000000000ULL) >> 56) |
+           ((value & 0x00ff000000000000ULL) >> 40) |
+           ((value & 0x0000ff0000000000ULL) >> 24) |
+           ((value & 0x000000ff00000000ULL) >>  8) |
+           ((value & 0x00000000ff000000ULL) <<  8) |
+           ((value & 0x0000000000ff0000ULL) << 24) |
+           ((value & 0x000000000000ff00ULL) << 40) |
+           ((value & 0x00000000000000ffULL) << 56);
+#endif
+}
+
+} // end namespace detail
+
+/// byteswap the data pointed to by ptr in-place.
+inline void byteswap_inplace(uint32_t* ptr) noexcept {
+    *ptr = detail::byteswap_impl(*ptr);
+}
+
+/// byteswap the data pointed to by ptr in-place.
+inline void byteswap_inplace(uint64_t* ptr) noexcept {
+    *ptr = detail::byteswap_impl(*ptr);
+}
+
+/// byteswap the data pointed to by ptr in-place.
+inline void byteswap_inplace(int32_t* ptr) noexcept {
+    auto bptr = reinterpret_cast<uint32_t*>(ptr);
+    *bptr = detail::byteswap_impl(*bptr);
+}
+
+/// byteswap the data pointed to by ptr in-place.
+inline void byteswap_inplace(int64_t* ptr) noexcept {
+    auto bptr = reinterpret_cast<uint64_t*>(ptr);
+    *bptr = detail::byteswap_impl(*bptr);
+}
+
+/// byteswap the data pointed to by ptr in-place.
+inline void byteswap_inplace(float* ptr) noexcept {
+    auto bptr = reinterpret_cast<uint32_t*>(ptr);
+    *bptr = detail::byteswap_impl(*bptr);
+}
+
+/// byteswap the data pointed to by ptr in-place.
+inline void byteswap_inplace(double* ptr) noexcept {
+    auto bptr = reinterpret_cast<uint64_t*>(ptr);
+    *bptr = detail::byteswap_impl(*bptr);
+}
+
+namespace detail {
+
+    // Added for backwards compatibility with any code that might use this
+    // function (even if it shouldn't have). Will be removed in a later
+    // version of protozero.
+    using ::protozero::byteswap_inplace;
+
+} // end namespace detail
+
+} // end namespace protozero
+
+#endif // PROTOZERO_BYTESWAP_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/config.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/config.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/config.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,48 @@
+#ifndef PROTOZERO_CONFIG_HPP
+#define PROTOZERO_CONFIG_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+#include <cassert>
+
+/**
+ * @file config.hpp
+ *
+ * @brief Contains macro checks for different configurations.
+ */
+
+#define PROTOZERO_LITTLE_ENDIAN 1234
+#define PROTOZERO_BIG_ENDIAN    4321
+
+// Find out which byte order the machine has.
+#if defined(__BYTE_ORDER)
+# if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define PROTOZERO_BYTE_ORDER PROTOZERO_LITTLE_ENDIAN
+# endif
+# if (__BYTE_ORDER == __BIG_ENDIAN)
+#  define PROTOZERO_BYTE_ORDER PROTOZERO_BIG_ENDIAN
+# endif
+#else
+// This probably isn't a very good default, but might do until we figure
+// out something better.
+# define PROTOZERO_BYTE_ORDER PROTOZERO_LITTLE_ENDIAN
+#endif
+
+// Check whether __builtin_bswap is available
+#if defined(__GNUC__) || defined(__clang__)
+# define PROTOZERO_USE_BUILTIN_BSWAP
+#endif
+
+// Wrapper for assert() used for testing
+#ifndef protozero_assert
+# define protozero_assert(x) assert(x)
+#endif
+
+#endif // PROTOZERO_CONFIG_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/data_view.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/data_view.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/data_view.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,236 @@
+#ifndef PROTOZERO_DATA_VIEW_HPP
+#define PROTOZERO_DATA_VIEW_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file data_view.hpp
+ *
+ * @brief Contains the implementation of the data_view class.
+ */
+
+#include <protozero/config.hpp>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <string>
+#include <utility>
+
+namespace protozero {
+
+#ifdef PROTOZERO_USE_VIEW
+using data_view = PROTOZERO_USE_VIEW;
+#else
+
+/**
+ * Holds a pointer to some data and a length.
+ *
+ * This class is supposed to be compatible with the std::string_view
+ * that will be available in C++17.
+ */
+class data_view {
+
+    const char* m_data = nullptr;
+    std::size_t m_size = 0;
+
+public:
+
+    /**
+     * Default constructor. Construct an empty data_view.
+     */
+    constexpr data_view() noexcept = default;
+
+    /**
+     * Create data_view from pointer and size.
+     *
+     * @param ptr Pointer to the data.
+     * @param length Length of the data.
+     */
+    constexpr data_view(const char* ptr, std::size_t length) noexcept
+        : m_data{ptr},
+          m_size{length} {
+    }
+
+    /**
+     * Create data_view from string.
+     *
+     * @param str String with the data.
+     */
+    data_view(const std::string& str) noexcept // NOLINT(google-explicit-constructor, hicpp-explicit-conversions)
+        : m_data{str.data()},
+          m_size{str.size()} {
+    }
+
+    /**
+     * Create data_view from zero-terminated string.
+     *
+     * @param ptr Pointer to the data.
+     */
+    data_view(const char* ptr) noexcept // NOLINT(google-explicit-constructor, hicpp-explicit-conversions)
+        : m_data{ptr},
+          m_size{std::strlen(ptr)} {
+    }
+
+    /**
+     * Swap the contents of this object with the other.
+     *
+     * @param other Other object to swap data with.
+     */
+    void swap(data_view& other) noexcept {
+        using std::swap;
+        swap(m_data, other.m_data);
+        swap(m_size, other.m_size);
+    }
+
+    /// Return pointer to data.
+    constexpr const char* data() const noexcept {
+        return m_data;
+    }
+
+    /// Return length of data in bytes.
+    constexpr std::size_t size() const noexcept {
+        return m_size;
+    }
+
+    /// Returns true if size is 0.
+    constexpr bool empty() const noexcept {
+        return m_size == 0;
+    }
+
+#ifndef PROTOZERO_STRICT_API
+    /**
+     * Convert data view to string.
+     *
+     * @pre Must not be default constructed data_view.
+     *
+     * @deprecated to_string() is not available in C++17 string_view so it
+     *             should not be used to make conversion to that class easier
+     *             in the future.
+     */
+    std::string to_string() const {
+        protozero_assert(m_data);
+        return {m_data, m_size};
+    }
+#endif
+
+    /**
+     * Convert data view to string.
+     *
+     * @pre Must not be default constructed data_view.
+     */
+    explicit operator std::string() const {
+        protozero_assert(m_data);
+        return {m_data, m_size};
+    }
+
+    /**
+     * Compares the contents of this object with the given other object.
+     *
+     * @returns 0 if they are the same, <0 if this object is smaller than
+     *          the other or >0 if it is larger. If both objects have the
+     *          same size returns <0 if this object is lexicographically
+     *          before the other, >0 otherwise.
+     *
+     * @pre Must not be default constructed data_view.
+     */
+    int compare(data_view other) const {
+        protozero_assert(m_data && other.m_data);
+        const int cmp = std::memcmp(data(), other.data(),
+                                    std::min(size(), other.size()));
+        if (cmp == 0) {
+            if (size() == other.size()) {
+                return 0;
+            }
+            return size() < other.size() ? -1 : 1;
+        }
+        return cmp;
+    }
+
+}; // class data_view
+
+/**
+ * Swap two data_view objects.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline void swap(data_view& lhs, data_view& rhs) noexcept {
+    lhs.swap(rhs);
+}
+
+/**
+ * Two data_view instances are equal if they have the same size and the
+ * same content.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline constexpr bool operator==(const data_view lhs, const data_view rhs) noexcept {
+    return lhs.size() == rhs.size() &&
+           std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data());
+}
+
+/**
+ * Two data_view instances are not equal if they have different sizes or the
+ * content differs.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline constexpr bool operator!=(const data_view lhs, const data_view rhs) noexcept {
+    return !(lhs == rhs);
+}
+
+/**
+ * Returns true if lhs.compare(rhs) < 0.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline bool operator<(const data_view lhs, const data_view rhs) noexcept {
+    return lhs.compare(rhs) < 0;
+}
+
+/**
+ * Returns true if lhs.compare(rhs) <= 0.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline bool operator<=(const data_view lhs, const data_view rhs) noexcept {
+    return lhs.compare(rhs) <= 0;
+}
+
+/**
+ * Returns true if lhs.compare(rhs) > 0.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline bool operator>(const data_view lhs, const data_view rhs) noexcept {
+    return lhs.compare(rhs) > 0;
+}
+
+/**
+ * Returns true if lhs.compare(rhs) >= 0.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline bool operator>=(const data_view lhs, const data_view rhs) noexcept {
+    return lhs.compare(rhs) >= 0;
+}
+
+#endif
+
+} // end namespace protozero
+
+#endif // PROTOZERO_DATA_VIEW_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/exception.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/exception.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/exception.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,101 @@
+#ifndef PROTOZERO_EXCEPTION_HPP
+#define PROTOZERO_EXCEPTION_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file exception.hpp
+ *
+ * @brief Contains the exceptions used in the protozero library.
+ */
+
+#include <exception>
+
+/**
+ * @brief All parts of the protozero header-only library are in this namespace.
+ */
+namespace protozero {
+
+/**
+ * All exceptions explicitly thrown by the functions of the protozero library
+ * derive from this exception.
+ */
+struct exception : std::exception {
+    /// Returns the explanatory string.
+    const char* what() const noexcept override {
+        return "pbf exception";
+    }
+};
+
+/**
+ * This exception is thrown when parsing a varint thats larger than allowed.
+ * This should never happen unless the data is corrupted.
+ */
+struct varint_too_long_exception : exception {
+    /// Returns the explanatory string.
+    const char* what() const noexcept override {
+        return "varint too long exception";
+    }
+};
+
+/**
+ * This exception is thrown when the wire type of a pdf field is unknown.
+ * This should never happen unless the data is corrupted.
+ */
+struct unknown_pbf_wire_type_exception : exception {
+    /// Returns the explanatory string.
+    const char* what() const noexcept override {
+        return "unknown pbf field type exception";
+    }
+};
+
+/**
+ * This exception is thrown when we are trying to read a field and there
+ * are not enough bytes left in the buffer to read it. Almost all functions
+ * of the pbf_reader class can throw this exception.
+ *
+ * This should never happen unless the data is corrupted or you have
+ * initialized the pbf_reader object with incomplete data.
+ */
+struct end_of_buffer_exception : exception {
+    /// Returns the explanatory string.
+    const char* what() const noexcept override {
+        return "end of buffer exception";
+    }
+};
+
+/**
+ * This exception is thrown when a tag has an invalid value. Tags must be
+ * unsigned integers between 1 and 2^29-1. Tags between 19000 and 19999 are
+ * not allowed. See
+ * https://developers.google.com/protocol-buffers/docs/proto#assigning-tags
+ */
+struct invalid_tag_exception : exception {
+    /// Returns the explanatory string.
+    const char* what() const noexcept override {
+        return "invalid tag exception";
+    }
+};
+
+/**
+ * This exception is thrown when a length field of a packed repeated field is
+ * invalid. For fixed size types the length must be a multiple of the size of
+ * the type.
+ */
+struct invalid_length_exception : exception {
+    /// Returns the explanatory string.
+    const char* what() const noexcept override {
+        return "invalid length exception";
+    }
+};
+
+} // end namespace protozero
+
+#endif // PROTOZERO_EXCEPTION_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/iterators.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/iterators.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/iterators.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,481 @@
+#ifndef PROTOZERO_ITERATORS_HPP
+#define PROTOZERO_ITERATORS_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file iterators.hpp
+ *
+ * @brief Contains the iterators for access to packed repeated fields.
+ */
+
+#include <protozero/config.hpp>
+#include <protozero/varint.hpp>
+
+#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
+# include <protozero/byteswap.hpp>
+#endif
+
+#include <algorithm>
+#include <cstring>
+#include <iterator>
+#include <utility>
+
+namespace protozero {
+
+/**
+ * A range of iterators based on std::pair. Created from beginning and
+ * end iterators. Used as a return type from some pbf_reader methods
+ * that is easy to use with range-based for loops.
+ */
+template <typename T, typename P = std::pair<T, T>>
+class iterator_range :
+#ifdef PROTOZERO_STRICT_API
+    protected
+#else
+    public
+#endif
+        P {
+
+public:
+
+    /// The type of the iterators in this range.
+    using iterator = T;
+
+    /// The value type of the underlying iterator.
+    using value_type = typename std::iterator_traits<T>::value_type;
+
+    /**
+     * Default constructor. Create empty iterator_range.
+     */
+    constexpr iterator_range() :
+        P{iterator{}, iterator{}} {
+    }
+
+    /**
+     * Create iterator range from two iterators.
+     *
+     * @param first_iterator Iterator to beginning of range.
+     * @param last_iterator Iterator to end of range.
+     */
+    constexpr iterator_range(iterator&& first_iterator, iterator&& last_iterator) :
+        P{std::forward<iterator>(first_iterator),
+          std::forward<iterator>(last_iterator)} {
+    }
+
+    /// Return iterator to beginning of range.
+    constexpr iterator begin() const noexcept {
+        return this->first;
+    }
+
+    /// Return iterator to end of range.
+    constexpr iterator end() const noexcept {
+        return this->second;
+    }
+
+    /// Return iterator to beginning of range.
+    constexpr iterator cbegin() const noexcept {
+        return this->first;
+    }
+
+    /// Return iterator to end of range.
+    constexpr iterator cend() const noexcept {
+        return this->second;
+    }
+
+    /**
+     * Return true if this range is empty.
+     *
+     * Complexity: Constant.
+     */
+    constexpr bool empty() const noexcept {
+        return begin() == end();
+    }
+
+    /**
+     * Get the size of the range, ie the number of elements it contains.
+     *
+     * Complexity: Constant or linear depending on the underlaying iterator.
+     */
+    std::size_t size() const noexcept {
+        return static_cast<size_t>(std::distance(begin(), end()));
+    }
+
+    /**
+     * Get element at the beginning of the range.
+     *
+     * @pre Range must not be empty.
+     */
+    value_type front() const {
+        protozero_assert(!empty());
+        return *(this->first);
+    }
+
+    /**
+     * Advance beginning of range by one.
+     *
+     * @pre Range must not be empty.
+     */
+    void drop_front() {
+        protozero_assert(!empty());
+        ++this->first;
+    }
+
+    /**
+     * Swap the contents of this range with the other.
+     *
+     * @param other Other range to swap data with.
+     */
+    void swap(iterator_range& other) noexcept {
+        using std::swap;
+        swap(this->first, other.first);
+        swap(this->second, other.second);
+    }
+
+}; // struct iterator_range
+
+/**
+ * Swap two iterator_ranges.
+ *
+ * @param lhs First range.
+ * @param rhs Second range.
+ */
+template <typename T>
+inline void swap(iterator_range<T>& lhs, iterator_range<T>& rhs) noexcept {
+    lhs.swap(rhs);
+}
+
+/**
+ * A forward iterator used for accessing packed repeated fields of fixed
+ * length (fixed32, sfixed32, float, double).
+ */
+template <typename T>
+class const_fixed_iterator {
+
+    /// Pointer to current iterator position
+    const char* m_data = nullptr;
+
+public:
+
+    /// @cond usual iterator functions not documented
+
+    using iterator_category = std::random_access_iterator_tag;
+    using value_type        = T;
+    using difference_type   = std::ptrdiff_t;
+    using pointer           = value_type*;
+    using reference         = value_type&;
+
+    const_fixed_iterator() noexcept = default;
+
+    explicit const_fixed_iterator(const char* data) noexcept :
+        m_data{data} {
+    }
+
+    const_fixed_iterator(const const_fixed_iterator&) noexcept = default;
+    const_fixed_iterator(const_fixed_iterator&&) noexcept = default;
+
+    const_fixed_iterator& operator=(const const_fixed_iterator&) noexcept = default;
+    const_fixed_iterator& operator=(const_fixed_iterator&&) noexcept = default;
+
+    ~const_fixed_iterator() noexcept = default;
+
+    value_type operator*() const noexcept {
+        value_type result;
+        std::memcpy(&result, m_data, sizeof(value_type));
+#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
+        byteswap_inplace(&result);
+#endif
+        return result;
+    }
+
+    const_fixed_iterator& operator++() noexcept {
+        m_data += sizeof(value_type);
+        return *this;
+    }
+
+    const_fixed_iterator operator++(int) noexcept {
+        const const_fixed_iterator tmp{*this};
+        ++(*this);
+        return tmp;
+    }
+
+    const_fixed_iterator& operator--() noexcept {
+        m_data -= sizeof(value_type);
+        return *this;
+    }
+
+    const_fixed_iterator operator--(int) noexcept {
+        const const_fixed_iterator tmp{*this};
+        --(*this);
+        return tmp;
+    }
+
+    friend bool operator==(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept {
+        return lhs.m_data == rhs.m_data;
+    }
+
+    friend bool operator!=(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept {
+        return !(lhs == rhs);
+    }
+
+    friend bool operator<(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept {
+        return lhs.m_data < rhs.m_data;
+    }
+
+    friend bool operator>(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept {
+        return rhs < lhs;
+    }
+
+    friend bool operator<=(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept {
+        return !(lhs > rhs);
+    }
+
+    friend bool operator>=(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept {
+        return !(lhs < rhs);
+    }
+
+    const_fixed_iterator& operator+=(difference_type val) noexcept {
+        m_data += (sizeof(value_type) * val);
+        return *this;
+    }
+
+    friend const_fixed_iterator operator+(const_fixed_iterator lhs, difference_type rhs) noexcept {
+        const_fixed_iterator tmp{lhs};
+        tmp.m_data += (sizeof(value_type) * rhs);
+        return tmp;
+    }
+
+    friend const_fixed_iterator operator+(difference_type lhs, const_fixed_iterator rhs) noexcept {
+        const_fixed_iterator tmp{rhs};
+        tmp.m_data += (sizeof(value_type) * lhs);
+        return tmp;
+    }
+
+    const_fixed_iterator& operator-=(difference_type val) noexcept {
+        m_data -= (sizeof(value_type) * val);
+        return *this;
+    }
+
+    friend const_fixed_iterator operator-(const_fixed_iterator lhs, difference_type rhs) noexcept {
+        const_fixed_iterator tmp{lhs};
+        tmp.m_data -= (sizeof(value_type) * rhs);
+        return tmp;
+    }
+
+    friend difference_type operator-(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept {
+        return static_cast<difference_type>(lhs.m_data - rhs.m_data) / static_cast<difference_type>(sizeof(T));
+    }
+
+    value_type operator[](difference_type n) const noexcept {
+        return *(*this + n);
+    }
+
+    /// @endcond
+
+}; // class const_fixed_iterator
+
+/**
+ * A forward iterator used for accessing packed repeated varint fields
+ * (int32, uint32, int64, uint64, bool, enum).
+ */
+template <typename T>
+class const_varint_iterator {
+
+protected:
+
+    /// Pointer to current iterator position
+    const char* m_data = nullptr;
+
+    /// Pointer to end iterator position
+    const char* m_end = nullptr;
+
+public:
+
+    /// @cond usual iterator functions not documented
+
+    using iterator_category = std::forward_iterator_tag;
+    using value_type        = T;
+    using difference_type   = std::ptrdiff_t;
+    using pointer           = value_type*;
+    using reference         = value_type&;
+
+    static difference_type distance(const_varint_iterator begin, const_varint_iterator end) noexcept {
+        // The "distance" between default initialized const_varint_iterator's
+        // is always 0.
+        if (!begin.m_data) {
+            return 0;
+        }
+        // We know that each varint contains exactly one byte with the most
+        // significant bit not set. We can use this to quickly figure out
+        // how many varints there are without actually decoding the varints.
+        return std::count_if(begin.m_data, end.m_data, [](char c) noexcept {
+            return (static_cast<unsigned char>(c) & 0x80u) == 0;
+        });
+    }
+
+    const_varint_iterator() noexcept = default;
+
+    const_varint_iterator(const char* data, const char* end) noexcept :
+        m_data{data},
+        m_end{end} {
+    }
+
+    const_varint_iterator(const const_varint_iterator&) noexcept = default;
+    const_varint_iterator(const_varint_iterator&&) noexcept = default;
+
+    const_varint_iterator& operator=(const const_varint_iterator&) noexcept = default;
+    const_varint_iterator& operator=(const_varint_iterator&&) noexcept = default;
+
+    ~const_varint_iterator() noexcept = default;
+
+    value_type operator*() const {
+        protozero_assert(m_data);
+        const char* d = m_data; // will be thrown away
+        return static_cast<value_type>(decode_varint(&d, m_end));
+    }
+
+    const_varint_iterator& operator++() {
+        protozero_assert(m_data);
+        skip_varint(&m_data, m_end);
+        return *this;
+    }
+
+    const_varint_iterator operator++(int) {
+        protozero_assert(m_data);
+        const const_varint_iterator tmp{*this};
+        ++(*this);
+        return tmp;
+    }
+
+    bool operator==(const const_varint_iterator& rhs) const noexcept {
+        return m_data == rhs.m_data && m_end == rhs.m_end;
+    }
+
+    bool operator!=(const const_varint_iterator& rhs) const noexcept {
+        return !(*this == rhs);
+    }
+
+    /// @endcond
+
+}; // class const_varint_iterator
+
+/**
+ * A forward iterator used for accessing packed repeated svarint fields
+ * (sint32, sint64).
+ */
+template <typename T>
+class const_svarint_iterator : public const_varint_iterator<T> {
+
+public:
+
+    /// @cond usual iterator functions not documented
+
+    using iterator_category = std::forward_iterator_tag;
+    using value_type        = T;
+    using difference_type   = std::ptrdiff_t;
+    using pointer           = value_type*;
+    using reference         = value_type&;
+
+    const_svarint_iterator() noexcept :
+        const_varint_iterator<T>{} {
+    }
+
+    const_svarint_iterator(const char* data, const char* end) noexcept :
+        const_varint_iterator<T>{data, end} {
+    }
+
+    const_svarint_iterator(const const_svarint_iterator&) = default;
+    const_svarint_iterator(const_svarint_iterator&&) noexcept = default;
+
+    const_svarint_iterator& operator=(const const_svarint_iterator&) = default;
+    const_svarint_iterator& operator=(const_svarint_iterator&&) noexcept = default;
+
+    ~const_svarint_iterator() = default;
+
+    value_type operator*() const {
+        protozero_assert(this->m_data);
+        const char* d = this->m_data; // will be thrown away
+        return static_cast<value_type>(decode_zigzag64(decode_varint(&d, this->m_end)));
+    }
+
+    const_svarint_iterator& operator++() {
+        protozero_assert(this->m_data);
+        skip_varint(&this->m_data, this->m_end);
+        return *this;
+    }
+
+    const_svarint_iterator operator++(int) {
+        protozero_assert(this->m_data);
+        const const_svarint_iterator tmp{*this};
+        ++(*this);
+        return tmp;
+    }
+
+    /// @endcond
+
+}; // class const_svarint_iterator
+
+} // end namespace protozero
+
+namespace std {
+
+    // Specialize std::distance for all the protozero iterators. Because
+    // functions can't be partially specialized, we have to do this for
+    // every value_type we are using.
+
+    /// @cond individual overloads do not need to be documented
+
+    template <>
+    inline typename protozero::const_varint_iterator<int32_t>::difference_type
+    distance<protozero::const_varint_iterator<int32_t>>(protozero::const_varint_iterator<int32_t> first, // NOLINT(readability-inconsistent-declaration-parameter-name)
+                                                        protozero::const_varint_iterator<int32_t> last) {
+        return protozero::const_varint_iterator<int32_t>::distance(first, last);
+    }
+
+    template <>
+    inline typename protozero::const_varint_iterator<int64_t>::difference_type
+    distance<protozero::const_varint_iterator<int64_t>>(protozero::const_varint_iterator<int64_t> first, // NOLINT(readability-inconsistent-declaration-parameter-name)
+                                                        protozero::const_varint_iterator<int64_t> last) {
+        return protozero::const_varint_iterator<int64_t>::distance(first, last);
+    }
+
+    template <>
+    inline typename protozero::const_varint_iterator<uint32_t>::difference_type
+    distance<protozero::const_varint_iterator<uint32_t>>(protozero::const_varint_iterator<uint32_t> first, // NOLINT(readability-inconsistent-declaration-parameter-name)
+                                                         protozero::const_varint_iterator<uint32_t> last) {
+        return protozero::const_varint_iterator<uint32_t>::distance(first, last);
+    }
+
+    template <>
+    inline typename protozero::const_varint_iterator<uint64_t>::difference_type
+    distance<protozero::const_varint_iterator<uint64_t>>(protozero::const_varint_iterator<uint64_t> first, // NOLINT(readability-inconsistent-declaration-parameter-name)
+                                                         protozero::const_varint_iterator<uint64_t> last) {
+        return protozero::const_varint_iterator<uint64_t>::distance(first, last);
+    }
+
+    template <>
+    inline typename protozero::const_svarint_iterator<int32_t>::difference_type
+    distance<protozero::const_svarint_iterator<int32_t>>(protozero::const_svarint_iterator<int32_t> first, // NOLINT(readability-inconsistent-declaration-parameter-name)
+                                                         protozero::const_svarint_iterator<int32_t> last) {
+        return protozero::const_svarint_iterator<int32_t>::distance(first, last);
+    }
+
+    template <>
+    inline typename protozero::const_svarint_iterator<int64_t>::difference_type
+    distance<protozero::const_svarint_iterator<int64_t>>(protozero::const_svarint_iterator<int64_t> first, // NOLINT(readability-inconsistent-declaration-parameter-name)
+                                                         protozero::const_svarint_iterator<int64_t> last) {
+        return protozero::const_svarint_iterator<int64_t>::distance(first, last);
+    }
+
+    /// @endcond
+
+} // end namespace std
+
+#endif // PROTOZERO_ITERATORS_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_builder.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_builder.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_builder.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,265 @@
+#ifndef PROTOZERO_PBF_BUILDER_HPP
+#define PROTOZERO_PBF_BUILDER_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file pbf_builder.hpp
+ *
+ * @brief Contains the pbf_builder template class.
+ */
+
+#include <protozero/pbf_writer.hpp>
+#include <protozero/types.hpp>
+
+#include <type_traits>
+
+namespace protozero {
+
+/**
+ * The pbf_builder is used to write PBF formatted messages into a buffer. It
+ * is based on the pbf_writer class and has all the same methods. The
+ * difference is that while the pbf_writer class takes an integer tag,
+ * this template class takes a tag of the template type T. The idea is that
+ * T will be an enumeration value and this helps reduce the possibility of
+ * programming errors.
+ *
+ * Almost all methods in this class can throw an std::bad_alloc exception if
+ * the std::string used as a buffer wants to resize.
+ *
+ * Read the tutorial to understand how this class is used.
+ */
+template <typename T>
+class pbf_builder : public pbf_writer {
+
+    static_assert(std::is_same<pbf_tag_type, typename std::underlying_type<T>::type>::value,
+                  "T must be enum with underlying type protozero::pbf_tag_type");
+
+public:
+
+    /// The type of messages this class will build.
+    using enum_type = T;
+
+    pbf_builder() = default;
+
+    /**
+     * Create a builder using the given string as a data store. The object
+     * stores a reference to that string and adds all data to it. The string
+     * doesn't have to be empty. The pbf_message object will just append data.
+     */
+    explicit pbf_builder(std::string& data) noexcept :
+        pbf_writer{data} {
+    }
+
+    /**
+     * Construct a pbf_builder for a submessage from the pbf_message or
+     * pbf_writer of the parent message.
+     *
+     * @param parent_writer The parent pbf_message or pbf_writer
+     * @param tag Tag of the field that will be written
+     */
+    template <typename P>
+    pbf_builder(pbf_writer& parent_writer, P tag) noexcept :
+        pbf_writer{parent_writer, pbf_tag_type(tag)} {
+    }
+
+/// @cond INTERNAL
+#define PROTOZERO_WRITER_WRAP_ADD_SCALAR(name, type) \
+    void add_##name(T tag, type value) { \
+        pbf_writer::add_##name(pbf_tag_type(tag), value); \
+    }
+
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(bool, bool)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(enum, int32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(int32, int32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint32, int32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint32, uint32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(int64, int64_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint64, int64_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint64, uint64_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed32, uint32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed32, int32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed64, uint64_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed64, int64_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(float, float)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(double, double)
+
+#undef PROTOZERO_WRITER_WRAP_ADD_SCALAR
+/// @endcond
+
+    /**
+     * Add "bytes" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Pointer to value to be written
+     * @param size Number of bytes to be written
+     */
+    void add_bytes(T tag, const char* value, std::size_t size) {
+        pbf_writer::add_bytes(pbf_tag_type(tag), value, size);
+    }
+
+    /**
+     * Add "bytes" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written
+     */
+    void add_bytes(T tag, const data_view& value) {
+        pbf_writer::add_bytes(pbf_tag_type(tag), value);
+    }
+
+    /**
+     * Add "bytes" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written
+     */
+    void add_bytes(T tag, const std::string& value) {
+        pbf_writer::add_bytes(pbf_tag_type(tag), value);
+    }
+
+    /**
+     * Add "bytes" field to data. Bytes from the value are written until
+     * a null byte is encountered. The null byte is not added.
+     *
+     * @param tag Tag of the field
+     * @param value Pointer to zero-delimited value to be written
+     */
+    void add_bytes(T tag, const char* value) {
+        pbf_writer::add_bytes(pbf_tag_type(tag), value);
+    }
+
+    /**
+     * Add "bytes" field to data using vectored input. All the data in the
+     * 2nd and further arguments is "concatenated" with only a single copy
+     * into the final buffer.
+     *
+     * This will work with objects of any type supporting the data() and
+     * size() methods like std::string or protozero::data_view.
+     *
+     * Example:
+     * @code
+     * std::string data1 = "abc";
+     * std::string data2 = "xyz";
+     * builder.add_bytes_vectored(1, data1, data2);
+     * @endcode
+     *
+     * @tparam Ts List of types supporting data() and size() methods.
+     * @param tag Tag of the field
+     * @param values List of objects of types Ts with data to be appended.
+     */
+    template <typename... Ts>
+    void add_bytes_vectored(T tag, Ts&&... values) {
+        pbf_writer::add_bytes_vectored(pbf_tag_type(tag), std::forward<Ts>(values)...);
+    }
+
+    /**
+     * Add "string" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Pointer to value to be written
+     * @param size Number of bytes to be written
+     */
+    void add_string(T tag, const char* value, std::size_t size) {
+        pbf_writer::add_string(pbf_tag_type(tag), value, size);
+    }
+
+    /**
+     * Add "string" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written
+     */
+    void add_string(T tag, const data_view& value) {
+        pbf_writer::add_string(pbf_tag_type(tag), value);
+    }
+
+    /**
+     * Add "string" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written
+     */
+    void add_string(T tag, const std::string& value) {
+        pbf_writer::add_string(pbf_tag_type(tag), value);
+    }
+
+    /**
+     * Add "string" field to data. Bytes from the value are written until
+     * a null byte is encountered. The null byte is not added.
+     *
+     * @param tag Tag of the field
+     * @param value Pointer to value to be written
+     */
+    void add_string(T tag, const char* value) {
+        pbf_writer::add_string(pbf_tag_type(tag), value);
+    }
+
+    /**
+     * Add "message" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Pointer to message to be written
+     * @param size Length of the message
+     */
+    void add_message(T tag, const char* value, std::size_t size) {
+        pbf_writer::add_message(pbf_tag_type(tag), value, size);
+    }
+
+    /**
+     * Add "message" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written. The value must be a complete message.
+     */
+    void add_message(T tag, const data_view& value) {
+        pbf_writer::add_message(pbf_tag_type(tag), value);
+    }
+
+    /**
+     * Add "message" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written. The value must be a complete message.
+     */
+    void add_message(T tag, const std::string& value) {
+        pbf_writer::add_message(pbf_tag_type(tag), value);
+    }
+
+/// @cond INTERNAL
+#define PROTOZERO_WRITER_WRAP_ADD_PACKED(name) \
+    template <typename InputIterator> \
+    void add_packed_##name(T tag, InputIterator first, InputIterator last) { \
+        pbf_writer::add_packed_##name(pbf_tag_type(tag), first, last); \
+    }
+
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(bool)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(enum)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(int32)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(sint32)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(uint32)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(int64)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(sint64)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(uint64)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed32)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed32)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed64)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed64)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(float)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(double)
+
+#undef PROTOZERO_WRITER_WRAP_ADD_PACKED
+/// @endcond
+
+}; // class pbf_builder
+
+} // end namespace protozero
+
+#endif // PROTOZERO_PBF_BUILDER_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_message.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_message.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_message.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,184 @@
+#ifndef PROTOZERO_PBF_MESSAGE_HPP
+#define PROTOZERO_PBF_MESSAGE_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file pbf_message.hpp
+ *
+ * @brief Contains the pbf_message template class.
+ */
+
+#include <protozero/pbf_reader.hpp>
+#include <protozero/types.hpp>
+
+#include <type_traits>
+
+namespace protozero {
+
+/**
+ * This class represents a protobuf message. Either a top-level message or
+ * a nested sub-message. Top-level messages can be created from any buffer
+ * with a pointer and length:
+ *
+ * @code
+ *    enum class Message : protozero::pbf_tag_type {
+ *       ...
+ *    };
+ *
+ *    std::string buffer;
+ *    // fill buffer...
+ *    pbf_message<Message> message{buffer.data(), buffer.size()};
+ * @endcode
+ *
+ * Sub-messages are created using get_message():
+ *
+ * @code
+ *    enum class SubMessage : protozero::pbf_tag_type {
+ *       ...
+ *    };
+ *
+ *    pbf_message<Message> message{...};
+ *    message.next();
+ *    pbf_message<SubMessage> submessage = message.get_message();
+ * @endcode
+ *
+ * All methods of the pbf_message class except get_bytes() and get_string()
+ * provide the strong exception guarantee, ie they either succeed or do not
+ * change the pbf_message object they are called on. Use the get_data() method
+ * instead of get_bytes() or get_string(), if you need this guarantee.
+ *
+ * This template class is based on the pbf_reader class and has all the same
+ * methods. The difference is that whereever the pbf_reader class takes an
+ * integer tag, this template class takes a tag of the template type T.
+ *
+ * Read the tutorial to understand how this class is used.
+ */
+template <typename T>
+class pbf_message : public pbf_reader {
+
+    static_assert(std::is_same<pbf_tag_type, typename std::underlying_type<T>::type>::value,
+                  "T must be enum with underlying type protozero::pbf_tag_type");
+
+public:
+
+    /// The type of messages this class will read.
+    using enum_type = T;
+
+    /**
+     * Construct a pbf_message. All arguments are forwarded to the pbf_reader
+     * parent class.
+     */
+    template <typename... Args>
+    pbf_message(Args&&... args) noexcept : // NOLINT(google-explicit-constructor, hicpp-explicit-conversions)
+        pbf_reader{std::forward<Args>(args)...} {
+    }
+
+    /**
+     * Set next field in the message as the current field. This is usually
+     * called in a while loop:
+     *
+     * @code
+     *    pbf_message<...> message(...);
+     *    while (message.next()) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * @returns `true` if there is a next field, `false` if not.
+     * @pre There must be no current field.
+     * @post If it returns `true` there is a current field now.
+     */
+    bool next() {
+        return pbf_reader::next();
+    }
+
+    /**
+     * Set next field with given tag in the message as the current field.
+     * Fields with other tags are skipped. This is usually called in a while
+     * loop for repeated fields:
+     *
+     * @code
+     *    pbf_message<Example1> message{...};
+     *    while (message.next(Example1::repeated_fixed64_r)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * or you can call it just once to get the one field with this tag:
+     *
+     * @code
+     *    pbf_message<Example1> message{...};
+     *    if (message.next(Example1::required_uint32_x)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * Note that this will not check the wire type. The two-argument version
+     * of this function will also check the wire type.
+     *
+     * @returns `true` if there is a next field with this tag.
+     * @pre There must be no current field.
+     * @post If it returns `true` there is a current field now with the given tag.
+     */
+    bool next(T next_tag) {
+        return pbf_reader::next(pbf_tag_type(next_tag));
+    }
+
+    /**
+     * Set next field with given tag and wire type in the message as the
+     * current field. Fields with other tags are skipped. This is usually
+     * called in a while loop for repeated fields:
+     *
+     * @code
+     *    pbf_message<Example1> message{...};
+     *    while (message.next(Example1::repeated_fixed64_r, pbf_wire_type::varint)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * or you can call it just once to get the one field with this tag:
+     *
+     * @code
+     *    pbf_message<Example1> message{...};
+     *    if (message.next(Example1::required_uint32_x, pbf_wire_type::varint)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * Note that this will also check the wire type. The one-argument version
+     * of this function will not check the wire type.
+     *
+     * @returns `true` if there is a next field with this tag.
+     * @pre There must be no current field.
+     * @post If it returns `true` there is a current field now with the given tag.
+     */
+    bool next(T next_tag, pbf_wire_type type) {
+        return pbf_reader::next(pbf_tag_type(next_tag), type);
+    }
+
+    /**
+     * The tag of the current field. The tag is the enum value for the field
+     * number from the description in the .proto file.
+     *
+     * Call next() before calling this function to set the current field.
+     *
+     * @returns tag of the current field.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     */
+    T tag() const noexcept {
+        return T(pbf_reader::tag());
+    }
+
+}; // class pbf_message
+
+} // end namespace protozero
+
+#endif // PROTOZERO_PBF_MESSAGE_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_reader.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_reader.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_reader.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,977 @@
+#ifndef PROTOZERO_PBF_READER_HPP
+#define PROTOZERO_PBF_READER_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file pbf_reader.hpp
+ *
+ * @brief Contains the pbf_reader class.
+ */
+
+#include <protozero/config.hpp>
+#include <protozero/data_view.hpp>
+#include <protozero/exception.hpp>
+#include <protozero/iterators.hpp>
+#include <protozero/types.hpp>
+#include <protozero/varint.hpp>
+
+#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
+# include <protozero/byteswap.hpp>
+#endif
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <utility>
+
+namespace protozero {
+
+/**
+ * This class represents a protobuf message. Either a top-level message or
+ * a nested sub-message. Top-level messages can be created from any buffer
+ * with a pointer and length:
+ *
+ * @code
+ *    std::string buffer;
+ *    // fill buffer...
+ *    pbf_reader message{buffer.data(), buffer.size()};
+ * @endcode
+ *
+ * Sub-messages are created using get_message():
+ *
+ * @code
+ *    pbf_reader message{...};
+ *    message.next();
+ *    pbf_reader submessage = message.get_message();
+ * @endcode
+ *
+ * All methods of the pbf_reader class except get_bytes() and get_string()
+ * provide the strong exception guarantee, ie they either succeed or do not
+ * change the pbf_reader object they are called on. Use the get_view() method
+ * instead of get_bytes() or get_string(), if you need this guarantee.
+ */
+class pbf_reader {
+
+    // A pointer to the next unread data.
+    const char* m_data = nullptr;
+
+    // A pointer to one past the end of data.
+    const char* m_end = nullptr;
+
+    // The wire type of the current field.
+    pbf_wire_type m_wire_type = pbf_wire_type::unknown;
+
+    // The tag of the current field.
+    pbf_tag_type m_tag = 0;
+
+    template <typename T>
+    T get_fixed() {
+        T result;
+        const char* data = m_data;
+        skip_bytes(sizeof(T));
+        std::memcpy(&result, data, sizeof(T));
+#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
+        byteswap_inplace(&result);
+#endif
+        return result;
+    }
+
+    template <typename T>
+    iterator_range<const_fixed_iterator<T>> packed_fixed() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        const auto len = get_len_and_skip();
+        if (len % sizeof(T) != 0) {
+            throw invalid_length_exception{};
+        }
+        return {const_fixed_iterator<T>(m_data - len),
+                const_fixed_iterator<T>(m_data)};
+    }
+
+    template <typename T>
+    T get_varint() {
+        const auto val = static_cast<T>(decode_varint(&m_data, m_end));
+        return val;
+    }
+
+    template <typename T>
+    T get_svarint() {
+        protozero_assert((has_wire_type(pbf_wire_type::varint) || has_wire_type(pbf_wire_type::length_delimited)) && "not a varint");
+        return static_cast<T>(decode_zigzag64(decode_varint(&m_data, m_end)));
+    }
+
+    pbf_length_type get_length() {
+        return get_varint<pbf_length_type>();
+    }
+
+    void skip_bytes(pbf_length_type len) {
+        if (m_end - m_data < static_cast<ptrdiff_t>(len)) {
+            throw end_of_buffer_exception{};
+        }
+        m_data += len;
+
+#ifndef NDEBUG
+        // In debug builds reset the tag to zero so that we can detect (some)
+        // wrong code.
+        m_tag = 0;
+#endif
+    }
+
+    pbf_length_type get_len_and_skip() {
+        const auto len = get_length();
+        skip_bytes(len);
+        return len;
+    }
+
+    template <typename T>
+    iterator_range<T> get_packed() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        const auto len = get_len_and_skip();
+        return {T{m_data - len, m_data},
+                T{m_data, m_data}};
+    }
+
+public:
+
+    /**
+     * Construct a pbf_reader message from a data_view. The pointer from the
+     * data_view will be stored inside the pbf_reader object, no data is
+     * copied. So you must make sure the view stays valid as long as the
+     * pbf_reader object is used.
+     *
+     * The buffer must contain a complete protobuf message.
+     *
+     * @post There is no current field.
+     */
+    explicit pbf_reader(const data_view& view) noexcept
+        : m_data{view.data()},
+          m_end{view.data() + view.size()} {
+    }
+
+    /**
+     * Construct a pbf_reader message from a data pointer and a length. The
+     * pointer will be stored inside the pbf_reader object, no data is copied.
+     * So you must make sure the buffer stays valid as long as the pbf_reader
+     * object is used.
+     *
+     * The buffer must contain a complete protobuf message.
+     *
+     * @post There is no current field.
+     */
+    pbf_reader(const char* data, std::size_t size) noexcept
+        : m_data{data},
+          m_end{data + size} {
+    }
+
+#ifndef PROTOZERO_STRICT_API
+    /**
+     * Construct a pbf_reader message from a data pointer and a length. The
+     * pointer will be stored inside the pbf_reader object, no data is copied.
+     * So you must make sure the buffer stays valid as long as the pbf_reader
+     * object is used.
+     *
+     * The buffer must contain a complete protobuf message.
+     *
+     * @post There is no current field.
+     * @deprecated Use one of the other constructors.
+     */
+    explicit pbf_reader(const std::pair<const char*, std::size_t>& data) noexcept
+        : m_data{data.first},
+          m_end{data.first + data.second} {
+    }
+#endif
+
+    /**
+     * Construct a pbf_reader message from a std::string. A pointer to the
+     * string internals will be stored inside the pbf_reader object, no data
+     * is copied. So you must make sure the string is unchanged as long as the
+     * pbf_reader object is used.
+     *
+     * The string must contain a complete protobuf message.
+     *
+     * @post There is no current field.
+     */
+    explicit pbf_reader(const std::string& data) noexcept
+        : m_data{data.data()},
+          m_end{data.data() + data.size()} {
+    }
+
+    /**
+     * pbf_reader can be default constructed and behaves like it has an empty
+     * buffer.
+     */
+    pbf_reader() noexcept = default;
+
+    /// pbf_reader messages can be copied trivially.
+    pbf_reader(const pbf_reader&) noexcept = default;
+
+    /// pbf_reader messages can be moved trivially.
+    pbf_reader(pbf_reader&&) noexcept = default;
+
+    /// pbf_reader messages can be copied trivially.
+    pbf_reader& operator=(const pbf_reader& other) noexcept = default;
+
+    /// pbf_reader messages can be moved trivially.
+    pbf_reader& operator=(pbf_reader&& other) noexcept = default;
+
+    ~pbf_reader() = default;
+
+    /**
+     * Swap the contents of this object with the other.
+     *
+     * @param other Other object to swap data with.
+     */
+    void swap(pbf_reader& other) noexcept {
+        using std::swap;
+        swap(m_data, other.m_data);
+        swap(m_end, other.m_end);
+        swap(m_wire_type, other.m_wire_type);
+        swap(m_tag, other.m_tag);
+    }
+
+    /**
+     * In a boolean context the pbf_reader class evaluates to `true` if there
+     * are still fields available and to `false` if the last field has been
+     * read.
+     */
+    operator bool() const noexcept { // NOLINT(google-explicit-constructor, hicpp-explicit-conversions)
+        return m_data != m_end;
+    }
+
+    /**
+     * Get a view of the not yet read data.
+     */
+    data_view data() const noexcept {
+        return {m_data, static_cast<std::size_t>(m_end - m_data)};
+    }
+
+    /**
+     * Return the length in bytes of the current message. If you have
+     * already called next() and/or any of the get_*() functions, this will
+     * return the remaining length.
+     *
+     * This can, for instance, be used to estimate the space needed for a
+     * buffer. Of course you have to know reasonably well what data to expect
+     * and how it is encoded for this number to have any meaning.
+     */
+    std::size_t length() const noexcept {
+        return std::size_t(m_end - m_data);
+    }
+
+    /**
+     * Set next field in the message as the current field. This is usually
+     * called in a while loop:
+     *
+     * @code
+     *    pbf_reader message(...);
+     *    while (message.next()) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * @returns `true` if there is a next field, `false` if not.
+     * @pre There must be no current field.
+     * @post If it returns `true` there is a current field now.
+     */
+    bool next() {
+        if (m_data == m_end) {
+            return false;
+        }
+
+        const auto value = get_varint<uint32_t>();
+        m_tag = pbf_tag_type(value >> 3u);
+
+        // tags 0 and 19000 to 19999 are not allowed as per
+        // https://developers.google.com/protocol-buffers/docs/proto#assigning-tags
+        if (m_tag == 0 || (m_tag >= 19000 && m_tag <= 19999)) {
+            throw invalid_tag_exception{};
+        }
+
+        m_wire_type = pbf_wire_type(value & 0x07u);
+        switch (m_wire_type) {
+            case pbf_wire_type::varint:
+            case pbf_wire_type::fixed64:
+            case pbf_wire_type::length_delimited:
+            case pbf_wire_type::fixed32:
+                break;
+            default:
+                throw unknown_pbf_wire_type_exception{};
+        }
+
+        return true;
+    }
+
+    /**
+     * Set next field with given tag in the message as the current field.
+     * Fields with other tags are skipped. This is usually called in a while
+     * loop for repeated fields:
+     *
+     * @code
+     *    pbf_reader message{...};
+     *    while (message.next(17)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * or you can call it just once to get the one field with this tag:
+     *
+     * @code
+     *    pbf_reader message{...};
+     *    if (message.next(17)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * Note that this will not check the wire type. The two-argument version
+     * of this function will also check the wire type.
+     *
+     * @returns `true` if there is a next field with this tag.
+     * @pre There must be no current field.
+     * @post If it returns `true` there is a current field now with the given tag.
+     */
+    bool next(pbf_tag_type next_tag) {
+        while (next()) {
+            if (m_tag == next_tag) {
+                return true;
+            }
+            skip();
+        }
+        return false;
+    }
+
+    /**
+     * Set next field with given tag and wire type in the message as the
+     * current field. Fields with other tags are skipped. This is usually
+     * called in a while loop for repeated fields:
+     *
+     * @code
+     *    pbf_reader message{...};
+     *    while (message.next(17, pbf_wire_type::varint)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * or you can call it just once to get the one field with this tag:
+     *
+     * @code
+     *    pbf_reader message{...};
+     *    if (message.next(17, pbf_wire_type::varint)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * Note that this will also check the wire type. The one-argument version
+     * of this function will not check the wire type.
+     *
+     * @returns `true` if there is a next field with this tag.
+     * @pre There must be no current field.
+     * @post If it returns `true` there is a current field now with the given tag.
+     */
+    bool next(pbf_tag_type next_tag, pbf_wire_type type) {
+        while (next()) {
+            if (m_tag == next_tag && m_wire_type == type) {
+                return true;
+            }
+            skip();
+        }
+        return false;
+    }
+
+    /**
+     * The tag of the current field. The tag is the field number from the
+     * description in the .proto file.
+     *
+     * Call next() before calling this function to set the current field.
+     *
+     * @returns tag of the current field.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     */
+    pbf_tag_type tag() const noexcept {
+        return m_tag;
+    }
+
+    /**
+     * Get the wire type of the current field. The wire types are:
+     *
+     * * 0 - varint
+     * * 1 - 64 bit
+     * * 2 - length-delimited
+     * * 5 - 32 bit
+     *
+     * All other types are illegal.
+     *
+     * Call next() before calling this function to set the current field.
+     *
+     * @returns wire type of the current field.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     */
+    pbf_wire_type wire_type() const noexcept {
+        return m_wire_type;
+    }
+
+    /**
+     * Get the tag and wire type of the current field in one integer suitable
+     * for comparison with a switch statement.
+     *
+     * Use it like this:
+     *
+     * @code
+     *    pbf_reader message{...};
+     *    while (message.next()) {
+     *        switch (message.tag_and_type()) {
+     *            case tag_and_type(17, pbf_wire_type::length_delimited):
+     *                ....
+     *                break;
+     *            case tag_and_type(21, pbf_wire_type::varint):
+     *                ....
+     *                break;
+     *            default:
+     *                message.skip();
+     *        }
+     *    }
+     * @endcode
+     */
+    uint32_t tag_and_type() const noexcept {
+        return protozero::tag_and_type(tag(), wire_type());
+    }
+
+    /**
+     * Check the wire type of the current field.
+     *
+     * @returns `true` if the current field has the given wire type.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     */
+    bool has_wire_type(pbf_wire_type type) const noexcept {
+        return wire_type() == type;
+    }
+
+    /**
+     * Consume the current field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @post The current field was consumed and there is no current field now.
+     */
+    void skip() {
+        protozero_assert(tag() != 0 && "call next() before calling skip()");
+        switch (wire_type()) {
+            case pbf_wire_type::varint:
+                skip_varint(&m_data, m_end);
+                break;
+            case pbf_wire_type::fixed64:
+                skip_bytes(8);
+                break;
+            case pbf_wire_type::length_delimited:
+                skip_bytes(get_length());
+                break;
+            case pbf_wire_type::fixed32:
+                skip_bytes(4);
+                break;
+            default:
+                break;
+        }
+    }
+
+    ///@{
+    /**
+     * @name Scalar field accessor functions
+     */
+
+    /**
+     * Consume and return value of current "bool" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "bool".
+     * @post The current field was consumed and there is no current field now.
+     */
+    bool get_bool() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        const auto data = m_data;
+        skip_varint(&m_data, m_end);
+        return data[0] != 0;
+    }
+
+    /**
+     * Consume and return value of current "enum" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "enum".
+     * @post The current field was consumed and there is no current field now.
+     */
+    int32_t get_enum() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_varint<int32_t>();
+    }
+
+    /**
+     * Consume and return value of current "int32" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "int32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    int32_t get_int32() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_varint<int32_t>();
+    }
+
+    /**
+     * Consume and return value of current "sint32" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "sint32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    int32_t get_sint32() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_svarint<int32_t>();
+    }
+
+    /**
+     * Consume and return value of current "uint32" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "uint32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    uint32_t get_uint32() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_varint<uint32_t>();
+    }
+
+    /**
+     * Consume and return value of current "int64" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "int64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    int64_t get_int64() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_varint<int64_t>();
+    }
+
+    /**
+     * Consume and return value of current "sint64" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "sint64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    int64_t get_sint64() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_svarint<int64_t>();
+    }
+
+    /**
+     * Consume and return value of current "uint64" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "uint64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    uint64_t get_uint64() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_varint<uint64_t>();
+    }
+
+    /**
+     * Consume and return value of current "fixed32" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "fixed32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    uint32_t get_fixed32() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed");
+        return get_fixed<uint32_t>();
+    }
+
+    /**
+     * Consume and return value of current "sfixed32" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "sfixed32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    int32_t get_sfixed32() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed");
+        return get_fixed<int32_t>();
+    }
+
+    /**
+     * Consume and return value of current "fixed64" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "fixed64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    uint64_t get_fixed64() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed");
+        return get_fixed<uint64_t>();
+    }
+
+    /**
+     * Consume and return value of current "sfixed64" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "sfixed64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    int64_t get_sfixed64() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed");
+        return get_fixed<int64_t>();
+    }
+
+    /**
+     * Consume and return value of current "float" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "float".
+     * @post The current field was consumed and there is no current field now.
+     */
+    float get_float() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed");
+        return get_fixed<float>();
+    }
+
+    /**
+     * Consume and return value of current "double" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "double".
+     * @post The current field was consumed and there is no current field now.
+     */
+    double get_double() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed");
+        return get_fixed<double>();
+    }
+
+    /**
+     * Consume and return value of current "bytes", "string", or "message"
+     * field.
+     *
+     * @returns A data_view object.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "bytes", "string", or "message".
+     * @post The current field was consumed and there is no current field now.
+     */
+    data_view get_view() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        protozero_assert(has_wire_type(pbf_wire_type::length_delimited) && "not of type string, bytes or message");
+        const auto len = get_len_and_skip();
+        return {m_data - len, len};
+    }
+
+#ifndef PROTOZERO_STRICT_API
+    /**
+     * Consume and return value of current "bytes" or "string" field.
+     *
+     * @returns A pair with a pointer to the data and the length of the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "bytes" or "string".
+     * @post The current field was consumed and there is no current field now.
+     */
+    std::pair<const char*, pbf_length_type> get_data() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        protozero_assert(has_wire_type(pbf_wire_type::length_delimited) && "not of type string, bytes or message");
+        const auto len = get_len_and_skip();
+        return {m_data - len, len};
+    }
+#endif
+
+    /**
+     * Consume and return value of current "bytes" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "bytes".
+     * @post The current field was consumed and there is no current field now.
+     */
+    std::string get_bytes() {
+        return std::string(get_view());
+    }
+
+    /**
+     * Consume and return value of current "string" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "string".
+     * @post The current field was consumed and there is no current field now.
+     */
+    std::string get_string() {
+        return std::string(get_view());
+    }
+
+    /**
+     * Consume and return value of current "message" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "message".
+     * @post The current field was consumed and there is no current field now.
+     */
+    pbf_reader get_message() {
+        return pbf_reader{get_view()};
+    }
+
+    ///@}
+
+    /// Forward iterator for iterating over bool (int32 varint) values.
+    using const_bool_iterator   = const_varint_iterator< int32_t>;
+
+    /// Forward iterator for iterating over enum (int32 varint) values.
+    using const_enum_iterator   = const_varint_iterator< int32_t>;
+
+    /// Forward iterator for iterating over int32 (varint) values.
+    using const_int32_iterator  = const_varint_iterator< int32_t>;
+
+    /// Forward iterator for iterating over sint32 (varint) values.
+    using const_sint32_iterator = const_svarint_iterator<int32_t>;
+
+    /// Forward iterator for iterating over uint32 (varint) values.
+    using const_uint32_iterator = const_varint_iterator<uint32_t>;
+
+    /// Forward iterator for iterating over int64 (varint) values.
+    using const_int64_iterator  = const_varint_iterator< int64_t>;
+
+    /// Forward iterator for iterating over sint64 (varint) values.
+    using const_sint64_iterator = const_svarint_iterator<int64_t>;
+
+    /// Forward iterator for iterating over uint64 (varint) values.
+    using const_uint64_iterator = const_varint_iterator<uint64_t>;
+
+    /// Forward iterator for iterating over fixed32 values.
+    using const_fixed32_iterator = const_fixed_iterator<uint32_t>;
+
+    /// Forward iterator for iterating over sfixed32 values.
+    using const_sfixed32_iterator = const_fixed_iterator<int32_t>;
+
+    /// Forward iterator for iterating over fixed64 values.
+    using const_fixed64_iterator = const_fixed_iterator<uint64_t>;
+
+    /// Forward iterator for iterating over sfixed64 values.
+    using const_sfixed64_iterator = const_fixed_iterator<int64_t>;
+
+    /// Forward iterator for iterating over float values.
+    using const_float_iterator = const_fixed_iterator<float>;
+
+    /// Forward iterator for iterating over double values.
+    using const_double_iterator = const_fixed_iterator<double>;
+
+    ///@{
+    /**
+     * @name Repeated packed field accessor functions
+     */
+
+    /**
+     * Consume current "repeated packed bool" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed bool".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_bool_iterator> get_packed_bool() {
+        return get_packed<pbf_reader::const_bool_iterator>();
+    }
+
+    /**
+     * Consume current "repeated packed enum" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed enum".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_enum_iterator> get_packed_enum() {
+        return get_packed<pbf_reader::const_enum_iterator>();
+    }
+
+    /**
+     * Consume current "repeated packed int32" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed int32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_int32_iterator> get_packed_int32() {
+        return get_packed<pbf_reader::const_int32_iterator>();
+    }
+
+    /**
+     * Consume current "repeated packed sint32" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed sint32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_sint32_iterator> get_packed_sint32() {
+        return get_packed<pbf_reader::const_sint32_iterator>();
+    }
+
+    /**
+     * Consume current "repeated packed uint32" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed uint32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_uint32_iterator> get_packed_uint32() {
+        return get_packed<pbf_reader::const_uint32_iterator>();
+    }
+
+    /**
+     * Consume current "repeated packed int64" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed int64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_int64_iterator> get_packed_int64() {
+        return get_packed<pbf_reader::const_int64_iterator>();
+    }
+
+    /**
+     * Consume current "repeated packed sint64" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed sint64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_sint64_iterator> get_packed_sint64() {
+        return get_packed<pbf_reader::const_sint64_iterator>();
+    }
+
+    /**
+     * Consume current "repeated packed uint64" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed uint64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_uint64_iterator> get_packed_uint64() {
+        return get_packed<pbf_reader::const_uint64_iterator>();
+    }
+
+    /**
+     * Consume current "repeated packed fixed32" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed fixed32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_fixed32_iterator> get_packed_fixed32() {
+        return packed_fixed<uint32_t>();
+    }
+
+    /**
+     * Consume current "repeated packed sfixed32" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed sfixed32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_sfixed32_iterator> get_packed_sfixed32() {
+        return packed_fixed<int32_t>();
+    }
+
+    /**
+     * Consume current "repeated packed fixed64" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed fixed64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_fixed64_iterator> get_packed_fixed64() {
+        return packed_fixed<uint64_t>();
+    }
+
+    /**
+     * Consume current "repeated packed sfixed64" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed sfixed64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_sfixed64_iterator> get_packed_sfixed64() {
+        return packed_fixed<int64_t>();
+    }
+
+    /**
+     * Consume current "repeated packed float" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed float".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_float_iterator> get_packed_float() {
+        return packed_fixed<float>();
+    }
+
+    /**
+     * Consume current "repeated packed double" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed double".
+     * @post The current field was consumed and there is no current field now.
+     */
+    iterator_range<pbf_reader::const_double_iterator> get_packed_double() {
+        return packed_fixed<double>();
+    }
+
+    ///@}
+
+}; // class pbf_reader
+
+/**
+ * Swap two pbf_reader objects.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline void swap(pbf_reader& lhs, pbf_reader& rhs) noexcept {
+    lhs.swap(rhs);
+}
+
+} // end namespace protozero
+
+#endif // PROTOZERO_PBF_READER_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_writer.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_writer.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/pbf_writer.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,1078 @@
+#ifndef PROTOZERO_PBF_WRITER_HPP
+#define PROTOZERO_PBF_WRITER_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file pbf_writer.hpp
+ *
+ * @brief Contains the pbf_writer class.
+ */
+
+#include <protozero/config.hpp>
+#include <protozero/data_view.hpp>
+#include <protozero/types.hpp>
+#include <protozero/varint.hpp>
+
+#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
+# include <protozero/byteswap.hpp>
+#endif
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <limits>
+#include <string>
+#include <utility>
+
+namespace protozero {
+
+namespace detail {
+
+    template <typename T> class packed_field_varint;
+    template <typename T> class packed_field_svarint;
+    template <typename T> class packed_field_fixed;
+
+} // end namespace detail
+
+/**
+ * The pbf_writer is used to write PBF formatted messages into a buffer.
+ *
+ * Almost all methods in this class can throw an std::bad_alloc exception if
+ * the std::string used as a buffer wants to resize.
+ */
+class pbf_writer {
+
+    // A pointer to a string buffer holding the data already written to the
+    // PBF message. For default constructed writers or writers that have been
+    // rolled back, this is a nullptr.
+    std::string* m_data = nullptr;
+
+    // A pointer to a parent writer object if this is a submessage. If this
+    // is a top-level writer, it is a nullptr.
+    pbf_writer* m_parent_writer = nullptr;
+
+    // This is usually 0. If there is an open submessage, this is set in the
+    // parent to the rollback position, ie. the last position before the
+    // submessage was started. This is the position where the header of the
+    // submessage starts.
+    std::size_t m_rollback_pos = 0;
+
+    // This is usually 0. If there is an open submessage, this is set in the
+    // parent to the position where the data of the submessage is written to.
+    std::size_t m_pos = 0;
+
+    void add_varint(uint64_t value) {
+        protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
+        protozero_assert(m_data);
+        write_varint(std::back_inserter(*m_data), value);
+    }
+
+    void add_field(pbf_tag_type tag, pbf_wire_type type) {
+        protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1u << 29u) - 1))) && "tag out of range");
+        const uint32_t b = (tag << 3u) | uint32_t(type);
+        add_varint(b);
+    }
+
+    void add_tagged_varint(pbf_tag_type tag, uint64_t value) {
+        add_field(tag, pbf_wire_type::varint);
+        add_varint(value);
+    }
+
+    template <typename T>
+    void add_fixed(T value) {
+        protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
+        protozero_assert(m_data);
+#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
+        byteswap_inplace(&value);
+#endif
+        m_data->append(reinterpret_cast<const char*>(&value), sizeof(T));
+    }
+
+    template <typename T, typename It>
+    void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag /*unused*/) {
+        if (first == last) {
+            return;
+        }
+
+        pbf_writer sw{*this, tag};
+
+        while (first != last) {
+            sw.add_fixed<T>(*first++);
+        }
+    }
+
+    template <typename T, typename It>
+    void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag /*unused*/) {
+        if (first == last) {
+            return;
+        }
+
+        const auto length = std::distance(first, last);
+        add_length_varint(tag, sizeof(T) * pbf_length_type(length));
+        reserve(sizeof(T) * std::size_t(length));
+
+        while (first != last) {
+            add_fixed<T>(*first++);
+        }
+    }
+
+    template <typename It>
+    void add_packed_varint(pbf_tag_type tag, It first, It last) {
+        if (first == last) {
+            return;
+        }
+
+        pbf_writer sw{*this, tag};
+
+        while (first != last) {
+            sw.add_varint(uint64_t(*first++));
+        }
+    }
+
+    template <typename It>
+    void add_packed_svarint(pbf_tag_type tag, It first, It last) {
+        if (first == last) {
+            return;
+        }
+
+        pbf_writer sw{*this, tag};
+
+        while (first != last) {
+            sw.add_varint(encode_zigzag64(*first++));
+        }
+    }
+
+    // The number of bytes to reserve for the varint holding the length of
+    // a length-delimited field. The length has to fit into pbf_length_type,
+    // and a varint needs 8 bit for every 7 bit.
+    enum constant_reserve_bytes : int {
+        reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1
+    };
+
+    // If m_rollpack_pos is set to this special value, it means that when
+    // the submessage is closed, nothing needs to be done, because the length
+    // of the submessage has already been written correctly.
+    enum constant_size_is_known : std::size_t {
+        size_is_known = std::numeric_limits<std::size_t>::max()
+    };
+
+    void open_submessage(pbf_tag_type tag, std::size_t size) {
+        protozero_assert(m_pos == 0);
+        protozero_assert(m_data);
+        if (size == 0) {
+            m_rollback_pos = m_data->size();
+            add_field(tag, pbf_wire_type::length_delimited);
+            m_data->append(std::size_t(reserve_bytes), '\0');
+        } else {
+            m_rollback_pos = size_is_known;
+            add_length_varint(tag, pbf_length_type(size));
+            reserve(size);
+        }
+        m_pos = m_data->size();
+    }
+
+    void rollback_submessage() {
+        protozero_assert(m_pos != 0);
+        protozero_assert(m_rollback_pos != size_is_known);
+        protozero_assert(m_data);
+        m_data->resize(m_rollback_pos);
+        m_pos = 0;
+    }
+
+    void commit_submessage() {
+        protozero_assert(m_pos != 0);
+        protozero_assert(m_rollback_pos != size_is_known);
+        protozero_assert(m_data);
+        const auto length = pbf_length_type(m_data->size() - m_pos);
+
+        protozero_assert(m_data->size() >= m_pos - reserve_bytes);
+        const auto n = write_varint(m_data->begin() + int64_t(m_pos) - reserve_bytes, length);
+
+        m_data->erase(m_data->begin() + int64_t(m_pos) - reserve_bytes + n, m_data->begin() + int64_t(m_pos));
+        m_pos = 0;
+    }
+
+    void close_submessage() {
+        protozero_assert(m_data);
+        if (m_pos == 0 || m_rollback_pos == size_is_known) {
+            return;
+        }
+        if (m_data->size() - m_pos == 0) {
+            rollback_submessage();
+        } else {
+            commit_submessage();
+        }
+    }
+
+    void add_length_varint(pbf_tag_type tag, pbf_length_type length) {
+        add_field(tag, pbf_wire_type::length_delimited);
+        add_varint(length);
+    }
+
+public:
+
+    /**
+     * Create a writer using the given string as a data store. The pbf_writer
+     * stores a reference to that string and adds all data to it. The string
+     * doesn't have to be empty. The pbf_writer will just append data.
+     */
+    explicit pbf_writer(std::string& data) noexcept :
+        m_data{&data} {
+    }
+
+    /**
+     * Create a writer without a data store. In this form the writer can not
+     * be used!
+     */
+    pbf_writer() noexcept = default;
+
+    /**
+     * Construct a pbf_writer for a submessage from the pbf_writer of the
+     * parent message.
+     *
+     * @param parent_writer The pbf_writer
+     * @param tag Tag (field number) of the field that will be written
+     * @param size Optional size of the submessage in bytes (use 0 for unknown).
+     *        Setting this allows some optimizations but is only possible in
+     *        a few very specific cases.
+     */
+    pbf_writer(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size=0) :
+        m_data{parent_writer.m_data},
+        m_parent_writer{&parent_writer} {
+        m_parent_writer->open_submessage(tag, size);
+    }
+
+    /// A pbf_writer object can not be copied
+    pbf_writer(const pbf_writer&) = delete;
+
+    /// A pbf_writer object can not be copied
+    pbf_writer& operator=(const pbf_writer&) = delete;
+
+    /**
+     * A pbf_writer object can be moved. After this the other pbf_writer will
+     * be invalid.
+     */
+    pbf_writer(pbf_writer&& other) noexcept :
+        m_data{other.m_data},
+        m_parent_writer{other.m_parent_writer},
+        m_rollback_pos{other.m_rollback_pos},
+        m_pos{other.m_pos} {
+        other.m_data = nullptr;
+        other.m_parent_writer = nullptr;
+        other.m_rollback_pos = 0;
+        other.m_pos = 0;
+    }
+
+    /**
+     * A pbf_writer object can be moved. After this the other pbf_writer will
+     * be invalid.
+     */
+    pbf_writer& operator=(pbf_writer&& other) noexcept {
+        m_data = other.m_data;
+        m_parent_writer = other.m_parent_writer;
+        m_rollback_pos = other.m_rollback_pos;
+        m_pos = other.m_pos;
+        other.m_data = nullptr;
+        other.m_parent_writer = nullptr;
+        other.m_rollback_pos = 0;
+        other.m_pos = 0;
+        return *this;
+    }
+
+    ~pbf_writer() {
+        if (m_parent_writer != nullptr) {
+            m_parent_writer->close_submessage();
+        }
+    }
+
+    /**
+     * Check if this writer is valid. A writer is invalid if it was default
+     * constructed, moved from, or if commit() has been called on it.
+     * Otherwise it is valid.
+     */
+    bool valid() const noexcept {
+        return m_data != nullptr;
+    }
+
+    /**
+     * Swap the contents of this object with the other.
+     *
+     * @param other Other object to swap data with.
+     */
+    void swap(pbf_writer& other) noexcept {
+        using std::swap;
+        swap(m_data, other.m_data);
+        swap(m_parent_writer, other.m_parent_writer);
+        swap(m_rollback_pos, other.m_rollback_pos);
+        swap(m_pos, other.m_pos);
+    }
+
+    /**
+     * Reserve size bytes in the underlying message store in addition to
+     * whatever the message store already holds. So unlike
+     * the `std::string::reserve()` method this is not an absolute size,
+     * but additional memory that should be reserved.
+     *
+     * @param size Number of bytes to reserve in underlying message store.
+     */
+    void reserve(std::size_t size) {
+        protozero_assert(m_data);
+        m_data->reserve(m_data->size() + size);
+    }
+
+    /**
+     * Commit this submessage. This does the same as when the pbf_writer
+     * goes out of scope and is destructed.
+     *
+     * @pre Must be a pbf_writer of a submessage, ie one opened with the
+     *      pbf_writer constructor taking a parent message.
+     * @post The pbf_writer is invalid and can't be used any more.
+     */
+    void commit() {
+        protozero_assert(m_parent_writer && "you can't call commit() on a pbf_writer without a parent");
+        protozero_assert(m_pos == 0 && "you can't call commit() on a pbf_writer that has an open nested submessage");
+        m_parent_writer->close_submessage();
+        m_parent_writer = nullptr;
+        m_data = nullptr;
+    }
+
+    /**
+     * Cancel writing of this submessage. The complete submessage will be
+     * removed as if it was never created and no fields were added.
+     *
+     * @pre Must be a pbf_writer of a submessage, ie one opened with the
+     *      pbf_writer constructor taking a parent message.
+     * @post The pbf_writer is invalid and can't be used any more.
+     */
+    void rollback() {
+        protozero_assert(m_parent_writer && "you can't call rollback() on a pbf_writer without a parent");
+        protozero_assert(m_pos == 0 && "you can't call rollback() on a pbf_writer that has an open nested submessage");
+        m_parent_writer->rollback_submessage();
+        m_parent_writer = nullptr;
+        m_data = nullptr;
+    }
+
+    ///@{
+    /**
+     * @name Scalar field writer functions
+     */
+
+    /**
+     * Add "bool" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_bool(pbf_tag_type tag, bool value) {
+        add_field(tag, pbf_wire_type::varint);
+        protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
+        protozero_assert(m_data);
+        m_data->append(1, char(value));
+    }
+
+    /**
+     * Add "enum" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_enum(pbf_tag_type tag, int32_t value) {
+        add_tagged_varint(tag, uint64_t(value));
+    }
+
+    /**
+     * Add "int32" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_int32(pbf_tag_type tag, int32_t value) {
+        add_tagged_varint(tag, uint64_t(value));
+    }
+
+    /**
+     * Add "sint32" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_sint32(pbf_tag_type tag, int32_t value) {
+        add_tagged_varint(tag, encode_zigzag32(value));
+    }
+
+    /**
+     * Add "uint32" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_uint32(pbf_tag_type tag, uint32_t value) {
+        add_tagged_varint(tag, value);
+    }
+
+    /**
+     * Add "int64" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_int64(pbf_tag_type tag, int64_t value) {
+        add_tagged_varint(tag, uint64_t(value));
+    }
+
+    /**
+     * Add "sint64" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_sint64(pbf_tag_type tag, int64_t value) {
+        add_tagged_varint(tag, encode_zigzag64(value));
+    }
+
+    /**
+     * Add "uint64" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_uint64(pbf_tag_type tag, uint64_t value) {
+        add_tagged_varint(tag, value);
+    }
+
+    /**
+     * Add "fixed32" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_fixed32(pbf_tag_type tag, uint32_t value) {
+        add_field(tag, pbf_wire_type::fixed32);
+        add_fixed<uint32_t>(value);
+    }
+
+    /**
+     * Add "sfixed32" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_sfixed32(pbf_tag_type tag, int32_t value) {
+        add_field(tag, pbf_wire_type::fixed32);
+        add_fixed<int32_t>(value);
+    }
+
+    /**
+     * Add "fixed64" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_fixed64(pbf_tag_type tag, uint64_t value) {
+        add_field(tag, pbf_wire_type::fixed64);
+        add_fixed<uint64_t>(value);
+    }
+
+    /**
+     * Add "sfixed64" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_sfixed64(pbf_tag_type tag, int64_t value) {
+        add_field(tag, pbf_wire_type::fixed64);
+        add_fixed<int64_t>(value);
+    }
+
+    /**
+     * Add "float" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_float(pbf_tag_type tag, float value) {
+        add_field(tag, pbf_wire_type::fixed32);
+        add_fixed<float>(value);
+    }
+
+    /**
+     * Add "double" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_double(pbf_tag_type tag, double value) {
+        add_field(tag, pbf_wire_type::fixed64);
+        add_fixed<double>(value);
+    }
+
+    /**
+     * Add "bytes" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Pointer to value to be written
+     * @param size Number of bytes to be written
+     */
+    void add_bytes(pbf_tag_type tag, const char* value, std::size_t size) {
+        protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
+        protozero_assert(m_data);
+        protozero_assert(size <= std::numeric_limits<pbf_length_type>::max());
+        add_length_varint(tag, pbf_length_type(size));
+        m_data->append(value, size);
+    }
+
+    /**
+     * Add "bytes" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_bytes(pbf_tag_type tag, const data_view& value) {
+        add_bytes(tag, value.data(), value.size());
+    }
+
+    /**
+     * Add "bytes" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_bytes(pbf_tag_type tag, const std::string& value) {
+        add_bytes(tag, value.data(), value.size());
+    }
+
+    /**
+     * Add "bytes" field to data. Bytes from the value are written until
+     * a null byte is encountered. The null byte is not added.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Pointer to zero-delimited value to be written
+     */
+    void add_bytes(pbf_tag_type tag, const char* value) {
+        add_bytes(tag, value, std::strlen(value));
+    }
+
+    /**
+     * Add "bytes" field to data using vectored input. All the data in the
+     * 2nd and further arguments is "concatenated" with only a single copy
+     * into the final buffer.
+     *
+     * This will work with objects of any type supporting the data() and
+     * size() methods like std::string or protozero::data_view.
+     *
+     * Example:
+     * @code
+     * std::string data1 = "abc";
+     * std::string data2 = "xyz";
+     * writer.add_bytes_vectored(1, data1, data2);
+     * @endcode
+     *
+     * @tparam Ts List of types supporting data() and size() methods.
+     * @param tag Tag (field number) of the field
+     * @param values List of objects of types Ts with data to be appended.
+     */
+    template <typename... Ts>
+    void add_bytes_vectored(pbf_tag_type tag, Ts&&... values) {
+        protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
+        protozero_assert(m_data);
+        size_t sum_size = 0;
+        (void)std::initializer_list<size_t>{sum_size += values.size()...};
+        protozero_assert(sum_size <= std::numeric_limits<pbf_length_type>::max());
+        add_length_varint(tag, pbf_length_type(sum_size));
+        m_data->reserve(m_data->size() + sum_size);
+        (void)std::initializer_list<int>{(m_data->append(values.data(), values.size()), 0)...};
+    }
+
+    /**
+     * Add "string" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Pointer to value to be written
+     * @param size Number of bytes to be written
+     */
+    void add_string(pbf_tag_type tag, const char* value, std::size_t size) {
+        add_bytes(tag, value, size);
+    }
+
+    /**
+     * Add "string" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_string(pbf_tag_type tag, const data_view& value) {
+        add_bytes(tag, value.data(), value.size());
+    }
+
+    /**
+     * Add "string" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    void add_string(pbf_tag_type tag, const std::string& value) {
+        add_bytes(tag, value.data(), value.size());
+    }
+
+    /**
+     * Add "string" field to data. Bytes from the value are written until
+     * a null byte is encountered. The null byte is not added.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Pointer to value to be written
+     */
+    void add_string(pbf_tag_type tag, const char* value) {
+        add_bytes(tag, value, std::strlen(value));
+    }
+
+    /**
+     * Add "message" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Pointer to message to be written
+     * @param size Length of the message
+     */
+    void add_message(pbf_tag_type tag, const char* value, std::size_t size) {
+        add_bytes(tag, value, size);
+    }
+
+    /**
+     * Add "message" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written. The value must be a complete message.
+     */
+    void add_message(pbf_tag_type tag, const data_view& value) {
+        add_bytes(tag, value.data(), value.size());
+    }
+
+    /**
+     * Add "message" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written. The value must be a complete message.
+     */
+    void add_message(pbf_tag_type tag, const std::string& value) {
+        add_bytes(tag, value.data(), value.size());
+    }
+
+    ///@}
+
+    ///@{
+    /**
+     * @name Repeated packed field writer functions
+     */
+
+    /**
+     * Add "repeated packed bool" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to bool.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed enum" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed int32" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed sint32" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_svarint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed uint32" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to uint32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed int64" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int64_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed sint64" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int64_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_svarint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed uint64" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to uint64_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add a "repeated packed" fixed-size field to data. The following
+     * fixed-size fields are available:
+     *
+     * uint32_t -> repeated packed fixed32
+     * int32_t  -> repeated packed sfixed32
+     * uint64_t -> repeated packed fixed64
+     * int64_t  -> repeated packed sfixed64
+     * double   -> repeated packed double
+     * float    -> repeated packed float
+     *
+     * @tparam ValueType One of the following types: (u)int32/64_t, double, float.
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename ValueType, typename InputIterator>
+    void add_packed_fixed(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        static_assert(std::is_same<ValueType, uint32_t>::value ||
+                      std::is_same<ValueType, int32_t>::value ||
+                      std::is_same<ValueType, int64_t>::value ||
+                      std::is_same<ValueType, uint64_t>::value ||
+                      std::is_same<ValueType, double>::value ||
+                      std::is_same<ValueType, float>::value, "Only some types are allowed");
+        add_packed_fixed<ValueType, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category{});
+    }
+
+    /**
+     * Add "repeated packed fixed32" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to uint32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<uint32_t, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category{});
+    }
+
+    /**
+     * Add "repeated packed sfixed32" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<int32_t, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category{});
+    }
+
+    /**
+     * Add "repeated packed fixed64" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to uint64_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<uint64_t, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category{});
+    }
+
+    /**
+     * Add "repeated packed sfixed64" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int64_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<int64_t, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category{});
+    }
+
+    /**
+     * Add "repeated packed float" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to float.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<float, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category{});
+    }
+
+    /**
+     * Add "repeated packed double" field to data.
+     *
+     * @tparam InputIterator A type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to double.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<double, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category{});
+    }
+
+    ///@}
+
+    template <typename T> friend class detail::packed_field_varint;
+    template <typename T> friend class detail::packed_field_svarint;
+    template <typename T> friend class detail::packed_field_fixed;
+
+}; // class pbf_writer
+
+/**
+ * Swap two pbf_writer objects.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline void swap(pbf_writer& lhs, pbf_writer& rhs) noexcept {
+    lhs.swap(rhs);
+}
+
+namespace detail {
+
+    class packed_field {
+
+    protected:
+
+        pbf_writer m_writer{};
+
+    public:
+
+        packed_field(const packed_field&) = delete;
+        packed_field& operator=(const packed_field&) = delete;
+
+        packed_field(packed_field&&) noexcept = default;
+        packed_field& operator=(packed_field&&) noexcept = default;
+
+        packed_field() = default;
+
+        packed_field(pbf_writer& parent_writer, pbf_tag_type tag) :
+            m_writer{parent_writer, tag} {
+        }
+
+        packed_field(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size) :
+            m_writer{parent_writer, tag, size} {
+        }
+
+        ~packed_field() noexcept = default;
+
+        bool valid() const noexcept {
+            return m_writer.valid();
+        }
+
+        void commit() {
+            m_writer.commit();
+        }
+
+        void rollback() {
+            m_writer.rollback();
+        }
+
+    }; // class packed_field
+
+    template <typename T>
+    class packed_field_fixed : public packed_field {
+
+    public:
+
+        packed_field_fixed() :
+            packed_field{} {
+        }
+
+        template <typename P>
+        packed_field_fixed(pbf_writer& parent_writer, P tag) :
+            packed_field{parent_writer, static_cast<pbf_tag_type>(tag)} {
+        }
+
+        template <typename P>
+        packed_field_fixed(pbf_writer& parent_writer, P tag, std::size_t size) :
+            packed_field{parent_writer, static_cast<pbf_tag_type>(tag), size * sizeof(T)} {
+        }
+
+        void add_element(T value) {
+            m_writer.add_fixed<T>(value);
+        }
+
+    }; // class packed_field_fixed
+
+    template <typename T>
+    class packed_field_varint : public packed_field {
+
+    public:
+
+        packed_field_varint() :
+            packed_field{} {
+        }
+
+        template <typename P>
+        packed_field_varint(pbf_writer& parent_writer, P tag) :
+            packed_field{parent_writer, static_cast<pbf_tag_type>(tag)} {
+        }
+
+        void add_element(T value) {
+            m_writer.add_varint(uint64_t(value));
+        }
+
+    }; // class packed_field_varint
+
+    template <typename T>
+    class packed_field_svarint : public packed_field {
+
+    public:
+
+        packed_field_svarint() :
+            packed_field{} {
+        }
+
+        template <typename P>
+        packed_field_svarint(pbf_writer& parent_writer, P tag) :
+            packed_field{parent_writer, static_cast<pbf_tag_type>(tag)} {
+        }
+
+        void add_element(T value) {
+            m_writer.add_varint(encode_zigzag64(value));
+        }
+
+    }; // class packed_field_svarint
+
+} // end namespace detail
+
+/// Class for generating packed repeated bool fields.
+using packed_field_bool     = detail::packed_field_varint<bool>;
+
+/// Class for generating packed repeated enum fields.
+using packed_field_enum     = detail::packed_field_varint<int32_t>;
+
+/// Class for generating packed repeated int32 fields.
+using packed_field_int32    = detail::packed_field_varint<int32_t>;
+
+/// Class for generating packed repeated sint32 fields.
+using packed_field_sint32   = detail::packed_field_svarint<int32_t>;
+
+/// Class for generating packed repeated uint32 fields.
+using packed_field_uint32   = detail::packed_field_varint<uint32_t>;
+
+/// Class for generating packed repeated int64 fields.
+using packed_field_int64    = detail::packed_field_varint<int64_t>;
+
+/// Class for generating packed repeated sint64 fields.
+using packed_field_sint64   = detail::packed_field_svarint<int64_t>;
+
+/// Class for generating packed repeated uint64 fields.
+using packed_field_uint64   = detail::packed_field_varint<uint64_t>;
+
+/// Class for generating packed repeated fixed32 fields.
+using packed_field_fixed32  = detail::packed_field_fixed<uint32_t>;
+
+/// Class for generating packed repeated sfixed32 fields.
+using packed_field_sfixed32 = detail::packed_field_fixed<int32_t>;
+
+/// Class for generating packed repeated fixed64 fields.
+using packed_field_fixed64  = detail::packed_field_fixed<uint64_t>;
+
+/// Class for generating packed repeated sfixed64 fields.
+using packed_field_sfixed64 = detail::packed_field_fixed<int64_t>;
+
+/// Class for generating packed repeated float fields.
+using packed_field_float    = detail::packed_field_fixed<float>;
+
+/// Class for generating packed repeated double fields.
+using packed_field_double   = detail::packed_field_fixed<double>;
+
+} // end namespace protozero
+
+#endif // PROTOZERO_PBF_WRITER_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/types.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/types.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/types.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,66 @@
+#ifndef PROTOZERO_TYPES_HPP
+#define PROTOZERO_TYPES_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file types.hpp
+ *
+ * @brief Contains the declaration of low-level types used in the pbf format.
+ */
+
+#include <protozero/config.hpp>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <utility>
+
+namespace protozero {
+
+/**
+ * The type used for field tags (field numbers).
+ */
+using pbf_tag_type = uint32_t;
+
+/**
+ * The type used to encode type information.
+ * See the table on
+ *    https://developers.google.com/protocol-buffers/docs/encoding
+ */
+enum class pbf_wire_type : uint32_t {
+    varint           = 0, // int32/64, uint32/64, sint32/64, bool, enum
+    fixed64          = 1, // fixed64, sfixed64, double
+    length_delimited = 2, // string, bytes, nested messages, packed repeated fields
+    fixed32          = 5, // fixed32, sfixed32, float
+    unknown          = 99 // used for default setting in this library
+};
+
+/**
+ * Get the tag and wire type of the current field in one integer suitable
+ * for comparison with a switch statement.
+ *
+ * See pbf_reader.tag_and_type() for an example how to use this.
+ */
+template <typename T>
+constexpr inline uint32_t tag_and_type(T tag, pbf_wire_type wire_type) noexcept {
+    return (static_cast<uint32_t>(static_cast<pbf_tag_type>(tag)) << 3u) | static_cast<uint32_t>(wire_type);
+}
+
+/**
+ * The type used for length values, such as the length of a field.
+ */
+using pbf_length_type = uint32_t;
+
+} // end namespace protozero
+
+#endif // PROTOZERO_TYPES_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/varint.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/varint.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/varint.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,205 @@
+#ifndef PROTOZERO_VARINT_HPP
+#define PROTOZERO_VARINT_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file varint.hpp
+ *
+ * @brief Contains low-level varint and zigzag encoding and decoding functions.
+ */
+
+#include <protozero/exception.hpp>
+
+#include <cstdint>
+
+namespace protozero {
+
+/**
+ * The maximum length of a 64 bit varint.
+ */
+constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1;
+
+namespace detail {
+
+    // from https://github.com/facebook/folly/blob/master/folly/Varint.h
+    inline uint64_t decode_varint_impl(const char** data, const char* end) {
+        const auto begin = reinterpret_cast<const int8_t*>(*data);
+        const auto iend = reinterpret_cast<const int8_t*>(end);
+        const int8_t* p = begin;
+        uint64_t val = 0;
+
+        if (iend - begin >= max_varint_length) {  // fast path
+            do {
+                int64_t b;
+                b = *p++; val  = ((uint64_t(b) & 0x7fu)       ); if (b >= 0) { break; }
+                b = *p++; val |= ((uint64_t(b) & 0x7fu) <<  7u); if (b >= 0) { break; }
+                b = *p++; val |= ((uint64_t(b) & 0x7fu) << 14u); if (b >= 0) { break; }
+                b = *p++; val |= ((uint64_t(b) & 0x7fu) << 21u); if (b >= 0) { break; }
+                b = *p++; val |= ((uint64_t(b) & 0x7fu) << 28u); if (b >= 0) { break; }
+                b = *p++; val |= ((uint64_t(b) & 0x7fu) << 35u); if (b >= 0) { break; }
+                b = *p++; val |= ((uint64_t(b) & 0x7fu) << 42u); if (b >= 0) { break; }
+                b = *p++; val |= ((uint64_t(b) & 0x7fu) << 49u); if (b >= 0) { break; }
+                b = *p++; val |= ((uint64_t(b) & 0x7fu) << 56u); if (b >= 0) { break; }
+                b = *p++; val |= ((uint64_t(b) & 0x01u) << 63u); if (b >= 0) { break; }
+                throw varint_too_long_exception{};
+            } while (false);
+        } else {
+            unsigned int shift = 0;
+            while (p != iend && *p < 0) {
+                val |= (uint64_t(*p++) & 0x7fu) << shift;
+                shift += 7;
+            }
+            if (p == iend) {
+                throw end_of_buffer_exception{};
+            }
+            val |= uint64_t(*p++) << shift;
+        }
+
+        *data = reinterpret_cast<const char*>(p);
+        return val;
+    }
+
+} // end namespace detail
+
+/**
+ * Decode a 64 bit varint.
+ *
+ * Strong exception guarantee: if there is an exception the data pointer will
+ * not be changed.
+ *
+ * @param[in,out] data Pointer to pointer to the input data. After the function
+ *        returns this will point to the next data to be read.
+ * @param[in] end Pointer one past the end of the input data.
+ * @returns The decoded integer
+ * @throws varint_too_long_exception if the varint is longer then the maximum
+ *         length that would fit in a 64 bit int. Usually this means your data
+ *         is corrupted or you are trying to read something as a varint that
+ *         isn't.
+ * @throws end_of_buffer_exception if the *end* of the buffer was reached
+ *         before the end of the varint.
+ */
+inline uint64_t decode_varint(const char** data, const char* end) {
+    // If this is a one-byte varint, decode it here.
+    if (end != *data && ((static_cast<uint64_t>(**data) & 0x80u) == 0)) {
+        const auto val = static_cast<uint64_t>(**data);
+        ++(*data);
+        return val;
+    }
+    // If this varint is more than one byte, defer to complete implementation.
+    return detail::decode_varint_impl(data, end);
+}
+
+/**
+ * Skip over a varint.
+ *
+ * Strong exception guarantee: if there is an exception the data pointer will
+ * not be changed.
+ *
+ * @param[in,out] data Pointer to pointer to the input data. After the function
+ *        returns this will point to the next data to be read.
+ * @param[in] end Pointer one past the end of the input data.
+ * @throws end_of_buffer_exception if the *end* of the buffer was reached
+ *         before the end of the varint.
+ */
+inline void skip_varint(const char** data, const char* end) {
+    const auto begin = reinterpret_cast<const int8_t*>(*data);
+    const auto iend = reinterpret_cast<const int8_t*>(end);
+    const int8_t* p = begin;
+
+    while (p != iend && *p < 0) {
+        ++p;
+    }
+
+    if (p - begin >= max_varint_length) {
+        throw varint_too_long_exception{};
+    }
+
+    if (p == iend) {
+        throw end_of_buffer_exception{};
+    }
+
+    ++p;
+
+    *data = reinterpret_cast<const char*>(p);
+}
+
+/**
+ * Varint encode a 64 bit integer.
+ *
+ * @tparam T An output iterator type.
+ * @param data Output iterator the varint encoded value will be written to
+ *             byte by byte.
+ * @param value The integer that will be encoded.
+ * @returns the number of bytes written
+ * @throws Any exception thrown by increment or dereference operator on data.
+ */
+template <typename T>
+inline int write_varint(T data, uint64_t value) {
+    int n = 1;
+
+    while (value >= 0x80u) {
+        *data++ = char((value & 0x7fu) | 0x80u);
+        value >>= 7u;
+        ++n;
+    }
+    *data++ = char(value);
+
+    return n;
+}
+
+/**
+ * Get the length of the varint the specified value would produce.
+ *
+ * @param value The integer to be encoded.
+ * @returns the number of bytes the varint would have if we created it.
+ */
+inline int length_of_varint(uint64_t value) noexcept {
+    int n = 1;
+
+    while (value >= 0x80u) {
+        value >>= 7u;
+        ++n;
+    }
+
+    return n;
+}
+
+/**
+ * ZigZag encodes a 32 bit integer.
+ */
+inline constexpr uint32_t encode_zigzag32(int32_t value) noexcept {
+    return (static_cast<uint32_t>(value) << 1u) ^ static_cast<uint32_t>(-static_cast<int32_t>(static_cast<uint32_t>(value) >> 31u));
+}
+
+/**
+ * ZigZag encodes a 64 bit integer.
+ */
+inline constexpr uint64_t encode_zigzag64(int64_t value) noexcept {
+    return (static_cast<uint64_t>(value) << 1u) ^ static_cast<uint64_t>(-static_cast<int64_t>(static_cast<uint64_t>(value) >> 63u));
+}
+
+/**
+ * Decodes a 32 bit ZigZag-encoded integer.
+ */
+inline constexpr int32_t decode_zigzag32(uint32_t value) noexcept {
+    return static_cast<int32_t>((value >> 1u) ^ static_cast<uint32_t>(-static_cast<int32_t>(value & 1u)));
+}
+
+/**
+ * Decodes a 64 bit ZigZag-encoded integer.
+ */
+inline constexpr int64_t decode_zigzag64(uint64_t value) noexcept {
+    return static_cast<int64_t>((value >> 1u) ^ static_cast<uint64_t>(-static_cast<int64_t>(value & 1u)));
+}
+
+} // end namespace protozero
+
+#endif // PROTOZERO_VARINT_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/version.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/version.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/include/protozero/version.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,34 @@
+#ifndef PROTOZERO_VERSION_HPP
+#define PROTOZERO_VERSION_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file version.hpp
+ *
+ * @brief Contains macros defining the protozero version.
+ */
+
+/// The major version number
+#define PROTOZERO_VERSION_MAJOR 1
+
+/// The minor version number
+#define PROTOZERO_VERSION_MINOR 6
+
+/// The patch number
+#define PROTOZERO_VERSION_PATCH 7
+
+/// The complete version number
+#define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH)
+
+/// Version number as string
+#define PROTOZERO_VERSION_STRING "1.6.7"
+
+#endif // PROTOZERO_VERSION_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/CMakeLists.txt
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/CMakeLists.txt	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/CMakeLists.txt	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,116 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake config
+#
+#  protozero tests
+#
+#-----------------------------------------------------------------------------
+
+include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/catch")
+include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
+
+add_subdirectory(unit)
+
+set(TEST_DIRS alignment
+              bool
+              bytes
+              complex
+              double
+              enum
+              fixed32
+              fixed64
+              float
+              int32
+              int64
+              message
+              nested
+              repeated
+              repeated_packed_bool
+              repeated_packed_double
+              repeated_packed_enum
+              repeated_packed_fixed32
+              repeated_packed_fixed64
+              repeated_packed_float
+              repeated_packed_int32
+              repeated_packed_int64
+              repeated_packed_sfixed32
+              repeated_packed_sfixed64
+              repeated_packed_sint32
+              repeated_packed_sint64
+              repeated_packed_uint32
+              repeated_packed_uint64
+              rollback
+              sfixed32
+              sfixed64
+              sint32
+              sint64
+              skip
+              string
+              tag_and_type
+              tags
+              uint32
+              uint64
+              vector_tile
+              wrong_type_access)
+
+string(REGEX REPLACE "([^;]+)" "t/\\1/reader_test_cases.cpp" _test_sources "${TEST_DIRS}")
+
+add_executable(reader_tests reader_tests.cpp ${_test_sources})
+
+add_test(NAME reader_tests COMMAND reader_tests)
+
+set_tests_properties(reader_tests PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
+
+if(PROTOBUF_FOUND)
+    message(STATUS "Found protobuf libraries: Adding writer tests...")
+
+    include_directories(SYSTEM ${PROTOBUF_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
+
+    set(PROTOBUF_GENERATE_CPP_APPEND_PATH false)
+
+    foreach(_dir IN LISTS TEST_DIRS)
+        set(_full_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/t/${_dir}")
+        if(EXISTS "${_full_src_dir}/writer_test_cases.cpp")
+            message(STATUS "  Adding ${_dir}")
+            set(_full_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/t/${_dir}")
+            set(_proto_file "${_full_src_dir}/${_dir}_testcase.proto")
+            set(_src_file "${_full_bin_dir}/${_dir}_testcase.pb.cc")
+            set(_hdr_file "${_full_bin_dir}/${_dir}_testcase.pb.h")
+
+            file(MAKE_DIRECTORY ${_full_bin_dir})
+
+            list(APPEND SOURCES     "${_full_src_dir}/writer_test_cases.cpp")
+            list(APPEND PROTO_FILES "${_proto_file}")
+            list(APPEND PROTO_SRCS  "${_src_file}")
+            list(APPEND PROTO_HDRS  "${_hdr_file}")
+
+            set_source_files_properties(${_proto_file} ${_hdr_file}
+                                        PROPERTIES GENERATED TRUE)
+
+            add_custom_command(
+                OUTPUT ${_src_file} ${_hdr_file}
+                COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
+                ARGS --cpp_out=${_full_bin_dir} -I ${_full_src_dir} ${_proto_file}
+                DEPENDS ${_proto_file}
+                VERBATIM)
+        endif()
+    endforeach()
+
+    add_executable(writer_tests writer_tests.cpp ${SOURCES} ${PROTO_SRCS} ${PROTO_HDRS})
+
+    target_link_libraries(writer_tests ${PROTOBUF_LITE_LIBRARY})
+
+    if(NOT MSVC)
+        set_target_properties(writer_tests PROPERTIES COMPILE_FLAGS "-pthread")
+        if(NOT APPLE)
+            set_target_properties(writer_tests PROPERTIES LINK_FLAGS "-pthread")
+        endif()
+    endif()
+
+    add_test(NAME writer_tests COMMAND writer_tests)
+else()
+    message(STATUS "Protobuf libraries not found: Disabling writer tests.")
+endif()
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/README.md
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/README.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/README.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,52 @@
+
+# Tests
+
+Tests are using the [Catch Unit Test Framework](https://github.com/philsquared/Catch).
+
+## Organization of the unit tests
+
+Unit tests test low-level functions of the library. They are in the `unit`
+directory.
+
+
+## Organization of the reader/writer test cases
+
+The hart of the tests are the reader/writer tests checking all aspects of
+decoding and encoding protobuf files.
+
+Each test case is in its own directory under the `t` directory. Each directory
+contains (some of) the following files:
+
+* `reader_test_cases.cpp`: The C++ source code that runs the reader tests.
+* `writer_test_cases.cpp`: The C++ source code that runs the writer tests.
+* `data-*.pbf`: PBF data files used by the tests.
+* `testcase.proto`: Protobuf file describing the format of the data files.
+* `testcase.cpp`: C++ file for creating the data files.
+
+### Reader tests
+
+The CMake config finds all the `reader_test_cases.cpp` files and compiles them.
+Together with the `reader_tests.cpp` file they make up the `reader_tests`
+executable which can be called to execute all the reader tests.
+
+### Extra writer tests
+
+The CMake config finds all the `writer_test_cases.cpp` files and compiles them.
+Together with the `writer_tests.cpp` file they make up the `writer_tests`
+executable which can be called to execute all the writer tests.
+
+The writer tests need the Google protobuf library to work.
+
+
+## Creating test data from scratch
+
+Most tests use test data stored in PBF format in their directory. The files
+have the suffix `.pbf`. Most of those files have been generated from the
+provided `testcase.proto` and `testcase.cpp` files.
+
+Usually you do not have to do this, but if you want to re-generate the PBF
+data files, you can do so:
+
+    cd test
+    ./create_pbf_test_data.sh
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/catch/catch.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/catch/catch.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/catch/catch.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11678 @@
+/*
+ *  Catch v1.12.0
+ *  Generated: 2018-01-11 21:56:34.893972
+ *  ----------------------------------------------------------
+ *  This file has been merged from multiple headers. Please don't edit it directly
+ *  Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
+#define TWOBLUECUBES_CATCH_HPP_INCLUDED
+
+#ifdef __clang__
+#    pragma clang system_header
+#elif defined __GNUC__
+#    pragma GCC system_header
+#endif
+
+// #included from: internal/catch_suppress_warnings.h
+
+#ifdef __clang__
+#   ifdef __ICC // icpc defines the __clang__ macro
+#       pragma warning(push)
+#       pragma warning(disable: 161 1682)
+#   else // __ICC
+#       pragma clang diagnostic ignored "-Wglobal-constructors"
+#       pragma clang diagnostic ignored "-Wvariadic-macros"
+#       pragma clang diagnostic ignored "-Wc99-extensions"
+#       pragma clang diagnostic ignored "-Wunused-variable"
+#       pragma clang diagnostic push
+#       pragma clang diagnostic ignored "-Wpadded"
+#       pragma clang diagnostic ignored "-Wc++98-compat"
+#       pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#       pragma clang diagnostic ignored "-Wswitch-enum"
+#       pragma clang diagnostic ignored "-Wcovered-switch-default"
+#    endif
+#elif defined __GNUC__
+#    pragma GCC diagnostic ignored "-Wvariadic-macros"
+#    pragma GCC diagnostic ignored "-Wunused-variable"
+#    pragma GCC diagnostic ignored "-Wparentheses"
+
+#    pragma GCC diagnostic push
+#    pragma GCC diagnostic ignored "-Wpadded"
+#endif
+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
+#  define CATCH_IMPL
+#endif
+
+#ifdef CATCH_IMPL
+#  ifndef CLARA_CONFIG_MAIN
+#    define CLARA_CONFIG_MAIN_NOT_DEFINED
+#    define CLARA_CONFIG_MAIN
+#  endif
+#endif
+
+// #included from: internal/catch_notimplemented_exception.h
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
+
+// #included from: catch_common.h
+#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
+
+// #included from: catch_compiler_capabilities.h
+#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
+// The following features are defined:
+//
+// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported?
+// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
+// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
+// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported?
+// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported
+// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported?
+// CATCH_CONFIG_CPP11_OVERRIDE : is override supported?
+// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
+// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported?
+// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported?
+
+// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
+
+// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
+// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
+// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
+// ****************
+// Note to maintainers: if new toggles are added please document them
+// in configuration.md, too
+// ****************
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
+
+#ifdef __cplusplus
+
+#  if __cplusplus >= 201103L
+#    define CATCH_CPP11_OR_GREATER
+#  endif
+
+#  if __cplusplus >= 201402L
+#    define CATCH_CPP14_OR_GREATER
+#  endif
+
+#endif
+
+#ifdef __clang__
+
+#  if __has_feature(cxx_nullptr)
+#    define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#  endif
+
+#  if __has_feature(cxx_noexcept)
+#    define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#  endif
+
+#   if defined(CATCH_CPP11_OR_GREATER)
+#       define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+            _Pragma( "clang diagnostic push" ) \
+            _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" )
+#       define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+            _Pragma( "clang diagnostic pop" )
+
+#       define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+            _Pragma( "clang diagnostic push" ) \
+            _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
+#       define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+            _Pragma( "clang diagnostic pop" )
+#   endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// We know some environments not to support full POSIX signals
+#if defined(__CYGWIN__) || defined(__QNX__)
+
+#   if !defined(CATCH_CONFIG_POSIX_SIGNALS)
+#       define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+#   endif
+
+#endif
+
+#ifdef __OS400__
+#       define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+#       define CATCH_CONFIG_COLOUR_NONE
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Cygwin
+#ifdef __CYGWIN__
+
+// Required for some versions of Cygwin to declare gettimeofday
+// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
+#   define _BSD_SOURCE
+
+#endif // __CYGWIN__
+
+////////////////////////////////////////////////////////////////////////////////
+// Borland
+#ifdef __BORLANDC__
+
+#endif // __BORLANDC__
+
+////////////////////////////////////////////////////////////////////////////////
+// EDG
+#ifdef __EDG_VERSION__
+
+#endif // __EDG_VERSION__
+
+////////////////////////////////////////////////////////////////////////////////
+// Digital Mars
+#ifdef __DMC__
+
+#endif // __DMC__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+#   if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
+#       define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#   endif
+
+// - otherwise more recent versions define __cplusplus >= 201103L
+// and will get picked up below
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
+
+#if (_MSC_VER >= 1600)
+#   define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#   define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
+#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
+#endif
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Use variadic macros if the compiler supports them
+#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
+    ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
+    ( defined __GNUC__ && __GNUC__ >= 3 ) || \
+    ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
+
+#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+
+#endif
+
+// Use __COUNTER__ if the compiler supports it
+#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
+    ( defined __GNUC__  && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \
+    ( defined __clang__ && __clang_major__ >= 3 )
+
+// Use of __COUNTER__ is suppressed during code analysis in CLion/AppCode 2017.2.x and former,
+// because __COUNTER__ is not properly handled by it.
+// This does not affect compilation
+#if ( !defined __JETBRAINS_IDE__ || __JETBRAINS_IDE__ >= 20170300L )
+    #define CATCH_INTERNAL_CONFIG_COUNTER
+#endif
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if defined(CATCH_CPP11_OR_GREATER)
+
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
+#    define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#    define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#    define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+#    define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+#    define CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+#    define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+#  endif
+
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG)
+#    define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG
+#  endif
+
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE)
+#    define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE
+#  endif
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
+#    define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#  endif
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE)
+#   define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
+#  endif
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS)
+#  define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
+# endif
+
+#endif // __cplusplus >= 201103L
+
+// Now set the actual defines based on the above + anything the user has configured
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_NULLPTR
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_NOEXCEPT
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_GENERATED_METHODS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_IS_ENUM
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_TUPLE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS)
+#   define CATCH_CONFIG_VARIADIC_MACROS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_LONG_LONG
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_OVERRIDE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_UNIQUE_PTR
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
+#   define CATCH_CONFIG_COUNTER
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_SHUFFLE
+#endif
+# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11)
+#  define CATCH_CONFIG_CPP11_TYPE_TRAITS
+# endif
+#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
+#   define CATCH_CONFIG_WINDOWS_SEH
+#endif
+// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
+#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
+#   define CATCH_CONFIG_POSIX_SIGNALS
+#endif
+
+#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
+#   define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
+#   define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+#endif
+
+// noexcept support:
+#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
+#  define CATCH_NOEXCEPT noexcept
+#  define CATCH_NOEXCEPT_IS(x) noexcept(x)
+#else
+#  define CATCH_NOEXCEPT throw()
+#  define CATCH_NOEXCEPT_IS(x)
+#endif
+
+// nullptr support
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+#   define CATCH_NULL nullptr
+#else
+#   define CATCH_NULL NULL
+#endif
+
+// override support
+#ifdef CATCH_CONFIG_CPP11_OVERRIDE
+#   define CATCH_OVERRIDE override
+#else
+#   define CATCH_OVERRIDE
+#endif
+
+// unique_ptr support
+#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR
+#   define CATCH_AUTO_PTR( T ) std::unique_ptr<T>
+#else
+#   define CATCH_AUTO_PTR( T ) std::auto_ptr<T>
+#endif
+
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
+#ifdef CATCH_CONFIG_COUNTER
+#  define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
+#else
+#  define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
+#endif
+
+#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
+#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
+
+#include <sstream>
+#include <algorithm>
+
+namespace Catch {
+
+    struct IConfig;
+
+    struct CaseSensitive { enum Choice {
+        Yes,
+        No
+    }; };
+
+    class NonCopyable {
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        NonCopyable( NonCopyable const& )              = delete;
+        NonCopyable( NonCopyable && )                  = delete;
+        NonCopyable& operator = ( NonCopyable const& ) = delete;
+        NonCopyable& operator = ( NonCopyable && )     = delete;
+#else
+        NonCopyable( NonCopyable const& info );
+        NonCopyable& operator = ( NonCopyable const& );
+#endif
+
+    protected:
+        NonCopyable() {}
+        virtual ~NonCopyable();
+    };
+
+    class SafeBool {
+    public:
+        typedef void (SafeBool::*type)() const;
+
+        static type makeSafe( bool value ) {
+            return value ? &SafeBool::trueValue : 0;
+        }
+    private:
+        void trueValue() const {}
+    };
+
+    template<typename ContainerT>
+    void deleteAll( ContainerT& container ) {
+        typename ContainerT::const_iterator it = container.begin();
+        typename ContainerT::const_iterator itEnd = container.end();
+        for(; it != itEnd; ++it )
+            delete *it;
+    }
+    template<typename AssociativeContainerT>
+    void deleteAllValues( AssociativeContainerT& container ) {
+        typename AssociativeContainerT::const_iterator it = container.begin();
+        typename AssociativeContainerT::const_iterator itEnd = container.end();
+        for(; it != itEnd; ++it )
+            delete it->second;
+    }
+
+    bool startsWith( std::string const& s, std::string const& prefix );
+    bool startsWith( std::string const& s, char prefix );
+    bool endsWith( std::string const& s, std::string const& suffix );
+    bool endsWith( std::string const& s, char suffix );
+    bool contains( std::string const& s, std::string const& infix );
+    void toLowerInPlace( std::string& s );
+    std::string toLower( std::string const& s );
+    std::string trim( std::string const& str );
+    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
+
+    struct pluralise {
+        pluralise( std::size_t count, std::string const& label );
+
+        friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
+
+        std::size_t m_count;
+        std::string m_label;
+    };
+
+    struct SourceLineInfo {
+
+        SourceLineInfo();
+        SourceLineInfo( char const* _file, std::size_t _line );
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        SourceLineInfo(SourceLineInfo const& other)          = default;
+        SourceLineInfo( SourceLineInfo && )                  = default;
+        SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
+        SourceLineInfo& operator = ( SourceLineInfo && )     = default;
+#  endif
+        bool empty() const;
+        bool operator == ( SourceLineInfo const& other ) const;
+        bool operator < ( SourceLineInfo const& other ) const;
+
+        char const* file;
+        std::size_t line;
+    };
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
+
+    // This is just here to avoid compiler warnings with macro constants and boolean literals
+    inline bool isTrue( bool value ){ return value; }
+    inline bool alwaysTrue() { return true; }
+    inline bool alwaysFalse() { return false; }
+
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
+
+    void seedRng( IConfig const& config );
+    unsigned int rngSeed();
+
+    // Use this in variadic streaming macros to allow
+    //    >> +StreamEndStop
+    // as well as
+    //    >> stuff +StreamEndStop
+    struct StreamEndStop {
+        std::string operator+() {
+            return std::string();
+        }
+    };
+    template<typename T>
+    T const& operator + ( T const& value, StreamEndStop ) {
+        return value;
+    }
+}
+
+#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
+#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
+
+namespace Catch {
+
+    class NotImplementedException : public std::exception
+    {
+    public:
+        NotImplementedException( SourceLineInfo const& lineInfo );
+
+        virtual ~NotImplementedException() CATCH_NOEXCEPT {}
+
+        virtual const char* what() const CATCH_NOEXCEPT;
+
+    private:
+        std::string m_what;
+        SourceLineInfo m_lineInfo;
+    };
+
+} // end namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
+
+// #included from: internal/catch_context.h
+#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
+
+// #included from: catch_interfaces_generators.h
+#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct IGeneratorInfo {
+        virtual ~IGeneratorInfo();
+        virtual bool moveNext() = 0;
+        virtual std::size_t getCurrentIndex() const = 0;
+    };
+
+    struct IGeneratorsForTest {
+        virtual ~IGeneratorsForTest();
+
+        virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
+        virtual bool moveNext() = 0;
+    };
+
+    IGeneratorsForTest* createGeneratorsForTest();
+
+} // end namespace Catch
+
+// #included from: catch_ptr.hpp
+#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    // An intrusive reference counting smart pointer.
+    // T must implement addRef() and release() methods
+    // typically implementing the IShared interface
+    template<typename T>
+    class Ptr {
+    public:
+        Ptr() : m_p( CATCH_NULL ){}
+        Ptr( T* p ) : m_p( p ){
+            if( m_p )
+                m_p->addRef();
+        }
+        Ptr( Ptr const& other ) : m_p( other.m_p ){
+            if( m_p )
+                m_p->addRef();
+        }
+        ~Ptr(){
+            if( m_p )
+                m_p->release();
+        }
+        void reset() {
+            if( m_p )
+                m_p->release();
+            m_p = CATCH_NULL;
+        }
+        Ptr& operator = ( T* p ){
+            Ptr temp( p );
+            swap( temp );
+            return *this;
+        }
+        Ptr& operator = ( Ptr const& other ){
+            Ptr temp( other );
+            swap( temp );
+            return *this;
+        }
+        void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
+        T* get() const{ return m_p; }
+        T& operator*() const { return *m_p; }
+        T* operator->() const { return m_p; }
+        bool operator !() const { return m_p == CATCH_NULL; }
+        operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); }
+
+    private:
+        T* m_p;
+    };
+
+    struct IShared : NonCopyable {
+        virtual ~IShared();
+        virtual void addRef() const = 0;
+        virtual void release() const = 0;
+    };
+
+    template<typename T = IShared>
+    struct SharedImpl : T {
+
+        SharedImpl() : m_rc( 0 ){}
+
+        virtual void addRef() const {
+            ++m_rc;
+        }
+        virtual void release() const {
+            if( --m_rc == 0 )
+                delete this;
+        }
+
+        mutable unsigned int m_rc;
+    };
+
+} // end namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+    class TestCase;
+    class Stream;
+    struct IResultCapture;
+    struct IRunner;
+    struct IGeneratorsForTest;
+    struct IConfig;
+
+    struct IContext
+    {
+        virtual ~IContext();
+
+        virtual IResultCapture* getResultCapture() = 0;
+        virtual IRunner* getRunner() = 0;
+        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
+        virtual bool advanceGeneratorsForCurrentTest() = 0;
+        virtual Ptr<IConfig const> getConfig() const = 0;
+    };
+
+    struct IMutableContext : IContext
+    {
+        virtual ~IMutableContext();
+        virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
+        virtual void setRunner( IRunner* runner ) = 0;
+        virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
+    };
+
+    IContext& getCurrentContext();
+    IMutableContext& getCurrentMutableContext();
+    void cleanUpContext();
+    Stream createStream( std::string const& streamName );
+
+}
+
+// #included from: internal/catch_test_registry.hpp
+#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_interfaces_testcase.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
+
+#include <vector>
+
+namespace Catch {
+
+    class TestSpec;
+
+    struct ITestCase : IShared {
+        virtual void invoke () const = 0;
+    protected:
+        virtual ~ITestCase();
+    };
+
+    class TestCase;
+    struct IConfig;
+
+    struct ITestCaseRegistry {
+        virtual ~ITestCaseRegistry();
+        virtual std::vector<TestCase> const& getAllTests() const = 0;
+        virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
+    };
+
+    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
+    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
+    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
+
+}
+
+namespace Catch {
+
+template<typename C>
+class MethodTestCase : public SharedImpl<ITestCase> {
+
+public:
+    MethodTestCase( void (C::*method)() ) : m_method( method ) {}
+
+    virtual void invoke() const {
+        C obj;
+        (obj.*m_method)();
+    }
+
+private:
+    virtual ~MethodTestCase() {}
+
+    void (C::*m_method)();
+};
+
+typedef void(*TestFunction)();
+
+struct NameAndDesc {
+    NameAndDesc( const char* _name = "", const char* _description= "" )
+    : name( _name ), description( _description )
+    {}
+
+    const char* name;
+    const char* description;
+};
+
+void registerTestCase
+    (   ITestCase* testCase,
+        char const* className,
+        NameAndDesc const& nameAndDesc,
+        SourceLineInfo const& lineInfo );
+
+struct AutoReg {
+
+    AutoReg
+        (   TestFunction function,
+            SourceLineInfo const& lineInfo,
+            NameAndDesc const& nameAndDesc );
+
+    template<typename C>
+    AutoReg
+        (   void (C::*method)(),
+            char const* className,
+            NameAndDesc const& nameAndDesc,
+            SourceLineInfo const& lineInfo ) {
+
+        registerTestCase
+            (   new MethodTestCase<C>( method ),
+                className,
+                nameAndDesc,
+                lineInfo );
+    }
+
+    ~AutoReg();
+
+private:
+    AutoReg( AutoReg const& );
+    void operator= ( AutoReg const& );
+};
+
+void registerTestCaseFunction
+    (   TestFunction function,
+        SourceLineInfo const& lineInfo,
+        NameAndDesc const& nameAndDesc );
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
+        static void TestName(); \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        static void TestName()
+    #define INTERNAL_CATCH_TESTCASE( ... ) \
+        INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ \
+            struct TestName : ClassName{ \
+                void test(); \
+            }; \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \
+        } \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        void TestName::test()
+    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
+        INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+#else
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
+        static void TestName(); \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); } /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        static void TestName()
+    #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
+        INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ \
+            struct TestCaseName : ClassName{ \
+                void test(); \
+            }; \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \
+        } \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        void TestCaseName::test()
+    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
+        INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+#endif
+
+// #included from: internal/catch_capture.hpp
+#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
+
+// #included from: catch_result_builder.h
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
+
+// #included from: catch_result_type.h
+#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
+
+namespace Catch {
+
+    // ResultWas::OfType enum
+    struct ResultWas { enum OfType {
+        Unknown = -1,
+        Ok = 0,
+        Info = 1,
+        Warning = 2,
+
+        FailureBit = 0x10,
+
+        ExpressionFailed = FailureBit | 1,
+        ExplicitFailure = FailureBit | 2,
+
+        Exception = 0x100 | FailureBit,
+
+        ThrewException = Exception | 1,
+        DidntThrowException = Exception | 2,
+
+        FatalErrorCondition = 0x200 | FailureBit
+
+    }; };
+
+    inline bool isOk( ResultWas::OfType resultType ) {
+        return ( resultType & ResultWas::FailureBit ) == 0;
+    }
+    inline bool isJustInfo( int flags ) {
+        return flags == ResultWas::Info;
+    }
+
+    // ResultDisposition::Flags enum
+    struct ResultDisposition { enum Flags {
+        Normal = 0x01,
+
+        ContinueOnFailure = 0x02,   // Failures fail test, but execution continues
+        FalseTest = 0x04,           // Prefix expression with !
+        SuppressFail = 0x08         // Failures are reported but do not fail the test
+    }; };
+
+    inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
+        return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
+    }
+
+    inline bool shouldContinueOnFailure( int flags )    { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
+    inline bool isFalseTest( int flags )                { return ( flags & ResultDisposition::FalseTest ) != 0; }
+    inline bool shouldSuppressFailure( int flags )      { return ( flags & ResultDisposition::SuppressFail ) != 0; }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.h
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
+
+    struct DecomposedExpression
+    {
+        virtual ~DecomposedExpression() {}
+        virtual bool isBinaryExpression() const {
+            return false;
+        }
+        virtual void reconstructExpression( std::string& dest ) const = 0;
+
+        // Only simple binary comparisons can be decomposed.
+        // If more complex check is required then wrap sub-expressions in parentheses.
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
+
+    private:
+        DecomposedExpression& operator = (DecomposedExpression const&);
+    };
+
+    struct AssertionInfo
+    {
+        AssertionInfo();
+        AssertionInfo(  char const * _macroName,
+                        SourceLineInfo const& _lineInfo,
+                        char const * _capturedExpression,
+                        ResultDisposition::Flags _resultDisposition,
+                        char const * _secondArg = "");
+
+        char const * macroName;
+        SourceLineInfo lineInfo;
+        char const * capturedExpression;
+        ResultDisposition::Flags resultDisposition;
+        char const * secondArg;
+    };
+
+    struct AssertionResultData
+    {
+        AssertionResultData() : decomposedExpression( CATCH_NULL )
+                              , resultType( ResultWas::Unknown )
+                              , negated( false )
+                              , parenthesized( false ) {}
+
+        void negate( bool parenthesize ) {
+            negated = !negated;
+            parenthesized = parenthesize;
+            if( resultType == ResultWas::Ok )
+                resultType = ResultWas::ExpressionFailed;
+            else if( resultType == ResultWas::ExpressionFailed )
+                resultType = ResultWas::Ok;
+        }
+
+        std::string const& reconstructExpression() const {
+            if( decomposedExpression != CATCH_NULL ) {
+                decomposedExpression->reconstructExpression( reconstructedExpression );
+                if( parenthesized ) {
+                    reconstructedExpression.insert( 0, 1, '(' );
+                    reconstructedExpression.append( 1, ')' );
+                }
+                if( negated ) {
+                    reconstructedExpression.insert( 0, 1, '!' );
+                }
+                decomposedExpression = CATCH_NULL;
+            }
+            return reconstructedExpression;
+        }
+
+        mutable DecomposedExpression const* decomposedExpression;
+        mutable std::string reconstructedExpression;
+        std::string message;
+        ResultWas::OfType resultType;
+        bool negated;
+        bool parenthesized;
+    };
+
+    class AssertionResult {
+    public:
+        AssertionResult();
+        AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
+        ~AssertionResult();
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+         AssertionResult( AssertionResult const& )              = default;
+         AssertionResult( AssertionResult && )                  = default;
+         AssertionResult& operator = ( AssertionResult const& ) = default;
+         AssertionResult& operator = ( AssertionResult && )     = default;
+#  endif
+
+        bool isOk() const;
+        bool succeeded() const;
+        ResultWas::OfType getResultType() const;
+        bool hasExpression() const;
+        bool hasMessage() const;
+        std::string getExpression() const;
+        std::string getExpressionInMacro() const;
+        bool hasExpandedExpression() const;
+        std::string getExpandedExpression() const;
+        std::string getMessage() const;
+        SourceLineInfo getSourceInfo() const;
+        std::string getTestMacroName() const;
+        void discardDecomposedExpression() const;
+        void expandDecomposedExpression() const;
+
+    protected:
+        AssertionInfo m_info;
+        AssertionResultData m_resultData;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_matchers.hpp
+#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+    namespace Impl {
+
+        template<typename ArgT> struct MatchAllOf;
+        template<typename ArgT> struct MatchAnyOf;
+        template<typename ArgT> struct MatchNotOf;
+
+        class MatcherUntypedBase {
+        public:
+            std::string toString() const {
+                if( m_cachedToString.empty() )
+                    m_cachedToString = describe();
+                return m_cachedToString;
+            }
+
+        protected:
+            virtual ~MatcherUntypedBase();
+            virtual std::string describe() const = 0;
+            mutable std::string m_cachedToString;
+        private:
+            MatcherUntypedBase& operator = ( MatcherUntypedBase const& );
+        };
+
+        template<typename ObjectT>
+        struct MatcherMethod {
+            virtual bool match( ObjectT const& arg ) const = 0;
+        };
+        template<typename PtrT>
+        struct MatcherMethod<PtrT*> {
+            virtual bool match( PtrT* arg ) const = 0;
+        };
+
+        template<typename ObjectT, typename ComparatorT = ObjectT>
+        struct MatcherBase : MatcherUntypedBase, MatcherMethod<ObjectT> {
+
+            MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const;
+            MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const;
+            MatchNotOf<ComparatorT> operator ! () const;
+        };
+
+        template<typename ArgT>
+        struct MatchAllOf : MatcherBase<ArgT> {
+            virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if (!m_matchers[i]->match(arg))
+                        return false;
+                }
+                return true;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                std::string description;
+                description.reserve( 4 + m_matchers.size()*32 );
+                description += "( ";
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if( i != 0 )
+                        description += " and ";
+                    description += m_matchers[i]->toString();
+                }
+                description += " )";
+                return description;
+            }
+
+            MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
+                m_matchers.push_back( &other );
+                return *this;
+            }
+
+            std::vector<MatcherBase<ArgT> const*> m_matchers;
+        };
+        template<typename ArgT>
+        struct MatchAnyOf : MatcherBase<ArgT> {
+
+            virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if (m_matchers[i]->match(arg))
+                        return true;
+                }
+                return false;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                std::string description;
+                description.reserve( 4 + m_matchers.size()*32 );
+                description += "( ";
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if( i != 0 )
+                        description += " or ";
+                    description += m_matchers[i]->toString();
+                }
+                description += " )";
+                return description;
+            }
+
+            MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
+                m_matchers.push_back( &other );
+                return *this;
+            }
+
+            std::vector<MatcherBase<ArgT> const*> m_matchers;
+        };
+
+        template<typename ArgT>
+        struct MatchNotOf : MatcherBase<ArgT> {
+
+            MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
+
+            virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+                return !m_underlyingMatcher.match( arg );
+            }
+
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "not " + m_underlyingMatcher.toString();
+            }
+            MatcherBase<ArgT> const& m_underlyingMatcher;
+        };
+
+        template<typename ObjectT, typename ComparatorT>
+        MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const {
+            return MatchAllOf<ComparatorT>() && *this && other;
+        }
+        template<typename ObjectT, typename ComparatorT>
+        MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const {
+            return MatchAnyOf<ComparatorT>() || *this || other;
+        }
+        template<typename ObjectT, typename ComparatorT>
+        MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const {
+            return MatchNotOf<ComparatorT>( *this );
+        }
+
+    } // namespace Impl
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+    // - deprecated: prefer ||, && and !
+    template<typename T>
+    Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
+        return Impl::MatchNotOf<T>( underlyingMatcher );
+    }
+    template<typename T>
+    Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+        return Impl::MatchAllOf<T>() && m1 && m2;
+    }
+    template<typename T>
+    Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+        return Impl::MatchAllOf<T>() && m1 && m2 && m3;
+    }
+    template<typename T>
+    Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+        return Impl::MatchAnyOf<T>() || m1 || m2;
+    }
+    template<typename T>
+    Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+        return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
+    }
+
+} // namespace Matchers
+
+using namespace Matchers;
+using Matchers::Impl::MatcherBase;
+
+} // namespace Catch
+
+namespace Catch {
+
+    struct TestFailureException{};
+
+    template<typename T> class ExpressionLhs;
+
+    struct CopyableStream {
+        CopyableStream() {}
+        CopyableStream( CopyableStream const& other ) {
+            oss << other.oss.str();
+        }
+        CopyableStream& operator=( CopyableStream const& other ) {
+            oss.str(std::string());
+            oss << other.oss.str();
+            return *this;
+        }
+        std::ostringstream oss;
+    };
+
+    class ResultBuilder : public DecomposedExpression {
+    public:
+        ResultBuilder(  char const* macroName,
+                        SourceLineInfo const& lineInfo,
+                        char const* capturedExpression,
+                        ResultDisposition::Flags resultDisposition,
+                        char const* secondArg = "" );
+        ~ResultBuilder();
+
+        template<typename T>
+        ExpressionLhs<T const&> operator <= ( T const& operand );
+        ExpressionLhs<bool> operator <= ( bool value );
+
+        template<typename T>
+        ResultBuilder& operator << ( T const& value ) {
+            stream().oss << value;
+            return *this;
+        }
+
+        ResultBuilder& setResultType( ResultWas::OfType result );
+        ResultBuilder& setResultType( bool result );
+
+        void endExpression( DecomposedExpression const& expr );
+
+        virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE;
+
+        AssertionResult build() const;
+        AssertionResult build( DecomposedExpression const& expr ) const;
+
+        void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
+        void captureResult( ResultWas::OfType resultType );
+        void captureExpression();
+        void captureExpectedException( std::string const& expectedMessage );
+        void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher );
+        void handleResult( AssertionResult const& result );
+        void react();
+        bool shouldDebugBreak() const;
+        bool allowThrows() const;
+
+        template<typename ArgT, typename MatcherT>
+        void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
+
+        void setExceptionGuard();
+        void unsetExceptionGuard();
+
+    private:
+        AssertionInfo m_assertionInfo;
+        AssertionResultData m_data;
+
+        CopyableStream &stream()
+        {
+            if(!m_usedStream)
+            {
+                m_usedStream = true;
+                m_stream().oss.str("");
+            }
+            return m_stream();
+        }
+
+        static CopyableStream &m_stream()
+        {
+            static CopyableStream s;
+            return s;
+        }
+
+        bool m_shouldDebugBreak;
+        bool m_shouldThrow;
+        bool m_guardException;
+        bool m_usedStream;
+    };
+
+} // namespace Catch
+
+// Include after due to circular dependency:
+// #included from: catch_expression_lhs.hpp
+#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
+
+// #included from: catch_evaluate.hpp
+#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+#pragma warning(disable:4018) // more "signed/unsigned mismatch"
+#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
+#endif
+
+#include <cstddef>
+
+namespace Catch {
+namespace Internal {
+
+    enum Operator {
+        IsEqualTo,
+        IsNotEqualTo,
+        IsLessThan,
+        IsGreaterThan,
+        IsLessThanOrEqualTo,
+        IsGreaterThanOrEqualTo
+    };
+
+    template<Operator Op> struct OperatorTraits             { static const char* getName(){ return "*error*"; } };
+    template<> struct OperatorTraits<IsEqualTo>             { static const char* getName(){ return "=="; } };
+    template<> struct OperatorTraits<IsNotEqualTo>          { static const char* getName(){ return "!="; } };
+    template<> struct OperatorTraits<IsLessThan>            { static const char* getName(){ return "<"; } };
+    template<> struct OperatorTraits<IsGreaterThan>         { static const char* getName(){ return ">"; } };
+    template<> struct OperatorTraits<IsLessThanOrEqualTo>   { static const char* getName(){ return "<="; } };
+    template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
+
+    template<typename T>
+    T& opCast(T const& t) { return const_cast<T&>(t); }
+
+// nullptr_t support based on pull request #154 from Konstantin Baumann
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+    inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+    // So the compare overloads can be operator agnostic we convey the operator as a template
+    // enum, which is used to specialise an Evaluator for doing the comparison.
+    template<typename T1, typename T2, Operator Op>
+    struct Evaluator{};
+
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs) {
+            return bool( opCast( lhs ) ==  opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsNotEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) != opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsLessThan> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) < opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsGreaterThan> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) > opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) >= opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) <= opCast( rhs ) );
+        }
+    };
+
+    template<Operator Op, typename T1, typename T2>
+    bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
+        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+    }
+
+    // This level of indirection allows us to specialise for integer types
+    // to avoid signed/ unsigned warnings
+
+    // "base" overload
+    template<Operator Op, typename T1, typename T2>
+    bool compare( T1 const& lhs, T2 const& rhs ) {
+        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+    }
+
+    // unsigned X to int
+    template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+
+    // unsigned X to long
+    template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+
+    // int to unsigned X
+    template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+
+    // long to unsigned X
+    template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+
+    // pointer to long (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+
+    // pointer to int (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+    // long long to unsigned X
+    template<Operator Op> bool compare( long long lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long long lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long long lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+
+    // unsigned long long to X
+    template<Operator Op> bool compare( unsigned long long lhs, int rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( unsigned long long lhs, long rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( unsigned long long lhs, char rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+
+    // pointer to long long (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+#endif // CATCH_CONFIG_CPP11_LONG_LONG
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+    // pointer to nullptr_t (when comparing against nullptr)
+    template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr );
+    }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+} // end of namespace Internal
+} // end of namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// #included from: catch_tostring.h
+#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
+
+#include <sstream>
+#include <iomanip>
+#include <limits>
+#include <vector>
+#include <cstddef>
+
+#ifdef __OBJC__
+// #included from: catch_objc_arc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
+
+#import <Foundation/Foundation.h>
+
+#ifdef __has_feature
+#define CATCH_ARC_ENABLED __has_feature(objc_arc)
+#else
+#define CATCH_ARC_ENABLED 0
+#endif
+
+void arcSafeRelease( NSObject* obj );
+id performOptionalSelector( id obj, SEL sel );
+
+#if !CATCH_ARC_ENABLED
+inline void arcSafeRelease( NSObject* obj ) {
+    [obj release];
+}
+inline id performOptionalSelector( id obj, SEL sel ) {
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED
+#define CATCH_ARC_STRONG
+#else
+inline void arcSafeRelease( NSObject* ){}
+inline id performOptionalSelector( id obj, SEL sel ) {
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+#endif
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
+#define CATCH_ARC_STRONG __strong
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+#include <tuple>
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_IS_ENUM
+#include <type_traits>
+#endif
+
+namespace Catch {
+
+// Why we're here.
+template<typename T>
+std::string toString( T const& value );
+
+// Built in overloads
+
+std::string toString( std::string const& value );
+std::string toString( std::wstring const& value );
+std::string toString( const char* const value );
+std::string toString( char* const value );
+std::string toString( const wchar_t* const value );
+std::string toString( wchar_t* const value );
+std::string toString( int value );
+std::string toString( unsigned long value );
+std::string toString( unsigned int value );
+std::string toString( const double value );
+std::string toString( const float value );
+std::string toString( bool value );
+std::string toString( char value );
+std::string toString( signed char value );
+std::string toString( unsigned char value );
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString( long long value );
+std::string toString( unsigned long long value );
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t );
+#endif
+
+#ifdef __OBJC__
+    std::string toString( NSString const * const& nsstring );
+    std::string toString( NSString * CATCH_ARC_STRONG & nsstring );
+    std::string toString( NSObject* const& nsObject );
+#endif
+
+namespace Detail {
+
+    extern const std::string unprintableString;
+
+ #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK)
+    struct BorgType {
+        template<typename T> BorgType( T const& );
+    };
+
+    struct TrueType { char sizer[1]; };
+    struct FalseType { char sizer[2]; };
+
+    TrueType& testStreamable( std::ostream& );
+    FalseType testStreamable( FalseType );
+
+    FalseType operator<<( std::ostream const&, BorgType const& );
+
+    template<typename T>
+    struct IsStreamInsertable {
+        static std::ostream &s;
+        static T  const&t;
+        enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
+    };
+#else
+    template<typename T>
+    class IsStreamInsertable {
+        template<typename SS, typename TT>
+        static auto test(int)
+        -> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() );
+
+        template<typename, typename>
+        static auto test(...) -> std::false_type;
+
+    public:
+        static const bool value = decltype(test<std::ostream,const T&>(0))::value;
+    };
+#endif
+
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+    template<typename T,
+             bool IsEnum = std::is_enum<T>::value
+             >
+    struct EnumStringMaker
+    {
+        static std::string convert( T const& ) { return unprintableString; }
+    };
+
+    template<typename T>
+    struct EnumStringMaker<T,true>
+    {
+        static std::string convert( T const& v )
+        {
+            return ::Catch::toString(
+                static_cast<typename std::underlying_type<T>::type>(v)
+                );
+        }
+    };
+#endif
+    template<bool C>
+    struct StringMakerBase {
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+        template<typename T>
+        static std::string convert( T const& v )
+        {
+            return EnumStringMaker<T>::convert( v );
+        }
+#else
+        template<typename T>
+        static std::string convert( T const& ) { return unprintableString; }
+#endif
+    };
+
+    template<>
+    struct StringMakerBase<true> {
+        template<typename T>
+        static std::string convert( T const& _value ) {
+            std::ostringstream oss;
+            oss << _value;
+            return oss.str();
+        }
+    };
+
+    std::string rawMemoryToString( const void *object, std::size_t size );
+
+    template<typename T>
+    std::string rawMemoryToString( const T& object ) {
+      return rawMemoryToString( &object, sizeof(object) );
+    }
+
+} // end namespace Detail
+
+template<typename T>
+struct StringMaker :
+    Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
+
+template<typename T>
+struct StringMaker<T*> {
+    template<typename U>
+    static std::string convert( U* p ) {
+        if( !p )
+            return "NULL";
+        else
+            return Detail::rawMemoryToString( p );
+    }
+};
+
+template<typename R, typename C>
+struct StringMaker<R C::*> {
+    static std::string convert( R C::* p ) {
+        if( !p )
+            return "NULL";
+        else
+            return Detail::rawMemoryToString( p );
+    }
+};
+
+namespace Detail {
+    template<typename InputIterator>
+    std::string rangeToString( InputIterator first, InputIterator last );
+}
+
+//template<typename T, typename Allocator>
+//struct StringMaker<std::vector<T, Allocator> > {
+//    static std::string convert( std::vector<T,Allocator> const& v ) {
+//        return Detail::rangeToString( v.begin(), v.end() );
+//    }
+//};
+
+template<typename T, typename Allocator>
+std::string toString( std::vector<T,Allocator> const& v ) {
+    return Detail::rangeToString( v.begin(), v.end() );
+}
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+
+// toString for tuples
+namespace TupleDetail {
+  template<
+      typename Tuple,
+      std::size_t N = 0,
+      bool = (N < std::tuple_size<Tuple>::value)
+      >
+  struct ElementPrinter {
+      static void print( const Tuple& tuple, std::ostream& os )
+      {
+          os << ( N ? ", " : " " )
+             << Catch::toString(std::get<N>(tuple));
+          ElementPrinter<Tuple,N+1>::print(tuple,os);
+      }
+  };
+
+  template<
+      typename Tuple,
+      std::size_t N
+      >
+  struct ElementPrinter<Tuple,N,false> {
+      static void print( const Tuple&, std::ostream& ) {}
+  };
+
+}
+
+template<typename ...Types>
+struct StringMaker<std::tuple<Types...>> {
+
+    static std::string convert( const std::tuple<Types...>& tuple )
+    {
+        std::ostringstream os;
+        os << '{';
+        TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os );
+        os << " }";
+        return os.str();
+    }
+};
+#endif // CATCH_CONFIG_CPP11_TUPLE
+
+namespace Detail {
+    template<typename T>
+    std::string makeString( T const& value ) {
+        return StringMaker<T>::convert( value );
+    }
+} // end namespace Detail
+
+/// \brief converts any type to a string
+///
+/// The default template forwards on to ostringstream - except when an
+/// ostringstream overload does not exist - in which case it attempts to detect
+/// that and writes {?}.
+/// Overload (not specialise) this template for custom typs that you don't want
+/// to provide an ostream overload for.
+template<typename T>
+std::string toString( T const& value ) {
+    return StringMaker<T>::convert( value );
+}
+
+    namespace Detail {
+    template<typename InputIterator>
+    std::string rangeToString( InputIterator first, InputIterator last ) {
+        std::ostringstream oss;
+        oss << "{ ";
+        if( first != last ) {
+            oss << Catch::toString( *first );
+            for( ++first ; first != last ; ++first )
+                oss << ", " << Catch::toString( *first );
+        }
+        oss << " }";
+        return oss.str();
+    }
+}
+
+} // end namespace Catch
+
+namespace Catch {
+
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+class BinaryExpression;
+
+template<typename ArgT, typename MatcherT>
+class MatchExpression;
+
+// Wraps the LHS of an expression and overloads comparison operators
+// for also capturing those and RHS (if any)
+template<typename T>
+class ExpressionLhs : public DecomposedExpression {
+public:
+    ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
+
+    ExpressionLhs& operator = ( const ExpressionLhs& );
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
+    operator == ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
+    operator != ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsNotEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsLessThan, RhsT const&>
+    operator < ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsLessThan>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
+    operator > ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsGreaterThan>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
+    operator <= ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
+    operator >= ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
+    }
+
+    BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) {
+        return captureExpression<Internal::IsEqualTo>( rhs );
+    }
+
+    BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) {
+        return captureExpression<Internal::IsNotEqualTo>( rhs );
+    }
+
+    void endExpression() {
+        m_truthy = m_lhs ? true : false;
+        m_rb
+            .setResultType( m_truthy )
+            .endExpression( *this );
+    }
+
+    virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+        dest = Catch::toString( m_lhs );
+    }
+
+private:
+    template<Internal::Operator Op, typename RhsT>
+    BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
+        return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
+    }
+
+    template<Internal::Operator Op>
+    BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
+        return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
+    }
+
+private:
+    ResultBuilder& m_rb;
+    T m_lhs;
+    bool m_truthy;
+};
+
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+class BinaryExpression : public DecomposedExpression {
+public:
+    BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs )
+        : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {}
+
+    BinaryExpression& operator = ( BinaryExpression& );
+
+    void endExpression() const {
+        m_rb
+            .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) )
+            .endExpression( *this );
+    }
+
+    virtual bool isBinaryExpression() const CATCH_OVERRIDE {
+        return true;
+    }
+
+    virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+        std::string lhs = Catch::toString( m_lhs );
+        std::string rhs = Catch::toString( m_rhs );
+        char delim = lhs.size() + rhs.size() < 40 &&
+                     lhs.find('\n') == std::string::npos &&
+                     rhs.find('\n') == std::string::npos ? ' ' : '\n';
+        dest.reserve( 7 + lhs.size() + rhs.size() );
+                   // 2 for spaces around operator
+                   // 2 for operator
+                   // 2 for parentheses (conditionally added later)
+                   // 1 for negation (conditionally added later)
+        dest = lhs;
+        dest += delim;
+        dest += Internal::OperatorTraits<Op>::getName();
+        dest += delim;
+        dest += rhs;
+    }
+
+private:
+    ResultBuilder& m_rb;
+    LhsT m_lhs;
+    RhsT m_rhs;
+};
+
+template<typename ArgT, typename MatcherT>
+class MatchExpression : public DecomposedExpression {
+public:
+    MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString )
+        : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {}
+
+    virtual bool isBinaryExpression() const CATCH_OVERRIDE {
+        return true;
+    }
+
+    virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+        std::string matcherAsString = m_matcher.toString();
+        dest = Catch::toString( m_arg );
+        dest += ' ';
+        if( matcherAsString == Detail::unprintableString )
+            dest += m_matcherString;
+        else
+            dest += matcherAsString;
+    }
+
+private:
+    ArgT m_arg;
+    MatcherT m_matcher;
+    char const* m_matcherString;
+};
+
+} // end namespace Catch
+
+
+namespace Catch {
+
+    template<typename T>
+    ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
+        return ExpressionLhs<T const&>( *this, operand );
+    }
+
+    inline ExpressionLhs<bool> ResultBuilder::operator <= ( bool value ) {
+        return ExpressionLhs<bool>( *this, value );
+    }
+
+    template<typename ArgT, typename MatcherT>
+    void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
+                                             char const* matcherString ) {
+        MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
+        setResultType( matcher.match( arg ) );
+        endExpression( expr );
+    }
+
+} // namespace Catch
+
+// #included from: catch_message.h
+#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct MessageInfo {
+        MessageInfo(    std::string const& _macroName,
+                        SourceLineInfo const& _lineInfo,
+                        ResultWas::OfType _type );
+
+        std::string macroName;
+        SourceLineInfo lineInfo;
+        ResultWas::OfType type;
+        std::string message;
+        unsigned int sequence;
+
+        bool operator == ( MessageInfo const& other ) const {
+            return sequence == other.sequence;
+        }
+        bool operator < ( MessageInfo const& other ) const {
+            return sequence < other.sequence;
+        }
+    private:
+        static unsigned int globalCount;
+    };
+
+    struct MessageBuilder {
+        MessageBuilder( std::string const& macroName,
+                        SourceLineInfo const& lineInfo,
+                        ResultWas::OfType type )
+        : m_info( macroName, lineInfo, type )
+        {}
+
+        template<typename T>
+        MessageBuilder& operator << ( T const& value ) {
+            m_stream << value;
+            return *this;
+        }
+
+        MessageInfo m_info;
+        std::ostringstream m_stream;
+    };
+
+    class ScopedMessage {
+    public:
+        ScopedMessage( MessageBuilder const& builder );
+        ScopedMessage( ScopedMessage const& other );
+        ~ScopedMessage();
+
+        MessageInfo m_info;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_capture.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    class TestCase;
+    class AssertionResult;
+    struct AssertionInfo;
+    struct SectionInfo;
+    struct SectionEndInfo;
+    struct MessageInfo;
+    class ScopedMessageBuilder;
+    struct Counts;
+
+    struct IResultCapture {
+
+        virtual ~IResultCapture();
+
+        virtual void assertionEnded( AssertionResult const& result ) = 0;
+        virtual bool sectionStarted(    SectionInfo const& sectionInfo,
+                                        Counts& assertions ) = 0;
+        virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
+        virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
+        virtual void pushScopedMessage( MessageInfo const& message ) = 0;
+        virtual void popScopedMessage( MessageInfo const& message ) = 0;
+
+        virtual std::string getCurrentTestName() const = 0;
+        virtual const AssertionResult* getLastResult() const = 0;
+
+        virtual void exceptionEarlyReported() = 0;
+
+        virtual void handleFatalErrorCondition( std::string const& message ) = 0;
+
+        virtual bool lastAssertionPassed() = 0;
+        virtual void assertionPassed() = 0;
+        virtual void assertionRun() = 0;
+    };
+
+    IResultCapture& getResultCapture();
+}
+
+// #included from: catch_debugger.h
+#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
+
+// #included from: catch_platform.h
+#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
+
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#  define CATCH_PLATFORM_MAC
+#elif  defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+#  define CATCH_PLATFORM_IPHONE
+#elif defined(linux) || defined(__linux) || defined(__linux__)
+#  define CATCH_PLATFORM_LINUX
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#  define CATCH_PLATFORM_WINDOWS
+#  if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
+#    define CATCH_DEFINES_NOMINMAX
+#  endif
+#  if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
+#    define CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+#  endif
+#endif
+
+#include <string>
+
+namespace Catch{
+
+    bool isDebuggerActive();
+    void writeToDebugConsole( std::string const& text );
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+    // The following code snippet based on:
+    // http://cocoawithlove.com/2008/03/break-into-debugger.html
+    #if defined(__ppc64__) || defined(__ppc__)
+        #define CATCH_TRAP() \
+                __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
+                : : : "memory","r0","r3","r4" ) /* NOLINT */
+    #else
+        #define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ )
+    #endif
+
+#elif defined(CATCH_PLATFORM_LINUX)
+    // If we can use inline assembler, do it because this allows us to break
+    // directly at the location of the failing check instead of breaking inside
+    // raise() called from it, i.e. one stack frame below.
+    #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
+        #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
+    #else // Fall back to the generic way.
+        #include <signal.h>
+
+        #define CATCH_TRAP() raise(SIGTRAP)
+    #endif
+#elif defined(_MSC_VER)
+    #define CATCH_TRAP() __debugbreak()
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+    #define CATCH_TRAP() DebugBreak()
+#endif
+
+#ifdef CATCH_TRAP
+    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
+#else
+    #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
+#endif
+
+// #included from: catch_interfaces_runner.h
+#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
+
+namespace Catch {
+    class TestCase;
+
+    struct IRunner {
+        virtual ~IRunner();
+        virtual bool aborting() const = 0;
+    };
+}
+
+#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
+# define CATCH_INTERNAL_STRINGIFY(expr) #expr
+#else
+# define CATCH_INTERNAL_STRINGIFY(expr) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
+#endif
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+///////////////////////////////////////////////////////////////////////////////
+// We can speedup compilation significantly by breaking into debugger lower in
+// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER
+// macro in each assertion
+#define INTERNAL_CATCH_REACT( resultBuilder ) \
+    resultBuilder.react();
+
+///////////////////////////////////////////////////////////////////////////////
+// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
+// macros.
+// This can potentially cause false negative, if the test code catches
+// the exception before it propagates back up to the runner.
+#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
+        __catchResult.setExceptionGuard(); \
+        CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+        ( __catchResult <= expr ).endExpression(); \
+        CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+        __catchResult.unsetExceptionGuard(); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+
+#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+        __catchResult.setExceptionGuard(); \
+        __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
+        __catchResult.unsetExceptionGuard(); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+#else
+///////////////////////////////////////////////////////////////////////////////
+// In the event of a failure works out if the debugger needs to be invoked
+// and/or an exception thrown and takes appropriate action.
+// This needs to be done as a macro so the debugger will stop in the user
+// source code rather than in Catch library code
+#define INTERNAL_CATCH_REACT( resultBuilder ) \
+    if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
+    resultBuilder.react();
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
+        try { \
+            CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+            ( __catchResult <= expr ).endExpression(); \
+            CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+        } \
+        catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+    // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \
+    INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
+    if( Catch::getResultCapture().lastAssertionPassed() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \
+    INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
+    if( !Catch::getResultCapture().lastAssertionPassed() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
+        try { \
+            static_cast<void>(expr); \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        } \
+        catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition, CATCH_INTERNAL_STRINGIFY(matcher) ); \
+        if( __catchResult.allowThrows() ) \
+            try { \
+                static_cast<void>(expr); \
+                __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+            } \
+            catch( ... ) { \
+                __catchResult.captureExpectedException( matcher ); \
+            } \
+        else \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
+        if( __catchResult.allowThrows() ) \
+            try { \
+                static_cast<void>(expr); \
+                __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+            } \
+            catch( exceptionType ) { \
+                __catchResult.captureResult( Catch::ResultWas::Ok ); \
+            } \
+            catch( ... ) { \
+                __catchResult.useActiveException( resultDisposition ); \
+            } \
+        else \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
+        do { \
+            Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+            __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
+            __catchResult.captureResult( messageType ); \
+            INTERNAL_CATCH_REACT( __catchResult ) \
+        } while( Catch::alwaysFalse() )
+#else
+    #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \
+        do { \
+            Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+            __catchResult << log + ::Catch::StreamEndStop(); \
+            __catchResult.captureResult( messageType ); \
+            INTERNAL_CATCH_REACT( __catchResult ) \
+        } while( Catch::alwaysFalse() )
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO( macroName, log ) \
+    Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+        try { \
+            __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
+        } catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+// #included from: internal/catch_section.h
+#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
+
+// #included from: catch_section_info.h
+#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
+
+// #included from: catch_totals.hpp
+#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
+
+#include <cstddef>
+
+namespace Catch {
+
+    struct Counts {
+        Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {}
+
+        Counts operator - ( Counts const& other ) const {
+            Counts diff;
+            diff.passed = passed - other.passed;
+            diff.failed = failed - other.failed;
+            diff.failedButOk = failedButOk - other.failedButOk;
+            return diff;
+        }
+        Counts& operator += ( Counts const& other ) {
+            passed += other.passed;
+            failed += other.failed;
+            failedButOk += other.failedButOk;
+            return *this;
+        }
+
+        std::size_t total() const {
+            return passed + failed + failedButOk;
+        }
+        bool allPassed() const {
+            return failed == 0 && failedButOk == 0;
+        }
+        bool allOk() const {
+            return failed == 0;
+        }
+
+        std::size_t passed;
+        std::size_t failed;
+        std::size_t failedButOk;
+    };
+
+    struct Totals {
+
+        Totals operator - ( Totals const& other ) const {
+            Totals diff;
+            diff.assertions = assertions - other.assertions;
+            diff.testCases = testCases - other.testCases;
+            return diff;
+        }
+
+        Totals delta( Totals const& prevTotals ) const {
+            Totals diff = *this - prevTotals;
+            if( diff.assertions.failed > 0 )
+                ++diff.testCases.failed;
+            else if( diff.assertions.failedButOk > 0 )
+                ++diff.testCases.failedButOk;
+            else
+                ++diff.testCases.passed;
+            return diff;
+        }
+
+        Totals& operator += ( Totals const& other ) {
+            assertions += other.assertions;
+            testCases += other.testCases;
+            return *this;
+        }
+
+        Counts assertions;
+        Counts testCases;
+    };
+}
+
+#include <string>
+
+namespace Catch {
+
+    struct SectionInfo {
+        SectionInfo
+            (   SourceLineInfo const& _lineInfo,
+                std::string const& _name,
+                std::string const& _description = std::string() );
+
+        std::string name;
+        std::string description;
+        SourceLineInfo lineInfo;
+    };
+
+    struct SectionEndInfo {
+        SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
+        : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
+        {}
+
+        SectionInfo sectionInfo;
+        Counts prevAssertions;
+        double durationInSeconds;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_timer.h
+#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
+
+#ifdef _MSC_VER
+
+namespace Catch {
+    typedef unsigned long long UInt64;
+}
+#else
+#include <stdint.h>
+namespace Catch {
+    typedef uint64_t UInt64;
+}
+#endif
+
+namespace Catch {
+    class Timer {
+    public:
+        Timer() : m_ticks( 0 ) {}
+        void start();
+        unsigned int getElapsedMicroseconds() const;
+        unsigned int getElapsedMilliseconds() const;
+        double getElapsedSeconds() const;
+
+    private:
+        UInt64 m_ticks;
+    };
+
+} // namespace Catch
+
+#include <string>
+
+namespace Catch {
+
+    class Section : NonCopyable {
+    public:
+        Section( SectionInfo const& info );
+        ~Section();
+
+        // This indicates whether the section should be executed or not
+        operator bool() const;
+
+    private:
+        SectionInfo m_info;
+
+        std::string m_name;
+        Counts m_assertions;
+        bool m_sectionIncluded;
+        Timer m_timer;
+    };
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define INTERNAL_CATCH_SECTION( ... ) \
+        if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
+#else
+    #define INTERNAL_CATCH_SECTION( name, desc ) \
+        if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) )
+#endif
+
+// #included from: internal/catch_generators.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <stdlib.h>
+
+namespace Catch {
+
+template<typename T>
+struct IGenerator {
+    virtual ~IGenerator() {}
+    virtual T getValue( std::size_t index ) const = 0;
+    virtual std::size_t size () const = 0;
+};
+
+template<typename T>
+class BetweenGenerator : public IGenerator<T> {
+public:
+    BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
+
+    virtual T getValue( std::size_t index ) const {
+        return m_from+static_cast<int>( index );
+    }
+
+    virtual std::size_t size() const {
+        return static_cast<std::size_t>( 1+m_to-m_from );
+    }
+
+private:
+
+    T m_from;
+    T m_to;
+};
+
+template<typename T>
+class ValuesGenerator : public IGenerator<T> {
+public:
+    ValuesGenerator(){}
+
+    void add( T value ) {
+        m_values.push_back( value );
+    }
+
+    virtual T getValue( std::size_t index ) const {
+        return m_values[index];
+    }
+
+    virtual std::size_t size() const {
+        return m_values.size();
+    }
+
+private:
+    std::vector<T> m_values;
+};
+
+template<typename T>
+class CompositeGenerator {
+public:
+    CompositeGenerator() : m_totalSize( 0 ) {}
+
+    // *** Move semantics, similar to auto_ptr ***
+    CompositeGenerator( CompositeGenerator& other )
+    :   m_fileInfo( other.m_fileInfo ),
+        m_totalSize( 0 )
+    {
+        move( other );
+    }
+
+    CompositeGenerator& setFileInfo( const char* fileInfo ) {
+        m_fileInfo = fileInfo;
+        return *this;
+    }
+
+    ~CompositeGenerator() {
+        deleteAll( m_composed );
+    }
+
+    operator T () const {
+        size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
+
+        typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
+        typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
+        for( size_t index = 0; it != itEnd; ++it )
+        {
+            const IGenerator<T>* generator = *it;
+            if( overallIndex >= index && overallIndex < index + generator->size() )
+            {
+                return generator->getValue( overallIndex-index );
+            }
+            index += generator->size();
+        }
+        CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
+        return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
+    }
+
+    void add( const IGenerator<T>* generator ) {
+        m_totalSize += generator->size();
+        m_composed.push_back( generator );
+    }
+
+    CompositeGenerator& then( CompositeGenerator& other ) {
+        move( other );
+        return *this;
+    }
+
+    CompositeGenerator& then( T value ) {
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( value );
+        add( valuesGen );
+        return *this;
+    }
+
+private:
+
+    void move( CompositeGenerator& other ) {
+        m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() );
+        m_totalSize += other.m_totalSize;
+        other.m_composed.clear();
+    }
+
+    std::vector<const IGenerator<T>*> m_composed;
+    std::string m_fileInfo;
+    size_t m_totalSize;
+};
+
+namespace Generators
+{
+    template<typename T>
+    CompositeGenerator<T> between( T from, T to ) {
+        CompositeGenerator<T> generators;
+        generators.add( new BetweenGenerator<T>( from, to ) );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2 ) {
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2, T val3 ){
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        valuesGen->add( val3 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        valuesGen->add( val3 );
+        valuesGen->add( val4 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+} // end namespace Generators
+
+using namespace Generators;
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_LINESTR2( line ) #line
+#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
+
+#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
+
+// #included from: internal/catch_interfaces_exception.h
+#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
+
+#include <string>
+#include <vector>
+
+// #included from: catch_interfaces_registry_hub.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    class TestCase;
+    struct ITestCaseRegistry;
+    struct IExceptionTranslatorRegistry;
+    struct IExceptionTranslator;
+    struct IReporterRegistry;
+    struct IReporterFactory;
+    struct ITagAliasRegistry;
+
+    struct IRegistryHub {
+        virtual ~IRegistryHub();
+
+        virtual IReporterRegistry const& getReporterRegistry() const = 0;
+        virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+        virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
+
+        virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
+    };
+
+    struct IMutableRegistryHub {
+        virtual ~IMutableRegistryHub();
+        virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0;
+        virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
+        virtual void registerTest( TestCase const& testInfo ) = 0;
+        virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
+        virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
+    };
+
+    IRegistryHub& getRegistryHub();
+    IMutableRegistryHub& getMutableRegistryHub();
+    void cleanUp();
+    std::string translateActiveException();
+
+}
+
+namespace Catch {
+
+    typedef std::string(*exceptionTranslateFunction)();
+
+    struct IExceptionTranslator;
+    typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
+
+    struct IExceptionTranslator {
+        virtual ~IExceptionTranslator();
+        virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
+    };
+
+    struct IExceptionTranslatorRegistry {
+        virtual ~IExceptionTranslatorRegistry();
+
+        virtual std::string translateActiveException() const = 0;
+    };
+
+    class ExceptionTranslatorRegistrar {
+        template<typename T>
+        class ExceptionTranslator : public IExceptionTranslator {
+        public:
+
+            ExceptionTranslator( std::string(*translateFunction)( T& ) )
+            : m_translateFunction( translateFunction )
+            {}
+
+            virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE {
+                try {
+                    if( it == itEnd )
+                        throw;
+                    else
+                        return (*it)->translate( it+1, itEnd );
+                }
+                catch( T& ex ) {
+                    return m_translateFunction( ex );
+                }
+            }
+
+        protected:
+            std::string(*m_translateFunction)( T& );
+        };
+
+    public:
+        template<typename T>
+        ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
+            getMutableRegistryHub().registerTranslator
+                ( new ExceptionTranslator<T>( translateFunction ) );
+        }
+    };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
+    static std::string translatorName( signature ); \
+    namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
+    static std::string translatorName( signature )
+
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
+
+// #included from: internal/catch_approx.hpp
+#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
+
+#include <cmath>
+#include <limits>
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+#include <type_traits>
+#endif
+
+namespace Catch {
+namespace Detail {
+
+    class Approx {
+    public:
+        explicit Approx ( double value )
+        :   m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
+            m_margin( 0.0 ),
+            m_scale( 1.0 ),
+            m_value( value )
+        {}
+
+        static Approx custom() {
+            return Approx( 0 );
+        }
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx operator()( T value ) {
+            Approx approx( static_cast<double>(value) );
+            approx.epsilon( m_epsilon );
+            approx.margin( m_margin );
+            approx.scale( m_scale );
+            return approx;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        explicit Approx( T value ): Approx(static_cast<double>(value))
+        {}
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator == ( const T& lhs, Approx const& rhs ) {
+            // Thanks to Richard Harris for his help refining this formula
+            auto lhs_v = double(lhs);
+            bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value)));
+            if (relativeOK) {
+                return true;
+            }
+
+            return std::fabs(lhs_v - rhs.m_value) <= rhs.m_margin;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator == ( Approx const& lhs, const T& rhs ) {
+            return operator==( rhs, lhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator != ( T lhs, Approx const& rhs ) {
+            return !operator==( lhs, rhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator != ( Approx const& lhs, T rhs ) {
+            return !operator==( rhs, lhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator <= ( T lhs, Approx const& rhs ) {
+            return double(lhs) < rhs.m_value || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator <= ( Approx const& lhs, T rhs ) {
+            return lhs.m_value < double(rhs) || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator >= ( T lhs, Approx const& rhs ) {
+            return double(lhs) > rhs.m_value || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator >= ( Approx const& lhs, T rhs ) {
+            return lhs.m_value > double(rhs) || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& epsilon( T newEpsilon ) {
+            m_epsilon = double(newEpsilon);
+            return *this;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& margin( T newMargin ) {
+            m_margin = double(newMargin);
+            return *this;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& scale( T newScale ) {
+            m_scale = double(newScale);
+            return *this;
+        }
+
+#else
+
+        Approx operator()( double value ) {
+            Approx approx( value );
+            approx.epsilon( m_epsilon );
+            approx.margin( m_margin );
+            approx.scale( m_scale );
+            return approx;
+        }
+
+        friend bool operator == ( double lhs, Approx const& rhs ) {
+            // Thanks to Richard Harris for his help refining this formula
+            bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) );
+            if (relativeOK) {
+                return true;
+            }
+            return std::fabs(lhs - rhs.m_value) <= rhs.m_margin;
+        }
+
+        friend bool operator == ( Approx const& lhs, double rhs ) {
+            return operator==( rhs, lhs );
+        }
+
+        friend bool operator != ( double lhs, Approx const& rhs ) {
+            return !operator==( lhs, rhs );
+        }
+
+        friend bool operator != ( Approx const& lhs, double rhs ) {
+            return !operator==( rhs, lhs );
+        }
+
+        friend bool operator <= ( double lhs, Approx const& rhs ) {
+            return lhs < rhs.m_value || lhs == rhs;
+        }
+
+        friend bool operator <= ( Approx const& lhs, double rhs ) {
+            return lhs.m_value < rhs || lhs == rhs;
+        }
+
+        friend bool operator >= ( double lhs, Approx const& rhs ) {
+            return lhs > rhs.m_value || lhs == rhs;
+        }
+
+        friend bool operator >= ( Approx const& lhs, double rhs ) {
+            return lhs.m_value > rhs || lhs == rhs;
+        }
+
+        Approx& epsilon( double newEpsilon ) {
+            m_epsilon = newEpsilon;
+            return *this;
+        }
+
+        Approx& margin( double newMargin ) {
+            m_margin = newMargin;
+            return *this;
+        }
+
+        Approx& scale( double newScale ) {
+            m_scale = newScale;
+            return *this;
+        }
+#endif
+
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << "Approx( " << Catch::toString( m_value ) << " )";
+            return oss.str();
+        }
+
+    private:
+        double m_epsilon;
+        double m_margin;
+        double m_scale;
+        double m_value;
+    };
+}
+
+template<>
+inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
+    return value.toString();
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_matchers_string.h
+#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+
+    namespace StdString {
+
+        struct CasedString
+        {
+            CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity );
+            std::string adjustString( std::string const& str ) const;
+            std::string caseSensitivitySuffix() const;
+
+            CaseSensitive::Choice m_caseSensitivity;
+            std::string m_str;
+        };
+
+        struct StringMatcherBase : MatcherBase<std::string> {
+            StringMatcherBase( std::string const& operation, CasedString const& comparator );
+            virtual std::string describe() const CATCH_OVERRIDE;
+
+            CasedString m_comparator;
+            std::string m_operation;
+        };
+
+        struct EqualsMatcher : StringMatcherBase {
+            EqualsMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+        struct ContainsMatcher : StringMatcherBase {
+            ContainsMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+        struct StartsWithMatcher : StringMatcherBase {
+            StartsWithMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+        struct EndsWithMatcher : StringMatcherBase {
+            EndsWithMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+
+    } // namespace StdString
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+
+    StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+
+} // namespace Matchers
+} // namespace Catch
+
+// #included from: internal/catch_matchers_vector.h
+#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+
+    namespace Vector {
+
+        template<typename T>
+        struct ContainsElementMatcher : MatcherBase<std::vector<T>, T> {
+
+            ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
+
+            bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+                return std::find(v.begin(), v.end(), m_comparator) != v.end();
+            }
+
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "Contains: " + Catch::toString( m_comparator );
+            }
+
+            T const& m_comparator;
+        };
+
+        template<typename T>
+        struct ContainsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
+
+            ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+            bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+                // !TBD: see note in EqualsMatcher
+                if (m_comparator.size() > v.size())
+                    return false;
+                for (size_t i = 0; i < m_comparator.size(); ++i)
+                    if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end())
+                        return false;
+                return true;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "Contains: " + Catch::toString( m_comparator );
+            }
+
+            std::vector<T> const& m_comparator;
+        };
+
+        template<typename T>
+        struct EqualsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
+
+            EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+            bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+                // !TBD: This currently works if all elements can be compared using !=
+                // - a more general approach would be via a compare template that defaults
+                // to using !=. but could be specialised for, e.g. std::vector<T> etc
+                // - then just call that directly
+                if (m_comparator.size() != v.size())
+                    return false;
+                for (size_t i = 0; i < v.size(); ++i)
+                    if (m_comparator[i] != v[i])
+                        return false;
+                return true;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "Equals: " + Catch::toString( m_comparator );
+            }
+            std::vector<T> const& m_comparator;
+        };
+
+    } // namespace Vector
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+
+    template<typename T>
+    Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
+        return Vector::ContainsMatcher<T>( comparator );
+    }
+
+    template<typename T>
+    Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
+        return Vector::ContainsElementMatcher<T>( comparator );
+    }
+
+    template<typename T>
+    Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
+        return Vector::EqualsMatcher<T>( comparator );
+    }
+
+} // namespace Matchers
+} // namespace Catch
+
+// #included from: internal/catch_interfaces_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+// #included from: catch_tag_alias.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct TagAlias {
+        TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
+
+        std::string tag;
+        SourceLineInfo lineInfo;
+    };
+
+    struct RegistrarForTagAliases {
+        RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+    };
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); }
+// #included from: catch_option.hpp
+#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
+
+namespace Catch {
+
+    // An optional type
+    template<typename T>
+    class Option {
+    public:
+        Option() : nullableValue( CATCH_NULL ) {}
+        Option( T const& _value )
+        : nullableValue( new( storage ) T( _value ) )
+        {}
+        Option( Option const& _other )
+        : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL )
+        {}
+
+        ~Option() {
+            reset();
+        }
+
+        Option& operator= ( Option const& _other ) {
+            if( &_other != this ) {
+                reset();
+                if( _other )
+                    nullableValue = new( storage ) T( *_other );
+            }
+            return *this;
+        }
+        Option& operator = ( T const& _value ) {
+            reset();
+            nullableValue = new( storage ) T( _value );
+            return *this;
+        }
+
+        void reset() {
+            if( nullableValue )
+                nullableValue->~T();
+            nullableValue = CATCH_NULL;
+        }
+
+        T& operator*() { return *nullableValue; }
+        T const& operator*() const { return *nullableValue; }
+        T* operator->() { return nullableValue; }
+        const T* operator->() const { return nullableValue; }
+
+        T valueOr( T const& defaultValue ) const {
+            return nullableValue ? *nullableValue : defaultValue;
+        }
+
+        bool some() const { return nullableValue != CATCH_NULL; }
+        bool none() const { return nullableValue == CATCH_NULL; }
+
+        bool operator !() const { return nullableValue == CATCH_NULL; }
+        operator SafeBool::type() const {
+            return SafeBool::makeSafe( some() );
+        }
+
+    private:
+        T *nullableValue;
+        union {
+            char storage[sizeof(T)];
+
+            // These are here to force alignment for the storage
+            long double dummy1;
+            void (*dummy2)();
+            long double dummy3;
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+            long long dummy4;
+#endif
+        };
+    };
+
+} // end namespace Catch
+
+namespace Catch {
+
+    struct ITagAliasRegistry {
+        virtual ~ITagAliasRegistry();
+        virtual Option<TagAlias> find( std::string const& alias ) const = 0;
+        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
+
+        static ITagAliasRegistry const& get();
+    };
+
+} // end namespace Catch
+
+// These files are included here so the single_include script doesn't put them
+// in the conditionally compiled sections
+// #included from: internal/catch_test_case_info.h
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
+
+#include <string>
+#include <set>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    struct ITestCase;
+
+    struct TestCaseInfo {
+        enum SpecialProperties{
+            None = 0,
+            IsHidden = 1 << 1,
+            ShouldFail = 1 << 2,
+            MayFail = 1 << 3,
+            Throws = 1 << 4,
+            NonPortable = 1 << 5
+        };
+
+        TestCaseInfo(   std::string const& _name,
+                        std::string const& _className,
+                        std::string const& _description,
+                        std::set<std::string> const& _tags,
+                        SourceLineInfo const& _lineInfo );
+
+        TestCaseInfo( TestCaseInfo const& other );
+
+        friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags );
+
+        bool isHidden() const;
+        bool throws() const;
+        bool okToFail() const;
+        bool expectedToFail() const;
+
+        std::string name;
+        std::string className;
+        std::string description;
+        std::set<std::string> tags;
+        std::set<std::string> lcaseTags;
+        std::string tagsAsString;
+        SourceLineInfo lineInfo;
+        SpecialProperties properties;
+    };
+
+    class TestCase : public TestCaseInfo {
+    public:
+
+        TestCase( ITestCase* testCase, TestCaseInfo const& info );
+        TestCase( TestCase const& other );
+
+        TestCase withName( std::string const& _newName ) const;
+
+        void invoke() const;
+
+        TestCaseInfo const& getTestCaseInfo() const;
+
+        void swap( TestCase& other );
+        bool operator == ( TestCase const& other ) const;
+        bool operator < ( TestCase const& other ) const;
+        TestCase& operator = ( TestCase const& other );
+
+    private:
+        Ptr<ITestCase> test;
+    };
+
+    TestCase makeTestCase(  ITestCase* testCase,
+                            std::string const& className,
+                            std::string const& name,
+                            std::string const& description,
+                            SourceLineInfo const& lineInfo );
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+
+#ifdef __OBJC__
+// #included from: internal/catch_objc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
+
+#import <objc/runtime.h>
+
+#include <string>
+
+// NB. Any general catch headers included here must be included
+// in catch.hpp first to make sure they are included by the single
+// header for non obj-usage
+
+///////////////////////////////////////////////////////////////////////////////
+// This protocol is really only here for (self) documenting purposes, since
+// all its methods are optional.
+ at protocol OcFixture
+
+ at optional
+
+-(void) setUp;
+-(void) tearDown;
+
+ at end
+
+namespace Catch {
+
+    class OcMethod : public SharedImpl<ITestCase> {
+
+    public:
+        OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
+
+        virtual void invoke() const {
+            id obj = [[m_cls alloc] init];
+
+            performOptionalSelector( obj, @selector(setUp)  );
+            performOptionalSelector( obj, m_sel );
+            performOptionalSelector( obj, @selector(tearDown)  );
+
+            arcSafeRelease( obj );
+        }
+    private:
+        virtual ~OcMethod() {}
+
+        Class m_cls;
+        SEL m_sel;
+    };
+
+    namespace Detail{
+
+        inline std::string getAnnotation(   Class cls,
+                                            std::string const& annotationName,
+                                            std::string const& testCaseName ) {
+            NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
+            SEL sel = NSSelectorFromString( selStr );
+            arcSafeRelease( selStr );
+            id value = performOptionalSelector( cls, sel );
+            if( value )
+                return [(NSString*)value UTF8String];
+            return "";
+        }
+    }
+
+    inline size_t registerTestMethods() {
+        size_t noTestMethods = 0;
+        int noClasses = objc_getClassList( CATCH_NULL, 0 );
+
+        Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
+        objc_getClassList( classes, noClasses );
+
+        for( int c = 0; c < noClasses; c++ ) {
+            Class cls = classes[c];
+            {
+                u_int count;
+                Method* methods = class_copyMethodList( cls, &count );
+                for( u_int m = 0; m < count ; m++ ) {
+                    SEL selector = method_getName(methods[m]);
+                    std::string methodName = sel_getName(selector);
+                    if( startsWith( methodName, "Catch_TestCase_" ) ) {
+                        std::string testCaseName = methodName.substr( 15 );
+                        std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
+                        std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
+                        const char* className = class_getName( cls );
+
+                        getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
+                        noTestMethods++;
+                    }
+                }
+                free(methods);
+            }
+        }
+        return noTestMethods;
+    }
+
+    namespace Matchers {
+        namespace Impl {
+        namespace NSStringMatchers {
+
+            struct StringHolder : MatcherBase<NSString*>{
+                StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
+                StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
+                StringHolder() {
+                    arcSafeRelease( m_substr );
+                }
+
+                virtual bool match( NSString* arg ) const CATCH_OVERRIDE {
+                    return false;
+                }
+
+                NSString* m_substr;
+            };
+
+            struct Equals : StringHolder {
+                Equals( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const CATCH_OVERRIDE {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str isEqualToString:m_substr];
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "equals string: " + Catch::toString( m_substr );
+                }
+            };
+
+            struct Contains : StringHolder {
+                Contains( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location != NSNotFound;
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "contains string: " + Catch::toString( m_substr );
+                }
+            };
+
+            struct StartsWith : StringHolder {
+                StartsWith( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == 0;
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "starts with: " + Catch::toString( m_substr );
+                }
+            };
+            struct EndsWith : StringHolder {
+                EndsWith( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "ends with: " + Catch::toString( m_substr );
+                }
+            };
+
+        } // namespace NSStringMatchers
+        } // namespace Impl
+
+        inline Impl::NSStringMatchers::Equals
+            Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
+
+        inline Impl::NSStringMatchers::Contains
+            Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
+
+        inline Impl::NSStringMatchers::StartsWith
+            StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
+
+        inline Impl::NSStringMatchers::EndsWith
+            EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
+
+    } // namespace Matchers
+
+    using namespace Matchers;
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define OC_TEST_CASE( name, desc )\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
+{\
+return @ name; \
+}\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
+{ \
+return @ desc; \
+} \
+-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
+
+#endif
+
+#ifdef CATCH_IMPL
+
+// !TBD: Move the leak detector code into a separate header
+#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
+#include <crtdbg.h>
+class LeakDetector {
+public:
+    LeakDetector() {
+        int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+        flag |= _CRTDBG_LEAK_CHECK_DF;
+        flag |= _CRTDBG_ALLOC_MEM_DF;
+        _CrtSetDbgFlag(flag);
+        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+        _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+        // Change this to leaking allocation's number to break there
+        _CrtSetBreakAlloc(-1);
+    }
+};
+#else
+class LeakDetector {};
+#endif
+
+LeakDetector leakDetector;
+
+// #included from: internal/catch_impl.hpp
+#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
+
+// Collect all the implementation files together here
+// These are the equivalent of what would usually be cpp files
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// #included from: ../catch_session.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
+
+// #included from: internal/catch_commandline.hpp
+#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
+
+// #included from: catch_config.hpp
+#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
+
+// #included from: catch_test_spec_parser.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_test_spec.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_wildcard_pattern.hpp
+#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+
+#include <stdexcept>
+
+namespace Catch
+{
+    class WildcardPattern {
+        enum WildcardPosition {
+            NoWildcard = 0,
+            WildcardAtStart = 1,
+            WildcardAtEnd = 2,
+            WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+        };
+
+    public:
+
+        WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity )
+        :   m_caseSensitivity( caseSensitivity ),
+            m_wildcard( NoWildcard ),
+            m_pattern( adjustCase( pattern ) )
+        {
+            if( startsWith( m_pattern, '*' ) ) {
+                m_pattern = m_pattern.substr( 1 );
+                m_wildcard = WildcardAtStart;
+            }
+            if( endsWith( m_pattern, '*' ) ) {
+                m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
+                m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
+            }
+        }
+        virtual ~WildcardPattern();
+        virtual bool matches( std::string const& str ) const {
+            switch( m_wildcard ) {
+                case NoWildcard:
+                    return m_pattern == adjustCase( str );
+                case WildcardAtStart:
+                    return endsWith( adjustCase( str ), m_pattern );
+                case WildcardAtEnd:
+                    return startsWith( adjustCase( str ), m_pattern );
+                case WildcardAtBothEnds:
+                    return contains( adjustCase( str ), m_pattern );
+            }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+            throw std::logic_error( "Unknown enum" );
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+        }
+    private:
+        std::string adjustCase( std::string const& str ) const {
+            return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
+        }
+        CaseSensitive::Choice m_caseSensitivity;
+        WildcardPosition m_wildcard;
+        std::string m_pattern;
+    };
+}
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    class TestSpec {
+        struct Pattern : SharedImpl<> {
+            virtual ~Pattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+        };
+        class NamePattern : public Pattern {
+        public:
+            NamePattern( std::string const& name )
+            : m_wildcardPattern( toLower( name ), CaseSensitive::No )
+            {}
+            virtual ~NamePattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const {
+                return m_wildcardPattern.matches( toLower( testCase.name ) );
+            }
+        private:
+            WildcardPattern m_wildcardPattern;
+        };
+
+        class TagPattern : public Pattern {
+        public:
+            TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
+            virtual ~TagPattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const {
+                return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end();
+            }
+        private:
+            std::string m_tag;
+        };
+
+        class ExcludedPattern : public Pattern {
+        public:
+            ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
+            virtual ~ExcludedPattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
+        private:
+            Ptr<Pattern> m_underlyingPattern;
+        };
+
+        struct Filter {
+            std::vector<Ptr<Pattern> > m_patterns;
+
+            bool matches( TestCaseInfo const& testCase ) const {
+                // All patterns in a filter must match for the filter to be a match
+                for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
+                    if( !(*it)->matches( testCase ) )
+                        return false;
+                }
+                return true;
+            }
+        };
+
+    public:
+        bool hasFilters() const {
+            return !m_filters.empty();
+        }
+        bool matches( TestCaseInfo const& testCase ) const {
+            // A TestSpec matches if any filter matches
+            for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it )
+                if( it->matches( testCase ) )
+                    return true;
+            return false;
+        }
+
+    private:
+        std::vector<Filter> m_filters;
+
+        friend class TestSpecParser;
+    };
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+    class TestSpecParser {
+        enum Mode{ None, Name, QuotedName, Tag, EscapedName };
+        Mode m_mode;
+        bool m_exclusion;
+        std::size_t m_start, m_pos;
+        std::string m_arg;
+        std::vector<std::size_t> m_escapeChars;
+        TestSpec::Filter m_currentFilter;
+        TestSpec m_testSpec;
+        ITagAliasRegistry const* m_tagAliases;
+
+    public:
+        TestSpecParser( ITagAliasRegistry const& tagAliases ) :m_mode(None), m_exclusion(false), m_start(0), m_pos(0), m_tagAliases( &tagAliases ) {}
+
+        TestSpecParser& parse( std::string const& arg ) {
+            m_mode = None;
+            m_exclusion = false;
+            m_start = std::string::npos;
+            m_arg = m_tagAliases->expandAliases( arg );
+            m_escapeChars.clear();
+            for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
+                visitChar( m_arg[m_pos] );
+            if( m_mode == Name )
+                addPattern<TestSpec::NamePattern>();
+            return *this;
+        }
+        TestSpec testSpec() {
+            addFilter();
+            return m_testSpec;
+        }
+    private:
+        void visitChar( char c ) {
+            if( m_mode == None ) {
+                switch( c ) {
+                case ' ': return;
+                case '~': m_exclusion = true; return;
+                case '[': return startNewMode( Tag, ++m_pos );
+                case '"': return startNewMode( QuotedName, ++m_pos );
+                case '\\': return escape();
+                default: startNewMode( Name, m_pos ); break;
+                }
+            }
+            if( m_mode == Name ) {
+                if( c == ',' ) {
+                    addPattern<TestSpec::NamePattern>();
+                    addFilter();
+                }
+                else if( c == '[' ) {
+                    if( subString() == "exclude:" )
+                        m_exclusion = true;
+                    else
+                        addPattern<TestSpec::NamePattern>();
+                    startNewMode( Tag, ++m_pos );
+                }
+                else if( c == '\\' )
+                    escape();
+            }
+            else if( m_mode == EscapedName )
+                m_mode = Name;
+            else if( m_mode == QuotedName && c == '"' )
+                addPattern<TestSpec::NamePattern>();
+            else if( m_mode == Tag && c == ']' )
+                addPattern<TestSpec::TagPattern>();
+        }
+        void startNewMode( Mode mode, std::size_t start ) {
+            m_mode = mode;
+            m_start = start;
+        }
+        void escape() {
+            if( m_mode == None )
+                m_start = m_pos;
+            m_mode = EscapedName;
+            m_escapeChars.push_back( m_pos );
+        }
+        std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
+        template<typename T>
+        void addPattern() {
+            std::string token = subString();
+            for( size_t i = 0; i < m_escapeChars.size(); ++i )
+                token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
+            m_escapeChars.clear();
+            if( startsWith( token, "exclude:" ) ) {
+                m_exclusion = true;
+                token = token.substr( 8 );
+            }
+            if( !token.empty() ) {
+                Ptr<TestSpec::Pattern> pattern = new T( token );
+                if( m_exclusion )
+                    pattern = new TestSpec::ExcludedPattern( pattern );
+                m_currentFilter.m_patterns.push_back( pattern );
+            }
+            m_exclusion = false;
+            m_mode = None;
+        }
+        void addFilter() {
+            if( !m_currentFilter.m_patterns.empty() ) {
+                m_testSpec.m_filters.push_back( m_currentFilter );
+                m_currentFilter = TestSpec::Filter();
+            }
+        }
+    };
+    inline TestSpec parseTestSpec( std::string const& arg ) {
+        return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
+    }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// #included from: catch_interfaces_config.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    struct Verbosity { enum Level {
+        NoOutput = 0,
+        Quiet,
+        Normal
+    }; };
+
+    struct WarnAbout { enum What {
+        Nothing = 0x00,
+        NoAssertions = 0x01
+    }; };
+
+    struct ShowDurations { enum OrNot {
+        DefaultForReporter,
+        Always,
+        Never
+    }; };
+    struct RunTests { enum InWhatOrder {
+        InDeclarationOrder,
+        InLexicographicalOrder,
+        InRandomOrder
+    }; };
+    struct UseColour { enum YesOrNo {
+        Auto,
+        Yes,
+        No
+    }; };
+    struct WaitForKeypress { enum When {
+        Never,
+        BeforeStart = 1,
+        BeforeExit = 2,
+        BeforeStartAndExit = BeforeStart | BeforeExit
+    }; };
+
+    class TestSpec;
+
+    struct IConfig : IShared {
+
+        virtual ~IConfig();
+
+        virtual bool allowThrows() const = 0;
+        virtual std::ostream& stream() const = 0;
+        virtual std::string name() const = 0;
+        virtual bool includeSuccessfulResults() const = 0;
+        virtual bool shouldDebugBreak() const = 0;
+        virtual bool warnAboutMissingAssertions() const = 0;
+        virtual int abortAfter() const = 0;
+        virtual bool showInvisibles() const = 0;
+        virtual ShowDurations::OrNot showDurations() const = 0;
+        virtual TestSpec const& testSpec() const = 0;
+        virtual RunTests::InWhatOrder runOrder() const = 0;
+        virtual unsigned int rngSeed() const = 0;
+        virtual UseColour::YesOrNo useColour() const = 0;
+        virtual std::vector<std::string> const& getSectionsToRun() const = 0;
+
+    };
+}
+
+// #included from: catch_stream.h
+#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+
+// #included from: catch_streambuf.h
+#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
+
+#include <streambuf>
+
+namespace Catch {
+
+    class StreamBufBase : public std::streambuf {
+    public:
+        virtual ~StreamBufBase() CATCH_NOEXCEPT;
+    };
+}
+
+#include <streambuf>
+#include <ostream>
+#include <fstream>
+#include <memory>
+
+namespace Catch {
+
+    std::ostream& cout();
+    std::ostream& cerr();
+    std::ostream& clog();
+
+    struct IStream {
+        virtual ~IStream() CATCH_NOEXCEPT;
+        virtual std::ostream& stream() const = 0;
+    };
+
+    class FileStream : public IStream {
+        mutable std::ofstream m_ofs;
+    public:
+        FileStream( std::string const& filename );
+        virtual ~FileStream() CATCH_NOEXCEPT;
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
+
+    class CoutStream : public IStream {
+        mutable std::ostream m_os;
+    public:
+        CoutStream();
+        virtual ~CoutStream() CATCH_NOEXCEPT;
+
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
+
+    class DebugOutStream : public IStream {
+        CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
+        mutable std::ostream m_os;
+    public:
+        DebugOutStream();
+        virtual ~DebugOutStream() CATCH_NOEXCEPT;
+
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
+}
+
+#include <memory>
+#include <vector>
+#include <string>
+#include <stdexcept>
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+
+    struct ConfigData {
+
+        ConfigData()
+        :   listTests( false ),
+            listTags( false ),
+            listReporters( false ),
+            listTestNamesOnly( false ),
+            listExtraInfo( false ),
+            showSuccessfulTests( false ),
+            shouldDebugBreak( false ),
+            noThrow( false ),
+            showHelp( false ),
+            showInvisibles( false ),
+            filenamesAsTags( false ),
+            libIdentify( false ),
+            abortAfter( -1 ),
+            rngSeed( 0 ),
+            verbosity( Verbosity::Normal ),
+            warnings( WarnAbout::Nothing ),
+            showDurations( ShowDurations::DefaultForReporter ),
+            runOrder( RunTests::InDeclarationOrder ),
+            useColour( UseColour::Auto ),
+            waitForKeypress( WaitForKeypress::Never )
+        {}
+
+        bool listTests;
+        bool listTags;
+        bool listReporters;
+        bool listTestNamesOnly;
+        bool listExtraInfo;
+
+        bool showSuccessfulTests;
+        bool shouldDebugBreak;
+        bool noThrow;
+        bool showHelp;
+        bool showInvisibles;
+        bool filenamesAsTags;
+        bool libIdentify;
+
+        int abortAfter;
+        unsigned int rngSeed;
+
+        Verbosity::Level verbosity;
+        WarnAbout::What warnings;
+        ShowDurations::OrNot showDurations;
+        RunTests::InWhatOrder runOrder;
+        UseColour::YesOrNo useColour;
+        WaitForKeypress::When waitForKeypress;
+
+        std::string outputFilename;
+        std::string name;
+        std::string processName;
+
+        std::vector<std::string> reporterNames;
+        std::vector<std::string> testsOrTags;
+        std::vector<std::string> sectionsToRun;
+    };
+
+    class Config : public SharedImpl<IConfig> {
+    private:
+        Config( Config const& other );
+        Config& operator = ( Config const& other );
+        virtual void dummy();
+    public:
+
+        Config()
+        {}
+
+        Config( ConfigData const& data )
+        :   m_data( data ),
+            m_stream( openStream() )
+        {
+            if( !data.testsOrTags.empty() ) {
+                TestSpecParser parser( ITagAliasRegistry::get() );
+                for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
+                    parser.parse( data.testsOrTags[i] );
+                m_testSpec = parser.testSpec();
+            }
+        }
+
+        virtual ~Config() {}
+
+        std::string const& getFilename() const {
+            return m_data.outputFilename ;
+        }
+
+        bool listTests() const { return m_data.listTests; }
+        bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
+        bool listTags() const { return m_data.listTags; }
+        bool listReporters() const { return m_data.listReporters; }
+        bool listExtraInfo() const { return m_data.listExtraInfo; }
+
+        std::string getProcessName() const { return m_data.processName; }
+
+        std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
+        std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
+
+        virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; }
+
+        bool showHelp() const { return m_data.showHelp; }
+
+        // IConfig interface
+        virtual bool allowThrows() const CATCH_OVERRIDE                 { return !m_data.noThrow; }
+        virtual std::ostream& stream() const CATCH_OVERRIDE             { return m_stream->stream(); }
+        virtual std::string name() const CATCH_OVERRIDE                 { return m_data.name.empty() ? m_data.processName : m_data.name; }
+        virtual bool includeSuccessfulResults() const CATCH_OVERRIDE    { return m_data.showSuccessfulTests; }
+        virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE  { return m_data.warnings & WarnAbout::NoAssertions; }
+        virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; }
+        virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE   { return m_data.runOrder; }
+        virtual unsigned int rngSeed() const CATCH_OVERRIDE             { return m_data.rngSeed; }
+        virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE     { return m_data.useColour; }
+        virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; }
+        virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; }
+        virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; }
+
+    private:
+
+        IStream const* openStream() {
+            if( m_data.outputFilename.empty() )
+                return new CoutStream();
+            else if( m_data.outputFilename[0] == '%' ) {
+                if( m_data.outputFilename == "%debug" )
+                    return new DebugOutStream();
+                else
+                    throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename );
+            }
+            else
+                return new FileStream( m_data.outputFilename );
+        }
+        ConfigData m_data;
+
+        CATCH_AUTO_PTR( IStream const ) m_stream;
+        TestSpec m_testSpec;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_clara.h
+#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
+
+// Use Catch's value for console width (store Clara's off to the side, if present)
+#ifdef CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
+#undef CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+// Declare Clara inside the Catch namespace
+#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
+// #included from: ../external/clara.h
+
+// Version 0.0.2.4
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
+
+#ifndef STITCH_CLARA_OPEN_NAMESPACE
+#define TWOBLUECUBES_CLARA_H_INCLUDED
+#define STITCH_CLARA_OPEN_NAMESPACE
+#define STITCH_CLARA_CLOSE_NAMESPACE
+#else
+#define STITCH_CLARA_CLOSE_NAMESPACE }
+#endif
+
+#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
+
+// ----------- #included from tbc_text_format.h -----------
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
+#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#define TBC_TEXT_FORMAT_H_INCLUDED
+#endif
+
+#include <string>
+#include <vector>
+#include <sstream>
+#include <algorithm>
+#include <cctype>
+
+// Use optional outer namespace
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+    struct TextAttributes {
+        TextAttributes()
+        :   initialIndent( std::string::npos ),
+            indent( 0 ),
+            width( consoleWidth-1 ),
+            tabChar( '\t' )
+        {}
+
+        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
+        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
+        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
+        TextAttributes& setTabChar( char _value )               { tabChar = _value; return *this; }
+
+        std::size_t initialIndent;  // indent of first line, or npos
+        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
+        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
+        char tabChar;               // If this char is seen the indent is changed to current pos
+    };
+
+    class Text {
+    public:
+        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+        : attr( _attr )
+        {
+            std::string wrappableChars = " [({.,/|\\-";
+            std::size_t indent = _attr.initialIndent != std::string::npos
+                ? _attr.initialIndent
+                : _attr.indent;
+            std::string remainder = _str;
+
+            while( !remainder.empty() ) {
+                if( lines.size() >= 1000 ) {
+                    lines.push_back( "... message truncated due to excessive size" );
+                    return;
+                }
+                std::size_t tabPos = std::string::npos;
+                std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
+                std::size_t pos = remainder.find_first_of( '\n' );
+                if( pos <= width ) {
+                    width = pos;
+                }
+                pos = remainder.find_last_of( _attr.tabChar, width );
+                if( pos != std::string::npos ) {
+                    tabPos = pos;
+                    if( remainder[width] == '\n' )
+                        width--;
+                    remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
+                }
+
+                if( width == remainder.size() ) {
+                    spliceLine( indent, remainder, width );
+                }
+                else if( remainder[width] == '\n' ) {
+                    spliceLine( indent, remainder, width );
+                    if( width <= 1 || remainder.size() != 1 )
+                        remainder = remainder.substr( 1 );
+                    indent = _attr.indent;
+                }
+                else {
+                    pos = remainder.find_last_of( wrappableChars, width );
+                    if( pos != std::string::npos && pos > 0 ) {
+                        spliceLine( indent, remainder, pos );
+                        if( remainder[0] == ' ' )
+                            remainder = remainder.substr( 1 );
+                    }
+                    else {
+                        spliceLine( indent, remainder, width-1 );
+                        lines.back() += "-";
+                    }
+                    if( lines.size() == 1 )
+                        indent = _attr.indent;
+                    if( tabPos != std::string::npos )
+                        indent += tabPos;
+                }
+            }
+        }
+
+        void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
+            lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
+            _remainder = _remainder.substr( _pos );
+        }
+
+        typedef std::vector<std::string>::const_iterator const_iterator;
+
+        const_iterator begin() const { return lines.begin(); }
+        const_iterator end() const { return lines.end(); }
+        std::string const& last() const { return lines.back(); }
+        std::size_t size() const { return lines.size(); }
+        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+
+        friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+                it != itEnd; ++it ) {
+                if( it != _text.begin() )
+                    _stream << "\n";
+                _stream << *it;
+            }
+            return _stream;
+        }
+
+    private:
+        std::string str;
+        TextAttributes attr;
+        std::vector<std::string> lines;
+    };
+
+} // end namespace Tbc
+
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TBC_TEXT_FORMAT_H_INCLUDED
+
+// ----------- end of #include from tbc_text_format.h -----------
+// ........... back in clara.h
+
+#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
+
+// ----------- #included from clara_compilers.h -----------
+
+#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
+// The following features are defined:
+//
+// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported?
+// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
+// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
+// CLARA_CONFIG_CPP11_OVERRIDE : is override supported?
+// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
+
+// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
+
+// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11
+
+#ifdef __clang__
+
+#if __has_feature(cxx_nullptr)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#if __has_feature(cxx_noexcept)
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+// - otherwise more recent versions define __cplusplus >= 201103L
+// and will get picked up below
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#if (_MSC_VER >= 1600)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if defined(__cplusplus) && __cplusplus >= 201103L
+
+#define CLARA_CPP11_OR_GREATER
+
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE)
+#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE
+#endif
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
+#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#endif // __cplusplus >= 201103L
+
+// Now set the actual defines based on the above + anything the user has configured
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_NULLPTR
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_NOEXCEPT
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_GENERATED_METHODS
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_OVERRIDE
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+// noexcept support:
+#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT)
+#define CLARA_NOEXCEPT noexcept
+#  define CLARA_NOEXCEPT_IS(x) noexcept(x)
+#else
+#define CLARA_NOEXCEPT throw()
+#  define CLARA_NOEXCEPT_IS(x)
+#endif
+
+// nullptr support
+#ifdef CLARA_CONFIG_CPP11_NULLPTR
+#define CLARA_NULL nullptr
+#else
+#define CLARA_NULL NULL
+#endif
+
+// override support
+#ifdef CLARA_CONFIG_CPP11_OVERRIDE
+#define CLARA_OVERRIDE override
+#else
+#define CLARA_OVERRIDE
+#endif
+
+// unique_ptr support
+#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR
+#   define CLARA_AUTO_PTR( T ) std::unique_ptr<T>
+#else
+#   define CLARA_AUTO_PTR( T ) std::auto_ptr<T>
+#endif
+
+#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+
+// ----------- end of #include from clara_compilers.h -----------
+// ........... back in clara.h
+
+#include <map>
+#include <stdexcept>
+#include <memory>
+
+#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#define CLARA_PLATFORM_WINDOWS
+#endif
+
+// Use optional outer namespace
+#ifdef STITCH_CLARA_OPEN_NAMESPACE
+STITCH_CLARA_OPEN_NAMESPACE
+#endif
+
+namespace Clara {
+
+    struct UnpositionalTag {};
+
+    extern UnpositionalTag _;
+
+#ifdef CLARA_CONFIG_MAIN
+    UnpositionalTag _;
+#endif
+
+    namespace Detail {
+
+#ifdef CLARA_CONSOLE_WIDTH
+    const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+        using namespace Tbc;
+
+        inline bool startsWith( std::string const& str, std::string const& prefix ) {
+            return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix;
+        }
+
+        template<typename T> struct RemoveConstRef{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T&>{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T const&>{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T const>{ typedef T type; };
+
+        template<typename T>    struct IsBool       { static const bool value = false; };
+        template<>              struct IsBool<bool> { static const bool value = true; };
+
+        template<typename T>
+        void convertInto( std::string const& _source, T& _dest ) {
+            std::stringstream ss;
+            ss << _source;
+            ss >> _dest;
+            if( ss.fail() )
+                throw std::runtime_error( "Unable to convert " + _source + " to destination type" );
+        }
+        inline void convertInto( std::string const& _source, std::string& _dest ) {
+            _dest = _source;
+        }
+        char toLowerCh(char c) {
+            return static_cast<char>( std::tolower( c ) );
+        }
+        inline void convertInto( std::string const& _source, bool& _dest ) {
+            std::string sourceLC = _source;
+            std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh );
+            if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
+                _dest = true;
+            else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
+                _dest = false;
+            else
+                throw std::runtime_error( "Expected a boolean value but did not recognise:\n  '" + _source + "'" );
+        }
+
+        template<typename ConfigT>
+        struct IArgFunction {
+            virtual ~IArgFunction() {}
+#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS
+            IArgFunction()                      = default;
+            IArgFunction( IArgFunction const& ) = default;
+#endif
+            virtual void set( ConfigT& config, std::string const& value ) const = 0;
+            virtual bool takesArg() const = 0;
+            virtual IArgFunction* clone() const = 0;
+        };
+
+        template<typename ConfigT>
+        class BoundArgFunction {
+        public:
+            BoundArgFunction() : functionObj( CLARA_NULL ) {}
+            BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
+            BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {}
+            BoundArgFunction& operator = ( BoundArgFunction const& other ) {
+                IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL;
+                delete functionObj;
+                functionObj = newFunctionObj;
+                return *this;
+            }
+            ~BoundArgFunction() { delete functionObj; }
+
+            void set( ConfigT& config, std::string const& value ) const {
+                functionObj->set( config, value );
+            }
+            bool takesArg() const { return functionObj->takesArg(); }
+
+            bool isSet() const {
+                return functionObj != CLARA_NULL;
+            }
+        private:
+            IArgFunction<ConfigT>* functionObj;
+        };
+
+        template<typename C>
+        struct NullBinder : IArgFunction<C>{
+            virtual void set( C&, std::string const& ) const {}
+            virtual bool takesArg() const { return true; }
+            virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
+        };
+
+        template<typename C, typename M>
+        struct BoundDataMember : IArgFunction<C>{
+            BoundDataMember( M C::* _member ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                convertInto( stringValue, p.*member );
+            }
+            virtual bool takesArg() const { return !IsBool<M>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
+            M C::* member;
+        };
+        template<typename C, typename M>
+        struct BoundUnaryMethod : IArgFunction<C>{
+            BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                typename RemoveConstRef<M>::type value;
+                convertInto( stringValue, value );
+                (p.*member)( value );
+            }
+            virtual bool takesArg() const { return !IsBool<M>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
+            void (C::*member)( M );
+        };
+        template<typename C>
+        struct BoundNullaryMethod : IArgFunction<C>{
+            BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                bool value;
+                convertInto( stringValue, value );
+                if( value )
+                    (p.*member)();
+            }
+            virtual bool takesArg() const { return false; }
+            virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
+            void (C::*member)();
+        };
+
+        template<typename C>
+        struct BoundUnaryFunction : IArgFunction<C>{
+            BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
+            virtual void set( C& obj, std::string const& stringValue ) const {
+                bool value;
+                convertInto( stringValue, value );
+                if( value )
+                    function( obj );
+            }
+            virtual bool takesArg() const { return false; }
+            virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
+            void (*function)( C& );
+        };
+
+        template<typename C, typename T>
+        struct BoundBinaryFunction : IArgFunction<C>{
+            BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {}
+            virtual void set( C& obj, std::string const& stringValue ) const {
+                typename RemoveConstRef<T>::type value;
+                convertInto( stringValue, value );
+                function( obj, value );
+            }
+            virtual bool takesArg() const { return !IsBool<T>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
+            void (*function)( C&, T );
+        };
+
+    } // namespace Detail
+
+    inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
+        std::vector<std::string> args( static_cast<std::size_t>( argc ) );
+        for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i )
+            args[i] = argv[i];
+
+        return args;
+    }
+
+    class Parser {
+        enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional };
+        Mode mode;
+        std::size_t from;
+        bool inQuotes;
+    public:
+
+        struct Token {
+            enum Type { Positional, ShortOpt, LongOpt };
+            Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {}
+            Type type;
+            std::string data;
+        };
+
+        Parser() : mode( None ), from( 0 ), inQuotes( false ){}
+
+        void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
+            const std::string doubleDash = "--";
+            for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
+                parseIntoTokens( args[i], tokens);
+        }
+
+        void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
+            for( std::size_t i = 0; i < arg.size(); ++i ) {
+                char c = arg[i];
+                if( c == '"' )
+                    inQuotes = !inQuotes;
+                mode = handleMode( i, c, arg, tokens );
+            }
+            mode = handleMode( arg.size(), '\0', arg, tokens );
+        }
+        Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+            switch( mode ) {
+                case None: return handleNone( i, c );
+                case MaybeShortOpt: return handleMaybeShortOpt( i, c );
+                case ShortOpt:
+                case LongOpt:
+                case SlashOpt: return handleOpt( i, c, arg, tokens );
+                case Positional: return handlePositional( i, c, arg, tokens );
+                default: throw std::logic_error( "Unknown mode" );
+            }
+        }
+
+        Mode handleNone( std::size_t i, char c ) {
+            if( inQuotes ) {
+                from = i;
+                return Positional;
+            }
+            switch( c ) {
+                case '-': return MaybeShortOpt;
+#ifdef CLARA_PLATFORM_WINDOWS
+                case '/': from = i+1; return SlashOpt;
+#endif
+                default: from = i; return Positional;
+            }
+        }
+        Mode handleMaybeShortOpt( std::size_t i, char c ) {
+            switch( c ) {
+                case '-': from = i+1; return LongOpt;
+                default: from = i; return ShortOpt;
+            }
+        }
+
+        Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+            if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
+                return mode;
+
+            std::string optName = arg.substr( from, i-from );
+            if( mode == ShortOpt )
+                for( std::size_t j = 0; j < optName.size(); ++j )
+                    tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) );
+            else if( mode == SlashOpt && optName.size() == 1 )
+                tokens.push_back( Token( Token::ShortOpt, optName ) );
+            else
+                tokens.push_back( Token( Token::LongOpt, optName ) );
+            return None;
+        }
+        Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+            if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos )
+                return mode;
+
+            std::string data = arg.substr( from, i-from );
+            tokens.push_back( Token( Token::Positional, data ) );
+            return None;
+        }
+    };
+
+    template<typename ConfigT>
+    struct CommonArgProperties {
+        CommonArgProperties() {}
+        CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
+
+        Detail::BoundArgFunction<ConfigT> boundField;
+        std::string description;
+        std::string detail;
+        std::string placeholder; // Only value if boundField takes an arg
+
+        bool takesArg() const {
+            return !placeholder.empty();
+        }
+        void validate() const {
+            if( !boundField.isSet() )
+                throw std::logic_error( "option not bound" );
+        }
+    };
+    struct OptionArgProperties {
+        std::vector<std::string> shortNames;
+        std::string longName;
+
+        bool hasShortName( std::string const& shortName ) const {
+            return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end();
+        }
+        bool hasLongName( std::string const& _longName ) const {
+            return _longName == longName;
+        }
+    };
+    struct PositionalArgProperties {
+        PositionalArgProperties() : position( -1 ) {}
+        int position; // -1 means non-positional (floating)
+
+        bool isFixedPositional() const {
+            return position != -1;
+        }
+    };
+
+    template<typename ConfigT>
+    class CommandLine {
+
+        struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties {
+            Arg() {}
+            Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {}
+
+            using CommonArgProperties<ConfigT>::placeholder; // !TBD
+
+            std::string dbgName() const {
+                if( !longName.empty() )
+                    return "--" + longName;
+                if( !shortNames.empty() )
+                    return "-" + shortNames[0];
+                return "positional args";
+            }
+            std::string commands() const {
+                std::ostringstream oss;
+                bool first = true;
+                std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
+                for(; it != itEnd; ++it ) {
+                    if( first )
+                        first = false;
+                    else
+                        oss << ", ";
+                    oss << "-" << *it;
+                }
+                if( !longName.empty() ) {
+                    if( !first )
+                        oss << ", ";
+                    oss << "--" << longName;
+                }
+                if( !placeholder.empty() )
+                    oss << " <" << placeholder << ">";
+                return oss.str();
+            }
+        };
+
+        typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr;
+
+        friend void addOptName( Arg& arg, std::string const& optName )
+        {
+            if( optName.empty() )
+                return;
+            if( Detail::startsWith( optName, "--" ) ) {
+                if( !arg.longName.empty() )
+                    throw std::logic_error( "Only one long opt may be specified. '"
+                        + arg.longName
+                        + "' already specified, now attempting to add '"
+                        + optName + "'" );
+                arg.longName = optName.substr( 2 );
+            }
+            else if( Detail::startsWith( optName, "-" ) )
+                arg.shortNames.push_back( optName.substr( 1 ) );
+            else
+                throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" );
+        }
+        friend void setPositionalArg( Arg& arg, int position )
+        {
+            arg.position = position;
+        }
+
+        class ArgBuilder {
+        public:
+            ArgBuilder( Arg* arg ) : m_arg( arg ) {}
+
+            // Bind a non-boolean data member (requires placeholder string)
+            template<typename C, typename M>
+            void bind( M C::* field, std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundDataMember<C,M>( field );
+                m_arg->placeholder = placeholder;
+            }
+            // Bind a boolean data member (no placeholder required)
+            template<typename C>
+            void bind( bool C::* field ) {
+                m_arg->boundField = new Detail::BoundDataMember<C,bool>( field );
+            }
+
+            // Bind a method taking a single, non-boolean argument (requires a placeholder string)
+            template<typename C, typename M>
+            void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod );
+                m_arg->placeholder = placeholder;
+            }
+
+            // Bind a method taking a single, boolean argument (no placeholder string required)
+            template<typename C>
+            void bind( void (C::* unaryMethod)( bool ) ) {
+                m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod );
+            }
+
+            // Bind a method that takes no arguments (will be called if opt is present)
+            template<typename C>
+            void bind( void (C::* nullaryMethod)() ) {
+                m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod );
+            }
+
+            // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
+            template<typename C>
+            void bind( void (* unaryFunction)( C& ) ) {
+                m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction );
+            }
+
+            // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
+            template<typename C, typename T>
+            void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction );
+                m_arg->placeholder = placeholder;
+            }
+
+            ArgBuilder& describe( std::string const& description ) {
+                m_arg->description = description;
+                return *this;
+            }
+            ArgBuilder& detail( std::string const& detail ) {
+                m_arg->detail = detail;
+                return *this;
+            }
+
+        protected:
+            Arg* m_arg;
+        };
+
+        class OptBuilder : public ArgBuilder {
+        public:
+            OptBuilder( Arg* arg ) : ArgBuilder( arg ) {}
+            OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {}
+
+            OptBuilder& operator[]( std::string const& optName ) {
+                addOptName( *ArgBuilder::m_arg, optName );
+                return *this;
+            }
+        };
+
+    public:
+
+        CommandLine()
+        :   m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
+            m_highestSpecifiedArgPosition( 0 ),
+            m_throwOnUnrecognisedTokens( false )
+        {}
+        CommandLine( CommandLine const& other )
+        :   m_boundProcessName( other.m_boundProcessName ),
+            m_options ( other.m_options ),
+            m_positionalArgs( other.m_positionalArgs ),
+            m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
+            m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
+        {
+            if( other.m_floatingArg.get() )
+                m_floatingArg.reset( new Arg( *other.m_floatingArg ) );
+        }
+
+        CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
+            m_throwOnUnrecognisedTokens = shouldThrow;
+            return *this;
+        }
+
+        OptBuilder operator[]( std::string const& optName ) {
+            m_options.push_back( Arg() );
+            addOptName( m_options.back(), optName );
+            OptBuilder builder( &m_options.back() );
+            return builder;
+        }
+
+        ArgBuilder operator[]( int position ) {
+            m_positionalArgs.insert( std::make_pair( position, Arg() ) );
+            if( position > m_highestSpecifiedArgPosition )
+                m_highestSpecifiedArgPosition = position;
+            setPositionalArg( m_positionalArgs[position], position );
+            ArgBuilder builder( &m_positionalArgs[position] );
+            return builder;
+        }
+
+        // Invoke this with the _ instance
+        ArgBuilder operator[]( UnpositionalTag ) {
+            if( m_floatingArg.get() )
+                throw std::logic_error( "Only one unpositional argument can be added" );
+            m_floatingArg.reset( new Arg() );
+            ArgBuilder builder( m_floatingArg.get() );
+            return builder;
+        }
+
+        template<typename C, typename M>
+        void bindProcessName( M C::* field ) {
+            m_boundProcessName = new Detail::BoundDataMember<C,M>( field );
+        }
+        template<typename C, typename M>
+        void bindProcessName( void (C::*_unaryMethod)( M ) ) {
+            m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod );
+        }
+
+        void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const {
+            typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
+            std::size_t maxWidth = 0;
+            for( it = itBegin; it != itEnd; ++it )
+                maxWidth = (std::max)( maxWidth, it->commands().size() );
+
+            for( it = itBegin; it != itEnd; ++it ) {
+                Detail::Text usage( it->commands(), Detail::TextAttributes()
+                                                        .setWidth( maxWidth+indent )
+                                                        .setIndent( indent ) );
+                Detail::Text desc( it->description, Detail::TextAttributes()
+                                                        .setWidth( width - maxWidth - 3 ) );
+
+                for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
+                    std::string usageCol = i < usage.size() ? usage[i] : "";
+                    os << usageCol;
+
+                    if( i < desc.size() && !desc[i].empty() )
+                        os  << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' )
+                            << desc[i];
+                    os << "\n";
+                }
+            }
+        }
+        std::string optUsage() const {
+            std::ostringstream oss;
+            optUsage( oss );
+            return oss.str();
+        }
+
+        void argSynopsis( std::ostream& os ) const {
+            for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) {
+                if( i > 1 )
+                    os << " ";
+                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i );
+                if( it != m_positionalArgs.end() )
+                    os << "<" << it->second.placeholder << ">";
+                else if( m_floatingArg.get() )
+                    os << "<" << m_floatingArg->placeholder << ">";
+                else
+                    throw std::logic_error( "non consecutive positional arguments with no floating args" );
+            }
+            // !TBD No indication of mandatory args
+            if( m_floatingArg.get() ) {
+                if( m_highestSpecifiedArgPosition > 1 )
+                    os << " ";
+                os << "[<" << m_floatingArg->placeholder << "> ...]";
+            }
+        }
+        std::string argSynopsis() const {
+            std::ostringstream oss;
+            argSynopsis( oss );
+            return oss.str();
+        }
+
+        void usage( std::ostream& os, std::string const& procName ) const {
+            validate();
+            os << "usage:\n  " << procName << " ";
+            argSynopsis( os );
+            if( !m_options.empty() ) {
+                os << " [options]\n\nwhere options are: \n";
+                optUsage( os, 2 );
+            }
+            os << "\n";
+        }
+        std::string usage( std::string const& procName ) const {
+            std::ostringstream oss;
+            usage( oss, procName );
+            return oss.str();
+        }
+
+        ConfigT parse( std::vector<std::string> const& args ) const {
+            ConfigT config;
+            parseInto( args, config );
+            return config;
+        }
+
+        std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
+            std::string processName = args.empty() ? std::string() : args[0];
+            std::size_t lastSlash = processName.find_last_of( "/\\" );
+            if( lastSlash != std::string::npos )
+                processName = processName.substr( lastSlash+1 );
+            m_boundProcessName.set( config, processName );
+            std::vector<Parser::Token> tokens;
+            Parser parser;
+            parser.parseIntoTokens( args, tokens );
+            return populate( tokens, config );
+        }
+
+        std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            validate();
+            std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config );
+            unusedTokens = populateFixedArgs( unusedTokens, config );
+            unusedTokens = populateFloatingArgs( unusedTokens, config );
+            return unusedTokens;
+        }
+
+        std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            std::vector<Parser::Token> unusedTokens;
+            std::vector<std::string> errors;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
+                for(; it != itEnd; ++it ) {
+                    Arg const& arg = *it;
+
+                    try {
+                        if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) ||
+                            ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
+                            if( arg.takesArg() ) {
+                                if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
+                                    errors.push_back( "Expected argument to option: " + token.data );
+                                else
+                                    arg.boundField.set( config, tokens[++i].data );
+                            }
+                            else {
+                                arg.boundField.set( config, "true" );
+                            }
+                            break;
+                        }
+                    }
+                    catch( std::exception& ex ) {
+                        errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
+                    }
+                }
+                if( it == itEnd ) {
+                    if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
+                        unusedTokens.push_back( token );
+                    else if( errors.empty() && m_throwOnUnrecognisedTokens )
+                        errors.push_back( "unrecognised option: " + token.data );
+                }
+            }
+            if( !errors.empty() ) {
+                std::ostringstream oss;
+                for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
+                        it != itEnd;
+                        ++it ) {
+                    if( it != errors.begin() )
+                        oss << "\n";
+                    oss << *it;
+                }
+                throw std::runtime_error( oss.str() );
+            }
+            return unusedTokens;
+        }
+        std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            std::vector<Parser::Token> unusedTokens;
+            int position = 1;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position );
+                if( it != m_positionalArgs.end() )
+                    it->second.boundField.set( config, token.data );
+                else
+                    unusedTokens.push_back( token );
+                if( token.type == Parser::Token::Positional )
+                    position++;
+            }
+            return unusedTokens;
+        }
+        std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            if( !m_floatingArg.get() )
+                return tokens;
+            std::vector<Parser::Token> unusedTokens;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                if( token.type == Parser::Token::Positional )
+                    m_floatingArg->boundField.set( config, token.data );
+                else
+                    unusedTokens.push_back( token );
+            }
+            return unusedTokens;
+        }
+
+        void validate() const
+        {
+            if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() )
+                throw std::logic_error( "No options or arguments specified" );
+
+            for( typename std::vector<Arg>::const_iterator  it = m_options.begin(),
+                                                            itEnd = m_options.end();
+                    it != itEnd; ++it )
+                it->validate();
+        }
+
+    private:
+        Detail::BoundArgFunction<ConfigT> m_boundProcessName;
+        std::vector<Arg> m_options;
+        std::map<int, Arg> m_positionalArgs;
+        ArgAutoPtr m_floatingArg;
+        int m_highestSpecifiedArgPosition;
+        bool m_throwOnUnrecognisedTokens;
+    };
+
+} // end namespace Clara
+
+STITCH_CLARA_CLOSE_NAMESPACE
+#undef STITCH_CLARA_OPEN_NAMESPACE
+#undef STITCH_CLARA_CLOSE_NAMESPACE
+
+#endif // TWOBLUECUBES_CLARA_H_INCLUDED
+#undef STITCH_CLARA_OPEN_NAMESPACE
+
+// Restore Clara's value for console width, if present
+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+#include <fstream>
+#include <ctime>
+
+namespace Catch {
+
+    inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
+    inline void abortAfterX( ConfigData& config, int x ) {
+        if( x < 1 )
+            throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
+        config.abortAfter = x;
+    }
+    inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
+    inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); }
+    inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
+
+    inline void addWarning( ConfigData& config, std::string const& _warning ) {
+        if( _warning == "NoAssertions" )
+            config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
+        else
+            throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' );
+    }
+    inline void setOrder( ConfigData& config, std::string const& order ) {
+        if( startsWith( "declared", order ) )
+            config.runOrder = RunTests::InDeclarationOrder;
+        else if( startsWith( "lexical", order ) )
+            config.runOrder = RunTests::InLexicographicalOrder;
+        else if( startsWith( "random", order ) )
+            config.runOrder = RunTests::InRandomOrder;
+        else
+            throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' );
+    }
+    inline void setRngSeed( ConfigData& config, std::string const& seed ) {
+        if( seed == "time" ) {
+            config.rngSeed = static_cast<unsigned int>( std::time(0) );
+        }
+        else {
+            std::stringstream ss;
+            ss << seed;
+            ss >> config.rngSeed;
+            if( ss.fail() )
+                throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" );
+        }
+    }
+    inline void setVerbosity( ConfigData& config, int level ) {
+        // !TBD: accept strings?
+        config.verbosity = static_cast<Verbosity::Level>( level );
+    }
+    inline void setShowDurations( ConfigData& config, bool _showDurations ) {
+        config.showDurations = _showDurations
+            ? ShowDurations::Always
+            : ShowDurations::Never;
+    }
+    inline void setUseColour( ConfigData& config, std::string const& value ) {
+        std::string mode = toLower( value );
+
+        if( mode == "yes" )
+            config.useColour = UseColour::Yes;
+        else if( mode == "no" )
+            config.useColour = UseColour::No;
+        else if( mode == "auto" )
+            config.useColour = UseColour::Auto;
+        else
+            throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
+    }
+    inline void setWaitForKeypress( ConfigData& config, std::string const& keypress ) {
+        std::string keypressLc = toLower( keypress );
+        if( keypressLc == "start" )
+            config.waitForKeypress = WaitForKeypress::BeforeStart;
+        else if( keypressLc == "exit" )
+            config.waitForKeypress = WaitForKeypress::BeforeExit;
+        else if( keypressLc == "both" )
+            config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
+        else
+            throw std::runtime_error( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
+    };
+
+    inline void forceColour( ConfigData& config ) {
+        config.useColour = UseColour::Yes;
+    }
+    inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
+        std::ifstream f( _filename.c_str() );
+        if( !f.is_open() )
+            throw std::domain_error( "Unable to load input file: " + _filename );
+
+        std::string line;
+        while( std::getline( f, line ) ) {
+            line = trim(line);
+            if( !line.empty() && !startsWith( line, '#' ) ) {
+                if( !startsWith( line, '"' ) )
+                    line = '"' + line + '"';
+                addTestOrTags( config, line + ',' );
+            }
+        }
+    }
+
+    inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
+
+        using namespace Clara;
+        CommandLine<ConfigData> cli;
+
+        cli.bindProcessName( &ConfigData::processName );
+
+        cli["-?"]["-h"]["--help"]
+            .describe( "display usage information" )
+            .bind( &ConfigData::showHelp );
+
+        cli["-l"]["--list-tests"]
+            .describe( "list all/matching test cases" )
+            .bind( &ConfigData::listTests );
+
+        cli["-t"]["--list-tags"]
+            .describe( "list all/matching tags" )
+            .bind( &ConfigData::listTags );
+
+        cli["-s"]["--success"]
+            .describe( "include successful tests in output" )
+            .bind( &ConfigData::showSuccessfulTests );
+
+        cli["-b"]["--break"]
+            .describe( "break into debugger on failure" )
+            .bind( &ConfigData::shouldDebugBreak );
+
+        cli["-e"]["--nothrow"]
+            .describe( "skip exception tests" )
+            .bind( &ConfigData::noThrow );
+
+        cli["-i"]["--invisibles"]
+            .describe( "show invisibles (tabs, newlines)" )
+            .bind( &ConfigData::showInvisibles );
+
+        cli["-o"]["--out"]
+            .describe( "output filename" )
+            .bind( &ConfigData::outputFilename, "filename" );
+
+        cli["-r"]["--reporter"]
+//            .placeholder( "name[:filename]" )
+            .describe( "reporter to use (defaults to console)" )
+            .bind( &addReporterName, "name" );
+
+        cli["-n"]["--name"]
+            .describe( "suite name" )
+            .bind( &ConfigData::name, "name" );
+
+        cli["-a"]["--abort"]
+            .describe( "abort at first failure" )
+            .bind( &abortAfterFirst );
+
+        cli["-x"]["--abortx"]
+            .describe( "abort after x failures" )
+            .bind( &abortAfterX, "no. failures" );
+
+        cli["-w"]["--warn"]
+            .describe( "enable warnings" )
+            .bind( &addWarning, "warning name" );
+
+// - needs updating if reinstated
+//        cli.into( &setVerbosity )
+//            .describe( "level of verbosity (0=no output)" )
+//            .shortOpt( "v")
+//            .longOpt( "verbosity" )
+//            .placeholder( "level" );
+
+        cli[_]
+            .describe( "which test or tests to use" )
+            .bind( &addTestOrTags, "test name, pattern or tags" );
+
+        cli["-d"]["--durations"]
+            .describe( "show test durations" )
+            .bind( &setShowDurations, "yes|no" );
+
+        cli["-f"]["--input-file"]
+            .describe( "load test names to run from a file" )
+            .bind( &loadTestNamesFromFile, "filename" );
+
+        cli["-#"]["--filenames-as-tags"]
+            .describe( "adds a tag for the filename" )
+            .bind( &ConfigData::filenamesAsTags );
+
+        cli["-c"]["--section"]
+                .describe( "specify section to run" )
+                .bind( &addSectionToRun, "section name" );
+
+        // Less common commands which don't have a short form
+        cli["--list-test-names-only"]
+            .describe( "list all/matching test cases names only" )
+            .bind( &ConfigData::listTestNamesOnly );
+
+        cli["--list-extra-info"]
+            .describe( "list all/matching test cases with more info" )
+            .bind( &ConfigData::listExtraInfo );
+
+        cli["--list-reporters"]
+            .describe( "list all reporters" )
+            .bind( &ConfigData::listReporters );
+
+        cli["--order"]
+            .describe( "test case order (defaults to decl)" )
+            .bind( &setOrder, "decl|lex|rand" );
+
+        cli["--rng-seed"]
+            .describe( "set a specific seed for random numbers" )
+            .bind( &setRngSeed, "'time'|number" );
+
+        cli["--force-colour"]
+            .describe( "force colourised output (deprecated)" )
+            .bind( &forceColour );
+
+        cli["--use-colour"]
+            .describe( "should output be colourised" )
+            .bind( &setUseColour, "yes|no" );
+
+        cli["--libidentify"]
+            .describe( "report name and version according to libidentify standard" )
+            .bind( &ConfigData::libIdentify );
+
+        cli["--wait-for-keypress"]
+                .describe( "waits for a keypress before exiting" )
+                .bind( &setWaitForKeypress, "start|exit|both" );
+
+        return cli;
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_list.hpp
+#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
+
+// #included from: catch_text.h
+#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
+
+#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
+// #included from: ../external/tbc_text_format.h
+// Only use header guard if we are not using an outer namespace
+#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+#  ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#   define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#  endif
+# else
+#  define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+# endif
+#endif
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#include <string>
+#include <vector>
+#include <sstream>
+
+// Use optional outer namespace
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+    struct TextAttributes {
+        TextAttributes()
+        :   initialIndent( std::string::npos ),
+            indent( 0 ),
+            width( consoleWidth-1 )
+        {}
+
+        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
+        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
+        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
+
+        std::size_t initialIndent;  // indent of first line, or npos
+        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
+        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
+    };
+
+    class Text {
+    public:
+        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+        : attr( _attr )
+        {
+            const std::string wrappableBeforeChars = "[({<\t";
+            const std::string wrappableAfterChars = "])}>-,./|\\";
+            const std::string wrappableInsteadOfChars = " \n\r";
+            std::string indent = _attr.initialIndent != std::string::npos
+                ? std::string( _attr.initialIndent, ' ' )
+                : std::string( _attr.indent, ' ' );
+
+            typedef std::string::const_iterator iterator;
+            iterator it = _str.begin();
+            const iterator strEnd = _str.end();
+
+            while( it != strEnd ) {
+
+                if( lines.size() >= 1000 ) {
+                    lines.push_back( "... message truncated due to excessive size" );
+                    return;
+                }
+
+                std::string suffix;
+                std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) );
+                iterator itEnd = it+width;
+                iterator itNext = _str.end();
+
+                iterator itNewLine = std::find( it, itEnd, '\n' );
+                if( itNewLine != itEnd )
+                    itEnd = itNewLine;
+
+                if( itEnd != strEnd  ) {
+                    bool foundWrapPoint = false;
+                    iterator findIt = itEnd;
+                    do {
+                        if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) {
+                            itEnd = findIt+1;
+                            itNext = findIt+1;
+                            foundWrapPoint = true;
+                        }
+                        else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) {
+                            itEnd = findIt;
+                            itNext = findIt;
+                            foundWrapPoint = true;
+                        }
+                        else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) {
+                            itNext = findIt+1;
+                            itEnd = findIt;
+                            foundWrapPoint = true;
+                        }
+                        if( findIt == it )
+                            break;
+                        else
+                            --findIt;
+                    }
+                    while( !foundWrapPoint );
+
+                    if( !foundWrapPoint ) {
+                        // No good wrap char, so we'll break mid word and add a hyphen
+                        --itEnd;
+                        itNext = itEnd;
+                        suffix = "-";
+                    }
+                    else {
+                        while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos )
+                            --itEnd;
+                    }
+                }
+                lines.push_back( indent + std::string( it, itEnd ) + suffix );
+
+                if( indent.size() != _attr.indent )
+                    indent = std::string( _attr.indent, ' ' );
+                it = itNext;
+            }
+        }
+
+        typedef std::vector<std::string>::const_iterator const_iterator;
+
+        const_iterator begin() const { return lines.begin(); }
+        const_iterator end() const { return lines.end(); }
+        std::string const& last() const { return lines.back(); }
+        std::size_t size() const { return lines.size(); }
+        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+
+        inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+                it != itEnd; ++it ) {
+                if( it != _text.begin() )
+                    _stream << "\n";
+                _stream << *it;
+            }
+            return _stream;
+        }
+
+    private:
+        std::string str;
+        TextAttributes attr;
+        std::vector<std::string> lines;
+    };
+
+} // end namespace Tbc
+
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+
+namespace Catch {
+    using Tbc::Text;
+    using Tbc::TextAttributes;
+}
+
+// #included from: catch_console_colour.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+
+namespace Catch {
+
+    struct Colour {
+        enum Code {
+            None = 0,
+
+            White,
+            Red,
+            Green,
+            Blue,
+            Cyan,
+            Yellow,
+            Grey,
+
+            Bright = 0x10,
+
+            BrightRed = Bright | Red,
+            BrightGreen = Bright | Green,
+            LightGrey = Bright | Grey,
+            BrightWhite = Bright | White,
+
+            // By intention
+            FileName = LightGrey,
+            Warning = Yellow,
+            ResultError = BrightRed,
+            ResultSuccess = BrightGreen,
+            ResultExpectedFailure = Warning,
+
+            Error = BrightRed,
+            Success = Green,
+
+            OriginalExpression = Cyan,
+            ReconstructedExpression = Yellow,
+
+            SecondaryText = LightGrey,
+            Headers = White
+        };
+
+        // Use constructed object for RAII guard
+        Colour( Code _colourCode );
+        Colour( Colour const& other );
+        ~Colour();
+
+        // Use static method for one-shot changes
+        static void use( Code _colourCode );
+
+    private:
+        bool m_moved;
+    };
+
+    inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; }
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_reporter.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
+
+#include <string>
+#include <ostream>
+#include <map>
+
+namespace Catch
+{
+    struct ReporterConfig {
+        explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig )
+        :   m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
+
+        ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream )
+        :   m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
+
+        std::ostream& stream() const    { return *m_stream; }
+        Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
+
+    private:
+        std::ostream* m_stream;
+        Ptr<IConfig const> m_fullConfig;
+    };
+
+    struct ReporterPreferences {
+        ReporterPreferences()
+        : shouldRedirectStdOut( false )
+        {}
+
+        bool shouldRedirectStdOut;
+    };
+
+    template<typename T>
+    struct LazyStat : Option<T> {
+        LazyStat() : used( false ) {}
+        LazyStat& operator=( T const& _value ) {
+            Option<T>::operator=( _value );
+            used = false;
+            return *this;
+        }
+        void reset() {
+            Option<T>::reset();
+            used = false;
+        }
+        bool used;
+    };
+
+    struct TestRunInfo {
+        TestRunInfo( std::string const& _name ) : name( _name ) {}
+        std::string name;
+    };
+    struct GroupInfo {
+        GroupInfo(  std::string const& _name,
+                    std::size_t _groupIndex,
+                    std::size_t _groupsCount )
+        :   name( _name ),
+            groupIndex( _groupIndex ),
+            groupsCounts( _groupsCount )
+        {}
+
+        std::string name;
+        std::size_t groupIndex;
+        std::size_t groupsCounts;
+    };
+
+    struct AssertionStats {
+        AssertionStats( AssertionResult const& _assertionResult,
+                        std::vector<MessageInfo> const& _infoMessages,
+                        Totals const& _totals )
+        :   assertionResult( _assertionResult ),
+            infoMessages( _infoMessages ),
+            totals( _totals )
+        {
+            if( assertionResult.hasMessage() ) {
+                // Copy message into messages list.
+                // !TBD This should have been done earlier, somewhere
+                MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
+                builder << assertionResult.getMessage();
+                builder.m_info.message = builder.m_stream.str();
+
+                infoMessages.push_back( builder.m_info );
+            }
+        }
+        virtual ~AssertionStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        AssertionStats( AssertionStats const& )              = default;
+        AssertionStats( AssertionStats && )                  = default;
+        AssertionStats& operator = ( AssertionStats const& ) = default;
+        AssertionStats& operator = ( AssertionStats && )     = default;
+#  endif
+
+        AssertionResult assertionResult;
+        std::vector<MessageInfo> infoMessages;
+        Totals totals;
+    };
+
+    struct SectionStats {
+        SectionStats(   SectionInfo const& _sectionInfo,
+                        Counts const& _assertions,
+                        double _durationInSeconds,
+                        bool _missingAssertions )
+        :   sectionInfo( _sectionInfo ),
+            assertions( _assertions ),
+            durationInSeconds( _durationInSeconds ),
+            missingAssertions( _missingAssertions )
+        {}
+        virtual ~SectionStats();
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        SectionStats( SectionStats const& )              = default;
+        SectionStats( SectionStats && )                  = default;
+        SectionStats& operator = ( SectionStats const& ) = default;
+        SectionStats& operator = ( SectionStats && )     = default;
+#  endif
+
+        SectionInfo sectionInfo;
+        Counts assertions;
+        double durationInSeconds;
+        bool missingAssertions;
+    };
+
+    struct TestCaseStats {
+        TestCaseStats(  TestCaseInfo const& _testInfo,
+                        Totals const& _totals,
+                        std::string const& _stdOut,
+                        std::string const& _stdErr,
+                        bool _aborting )
+        : testInfo( _testInfo ),
+            totals( _totals ),
+            stdOut( _stdOut ),
+            stdErr( _stdErr ),
+            aborting( _aborting )
+        {}
+        virtual ~TestCaseStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestCaseStats( TestCaseStats const& )              = default;
+        TestCaseStats( TestCaseStats && )                  = default;
+        TestCaseStats& operator = ( TestCaseStats const& ) = default;
+        TestCaseStats& operator = ( TestCaseStats && )     = default;
+#  endif
+
+        TestCaseInfo testInfo;
+        Totals totals;
+        std::string stdOut;
+        std::string stdErr;
+        bool aborting;
+    };
+
+    struct TestGroupStats {
+        TestGroupStats( GroupInfo const& _groupInfo,
+                        Totals const& _totals,
+                        bool _aborting )
+        :   groupInfo( _groupInfo ),
+            totals( _totals ),
+            aborting( _aborting )
+        {}
+        TestGroupStats( GroupInfo const& _groupInfo )
+        :   groupInfo( _groupInfo ),
+            aborting( false )
+        {}
+        virtual ~TestGroupStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestGroupStats( TestGroupStats const& )              = default;
+        TestGroupStats( TestGroupStats && )                  = default;
+        TestGroupStats& operator = ( TestGroupStats const& ) = default;
+        TestGroupStats& operator = ( TestGroupStats && )     = default;
+#  endif
+
+        GroupInfo groupInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+    struct TestRunStats {
+        TestRunStats(   TestRunInfo const& _runInfo,
+                        Totals const& _totals,
+                        bool _aborting )
+        :   runInfo( _runInfo ),
+            totals( _totals ),
+            aborting( _aborting )
+        {}
+        virtual ~TestRunStats();
+
+#  ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestRunStats( TestRunStats const& _other )
+        :   runInfo( _other.runInfo ),
+            totals( _other.totals ),
+            aborting( _other.aborting )
+        {}
+#  else
+        TestRunStats( TestRunStats const& )              = default;
+        TestRunStats( TestRunStats && )                  = default;
+        TestRunStats& operator = ( TestRunStats const& ) = default;
+        TestRunStats& operator = ( TestRunStats && )     = default;
+#  endif
+
+        TestRunInfo runInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+    class MultipleReporters;
+
+    struct IStreamingReporter : IShared {
+        virtual ~IStreamingReporter();
+
+        // Implementing class must also provide the following static method:
+        // static std::string getDescription();
+
+        virtual ReporterPreferences getPreferences() const = 0;
+
+        virtual void noMatchingTestCases( std::string const& spec ) = 0;
+
+        virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
+
+        virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
+
+        virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
+
+        // The return value indicates if the messages buffer should be cleared:
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
+
+        virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
+        virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
+
+        virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
+
+        virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
+    };
+
+    struct IReporterFactory : IShared {
+        virtual ~IReporterFactory();
+        virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
+        virtual std::string getDescription() const = 0;
+    };
+
+    struct IReporterRegistry {
+        typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap;
+        typedef std::vector<Ptr<IReporterFactory> > Listeners;
+
+        virtual ~IReporterRegistry();
+        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0;
+        virtual FactoryMap const& getFactories() const = 0;
+        virtual Listeners const& getListeners() const = 0;
+    };
+
+    Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter );
+
+}
+
+#include <limits>
+#include <algorithm>
+
+namespace Catch {
+
+    inline std::size_t listTests( Config const& config ) {
+
+        TestSpec testSpec = config.testSpec();
+        if( config.testSpec().hasFilters() )
+            Catch::cout() << "Matching test cases:\n";
+        else {
+            Catch::cout() << "All available test cases:\n";
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        }
+
+        std::size_t matchedTests = 0;
+        TextAttributes nameAttr, descAttr, tagsAttr;
+        nameAttr.setInitialIndent( 2 ).setIndent( 4 );
+        descAttr.setIndent( 4 );
+        tagsAttr.setIndent( 6 );
+
+        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            matchedTests++;
+            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+            Colour::Code colour = testCaseInfo.isHidden()
+                ? Colour::SecondaryText
+                : Colour::None;
+            Colour colourGuard( colour );
+
+            Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
+            if( config.listExtraInfo() ) {
+                Catch::cout() << "    " << testCaseInfo.lineInfo << std::endl;
+                std::string description = testCaseInfo.description;
+                if( description.empty() )
+                    description = "(NO DESCRIPTION)";
+                Catch::cout() << Text( description, descAttr ) << std::endl;
+            }
+            if( !testCaseInfo.tags.empty() )
+                Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
+        }
+
+        if( !config.testSpec().hasFilters() )
+            Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
+        else
+            Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
+        return matchedTests;
+    }
+
+    inline std::size_t listTestsNamesOnly( Config const& config ) {
+        TestSpec testSpec = config.testSpec();
+        if( !config.testSpec().hasFilters() )
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        std::size_t matchedTests = 0;
+        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            matchedTests++;
+            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+            if( startsWith( testCaseInfo.name, '#' ) )
+               Catch::cout() << '"' << testCaseInfo.name << '"';
+            else
+               Catch::cout() << testCaseInfo.name;
+            if ( config.listExtraInfo() )
+                Catch::cout() << "\t@" << testCaseInfo.lineInfo;
+            Catch::cout() << std::endl;
+        }
+        return matchedTests;
+    }
+
+    struct TagInfo {
+        TagInfo() : count ( 0 ) {}
+        void add( std::string const& spelling ) {
+            ++count;
+            spellings.insert( spelling );
+        }
+        std::string all() const {
+            std::string out;
+            for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
+                        it != itEnd;
+                        ++it )
+                out += "[" + *it + "]";
+            return out;
+        }
+        std::set<std::string> spellings;
+        std::size_t count;
+    };
+
+    inline std::size_t listTags( Config const& config ) {
+        TestSpec testSpec = config.testSpec();
+        if( config.testSpec().hasFilters() )
+            Catch::cout() << "Tags for matching test cases:\n";
+        else {
+            Catch::cout() << "All available tags:\n";
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        }
+
+        std::map<std::string, TagInfo> tagCounts;
+
+        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            for( std::set<std::string>::const_iterator  tagIt = it->getTestCaseInfo().tags.begin(),
+                                                        tagItEnd = it->getTestCaseInfo().tags.end();
+                    tagIt != tagItEnd;
+                    ++tagIt ) {
+                std::string tagName = *tagIt;
+                std::string lcaseTagName = toLower( tagName );
+                std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName );
+                if( countIt == tagCounts.end() )
+                    countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
+                countIt->second.add( tagName );
+            }
+        }
+
+        for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
+                                                            countItEnd = tagCounts.end();
+                countIt != countItEnd;
+                ++countIt ) {
+            std::ostringstream oss;
+            oss << "  " << std::setw(2) << countIt->second.count << "  ";
+            Text wrapper( countIt->second.all(), TextAttributes()
+                                                    .setInitialIndent( 0 )
+                                                    .setIndent( oss.str().size() )
+                                                    .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
+            Catch::cout() << oss.str() << wrapper << '\n';
+        }
+        Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
+        return tagCounts.size();
+    }
+
+    inline std::size_t listReporters( Config const& /*config*/ ) {
+        Catch::cout() << "Available reporters:\n";
+        IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+        IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
+        std::size_t maxNameLen = 0;
+        for(it = itBegin; it != itEnd; ++it )
+            maxNameLen = (std::max)( maxNameLen, it->first.size() );
+
+        for(it = itBegin; it != itEnd; ++it ) {
+            Text wrapper( it->second->getDescription(), TextAttributes()
+                                                        .setInitialIndent( 0 )
+                                                        .setIndent( 7+maxNameLen )
+                                                        .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
+            Catch::cout() << "  "
+                    << it->first
+                    << ':'
+                    << std::string( maxNameLen - it->first.size() + 2, ' ' )
+                    << wrapper << '\n';
+        }
+        Catch::cout() << std::endl;
+        return factories.size();
+    }
+
+    inline Option<std::size_t> list( Config const& config ) {
+        Option<std::size_t> listedCount;
+        if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) )
+            listedCount = listedCount.valueOr(0) + listTests( config );
+        if( config.listTestNamesOnly() )
+            listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
+        if( config.listTags() )
+            listedCount = listedCount.valueOr(0) + listTags( config );
+        if( config.listReporters() )
+            listedCount = listedCount.valueOr(0) + listReporters( config );
+        return listedCount;
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_run_context.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
+
+// #included from: catch_test_case_tracker.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+
+#include <algorithm>
+#include <string>
+#include <assert.h>
+#include <vector>
+#include <stdexcept>
+
+CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
+
+namespace Catch {
+namespace TestCaseTracking {
+
+    struct NameAndLocation {
+        std::string name;
+        SourceLineInfo location;
+
+        NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
+        :   name( _name ),
+            location( _location )
+        {}
+    };
+
+    struct ITracker : SharedImpl<> {
+        virtual ~ITracker();
+
+        // static queries
+        virtual NameAndLocation const& nameAndLocation() const = 0;
+
+        // dynamic queries
+        virtual bool isComplete() const = 0; // Successfully completed or failed
+        virtual bool isSuccessfullyCompleted() const = 0;
+        virtual bool isOpen() const = 0; // Started but not complete
+        virtual bool hasChildren() const = 0;
+
+        virtual ITracker& parent() = 0;
+
+        // actions
+        virtual void close() = 0; // Successfully complete
+        virtual void fail() = 0;
+        virtual void markAsNeedingAnotherRun() = 0;
+
+        virtual void addChild( Ptr<ITracker> const& child ) = 0;
+        virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0;
+        virtual void openChild() = 0;
+
+        // Debug/ checking
+        virtual bool isSectionTracker() const = 0;
+        virtual bool isIndexTracker() const = 0;
+    };
+
+    class  TrackerContext {
+
+        enum RunState {
+            NotStarted,
+            Executing,
+            CompletedCycle
+        };
+
+        Ptr<ITracker> m_rootTracker;
+        ITracker* m_currentTracker;
+        RunState m_runState;
+
+    public:
+
+        static TrackerContext& instance() {
+            static TrackerContext s_instance;
+            return s_instance;
+        }
+
+        TrackerContext()
+        :   m_currentTracker( CATCH_NULL ),
+            m_runState( NotStarted )
+        {}
+
+        ITracker& startRun();
+
+        void endRun() {
+            m_rootTracker.reset();
+            m_currentTracker = CATCH_NULL;
+            m_runState = NotStarted;
+        }
+
+        void startCycle() {
+            m_currentTracker = m_rootTracker.get();
+            m_runState = Executing;
+        }
+        void completeCycle() {
+            m_runState = CompletedCycle;
+        }
+
+        bool completedCycle() const {
+            return m_runState == CompletedCycle;
+        }
+        ITracker& currentTracker() {
+            return *m_currentTracker;
+        }
+        void setCurrentTracker( ITracker* tracker ) {
+            m_currentTracker = tracker;
+        }
+    };
+
+    class TrackerBase : public ITracker {
+    protected:
+        enum CycleState {
+            NotStarted,
+            Executing,
+            ExecutingChildren,
+            NeedsAnotherRun,
+            CompletedSuccessfully,
+            Failed
+        };
+        class TrackerHasName {
+            NameAndLocation m_nameAndLocation;
+        public:
+            TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
+            bool operator ()( Ptr<ITracker> const& tracker ) {
+                return
+                    tracker->nameAndLocation().name == m_nameAndLocation.name &&
+                    tracker->nameAndLocation().location == m_nameAndLocation.location;
+            }
+        };
+        typedef std::vector<Ptr<ITracker> > Children;
+        NameAndLocation m_nameAndLocation;
+        TrackerContext& m_ctx;
+        ITracker* m_parent;
+        Children m_children;
+        CycleState m_runState;
+    public:
+        TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+        :   m_nameAndLocation( nameAndLocation ),
+            m_ctx( ctx ),
+            m_parent( parent ),
+            m_runState( NotStarted )
+        {}
+        virtual ~TrackerBase();
+
+        virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE {
+            return m_nameAndLocation;
+        }
+        virtual bool isComplete() const CATCH_OVERRIDE {
+            return m_runState == CompletedSuccessfully || m_runState == Failed;
+        }
+        virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE {
+            return m_runState == CompletedSuccessfully;
+        }
+        virtual bool isOpen() const CATCH_OVERRIDE {
+            return m_runState != NotStarted && !isComplete();
+        }
+        virtual bool hasChildren() const CATCH_OVERRIDE {
+            return !m_children.empty();
+        }
+
+        virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE {
+            m_children.push_back( child );
+        }
+
+        virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE {
+            Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
+            return( it != m_children.end() )
+                ? it->get()
+                : CATCH_NULL;
+        }
+        virtual ITracker& parent() CATCH_OVERRIDE {
+            assert( m_parent ); // Should always be non-null except for root
+            return *m_parent;
+        }
+
+        virtual void openChild() CATCH_OVERRIDE {
+            if( m_runState != ExecutingChildren ) {
+                m_runState = ExecutingChildren;
+                if( m_parent )
+                    m_parent->openChild();
+            }
+        }
+
+        virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
+        virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
+
+        void open() {
+            m_runState = Executing;
+            moveToThis();
+            if( m_parent )
+                m_parent->openChild();
+        }
+
+        virtual void close() CATCH_OVERRIDE {
+
+            // Close any still open children (e.g. generators)
+            while( &m_ctx.currentTracker() != this )
+                m_ctx.currentTracker().close();
+
+            switch( m_runState ) {
+                case NotStarted:
+                case CompletedSuccessfully:
+                case Failed:
+                    throw std::logic_error( "Illogical state" );
+
+                case NeedsAnotherRun:
+                    break;;
+
+                case Executing:
+                    m_runState = CompletedSuccessfully;
+                    break;
+                case ExecutingChildren:
+                    if( m_children.empty() || m_children.back()->isComplete() )
+                        m_runState = CompletedSuccessfully;
+                    break;
+
+                default:
+                    throw std::logic_error( "Unexpected state" );
+            }
+            moveToParent();
+            m_ctx.completeCycle();
+        }
+        virtual void fail() CATCH_OVERRIDE {
+            m_runState = Failed;
+            if( m_parent )
+                m_parent->markAsNeedingAnotherRun();
+            moveToParent();
+            m_ctx.completeCycle();
+        }
+        virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE {
+            m_runState = NeedsAnotherRun;
+        }
+    private:
+        void moveToParent() {
+            assert( m_parent );
+            m_ctx.setCurrentTracker( m_parent );
+        }
+        void moveToThis() {
+            m_ctx.setCurrentTracker( this );
+        }
+    };
+
+    class SectionTracker : public TrackerBase {
+        std::vector<std::string> m_filters;
+    public:
+        SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+        :   TrackerBase( nameAndLocation, ctx, parent )
+        {
+            if( parent ) {
+                while( !parent->isSectionTracker() )
+                    parent = &parent->parent();
+
+                SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
+                addNextFilters( parentSection.m_filters );
+            }
+        }
+        virtual ~SectionTracker();
+
+        virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
+
+        static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
+            SectionTracker* section = CATCH_NULL;
+
+            ITracker& currentTracker = ctx.currentTracker();
+            if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
+                assert( childTracker );
+                assert( childTracker->isSectionTracker() );
+                section = static_cast<SectionTracker*>( childTracker );
+            }
+            else {
+                section = new SectionTracker( nameAndLocation, ctx, &currentTracker );
+                currentTracker.addChild( section );
+            }
+            if( !ctx.completedCycle() )
+                section->tryOpen();
+            return *section;
+        }
+
+        void tryOpen() {
+            if( !isComplete() && (m_filters.empty() || m_filters[0].empty() ||  m_filters[0] == m_nameAndLocation.name ) )
+                open();
+        }
+
+        void addInitialFilters( std::vector<std::string> const& filters ) {
+            if( !filters.empty() ) {
+                m_filters.push_back(""); // Root - should never be consulted
+                m_filters.push_back(""); // Test Case - not a section filter
+                m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
+            }
+        }
+        void addNextFilters( std::vector<std::string> const& filters ) {
+            if( filters.size() > 1 )
+                m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
+        }
+    };
+
+    class IndexTracker : public TrackerBase {
+        int m_size;
+        int m_index;
+    public:
+        IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
+        :   TrackerBase( nameAndLocation, ctx, parent ),
+            m_size( size ),
+            m_index( -1 )
+        {}
+        virtual ~IndexTracker();
+
+        virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
+
+        static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
+            IndexTracker* tracker = CATCH_NULL;
+
+            ITracker& currentTracker = ctx.currentTracker();
+            if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
+                assert( childTracker );
+                assert( childTracker->isIndexTracker() );
+                tracker = static_cast<IndexTracker*>( childTracker );
+            }
+            else {
+                tracker = new IndexTracker( nameAndLocation, ctx, &currentTracker, size );
+                currentTracker.addChild( tracker );
+            }
+
+            if( !ctx.completedCycle() && !tracker->isComplete() ) {
+                if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
+                    tracker->moveNext();
+                tracker->open();
+            }
+
+            return *tracker;
+        }
+
+        int index() const { return m_index; }
+
+        void moveNext() {
+            m_index++;
+            m_children.clear();
+        }
+
+        virtual void close() CATCH_OVERRIDE {
+            TrackerBase::close();
+            if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
+                m_runState = Executing;
+        }
+    };
+
+    inline ITracker& TrackerContext::startRun() {
+        m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL );
+        m_currentTracker = CATCH_NULL;
+        m_runState = Executing;
+        return *m_rootTracker;
+    }
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+using TestCaseTracking::IndexTracker;
+
+} // namespace Catch
+
+CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+// #included from: catch_fatal_condition.hpp
+#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
+
+namespace Catch {
+
+    // Report the error condition
+    inline void reportFatal( std::string const& message ) {
+        IContext& context = Catch::getCurrentContext();
+        IResultCapture* resultCapture = context.getResultCapture();
+        resultCapture->handleFatalErrorCondition( message );
+    }
+
+} // namespace Catch
+
+#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
+// #included from: catch_windows_h_proxy.h
+
+#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED
+
+#ifdef CATCH_DEFINES_NOMINMAX
+#  define NOMINMAX
+#endif
+#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+#ifdef CATCH_DEFINES_NOMINMAX
+#  undef NOMINMAX
+#endif
+#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+#  undef WIN32_LEAN_AND_MEAN
+#endif
+
+
+#  if !defined ( CATCH_CONFIG_WINDOWS_SEH )
+
+namespace Catch {
+    struct FatalConditionHandler {
+        void reset() {}
+    };
+}
+
+#  else // CATCH_CONFIG_WINDOWS_SEH is defined
+
+namespace Catch {
+
+    struct SignalDefs { DWORD id; const char* name; };
+    extern SignalDefs signalDefs[];
+    // There is no 1-1 mapping between signals and windows exceptions.
+    // Windows can easily distinguish between SO and SigSegV,
+    // but SigInt, SigTerm, etc are handled differently.
+    SignalDefs signalDefs[] = {
+        { EXCEPTION_ILLEGAL_INSTRUCTION,  "SIGILL - Illegal instruction signal" },
+        { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
+        { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
+        { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
+    };
+
+    struct FatalConditionHandler {
+
+        static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
+            for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+                if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
+                    reportFatal(signalDefs[i].name);
+                }
+            }
+            // If its not an exception we care about, pass it along.
+            // This stops us from eating debugger breaks etc.
+            return EXCEPTION_CONTINUE_SEARCH;
+        }
+
+        FatalConditionHandler() {
+            isSet = true;
+            // 32k seems enough for Catch to handle stack overflow,
+            // but the value was found experimentally, so there is no strong guarantee
+            guaranteeSize = 32 * 1024;
+            exceptionHandlerHandle = CATCH_NULL;
+            // Register as first handler in current chain
+            exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
+            // Pass in guarantee size to be filled
+            SetThreadStackGuarantee(&guaranteeSize);
+        }
+
+        static void reset() {
+            if (isSet) {
+                // Unregister handler and restore the old guarantee
+                RemoveVectoredExceptionHandler(exceptionHandlerHandle);
+                SetThreadStackGuarantee(&guaranteeSize);
+                exceptionHandlerHandle = CATCH_NULL;
+                isSet = false;
+            }
+        }
+
+        ~FatalConditionHandler() {
+            reset();
+        }
+    private:
+        static bool isSet;
+        static ULONG guaranteeSize;
+        static PVOID exceptionHandlerHandle;
+    };
+
+    bool FatalConditionHandler::isSet = false;
+    ULONG FatalConditionHandler::guaranteeSize = 0;
+    PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL;
+
+} // namespace Catch
+
+#  endif // CATCH_CONFIG_WINDOWS_SEH
+
+#else // Not Windows - assumed to be POSIX compatible //////////////////////////
+
+#  if !defined(CATCH_CONFIG_POSIX_SIGNALS)
+
+namespace Catch {
+    struct FatalConditionHandler {
+        void reset() {}
+    };
+}
+
+#  else // CATCH_CONFIG_POSIX_SIGNALS is defined
+
+#include <signal.h>
+
+namespace Catch {
+
+    struct SignalDefs {
+        int id;
+        const char* name;
+    };
+    extern SignalDefs signalDefs[];
+    SignalDefs signalDefs[] = {
+            { SIGINT,  "SIGINT - Terminal interrupt signal" },
+            { SIGILL,  "SIGILL - Illegal instruction signal" },
+            { SIGFPE,  "SIGFPE - Floating point error signal" },
+            { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
+            { SIGTERM, "SIGTERM - Termination request signal" },
+            { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
+    };
+
+    struct FatalConditionHandler {
+
+        static bool isSet;
+        static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
+        static stack_t oldSigStack;
+        static char altStackMem[SIGSTKSZ];
+
+        static void handleSignal( int sig ) {
+            std::string name = "<unknown signal>";
+            for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+                SignalDefs &def = signalDefs[i];
+                if (sig == def.id) {
+                    name = def.name;
+                    break;
+                }
+            }
+            reset();
+            reportFatal(name);
+            raise( sig );
+        }
+
+        FatalConditionHandler() {
+            isSet = true;
+            stack_t sigStack;
+            sigStack.ss_sp = altStackMem;
+            sigStack.ss_size = SIGSTKSZ;
+            sigStack.ss_flags = 0;
+            sigaltstack(&sigStack, &oldSigStack);
+            struct sigaction sa = { 0 };
+
+            sa.sa_handler = handleSignal;
+            sa.sa_flags = SA_ONSTACK;
+            for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
+                sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
+            }
+        }
+
+        ~FatalConditionHandler() {
+            reset();
+        }
+        static void reset() {
+            if( isSet ) {
+                // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
+                for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
+                    sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL);
+                }
+                // Return the old stack
+                sigaltstack(&oldSigStack, CATCH_NULL);
+                isSet = false;
+            }
+        }
+    };
+
+    bool FatalConditionHandler::isSet = false;
+    struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
+    stack_t FatalConditionHandler::oldSigStack = {};
+    char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
+
+} // namespace Catch
+
+#  endif // CATCH_CONFIG_POSIX_SIGNALS
+
+#endif // not Windows
+
+#include <set>
+#include <string>
+
+namespace Catch {
+
+    class StreamRedirect {
+
+    public:
+        StreamRedirect( std::ostream& stream, std::string& targetString )
+        :   m_stream( stream ),
+            m_prevBuf( stream.rdbuf() ),
+            m_targetString( targetString )
+        {
+            stream.rdbuf( m_oss.rdbuf() );
+        }
+
+        ~StreamRedirect() {
+            m_targetString += m_oss.str();
+            m_stream.rdbuf( m_prevBuf );
+        }
+
+    private:
+        std::ostream& m_stream;
+        std::streambuf* m_prevBuf;
+        std::ostringstream m_oss;
+        std::string& m_targetString;
+    };
+
+    // StdErr has two constituent streams in C++, std::cerr and std::clog
+    // This means that we need to redirect 2 streams into 1 to keep proper
+    // order of writes and cannot use StreamRedirect on its own
+    class StdErrRedirect {
+    public:
+        StdErrRedirect(std::string& targetString)
+        :m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()),
+        m_targetString(targetString){
+            cerr().rdbuf(m_oss.rdbuf());
+            clog().rdbuf(m_oss.rdbuf());
+        }
+        ~StdErrRedirect() {
+            m_targetString += m_oss.str();
+            cerr().rdbuf(m_cerrBuf);
+            clog().rdbuf(m_clogBuf);
+        }
+    private:
+        std::streambuf* m_cerrBuf;
+        std::streambuf* m_clogBuf;
+        std::ostringstream m_oss;
+        std::string& m_targetString;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class RunContext : public IResultCapture, public IRunner {
+
+        RunContext( RunContext const& );
+        void operator =( RunContext const& );
+
+    public:
+
+        explicit RunContext( Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter )
+        :   m_runInfo( _config->name() ),
+            m_context( getCurrentMutableContext() ),
+            m_activeTestCase( CATCH_NULL ),
+            m_config( _config ),
+            m_reporter( reporter ),
+            m_shouldReportUnexpected ( true )
+        {
+            m_context.setRunner( this );
+            m_context.setConfig( m_config );
+            m_context.setResultCapture( this );
+            m_reporter->testRunStarting( m_runInfo );
+        }
+
+        virtual ~RunContext() {
+            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
+        }
+
+        void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
+            m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
+        }
+        void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
+            m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
+        }
+
+        Totals runTest( TestCase const& testCase ) {
+            Totals prevTotals = m_totals;
+
+            std::string redirectedCout;
+            std::string redirectedCerr;
+
+            TestCaseInfo testInfo = testCase.getTestCaseInfo();
+
+            m_reporter->testCaseStarting( testInfo );
+
+            m_activeTestCase = &testCase;
+
+            do {
+                ITracker& rootTracker = m_trackerContext.startRun();
+                assert( rootTracker.isSectionTracker() );
+                static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() );
+                do {
+                    m_trackerContext.startCycle();
+                    m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
+                    runCurrentTest( redirectedCout, redirectedCerr );
+                }
+                while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
+            }
+            // !TBD: deprecated - this will be replaced by indexed trackers
+            while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
+
+            Totals deltaTotals = m_totals.delta( prevTotals );
+            if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
+                deltaTotals.assertions.failed++;
+                deltaTotals.testCases.passed--;
+                deltaTotals.testCases.failed++;
+            }
+            m_totals.testCases += deltaTotals.testCases;
+            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
+                                                        deltaTotals,
+                                                        redirectedCout,
+                                                        redirectedCerr,
+                                                        aborting() ) );
+
+            m_activeTestCase = CATCH_NULL;
+            m_testCaseTracker = CATCH_NULL;
+
+            return deltaTotals;
+        }
+
+        Ptr<IConfig const> config() const {
+            return m_config;
+        }
+
+    private: // IResultCapture
+
+        virtual void assertionEnded( AssertionResult const& result ) {
+            if( result.getResultType() == ResultWas::Ok ) {
+                m_totals.assertions.passed++;
+            }
+            else if( !result.isOk() ) {
+                if( m_activeTestCase->getTestCaseInfo().okToFail() )
+                    m_totals.assertions.failedButOk++;
+                else
+                    m_totals.assertions.failed++;
+            }
+
+            // We have no use for the return value (whether messages should be cleared), because messages were made scoped
+            // and should be let to clear themselves out.
+            static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
+
+            // Reset working state
+            m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
+            m_lastResult = result;
+        }
+
+        virtual bool lastAssertionPassed()
+        {
+            return m_totals.assertions.passed == (m_prevPassed + 1);
+        }
+
+        virtual void assertionPassed()
+        {
+            m_totals.assertions.passed++;
+            m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}";
+            m_lastAssertionInfo.macroName = "";
+        }
+
+        virtual void assertionRun()
+        {
+            m_prevPassed = m_totals.assertions.passed;
+        }
+
+        virtual bool sectionStarted (
+            SectionInfo const& sectionInfo,
+            Counts& assertions
+        )
+        {
+            ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
+            if( !sectionTracker.isOpen() )
+                return false;
+            m_activeSections.push_back( &sectionTracker );
+
+            m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+            m_reporter->sectionStarting( sectionInfo );
+
+            assertions = m_totals.assertions;
+
+            return true;
+        }
+        bool testForMissingAssertions( Counts& assertions ) {
+            if( assertions.total() != 0 )
+                return false;
+            if( !m_config->warnAboutMissingAssertions() )
+                return false;
+            if( m_trackerContext.currentTracker().hasChildren() )
+                return false;
+            m_totals.assertions.failed++;
+            assertions.failed++;
+            return true;
+        }
+
+        virtual void sectionEnded( SectionEndInfo const& endInfo ) {
+            Counts assertions = m_totals.assertions - endInfo.prevAssertions;
+            bool missingAssertions = testForMissingAssertions( assertions );
+
+            if( !m_activeSections.empty() ) {
+                m_activeSections.back()->close();
+                m_activeSections.pop_back();
+            }
+
+            m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) );
+            m_messages.clear();
+        }
+
+        virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) {
+            if( m_unfinishedSections.empty() )
+                m_activeSections.back()->fail();
+            else
+                m_activeSections.back()->close();
+            m_activeSections.pop_back();
+
+            m_unfinishedSections.push_back( endInfo );
+        }
+
+        virtual void pushScopedMessage( MessageInfo const& message ) {
+            m_messages.push_back( message );
+        }
+
+        virtual void popScopedMessage( MessageInfo const& message ) {
+            m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
+        }
+
+        virtual std::string getCurrentTestName() const {
+            return m_activeTestCase
+                ? m_activeTestCase->getTestCaseInfo().name
+                : std::string();
+        }
+
+        virtual const AssertionResult* getLastResult() const {
+            return &m_lastResult;
+        }
+
+        virtual void exceptionEarlyReported() {
+            m_shouldReportUnexpected = false;
+        }
+
+        virtual void handleFatalErrorCondition( std::string const& message ) {
+            // Don't rebuild the result -- the stringification itself can cause more fatal errors
+            // Instead, fake a result data.
+            AssertionResultData tempResult;
+            tempResult.resultType = ResultWas::FatalErrorCondition;
+            tempResult.message = message;
+            AssertionResult result(m_lastAssertionInfo, tempResult);
+
+            getResultCapture().assertionEnded(result);
+
+            handleUnfinishedSections();
+
+            // Recreate section for test case (as we will lose the one that was in scope)
+            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+            SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
+
+            Counts assertions;
+            assertions.failed = 1;
+            SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false );
+            m_reporter->sectionEnded( testCaseSectionStats );
+
+            TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
+
+            Totals deltaTotals;
+            deltaTotals.testCases.failed = 1;
+            deltaTotals.assertions.failed = 1;
+            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
+                                                        deltaTotals,
+                                                        std::string(),
+                                                        std::string(),
+                                                        false ) );
+            m_totals.testCases.failed++;
+            testGroupEnded( std::string(), m_totals, 1, 1 );
+            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
+        }
+
+    public:
+        // !TBD We need to do this another way!
+        bool aborting() const {
+            return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
+        }
+
+    private:
+
+        void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
+            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+            SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
+            m_reporter->sectionStarting( testCaseSection );
+            Counts prevAssertions = m_totals.assertions;
+            double duration = 0;
+            m_shouldReportUnexpected = true;
+            try {
+                m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
+
+                seedRng( *m_config );
+
+                Timer timer;
+                timer.start();
+                if( m_reporter->getPreferences().shouldRedirectStdOut ) {
+                    StreamRedirect coutRedir( Catch::cout(), redirectedCout );
+                    StdErrRedirect errRedir( redirectedCerr );
+                    invokeActiveTestCase();
+                }
+                else {
+                    invokeActiveTestCase();
+                }
+                duration = timer.getElapsedSeconds();
+            }
+            catch( TestFailureException& ) {
+                // This just means the test was aborted due to failure
+            }
+            catch(...) {
+                // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
+                // are reported without translation at the point of origin.
+                if (m_shouldReportUnexpected) {
+                    makeUnexpectedResultBuilder().useActiveException();
+                }
+            }
+            m_testCaseTracker->close();
+            handleUnfinishedSections();
+            m_messages.clear();
+
+            Counts assertions = m_totals.assertions - prevAssertions;
+            bool missingAssertions = testForMissingAssertions( assertions );
+
+            SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
+            m_reporter->sectionEnded( testCaseSectionStats );
+        }
+
+        void invokeActiveTestCase() {
+            FatalConditionHandler fatalConditionHandler; // Handle signals
+            m_activeTestCase->invoke();
+            fatalConditionHandler.reset();
+        }
+
+    private:
+
+        ResultBuilder makeUnexpectedResultBuilder() const {
+            return ResultBuilder(   m_lastAssertionInfo.macroName,
+                                    m_lastAssertionInfo.lineInfo,
+                                    m_lastAssertionInfo.capturedExpression,
+                                    m_lastAssertionInfo.resultDisposition );
+        }
+
+        void handleUnfinishedSections() {
+            // If sections ended prematurely due to an exception we stored their
+            // infos here so we can tear them down outside the unwind process.
+            for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
+                        itEnd = m_unfinishedSections.rend();
+                    it != itEnd;
+                    ++it )
+                sectionEnded( *it );
+            m_unfinishedSections.clear();
+        }
+
+        TestRunInfo m_runInfo;
+        IMutableContext& m_context;
+        TestCase const* m_activeTestCase;
+        ITracker* m_testCaseTracker;
+        ITracker* m_currentSectionTracker;
+        AssertionResult m_lastResult;
+
+        Ptr<IConfig const> m_config;
+        Totals m_totals;
+        Ptr<IStreamingReporter> m_reporter;
+        std::vector<MessageInfo> m_messages;
+        AssertionInfo m_lastAssertionInfo;
+        std::vector<SectionEndInfo> m_unfinishedSections;
+        std::vector<ITracker*> m_activeSections;
+        TrackerContext m_trackerContext;
+        size_t m_prevPassed;
+        bool m_shouldReportUnexpected;
+    };
+
+    IResultCapture& getResultCapture() {
+        if( IResultCapture* capture = getCurrentContext().getResultCapture() )
+            return *capture;
+        else
+            throw std::logic_error( "No result capture instance" );
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_version.h
+#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
+
+namespace Catch {
+
+    // Versioning information
+    struct Version {
+        Version(    unsigned int _majorVersion,
+                    unsigned int _minorVersion,
+                    unsigned int _patchNumber,
+                    char const * const _branchName,
+                    unsigned int _buildNumber );
+
+        unsigned int const majorVersion;
+        unsigned int const minorVersion;
+        unsigned int const patchNumber;
+
+        // buildNumber is only used if branchName is not null
+        char const * const branchName;
+        unsigned int const buildNumber;
+
+        friend std::ostream& operator << ( std::ostream& os, Version const& version );
+
+    private:
+        void operator=( Version const& );
+    };
+
+    inline Version libraryVersion();
+}
+
+#include <fstream>
+#include <stdlib.h>
+#include <limits>
+
+namespace Catch {
+
+    Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) {
+        Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() );
+        if( !reporter ) {
+            std::ostringstream oss;
+            oss << "No reporter registered with name: '" << reporterName << "'";
+            throw std::domain_error( oss.str() );
+        }
+        return reporter;
+    }
+
+#if !defined(CATCH_CONFIG_DEFAULT_REPORTER)
+#define CATCH_CONFIG_DEFAULT_REPORTER "console"
+#endif
+
+    Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
+        std::vector<std::string> reporters = config->getReporterNames();
+        if( reporters.empty() )
+            reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER );
+
+        Ptr<IStreamingReporter> reporter;
+        for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
+                it != itEnd;
+                ++it )
+            reporter = addReporter( reporter, createReporter( *it, config ) );
+        return reporter;
+    }
+    Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) {
+        IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
+        for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
+                it != itEnd;
+                ++it )
+            reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) );
+        return reporters;
+    }
+
+    Totals runTests( Ptr<Config> const& config ) {
+
+        Ptr<IConfig const> iconfig = config.get();
+
+        Ptr<IStreamingReporter> reporter = makeReporter( config );
+        reporter = addListeners( iconfig, reporter );
+
+        RunContext context( iconfig, reporter );
+
+        Totals totals;
+
+        context.testGroupStarting( config->name(), 1, 1 );
+
+        TestSpec testSpec = config->testSpec();
+        if( !testSpec.hasFilters() )
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
+
+        std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig );
+        for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
+                it != itEnd;
+                ++it ) {
+            if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) )
+                totals += context.runTest( *it );
+            else
+                reporter->skipTest( *it );
+        }
+
+        context.testGroupEnded( iconfig->name(), totals, 1, 1 );
+        return totals;
+    }
+
+    void applyFilenamesAsTags( IConfig const& config ) {
+        std::vector<TestCase> const& tests = getAllTestCasesSorted( config );
+        for(std::size_t i = 0; i < tests.size(); ++i ) {
+            TestCase& test = const_cast<TestCase&>( tests[i] );
+            std::set<std::string> tags = test.tags;
+
+            std::string filename = test.lineInfo.file;
+            std::string::size_type lastSlash = filename.find_last_of( "\\/" );
+            if( lastSlash != std::string::npos )
+                filename = filename.substr( lastSlash+1 );
+
+            std::string::size_type lastDot = filename.find_last_of( '.' );
+            if( lastDot != std::string::npos )
+                filename = filename.substr( 0, lastDot );
+
+            tags.insert( '#' + filename );
+            setTags( test, tags );
+        }
+    }
+
+    class Session : NonCopyable {
+        static bool alreadyInstantiated;
+
+    public:
+
+        struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
+
+        Session()
+        : m_cli( makeCommandLineParser() ) {
+            if( alreadyInstantiated ) {
+                std::string msg = "Only one instance of Catch::Session can ever be used";
+                Catch::cerr() << msg << std::endl;
+                throw std::logic_error( msg );
+            }
+            alreadyInstantiated = true;
+        }
+        ~Session() {
+            Catch::cleanUp();
+        }
+
+        void showHelp( std::string const& processName ) {
+            Catch::cout() << "\nCatch v" << libraryVersion() << "\n";
+
+            m_cli.usage( Catch::cout(), processName );
+            Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
+        }
+        void libIdentify() {
+            Catch::cout()
+                    << std::left << std::setw(16) << "description: " << "A Catch test executable\n"
+                    << std::left << std::setw(16) << "category: " << "testframework\n"
+                    << std::left << std::setw(16) << "framework: " << "Catch Test\n"
+                    << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
+        }
+
+        int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
+            try {
+                m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
+                m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
+                if( m_configData.showHelp )
+                    showHelp( m_configData.processName );
+                if( m_configData.libIdentify )
+                    libIdentify();
+                m_config.reset();
+            }
+            catch( std::exception& ex ) {
+                {
+                    Colour colourGuard( Colour::Red );
+                    Catch::cerr()
+                        << "\nError(s) in input:\n"
+                        << Text( ex.what(), TextAttributes().setIndent(2) )
+                        << "\n\n";
+                }
+                m_cli.usage( Catch::cout(), m_configData.processName );
+                return (std::numeric_limits<int>::max)();
+            }
+            return 0;
+        }
+
+        void useConfigData( ConfigData const& _configData ) {
+            m_configData = _configData;
+            m_config.reset();
+        }
+
+        int run( int argc, char const* const* const argv ) {
+
+            int returnCode = applyCommandLine( argc, argv );
+            if( returnCode == 0 )
+                returnCode = run();
+            return returnCode;
+        }
+
+    #if defined(WIN32) && defined(UNICODE)
+        int run( int argc, wchar_t const* const* const argv ) {
+
+            char **utf8Argv = new char *[ argc ];
+
+            for ( int i = 0; i < argc; ++i ) {
+                int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
+
+                utf8Argv[ i ] = new char[ bufSize ];
+
+                WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
+            }
+
+            int returnCode = applyCommandLine( argc, utf8Argv );
+            if( returnCode == 0 )
+                returnCode = run();
+
+            for ( int i = 0; i < argc; ++i )
+                delete [] utf8Argv[ i ];
+
+            delete [] utf8Argv;
+
+            return returnCode;
+        }
+    #endif
+
+        int run() {
+            if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
+                Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
+                static_cast<void>(std::getchar());
+            }
+            int exitCode = runInternal();
+            if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
+                Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
+                static_cast<void>(std::getchar());
+            }
+            return exitCode;
+        }
+
+        Clara::CommandLine<ConfigData> const& cli() const {
+            return m_cli;
+        }
+        std::vector<Clara::Parser::Token> const& unusedTokens() const {
+            return m_unusedTokens;
+        }
+        ConfigData& configData() {
+            return m_configData;
+        }
+        Config& config() {
+            if( !m_config )
+                m_config = new Config( m_configData );
+            return *m_config;
+        }
+    private:
+
+        int runInternal() {
+            if( m_configData.showHelp || m_configData.libIdentify )
+                return 0;
+
+            try
+            {
+                config(); // Force config to be constructed
+
+                seedRng( *m_config );
+
+                if( m_configData.filenamesAsTags )
+                    applyFilenamesAsTags( *m_config );
+
+                // Handle list request
+                if( Option<std::size_t> listed = list( config() ) )
+                    return static_cast<int>( *listed );
+
+                return static_cast<int>( runTests( m_config ).assertions.failed );
+            }
+            catch( std::exception& ex ) {
+                Catch::cerr() << ex.what() << std::endl;
+                return (std::numeric_limits<int>::max)();
+            }
+        }
+
+        Clara::CommandLine<ConfigData> m_cli;
+        std::vector<Clara::Parser::Token> m_unusedTokens;
+        ConfigData m_configData;
+        Ptr<Config> m_config;
+    };
+
+    bool Session::alreadyInstantiated = false;
+
+} // end namespace Catch
+
+// #included from: catch_registry_hub.hpp
+#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
+
+// #included from: catch_test_case_registry_impl.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <set>
+#include <sstream>
+#include <algorithm>
+
+namespace Catch {
+
+    struct RandomNumberGenerator {
+        typedef unsigned int result_type;
+
+        result_type operator()( result_type n ) const { return std::rand() % n; }
+
+#ifdef CATCH_CONFIG_CPP11_SHUFFLE
+        static constexpr result_type min() { return 0; }
+        static constexpr result_type max() { return 1000000; }
+        result_type operator()() const { return std::rand() % max(); }
+#endif
+        template<typename V>
+        static void shuffle( V& vector ) {
+            RandomNumberGenerator rng;
+#ifdef CATCH_CONFIG_CPP11_SHUFFLE
+            std::shuffle( vector.begin(), vector.end(), rng );
+#else
+            std::random_shuffle( vector.begin(), vector.end(), rng );
+#endif
+        }
+    };
+
+    inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
+
+        std::vector<TestCase> sorted = unsortedTestCases;
+
+        switch( config.runOrder() ) {
+            case RunTests::InLexicographicalOrder:
+                std::sort( sorted.begin(), sorted.end() );
+                break;
+            case RunTests::InRandomOrder:
+                {
+                    seedRng( config );
+                    RandomNumberGenerator::shuffle( sorted );
+                }
+                break;
+            case RunTests::InDeclarationOrder:
+                // already in declaration order
+                break;
+        }
+        return sorted;
+    }
+    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
+        return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
+    }
+
+    void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
+        std::set<TestCase> seenFunctions;
+        for( std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end();
+            it != itEnd;
+            ++it ) {
+            std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
+            if( !prev.second ) {
+                std::ostringstream ss;
+
+                ss  << Colour( Colour::Red )
+                    << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
+                    << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n'
+                    << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
+
+                throw std::runtime_error(ss.str());
+            }
+        }
+    }
+
+    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
+        std::vector<TestCase> filtered;
+        filtered.reserve( testCases.size() );
+        for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
+                it != itEnd;
+                ++it )
+            if( matchTest( *it, testSpec, config ) )
+                filtered.push_back( *it );
+        return filtered;
+    }
+    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
+        return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
+    }
+
+    class TestRegistry : public ITestCaseRegistry {
+    public:
+        TestRegistry()
+        :   m_currentSortOrder( RunTests::InDeclarationOrder ),
+            m_unnamedCount( 0 )
+        {}
+        virtual ~TestRegistry();
+
+        virtual void registerTest( TestCase const& testCase ) {
+            std::string name = testCase.getTestCaseInfo().name;
+            if( name.empty() ) {
+                std::ostringstream oss;
+                oss << "Anonymous test case " << ++m_unnamedCount;
+                return registerTest( testCase.withName( oss.str() ) );
+            }
+            m_functions.push_back( testCase );
+        }
+
+        virtual std::vector<TestCase> const& getAllTests() const {
+            return m_functions;
+        }
+        virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const {
+            if( m_sortedFunctions.empty() )
+                enforceNoDuplicateTestCases( m_functions );
+
+            if(  m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
+                m_sortedFunctions = sortTests( config, m_functions );
+                m_currentSortOrder = config.runOrder();
+            }
+            return m_sortedFunctions;
+        }
+
+    private:
+        std::vector<TestCase> m_functions;
+        mutable RunTests::InWhatOrder m_currentSortOrder;
+        mutable std::vector<TestCase> m_sortedFunctions;
+        size_t m_unnamedCount;
+        std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class FreeFunctionTestCase : public SharedImpl<ITestCase> {
+    public:
+
+        FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
+
+        virtual void invoke() const {
+            m_fun();
+        }
+
+    private:
+        virtual ~FreeFunctionTestCase();
+
+        TestFunction m_fun;
+    };
+
+    inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
+        std::string className = classOrQualifiedMethodName;
+        if( startsWith( className, '&' ) )
+        {
+            std::size_t lastColons = className.rfind( "::" );
+            std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
+            if( penultimateColons == std::string::npos )
+                penultimateColons = 1;
+            className = className.substr( penultimateColons, lastColons-penultimateColons );
+        }
+        return className;
+    }
+
+    void registerTestCase
+        (   ITestCase* testCase,
+            char const* classOrQualifiedMethodName,
+            NameAndDesc const& nameAndDesc,
+            SourceLineInfo const& lineInfo ) {
+
+        getMutableRegistryHub().registerTest
+            ( makeTestCase
+                (   testCase,
+                    extractClassName( classOrQualifiedMethodName ),
+                    nameAndDesc.name,
+                    nameAndDesc.description,
+                    lineInfo ) );
+    }
+    void registerTestCaseFunction
+        (   TestFunction function,
+            SourceLineInfo const& lineInfo,
+            NameAndDesc const& nameAndDesc ) {
+        registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    AutoReg::AutoReg
+        (   TestFunction function,
+            SourceLineInfo const& lineInfo,
+            NameAndDesc const& nameAndDesc ) {
+        registerTestCaseFunction( function, lineInfo, nameAndDesc );
+    }
+
+    AutoReg::~AutoReg() {}
+
+} // end namespace Catch
+
+// #included from: catch_reporter_registry.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+    class ReporterRegistry : public IReporterRegistry {
+
+    public:
+
+        virtual ~ReporterRegistry() CATCH_OVERRIDE {}
+
+        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE {
+            FactoryMap::const_iterator it =  m_factories.find( name );
+            if( it == m_factories.end() )
+                return CATCH_NULL;
+            return it->second->create( ReporterConfig( config ) );
+        }
+
+        void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) {
+            m_factories.insert( std::make_pair( name, factory ) );
+        }
+        void registerListener( Ptr<IReporterFactory> const& factory ) {
+            m_listeners.push_back( factory );
+        }
+
+        virtual FactoryMap const& getFactories() const CATCH_OVERRIDE {
+            return m_factories;
+        }
+        virtual Listeners const& getListeners() const CATCH_OVERRIDE {
+            return m_listeners;
+        }
+
+    private:
+        FactoryMap m_factories;
+        Listeners m_listeners;
+    };
+}
+
+// #included from: catch_exception_translator_registry.hpp
+#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+
+#ifdef __OBJC__
+#import "Foundation/Foundation.h"
+#endif
+
+namespace Catch {
+
+    class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
+    public:
+        ~ExceptionTranslatorRegistry() {
+            deleteAll( m_translators );
+        }
+
+        virtual void registerTranslator( const IExceptionTranslator* translator ) {
+            m_translators.push_back( translator );
+        }
+
+        virtual std::string translateActiveException() const {
+            try {
+#ifdef __OBJC__
+                // In Objective-C try objective-c exceptions first
+                @try {
+                    return tryTranslators();
+                }
+                @catch (NSException *exception) {
+                    return Catch::toString( [exception description] );
+                }
+#else
+                return tryTranslators();
+#endif
+            }
+            catch( TestFailureException& ) {
+                throw;
+            }
+            catch( std::exception& ex ) {
+                return ex.what();
+            }
+            catch( std::string& msg ) {
+                return msg;
+            }
+            catch( const char* msg ) {
+                return msg;
+            }
+            catch(...) {
+                return "Unknown exception";
+            }
+        }
+
+        std::string tryTranslators() const {
+            if( m_translators.empty() )
+                throw;
+            else
+                return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
+        }
+
+    private:
+        std::vector<const IExceptionTranslator*> m_translators;
+    };
+}
+
+// #included from: catch_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+    class TagAliasRegistry : public ITagAliasRegistry {
+    public:
+        virtual ~TagAliasRegistry();
+        virtual Option<TagAlias> find( std::string const& alias ) const;
+        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
+        void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
+
+    private:
+        std::map<std::string, TagAlias> m_registry;
+    };
+
+} // end namespace Catch
+
+namespace Catch {
+
+    namespace {
+
+        class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
+
+            RegistryHub( RegistryHub const& );
+            void operator=( RegistryHub const& );
+
+        public: // IRegistryHub
+            RegistryHub() {
+            }
+            virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE {
+                return m_reporterRegistry;
+            }
+            virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE {
+                return m_testCaseRegistry;
+            }
+            virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE {
+                return m_exceptionTranslatorRegistry;
+            }
+            virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE {
+                return m_tagAliasRegistry;
+            }
+
+        public: // IMutableRegistryHub
+            virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
+                m_reporterRegistry.registerReporter( name, factory );
+            }
+            virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
+                m_reporterRegistry.registerListener( factory );
+            }
+            virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE {
+                m_testCaseRegistry.registerTest( testInfo );
+            }
+            virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE {
+                m_exceptionTranslatorRegistry.registerTranslator( translator );
+            }
+            virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE {
+                m_tagAliasRegistry.add( alias, tag, lineInfo );
+            }
+
+        private:
+            TestRegistry m_testCaseRegistry;
+            ReporterRegistry m_reporterRegistry;
+            ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+            TagAliasRegistry m_tagAliasRegistry;
+        };
+
+        // Single, global, instance
+        inline RegistryHub*& getTheRegistryHub() {
+            static RegistryHub* theRegistryHub = CATCH_NULL;
+            if( !theRegistryHub )
+                theRegistryHub = new RegistryHub();
+            return theRegistryHub;
+        }
+    }
+
+    IRegistryHub& getRegistryHub() {
+        return *getTheRegistryHub();
+    }
+    IMutableRegistryHub& getMutableRegistryHub() {
+        return *getTheRegistryHub();
+    }
+    void cleanUp() {
+        delete getTheRegistryHub();
+        getTheRegistryHub() = CATCH_NULL;
+        cleanUpContext();
+    }
+    std::string translateActiveException() {
+        return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_notimplemented_exception.hpp
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
+
+#include <sstream>
+
+namespace Catch {
+
+    NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
+    :   m_lineInfo( lineInfo ) {
+        std::ostringstream oss;
+        oss << lineInfo << ": function ";
+        oss << "not implemented";
+        m_what = oss.str();
+    }
+
+    const char* NotImplementedException::what() const CATCH_NOEXCEPT {
+        return m_what.c_str();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_context_impl.hpp
+#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
+
+// #included from: catch_stream.hpp
+#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
+
+#include <stdexcept>
+#include <cstdio>
+#include <iostream>
+
+namespace Catch {
+
+    template<typename WriterF, size_t bufferSize=256>
+    class StreamBufImpl : public StreamBufBase {
+        char data[bufferSize];
+        WriterF m_writer;
+
+    public:
+        StreamBufImpl() {
+            setp( data, data + sizeof(data) );
+        }
+
+        ~StreamBufImpl() CATCH_NOEXCEPT {
+            sync();
+        }
+
+    private:
+        int overflow( int c ) {
+            sync();
+
+            if( c != EOF ) {
+                if( pbase() == epptr() )
+                    m_writer( std::string( 1, static_cast<char>( c ) ) );
+                else
+                    sputc( static_cast<char>( c ) );
+            }
+            return 0;
+        }
+
+        int sync() {
+            if( pbase() != pptr() ) {
+                m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
+                setp( pbase(), epptr() );
+            }
+            return 0;
+        }
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    FileStream::FileStream( std::string const& filename ) {
+        m_ofs.open( filename.c_str() );
+        if( m_ofs.fail() ) {
+            std::ostringstream oss;
+            oss << "Unable to open file: '" << filename << '\'';
+            throw std::domain_error( oss.str() );
+        }
+    }
+
+    std::ostream& FileStream::stream() const {
+        return m_ofs;
+    }
+
+    struct OutputDebugWriter {
+
+        void operator()( std::string const&str ) {
+            writeToDebugConsole( str );
+        }
+    };
+
+    DebugOutStream::DebugOutStream()
+    :   m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
+        m_os( m_streamBuf.get() )
+    {}
+
+    std::ostream& DebugOutStream::stream() const {
+        return m_os;
+    }
+
+    // Store the streambuf from cout up-front because
+    // cout may get redirected when running tests
+    CoutStream::CoutStream()
+    :   m_os( Catch::cout().rdbuf() )
+    {}
+
+    std::ostream& CoutStream::stream() const {
+        return m_os;
+    }
+
+#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
+    std::ostream& cout() {
+        return std::cout;
+    }
+    std::ostream& cerr() {
+        return std::cerr;
+    }
+    std::ostream& clog() {
+        return std::clog;
+    }
+#endif
+}
+
+namespace Catch {
+
+    class Context : public IMutableContext {
+
+        Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {}
+        Context( Context const& );
+        void operator=( Context const& );
+
+    public:
+        virtual ~Context() {
+            deleteAllValues( m_generatorsByTestName );
+        }
+
+    public: // IContext
+        virtual IResultCapture* getResultCapture() {
+            return m_resultCapture;
+        }
+        virtual IRunner* getRunner() {
+            return m_runner;
+        }
+        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
+            return getGeneratorsForCurrentTest()
+            .getGeneratorInfo( fileInfo, totalSize )
+            .getCurrentIndex();
+        }
+        virtual bool advanceGeneratorsForCurrentTest() {
+            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+            return generators && generators->moveNext();
+        }
+
+        virtual Ptr<IConfig const> getConfig() const {
+            return m_config;
+        }
+
+    public: // IMutableContext
+        virtual void setResultCapture( IResultCapture* resultCapture ) {
+            m_resultCapture = resultCapture;
+        }
+        virtual void setRunner( IRunner* runner ) {
+            m_runner = runner;
+        }
+        virtual void setConfig( Ptr<IConfig const> const& config ) {
+            m_config = config;
+        }
+
+        friend IMutableContext& getCurrentMutableContext();
+
+    private:
+        IGeneratorsForTest* findGeneratorsForCurrentTest() {
+            std::string testName = getResultCapture()->getCurrentTestName();
+
+            std::map<std::string, IGeneratorsForTest*>::const_iterator it =
+                m_generatorsByTestName.find( testName );
+            return it != m_generatorsByTestName.end()
+                ? it->second
+                : CATCH_NULL;
+        }
+
+        IGeneratorsForTest& getGeneratorsForCurrentTest() {
+            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+            if( !generators ) {
+                std::string testName = getResultCapture()->getCurrentTestName();
+                generators = createGeneratorsForTest();
+                m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
+            }
+            return *generators;
+        }
+
+    private:
+        Ptr<IConfig const> m_config;
+        IRunner* m_runner;
+        IResultCapture* m_resultCapture;
+        std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
+    };
+
+    namespace {
+        Context* currentContext = CATCH_NULL;
+    }
+    IMutableContext& getCurrentMutableContext() {
+        if( !currentContext )
+            currentContext = new Context();
+        return *currentContext;
+    }
+    IContext& getCurrentContext() {
+        return getCurrentMutableContext();
+    }
+
+    void cleanUpContext() {
+        delete currentContext;
+        currentContext = CATCH_NULL;
+    }
+}
+
+// #included from: catch_console_colour_impl.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
+
+// #included from: catch_errno_guard.hpp
+#define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED
+
+#include <cerrno>
+
+namespace Catch {
+
+    class ErrnoGuard {
+    public:
+        ErrnoGuard():m_oldErrno(errno){}
+        ~ErrnoGuard() { errno = m_oldErrno; }
+    private:
+        int m_oldErrno;
+    };
+
+}
+
+namespace Catch {
+    namespace {
+
+        struct IColourImpl {
+            virtual ~IColourImpl() {}
+            virtual void use( Colour::Code _colourCode ) = 0;
+        };
+
+        struct NoColourImpl : IColourImpl {
+            void use( Colour::Code ) {}
+
+            static IColourImpl* instance() {
+                static NoColourImpl s_instance;
+                return &s_instance;
+            }
+        };
+
+    } // anon namespace
+} // namespace Catch
+
+#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )
+#   ifdef CATCH_PLATFORM_WINDOWS
+#       define CATCH_CONFIG_COLOUR_WINDOWS
+#   else
+#       define CATCH_CONFIG_COLOUR_ANSI
+#   endif
+#endif
+
+#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
+
+namespace Catch {
+namespace {
+
+    class Win32ColourImpl : public IColourImpl {
+    public:
+        Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
+        {
+            CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+            GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
+            originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
+            originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
+        }
+
+        virtual void use( Colour::Code _colourCode ) {
+            switch( _colourCode ) {
+                case Colour::None:      return setTextAttribute( originalForegroundAttributes );
+                case Colour::White:     return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+                case Colour::Red:       return setTextAttribute( FOREGROUND_RED );
+                case Colour::Green:     return setTextAttribute( FOREGROUND_GREEN );
+                case Colour::Blue:      return setTextAttribute( FOREGROUND_BLUE );
+                case Colour::Cyan:      return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
+                case Colour::Yellow:    return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
+                case Colour::Grey:      return setTextAttribute( 0 );
+
+                case Colour::LightGrey:     return setTextAttribute( FOREGROUND_INTENSITY );
+                case Colour::BrightRed:     return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
+                case Colour::BrightGreen:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
+                case Colour::BrightWhite:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+
+                case Colour::Bright: throw std::logic_error( "not a colour" );
+            }
+        }
+
+    private:
+        void setTextAttribute( WORD _textAttribute ) {
+            SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );
+        }
+        HANDLE stdoutHandle;
+        WORD originalForegroundAttributes;
+        WORD originalBackgroundAttributes;
+    };
+
+    IColourImpl* platformColourInstance() {
+        static Win32ColourImpl s_instance;
+
+        Ptr<IConfig const> config = getCurrentContext().getConfig();
+        UseColour::YesOrNo colourMode = config
+            ? config->useColour()
+            : UseColour::Auto;
+        if( colourMode == UseColour::Auto )
+            colourMode = !isDebuggerActive()
+                ? UseColour::Yes
+                : UseColour::No;
+        return colourMode == UseColour::Yes
+            ? &s_instance
+            : NoColourImpl::instance();
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////
+
+#include <unistd.h>
+
+namespace Catch {
+namespace {
+
+    // use POSIX/ ANSI console terminal codes
+    // Thanks to Adam Strzelecki for original contribution
+    // (http://github.com/nanoant)
+    // https://github.com/philsquared/Catch/pull/131
+    class PosixColourImpl : public IColourImpl {
+    public:
+        virtual void use( Colour::Code _colourCode ) {
+            switch( _colourCode ) {
+                case Colour::None:
+                case Colour::White:     return setColour( "[0m" );
+                case Colour::Red:       return setColour( "[0;31m" );
+                case Colour::Green:     return setColour( "[0;32m" );
+                case Colour::Blue:      return setColour( "[0;34m" );
+                case Colour::Cyan:      return setColour( "[0;36m" );
+                case Colour::Yellow:    return setColour( "[0;33m" );
+                case Colour::Grey:      return setColour( "[1;30m" );
+
+                case Colour::LightGrey:     return setColour( "[0;37m" );
+                case Colour::BrightRed:     return setColour( "[1;31m" );
+                case Colour::BrightGreen:   return setColour( "[1;32m" );
+                case Colour::BrightWhite:   return setColour( "[1;37m" );
+
+                case Colour::Bright: throw std::logic_error( "not a colour" );
+            }
+        }
+        static IColourImpl* instance() {
+            static PosixColourImpl s_instance;
+            return &s_instance;
+        }
+
+    private:
+        void setColour( const char* _escapeCode ) {
+            Catch::cout() << '\033' << _escapeCode;
+        }
+    };
+
+    IColourImpl* platformColourInstance() {
+        ErrnoGuard guard;
+        Ptr<IConfig const> config = getCurrentContext().getConfig();
+        UseColour::YesOrNo colourMode = config
+            ? config->useColour()
+            : UseColour::Auto;
+        if( colourMode == UseColour::Auto )
+            colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) )
+                ? UseColour::Yes
+                : UseColour::No;
+        return colourMode == UseColour::Yes
+            ? PosixColourImpl::instance()
+            : NoColourImpl::instance();
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#else  // not Windows or ANSI ///////////////////////////////////////////////
+
+namespace Catch {
+
+    static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
+
+} // end namespace Catch
+
+#endif // Windows/ ANSI/ None
+
+namespace Catch {
+
+    Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
+    Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
+    Colour::~Colour(){ if( !m_moved ) use( None ); }
+
+    void Colour::use( Code _colourCode ) {
+        static IColourImpl* impl = platformColourInstance();
+        impl->use( _colourCode );
+    }
+
+} // end namespace Catch
+
+// #included from: catch_generators_impl.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <map>
+
+namespace Catch {
+
+    struct GeneratorInfo : IGeneratorInfo {
+
+        GeneratorInfo( std::size_t size )
+        :   m_size( size ),
+            m_currentIndex( 0 )
+        {}
+
+        bool moveNext() {
+            if( ++m_currentIndex == m_size ) {
+                m_currentIndex = 0;
+                return false;
+            }
+            return true;
+        }
+
+        std::size_t getCurrentIndex() const {
+            return m_currentIndex;
+        }
+
+        std::size_t m_size;
+        std::size_t m_currentIndex;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class GeneratorsForTest : public IGeneratorsForTest {
+
+    public:
+        ~GeneratorsForTest() {
+            deleteAll( m_generatorsInOrder );
+        }
+
+        IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
+            std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
+            if( it == m_generatorsByName.end() ) {
+                IGeneratorInfo* info = new GeneratorInfo( size );
+                m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
+                m_generatorsInOrder.push_back( info );
+                return *info;
+            }
+            return *it->second;
+        }
+
+        bool moveNext() {
+            std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
+            std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
+            for(; it != itEnd; ++it ) {
+                if( (*it)->moveNext() )
+                    return true;
+            }
+            return false;
+        }
+
+    private:
+        std::map<std::string, IGeneratorInfo*> m_generatorsByName;
+        std::vector<IGeneratorInfo*> m_generatorsInOrder;
+    };
+
+    IGeneratorsForTest* createGeneratorsForTest()
+    {
+        return new GeneratorsForTest();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.hpp
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
+
+namespace Catch {
+
+    AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){}
+
+    AssertionInfo::AssertionInfo(   char const * _macroName,
+                                    SourceLineInfo const& _lineInfo,
+                                    char const * _capturedExpression,
+                                    ResultDisposition::Flags _resultDisposition,
+                                    char const * _secondArg)
+    :   macroName( _macroName ),
+        lineInfo( _lineInfo ),
+        capturedExpression( _capturedExpression ),
+        resultDisposition( _resultDisposition ),
+        secondArg( _secondArg )
+    {}
+
+    AssertionResult::AssertionResult() {}
+
+    AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
+    :   m_info( info ),
+        m_resultData( data )
+    {}
+
+    AssertionResult::~AssertionResult() {}
+
+    // Result was a success
+    bool AssertionResult::succeeded() const {
+        return Catch::isOk( m_resultData.resultType );
+    }
+
+    // Result was a success, or failure is suppressed
+    bool AssertionResult::isOk() const {
+        return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
+    }
+
+    ResultWas::OfType AssertionResult::getResultType() const {
+        return m_resultData.resultType;
+    }
+
+    bool AssertionResult::hasExpression() const {
+        return m_info.capturedExpression[0] != 0;
+    }
+
+    bool AssertionResult::hasMessage() const {
+        return !m_resultData.message.empty();
+    }
+
+    std::string capturedExpressionWithSecondArgument( char const * capturedExpression, char const * secondArg ) {
+        return (secondArg[0] == 0 || secondArg[0] == '"' && secondArg[1] == '"')
+            ? capturedExpression
+            : std::string(capturedExpression) + ", " + secondArg;
+    }
+
+    std::string AssertionResult::getExpression() const {
+        if( isFalseTest( m_info.resultDisposition ) )
+            return "!(" + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + ")";
+        else
+            return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
+    }
+    std::string AssertionResult::getExpressionInMacro() const {
+        if( m_info.macroName[0] == 0 )
+            return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
+        else
+            return std::string(m_info.macroName) + "( " + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + " )";
+    }
+
+    bool AssertionResult::hasExpandedExpression() const {
+        return hasExpression() && getExpandedExpression() != getExpression();
+    }
+
+    std::string AssertionResult::getExpandedExpression() const {
+        return m_resultData.reconstructExpression();
+    }
+
+    std::string AssertionResult::getMessage() const {
+        return m_resultData.message;
+    }
+    SourceLineInfo AssertionResult::getSourceInfo() const {
+        return m_info.lineInfo;
+    }
+
+    std::string AssertionResult::getTestMacroName() const {
+        return m_info.macroName;
+    }
+
+    void AssertionResult::discardDecomposedExpression() const {
+        m_resultData.decomposedExpression = CATCH_NULL;
+    }
+
+    void AssertionResult::expandDecomposedExpression() const {
+        m_resultData.reconstructExpression();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_test_case_info.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
+
+#include <cctype>
+
+namespace Catch {
+
+    inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
+        if( startsWith( tag, '.' ) ||
+            tag == "hide" ||
+            tag == "!hide" )
+            return TestCaseInfo::IsHidden;
+        else if( tag == "!throws" )
+            return TestCaseInfo::Throws;
+        else if( tag == "!shouldfail" )
+            return TestCaseInfo::ShouldFail;
+        else if( tag == "!mayfail" )
+            return TestCaseInfo::MayFail;
+        else if( tag == "!nonportable" )
+            return TestCaseInfo::NonPortable;
+        else
+            return TestCaseInfo::None;
+    }
+    inline bool isReservedTag( std::string const& tag ) {
+        return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] );
+    }
+    inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
+        if( isReservedTag( tag ) ) {
+            std::ostringstream ss;
+            ss << Colour(Colour::Red)
+               << "Tag name [" << tag << "] not allowed.\n"
+               << "Tag names starting with non alpha-numeric characters are reserved\n"
+               << Colour(Colour::FileName)
+               << _lineInfo << '\n';
+            throw std::runtime_error(ss.str());
+        }
+    }
+
+    TestCase makeTestCase(  ITestCase* _testCase,
+                            std::string const& _className,
+                            std::string const& _name,
+                            std::string const& _descOrTags,
+                            SourceLineInfo const& _lineInfo )
+    {
+        bool isHidden( startsWith( _name, "./" ) ); // Legacy support
+
+        // Parse out tags
+        std::set<std::string> tags;
+        std::string desc, tag;
+        bool inTag = false;
+        for( std::size_t i = 0; i < _descOrTags.size(); ++i ) {
+            char c = _descOrTags[i];
+            if( !inTag ) {
+                if( c == '[' )
+                    inTag = true;
+                else
+                    desc += c;
+            }
+            else {
+                if( c == ']' ) {
+                    TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );
+                    if( prop == TestCaseInfo::IsHidden )
+                        isHidden = true;
+                    else if( prop == TestCaseInfo::None )
+                        enforceNotReservedTag( tag, _lineInfo );
+
+                    tags.insert( tag );
+                    tag.clear();
+                    inTag = false;
+                }
+                else
+                    tag += c;
+            }
+        }
+        if( isHidden ) {
+            tags.insert( "hide" );
+            tags.insert( "." );
+        }
+
+        TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
+        return TestCase( _testCase, info );
+    }
+
+    void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags )
+    {
+        testCaseInfo.tags = tags;
+        testCaseInfo.lcaseTags.clear();
+
+        std::ostringstream oss;
+        for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) {
+            oss << '[' << *it << ']';
+            std::string lcaseTag = toLower( *it );
+            testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
+            testCaseInfo.lcaseTags.insert( lcaseTag );
+        }
+        testCaseInfo.tagsAsString = oss.str();
+    }
+
+    TestCaseInfo::TestCaseInfo( std::string const& _name,
+                                std::string const& _className,
+                                std::string const& _description,
+                                std::set<std::string> const& _tags,
+                                SourceLineInfo const& _lineInfo )
+    :   name( _name ),
+        className( _className ),
+        description( _description ),
+        lineInfo( _lineInfo ),
+        properties( None )
+    {
+        setTags( *this, _tags );
+    }
+
+    TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
+    :   name( other.name ),
+        className( other.className ),
+        description( other.description ),
+        tags( other.tags ),
+        lcaseTags( other.lcaseTags ),
+        tagsAsString( other.tagsAsString ),
+        lineInfo( other.lineInfo ),
+        properties( other.properties )
+    {}
+
+    bool TestCaseInfo::isHidden() const {
+        return ( properties & IsHidden ) != 0;
+    }
+    bool TestCaseInfo::throws() const {
+        return ( properties & Throws ) != 0;
+    }
+    bool TestCaseInfo::okToFail() const {
+        return ( properties & (ShouldFail | MayFail ) ) != 0;
+    }
+    bool TestCaseInfo::expectedToFail() const {
+        return ( properties & (ShouldFail ) ) != 0;
+    }
+
+    TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
+
+    TestCase::TestCase( TestCase const& other )
+    :   TestCaseInfo( other ),
+        test( other.test )
+    {}
+
+    TestCase TestCase::withName( std::string const& _newName ) const {
+        TestCase other( *this );
+        other.name = _newName;
+        return other;
+    }
+
+    void TestCase::swap( TestCase& other ) {
+        test.swap( other.test );
+        name.swap( other.name );
+        className.swap( other.className );
+        description.swap( other.description );
+        tags.swap( other.tags );
+        lcaseTags.swap( other.lcaseTags );
+        tagsAsString.swap( other.tagsAsString );
+        std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties );
+        std::swap( lineInfo, other.lineInfo );
+    }
+
+    void TestCase::invoke() const {
+        test->invoke();
+    }
+
+    bool TestCase::operator == ( TestCase const& other ) const {
+        return  test.get() == other.test.get() &&
+                name == other.name &&
+                className == other.className;
+    }
+
+    bool TestCase::operator < ( TestCase const& other ) const {
+        return name < other.name;
+    }
+    TestCase& TestCase::operator = ( TestCase const& other ) {
+        TestCase temp( other );
+        swap( temp );
+        return *this;
+    }
+
+    TestCaseInfo const& TestCase::getTestCaseInfo() const
+    {
+        return *this;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_version.hpp
+#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
+
+namespace Catch {
+
+    Version::Version
+        (   unsigned int _majorVersion,
+            unsigned int _minorVersion,
+            unsigned int _patchNumber,
+            char const * const _branchName,
+            unsigned int _buildNumber )
+    :   majorVersion( _majorVersion ),
+        minorVersion( _minorVersion ),
+        patchNumber( _patchNumber ),
+        branchName( _branchName ),
+        buildNumber( _buildNumber )
+    {}
+
+    std::ostream& operator << ( std::ostream& os, Version const& version ) {
+        os  << version.majorVersion << '.'
+            << version.minorVersion << '.'
+            << version.patchNumber;
+        // branchName is never null -> 0th char is \0 if it is empty
+        if (version.branchName[0]) {
+            os << '-' << version.branchName
+               << '.' << version.buildNumber;
+        }
+        return os;
+    }
+
+    inline Version libraryVersion() {
+        static Version version( 1, 12, 0, "", 0 );
+        return version;
+    }
+
+}
+
+// #included from: catch_message.hpp
+#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
+
+namespace Catch {
+
+    MessageInfo::MessageInfo(   std::string const& _macroName,
+                                SourceLineInfo const& _lineInfo,
+                                ResultWas::OfType _type )
+    :   macroName( _macroName ),
+        lineInfo( _lineInfo ),
+        type( _type ),
+        sequence( ++globalCount )
+    {}
+
+    // This may need protecting if threading support is added
+    unsigned int MessageInfo::globalCount = 0;
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    ScopedMessage::ScopedMessage( MessageBuilder const& builder )
+    : m_info( builder.m_info )
+    {
+        m_info.message = builder.m_stream.str();
+        getResultCapture().pushScopedMessage( m_info );
+    }
+    ScopedMessage::ScopedMessage( ScopedMessage const& other )
+    : m_info( other.m_info )
+    {}
+
+    ScopedMessage::~ScopedMessage() {
+        if ( !std::uncaught_exception() ){
+            getResultCapture().popScopedMessage(m_info);
+        }
+    }
+
+} // end namespace Catch
+
+// #included from: catch_legacy_reporter_adapter.hpp
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
+
+// #included from: catch_legacy_reporter_adapter.h
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
+
+namespace Catch
+{
+    // Deprecated
+    struct IReporter : IShared {
+        virtual ~IReporter();
+
+        virtual bool shouldRedirectStdout() const = 0;
+
+        virtual void StartTesting() = 0;
+        virtual void EndTesting( Totals const& totals ) = 0;
+        virtual void StartGroup( std::string const& groupName ) = 0;
+        virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
+        virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
+        virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
+        virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
+        virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
+        virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
+        virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
+        virtual void Aborted() = 0;
+        virtual void Result( AssertionResult const& result ) = 0;
+    };
+
+    class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
+    {
+    public:
+        LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
+        virtual ~LegacyReporterAdapter();
+
+        virtual ReporterPreferences getPreferences() const;
+        virtual void noMatchingTestCases( std::string const& );
+        virtual void testRunStarting( TestRunInfo const& );
+        virtual void testGroupStarting( GroupInfo const& groupInfo );
+        virtual void testCaseStarting( TestCaseInfo const& testInfo );
+        virtual void sectionStarting( SectionInfo const& sectionInfo );
+        virtual void assertionStarting( AssertionInfo const& );
+        virtual bool assertionEnded( AssertionStats const& assertionStats );
+        virtual void sectionEnded( SectionStats const& sectionStats );
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats );
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats );
+        virtual void testRunEnded( TestRunStats const& testRunStats );
+        virtual void skipTest( TestCaseInfo const& );
+
+    private:
+        Ptr<IReporter> m_legacyReporter;
+    };
+}
+
+namespace Catch
+{
+    LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
+    :   m_legacyReporter( legacyReporter )
+    {}
+    LegacyReporterAdapter::~LegacyReporterAdapter() {}
+
+    ReporterPreferences LegacyReporterAdapter::getPreferences() const {
+        ReporterPreferences prefs;
+        prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
+        return prefs;
+    }
+
+    void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
+    void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
+        m_legacyReporter->StartTesting();
+    }
+    void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
+        m_legacyReporter->StartGroup( groupInfo.name );
+    }
+    void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
+        m_legacyReporter->StartTestCase( testInfo );
+    }
+    void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
+        m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
+    }
+    void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
+        // Not on legacy interface
+    }
+
+    bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
+        if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
+            for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+                    it != itEnd;
+                    ++it ) {
+                if( it->type == ResultWas::Info ) {
+                    ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal );
+                    rb << it->message;
+                    rb.setResultType( ResultWas::Info );
+                    AssertionResult result = rb.build();
+                    m_legacyReporter->Result( result );
+                }
+            }
+        }
+        m_legacyReporter->Result( assertionStats.assertionResult );
+        return true;
+    }
+    void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
+        if( sectionStats.missingAssertions )
+            m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
+        m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
+    }
+    void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+        m_legacyReporter->EndTestCase
+            (   testCaseStats.testInfo,
+                testCaseStats.totals,
+                testCaseStats.stdOut,
+                testCaseStats.stdErr );
+    }
+    void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+        if( testGroupStats.aborting )
+            m_legacyReporter->Aborted();
+        m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
+    }
+    void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
+        m_legacyReporter->EndTesting( testRunStats.totals );
+    }
+    void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) {
+    }
+}
+
+// #included from: catch_timer.hpp
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#endif
+
+#ifdef CATCH_PLATFORM_WINDOWS
+
+#else
+
+#include <sys/time.h>
+
+#endif
+
+namespace Catch {
+
+    namespace {
+#ifdef CATCH_PLATFORM_WINDOWS
+        UInt64 getCurrentTicks() {
+            static UInt64 hz=0, hzo=0;
+            if (!hz) {
+                QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) );
+                QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) );
+            }
+            UInt64 t;
+            QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) );
+            return ((t-hzo)*1000000)/hz;
+        }
+#else
+        UInt64 getCurrentTicks() {
+            timeval t;
+            gettimeofday(&t,CATCH_NULL);
+            return static_cast<UInt64>( t.tv_sec ) * 1000000ull + static_cast<UInt64>( t.tv_usec );
+        }
+#endif
+    }
+
+    void Timer::start() {
+        m_ticks = getCurrentTicks();
+    }
+    unsigned int Timer::getElapsedMicroseconds() const {
+        return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
+    }
+    unsigned int Timer::getElapsedMilliseconds() const {
+        return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
+    }
+    double Timer::getElapsedSeconds() const {
+        return getElapsedMicroseconds()/1000000.0;
+    }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+// #included from: catch_common.hpp
+#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+
+#include <cstring>
+#include <cctype>
+
+namespace Catch {
+
+    bool startsWith( std::string const& s, std::string const& prefix ) {
+        return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
+    }
+    bool startsWith( std::string const& s, char prefix ) {
+        return !s.empty() && s[0] == prefix;
+    }
+    bool endsWith( std::string const& s, std::string const& suffix ) {
+        return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
+    }
+    bool endsWith( std::string const& s, char suffix ) {
+        return !s.empty() && s[s.size()-1] == suffix;
+    }
+    bool contains( std::string const& s, std::string const& infix ) {
+        return s.find( infix ) != std::string::npos;
+    }
+    char toLowerCh(char c) {
+        return static_cast<char>( std::tolower( c ) );
+    }
+    void toLowerInPlace( std::string& s ) {
+        std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
+    }
+    std::string toLower( std::string const& s ) {
+        std::string lc = s;
+        toLowerInPlace( lc );
+        return lc;
+    }
+    std::string trim( std::string const& str ) {
+        static char const* whitespaceChars = "\n\r\t ";
+        std::string::size_type start = str.find_first_not_of( whitespaceChars );
+        std::string::size_type end = str.find_last_not_of( whitespaceChars );
+
+        return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
+    }
+
+    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
+        bool replaced = false;
+        std::size_t i = str.find( replaceThis );
+        while( i != std::string::npos ) {
+            replaced = true;
+            str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
+            if( i < str.size()-withThis.size() )
+                i = str.find( replaceThis, i+withThis.size() );
+            else
+                i = std::string::npos;
+        }
+        return replaced;
+    }
+
+    pluralise::pluralise( std::size_t count, std::string const& label )
+    :   m_count( count ),
+        m_label( label )
+    {}
+
+    std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
+        os << pluraliser.m_count << ' ' << pluraliser.m_label;
+        if( pluraliser.m_count != 1 )
+            os << 's';
+        return os;
+    }
+
+    SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){}
+    SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
+    :   file( _file ),
+        line( _line )
+    {}
+    bool SourceLineInfo::empty() const {
+        return file[0] == '\0';
+    }
+    bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
+        return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
+    }
+    bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
+        return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
+    }
+
+    void seedRng( IConfig const& config ) {
+        if( config.rngSeed() != 0 )
+            std::srand( config.rngSeed() );
+    }
+    unsigned int rngSeed() {
+        return getCurrentContext().getConfig()->rngSeed();
+    }
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
+#ifndef __GNUG__
+        os << info.file << '(' << info.line << ')';
+#else
+        os << info.file << ':' << info.line;
+#endif
+        return os;
+    }
+
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
+        std::ostringstream oss;
+        oss << locationInfo << ": Internal Catch error: '" << message << '\'';
+        if( alwaysTrue() )
+            throw std::logic_error( oss.str() );
+    }
+}
+
+// #included from: catch_section.hpp
+#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
+
+namespace Catch {
+
+    SectionInfo::SectionInfo
+        (   SourceLineInfo const& _lineInfo,
+            std::string const& _name,
+            std::string const& _description )
+    :   name( _name ),
+        description( _description ),
+        lineInfo( _lineInfo )
+    {}
+
+    Section::Section( SectionInfo const& info )
+    :   m_info( info ),
+        m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
+    {
+        m_timer.start();
+    }
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17
+#endif
+    Section::~Section() {
+        if( m_sectionIncluded ) {
+            SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
+            if( std::uncaught_exception() )
+                getResultCapture().sectionEndedEarly( endInfo );
+            else
+                getResultCapture().sectionEnded( endInfo );
+        }
+    }
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+    // This indicates whether the section should be executed or not
+    Section::operator bool() const {
+        return m_sectionIncluded;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_debugger.hpp
+#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
+
+#ifdef CATCH_PLATFORM_MAC
+
+    #include <assert.h>
+    #include <stdbool.h>
+    #include <sys/types.h>
+    #include <unistd.h>
+    #include <sys/sysctl.h>
+
+    namespace Catch{
+
+        // The following function is taken directly from the following technical note:
+        // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
+
+        // Returns true if the current process is being debugged (either
+        // running under the debugger or has a debugger attached post facto).
+        bool isDebuggerActive(){
+
+            int                 mib[4];
+            struct kinfo_proc   info;
+            size_t              size;
+
+            // Initialize the flags so that, if sysctl fails for some bizarre
+            // reason, we get a predictable result.
+
+            info.kp_proc.p_flag = 0;
+
+            // Initialize mib, which tells sysctl the info we want, in this case
+            // we're looking for information about a specific process ID.
+
+            mib[0] = CTL_KERN;
+            mib[1] = KERN_PROC;
+            mib[2] = KERN_PROC_PID;
+            mib[3] = getpid();
+
+            // Call sysctl.
+
+            size = sizeof(info);
+            if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) {
+                Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
+                return false;
+            }
+
+            // We're being debugged if the P_TRACED flag is set.
+
+            return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
+        }
+    } // namespace Catch
+
+#elif defined(CATCH_PLATFORM_LINUX)
+    #include <fstream>
+    #include <string>
+
+    namespace Catch{
+        // The standard POSIX way of detecting a debugger is to attempt to
+        // ptrace() the process, but this needs to be done from a child and not
+        // this process itself to still allow attaching to this process later
+        // if wanted, so is rather heavy. Under Linux we have the PID of the
+        // "debugger" (which doesn't need to be gdb, of course, it could also
+        // be strace, for example) in /proc/$PID/status, so just get it from
+        // there instead.
+        bool isDebuggerActive(){
+            // Libstdc++ has a bug, where std::ifstream sets errno to 0
+            // This way our users can properly assert over errno values
+            ErrnoGuard guard;
+            std::ifstream in("/proc/self/status");
+            for( std::string line; std::getline(in, line); ) {
+                static const int PREFIX_LEN = 11;
+                if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
+                    // We're traced if the PID is not 0 and no other PID starts
+                    // with 0 digit, so it's enough to check for just a single
+                    // character.
+                    return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
+                }
+            }
+
+            return false;
+        }
+    } // namespace Catch
+#elif defined(_MSC_VER)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#else
+    namespace Catch {
+       inline bool isDebuggerActive() { return false; }
+    }
+#endif // Platform
+
+#ifdef CATCH_PLATFORM_WINDOWS
+
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            ::OutputDebugStringA( text.c_str() );
+        }
+    }
+#else
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            // !TBD: Need a version for Mac/ XCode and other IDEs
+            Catch::cout() << text;
+        }
+    }
+#endif // Platform
+
+// #included from: catch_tostring.hpp
+#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
+
+namespace Catch {
+
+namespace Detail {
+
+    const std::string unprintableString = "{?}";
+
+    namespace {
+        const int hexThreshold = 255;
+
+        struct Endianness {
+            enum Arch { Big, Little };
+
+            static Arch which() {
+                union _{
+                    int asInt;
+                    char asChar[sizeof (int)];
+                } u;
+
+                u.asInt = 1;
+                return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
+            }
+        };
+    }
+
+    std::string rawMemoryToString( const void *object, std::size_t size )
+    {
+        // Reverse order for little endian architectures
+        int i = 0, end = static_cast<int>( size ), inc = 1;
+        if( Endianness::which() == Endianness::Little ) {
+            i = end-1;
+            end = inc = -1;
+        }
+
+        unsigned char const *bytes = static_cast<unsigned char const *>(object);
+        std::ostringstream os;
+        os << "0x" << std::setfill('0') << std::hex;
+        for( ; i != end; i += inc )
+             os << std::setw(2) << static_cast<unsigned>(bytes[i]);
+       return os.str();
+    }
+}
+
+std::string toString( std::string const& value ) {
+    std::string s = value;
+    if( getCurrentContext().getConfig()->showInvisibles() ) {
+        for(size_t i = 0; i < s.size(); ++i ) {
+            std::string subs;
+            switch( s[i] ) {
+            case '\n': subs = "\\n"; break;
+            case '\t': subs = "\\t"; break;
+            default: break;
+            }
+            if( !subs.empty() ) {
+                s = s.substr( 0, i ) + subs + s.substr( i+1 );
+                ++i;
+            }
+        }
+    }
+    return '"' + s + '"';
+}
+std::string toString( std::wstring const& value ) {
+
+    std::string s;
+    s.reserve( value.size() );
+    for(size_t i = 0; i < value.size(); ++i )
+        s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
+    return Catch::toString( s );
+}
+
+std::string toString( const char* const value ) {
+    return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
+}
+
+std::string toString( char* const value ) {
+    return Catch::toString( static_cast<const char*>( value ) );
+}
+
+std::string toString( const wchar_t* const value )
+{
+    return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
+}
+
+std::string toString( wchar_t* const value )
+{
+    return Catch::toString( static_cast<const wchar_t*>( value ) );
+}
+
+std::string toString( int value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+
+std::string toString( unsigned long value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+
+std::string toString( unsigned int value ) {
+    return Catch::toString( static_cast<unsigned long>( value ) );
+}
+
+template<typename T>
+std::string fpToString( T value, int precision ) {
+    std::ostringstream oss;
+    oss << std::setprecision( precision )
+        << std::fixed
+        << value;
+    std::string d = oss.str();
+    std::size_t i = d.find_last_not_of( '0' );
+    if( i != std::string::npos && i != d.size()-1 ) {
+        if( d[i] == '.' )
+            i++;
+        d = d.substr( 0, i+1 );
+    }
+    return d;
+}
+
+std::string toString( const double value ) {
+    return fpToString( value, 10 );
+}
+std::string toString( const float value ) {
+    return fpToString( value, 5 ) + 'f';
+}
+
+std::string toString( bool value ) {
+    return value ? "true" : "false";
+}
+
+std::string toString( char value ) {
+    if ( value == '\r' )
+        return "'\\r'";
+    if ( value == '\f' )
+        return "'\\f'";
+    if ( value == '\n' )
+        return "'\\n'";
+    if ( value == '\t' )
+        return "'\\t'";
+    if ( '\0' <= value && value < ' ' )
+        return toString( static_cast<unsigned int>( value ) );
+    char chstr[] = "' '";
+    chstr[1] = value;
+    return chstr;
+}
+
+std::string toString( signed char value ) {
+    return toString( static_cast<char>( value ) );
+}
+
+std::string toString( unsigned char value ) {
+    return toString( static_cast<char>( value ) );
+}
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString( long long value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+std::string toString( unsigned long long value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t ) {
+    return "nullptr";
+}
+#endif
+
+#ifdef __OBJC__
+    std::string toString( NSString const * const& nsstring ) {
+        if( !nsstring )
+            return "nil";
+        return "@" + toString([nsstring UTF8String]);
+    }
+    std::string toString( NSString * CATCH_ARC_STRONG & nsstring ) {
+        if( !nsstring )
+            return "nil";
+        return "@" + toString([nsstring UTF8String]);
+    }
+    std::string toString( NSObject* const& nsObject ) {
+        return toString( [nsObject description] );
+    }
+#endif
+
+} // end namespace Catch
+
+// #included from: catch_result_builder.hpp
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
+
+namespace Catch {
+
+    ResultBuilder::ResultBuilder(   char const* macroName,
+                                    SourceLineInfo const& lineInfo,
+                                    char const* capturedExpression,
+                                    ResultDisposition::Flags resultDisposition,
+                                    char const* secondArg )
+    :   m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ),
+        m_shouldDebugBreak( false ),
+        m_shouldThrow( false ),
+        m_guardException( false ),
+        m_usedStream( false )
+    {}
+
+    ResultBuilder::~ResultBuilder() {
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+        if ( m_guardException ) {
+            stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
+            captureResult( ResultWas::ThrewException );
+            getCurrentContext().getResultCapture()->exceptionEarlyReported();
+        }
+#endif
+    }
+
+    ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
+        m_data.resultType = result;
+        return *this;
+    }
+    ResultBuilder& ResultBuilder::setResultType( bool result ) {
+        m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
+        return *this;
+    }
+
+    void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
+        // Flip bool results if FalseTest flag is set
+        if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
+            m_data.negate( expr.isBinaryExpression() );
+        }
+
+        getResultCapture().assertionRun();
+
+        if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok)
+        {
+            AssertionResult result = build( expr );
+            handleResult( result );
+        }
+        else
+            getResultCapture().assertionPassed();
+    }
+
+    void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
+        m_assertionInfo.resultDisposition = resultDisposition;
+        stream().oss << Catch::translateActiveException();
+        captureResult( ResultWas::ThrewException );
+    }
+
+    void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
+        setResultType( resultType );
+        captureExpression();
+    }
+
+    void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
+        if( expectedMessage.empty() )
+            captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() );
+        else
+            captureExpectedException( Matchers::Equals( expectedMessage ) );
+    }
+
+    void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) {
+
+        assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
+        AssertionResultData data = m_data;
+        data.resultType = ResultWas::Ok;
+        data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
+
+        std::string actualMessage = Catch::translateActiveException();
+        if( !matcher.match( actualMessage ) ) {
+            data.resultType = ResultWas::ExpressionFailed;
+            data.reconstructedExpression = actualMessage;
+        }
+        AssertionResult result( m_assertionInfo, data );
+        handleResult( result );
+    }
+
+    void ResultBuilder::captureExpression() {
+        AssertionResult result = build();
+        handleResult( result );
+    }
+
+    void ResultBuilder::handleResult( AssertionResult const& result )
+    {
+        getResultCapture().assertionEnded( result );
+
+        if( !result.isOk() ) {
+            if( getCurrentContext().getConfig()->shouldDebugBreak() )
+                m_shouldDebugBreak = true;
+            if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) )
+                m_shouldThrow = true;
+        }
+    }
+
+    void ResultBuilder::react() {
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+        if (m_shouldDebugBreak) {
+            ///////////////////////////////////////////////////////////////////
+            // To inspect the state during test, you need to go one level up the callstack
+            // To go back to the test and change execution, jump over the throw statement
+            ///////////////////////////////////////////////////////////////////
+            CATCH_BREAK_INTO_DEBUGGER();
+        }
+#endif
+        if( m_shouldThrow )
+            throw Catch::TestFailureException();
+    }
+
+    bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
+    bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
+
+    AssertionResult ResultBuilder::build() const
+    {
+        return build( *this );
+    }
+
+    // CAVEAT: The returned AssertionResult stores a pointer to the argument expr,
+    //         a temporary DecomposedExpression, which in turn holds references to
+    //         operands, possibly temporary as well.
+    //         It should immediately be passed to handleResult; if the expression
+    //         needs to be reported, its string expansion must be composed before
+    //         the temporaries are destroyed.
+    AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const
+    {
+        assert( m_data.resultType != ResultWas::Unknown );
+        AssertionResultData data = m_data;
+
+        if(m_usedStream)
+            data.message = m_stream().oss.str();
+        data.decomposedExpression = &expr; // for lazy reconstruction
+        return AssertionResult( m_assertionInfo, data );
+    }
+
+    void ResultBuilder::reconstructExpression( std::string& dest ) const {
+        dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
+    }
+
+    void ResultBuilder::setExceptionGuard() {
+        m_guardException = true;
+    }
+    void ResultBuilder::unsetExceptionGuard() {
+        m_guardException = false;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_tag_alias_registry.hpp
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+namespace Catch {
+
+    TagAliasRegistry::~TagAliasRegistry() {}
+
+    Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const {
+        std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias );
+        if( it != m_registry.end() )
+            return it->second;
+        else
+            return Option<TagAlias>();
+    }
+
+    std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
+        std::string expandedTestSpec = unexpandedTestSpec;
+        for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
+                it != itEnd;
+                ++it ) {
+            std::size_t pos = expandedTestSpec.find( it->first );
+            if( pos != std::string::npos ) {
+                expandedTestSpec =  expandedTestSpec.substr( 0, pos ) +
+                                    it->second.tag +
+                                    expandedTestSpec.substr( pos + it->first.size() );
+            }
+        }
+        return expandedTestSpec;
+    }
+
+    void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
+
+        if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
+            std::ostringstream oss;
+            oss << Colour( Colour::Red )
+                << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n"
+                << Colour( Colour::FileName )
+                << lineInfo << '\n';
+            throw std::domain_error( oss.str().c_str() );
+        }
+        if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
+            std::ostringstream oss;
+            oss << Colour( Colour::Red )
+                << "error: tag alias, \"" << alias << "\" already registered.\n"
+                << "\tFirst seen at "
+                << Colour( Colour::Red ) << find(alias)->lineInfo << '\n'
+                << Colour( Colour::Red ) << "\tRedefined at "
+                << Colour( Colour::FileName) << lineInfo << '\n';
+            throw std::domain_error( oss.str().c_str() );
+        }
+    }
+
+    ITagAliasRegistry::~ITagAliasRegistry() {}
+
+    ITagAliasRegistry const& ITagAliasRegistry::get() {
+        return getRegistryHub().getTagAliasRegistry();
+    }
+
+    RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
+        getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo );
+    }
+
+} // end namespace Catch
+
+// #included from: catch_matchers_string.hpp
+
+namespace Catch {
+namespace Matchers {
+
+    namespace StdString {
+
+        CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
+        :   m_caseSensitivity( caseSensitivity ),
+            m_str( adjustString( str ) )
+        {}
+        std::string CasedString::adjustString( std::string const& str ) const {
+            return m_caseSensitivity == CaseSensitive::No
+                   ? toLower( str )
+                   : str;
+        }
+        std::string CasedString::caseSensitivitySuffix() const {
+            return m_caseSensitivity == CaseSensitive::No
+                   ? " (case insensitive)"
+                   : std::string();
+        }
+
+        StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )
+        : m_comparator( comparator ),
+          m_operation( operation ) {
+        }
+
+        std::string StringMatcherBase::describe() const {
+            std::string description;
+            description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
+                                        m_comparator.caseSensitivitySuffix().size());
+            description += m_operation;
+            description += ": \"";
+            description += m_comparator.m_str;
+            description += "\"";
+            description += m_comparator.caseSensitivitySuffix();
+            return description;
+        }
+
+        EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}
+
+        bool EqualsMatcher::match( std::string const& source ) const {
+            return m_comparator.adjustString( source ) == m_comparator.m_str;
+        }
+
+        ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}
+
+        bool ContainsMatcher::match( std::string const& source ) const {
+            return contains( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+        StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}
+
+        bool StartsWithMatcher::match( std::string const& source ) const {
+            return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+        EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}
+
+        bool EndsWithMatcher::match( std::string const& source ) const {
+            return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+    } // namespace StdString
+
+    StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+
+} // namespace Matchers
+} // namespace Catch
+// #included from: ../reporters/catch_reporter_multi.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED
+
+namespace Catch {
+
+class MultipleReporters : public SharedImpl<IStreamingReporter> {
+    typedef std::vector<Ptr<IStreamingReporter> > Reporters;
+    Reporters m_reporters;
+
+public:
+    void add( Ptr<IStreamingReporter> const& reporter ) {
+        m_reporters.push_back( reporter );
+    }
+
+public: // IStreamingReporter
+
+    virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+        return m_reporters[0]->getPreferences();
+    }
+
+    virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->noMatchingTestCases( spec );
+    }
+
+    virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testRunStarting( testRunInfo );
+    }
+
+    virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testGroupStarting( groupInfo );
+    }
+
+    virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testCaseStarting( testInfo );
+    }
+
+    virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->sectionStarting( sectionInfo );
+    }
+
+    virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->assertionStarting( assertionInfo );
+    }
+
+    // The return value indicates if the messages buffer should be cleared:
+    virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+        bool clearBuffer = false;
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            clearBuffer |= (*it)->assertionEnded( assertionStats );
+        return clearBuffer;
+    }
+
+    virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->sectionEnded( sectionStats );
+    }
+
+    virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testCaseEnded( testCaseStats );
+    }
+
+    virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testGroupEnded( testGroupStats );
+    }
+
+    virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testRunEnded( testRunStats );
+    }
+
+    virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->skipTest( testInfo );
+    }
+
+    virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE {
+        return this;
+    }
+
+};
+
+Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
+    Ptr<IStreamingReporter> resultingReporter;
+
+    if( existingReporter ) {
+        MultipleReporters* multi = existingReporter->tryAsMulti();
+        if( !multi ) {
+            multi = new MultipleReporters;
+            resultingReporter = Ptr<IStreamingReporter>( multi );
+            if( existingReporter )
+                multi->add( existingReporter );
+        }
+        else
+            resultingReporter = existingReporter;
+        multi->add( additionalReporter );
+    }
+    else
+        resultingReporter = additionalReporter;
+
+    return resultingReporter;
+}
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_xml.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
+
+// #included from: catch_reporter_bases.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+
+#include <cstring>
+#include <cfloat>
+#include <cstdio>
+#include <assert.h>
+
+namespace Catch {
+
+    namespace {
+        // Because formatting using c++ streams is stateful, drop down to C is required
+        // Alternatively we could use stringstream, but its performance is... not good.
+        std::string getFormattedDuration( double duration ) {
+            // Max exponent + 1 is required to represent the whole part
+            // + 1 for decimal point
+            // + 3 for the 3 decimal places
+            // + 1 for null terminator
+            const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
+            char buffer[maxDoubleSize];
+
+            // Save previous errno, to prevent sprintf from overwriting it
+            ErrnoGuard guard;
+#ifdef _MSC_VER
+            sprintf_s(buffer, "%.3f", duration);
+#else
+            sprintf(buffer, "%.3f", duration);
+#endif
+            return std::string(buffer);
+        }
+    }
+
+    struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
+
+        StreamingReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = false;
+        }
+
+        virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+            return m_reporterPrefs;
+        }
+
+        virtual ~StreamingReporterBase() CATCH_OVERRIDE;
+
+        virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {}
+
+        virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE {
+            currentTestRunInfo = _testRunInfo;
+        }
+        virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE {
+            currentGroupInfo = _groupInfo;
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE {
+            currentTestCaseInfo = _testInfo;
+        }
+        virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
+            m_sectionStack.push_back( _sectionInfo );
+        }
+
+        virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE {
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE {
+            currentTestCaseInfo.reset();
+        }
+        virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE {
+            currentGroupInfo.reset();
+        }
+        virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE {
+            currentTestCaseInfo.reset();
+            currentGroupInfo.reset();
+            currentTestRunInfo.reset();
+        }
+
+        virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {
+            // Don't do anything with this by default.
+            // It can optionally be overridden in the derived class.
+        }
+
+        Ptr<IConfig const> m_config;
+        std::ostream& stream;
+
+        LazyStat<TestRunInfo> currentTestRunInfo;
+        LazyStat<GroupInfo> currentGroupInfo;
+        LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+        std::vector<SectionInfo> m_sectionStack;
+        ReporterPreferences m_reporterPrefs;
+    };
+
+    struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
+        template<typename T, typename ChildNodeT>
+        struct Node : SharedImpl<> {
+            explicit Node( T const& _value ) : value( _value ) {}
+            virtual ~Node() {}
+
+            typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
+            T value;
+            ChildNodes children;
+        };
+        struct SectionNode : SharedImpl<> {
+            explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
+            virtual ~SectionNode();
+
+            bool operator == ( SectionNode const& other ) const {
+                return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+            }
+            bool operator == ( Ptr<SectionNode> const& other ) const {
+                return operator==( *other );
+            }
+
+            SectionStats stats;
+            typedef std::vector<Ptr<SectionNode> > ChildSections;
+            typedef std::vector<AssertionStats> Assertions;
+            ChildSections childSections;
+            Assertions assertions;
+            std::string stdOut;
+            std::string stdErr;
+        };
+
+        struct BySectionInfo {
+            BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
+            BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
+            bool operator() ( Ptr<SectionNode> const& node ) const {
+                return ((node->stats.sectionInfo.name == m_other.name) &&
+                        (node->stats.sectionInfo.lineInfo == m_other.lineInfo));
+            }
+        private:
+            void operator=( BySectionInfo const& );
+            SectionInfo const& m_other;
+        };
+
+        typedef Node<TestCaseStats, SectionNode> TestCaseNode;
+        typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
+        typedef Node<TestRunStats, TestGroupNode> TestRunNode;
+
+        CumulativeReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = false;
+        }
+        ~CumulativeReporterBase();
+
+        virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+            return m_reporterPrefs;
+        }
+
+        virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {}
+        virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {}
+
+        virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {}
+
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+            SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
+            Ptr<SectionNode> node;
+            if( m_sectionStack.empty() ) {
+                if( !m_rootSection )
+                    m_rootSection = new SectionNode( incompleteStats );
+                node = m_rootSection;
+            }
+            else {
+                SectionNode& parentNode = *m_sectionStack.back();
+                SectionNode::ChildSections::const_iterator it =
+                    std::find_if(   parentNode.childSections.begin(),
+                                    parentNode.childSections.end(),
+                                    BySectionInfo( sectionInfo ) );
+                if( it == parentNode.childSections.end() ) {
+                    node = new SectionNode( incompleteStats );
+                    parentNode.childSections.push_back( node );
+                }
+                else
+                    node = *it;
+            }
+            m_sectionStack.push_back( node );
+            m_deepestSection = node;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+            assert( !m_sectionStack.empty() );
+            SectionNode& sectionNode = *m_sectionStack.back();
+            sectionNode.assertions.push_back( assertionStats );
+            // AssertionResult holds a pointer to a temporary DecomposedExpression,
+            // which getExpandedExpression() calls to build the expression string.
+            // Our section stack copy of the assertionResult will likely outlive the
+            // temporary, so it must be expanded or discarded now to avoid calling
+            // a destroyed object later.
+            prepareExpandedExpression( sectionNode.assertions.back().assertionResult );
+            return true;
+        }
+        virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+            assert( !m_sectionStack.empty() );
+            SectionNode& node = *m_sectionStack.back();
+            node.stats = sectionStats;
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+            Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
+            assert( m_sectionStack.size() == 0 );
+            node->children.push_back( m_rootSection );
+            m_testCases.push_back( node );
+            m_rootSection.reset();
+
+            assert( m_deepestSection );
+            m_deepestSection->stdOut = testCaseStats.stdOut;
+            m_deepestSection->stdErr = testCaseStats.stdErr;
+        }
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+            Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
+            node->children.swap( m_testCases );
+            m_testGroups.push_back( node );
+        }
+        virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+            Ptr<TestRunNode> node = new TestRunNode( testRunStats );
+            node->children.swap( m_testGroups );
+            m_testRuns.push_back( node );
+            testRunEndedCumulative();
+        }
+        virtual void testRunEndedCumulative() = 0;
+
+        virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
+
+        virtual void prepareExpandedExpression( AssertionResult& result ) const {
+            if( result.isOk() )
+                result.discardDecomposedExpression();
+            else
+                result.expandDecomposedExpression();
+        }
+
+        Ptr<IConfig const> m_config;
+        std::ostream& stream;
+        std::vector<AssertionStats> m_assertions;
+        std::vector<std::vector<Ptr<SectionNode> > > m_sections;
+        std::vector<Ptr<TestCaseNode> > m_testCases;
+        std::vector<Ptr<TestGroupNode> > m_testGroups;
+
+        std::vector<Ptr<TestRunNode> > m_testRuns;
+
+        Ptr<SectionNode> m_rootSection;
+        Ptr<SectionNode> m_deepestSection;
+        std::vector<Ptr<SectionNode> > m_sectionStack;
+        ReporterPreferences m_reporterPrefs;
+
+    };
+
+    template<char C>
+    char const* getLineOfChars() {
+        static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
+        if( !*line ) {
+            std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
+            line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
+        }
+        return line;
+    }
+
+    struct TestEventListenerBase : StreamingReporterBase {
+        TestEventListenerBase( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config )
+        {}
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
+        virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE {
+            return false;
+        }
+    };
+
+} // end namespace Catch
+
+// #included from: ../internal/catch_reporter_registrars.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+
+namespace Catch {
+
+    template<typename T>
+    class LegacyReporterRegistrar {
+
+        class ReporterFactory : public IReporterFactory {
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new LegacyReporterAdapter( new T( config ) );
+            }
+
+            virtual std::string getDescription() const {
+                return T::getDescription();
+            }
+        };
+
+    public:
+
+        LegacyReporterRegistrar( std::string const& name ) {
+            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+        }
+    };
+
+    template<typename T>
+    class ReporterRegistrar {
+
+        class ReporterFactory : public SharedImpl<IReporterFactory> {
+
+            // *** Please Note ***:
+            // - If you end up here looking at a compiler error because it's trying to register
+            // your custom reporter class be aware that the native reporter interface has changed
+            // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
+            // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
+            // However please consider updating to the new interface as the old one is now
+            // deprecated and will probably be removed quite soon!
+            // Please contact me via github if you have any questions at all about this.
+            // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
+            // no idea who is actually using custom reporters at all (possibly no-one!).
+            // The new interface is designed to minimise exposure to interface changes in the future.
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new T( config );
+            }
+
+            virtual std::string getDescription() const {
+                return T::getDescription();
+            }
+        };
+
+    public:
+
+        ReporterRegistrar( std::string const& name ) {
+            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+        }
+    };
+
+    template<typename T>
+    class ListenerRegistrar {
+
+        class ListenerFactory : public SharedImpl<IReporterFactory> {
+
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new T( config );
+            }
+            virtual std::string getDescription() const {
+                return std::string();
+            }
+        };
+
+    public:
+
+        ListenerRegistrar() {
+            getMutableRegistryHub().registerListener( new ListenerFactory() );
+        }
+    };
+}
+
+#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
+    namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+
+#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
+    namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+
+// Deprecated - use the form without INTERNAL_
+#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
+    namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
+
+#define CATCH_REGISTER_LISTENER( listenerType ) \
+    namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
+
+// #included from: ../internal/catch_xmlwriter.hpp
+#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <iomanip>
+
+namespace Catch {
+
+    class XmlEncode {
+    public:
+        enum ForWhat { ForTextNodes, ForAttributes };
+
+        XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes )
+        :   m_str( str ),
+            m_forWhat( forWhat )
+        {}
+
+        void encodeTo( std::ostream& os ) const {
+
+            // Apostrophe escaping not necessary if we always use " to write attributes
+            // (see: http://www.w3.org/TR/xml/#syntax)
+
+            for( std::size_t i = 0; i < m_str.size(); ++ i ) {
+                char c = m_str[i];
+                switch( c ) {
+                    case '<':   os << "<"; break;
+                    case '&':   os << "&"; break;
+
+                    case '>':
+                        // See: http://www.w3.org/TR/xml/#syntax
+                        if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' )
+                            os << ">";
+                        else
+                            os << c;
+                        break;
+
+                    case '\"':
+                        if( m_forWhat == ForAttributes )
+                            os << """;
+                        else
+                            os << c;
+                        break;
+
+                    default:
+                        // Escape control chars - based on contribution by @espenalb in PR #465 and
+                        // by @mrpi PR #588
+                        if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) {
+                            // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
+                            os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
+                               << static_cast<int>( c );
+                        }
+                        else
+                            os << c;
+                }
+            }
+        }
+
+        friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
+            xmlEncode.encodeTo( os );
+            return os;
+        }
+
+    private:
+        std::string m_str;
+        ForWhat m_forWhat;
+    };
+
+    class XmlWriter {
+    public:
+
+        class ScopedElement {
+        public:
+            ScopedElement( XmlWriter* writer )
+            :   m_writer( writer )
+            {}
+
+            ScopedElement( ScopedElement const& other )
+            :   m_writer( other.m_writer ){
+                other.m_writer = CATCH_NULL;
+            }
+
+            ~ScopedElement() {
+                if( m_writer )
+                    m_writer->endElement();
+            }
+
+            ScopedElement& writeText( std::string const& text, bool indent = true ) {
+                m_writer->writeText( text, indent );
+                return *this;
+            }
+
+            template<typename T>
+            ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
+                m_writer->writeAttribute( name, attribute );
+                return *this;
+            }
+
+        private:
+            mutable XmlWriter* m_writer;
+        };
+
+        XmlWriter()
+        :   m_tagIsOpen( false ),
+            m_needsNewline( false ),
+            m_os( Catch::cout() )
+        {
+            writeDeclaration();
+        }
+
+        XmlWriter( std::ostream& os )
+        :   m_tagIsOpen( false ),
+            m_needsNewline( false ),
+            m_os( os )
+        {
+            writeDeclaration();
+        }
+
+        ~XmlWriter() {
+            while( !m_tags.empty() )
+                endElement();
+        }
+
+        XmlWriter& startElement( std::string const& name ) {
+            ensureTagClosed();
+            newlineIfNecessary();
+            m_os << m_indent << '<' << name;
+            m_tags.push_back( name );
+            m_indent += "  ";
+            m_tagIsOpen = true;
+            return *this;
+        }
+
+        ScopedElement scopedElement( std::string const& name ) {
+            ScopedElement scoped( this );
+            startElement( name );
+            return scoped;
+        }
+
+        XmlWriter& endElement() {
+            newlineIfNecessary();
+            m_indent = m_indent.substr( 0, m_indent.size()-2 );
+            if( m_tagIsOpen ) {
+                m_os << "/>";
+                m_tagIsOpen = false;
+            }
+            else {
+                m_os << m_indent << "</" << m_tags.back() << ">";
+            }
+            m_os << std::endl;
+            m_tags.pop_back();
+            return *this;
+        }
+
+        XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
+            if( !name.empty() && !attribute.empty() )
+                m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
+            return *this;
+        }
+
+        XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
+            m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
+            return *this;
+        }
+
+        template<typename T>
+        XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
+            std::ostringstream oss;
+            oss << attribute;
+            return writeAttribute( name, oss.str() );
+        }
+
+        XmlWriter& writeText( std::string const& text, bool indent = true ) {
+            if( !text.empty() ){
+                bool tagWasOpen = m_tagIsOpen;
+                ensureTagClosed();
+                if( tagWasOpen && indent )
+                    m_os << m_indent;
+                m_os << XmlEncode( text );
+                m_needsNewline = true;
+            }
+            return *this;
+        }
+
+        XmlWriter& writeComment( std::string const& text ) {
+            ensureTagClosed();
+            m_os << m_indent << "<!--" << text << "-->";
+            m_needsNewline = true;
+            return *this;
+        }
+
+        void writeStylesheetRef( std::string const& url ) {
+            m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
+        }
+
+        XmlWriter& writeBlankLine() {
+            ensureTagClosed();
+            m_os << '\n';
+            return *this;
+        }
+
+        void ensureTagClosed() {
+            if( m_tagIsOpen ) {
+                m_os << ">" << std::endl;
+                m_tagIsOpen = false;
+            }
+        }
+
+    private:
+        XmlWriter( XmlWriter const& );
+        void operator=( XmlWriter const& );
+
+        void writeDeclaration() {
+            m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+        }
+
+        void newlineIfNecessary() {
+            if( m_needsNewline ) {
+                m_os << std::endl;
+                m_needsNewline = false;
+            }
+        }
+
+        bool m_tagIsOpen;
+        bool m_needsNewline;
+        std::vector<std::string> m_tags;
+        std::string m_indent;
+        std::ostream& m_os;
+    };
+
+}
+
+namespace Catch {
+    class XmlReporter : public StreamingReporterBase {
+    public:
+        XmlReporter( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config ),
+            m_xml(_config.stream()),
+            m_sectionDepth( 0 )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = true;
+        }
+
+        virtual ~XmlReporter() CATCH_OVERRIDE;
+
+        static std::string getDescription() {
+            return "Reports test results as an XML document";
+        }
+
+        virtual std::string getStylesheetRef() const {
+            return std::string();
+        }
+
+        void writeSourceInfo( SourceLineInfo const& sourceInfo ) {
+            m_xml
+                .writeAttribute( "filename", sourceInfo.file )
+                .writeAttribute( "line", sourceInfo.line );
+        }
+
+    public: // StreamingReporterBase
+
+        virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE {
+            StreamingReporterBase::noMatchingTestCases( s );
+        }
+
+        virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::testRunStarting( testInfo );
+            std::string stylesheetRef = getStylesheetRef();
+            if( !stylesheetRef.empty() )
+                m_xml.writeStylesheetRef( stylesheetRef );
+            m_xml.startElement( "Catch" );
+            if( !m_config->name().empty() )
+                m_xml.writeAttribute( "name", m_config->name() );
+        }
+
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::testGroupStarting( groupInfo );
+            m_xml.startElement( "Group" )
+                .writeAttribute( "name", groupInfo.name );
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::testCaseStarting(testInfo);
+            m_xml.startElement( "TestCase" )
+                .writeAttribute( "name", trim( testInfo.name ) )
+                .writeAttribute( "description", testInfo.description )
+                .writeAttribute( "tags", testInfo.tagsAsString );
+
+            writeSourceInfo( testInfo.lineInfo );
+
+            if ( m_config->showDurations() == ShowDurations::Always )
+                m_testCaseTimer.start();
+            m_xml.ensureTagClosed();
+        }
+
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::sectionStarting( sectionInfo );
+            if( m_sectionDepth++ > 0 ) {
+                m_xml.startElement( "Section" )
+                    .writeAttribute( "name", trim( sectionInfo.name ) )
+                    .writeAttribute( "description", sectionInfo.description );
+                writeSourceInfo( sectionInfo.lineInfo );
+                m_xml.ensureTagClosed();
+            }
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { }
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+
+            AssertionResult const& result = assertionStats.assertionResult;
+
+            bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+            if( includeResults || result.getResultType() == ResultWas::Warning ) {
+                // Print any info messages in <Info> tags.
+                for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+                     it != itEnd;
+                     ++it ) {
+                    if( it->type == ResultWas::Info && includeResults ) {
+                        m_xml.scopedElement( "Info" )
+                                .writeText( it->message );
+                    } else if ( it->type == ResultWas::Warning ) {
+                        m_xml.scopedElement( "Warning" )
+                                .writeText( it->message );
+                    }
+                }
+            }
+
+            // Drop out if result was successful but we're not printing them.
+            if( !includeResults && result.getResultType() != ResultWas::Warning )
+                return true;
+
+            // Print the expression if there is one.
+            if( result.hasExpression() ) {
+                m_xml.startElement( "Expression" )
+                    .writeAttribute( "success", result.succeeded() )
+                    .writeAttribute( "type", result.getTestMacroName() );
+
+                writeSourceInfo( result.getSourceInfo() );
+
+                m_xml.scopedElement( "Original" )
+                    .writeText( result.getExpression() );
+                m_xml.scopedElement( "Expanded" )
+                    .writeText( result.getExpandedExpression() );
+            }
+
+            // And... Print a result applicable to each result type.
+            switch( result.getResultType() ) {
+                case ResultWas::ThrewException:
+                    m_xml.startElement( "Exception" );
+                    writeSourceInfo( result.getSourceInfo() );
+                    m_xml.writeText( result.getMessage() );
+                    m_xml.endElement();
+                    break;
+                case ResultWas::FatalErrorCondition:
+                    m_xml.startElement( "FatalErrorCondition" );
+                    writeSourceInfo( result.getSourceInfo() );
+                    m_xml.writeText( result.getMessage() );
+                    m_xml.endElement();
+                    break;
+                case ResultWas::Info:
+                    m_xml.scopedElement( "Info" )
+                        .writeText( result.getMessage() );
+                    break;
+                case ResultWas::Warning:
+                    // Warning will already have been written
+                    break;
+                case ResultWas::ExplicitFailure:
+                    m_xml.startElement( "Failure" );
+                    writeSourceInfo( result.getSourceInfo() );
+                    m_xml.writeText( result.getMessage() );
+                    m_xml.endElement();
+                    break;
+                default:
+                    break;
+            }
+
+            if( result.hasExpression() )
+                m_xml.endElement();
+
+            return true;
+        }
+
+        virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::sectionEnded( sectionStats );
+            if( --m_sectionDepth > 0 ) {
+                XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
+                e.writeAttribute( "successes", sectionStats.assertions.passed );
+                e.writeAttribute( "failures", sectionStats.assertions.failed );
+                e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
+
+                if ( m_config->showDurations() == ShowDurations::Always )
+                    e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
+
+                m_xml.endElement();
+            }
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testCaseEnded( testCaseStats );
+            XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
+            e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
+
+            if ( m_config->showDurations() == ShowDurations::Always )
+                e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
+
+            if( !testCaseStats.stdOut.empty() )
+                m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
+            if( !testCaseStats.stdErr.empty() )
+                m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
+
+            m_xml.endElement();
+        }
+
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testGroupEnded( testGroupStats );
+            // TODO: Check testGroupStats.aborting and act accordingly.
+            m_xml.scopedElement( "OverallResults" )
+                .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
+                .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
+                .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
+            m_xml.endElement();
+        }
+
+        virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testRunEnded( testRunStats );
+            m_xml.scopedElement( "OverallResults" )
+                .writeAttribute( "successes", testRunStats.totals.assertions.passed )
+                .writeAttribute( "failures", testRunStats.totals.assertions.failed )
+                .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
+            m_xml.endElement();
+        }
+
+    private:
+        Timer m_testCaseTimer;
+        XmlWriter m_xml;
+        int m_sectionDepth;
+    };
+
+     INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_junit.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
+
+#include <assert.h>
+
+namespace Catch {
+
+    namespace {
+        std::string getCurrentTimestamp() {
+            // Beware, this is not reentrant because of backward compatibility issues
+            // Also, UTC only, again because of backward compatibility (%z is C++11)
+            time_t rawtime;
+            std::time(&rawtime);
+            const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z");
+
+#ifdef _MSC_VER
+            std::tm timeInfo = {};
+            gmtime_s(&timeInfo, &rawtime);
+#else
+            std::tm* timeInfo;
+            timeInfo = std::gmtime(&rawtime);
+#endif
+
+            char timeStamp[timeStampSize];
+            const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+#ifdef _MSC_VER
+            std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+#else
+            std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
+#endif
+            return std::string(timeStamp);
+        }
+
+    }
+
+    class JunitReporter : public CumulativeReporterBase {
+    public:
+        JunitReporter( ReporterConfig const& _config )
+        :   CumulativeReporterBase( _config ),
+            xml( _config.stream() ),
+            unexpectedExceptions( 0 ),
+            m_okToFail( false )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = true;
+        }
+
+        virtual ~JunitReporter() CATCH_OVERRIDE;
+
+        static std::string getDescription() {
+            return "Reports test results in an XML format that looks like Ant's junitreport target";
+        }
+
+        virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {}
+
+        virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE {
+            CumulativeReporterBase::testRunStarting( runInfo );
+            xml.startElement( "testsuites" );
+        }
+
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+            suiteTimer.start();
+            stdOutForSuite.str("");
+            stdErrForSuite.str("");
+            unexpectedExceptions = 0;
+            CumulativeReporterBase::testGroupStarting( groupInfo );
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& testCaseInfo ) CATCH_OVERRIDE {
+            m_okToFail = testCaseInfo.okToFail();
+        }
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+            if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
+                unexpectedExceptions++;
+            return CumulativeReporterBase::assertionEnded( assertionStats );
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+            stdOutForSuite << testCaseStats.stdOut;
+            stdErrForSuite << testCaseStats.stdErr;
+            CumulativeReporterBase::testCaseEnded( testCaseStats );
+        }
+
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+            double suiteTime = suiteTimer.getElapsedSeconds();
+            CumulativeReporterBase::testGroupEnded( testGroupStats );
+            writeGroup( *m_testGroups.back(), suiteTime );
+        }
+
+        virtual void testRunEndedCumulative() CATCH_OVERRIDE {
+            xml.endElement();
+        }
+
+        void writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
+            XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
+            TestGroupStats const& stats = groupNode.value;
+            xml.writeAttribute( "name", stats.groupInfo.name );
+            xml.writeAttribute( "errors", unexpectedExceptions );
+            xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
+            xml.writeAttribute( "tests", stats.totals.assertions.total() );
+            xml.writeAttribute( "hostname", "tbd" ); // !TBD
+            if( m_config->showDurations() == ShowDurations::Never )
+                xml.writeAttribute( "time", "" );
+            else
+                xml.writeAttribute( "time", suiteTime );
+            xml.writeAttribute( "timestamp", getCurrentTimestamp() );
+
+            // Write test cases
+            for( TestGroupNode::ChildNodes::const_iterator
+                    it = groupNode.children.begin(), itEnd = groupNode.children.end();
+                    it != itEnd;
+                    ++it )
+                writeTestCase( **it );
+
+            xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false );
+            xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false );
+        }
+
+        void writeTestCase( TestCaseNode const& testCaseNode ) {
+            TestCaseStats const& stats = testCaseNode.value;
+
+            // All test cases have exactly one section - which represents the
+            // test case itself. That section may have 0-n nested sections
+            assert( testCaseNode.children.size() == 1 );
+            SectionNode const& rootSection = *testCaseNode.children.front();
+
+            std::string className = stats.testInfo.className;
+
+            if( className.empty() ) {
+                if( rootSection.childSections.empty() )
+                    className = "global";
+            }
+            writeSection( className, "", rootSection );
+        }
+
+        void writeSection(  std::string const& className,
+                            std::string const& rootName,
+                            SectionNode const& sectionNode ) {
+            std::string name = trim( sectionNode.stats.sectionInfo.name );
+            if( !rootName.empty() )
+                name = rootName + '/' + name;
+
+            if( !sectionNode.assertions.empty() ||
+                !sectionNode.stdOut.empty() ||
+                !sectionNode.stdErr.empty() ) {
+                XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
+                if( className.empty() ) {
+                    xml.writeAttribute( "classname", name );
+                    xml.writeAttribute( "name", "root" );
+                }
+                else {
+                    xml.writeAttribute( "classname", className );
+                    xml.writeAttribute( "name", name );
+                }
+                xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) );
+
+                writeAssertions( sectionNode );
+
+                if( !sectionNode.stdOut.empty() )
+                    xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
+                if( !sectionNode.stdErr.empty() )
+                    xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
+            }
+            for( SectionNode::ChildSections::const_iterator
+                    it = sectionNode.childSections.begin(),
+                    itEnd = sectionNode.childSections.end();
+                    it != itEnd;
+                    ++it )
+                if( className.empty() )
+                    writeSection( name, "", **it );
+                else
+                    writeSection( className, name, **it );
+        }
+
+        void writeAssertions( SectionNode const& sectionNode ) {
+            for( SectionNode::Assertions::const_iterator
+                    it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end();
+                    it != itEnd;
+                    ++it )
+                writeAssertion( *it );
+        }
+        void writeAssertion( AssertionStats const& stats ) {
+            AssertionResult const& result = stats.assertionResult;
+            if( !result.isOk() ) {
+                std::string elementName;
+                switch( result.getResultType() ) {
+                    case ResultWas::ThrewException:
+                    case ResultWas::FatalErrorCondition:
+                        elementName = "error";
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        elementName = "failure";
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        elementName = "failure";
+                        break;
+                    case ResultWas::DidntThrowException:
+                        elementName = "failure";
+                        break;
+
+                    // We should never see these here:
+                    case ResultWas::Info:
+                    case ResultWas::Warning:
+                    case ResultWas::Ok:
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        elementName = "internalError";
+                        break;
+                }
+
+                XmlWriter::ScopedElement e = xml.scopedElement( elementName );
+
+                xml.writeAttribute( "message", result.getExpandedExpression() );
+                xml.writeAttribute( "type", result.getTestMacroName() );
+
+                std::ostringstream oss;
+                if( !result.getMessage().empty() )
+                    oss << result.getMessage() << '\n';
+                for( std::vector<MessageInfo>::const_iterator
+                        it = stats.infoMessages.begin(),
+                        itEnd = stats.infoMessages.end();
+                            it != itEnd;
+                            ++it )
+                    if( it->type == ResultWas::Info )
+                        oss << it->message << '\n';
+
+                oss << "at " << result.getSourceInfo();
+                xml.writeText( oss.str(), false );
+            }
+        }
+
+        XmlWriter xml;
+        Timer suiteTimer;
+        std::ostringstream stdOutForSuite;
+        std::ostringstream stdErrForSuite;
+        unsigned int unexpectedExceptions;
+        bool m_okToFail;
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_console.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+
+#include <cfloat>
+#include <cstdio>
+
+namespace Catch {
+
+    struct ConsoleReporter : StreamingReporterBase {
+        ConsoleReporter( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config ),
+            m_headerPrinted( false )
+        {}
+
+        virtual ~ConsoleReporter() CATCH_OVERRIDE;
+        static std::string getDescription() {
+            return "Reports test results as plain lines of text";
+        }
+
+        virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
+            stream << "No test cases matched '" << spec << '\'' << std::endl;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {
+        }
+
+        virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE {
+            AssertionResult const& result = _assertionStats.assertionResult;
+
+            bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+            // Drop out if result was successful but we're not printing them.
+            if( !includeResults && result.getResultType() != ResultWas::Warning )
+                return false;
+
+            lazyPrint();
+
+            AssertionPrinter printer( stream, _assertionStats, includeResults );
+            printer.print();
+            stream << std::endl;
+            return true;
+        }
+
+        virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
+            m_headerPrinted = false;
+            StreamingReporterBase::sectionStarting( _sectionInfo );
+        }
+        virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE {
+            if( _sectionStats.missingAssertions ) {
+                lazyPrint();
+                Colour colour( Colour::ResultError );
+                if( m_sectionStack.size() > 1 )
+                    stream << "\nNo assertions in section";
+                else
+                    stream << "\nNo assertions in test case";
+                stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
+            }
+            if( m_config->showDurations() == ShowDurations::Always ) {
+                stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+            }
+            if( m_headerPrinted ) {
+                m_headerPrinted = false;
+            }
+            StreamingReporterBase::sectionEnded( _sectionStats );
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testCaseEnded( _testCaseStats );
+            m_headerPrinted = false;
+        }
+        virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE {
+            if( currentGroupInfo.used ) {
+                printSummaryDivider();
+                stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
+                printTotals( _testGroupStats.totals );
+                stream << '\n' << std::endl;
+            }
+            StreamingReporterBase::testGroupEnded( _testGroupStats );
+        }
+        virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE {
+            printTotalsDivider( _testRunStats.totals );
+            printTotals( _testRunStats.totals );
+            stream << std::endl;
+            StreamingReporterBase::testRunEnded( _testRunStats );
+        }
+
+    private:
+
+        class AssertionPrinter {
+            void operator= ( AssertionPrinter const& );
+        public:
+            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+            :   stream( _stream ),
+                stats( _stats ),
+                result( _stats.assertionResult ),
+                colour( Colour::None ),
+                message( result.getMessage() ),
+                messages( _stats.infoMessages ),
+                printInfoMessages( _printInfoMessages )
+            {
+                switch( result.getResultType() ) {
+                    case ResultWas::Ok:
+                        colour = Colour::Success;
+                        passOrFail = "PASSED";
+                        //if( result.hasMessage() )
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "with messages";
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        if( result.isOk() ) {
+                            colour = Colour::Success;
+                            passOrFail = "FAILED - but was ok";
+                        }
+                        else {
+                            colour = Colour::Error;
+                            passOrFail = "FAILED";
+                        }
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "with messages";
+                        break;
+                    case ResultWas::ThrewException:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "due to unexpected exception with ";
+                        if (_stats.infoMessages.size() == 1)
+                            messageLabel += "message";
+                        if (_stats.infoMessages.size() > 1)
+                            messageLabel += "messages";
+                        break;
+                    case ResultWas::FatalErrorCondition:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "due to a fatal error condition";
+                        break;
+                    case ResultWas::DidntThrowException:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "because no exception was thrown where one was expected";
+                        break;
+                    case ResultWas::Info:
+                        messageLabel = "info";
+                        break;
+                    case ResultWas::Warning:
+                        messageLabel = "warning";
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        passOrFail = "FAILED";
+                        colour = Colour::Error;
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "explicitly with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "explicitly with messages";
+                        break;
+                    // These cases are here to prevent compiler warnings
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        passOrFail = "** internal error **";
+                        colour = Colour::Error;
+                        break;
+                }
+            }
+
+            void print() const {
+                printSourceInfo();
+                if( stats.totals.assertions.total() > 0 ) {
+                    if( result.isOk() )
+                        stream << '\n';
+                    printResultType();
+                    printOriginalExpression();
+                    printReconstructedExpression();
+                }
+                else {
+                    stream << '\n';
+                }
+                printMessage();
+            }
+
+        private:
+            void printResultType() const {
+                if( !passOrFail.empty() ) {
+                    Colour colourGuard( colour );
+                    stream << passOrFail << ":\n";
+                }
+            }
+            void printOriginalExpression() const {
+                if( result.hasExpression() ) {
+                    Colour colourGuard( Colour::OriginalExpression );
+                    stream  << "  ";
+                    stream << result.getExpressionInMacro();
+                    stream << '\n';
+                }
+            }
+            void printReconstructedExpression() const {
+                if( result.hasExpandedExpression() ) {
+                    stream << "with expansion:\n";
+                    Colour colourGuard( Colour::ReconstructedExpression );
+                    stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n';
+                }
+            }
+            void printMessage() const {
+                if( !messageLabel.empty() )
+                    stream << messageLabel << ':' << '\n';
+                for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
+                        it != itEnd;
+                        ++it ) {
+                    // If this assertion is a warning ignore any INFO messages
+                    if( printInfoMessages || it->type != ResultWas::Info )
+                        stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n';
+                }
+            }
+            void printSourceInfo() const {
+                Colour colourGuard( Colour::FileName );
+                stream << result.getSourceInfo() << ": ";
+            }
+
+            std::ostream& stream;
+            AssertionStats const& stats;
+            AssertionResult const& result;
+            Colour::Code colour;
+            std::string passOrFail;
+            std::string messageLabel;
+            std::string message;
+            std::vector<MessageInfo> messages;
+            bool printInfoMessages;
+        };
+
+        void lazyPrint() {
+
+            if( !currentTestRunInfo.used )
+                lazyPrintRunInfo();
+            if( !currentGroupInfo.used )
+                lazyPrintGroupInfo();
+
+            if( !m_headerPrinted ) {
+                printTestCaseAndSectionHeader();
+                m_headerPrinted = true;
+            }
+        }
+        void lazyPrintRunInfo() {
+            stream  << '\n' << getLineOfChars<'~'>() << '\n';
+            Colour colour( Colour::SecondaryText );
+            stream  << currentTestRunInfo->name
+                    << " is a Catch v"  << libraryVersion() << " host application.\n"
+                    << "Run with -? for options\n\n";
+
+            if( m_config->rngSeed() != 0 )
+                stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
+
+            currentTestRunInfo.used = true;
+        }
+        void lazyPrintGroupInfo() {
+            if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
+                printClosedHeader( "Group: " + currentGroupInfo->name );
+                currentGroupInfo.used = true;
+            }
+        }
+        void printTestCaseAndSectionHeader() {
+            assert( !m_sectionStack.empty() );
+            printOpenHeader( currentTestCaseInfo->name );
+
+            if( m_sectionStack.size() > 1 ) {
+                Colour colourGuard( Colour::Headers );
+
+                std::vector<SectionInfo>::const_iterator
+                    it = m_sectionStack.begin()+1, // Skip first section (test case)
+                    itEnd = m_sectionStack.end();
+                for( ; it != itEnd; ++it )
+                    printHeaderString( it->name, 2 );
+            }
+
+            SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
+
+            if( !lineInfo.empty() ){
+                stream << getLineOfChars<'-'>() << '\n';
+                Colour colourGuard( Colour::FileName );
+                stream << lineInfo << '\n';
+            }
+            stream << getLineOfChars<'.'>() << '\n' << std::endl;
+        }
+
+        void printClosedHeader( std::string const& _name ) {
+            printOpenHeader( _name );
+            stream << getLineOfChars<'.'>() << '\n';
+        }
+        void printOpenHeader( std::string const& _name ) {
+            stream  << getLineOfChars<'-'>() << '\n';
+            {
+                Colour colourGuard( Colour::Headers );
+                printHeaderString( _name );
+            }
+        }
+
+        // if string has a : in first line will set indent to follow it on
+        // subsequent lines
+        void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
+            std::size_t i = _string.find( ": " );
+            if( i != std::string::npos )
+                i+=2;
+            else
+                i = 0;
+            stream << Text( _string, TextAttributes()
+                                        .setIndent( indent+i)
+                                        .setInitialIndent( indent ) ) << '\n';
+        }
+
+        struct SummaryColumn {
+
+            SummaryColumn( std::string const& _label, Colour::Code _colour )
+            :   label( _label ),
+                colour( _colour )
+            {}
+            SummaryColumn addRow( std::size_t count ) {
+                std::ostringstream oss;
+                oss << count;
+                std::string row = oss.str();
+                for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
+                    while( it->size() < row.size() )
+                        *it = ' ' + *it;
+                    while( it->size() > row.size() )
+                        row = ' ' + row;
+                }
+                rows.push_back( row );
+                return *this;
+            }
+
+            std::string label;
+            Colour::Code colour;
+            std::vector<std::string> rows;
+
+        };
+
+        void printTotals( Totals const& totals ) {
+            if( totals.testCases.total() == 0 ) {
+                stream << Colour( Colour::Warning ) << "No tests ran\n";
+            }
+            else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
+                stream << Colour( Colour::ResultSuccess ) << "All tests passed";
+                stream << " ("
+                        << pluralise( totals.assertions.passed, "assertion" ) << " in "
+                        << pluralise( totals.testCases.passed, "test case" ) << ')'
+                        << '\n';
+            }
+            else {
+
+                std::vector<SummaryColumn> columns;
+                columns.push_back( SummaryColumn( "", Colour::None )
+                                        .addRow( totals.testCases.total() )
+                                        .addRow( totals.assertions.total() ) );
+                columns.push_back( SummaryColumn( "passed", Colour::Success )
+                                        .addRow( totals.testCases.passed )
+                                        .addRow( totals.assertions.passed ) );
+                columns.push_back( SummaryColumn( "failed", Colour::ResultError )
+                                        .addRow( totals.testCases.failed )
+                                        .addRow( totals.assertions.failed ) );
+                columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
+                                        .addRow( totals.testCases.failedButOk )
+                                        .addRow( totals.assertions.failedButOk ) );
+
+                printSummaryRow( "test cases", columns, 0 );
+                printSummaryRow( "assertions", columns, 1 );
+            }
+        }
+        void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) {
+            for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) {
+                std::string value = it->rows[row];
+                if( it->label.empty() ) {
+                    stream << label << ": ";
+                    if( value != "0" )
+                        stream << value;
+                    else
+                        stream << Colour( Colour::Warning ) << "- none -";
+                }
+                else if( value != "0" ) {
+                    stream  << Colour( Colour::LightGrey ) << " | ";
+                    stream  << Colour( it->colour )
+                            << value << ' ' << it->label;
+                }
+            }
+            stream << '\n';
+        }
+
+        static std::size_t makeRatio( std::size_t number, std::size_t total ) {
+            std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0;
+            return ( ratio == 0 && number > 0 ) ? 1 : ratio;
+        }
+        static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
+            if( i > j && i > k )
+                return i;
+            else if( j > k )
+                return j;
+            else
+                return k;
+        }
+
+        void printTotalsDivider( Totals const& totals ) {
+            if( totals.testCases.total() > 0 ) {
+                std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() );
+                std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() );
+                std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() );
+                while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 )
+                    findMax( failedRatio, failedButOkRatio, passedRatio )++;
+                while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 )
+                    findMax( failedRatio, failedButOkRatio, passedRatio )--;
+
+                stream << Colour( Colour::Error ) << std::string( failedRatio, '=' );
+                stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' );
+                if( totals.testCases.allPassed() )
+                    stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' );
+                else
+                    stream << Colour( Colour::Success ) << std::string( passedRatio, '=' );
+            }
+            else {
+                stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
+            }
+            stream << '\n';
+        }
+        void printSummaryDivider() {
+            stream << getLineOfChars<'-'>() << '\n';
+        }
+
+    private:
+        bool m_headerPrinted;
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_compact.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
+
+namespace Catch {
+
+    struct CompactReporter : StreamingReporterBase {
+
+        CompactReporter( ReporterConfig const& _config )
+        : StreamingReporterBase( _config )
+        {}
+
+        virtual ~CompactReporter();
+
+        static std::string getDescription() {
+            return "Reports test results on a single line, suitable for IDEs";
+        }
+
+        virtual ReporterPreferences getPreferences() const {
+            ReporterPreferences prefs;
+            prefs.shouldRedirectStdOut = false;
+            return prefs;
+        }
+
+        virtual void noMatchingTestCases( std::string const& spec ) {
+            stream << "No test cases matched '" << spec << '\'' << std::endl;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) {}
+
+        virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
+            AssertionResult const& result = _assertionStats.assertionResult;
+
+            bool printInfoMessages = true;
+
+            // Drop out if result was successful and we're not printing those
+            if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+                if( result.getResultType() != ResultWas::Warning )
+                    return false;
+                printInfoMessages = false;
+            }
+
+            AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+            printer.print();
+
+            stream << std::endl;
+            return true;
+        }
+
+        virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE {
+            if (m_config->showDurations() == ShowDurations::Always) {
+                stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+            }
+        }
+
+        virtual void testRunEnded( TestRunStats const& _testRunStats ) {
+            printTotals( _testRunStats.totals );
+            stream << '\n' << std::endl;
+            StreamingReporterBase::testRunEnded( _testRunStats );
+        }
+
+    private:
+        class AssertionPrinter {
+            void operator= ( AssertionPrinter const& );
+        public:
+            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+            : stream( _stream )
+            , stats( _stats )
+            , result( _stats.assertionResult )
+            , messages( _stats.infoMessages )
+            , itMessage( _stats.infoMessages.begin() )
+            , printInfoMessages( _printInfoMessages )
+            {}
+
+            void print() {
+                printSourceInfo();
+
+                itMessage = messages.begin();
+
+                switch( result.getResultType() ) {
+                    case ResultWas::Ok:
+                        printResultType( Colour::ResultSuccess, passedString() );
+                        printOriginalExpression();
+                        printReconstructedExpression();
+                        if ( ! result.hasExpression() )
+                            printRemainingMessages( Colour::None );
+                        else
+                            printRemainingMessages();
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        if( result.isOk() )
+                            printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) );
+                        else
+                            printResultType( Colour::Error, failedString() );
+                        printOriginalExpression();
+                        printReconstructedExpression();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::ThrewException:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "unexpected exception with message:" );
+                        printMessage();
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::FatalErrorCondition:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "fatal error condition with message:" );
+                        printMessage();
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::DidntThrowException:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "expected exception, got none" );
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::Info:
+                        printResultType( Colour::None, "info" );
+                        printMessage();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::Warning:
+                        printResultType( Colour::None, "warning" );
+                        printMessage();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "explicitly" );
+                        printRemainingMessages( Colour::None );
+                        break;
+                    // These cases are here to prevent compiler warnings
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        printResultType( Colour::Error, "** internal error **" );
+                        break;
+                }
+            }
+
+        private:
+            // Colour::LightGrey
+
+            static Colour::Code dimColour() { return Colour::FileName; }
+
+#ifdef CATCH_PLATFORM_MAC
+            static const char* failedString() { return "FAILED"; }
+            static const char* passedString() { return "PASSED"; }
+#else
+            static const char* failedString() { return "failed"; }
+            static const char* passedString() { return "passed"; }
+#endif
+
+            void printSourceInfo() const {
+                Colour colourGuard( Colour::FileName );
+                stream << result.getSourceInfo() << ':';
+            }
+
+            void printResultType( Colour::Code colour, std::string const& passOrFail ) const {
+                if( !passOrFail.empty() ) {
+                    {
+                        Colour colourGuard( colour );
+                        stream << ' ' << passOrFail;
+                    }
+                    stream << ':';
+                }
+            }
+
+            void printIssue( std::string const& issue ) const {
+                stream << ' ' << issue;
+            }
+
+            void printExpressionWas() {
+                if( result.hasExpression() ) {
+                    stream << ';';
+                    {
+                        Colour colour( dimColour() );
+                        stream << " expression was:";
+                    }
+                    printOriginalExpression();
+                }
+            }
+
+            void printOriginalExpression() const {
+                if( result.hasExpression() ) {
+                    stream << ' ' << result.getExpression();
+                }
+            }
+
+            void printReconstructedExpression() const {
+                if( result.hasExpandedExpression() ) {
+                    {
+                        Colour colour( dimColour() );
+                        stream << " for: ";
+                    }
+                    stream << result.getExpandedExpression();
+                }
+            }
+
+            void printMessage() {
+                if ( itMessage != messages.end() ) {
+                    stream << " '" << itMessage->message << '\'';
+                    ++itMessage;
+                }
+            }
+
+            void printRemainingMessages( Colour::Code colour = dimColour() ) {
+                if ( itMessage == messages.end() )
+                    return;
+
+                // using messages.end() directly yields compilation error:
+                std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+                const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
+
+                {
+                    Colour colourGuard( colour );
+                    stream << " with " << pluralise( N, "message" ) << ':';
+                }
+
+                for(; itMessage != itEnd; ) {
+                    // If this assertion is a warning ignore any INFO messages
+                    if( printInfoMessages || itMessage->type != ResultWas::Info ) {
+                        stream << " '" << itMessage->message << '\'';
+                        if ( ++itMessage != itEnd ) {
+                            Colour colourGuard( dimColour() );
+                            stream << " and";
+                        }
+                    }
+                }
+            }
+
+        private:
+            std::ostream& stream;
+            AssertionStats const& stats;
+            AssertionResult const& result;
+            std::vector<MessageInfo> messages;
+            std::vector<MessageInfo>::const_iterator itMessage;
+            bool printInfoMessages;
+        };
+
+        // Colour, message variants:
+        // - white: No tests ran.
+        // -   red: Failed [both/all] N test cases, failed [both/all] M assertions.
+        // - white: Passed [both/all] N test cases (no assertions).
+        // -   red: Failed N tests cases, failed M assertions.
+        // - green: Passed [both/all] N tests cases with M assertions.
+
+        std::string bothOrAll( std::size_t count ) const {
+            return count == 1 ? std::string() : count == 2 ? "both " : "all " ;
+        }
+
+        void printTotals( const Totals& totals ) const {
+            if( totals.testCases.total() == 0 ) {
+                stream << "No tests ran.";
+            }
+            else if( totals.testCases.failed == totals.testCases.total() ) {
+                Colour colour( Colour::ResultError );
+                const std::string qualify_assertions_failed =
+                    totals.assertions.failed == totals.assertions.total() ?
+                        bothOrAll( totals.assertions.failed ) : std::string();
+                stream <<
+                    "Failed " << bothOrAll( totals.testCases.failed )
+                              << pluralise( totals.testCases.failed, "test case"  ) << ", "
+                    "failed " << qualify_assertions_failed <<
+                                 pluralise( totals.assertions.failed, "assertion" ) << '.';
+            }
+            else if( totals.assertions.total() == 0 ) {
+                stream <<
+                    "Passed " << bothOrAll( totals.testCases.total() )
+                              << pluralise( totals.testCases.total(), "test case" )
+                              << " (no assertions).";
+            }
+            else if( totals.assertions.failed ) {
+                Colour colour( Colour::ResultError );
+                stream <<
+                    "Failed " << pluralise( totals.testCases.failed, "test case"  ) << ", "
+                    "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.';
+            }
+            else {
+                Colour colour( Colour::ResultSuccess );
+                stream <<
+                    "Passed " << bothOrAll( totals.testCases.passed )
+                              << pluralise( totals.testCases.passed, "test case"  ) <<
+                    " with "  << pluralise( totals.assertions.passed, "assertion" ) << '.';
+            }
+        }
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter )
+
+} // end namespace Catch
+
+namespace Catch {
+    // These are all here to avoid warnings about not having any out of line
+    // virtual methods
+    NonCopyable::~NonCopyable() {}
+    IShared::~IShared() {}
+    IStream::~IStream() CATCH_NOEXCEPT {}
+    FileStream::~FileStream() CATCH_NOEXCEPT {}
+    CoutStream::~CoutStream() CATCH_NOEXCEPT {}
+    DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
+    StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
+    IContext::~IContext() {}
+    IResultCapture::~IResultCapture() {}
+    ITestCase::~ITestCase() {}
+    ITestCaseRegistry::~ITestCaseRegistry() {}
+    IRegistryHub::~IRegistryHub() {}
+    IMutableRegistryHub::~IMutableRegistryHub() {}
+    IExceptionTranslator::~IExceptionTranslator() {}
+    IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
+    IReporter::~IReporter() {}
+    IReporterFactory::~IReporterFactory() {}
+    IReporterRegistry::~IReporterRegistry() {}
+    IStreamingReporter::~IStreamingReporter() {}
+    AssertionStats::~AssertionStats() {}
+    SectionStats::~SectionStats() {}
+    TestCaseStats::~TestCaseStats() {}
+    TestGroupStats::~TestGroupStats() {}
+    TestRunStats::~TestRunStats() {}
+    CumulativeReporterBase::SectionNode::~SectionNode() {}
+    CumulativeReporterBase::~CumulativeReporterBase() {}
+
+    StreamingReporterBase::~StreamingReporterBase() {}
+    ConsoleReporter::~ConsoleReporter() {}
+    CompactReporter::~CompactReporter() {}
+    IRunner::~IRunner() {}
+    IMutableContext::~IMutableContext() {}
+    IConfig::~IConfig() {}
+    XmlReporter::~XmlReporter() {}
+    JunitReporter::~JunitReporter() {}
+    TestRegistry::~TestRegistry() {}
+    FreeFunctionTestCase::~FreeFunctionTestCase() {}
+    IGeneratorInfo::~IGeneratorInfo() {}
+    IGeneratorsForTest::~IGeneratorsForTest() {}
+    WildcardPattern::~WildcardPattern() {}
+    TestSpec::Pattern::~Pattern() {}
+    TestSpec::NamePattern::~NamePattern() {}
+    TestSpec::TagPattern::~TagPattern() {}
+    TestSpec::ExcludedPattern::~ExcludedPattern() {}
+    Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {}
+
+    void Config::dummy() {}
+
+    namespace TestCaseTracking {
+        ITracker::~ITracker() {}
+        TrackerBase::~TrackerBase() {}
+        SectionTracker::~SectionTracker() {}
+        IndexTracker::~IndexTracker() {}
+    }
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+// #included from: internal/catch_default_main.hpp
+#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
+
+#ifndef __OBJC__
+
+#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
+// Standard C/C++ Win32 Unicode wmain entry point
+extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
+#else
+// Standard C/C++ main entry point
+int main (int argc, char * argv[]) {
+#endif
+
+    int result = Catch::Session().run( argc, argv );
+    return ( result < 0xff ? result : 0xff );
+}
+
+#else // __OBJC__
+
+// Objective-C entry point
+int main (int argc, char * const argv[]) {
+#if !CATCH_ARC_ENABLED
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+#endif
+
+    Catch::registerTestMethods();
+    int result = Catch::Session().run( argc, (char* const*)argv );
+
+#if !CATCH_ARC_ENABLED
+    [pool drain];
+#endif
+
+    return ( result < 0xff ? result : 0xff );
+}
+
+#endif // __OBJC__
+
+#endif
+
+#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
+#  undef CLARA_CONFIG_MAIN
+#endif
+
+//////
+
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+#else
+#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr  )
+#endif
+
+#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
+
+#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
+#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
+
+#define CATCH_CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
+
+#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#else
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif
+
+#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
+#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+    #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+    #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+    #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+    #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+    #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+    #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+    #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#else
+    #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+    #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+    #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+    #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description )
+    #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+    #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
+    #define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
+    #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
+#endif
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
+#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define CATCH_GIVEN( desc )    CATCH_SECTION( std::string( "Given: ") + desc, "" )
+#define CATCH_WHEN( desc )     CATCH_SECTION( std::string( " When: ") + desc, "" )
+#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( "  And: ") + desc, "" )
+#define CATCH_THEN( desc )     CATCH_SECTION( std::string( " Then: ") + desc, "" )
+#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( "  And: ") + desc, "" )
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+
+#else
+#define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr  )
+#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+#endif
+
+#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
+#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
+
+#define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
+#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
+
+#define CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
+#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
+
+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#else
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif
+
+#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
+#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#else
+#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+    #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+    #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+    #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description )
+    #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+    #define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
+    #define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
+    #define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
+#endif
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
+#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define GIVEN( desc )    SECTION( std::string("   Given: ") + desc, "" )
+#define WHEN( desc )     SECTION( std::string("    When: ") + desc, "" )
+#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" )
+#define THEN( desc )     SECTION( std::string("    Then: ") + desc, "" )
+#define AND_THEN( desc ) SECTION( std::string("     And: ") + desc, "" )
+
+using Catch::Detail::Approx;
+
+// #included from: internal/catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#    ifdef __ICC // icpc defines the __clang__ macro
+#        pragma warning(pop)
+#    else
+#        pragma clang diagnostic pop
+#    endif
+#elif defined __GNUC__
+#    pragma GCC diagnostic pop
+#endif
+
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/create_pbf_test_data.sh
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/create_pbf_test_data.sh	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/create_pbf_test_data.sh	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+#  create_pbf_test_data.sh [TESTCASE]
+#
+#  This script creates the test data for the given test case in protobuf format
+#  using the testcase.proto description and the testcase.cpp code.
+#
+#  If called without a test case it will iterate over all test cases generating
+#  all data.
+#
+#  This program should be called with the "test" directory as current directory.
+#
+
+set -e
+
+if [ -z "$CXX" ]; then
+    echo "Please set CXX before running this script"
+    exit 1
+fi
+
+if [ -z "$1" ]; then
+    for dir in t/*; do
+        $0 $dir
+    done
+fi
+
+echo "Generating $1..."
+cd $1
+if [ -f testcase.proto ]; then
+    protoc --cpp_out=. testcase.proto
+    $CXX -std=c++11 -I../../include -o testcase testcase.cpp testcase.pb.cc -lprotobuf-lite -pthread
+    ./testcase
+fi
+cd ../..
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/packed_access.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/packed_access.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/packed_access.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,296 @@
+// NOLINT(llvm-header-guard)
+
+#define PBF_TYPE_NAME PROTOZERO_TEST_STRING(PBF_TYPE)
+#define GET_TYPE PROTOZERO_TEST_CONCAT(get_packed_, PBF_TYPE)
+#define ADD_TYPE PROTOZERO_TEST_CONCAT(add_packed_, PBF_TYPE)
+
+using packed_field_type = PROTOZERO_TEST_CONCAT(protozero::packed_field_, PBF_TYPE);
+
+TEST_CASE("read repeated packed field: " PBF_TYPE_NAME) {
+    // Run these tests twice, the second time we basically move the data
+    // one byte down in the buffer. It doesn't matter how the data or buffer
+    // is aligned before that, in at least one of these cases the ints will
+    // not be aligned properly. So we test that even in that case the ints
+    // will be extracted properly.
+
+    for (std::string::size_type n = 0; n < 2; ++n) {
+        std::string abuffer;
+        abuffer.reserve(1000);
+        abuffer.append(n, '\0');
+
+        SECTION("empty") {
+            abuffer.append(load_data("repeated_packed_" PBF_TYPE_NAME "/data-empty"));
+
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("one") {
+            abuffer.append(load_data("repeated_packed_" PBF_TYPE_NAME "/data-one"));
+
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            const auto it_range = item.GET_TYPE();
+            REQUIRE_FALSE(item.next());
+
+            REQUIRE(it_range.begin() != it_range.end());
+            REQUIRE(*it_range.begin() == 17);
+            REQUIRE(std::next(it_range.begin()) == it_range.end());
+        }
+
+        SECTION("many") {
+            abuffer.append(load_data("repeated_packed_" PBF_TYPE_NAME "/data-many"));
+
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            const auto it_range = item.GET_TYPE();
+            REQUIRE_FALSE(item.next());
+
+            auto it = it_range.begin();
+            REQUIRE(it != it_range.end());
+            REQUIRE(*it++ ==   17);
+            REQUIRE(*it++ ==  200);
+            REQUIRE(*it++ ==    0);
+            REQUIRE(*it++ ==    1);
+            REQUIRE(*it++ == std::numeric_limits<cpp_type>::max());
+#if PBF_TYPE_IS_SIGNED
+            REQUIRE(*it++ == -200);
+            REQUIRE(*it++ ==   -1);
+            REQUIRE(*it++ == std::numeric_limits<cpp_type>::min());
+#endif
+            REQUIRE(it == it_range.end());
+        }
+
+        SECTION("swap iterator range") {
+            abuffer.append(load_data("repeated_packed_" PBF_TYPE_NAME "/data-many"));
+
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            auto it_range1 = item.GET_TYPE();
+            REQUIRE_FALSE(item.next());
+
+            decltype(it_range1) it_range;
+            using std::swap;
+            swap(it_range, it_range1);
+
+            auto it = it_range.begin();
+            REQUIRE(it != it_range.end());
+            REQUIRE(*it++ ==   17);
+            REQUIRE(*it++ ==  200);
+            REQUIRE(*it++ ==    0);
+            REQUIRE(*it++ ==    1);
+            REQUIRE(*it++ == std::numeric_limits<cpp_type>::max());
+        }
+
+        SECTION("end_of_buffer") {
+            abuffer.append(load_data("repeated_packed_" PBF_TYPE_NAME "/data-many"));
+
+            for (std::string::size_type i = 1; i < abuffer.size() - n; ++i) {
+                protozero::pbf_reader item{abuffer.data() + n, i};
+                REQUIRE(item.next());
+                REQUIRE_THROWS_AS(item.GET_TYPE(), const protozero::end_of_buffer_exception&);
+            }
+        }
+
+    }
+
+}
+
+TEST_CASE("write repeated packed field: " PBF_TYPE_NAME) {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("empty") {
+        cpp_type data[] = { 17 };
+        pw.ADD_TYPE(1, std::begin(data), std::begin(data) /* !!!! */);
+
+        REQUIRE(buffer == load_data("repeated_packed_" PBF_TYPE_NAME "/data-empty"));
+    }
+
+    SECTION("one") {
+        cpp_type data[] = { 17 };
+        pw.ADD_TYPE(1, std::begin(data), std::end(data));
+
+        REQUIRE(buffer == load_data("repeated_packed_" PBF_TYPE_NAME "/data-one"));
+    }
+
+    SECTION("many") {
+        cpp_type data[] = {
+               17
+            , 200
+            ,   0
+            ,   1
+            ,std::numeric_limits<cpp_type>::max()
+#if PBF_TYPE_IS_SIGNED
+            ,-200
+            ,  -1
+            ,std::numeric_limits<cpp_type>::min()
+#endif
+        };
+        pw.ADD_TYPE(1, std::begin(data), std::end(data));
+
+        REQUIRE(buffer == load_data("repeated_packed_" PBF_TYPE_NAME "/data-many"));
+    }
+
+}
+
+TEST_CASE("write repeated packed field using packed field: " PBF_TYPE_NAME) {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("empty - should do rollback") {
+        {
+            packed_field_type field{pw, 1};
+        }
+
+        REQUIRE(buffer == load_data("repeated_packed_" PBF_TYPE_NAME "/data-empty"));
+    }
+
+    SECTION("one") {
+        {
+            packed_field_type field{pw, 1};
+            field.add_element(cpp_type(17));
+        }
+
+        REQUIRE(buffer == load_data("repeated_packed_" PBF_TYPE_NAME "/data-one"));
+    }
+
+    SECTION("many") {
+        {
+            packed_field_type field{pw, 1};
+            field.add_element(cpp_type(  17));
+            field.add_element(cpp_type( 200));
+            field.add_element(cpp_type(   0));
+            field.add_element(cpp_type(   1));
+            field.add_element(std::numeric_limits<cpp_type>::max());
+#if PBF_TYPE_IS_SIGNED
+            field.add_element(cpp_type(-200));
+            field.add_element(cpp_type(  -1));
+            field.add_element(std::numeric_limits<cpp_type>::min());
+#endif
+            REQUIRE(field.valid());
+            SECTION("with commit") {
+                field.commit();
+                REQUIRE_FALSE(field.valid());
+            }
+        }
+
+        REQUIRE(buffer == load_data("repeated_packed_" PBF_TYPE_NAME "/data-many"));
+    }
+}
+
+TEST_CASE("move repeated packed field: " PBF_TYPE_NAME) {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("move rvalue") {
+        packed_field_type field;
+        REQUIRE_FALSE(field.valid());
+        field = packed_field_type{pw, 1};
+        REQUIRE(field.valid());
+        field.add_element(cpp_type(17));
+    }
+
+    SECTION("explicit move") {
+        packed_field_type field2{pw, 1};
+        packed_field_type field;
+
+        REQUIRE(field2.valid());
+        REQUIRE_FALSE(field.valid());
+
+        field = std::move(field2);
+
+        REQUIRE_FALSE(field2.valid()); // NOLINT(hicpp-invalid-access-moved, bugprone-use-after-move)
+        REQUIRE(field.valid());
+
+        field.add_element(cpp_type(17));
+    }
+
+    SECTION("move constructor") {
+        packed_field_type field2{pw, 1};
+        REQUIRE(field2.valid());
+
+        packed_field_type field{std::move(field2)};
+        REQUIRE(field.valid());
+        REQUIRE_FALSE(field2.valid()); // NOLINT(hicpp-invalid-access-moved, bugprone-use-after-move)
+
+        field.add_element(cpp_type(17));
+    }
+
+    SECTION("swap") {
+        packed_field_type field;
+        packed_field_type field2{pw, 1};
+
+        REQUIRE_FALSE(field.valid());
+        REQUIRE(field2.valid());
+
+        using std::swap;
+        swap(field, field2);
+
+        REQUIRE(field.valid());
+        REQUIRE_FALSE(field2.valid());
+
+        field.add_element(cpp_type(17));
+    }
+
+    REQUIRE(buffer == load_data("repeated_packed_" PBF_TYPE_NAME "/data-one"));
+}
+
+TEST_CASE("write from different types of iterators: " PBF_TYPE_NAME) {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("from uint16_t") {
+#if PBF_TYPE_IS_SIGNED
+        const  int16_t data[] = { 1, 4, 9, 16, 25 };
+#else
+        const uint16_t data[] = { 1, 4, 9, 16, 25 };
+#endif
+
+        pw.ADD_TYPE(1, std::begin(data), std::end(data));
+    }
+
+    SECTION("from string") {
+        std::string data{"1 4 9 16 25"};
+        std::stringstream sdata{data};
+
+#if PBF_TYPE_IS_SIGNED
+        using test_type =  int32_t;
+#else
+        using test_type = uint32_t;
+#endif
+
+        std::istream_iterator<test_type> eod;
+        std::istream_iterator<test_type> it(sdata);
+
+        pw.ADD_TYPE(1, it, eod);
+    }
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    auto it_range = item.GET_TYPE();
+    REQUIRE_FALSE(item.next());
+    REQUIRE_FALSE(it_range.empty());
+    REQUIRE(std::distance(it_range.begin(), it_range.end()) == 5);
+    REQUIRE(it_range.size() == 5);
+
+    REQUIRE(it_range.front() ==  1); it_range.drop_front();
+    REQUIRE(it_range.front() ==  4); it_range.drop_front();
+    REQUIRE(std::distance(it_range.begin(), it_range.end()) == 3);
+    REQUIRE(it_range.size() == 3);
+    REQUIRE(it_range.front() ==  9); it_range.drop_front();
+    REQUIRE(it_range.front() == 16); it_range.drop_front();
+    REQUIRE(it_range.front() == 25); it_range.drop_front();
+    REQUIRE(it_range.empty());
+    REQUIRE(std::distance(it_range.begin(), it_range.end()) == 0);
+    REQUIRE(it_range.size() == 0); // NOLINT(readability-container-size-empty)
+
+    REQUIRE_THROWS_AS(it_range.front(), const assert_error&);
+    REQUIRE_THROWS_AS(it_range.drop_front(), const assert_error&);
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/scalar_access.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/scalar_access.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/scalar_access.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,129 @@
+// NOLINT(llvm-header-guard)
+
+#define PBF_TYPE_NAME PROTOZERO_TEST_STRING(PBF_TYPE)
+#define GET_TYPE PROTOZERO_TEST_CONCAT(get_, PBF_TYPE)
+#define ADD_TYPE PROTOZERO_TEST_CONCAT(add_, PBF_TYPE)
+
+TEST_CASE("read field: " PBF_TYPE_NAME) {
+
+    SECTION("zero") {
+        const std::string buffer = load_data(PBF_TYPE_NAME "/data-zero");
+
+        protozero::pbf_reader item{buffer};
+
+        REQUIRE(item.next());
+        REQUIRE(item.GET_TYPE() == 0);
+        REQUIRE_FALSE(item.next());
+    }
+
+    SECTION("positive") {
+        const std::string buffer = load_data(PBF_TYPE_NAME "/data-pos");
+
+        protozero::pbf_reader item{buffer};
+
+        REQUIRE(item.next());
+        REQUIRE(item.GET_TYPE() == 1);
+        REQUIRE_FALSE(item.next());
+    }
+
+    SECTION("pos200") {
+        const std::string buffer = load_data(PBF_TYPE_NAME "/data-pos200");
+
+        protozero::pbf_reader item{buffer};
+
+        REQUIRE(item.next());
+        REQUIRE(item.GET_TYPE() == 200);
+        REQUIRE_FALSE(item.next());
+    }
+
+    SECTION("max") {
+        const std::string buffer = load_data(PBF_TYPE_NAME "/data-max");
+
+        protozero::pbf_reader item{buffer};
+
+        REQUIRE(item.next());
+        REQUIRE(item.GET_TYPE() == std::numeric_limits<cpp_type>::max());
+        REQUIRE_FALSE(item.next());
+    }
+
+#if PBF_TYPE_IS_SIGNED
+    SECTION("negative") {
+        if (std::is_signed<cpp_type>::value) {
+            const std::string buffer = load_data(PBF_TYPE_NAME "/data-neg");
+
+            protozero::pbf_reader item{buffer};
+
+            REQUIRE(item.next());
+            REQUIRE(item.GET_TYPE() == -1);
+            REQUIRE_FALSE(item.next());
+        }
+    }
+
+    SECTION("neg200") {
+        const std::string buffer = load_data(PBF_TYPE_NAME "/data-neg200");
+
+        protozero::pbf_reader item{buffer};
+
+        REQUIRE(item.next());
+        REQUIRE(item.GET_TYPE() == -200);
+        REQUIRE_FALSE(item.next());
+    }
+
+    SECTION("min") {
+        if (std::is_signed<cpp_type>::value) {
+            const std::string buffer = load_data(PBF_TYPE_NAME "/data-min");
+
+            protozero::pbf_reader item{buffer};
+
+            REQUIRE(item.next());
+            REQUIRE(item.GET_TYPE() == std::numeric_limits<cpp_type>::min());
+            REQUIRE_FALSE(item.next());
+        }
+    }
+#endif
+
+    SECTION("end_of_buffer") {
+        const std::string buffer = load_data(PBF_TYPE_NAME "/data-max");
+
+        for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+            protozero::pbf_reader item{buffer.data(), i};
+            REQUIRE(item.next());
+            REQUIRE_THROWS_AS(item.GET_TYPE(), const protozero::end_of_buffer_exception&);
+        }
+    }
+}
+
+TEST_CASE("write field: " PBF_TYPE_NAME) {
+    std::string buffer;
+    protozero::pbf_writer pw(buffer);
+
+    SECTION("zero") {
+        pw.ADD_TYPE(1, 0);
+        REQUIRE(buffer == load_data(PBF_TYPE_NAME "/data-zero"));
+    }
+
+    SECTION("positive") {
+        pw.ADD_TYPE(1, 1);
+        REQUIRE(buffer == load_data(PBF_TYPE_NAME "/data-pos"));
+    }
+
+    SECTION("max") {
+        pw.ADD_TYPE(1, std::numeric_limits<cpp_type>::max());
+        REQUIRE(buffer == load_data(PBF_TYPE_NAME "/data-max"));
+    }
+
+#if PBF_TYPE_IS_SIGNED
+    SECTION("negative") {
+        pw.ADD_TYPE(1, -1);
+        REQUIRE(buffer == load_data(PBF_TYPE_NAME "/data-neg"));
+    }
+
+    SECTION("min") {
+        if (std::is_signed<cpp_type>::value) {
+            pw.ADD_TYPE(1, std::numeric_limits<cpp_type>::min());
+            REQUIRE(buffer == load_data(PBF_TYPE_NAME "/data-min"));
+        }
+    }
+#endif
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/test.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/test.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/test.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,28 @@
+#ifndef TEST_HPP
+#define TEST_HPP
+
+#include <catch.hpp>
+
+#include <stdexcept>
+// Define protozero_assert() to throw this error. This allows the tests to
+// check that the assert fails.
+struct assert_error : public std::runtime_error {
+    explicit assert_error(const char* what_arg) : std::runtime_error(what_arg) {
+    }
+};
+#define protozero_assert(x) if (!(x)) { throw assert_error{#x}; }
+
+#include <protozero/pbf_builder.hpp>
+#include <protozero/pbf_message.hpp>
+#include <protozero/pbf_reader.hpp>
+#include <protozero/pbf_writer.hpp>
+
+extern std::string load_data(const std::string& filename);
+
+#define PROTOZERO_TEST_CONCAT2(x, y) x##y
+#define PROTOZERO_TEST_CONCAT(x, y) PROTOZERO_TEST_CONCAT2(x, y)
+
+#define PROTOZERO_TEST_STRING2(s) #s
+#define PROTOZERO_TEST_STRING(s) PROTOZERO_TEST_STRING2(s)
+
+#endif // TEST_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/testcase.hpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/testcase.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/include/testcase.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,21 @@
+#ifndef TESTCASE_HPP
+#define TESTCASE_HPP
+
+#include <cassert>
+#include <fstream>
+#include <limits>
+#include <string>
+
+template <class T>
+std::string write_to_file(const T& msg, const char* filename) {
+    std::string out;
+
+    msg.SerializeToString(&out);
+    std::ofstream d{filename, std::ios_base::out|std::ios_base::binary};
+    assert(d.is_open());
+    d << out;
+
+    return out;
+}
+
+#endif // TESTCASE_HPP

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/reader_tests.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/reader_tests.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/reader_tests.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,30 @@
+
+#include <fstream>
+#include <stdexcept>
+#include <string>
+
+#define CATCH_CONFIG_MAIN
+#include <test.hpp> // IWYU pragma: keep
+
+std::string load_data(const std::string& filename) {
+    const char* tests_dir = std::getenv("TESTS_DIR");
+    if (tests_dir == nullptr) {
+        tests_dir = "test";
+    }
+
+    std::string fullname{tests_dir};
+    fullname += "/t/";
+    fullname += filename;
+    fullname += ".pbf";
+
+    std::ifstream stream{fullname, std::ios_base::in | std::ios_base::binary};
+    if (!stream.is_open()) {
+        throw std::runtime_error{"could not open: '" + filename + "'"};
+    }
+    std::string buffer{std::istreambuf_iterator<char>(stream.rdbuf()),
+                       std::istreambuf_iterator<char>()};
+    stream.close();
+
+    return buffer;
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/alignment/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/alignment/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/alignment/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,122 @@
+
+#include <test.hpp>
+
+// Run these tests twice, the second time we basically move the data
+// one byte down in the buffer. It doesn't matter how the data or buffer
+// is aligned before that, in at least one of these cases the int32 will
+// not be aligned properly. So we test that even in that case the int32
+// will be extracted properly.
+
+TEST_CASE("check alignment issues for fixed32 field") {
+    for (std::string::size_type n = 0; n < 2; ++n) {
+
+        std::string abuffer;
+        abuffer.reserve(1000);
+        abuffer.append(n, '\0');
+
+        SECTION("zero") {
+            abuffer.append(load_data("fixed32/data-zero"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(item.get_fixed32() == 0UL);
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("positive") {
+            abuffer.append(load_data("fixed32/data-pos"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(item.get_fixed32() == 1UL);
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("max") {
+            abuffer.append(load_data("fixed32/data-max"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(item.get_fixed32() == std::numeric_limits<uint32_t>::max());
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("end_of_buffer") {
+            abuffer.append(load_data("fixed32/data-pos"));
+
+            for (std::string::size_type i = 1; i < abuffer.size() - n; ++i) {
+                protozero::pbf_reader item{abuffer.data() + n, i};
+                REQUIRE(item.next());
+                REQUIRE_THROWS_AS(item.get_fixed32(), const protozero::end_of_buffer_exception&);
+            }
+        }
+
+        SECTION("assert detecting tag==0") {
+            abuffer.append(load_data("fixed32/data-zero"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE_THROWS_AS(item.get_fixed32(), const assert_error&);
+            REQUIRE(item.next());
+            REQUIRE(item.get_fixed32() == 0UL);
+            REQUIRE_THROWS(item.get_fixed32());
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("skip") {
+            abuffer.append(load_data("fixed32/data-zero"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE_THROWS_AS(item.skip(), const assert_error&);
+            REQUIRE(item.next());
+            item.skip();
+            REQUIRE_THROWS(item.skip());
+            REQUIRE_FALSE(item.next());
+        }
+    }
+}
+
+TEST_CASE("check alignment issues for fixed64 field") {
+    for (std::string::size_type n = 0; n < 2; ++n) {
+        std::string abuffer;
+        abuffer.reserve(1000);
+        abuffer.append(n, '\0');
+
+        SECTION("zero") {
+            abuffer.append(load_data("fixed64/data-zero"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(item.get_fixed64() == 0ULL);
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("positive") {
+            abuffer.append(load_data("fixed64/data-pos"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(item.get_fixed64() == 1ULL);
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("max") {
+            abuffer.append(load_data("fixed64/data-max"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(item.get_fixed64() == std::numeric_limits<uint64_t>::max());
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("end_of_buffer") {
+            abuffer.append(load_data("fixed64/data-pos"));
+
+            for (std::string::size_type i = 1; i < abuffer.size() - n; ++i) {
+                protozero::pbf_reader item{abuffer.data() + n, i};
+                REQUIRE(item.next());
+                REQUIRE_THROWS_AS(item.get_fixed64(), const protozero::end_of_buffer_exception&);
+            }
+        }
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/bool_testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/bool_testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/bool_testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,15 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestBoolean;
+
+message Test {
+
+    // this should be bool, but we are using uint32
+    // to be able to encode values other than 0 (false)
+    // and 1 (true)
+    required uint32 b = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-also-true.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-also-true.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-also-true.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-false.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-false.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-false.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-false.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-false.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-still-true.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-still-true.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-still-true.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+Ð
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-true.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-true.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/data-true.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,141 @@
+
+#include <test.hpp>
+
+namespace TestBoolean {
+
+enum class Test : protozero::pbf_tag_type {
+    required_bool_b = 1
+};
+
+} // end namespace TestBoolean
+
+TEST_CASE("read bool field using pbf_reader: false") {
+    const std::string buffer = load_data("bool/data-false");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE_FALSE(item.get_bool());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_reader: true") {
+    const std::string buffer = load_data("bool/data-true");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_bool());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_reader: also true") {
+    const std::string buffer = load_data("bool/data-also-true");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next(1));
+    REQUIRE(item.get_bool());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_reader: still true") {
+    const std::string buffer = load_data("bool/data-still-true");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next(1));
+    REQUIRE(item.get_bool());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_message: false") {
+    const std::string buffer = load_data("bool/data-false");
+
+    protozero::pbf_message<TestBoolean::Test> item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE_FALSE(item.get_bool());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_message: true") {
+    const std::string buffer = load_data("bool/data-true");
+
+    protozero::pbf_message<TestBoolean::Test> item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_bool());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_message: also true") {
+    const std::string buffer = load_data("bool/data-also-true");
+
+    protozero::pbf_message<TestBoolean::Test> item{buffer};
+
+    REQUIRE(item.next(TestBoolean::Test::required_bool_b));
+    REQUIRE(item.get_bool());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_message: still true") {
+    const std::string buffer = load_data("bool/data-still-true");
+
+    protozero::pbf_message<TestBoolean::Test> item{buffer};
+
+    REQUIRE(item.next(TestBoolean::Test::required_bool_b));
+    REQUIRE(item.get_bool());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("write bool field using pbf_writer") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("false") {
+        pw.add_bool(1, false);
+        REQUIRE(buffer == load_data("bool/data-false"));
+    }
+
+    SECTION("true") {
+        pw.add_bool(1, true);
+        REQUIRE(buffer == load_data("bool/data-true"));
+    }
+}
+
+TEST_CASE("write bool field using pbf_builder") {
+    std::string buffer;
+    protozero::pbf_builder<TestBoolean::Test> pw{buffer};
+
+    SECTION("false") {
+        pw.add_bool(TestBoolean::Test::required_bool_b, false);
+        REQUIRE(buffer == load_data("bool/data-false"));
+    }
+
+    SECTION("true") {
+        pw.add_bool(TestBoolean::Test::required_bool_b, true);
+        REQUIRE(buffer == load_data("bool/data-true"));
+    }
+}
+
+TEST_CASE("write bool field using moved pbf_builder") {
+    std::string buffer;
+    protozero::pbf_builder<TestBoolean::Test> pw2{buffer};
+    REQUIRE(pw2.valid());
+
+    protozero::pbf_builder<TestBoolean::Test> pw{std::move(pw2)};
+    REQUIRE(pw.valid());
+    REQUIRE_FALSE(pw2.valid()); // NOLINT(hicpp-invalid-access-moved, bugprone-use-after-move)
+
+    SECTION("false") {
+        pw.add_bool(TestBoolean::Test::required_bool_b, false);
+        REQUIRE(buffer == load_data("bool/data-false"));
+    }
+
+    SECTION("true") {
+        pw.add_bool(TestBoolean::Test::required_bool_b, true);
+        REQUIRE(buffer == load_data("bool/data-true"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,20 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestBoolean::Test msg;
+
+    msg.set_b(0);
+    write_to_file(msg, "data-false.pbf");
+
+    msg.set_b(1);
+    write_to_file(msg, "data-true.pbf");
+
+    msg.set_b(2);
+    write_to_file(msg, "data-also-true.pbf");
+
+    msg.set_b(2000);
+    write_to_file(msg, "data-still-true.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/writer_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/writer_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bool/writer_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,32 @@
+
+#include <string>
+
+#include <test.hpp> // IWYU pragma: keep
+
+#include "t/bool/bool_testcase.pb.h"
+
+TEST_CASE("write bool field and check with libprotobuf") {
+
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    TestBoolean::Test msg;
+
+    SECTION("false") {
+        pw.add_bool(1, false);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE_FALSE(msg.b());
+    }
+
+    SECTION("true") {
+        pw.add_bool(1, true);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.b());
+    }
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/bytes_testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/bytes_testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/bytes_testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestBytes;
+
+message Test {
+
+    required bytes s = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-binary.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-binary.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-binary.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-empty.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-empty.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-empty.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-empty.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-empty.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-one.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+x
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-string.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-string.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/data-string.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+foobar
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,139 @@
+
+#include <test.hpp>
+
+TEST_CASE("read bytes field: empty") {
+    const std::string buffer = load_data("bytes/data-empty");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_bytes().empty());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bytes field: one") {
+    const std::string buffer = load_data("bytes/data-one");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_bytes() == "x");
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bytes field: string") {
+    const std::string buffer = load_data("bytes/data-string");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_bytes() == "foobar");
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bytes field: binary") {
+    const std::string buffer = load_data("bytes/data-binary");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    const std::string data = item.get_bytes();
+    REQUIRE(data.size() == 3);
+    REQUIRE(data[0] == char(1));
+    REQUIRE(data[1] == char(2));
+    REQUIRE(data[2] == char(3));
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bytes field: end of buffer") {
+    const std::string buffer = load_data("bytes/data-binary");
+
+    for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+        protozero::pbf_reader item{buffer.data(), i};
+        REQUIRE(item.next());
+        REQUIRE_THROWS_AS(item.get_bytes(), const protozero::end_of_buffer_exception&);
+    }
+}
+
+TEST_CASE("write bytes field") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("empty") {
+        pw.add_string(1, "");
+        REQUIRE(buffer == load_data("bytes/data-empty"));
+    }
+
+    SECTION("one") {
+        pw.add_string(1, "x");
+        REQUIRE(buffer == load_data("bytes/data-one"));
+    }
+
+    SECTION("string") {
+        pw.add_string(1, "foobar");
+        REQUIRE(buffer == load_data("bytes/data-string"));
+    }
+
+    SECTION("binary") {
+        std::string data;
+        data.append(1, char(1));
+        data.append(1, char(2));
+        data.append(1, char(3));
+
+        pw.add_string(1, data);
+
+        REQUIRE(buffer == load_data("bytes/data-binary"));
+    }
+}
+
+TEST_CASE("write bytes field using vectored approach") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("using two strings") {
+        std::string d1{"foo"};
+        std::string d2{"bar"};
+
+        pw.add_bytes_vectored(1, d1, d2);
+    }
+
+    SECTION("using a string and a dataview") {
+        std::string d1{"foo"};
+        std::string d2{"bar"};
+        protozero::data_view dv{d2};
+
+        pw.add_bytes_vectored(1, d1, dv);
+    }
+
+    SECTION("using three strings") {
+        std::string d1{"foo"};
+        std::string d2{"ba"};
+        std::string d3{"r"};
+
+        pw.add_bytes_vectored(1, d1, d2, d3);
+    }
+
+    SECTION("with empty string") {
+        std::string d1{"foo"};
+        std::string d2{};
+        std::string d3{"bar"};
+
+        pw.add_bytes_vectored(1, d1, d2, d3);
+    }
+
+    REQUIRE(buffer == load_data("bytes/data-string"));
+}
+
+TEST_CASE("write bytes field using vectored approach with builder") {
+    enum class foo : protozero::pbf_tag_type { bar = 1 };
+    std::string buffer;
+    protozero::pbf_builder<foo> pw{buffer};
+
+    const std::string d1{"foo"};
+    const std::string d2{"bar"};
+
+    pw.add_bytes_vectored(foo::bar, d1, d2);
+
+    REQUIRE(buffer == load_data("bytes/data-string"));
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,24 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestBytes::Test msg;
+
+    msg.set_s("");
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.set_s("x");
+    write_to_file(msg, "data-one.pbf");
+
+    msg.set_s("foobar");
+    write_to_file(msg, "data-string.pbf");
+
+    std::string data;
+    data.append(1, char(1));
+    data.append(1, char(2));
+    data.append(1, char(3));
+    msg.set_s(data);
+    write_to_file(msg, "data-binary.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/writer_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/writer_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/bytes/writer_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,54 @@
+
+#include <test.hpp>
+
+#include "t/bytes/bytes_testcase.pb.h"
+
+TEST_CASE("write bytes field and check with libprotobuf") {
+
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    TestBytes::Test msg;
+
+    SECTION("empty") {
+        pw.add_string(1, "");
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.s().empty());
+    }
+
+    SECTION("one") {
+        pw.add_string(1, "x");
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.s() == "x");
+    }
+
+    SECTION("string") {
+        pw.add_string(1, "foobar");
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.s() == "foobar");
+    }
+
+    SECTION("binary") {
+        std::string data;
+        data.append(1, char(1));
+        data.append(1, char(2));
+        data.append(1, char(3));
+
+        pw.add_string(1, data);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.s().size() == 3);
+        REQUIRE(msg.s()[1] == char(2));
+        REQUIRE(msg.s()[2] == char(3));
+        REQUIRE(msg.s()[2] == char(3));
+    }
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-all.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-all.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-all.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-all.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-all.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-minimal.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-minimal.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-minimal.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-minimal.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-minimal.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-some.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-some.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-some.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-some.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/data-some.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,678 @@
+
+#include <test.hpp>
+
+namespace TestComplex {
+
+enum class Test : protozero::pbf_tag_type {
+    required_fixed32_f      = 1,
+    optional_int64_i        = 2,
+    optional_int64_j        = 3,
+    required_Sub_submessage = 5,
+    optional_string_s       = 8,
+    repeated_uint32_u       = 4,
+    packed_sint32_d         = 7
+};
+
+enum class Sub : protozero::pbf_tag_type {
+    required_string_s = 1
+};
+
+} // namespace TestComplex
+
+TEST_CASE("read complex data using pbf_reader: minimal") {
+    const std::string buffer = load_data("complex/data-minimal");
+
+    protozero::pbf_reader item{buffer};
+
+    while (item.next()) {
+        switch (item.tag()) {
+            case 1: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case 5: {
+                protozero::pbf_reader subitem = item.get_message();
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+}
+
+TEST_CASE("read complex data using pbf_reader: some") {
+    const std::string buffer = load_data("complex/data-some");
+
+    protozero::pbf_reader item2{buffer};
+    protozero::pbf_reader item;
+    using std::swap;
+    swap(item, item2);
+
+    uint32_t sum_of_u = 0;
+    while (item.next()) {
+        switch (item.tag()) {
+            case 1: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case 2: {
+                REQUIRE(true);
+                item.skip();
+                break;
+            }
+            case 4: {
+                sum_of_u += item.get_uint32();
+                break;
+            }
+            case 5: {
+                protozero::pbf_reader subitem = item.get_message();
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+    REQUIRE(sum_of_u == 66);
+}
+
+TEST_CASE("read complex data using pbf_reader: all") {
+    const std::string buffer = load_data("complex/data-all");
+
+    protozero::pbf_reader item{buffer};
+
+    int number_of_u = 0;
+    while (item.next()) {
+        switch (item.tag()) {
+            case 1: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case 2: {
+                REQUIRE(true);
+                item.skip();
+                break;
+            }
+            case 3: {
+                REQUIRE(item.get_int64() == 555555555LL);
+                break;
+            }
+            case 4: {
+                item.skip();
+                ++number_of_u;
+                break;
+            }
+            case 5: {
+                protozero::pbf_reader subitem = item.get_message();
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            case 7: {
+                const auto pi = item.get_packed_sint32();
+                int32_t sum = 0;
+                for (auto val : pi) {
+                    sum += val;
+                }
+                REQUIRE(sum == 5);
+                break;
+            }
+            case 8: {
+                REQUIRE(item.get_string() == "optionalstring");
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+    REQUIRE(number_of_u == 5);
+}
+
+TEST_CASE("read complex data using pbf_reader: skip everything") {
+    const std::string buffer = load_data("complex/data-all");
+
+    protozero::pbf_reader item{buffer};
+
+    while (item.next()) {
+        switch (item.tag()) {
+            case 1:
+            case 2:
+            case 3:
+            case 4:
+            case 5:
+            case 7:
+            case 8:
+                item.skip();
+                break;
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+}
+
+TEST_CASE("read complex data using pbf_message: minimal") {
+    const std::string buffer = load_data("complex/data-minimal");
+
+    protozero::pbf_message<TestComplex::Test> item{buffer};
+
+    while (item.next()) {
+        switch (item.tag()) {
+            case TestComplex::Test::required_fixed32_f: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case TestComplex::Test::required_Sub_submessage: {
+                protozero::pbf_message<TestComplex::Sub> subitem{item.get_message()};
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+}
+
+TEST_CASE("read complex data using pbf_message: some") {
+    const std::string buffer = load_data("complex/data-some");
+
+    protozero::pbf_message<TestComplex::Test> item2{buffer};
+    protozero::pbf_message<TestComplex::Test> item;
+    using std::swap;
+    swap(item, item2);
+
+    uint32_t sum_of_u = 0;
+    while (item.next()) {
+        switch (item.tag()) {
+            case TestComplex::Test::required_fixed32_f: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case TestComplex::Test::optional_int64_i: {
+                REQUIRE(true);
+                item.skip();
+                break;
+            }
+            case TestComplex::Test::repeated_uint32_u: {
+                sum_of_u += item.get_uint32();
+                break;
+            }
+            case TestComplex::Test::required_Sub_submessage: {
+                protozero::pbf_message<TestComplex::Sub> subitem = item.get_message();
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+    REQUIRE(sum_of_u == 66);
+}
+
+TEST_CASE("read complex data using pbf_message: all") {
+    const std::string buffer = load_data("complex/data-all");
+
+    protozero::pbf_message<TestComplex::Test> item{buffer};
+
+    int number_of_u = 0;
+    while (item.next()) {
+        switch (item.tag()) {
+            case TestComplex::Test::required_fixed32_f: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case TestComplex::Test::optional_int64_i: {
+                REQUIRE(true);
+                item.skip();
+                break;
+            }
+            case TestComplex::Test::optional_int64_j: {
+                REQUIRE(item.get_int64() == 555555555LL);
+                break;
+            }
+            case TestComplex::Test::repeated_uint32_u: {
+                item.skip();
+                ++number_of_u;
+                break;
+            }
+            case TestComplex::Test::required_Sub_submessage: {
+                protozero::pbf_message<TestComplex::Sub> subitem = item.get_message();
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            case TestComplex::Test::packed_sint32_d: {
+                const auto pi = item.get_packed_sint32();
+                int32_t sum = 0;
+                for (auto val : pi) {
+                    sum += val;
+                }
+                REQUIRE(sum == 5);
+                break;
+            }
+            case TestComplex::Test::optional_string_s: {
+                REQUIRE(item.get_string() == "optionalstring");
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+    REQUIRE(number_of_u == 5);
+}
+
+TEST_CASE("read complex data using pbf_message: skip everything") {
+    const std::string buffer = load_data("complex/data-all");
+
+    protozero::pbf_message<TestComplex::Test> item{buffer};
+
+    while (item.next()) {
+        switch (item.tag()) {
+            case TestComplex::Test::required_fixed32_f:
+            case TestComplex::Test::optional_int64_i:
+            case TestComplex::Test::optional_int64_j:
+            case TestComplex::Test::repeated_uint32_u:
+            case TestComplex::Test::required_Sub_submessage:
+            case TestComplex::Test::packed_sint32_d:
+            case TestComplex::Test::optional_string_s:
+                item.skip();
+                break;
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+}
+
+TEST_CASE("write complex data using pbf_writer: minimal") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+    pw.add_fixed32(1, 12345678);
+
+    std::string submessage;
+    protozero::pbf_writer pws{submessage};
+    pws.add_string(1, "foobar");
+
+    pw.add_message(5, submessage);
+
+    protozero::pbf_reader item{buffer};
+
+    while (item.next()) {
+        switch (item.tag()) {
+            case 1: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case 5: {
+                protozero::pbf_reader subitem = item.get_message();
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+}
+
+TEST_CASE("write complex data using pbf_writer: some") {
+    std::string buffer;
+    protozero::pbf_writer pw2{buffer};
+    pw2.add_fixed32(1, 12345678);
+
+    protozero::pbf_writer pw;
+    using std::swap;
+    swap(pw, pw2);
+
+    REQUIRE(pw.valid());
+    REQUIRE_FALSE(pw2.valid());
+
+    std::string submessage;
+    protozero::pbf_writer pws{submessage};
+    pws.add_string(1, "foobar");
+
+    pw.add_uint32(4, 22);
+    pw.add_uint32(4, 44);
+    pw.add_int64(2, -9876543);
+    pw.add_message(5, submessage);
+
+    protozero::pbf_reader item{buffer};
+
+    uint32_t sum_of_u = 0;
+    while (item.next()) {
+        switch (item.tag()) {
+            case 1: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case 2: {
+                REQUIRE(true);
+                item.skip();
+                break;
+            }
+            case 4: {
+                sum_of_u += item.get_uint32();
+                break;
+            }
+            case 5: {
+                const auto view = item.get_view();
+                protozero::pbf_reader subitem{view};
+                REQUIRE(subitem.next());
+                REQUIRE(std::string(subitem.get_view()) == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+    REQUIRE(sum_of_u == 66);
+}
+
+TEST_CASE("write complex data using pbf_writer: all") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+    pw.add_fixed32(1, 12345678);
+
+    std::string submessage;
+    protozero::pbf_writer pws{submessage};
+    pws.add_string(1, "foobar");
+    pw.add_message(5, submessage);
+
+    pw.add_uint32(4, 22);
+    pw.add_uint32(4, 44);
+    pw.add_int64(2, -9876543);
+    pw.add_uint32(4, 44);
+    pw.add_uint32(4, 66);
+    pw.add_uint32(4, 66);
+
+    const int32_t d[] = { -17, 22 };
+    pw.add_packed_sint32(7, std::begin(d), std::end(d));
+
+    pw.add_int64(3, 555555555);
+
+    protozero::pbf_reader item{buffer};
+
+    int number_of_u = 0;
+    while (item.next()) {
+        switch (item.tag()) {
+            case 1: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case 2: {
+                REQUIRE(true);
+                item.skip();
+                break;
+            }
+            case 3: {
+                REQUIRE(item.get_int64() == 555555555LL);
+                break;
+            }
+            case 4: {
+                item.skip();
+                ++number_of_u;
+                break;
+            }
+            case 5: {
+                protozero::pbf_reader subitem = item.get_message();
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            case 7: {
+                const auto pi = item.get_packed_sint32();
+                int32_t sum = 0;
+                for (auto val : pi) {
+                    sum += val;
+                }
+                REQUIRE(sum == 5);
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+    REQUIRE(number_of_u == 5);
+}
+
+TEST_CASE("write complex data using pbf_builder: minimal") {
+    std::string buffer;
+    protozero::pbf_builder<TestComplex::Test> pw{buffer};
+    pw.add_fixed32(TestComplex::Test::required_fixed32_f, 12345678);
+
+    std::string submessage;
+    protozero::pbf_builder<TestComplex::Sub> pws{submessage};
+    pws.add_string(TestComplex::Sub::required_string_s, "foobar");
+
+    pw.add_message(TestComplex::Test::required_Sub_submessage, submessage);
+
+    protozero::pbf_reader item{buffer};
+
+    while (item.next()) {
+        switch (item.tag()) {
+            case 1: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case 5: {
+                protozero::pbf_reader subitem = item.get_message();
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+}
+
+TEST_CASE("write complex data using pbf_builder: some") {
+    std::string buffer;
+    protozero::pbf_builder<TestComplex::Test> pw2{buffer};
+    pw2.add_fixed32(TestComplex::Test::required_fixed32_f, 12345678);
+
+    std::string dummy_buffer;
+    protozero::pbf_builder<TestComplex::Test> pw{dummy_buffer};
+    using std::swap;
+    swap(pw, pw2);
+
+    std::string submessage;
+    protozero::pbf_builder<TestComplex::Sub> pws{submessage};
+    pws.add_string(TestComplex::Sub::required_string_s, "foobar");
+
+    pw.add_uint32(TestComplex::Test::repeated_uint32_u, 22);
+    pw.add_uint32(TestComplex::Test::repeated_uint32_u, 44);
+    pw.add_int64(TestComplex::Test::optional_int64_i, -9876543);
+    pw.add_message(TestComplex::Test::required_Sub_submessage, submessage);
+
+    protozero::pbf_reader item{buffer};
+
+    uint32_t sum_of_u = 0;
+    while (item.next()) {
+        switch (item.tag()) {
+            case 1: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case 2: {
+                REQUIRE(true);
+                item.skip();
+                break;
+            }
+            case 4: {
+                sum_of_u += item.get_uint32();
+                break;
+            }
+            case 5: {
+                protozero::pbf_reader subitem = item.get_message();
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+    REQUIRE(sum_of_u == 66);
+}
+
+TEST_CASE("write complex data using pbf_builder: all") {
+    std::string buffer;
+    protozero::pbf_builder<TestComplex::Test> pw{buffer};
+    pw.add_fixed32(TestComplex::Test::required_fixed32_f, 12345678);
+
+    std::string submessage;
+    protozero::pbf_builder<TestComplex::Sub> pws{submessage};
+    pws.add_string(TestComplex::Sub::required_string_s, "foobar");
+    pw.add_message(TestComplex::Test::required_Sub_submessage, submessage);
+
+    pw.add_uint32(TestComplex::Test::repeated_uint32_u, 22);
+    pw.add_uint32(TestComplex::Test::repeated_uint32_u, 44);
+    pw.add_int64(TestComplex::Test::optional_int64_i, -9876543);
+    pw.add_uint32(TestComplex::Test::repeated_uint32_u, 44);
+    pw.add_uint32(TestComplex::Test::repeated_uint32_u, 66);
+    pw.add_uint32(TestComplex::Test::repeated_uint32_u, 66);
+
+    const int32_t d[] = { -17, 22 };
+    pw.add_packed_sint32(TestComplex::Test::packed_sint32_d, std::begin(d), std::end(d));
+
+    pw.add_int64(TestComplex::Test::optional_int64_j, 555555555);
+
+    protozero::pbf_reader item{buffer};
+
+    int number_of_u = 0;
+    while (item.next()) {
+        switch (item.tag()) {
+            case 1: {
+                REQUIRE(item.get_fixed32() == 12345678L);
+                break;
+            }
+            case 2: {
+                REQUIRE(true);
+                item.skip();
+                break;
+            }
+            case 3: {
+                REQUIRE(item.get_int64() == 555555555LL);
+                break;
+            }
+            case 4: {
+                item.skip();
+                ++number_of_u;
+                break;
+            }
+            case 5: {
+                protozero::pbf_reader subitem = item.get_message();
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            case 7: {
+                const auto pi = item.get_packed_sint32();
+                int32_t sum = 0;
+                for (auto val : pi) {
+                    sum += val;
+                }
+                REQUIRE(sum == 5);
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+    REQUIRE(number_of_u == 5);
+}
+
+static void check_message(const std::string& buffer) {
+    protozero::pbf_reader item{buffer};
+
+    while (item.next()) {
+        switch (item.tag()) {
+            case 1: {
+                REQUIRE(item.get_fixed32() == 42L);
+                break;
+            }
+            case 5: {
+                protozero::pbf_reader subitem = item.get_message();
+                REQUIRE(subitem.next());
+                REQUIRE(subitem.get_string() == "foobar");
+                REQUIRE_FALSE(subitem.next());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should not be here
+                break;
+            }
+        }
+    }
+}
+
+TEST_CASE("write complex with subwriter using pbf_writer") {
+    std::string buffer_test;
+    protozero::pbf_writer pbf_test{buffer_test};
+    pbf_test.add_fixed32(1, 42L);
+
+    SECTION("message in message") {
+        protozero::pbf_writer pbf_submessage{pbf_test, 5};
+        pbf_submessage.add_string(1, "foobar");
+    }
+
+    check_message(buffer_test);
+}
+
+TEST_CASE("write complex with subwriter using pbf_builder") {
+    std::string buffer_test;
+    protozero::pbf_builder<TestComplex::Test> pbf_test{buffer_test};
+    pbf_test.add_fixed32(TestComplex::Test::required_fixed32_f, 42L);
+
+    SECTION("message in message") {
+        protozero::pbf_builder<TestComplex::Sub> pbf_submessage{pbf_test, TestComplex::Test::required_Sub_submessage};
+        pbf_submessage.add_string(TestComplex::Sub::required_string_s, "foobar");
+    }
+
+    check_message(buffer_test);
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,30 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestComplex::Test msg;
+
+    msg.set_f(12345678);
+    TestComplex::Sub* submsg = msg.mutable_submessage();
+    submsg->set_s("foobar");
+
+    write_to_file(msg, "data-minimal.pbf");
+
+    msg.add_u(22);
+    msg.add_u(44);
+    msg.set_i(-9876543);
+
+    write_to_file(msg, "data-some.pbf");
+
+    msg.set_s("optionalstring");
+    msg.add_u(44);
+    msg.add_u(66);
+    msg.add_u(66);
+    msg.add_d(-17);
+    msg.add_d(22);
+    msg.set_j(555555555);
+
+    write_to_file(msg, "data-all.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/complex/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,20 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestComplex;
+
+message Sub {
+    required string s = 1;
+}
+
+message Test {
+    required fixed32 f = 1;
+    optional int64 i = 2;
+    optional int64 j = 3;
+    required Sub submessage = 5;
+    optional string s = 8;
+    repeated uint32 u = 4;
+    repeated sint32 d = 7 [packed=true];
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-neg.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-neg.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-neg.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+	×£p=*ÂÀ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-pos.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+	ßO—n’@
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/double_testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/double_testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/double_testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestDouble;
+
+message Test {
+
+    required double x = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,73 @@
+
+#include <test.hpp>
+
+TEST_CASE("read double field") {
+    // Run these tests twice, the second time we basically move the data
+    // one byte down in the buffer. It doesn't matter how the data or buffer
+    // is aligned before that, in at least one of these cases the double will
+    // not be aligned properly. So we test that even in that case the double
+    // will be extracted properly.
+    for (std::string::size_type n = 0; n < 2; ++n) {
+        std::string abuffer;
+        abuffer.reserve(1000);
+        abuffer.append(n, '\0');
+
+        SECTION("zero") {
+            abuffer.append(load_data("double/data-zero"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(item.get_double() == Approx(0.0));
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("positive") {
+            abuffer.append(load_data("double/data-pos"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(item.get_double() == Approx(4.893));
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("negative") {
+            abuffer.append(load_data("double/data-neg"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(item.get_double() == Approx(-9232.33));
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("end_of_buffer") {
+            abuffer.append(load_data("double/data-neg"));
+
+            for (std::string::size_type i = 1; i < abuffer.size() - n; ++i) {
+                protozero::pbf_reader item{abuffer.data() + n, i};
+                REQUIRE(item.next());
+                REQUIRE_THROWS_AS(item.get_double(), const protozero::end_of_buffer_exception&);
+            }
+        }
+    }
+}
+
+TEST_CASE("write double field") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("zero") {
+        pw.add_double(1, 0.0);
+        REQUIRE(buffer == load_data("double/data-zero"));
+    }
+
+    SECTION("positive") {
+        pw.add_double(1, 4.893);
+        REQUIRE(buffer == load_data("double/data-pos"));
+    }
+
+    SECTION("negative") {
+        pw.add_double(1, -9232.33);
+        REQUIRE(buffer == load_data("double/data-neg"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,17 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestDouble::Test msg;
+
+    msg.set_x(0.0);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_x(4.893);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_x(-9232.33);
+    write_to_file(msg, "data-neg.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/writer_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/writer_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/double/writer_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,38 @@
+
+#include <test.hpp>
+
+#include "t/double/double_testcase.pb.h"
+
+TEST_CASE("write double field and check with libprotobuf") {
+
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    TestDouble::Test msg;
+
+    SECTION("zero") {
+        pw.add_double(1, 0.0);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.x() == Approx(0.0));
+    }
+
+    SECTION("positive") {
+        pw.add_double(1, 4.893);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.x() == Approx(4.893));
+    }
+
+    SECTION("negative") {
+        pw.add_double(1, -9232.33);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.x() == Approx(-9232.33));
+    }
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-black.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-black.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-black.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-black.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-black.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-blue.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-blue.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-blue.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-max.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+ÿÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-min.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-min.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-min.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-min.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-min.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-neg.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-neg.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-neg.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-neg.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/data-neg.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/enum_testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/enum_testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/enum_testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,26 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestEnum;
+
+enum Color {
+    BLACK = 0;
+    RED   = 1;
+    GREEN = 2;
+    BLUE  = 3;
+    MAX   = 2147483646;
+    NEG   = -1;
+
+    // Older versions (before 2.6.0) of the google protobuf compiler have a
+    // bug and don't allow the real minimum of -2147483648, so we are testing
+    // with this.
+    MIN   = -2147483647;
+}
+
+message Test {
+
+    required Color color = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,83 @@
+
+#include <test.hpp>
+
+TEST_CASE("read enum field: zero") {
+    const std::string buffer = load_data("enum/data-black");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_enum() == 0L);
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read enum field: positive") {
+    const std::string buffer = load_data("enum/data-blue");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_enum() == 3L);
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read enum field: negative") {
+    const std::string buffer = load_data("enum/data-neg");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_enum() == -1L);
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read enum field: max") {
+    const std::string buffer = load_data("enum/data-max");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_enum() == std::numeric_limits<int32_t>::max());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read enum field: min") {
+    const std::string buffer = load_data("enum/data-min");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_enum() == (std::numeric_limits<int32_t>::min() + 1));
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("write enum field") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("zero") {
+        pw.add_enum(1, 0L);
+        REQUIRE(buffer == load_data("enum/data-black"));
+    }
+
+    SECTION("positive") {
+        pw.add_enum(1, 3L);
+        REQUIRE(buffer == load_data("enum/data-blue"));
+    }
+
+    SECTION("negative") {
+        pw.add_enum(1, -1L);
+        REQUIRE(buffer == load_data("enum/data-neg"));
+    }
+
+    SECTION("max") {
+        pw.add_enum(1, std::numeric_limits<int32_t>::max());
+        REQUIRE(buffer == load_data("enum/data-max"));
+    }
+
+    SECTION("min") {
+        pw.add_enum(1, std::numeric_limits<int32_t>::min() + 1);
+        REQUIRE(buffer == load_data("enum/data-min"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,23 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestEnum::Test msg;
+
+    msg.set_color(TestEnum::BLACK);
+    write_to_file(msg, "data-black.pbf");
+
+    msg.set_color(TestEnum::BLUE);
+    write_to_file(msg, "data-blue.pbf");
+
+    msg.set_color(TestEnum::NEG);
+    write_to_file(msg, "data-neg.pbf");
+
+    msg.set_color(TestEnum::MAX);
+    write_to_file(msg, "data-max.pbf");
+
+    msg.set_color(TestEnum::MIN);
+    write_to_file(msg, "data-min.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/writer_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/writer_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/enum/writer_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,54 @@
+
+#include <test.hpp>
+
+#include "t/enum/enum_testcase.pb.h"
+
+TEST_CASE("write enum field and check with libprotobuf") {
+
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    TestEnum::Test msg;
+
+    SECTION("zero") {
+        pw.add_enum(1, 0L);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.color() == TestEnum::Color::BLACK);
+    }
+
+    SECTION("positive") {
+        pw.add_enum(1, 3L);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.color() == TestEnum::Color::BLUE);
+    }
+
+    SECTION("negative") {
+        pw.add_enum(1, -1L);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.color() == TestEnum::Color::NEG);
+    }
+
+    SECTION("max") {
+        pw.add_enum(1, std::numeric_limits<int32_t>::max() - 1);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.color() == TestEnum::Color::MAX);
+    }
+
+    SECTION("min") {
+        pw.add_enum(1, std::numeric_limits<int32_t>::min() + 1);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.color() == TestEnum::Color::MIN);
+    }
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-max.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+ÿÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos200.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos200.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos200.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-pos200.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/fixed32_testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/fixed32_testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/fixed32_testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestFixed32;
+
+message Test {
+
+    required fixed32 i = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE fixed32
+#define PBF_TYPE_IS_SIGNED 0
+using cpp_type = uint32_t;
+
+#include <scalar_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,20 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestFixed32::Test msg;
+
+    msg.set_i(0);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_i(1);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_i(200);
+    write_to_file(msg, "data-pos200.pbf");
+
+    msg.set_i(std::numeric_limits<uint32_t>::max());
+    write_to_file(msg, "data-max.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/writer_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/writer_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed32/writer_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,38 @@
+
+#include <test.hpp>
+
+#include "t/fixed32/fixed32_testcase.pb.h"
+
+TEST_CASE("write fixed32 field and check with libprotobuf") {
+
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    TestFixed32::Test msg;
+
+    SECTION("zero") {
+        pw.add_fixed32(1, 0);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i() == 0);
+    }
+
+    SECTION("max") {
+        pw.add_fixed32(1, std::numeric_limits<uint32_t>::max());
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i() == std::numeric_limits<uint32_t>::max());
+    }
+
+    SECTION("min") {
+        pw.add_fixed32(1, std::numeric_limits<uint32_t>::min());
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i() == std::numeric_limits<uint32_t>::min());
+    }
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-max.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-max.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-max.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos200.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos200.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos200.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-pos200.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE fixed64
+#define PBF_TYPE_IS_SIGNED 0
+using cpp_type = uint64_t;
+
+#include <scalar_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,20 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestFixed64::Test msg;
+
+    msg.set_i(0);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_i(1);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_i(200);
+    write_to_file(msg, "data-pos200.pbf");
+
+    msg.set_i(std::numeric_limits<uint64_t>::max());
+    write_to_file(msg, "data-max.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/fixed64/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestFixed64;
+
+message Test {
+
+    required fixed64 i = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-neg.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-neg.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-neg.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+HáÚ¿
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-pos.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+Háª@
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,74 @@
+
+#include <test.hpp>
+
+TEST_CASE("read float field") {
+    // Run these tests twice, the second time we basically move the data
+    // one byte down in the buffer. It doesn't matter how the data or buffer
+    // is aligned before that, in at least one of these cases the float will
+    // not be aligned properly. So we test that even in that case the float
+    // will be extracted properly.
+
+    for (std::string::size_type n = 0; n < 2; ++n) {
+        std::string abuffer;
+        abuffer.reserve(1000);
+        abuffer.append(n, '\0');
+
+        SECTION("zero") {
+            abuffer.append(load_data("float/data-zero"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(double(item.get_float()) == Approx(0.0));
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("positive") {
+            abuffer.append(load_data("float/data-pos"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(double(item.get_float()) == Approx(5.34));
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("negative") {
+            abuffer.append(load_data("float/data-neg"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            REQUIRE(double(item.get_float()) == Approx(-1.71));
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("end_of_buffer") {
+            abuffer.append(load_data("float/data-neg"));
+
+            for (std::string::size_type i = 1; i < abuffer.size() - n; ++i) {
+                protozero::pbf_reader item{abuffer.data() + n, i};
+                REQUIRE(item.next());
+                REQUIRE_THROWS_AS(item.get_float(), const protozero::end_of_buffer_exception&);
+            }
+        }
+    }
+}
+
+TEST_CASE("write float field") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("zero") {
+        pw.add_float(1, 0.0f);
+        REQUIRE(buffer == load_data("float/data-zero"));
+    }
+
+    SECTION("positive") {
+        pw.add_float(1, 5.34f);
+        REQUIRE(buffer == load_data("float/data-pos"));
+    }
+
+    SECTION("negative") {
+        pw.add_float(1, -1.71f);
+        REQUIRE(buffer == load_data("float/data-neg"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,17 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestFloat::Test msg;
+
+    msg.set_x(0.0);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_x(5.34);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_x(-1.71);
+    write_to_file(msg, "data-neg.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/float/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestFloat;
+
+message Test {
+
+    required float x = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-max.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+ÿÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-min.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-min.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-min.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-min.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-min.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg200.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg200.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg200.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-neg200.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-pos.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-pos200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-pos200.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-pos200.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+È
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/int32_testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/int32_testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/int32_testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestInt32;
+
+message Test {
+
+    required int32 i = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE int32
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int32_t;
+
+#include <scalar_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,29 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestInt32::Test msg;
+
+    msg.set_i(0);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_i(1);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_i(200);
+    write_to_file(msg, "data-pos200.pbf");
+
+    msg.set_i(-1);
+    write_to_file(msg, "data-neg.pbf");
+
+    msg.set_i(-200);
+    write_to_file(msg, "data-neg200.pbf");
+
+    msg.set_i(std::numeric_limits<int32_t>::max());
+    write_to_file(msg, "data-max.pbf");
+
+    msg.set_i(std::numeric_limits<int32_t>::min());
+    write_to_file(msg, "data-min.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/writer_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/writer_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int32/writer_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,54 @@
+
+#include <test.hpp>
+
+#include "t/int32/int32_testcase.pb.h"
+
+TEST_CASE("write int32 field and check with libprotobuf") {
+
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    TestInt32::Test msg;
+
+    SECTION("zero") {
+        pw.add_int32(1, 0L);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i() == 0L);
+    }
+
+    SECTION("positive") {
+        pw.add_int32(1, 1L);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i() == 1L);
+    }
+
+    SECTION("negative") {
+        pw.add_int32(1, -1L);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i() == -1L);
+    }
+
+    SECTION("max") {
+        pw.add_int32(1, std::numeric_limits<int32_t>::max());
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i() == std::numeric_limits<int32_t>::max());
+    }
+
+    SECTION("min") {
+        pw.add_int32(1, std::numeric_limits<int32_t>::min());
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i() == std::numeric_limits<int32_t>::min());
+    }
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-max.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+ÿÿÿÿÿÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-min.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-min.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-min.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-min.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-min.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg200.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg200.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg200.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-neg200.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-pos.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-pos200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-pos200.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-pos200.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+È
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE int64
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int64_t;
+
+#include <scalar_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,29 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestInt64::Test msg;
+
+    msg.set_i(0);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_i(1);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_i(200);
+    write_to_file(msg, "data-pos200.pbf");
+
+    msg.set_i(-1);
+    write_to_file(msg, "data-neg.pbf");
+
+    msg.set_i(-200);
+    write_to_file(msg, "data-neg200.pbf");
+
+    msg.set_i(std::numeric_limits<int64_t>::max());
+    write_to_file(msg, "data-max.pbf");
+
+    msg.set_i(std::numeric_limits<int64_t>::min());
+    write_to_file(msg, "data-min.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/int64/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestInt64;
+
+message Test {
+
+    required int64 i = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/data-message.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/data-message.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/data-message.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,3 @@
+
+
+foobar
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/data-opt-element.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/data-opt-element.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/data-opt-element.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+optional
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/data-opt-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/message_testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/message_testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/message_testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,18 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestMessage;
+
+message Sub {
+    required string s = 1;
+}
+
+message Test {
+    required Sub submessage = 1;
+}
+
+message Opt {
+    optional string s = 1;
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,135 @@
+
+#include <test.hpp>
+
+TEST_CASE("read message field: string") {
+    const std::string buffer = load_data("message/data-message");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.data().data() == buffer.data());
+    REQUIRE(item.data().size() == buffer.size());
+
+    REQUIRE(item.next());
+    protozero::pbf_reader subitem{item.get_message()};
+    REQUIRE_FALSE(item.next());
+
+    REQUIRE(item.data().data() == buffer.data() + buffer.size());
+    REQUIRE(item.data().empty());
+
+    REQUIRE(subitem.next());
+    REQUIRE(subitem.get_string() == "foobar");
+    REQUIRE_FALSE(subitem.next());
+}
+
+TEST_CASE("read message field: end of buffer") {
+    const std::string buffer = load_data("message/data-message");
+
+    for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+        protozero::pbf_reader item{buffer.data(), i};
+        REQUIRE(item.next());
+        REQUIRE_THROWS_AS(item.get_string(), const protozero::end_of_buffer_exception&);
+    }
+}
+
+TEST_CASE("read message field: optional contents of message - empty") {
+    const std::string buffer = load_data("message/data-opt-empty");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read message field: string opt") {
+    const std::string buffer = load_data("message/data-opt-element");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_string() == "optional");
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("write message field") {
+    std::string buffer;
+    protozero::pbf_writer pbf_test{buffer};
+
+    SECTION("string") {
+        std::string buffer_submessage;
+        protozero::pbf_writer pbf_submessage{buffer_submessage};
+        pbf_submessage.add_string(1, "foobar");
+
+        pbf_test.add_message(1, buffer_submessage);
+    }
+
+    SECTION("string with subwriter") {
+        protozero::pbf_writer pbf_submessage{pbf_test, 1};
+        pbf_submessage.add_string(1, "foobar");
+    }
+
+    SECTION("string with subwriter with reserved size") {
+        std::string str{"foobar"};
+        const auto size = 1 /* tag */ + 1 /* length field */ + str.size();
+        protozero::pbf_writer pbf_submessage{pbf_test, 1, size};
+        pbf_submessage.add_string(1, "foobar");
+    }
+
+    REQUIRE(buffer == load_data("message/data-message"));
+}
+
+TEST_CASE("write message field into non-empty buffer") {
+    std::string buffer{"some data already in here"};
+    protozero::pbf_writer pbf_test{buffer};
+
+    SECTION("string") {
+        std::string buffer_submessage;
+        protozero::pbf_writer pbf_submessage{buffer_submessage};
+        pbf_submessage.add_string(1, "foobar");
+
+        pbf_test.add_message(1, buffer_submessage);
+    }
+
+    SECTION("string with subwriter") {
+        protozero::pbf_writer pbf_submessage{pbf_test, 1};
+        pbf_submessage.add_string(1, "foobar");
+    }
+
+    REQUIRE(buffer == std::string{"some data already in here"} + load_data("message/data-message"));
+}
+
+TEST_CASE("write message field reserving memory beforehand") {
+    std::string buffer;
+    protozero::pbf_writer pbf_test{buffer};
+    pbf_test.reserve(100);
+    REQUIRE(buffer.capacity() >= 100);
+
+    SECTION("string") {
+        std::string buffer_submessage;
+        protozero::pbf_writer pbf_submessage{buffer_submessage};
+        pbf_submessage.add_string(1, "foobar");
+
+        pbf_test.add_message(1, buffer_submessage);
+    }
+
+    SECTION("string with subwriter") {
+        protozero::pbf_writer pbf_submessage{pbf_test, 1};
+        pbf_submessage.add_string(1, "foobar");
+    }
+
+    REQUIRE(buffer == load_data("message/data-message"));
+}
+
+TEST_CASE("write optional message field") {
+    std::string buffer;
+    protozero::pbf_writer pbf_opt{buffer};
+
+    SECTION("add nothing") {
+        REQUIRE(buffer == load_data("message/data-opt-empty"));
+    }
+
+    SECTION("add string") {
+        pbf_opt.add_string(1, "optional");
+
+        REQUIRE(buffer == load_data("message/data-opt-element"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,19 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestMessage::Test msg;
+
+    TestMessage::Sub* submsg = msg.mutable_submessage();
+    submsg->set_s("foobar");
+
+    write_to_file(msg, "data-message.pbf");
+
+    TestMessage::Opt opt_msg;
+    write_to_file(opt_msg, "data-opt-empty.pbf");
+
+    opt_msg.set_s("optional");
+    write_to_file(opt_msg, "data-opt-element.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/writer_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/writer_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/message/writer_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,29 @@
+
+#include <test.hpp>
+
+#include "t/message/message_testcase.pb.h"
+
+TEST_CASE("write message field and check with libprotobuf") {
+
+    std::string buffer_test;
+    protozero::pbf_writer pbf_test{buffer_test};
+
+    SECTION("string") {
+        std::string buffer_submessage;
+        protozero::pbf_writer pbf_submessage{buffer_submessage};
+        pbf_submessage.add_string(1, "foobar");
+
+        pbf_test.add_message(1, buffer_submessage);
+    }
+
+    SECTION("string with subwriter") {
+        protozero::pbf_writer pbf_submessage{pbf_test, 1};
+        pbf_submessage.add_string(1, "foobar");
+    }
+
+    TestMessage::Test msg;
+    msg.ParseFromString(buffer_test);
+    REQUIRE(msg.submessage().s() == "foobar");
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/data-message.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/data-message.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/data-message.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,5 @@
+
+
+
+
+foobarcXM
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/data-no-message.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/data-no-message.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/data-no-message.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/data-no-message.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/data-no-message.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/nested_testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/nested_testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/nested_testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,21 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestNested;
+
+message SubSub {
+    optional string s = 1;
+    optional int32 i = 2;
+}
+
+message Sub {
+    optional SubSub subsub = 1;
+    optional int32 i = 2;
+}
+
+message Test {
+    optional Sub sub = 1;
+    optional int32 i = 2;
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,157 @@
+
+#include <test.hpp>
+
+inline void check_subsub(protozero::pbf_reader message) {
+    while (message.next()) {
+        switch (message.tag()) {
+            case 1: {
+                REQUIRE("foobar" == message.get_string());
+                break;
+            }
+            case 2: {
+                REQUIRE(99 == message.get_int32());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should never be here
+                break;
+            }
+        }
+    }
+}
+
+inline void check_sub(protozero::pbf_reader message) {
+    while (message.next()) {
+        switch (message.tag()) {
+            case 1: {
+                check_subsub(message.get_message());
+                break;
+            }
+            case 2: {
+                REQUIRE(88 == message.get_int32());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should never be here
+                break;
+            }
+        }
+    }
+}
+
+inline void check(protozero::pbf_reader message) {
+    while (message.next()) {
+        switch (message.tag()) {
+            case 1: {
+                check_sub(message.get_message());
+                break;
+            }
+            case 2: {
+                REQUIRE(77 == message.get_int32());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should never be here
+                break;
+            }
+        }
+    }
+}
+
+inline void check_empty(protozero::pbf_reader message) {
+    while (message.next()) {
+        switch (message.tag()) {
+            case 1: {
+                REQUIRE_FALSE(message.get_message().next());
+                break;
+            }
+            case 2: {
+                REQUIRE(77 == message.get_int32());
+                break;
+            }
+            default: {
+                REQUIRE(false); // should never be here
+                break;
+            }
+        }
+    }
+}
+
+TEST_CASE("read nested message fields: string") {
+    const std::string buffer = load_data("nested/data-message");
+
+    protozero::pbf_reader message{buffer};
+    check(message);
+}
+
+TEST_CASE("read nested message fields: no submessage") {
+    const std::string buffer = load_data("nested/data-no-message");
+
+    protozero::pbf_reader message{buffer};
+    check_empty(message);
+}
+
+TEST_CASE("write nested message fields") {
+    std::string buffer_test;
+    protozero::pbf_writer pbf_test{buffer_test};
+
+    SECTION("string") {
+        std::string buffer_subsub;
+        protozero::pbf_writer pbf_subsub{buffer_subsub};
+        pbf_subsub.add_string(1, "foobar");
+        pbf_subsub.add_int32(2, 99);
+
+        std::string buffer_sub;
+        protozero::pbf_writer pbf_sub{buffer_sub};
+        pbf_sub.add_string(1, buffer_subsub);
+        pbf_sub.add_int32(2, 88);
+
+        pbf_test.add_message(1, buffer_sub);
+    }
+
+    SECTION("string with subwriter") {
+        protozero::pbf_writer pbf_sub{pbf_test, 1};
+        {
+            protozero::pbf_writer pbf_subsub{pbf_sub, 1};
+            pbf_subsub.add_string(1, "foobar");
+            pbf_subsub.add_int32(2, 99);
+        }
+        pbf_sub.add_int32(2, 88);
+    }
+
+    pbf_test.add_int32(2, 77);
+
+    protozero::pbf_reader message{buffer_test};
+    check(message);
+}
+
+TEST_CASE("write nested message fields - no message") {
+    std::string buffer_test;
+    protozero::pbf_writer pbf_test{buffer_test};
+
+    SECTION("nothing") {
+    }
+
+    SECTION("empty string") {
+        std::string buffer_sub;
+
+        pbf_test.add_message(1, buffer_sub);
+    }
+
+    SECTION("string with pbf_writer") {
+        std::string buffer_sub;
+        protozero::pbf_writer pbf_sub{buffer_sub};
+
+        pbf_test.add_message(1, buffer_sub);
+    }
+
+    SECTION("string with subwriter") {
+        protozero::pbf_writer pbf_sub{pbf_test, 1};
+    }
+
+    pbf_test.add_int32(2, 77);
+
+    protozero::pbf_reader message{buffer_test};
+    check_empty(message);
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,21 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestNested::Test msg;
+    msg.set_i(77);
+
+    TestNested::Sub* sub = msg.mutable_sub();
+
+    write_to_file(msg, "data-no-message.pbf");
+
+    sub->set_i(88);
+
+    TestNested::SubSub* subsub = sub->mutable_subsub();
+    subsub->set_s("foobar");
+    subsub->set_i(99);
+
+    write_to_file(msg, "data-message.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/writer_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/writer_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/nested/writer_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,46 @@
+
+#include <test.hpp>
+
+#include "t/nested/nested_testcase.pb.h"
+
+TEST_CASE("write nested message fields and check with libprotobuf") {
+
+    std::string buffer_test;
+    protozero::pbf_writer pbf_test{buffer_test};
+
+    SECTION("string") {
+        std::string buffer_subsub;
+        protozero::pbf_writer pbf_subsub{buffer_subsub};
+        pbf_subsub.add_string(1, "foobar");
+        pbf_subsub.add_int32(2, 99);
+
+        std::string buffer_sub;
+        protozero::pbf_writer pbf_sub{buffer_sub};
+        pbf_sub.add_string(1, buffer_subsub);
+        pbf_sub.add_int32(2, 88);
+
+        pbf_test.add_message(1, buffer_sub);
+    }
+
+    SECTION("with subwriter") {
+        protozero::pbf_writer pbf_sub{pbf_test, 1};
+        {
+            protozero::pbf_writer pbf_subsub(pbf_sub, 1);
+            pbf_subsub.add_string(1, "foobar");
+            pbf_subsub.add_int32(2, 99);
+        }
+        pbf_sub.add_int32(2, 88);
+    }
+
+    pbf_test.add_int32(2, 77);
+
+    TestNested::Test msg;
+    msg.ParseFromString(buffer_test);
+
+    REQUIRE(msg.i() == 77);
+    REQUIRE(msg.sub().i() == 88);
+    REQUIRE(msg.sub().subsub().i() == 99);
+    REQUIRE(msg.sub().subsub().s() == "foobar");
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-one.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-one.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/data-one.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,74 @@
+
+#include <test.hpp>
+
+TEST_CASE("read repeated fields: empty") {
+    const std::string buffer = load_data("repeated/data-empty");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read repeated fields: one") {
+    const std::string buffer = load_data("repeated/data-one");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_int32() == 0L);
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read repeated fields: many") {
+    const std::string buffer = load_data("repeated/data-many");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_int32() == 0L);
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_int32() == 1L);
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_int32() == -1L);
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_int32() == std::numeric_limits<int32_t>::max());
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_int32() == std::numeric_limits<int32_t>::min());
+
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read repeated fields: end of buffer") {
+    const std::string buffer = load_data("repeated/data-one");
+
+    for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+        protozero::pbf_reader item{buffer.data(), i};
+        REQUIRE(item.next());
+        REQUIRE_THROWS_AS(item.get_int32(), const protozero::end_of_buffer_exception&);
+    }
+}
+
+TEST_CASE("write repeated fields") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("one") {
+        pw.add_int32(1, 0L);
+        REQUIRE(buffer == load_data("repeated/data-one"));
+    }
+
+    SECTION("many") {
+        pw.add_int32(1, 0L);
+        pw.add_int32(1, 1L);
+        pw.add_int32(1, -1L);
+        pw.add_int32(1, std::numeric_limits<int32_t>::max());
+        pw.add_int32(1, std::numeric_limits<int32_t>::min());
+
+        REQUIRE(buffer == load_data("repeated/data-many"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/repeated_testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/repeated_testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/repeated_testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeated;
+
+message Test {
+
+    repeated int32 i = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,19 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeated::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_i(0);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_i(1);
+    msg.add_i(-1);
+    msg.add_i(std::numeric_limits<int32_t>::max());
+    msg.add_i(std::numeric_limits<int32_t>::min());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/writer_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/writer_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated/writer_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,40 @@
+
+#include <test.hpp>
+
+#include "t/repeated/repeated_testcase.pb.h"
+
+TEST_CASE("write repeated fields and check with libprotobuf") {
+
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    TestRepeated::Test msg;
+
+    SECTION("one") {
+        pw.add_int32(1, 0L);
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i().size() == 1);
+        REQUIRE(msg.i(0) == 0L);
+    }
+
+    SECTION("many") {
+        pw.add_int32(1, 0L);
+        pw.add_int32(1, 1L);
+        pw.add_int32(1, -1L);
+        pw.add_int32(1, std::numeric_limits<int32_t>::max());
+        pw.add_int32(1, std::numeric_limits<int32_t>::min());
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i().size() == 5);
+        REQUIRE(msg.i(0) == 0L);
+        REQUIRE(msg.i(1) == 1L);
+        REQUIRE(msg.i(2) == -1L);
+        REQUIRE(msg.i(3) == std::numeric_limits<int32_t>::max());
+        REQUIRE(msg.i(4) == std::numeric_limits<int32_t>::min());
+    }
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-one.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,156 @@
+
+#include <test.hpp>
+
+TEST_CASE("read repeated packed bool field: empty") {
+    const std::string buffer = load_data("repeated_packed_bool/data-empty");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read repeated packed bool field: one") {
+    const std::string buffer = load_data("repeated_packed_bool/data-one");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    const auto it_range = item.get_packed_bool();
+    REQUIRE(std::distance(it_range.begin(), it_range.end()) == 1);
+    REQUIRE(it_range.size() == 1);
+    REQUIRE_FALSE(item.next());
+
+    REQUIRE(it_range.begin() != it_range.end());
+    REQUIRE(*it_range.begin());
+    REQUIRE(std::next(it_range.begin()) == it_range.end());
+}
+
+TEST_CASE("read repeated packed bool field: many") {
+    const std::string buffer = load_data("repeated_packed_bool/data-many");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    const auto it_range = item.get_packed_bool();
+    REQUIRE(std::distance(it_range.begin(), it_range.end()) == 4);
+    REQUIRE(it_range.size() == 4);
+    REQUIRE_FALSE(item.next());
+
+    auto it = it_range.begin();
+    REQUIRE(it != it_range.end());
+    REQUIRE(*it++);
+    REQUIRE(*it++);
+    REQUIRE_FALSE(*it++);
+    REQUIRE(*it++);
+    REQUIRE(it == it_range.end());
+}
+
+TEST_CASE("read repeated packed bool field: end of buffer") {
+    const std::string buffer = load_data("repeated_packed_bool/data-many");
+
+    for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+        protozero::pbf_reader item{buffer.data(), i};
+        REQUIRE(item.next());
+        REQUIRE_THROWS_AS(item.get_packed_bool(), const protozero::end_of_buffer_exception&);
+    }
+}
+
+TEST_CASE("write repeated packed bool field") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("empty") {
+        const bool data[] = { true };
+        pw.add_packed_bool(1, std::begin(data), std::begin(data) /* !!!! */);
+
+        REQUIRE(buffer == load_data("repeated_packed_bool/data-empty"));
+    }
+
+    SECTION("one") {
+        const bool data[] = { true };
+        pw.add_packed_bool(1, std::begin(data), std::end(data));
+
+        REQUIRE(buffer == load_data("repeated_packed_bool/data-one"));
+    }
+
+    SECTION("many") {
+        const bool data[] = { true, true, false, true };
+        pw.add_packed_bool(1, std::begin(data), std::end(data));
+
+        REQUIRE(buffer == load_data("repeated_packed_bool/data-many"));
+    }
+
+}
+
+TEST_CASE("write repeated packed bool field using packed_field_bool") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("empty - should do rollback") {
+        {
+            protozero::packed_field_bool field{pw, 1};
+        }
+
+        REQUIRE(buffer == load_data("repeated_packed_bool/data-empty"));
+    }
+
+    SECTION("one") {
+        {
+            protozero::packed_field_bool field{pw, 1};
+            field.add_element(true);
+        }
+
+        REQUIRE(buffer == load_data("repeated_packed_bool/data-one"));
+    }
+
+    SECTION("many") {
+        {
+            protozero::packed_field_bool field{pw, 1};
+            field.add_element(true);
+            field.add_element(true);
+            field.add_element(false);
+            field.add_element(true);
+        }
+
+        REQUIRE(buffer == load_data("repeated_packed_bool/data-many"));
+    }
+}
+
+TEST_CASE("write repeated packed bool field using packed_field_bool with pbf_builder") {
+    enum class msg : protozero::pbf_tag_type {
+        f = 1
+    };
+
+    std::string buffer;
+    protozero::pbf_builder<msg> pw{buffer};
+
+    SECTION("empty - should do rollback") {
+        {
+            protozero::packed_field_bool field{pw, msg::f};
+        }
+
+        REQUIRE(buffer == load_data("repeated_packed_bool/data-empty"));
+    }
+
+    SECTION("one") {
+        {
+            protozero::packed_field_bool field{pw, msg::f};
+            field.add_element(true);
+        }
+
+        REQUIRE(buffer == load_data("repeated_packed_bool/data-one"));
+    }
+
+    SECTION("many") {
+        {
+            protozero::packed_field_bool field{pw, msg::f};
+            field.add_element(true);
+            field.add_element(true);
+            field.add_element(false);
+            field.add_element(true);
+        }
+
+        REQUIRE(buffer == load_data("repeated_packed_bool/data-many"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,18 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedBool::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_b(true);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_b(true);
+    msg.add_b(false);
+    msg.add_b(true);
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_bool/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedBool;
+
+message Test {
+
+    repeated bool b = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-one.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,3 @@
+
+×£p=
+W1@
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,116 @@
+
+#include <test.hpp>
+
+TEST_CASE("read repeated packed double field") {
+    // Run these tests twice, the second time we basically move the data
+    // one byte down in the buffer. It doesn't matter how the data or buffer
+    // is aligned before that, in at least one of these cases the doubles will
+    // not be aligned properly. So we test that even in that case the doubles
+    // will be extracted properly.
+
+    for (std::string::size_type n = 0; n < 2; ++n) {
+        std::string abuffer;
+        abuffer.reserve(1000);
+        abuffer.append(n, '\0');
+
+        SECTION("empty") {
+            abuffer.append(load_data("repeated_packed_double/data-empty"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("one") {
+            abuffer.append(load_data("repeated_packed_double/data-one"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            const auto it_range = item.get_packed_double();
+            REQUIRE_FALSE(item.next());
+
+            REQUIRE(*it_range.begin() == Approx(17.34));
+            REQUIRE(std::next(it_range.begin()) == it_range.end());
+        }
+
+        SECTION("many") {
+            abuffer.append(load_data("repeated_packed_double/data-many"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            const auto it_range = item.get_packed_double();
+            REQUIRE_FALSE(item.next());
+
+            auto it = it_range.begin();
+            REQUIRE(*it++ == Approx(17.34));
+            REQUIRE(*it++ == Approx( 0.0));
+            REQUIRE(*it++ == Approx( 1.0));
+            REQUIRE(*it++ == std::numeric_limits<double>::min());
+            REQUIRE(*it++ == std::numeric_limits<double>::max());
+            REQUIRE(it == it_range.end());
+
+            it = it_range.begin();
+            auto it2 = it + 1;
+            REQUIRE(it2 > it);
+            REQUIRE(it < it2);
+            REQUIRE(it <= it_range.begin());
+            REQUIRE(it >= it_range.begin());
+            REQUIRE(*it2 == Approx(0.0));
+            auto it3 = 1 + it;
+            REQUIRE(*it3 == Approx(0.0));
+            auto it4 = it2 - 1;
+            REQUIRE(*it4 == Approx(17.34));
+            it4 += 2;
+            REQUIRE(*it4 == Approx(1.0));
+            it4 -= 2;
+            REQUIRE(*it4 == Approx(17.34));
+            it4 += 2;
+            REQUIRE(*it4 == Approx(1.0));
+            REQUIRE(*it4-- == Approx(1.0));
+            REQUIRE(*it4 == Approx(0.0));
+            REQUIRE(*--it4 == Approx(17.34));
+            REQUIRE(it4[0] == Approx(17.34));
+            REQUIRE(it4[1] == Approx(0.0));
+            REQUIRE(std::distance(it_range.begin(), it_range.end()) == 5);
+            REQUIRE(it_range.end() - it_range.begin() == 5);
+            REQUIRE(it_range.begin() - it_range.end() == -5);
+
+        }
+
+        SECTION("end_of_buffer") {
+            abuffer.append(load_data("repeated_packed_double/data-many"));
+
+            for (std::string::size_type i = 1; i < abuffer.size() - n; ++i) {
+                protozero::pbf_reader item{abuffer.data() + n, i};
+                REQUIRE(item.next());
+                REQUIRE_THROWS_AS(item.get_packed_double(), const protozero::end_of_buffer_exception&);
+            }
+        }
+    }
+}
+
+TEST_CASE("write repeated packed double field") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("empty") {
+        const double data[] = { 17.34 };
+        pw.add_packed_double(1, std::begin(data), std::begin(data) /* !!!! */);
+
+        REQUIRE(buffer == load_data("repeated_packed_double/data-empty"));
+    }
+
+    SECTION("one") {
+        const double data[] = { 17.34 };
+        pw.add_packed_double(1, std::begin(data), std::end(data));
+
+        REQUIRE(buffer == load_data("repeated_packed_double/data-one"));
+    }
+
+    SECTION("many") {
+        const double data[] = { 17.34, 0.0, 1.0, std::numeric_limits<double>::min(), std::numeric_limits<double>::max() };
+        pw.add_packed_double(1, std::begin(data), std::end(data));
+
+        REQUIRE(buffer == load_data("repeated_packed_double/data-many"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,19 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedDouble::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_d(17.34);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_d(0.0);
+    msg.add_d(1.0);
+    msg.add_d(std::numeric_limits<double>::min());
+    msg.add_d(std::numeric_limits<double>::max());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_double/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedDouble;
+
+message Test {
+
+    repeated double d = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-one.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-one.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/data-one.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,78 @@
+
+#include <test.hpp>
+
+TEST_CASE("read repeated packed enum field: empty") {
+    const std::string buffer = load_data("repeated_packed_enum/data-empty");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read repeated packed enum field: one") {
+    const std::string buffer = load_data("repeated_packed_enum/data-one");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    const auto it_range = item.get_packed_enum();
+    REQUIRE_FALSE(item.next());
+
+    REQUIRE(it_range.begin() != it_range.end());
+    REQUIRE(*it_range.begin() == 0 /* BLACK */);
+    REQUIRE(std::next(it_range.begin()) == it_range.end());
+}
+
+TEST_CASE("read repeated packed enum field: many") {
+    const std::string buffer = load_data("repeated_packed_enum/data-many");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    const auto it_range = item.get_packed_enum();
+    REQUIRE_FALSE(item.next());
+
+    auto it = it_range.begin();
+    REQUIRE(it != it_range.end());
+    REQUIRE(*it++ == 0 /* BLACK */);
+    REQUIRE(*it++ == 3 /* BLUE */);
+    REQUIRE(*it++ == 2 /* GREEN */);
+    REQUIRE(it == it_range.end());
+}
+
+TEST_CASE("read repeated packed enum field: end of buffer") {
+    const std::string buffer = load_data("repeated_packed_enum/data-many");
+
+    for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+        protozero::pbf_reader item{buffer.data(), i};
+        REQUIRE(item.next());
+        REQUIRE_THROWS_AS(item.get_packed_enum(), const protozero::end_of_buffer_exception&);
+    }
+}
+
+TEST_CASE("write repeated packed enum field") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("empty") {
+        const int32_t data[] = { 0 /* BLACK */ };
+        pw.add_packed_enum(1, std::begin(data), std::begin(data) /* !!!! */);
+
+        REQUIRE(buffer == load_data("repeated_packed_enum/data-empty"));
+    }
+
+    SECTION("one") {
+        const int32_t data[] = { 0 /* BLACK */ };
+        pw.add_packed_enum(1, std::begin(data), std::end(data));
+
+        REQUIRE(buffer == load_data("repeated_packed_enum/data-one"));
+    }
+
+    SECTION("many") {
+        const int32_t data[] = { 0 /* BLACK */, 3 /* BLUE */, 2 /* GREEN */ };
+        pw.add_packed_enum(1, std::begin(data), std::end(data));
+
+        REQUIRE(buffer == load_data("repeated_packed_enum/data-many"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,17 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedEnum::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_color(TestRepeatedPackedEnum::BLACK);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_color(TestRepeatedPackedEnum::BLUE);
+    msg.add_color(TestRepeatedPackedEnum::GREEN);
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_enum/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,18 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedEnum;
+
+enum Color {
+    BLACK = 0;
+    RED   = 1;
+    GREEN = 2;
+    BLUE  = 3;
+}
+
+message Test {
+
+    repeated Color color = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-one.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-one.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/data-one.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE fixed32
+#define PBF_TYPE_IS_SIGNED 0
+using cpp_type = uint32_t;
+
+#include <packed_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/repeated_packed_fixed32_testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/repeated_packed_fixed32_testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/repeated_packed_fixed32_testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedFixed32;
+
+message Test {
+
+    repeated fixed32 i = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,19 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedFixed32::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_i(17UL);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_i(200UL);
+    msg.add_i(0UL);
+    msg.add_i(1UL);
+    msg.add_i(std::numeric_limits<uint32_t>::max());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/writer_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/writer_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed32/writer_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,74 @@
+
+#include <test.hpp>
+
+#include "t/repeated_packed_fixed32/repeated_packed_fixed32_testcase.pb.h"
+
+TEST_CASE("write repeated packed fixed32 field and check with libprotobuf") {
+
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    TestRepeatedPackedFixed32::Test msg;
+
+    SECTION("empty") {
+        const uint32_t data[] = { 17UL };
+        pw.add_packed_fixed32(1, std::begin(data), std::begin(data) /* !!!! */);
+    }
+
+    SECTION("one") {
+        const uint32_t data[] = { 17UL };
+        pw.add_packed_fixed32(1, std::begin(data), std::end(data));
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i().size() == 1);
+        REQUIRE(msg.i(0) == 17UL);
+    }
+
+    SECTION("many") {
+        const uint32_t data[] = { 17UL, 0UL, 1UL, std::numeric_limits<uint32_t>::max() };
+        pw.add_packed_fixed32(1, std::begin(data), std::end(data));
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.i().size() == 4);
+        REQUIRE(msg.i(0) == 17UL);
+        REQUIRE(msg.i(1) ==  0UL);
+        REQUIRE(msg.i(2) ==  1UL);
+        REQUIRE(msg.i(3) == std::numeric_limits<uint32_t>::max());
+    }
+}
+
+TEST_CASE("write from different types of iterators and check with libprotobuf") {
+
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    TestRepeatedPackedFixed32::Test msg;
+
+    SECTION("from uint16_t") {
+        const uint16_t data[] = { 1, 4, 9, 16, 25 };
+
+        pw.add_packed_fixed<uint32_t>(1, std::begin(data), std::end(data));
+    }
+
+    SECTION("from string") {
+        std::string data = "1 4 9 16 25";
+        std::stringstream sdata(data);
+
+        std::istream_iterator<uint32_t> eod;
+        std::istream_iterator<uint32_t> it(sdata);
+
+        pw.add_packed_fixed<uint32_t>(1, it, eod);
+    }
+
+    msg.ParseFromString(buffer);
+
+    REQUIRE(msg.i().size() == 5);
+    REQUIRE(msg.i(0) ==  1);
+    REQUIRE(msg.i(1) ==  4);
+    REQUIRE(msg.i(2) ==  9);
+    REQUIRE(msg.i(3) == 16);
+    REQUIRE(msg.i(4) == 25);
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-one.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-one.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/data-one.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE fixed64
+#define PBF_TYPE_IS_SIGNED 0
+using cpp_type = uint64_t;
+
+#include <packed_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,19 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedFixed64::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_i(17ULL);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_i(200UL);
+    msg.add_i(0ULL);
+    msg.add_i(1ULL);
+    msg.add_i(std::numeric_limits<uint64_t>::max());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_fixed64/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedFixed64;
+
+message Test {
+
+    repeated fixed64 i = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-one.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+R¸ŠA
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,89 @@
+
+#include <test.hpp>
+
+TEST_CASE("read repeated packed float field") {
+    // Run these tests twice, the second time we basically move the data
+    // one byte down in the buffer. It doesn't matter how the data or buffer
+    // is aligned before that, in at least one of these cases the floats will
+    // not be aligned properly. So we test that even in that case the floats
+    // will be extracted properly.
+
+    for (std::string::size_type n = 0; n < 2; ++n) {
+        std::string abuffer;
+        abuffer.reserve(1000);
+        abuffer.append(n, '\0');
+
+        SECTION("empty") {
+            abuffer.append(load_data("repeated_packed_float/data-empty"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE_FALSE(item.next());
+        }
+
+        SECTION("one") {
+            abuffer.append(load_data("repeated_packed_float/data-one"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            auto it_range = item.get_packed_float();
+            REQUIRE_FALSE(item.next());
+
+            REQUIRE(*it_range.begin() == Approx(17.34f));
+            REQUIRE(std::next(it_range.begin()) == it_range.end());
+        }
+
+        SECTION("many") {
+            abuffer.append(load_data("repeated_packed_float/data-many"));
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
+
+            REQUIRE(item.next());
+            auto it_range = item.get_packed_float();
+            REQUIRE_FALSE(item.next());
+
+            auto it = it_range.begin();
+            REQUIRE(*it++ == Approx(17.34f));
+            REQUIRE(*it++ == Approx( 0.0f));
+            REQUIRE(*it++ == Approx( 1.0f));
+            REQUIRE(*it++ == std::numeric_limits<float>::min());
+            REQUIRE(*it++ == std::numeric_limits<float>::max());
+            REQUIRE(it == it_range.end());
+        }
+
+        SECTION("end_of_buffer") {
+            abuffer.append(load_data("repeated_packed_float/data-many"));
+
+            for (std::string::size_type i = 1; i < abuffer.size() - n; ++i) {
+                protozero::pbf_reader item{abuffer.data() + n, i};
+                REQUIRE(item.next());
+                REQUIRE_THROWS_AS(item.get_packed_float(), const protozero::end_of_buffer_exception&);
+            }
+        }
+    }
+}
+
+TEST_CASE("write repeated packed float field") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("empty") {
+        float data[] = { 17.34f };
+        pw.add_packed_float(1, std::begin(data), std::begin(data) /* !!!! */);
+
+        REQUIRE(buffer == load_data("repeated_packed_float/data-empty"));
+    }
+
+    SECTION("one") {
+        float data[] = { 17.34f };
+        pw.add_packed_float(1, std::begin(data), std::end(data));
+
+        REQUIRE(buffer == load_data("repeated_packed_float/data-one"));
+    }
+
+    SECTION("many") {
+        float data[] = { 17.34f, 0.0f, 1.0f, std::numeric_limits<float>::min(), std::numeric_limits<float>::max() };
+        pw.add_packed_float(1, std::begin(data), std::end(data));
+
+        REQUIRE(buffer == load_data("repeated_packed_float/data-many"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,19 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedFloat::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_f(17.34f);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_f(0.0f);
+    msg.add_f(1.0f);
+    msg.add_f(std::numeric_limits<float>::min());
+    msg.add_f(std::numeric_limits<float>::max());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_float/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedFloat;
+
+message Test {
+
+    repeated float f = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-one.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE int32
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int32_t;
+
+#include <packed_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,22 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedInt32::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_i(17L);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_i(200);
+    msg.add_i(0L);
+    msg.add_i(1L);
+    msg.add_i(std::numeric_limits<int32_t>::max());
+    msg.add_i(-200);
+    msg.add_i(-1L);
+    msg.add_i(std::numeric_limits<int32_t>::min());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int32/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedInt32;
+
+message Test {
+
+    repeated int32 i = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-one.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE int64
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int64_t;
+
+#include <packed_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,22 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedInt64::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_i(17LL);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_i(200);
+    msg.add_i(0LL);
+    msg.add_i(1LL);
+    msg.add_i(std::numeric_limits<int64_t>::max());
+    msg.add_i(-200);
+    msg.add_i(-1LL);
+    msg.add_i(std::numeric_limits<int64_t>::min());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_int64/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedInt64;
+
+message Test {
+
+    repeated int64 i = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-one.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-one.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/data-one.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,30 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE sfixed32
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int32_t;
+
+#include <packed_access.hpp>
+
+TEST_CASE("length value must be dividable by sizeof(T)") {
+    std::string data{load_data("repeated_packed_sfixed32/data-many")};
+
+    SECTION("1") {
+        data[1] = 1;
+    }
+
+    SECTION("2") {
+        data[1] = 2;
+    }
+
+    SECTION("3") {
+        data[1] = 3;
+    }
+
+    protozero::pbf_reader item{data};
+
+    REQUIRE(item.next());
+    REQUIRE_THROWS_AS(item.get_packed_sfixed32(), const protozero::invalid_length_exception&);
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,22 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedSFixed32::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_i(17);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_i(200);
+    msg.add_i(0);
+    msg.add_i(1);
+    msg.add_i(std::numeric_limits<int32_t>::max());
+    msg.add_i(-200);
+    msg.add_i(-1);
+    msg.add_i(std::numeric_limits<int32_t>::min());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed32/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedSFixed32;
+
+message Test {
+
+    repeated sfixed32 i = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-one.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-one.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/data-one.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE sfixed64
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int64_t;
+
+#include <packed_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,22 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedSFixed64::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_i(17);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_i(200);
+    msg.add_i(0);
+    msg.add_i(1);
+    msg.add_i(std::numeric_limits<int64_t>::max());
+    msg.add_i(-200);
+    msg.add_i(-1);
+    msg.add_i(std::numeric_limits<int64_t>::min());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sfixed64/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedSFixed64;
+
+message Test {
+
+    repeated sfixed64 i = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-one.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+"
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE sint32
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int32_t;
+
+#include <packed_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,22 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedSInt32::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_i(17L);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_i(200);
+    msg.add_i(0L);
+    msg.add_i(1L);
+    msg.add_i(std::numeric_limits<int32_t>::max());
+    msg.add_i(-200);
+    msg.add_i(-1L);
+    msg.add_i(std::numeric_limits<int32_t>::min());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint32/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedSInt32;
+
+message Test {
+
+    repeated sint32 i = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-one.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+"
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE sint64
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int64_t;
+
+#include <packed_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,22 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedSInt64::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_i(17LL);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_i(200);
+    msg.add_i(0LL);
+    msg.add_i(1LL);
+    msg.add_i(std::numeric_limits<int64_t>::max());
+    msg.add_i(-200);
+    msg.add_i(-1LL);
+    msg.add_i(std::numeric_limits<int64_t>::min());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_sint64/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedSInt64;
+
+message Test {
+
+    repeated sint64 i = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-one.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE uint32
+#define PBF_TYPE_IS_SIGNED 0
+using cpp_type = uint32_t;
+
+#include <packed_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,19 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedUInt32::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_i(17UL);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_i(200UL);
+    msg.add_i(0UL);
+    msg.add_i(1UL);
+    msg.add_i(std::numeric_limits<uint32_t>::max());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint32/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedUInt32;
+
+message Test {
+
+    repeated uint32 i = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-empty.pbf
===================================================================
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-many.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-many.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-many.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-many.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-many.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-one.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE uint64
+#define PBF_TYPE_IS_SIGNED 0
+using cpp_type = uint64_t;
+
+#include <packed_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,19 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestRepeatedPackedUInt64::Test msg;
+
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.add_i(17ULL);
+    write_to_file(msg, "data-one.pbf");
+
+    msg.add_i(200UL);
+    msg.add_i(0ULL);
+    msg.add_i(1ULL);
+    msg.add_i(std::numeric_limits<uint64_t>::max());
+    write_to_file(msg, "data-many.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/repeated_packed_uint64/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestRepeatedPackedUInt64;
+
+message Test {
+
+    repeated uint64 i = 1 [packed=true];
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/rollback/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/rollback/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/rollback/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,204 @@
+
+#include <test.hpp>
+
+TEST_CASE("rollback when using packed_field functions") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    pw.add_fixed64(2, 111);
+    pw.add_string(3, "foo");
+
+    SECTION("empty - should do rollback") {
+        {
+            protozero::packed_field_sint64 field{pw, 1};
+        }
+
+        pw.add_int32(4, 123);
+
+        protozero::pbf_reader msg{buffer};
+
+        msg.next();
+        REQUIRE(msg.tag() == 2);
+        REQUIRE(msg.get_fixed64() == 111);
+
+        msg.next();
+        REQUIRE(msg.tag() == 3);
+        REQUIRE(msg.get_string() == "foo");
+
+        msg.next();
+        REQUIRE(msg.tag() == 4);
+        REQUIRE(msg.get_int32() == 123);
+    }
+
+    SECTION("one") {
+        {
+            protozero::packed_field_sint64 field{pw, 1};
+            field.add_element(17L);
+        }
+
+        pw.add_int32(4, 123);
+
+        protozero::pbf_reader msg{buffer};
+
+        msg.next();
+        REQUIRE(msg.tag() == 2);
+        REQUIRE(msg.get_fixed64() == 111);
+
+        msg.next();
+        REQUIRE(msg.tag() == 3);
+        REQUIRE(msg.get_string() == "foo");
+
+        msg.next();
+        REQUIRE(msg.tag() == 1);
+        const auto it_range = msg.get_packed_sint64();
+        auto it = it_range.begin();
+        REQUIRE(*it++ == 17L);
+        REQUIRE(it == it_range.end());
+
+        msg.next();
+        REQUIRE(msg.tag() == 4);
+        REQUIRE(msg.get_int32() == 123);
+    }
+
+    SECTION("many") {
+        {
+            protozero::packed_field_sint64 field{pw, 1};
+            field.add_element(17L);
+            field.add_element( 0L);
+            field.add_element( 1L);
+            field.add_element(-1L);
+            field.add_element(std::numeric_limits<int64_t>::max());
+            field.add_element(std::numeric_limits<int64_t>::min());
+        }
+
+        pw.add_int32(4, 123);
+
+        protozero::pbf_reader msg{buffer};
+
+        msg.next();
+        REQUIRE(msg.tag() == 2);
+        REQUIRE(msg.get_fixed64() == 111);
+
+        msg.next();
+        REQUIRE(msg.tag() == 3);
+        REQUIRE(msg.get_string() == "foo");
+
+        msg.next();
+        REQUIRE(msg.tag() == 1);
+        const auto it_range = msg.get_packed_sint64();
+        auto it = it_range.begin();
+        REQUIRE(*it++ == 17L);
+        REQUIRE(*it++ ==  0L);
+        REQUIRE(*it++ ==  1L);
+        REQUIRE(*it++ == -1L);
+        REQUIRE(*it++ == std::numeric_limits<int64_t>::max());
+        REQUIRE(*it++ == std::numeric_limits<int64_t>::min());
+        REQUIRE(it == it_range.end());
+
+        msg.next();
+        REQUIRE(msg.tag() == 4);
+        REQUIRE(msg.get_int32() == 123);
+    }
+
+    SECTION("manual rollback") {
+        {
+            protozero::packed_field_sint64 field{pw, 1};
+            field.add_element(17L);
+            field.add_element( 0L);
+            field.add_element( 1L);
+            field.rollback();
+        }
+
+        pw.add_int32(4, 123);
+
+        protozero::pbf_reader msg{buffer};
+
+        msg.next();
+        REQUIRE(msg.tag() == 2);
+        REQUIRE(msg.get_fixed64() == 111);
+
+        msg.next();
+        REQUIRE(msg.tag() == 3);
+        REQUIRE(msg.get_string() == "foo");
+
+        msg.next();
+        REQUIRE(msg.tag() == 4);
+        REQUIRE(msg.get_int32() == 123);
+    }
+
+    SECTION("manual rollback") {
+        {
+            protozero::packed_field_sint64 field{pw, 1};
+            field.add_element(1L);
+            field.rollback();
+            REQUIRE_THROWS_AS(field.add_element(1L), const assert_error&);
+        }
+    }
+}
+
+TEST_CASE("rollback when using submessages") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    pw.add_fixed64(2, 111);
+    pw.add_string(3, "foo");
+
+    {
+        protozero::pbf_writer pws{pw, 1};
+        pws.add_string(1, "foobar");
+        pws.rollback();
+    }
+
+    pw.add_int32(4, 123);
+
+    protozero::pbf_reader msg{buffer};
+
+    msg.next();
+    REQUIRE(msg.tag() == 2);
+    REQUIRE(msg.get_fixed64() == 111);
+
+    msg.next();
+    REQUIRE(msg.tag() == 3);
+    REQUIRE(msg.get_string() == "foo");
+
+    msg.next();
+    REQUIRE(msg.tag() == 4);
+    REQUIRE(msg.get_int32() == 123);
+
+}
+
+TEST_CASE("rollback on parent message is never allowed") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+    REQUIRE_THROWS_AS(pw.rollback(), const assert_error&);
+}
+
+TEST_CASE("rollback on parent message is not allowed even if there is a submessage") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    pw.add_fixed64(2, 111);
+    pw.add_string(3, "foo");
+
+    {
+        protozero::pbf_writer pws{pw, 1};
+        pws.add_string(1, "foobar");
+        REQUIRE_THROWS_AS(pw.rollback(), const assert_error&);
+    }
+}
+
+TEST_CASE("rollback on message is not allowed if there is a nested submessage") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    pw.add_fixed64(2, 111);
+    pw.add_string(3, "foo");
+
+    {
+        protozero::pbf_writer pws{pw, 1};
+        pws.add_string(1, "foobar");
+        protozero::pbf_writer pws2{pws, 1};
+        REQUIRE_THROWS_AS(pws.rollback(), const assert_error&);
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-max.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+ÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-min.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-min.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-min.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-min.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-min.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-neg.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-neg.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-neg.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+ÿÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-neg200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-neg200.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-neg200.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+8ÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos200.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos200.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos200.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-pos200.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE sfixed32
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int32_t;
+
+#include <scalar_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,29 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestSFixed32::Test msg;
+
+    msg.set_i(0);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_i(1);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_i(200);
+    write_to_file(msg, "data-pos200.pbf");
+
+    msg.set_i(-1);
+    write_to_file(msg, "data-neg.pbf");
+
+    msg.set_i(-200);
+    write_to_file(msg, "data-neg200.pbf");
+
+    msg.set_i(std::numeric_limits<int32_t>::max());
+    write_to_file(msg, "data-max.pbf");
+
+    msg.set_i(std::numeric_limits<int32_t>::min());
+    write_to_file(msg, "data-min.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed32/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestSFixed32;
+
+message Test {
+
+    required sfixed32 i = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-max.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+	ÿÿÿÿÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-min.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-min.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-min.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-min.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-min.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-neg.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-neg.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-neg.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-neg.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-neg.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-neg200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-neg200.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-neg200.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+	8ÿÿÿÿÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos200.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos200.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos200.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-pos200.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE sfixed64
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int64_t;
+
+#include <scalar_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,29 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestSFixed64::Test msg;
+
+    msg.set_i(0);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_i(1);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_i(200);
+    write_to_file(msg, "data-pos200.pbf");
+
+    msg.set_i(-1);
+    write_to_file(msg, "data-neg.pbf");
+
+    msg.set_i(-200);
+    write_to_file(msg, "data-neg200.pbf");
+
+    msg.set_i(std::numeric_limits<int64_t>::max());
+    write_to_file(msg, "data-max.pbf");
+
+    msg.set_i(std::numeric_limits<int64_t>::min());
+    write_to_file(msg, "data-min.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sfixed64/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestSFixed64;
+
+message Test {
+
+    required sfixed64 i = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-max.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+þÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-min.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-min.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-min.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+ÿÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-neg.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-neg.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-neg.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-neg200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-neg200.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-neg200.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-pos.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-pos200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-pos200.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-pos200.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE sint32
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int32_t;
+
+#include <scalar_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,29 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestSInt32::Test msg;
+
+    msg.set_i(0L);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_i(1L);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_i(200);
+    write_to_file(msg, "data-pos200.pbf");
+
+    msg.set_i(-1);
+    write_to_file(msg, "data-neg.pbf");
+
+    msg.set_i(-200);
+    write_to_file(msg, "data-neg200.pbf");
+
+    msg.set_i(std::numeric_limits<int32_t>::max());
+    write_to_file(msg, "data-max.pbf");
+
+    msg.set_i(std::numeric_limits<int32_t>::min());
+    write_to_file(msg, "data-min.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint32/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestSInt32;
+
+message Test {
+
+    required sint32 i = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-max.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-max.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-max.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-min.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-min.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-min.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-min.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-min.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-neg.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-neg.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-neg.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-neg200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-neg200.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-neg200.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-pos.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-pos200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-pos200.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-pos200.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE sint64
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int64_t;
+
+#include <scalar_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,29 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestSInt64::Test msg;
+
+    msg.set_i(0LL);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_i(1LL);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_i(200LL);
+    write_to_file(msg, "data-pos200.pbf");
+
+    msg.set_i(-1LL);
+    write_to_file(msg, "data-neg.pbf");
+
+    msg.set_i(-200LL);
+    write_to_file(msg, "data-neg200.pbf");
+
+    msg.set_i(std::numeric_limits<int64_t>::max());
+    write_to_file(msg, "data-max.pbf");
+
+    msg.set_i(std::numeric_limits<int64_t>::min());
+    write_to_file(msg, "data-min.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/sint64/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestSInt64;
+
+message Test {
+
+    required sint64 i = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/skip/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/skip/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/skip/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,130 @@
+
+#include <test.hpp>
+
+TEST_CASE("skip() skips the right amount of bytes") {
+    // These are all the data files which contain exactly one field.
+    //
+    // Create this list with:
+    //   cd test/t
+    //   find . -name data\*pbf -not -empty | sed -e 's/^.\/\(.*\).pbf/"\1",/'
+    // and then remove everything manually that contains more than one
+    // field.
+    const std::vector<std::string> filenames = {
+        "bool/data-also-true",
+        "bool/data-false",
+        "bool/data-still-true",
+        "bool/data-true",
+        "bytes/data-binary",
+        "bytes/data-empty",
+        "bytes/data-one",
+        "bytes/data-string",
+        "double/data-neg",
+        "double/data-pos",
+        "double/data-zero",
+        "enum/data-black",
+        "enum/data-blue",
+        "fixed32/data-max",
+        "fixed32/data-pos",
+        "fixed32/data-zero",
+        "fixed64/data-max",
+        "fixed64/data-pos",
+        "fixed64/data-zero",
+        "float/data-neg",
+        "float/data-pos",
+        "float/data-zero",
+        "int32/data-max",
+        "int32/data-min",
+        "int32/data-neg",
+        "int32/data-pos",
+        "int32/data-zero",
+        "int64/data-max",
+        "int64/data-min",
+        "int64/data-neg",
+        "int64/data-pos",
+        "int64/data-zero",
+        "message/data-message",
+        "repeated/data-one",
+        "repeated_packed_fixed32/data-many",
+        "repeated_packed_fixed32/data-one",
+        "repeated_packed_fixed64/data-many",
+        "repeated_packed_fixed64/data-one",
+        "repeated_packed_int32/data-many",
+        "repeated_packed_int32/data-one",
+        "repeated_packed_int64/data-many",
+        "repeated_packed_int64/data-one",
+        "repeated_packed_sfixed32/data-many",
+        "repeated_packed_sfixed32/data-one",
+        "repeated_packed_sfixed64/data-many",
+        "repeated_packed_sfixed64/data-one",
+        "repeated_packed_sint32/data-many",
+        "repeated_packed_sint32/data-one",
+        "repeated_packed_sint64/data-many",
+        "repeated_packed_sint64/data-one",
+        "repeated_packed_uint32/data-many",
+        "repeated_packed_uint32/data-one",
+        "repeated_packed_uint64/data-many",
+        "repeated_packed_uint64/data-one",
+        "sfixed32/data-max",
+        "sfixed32/data-min",
+        "sfixed32/data-zero",
+        "sfixed64/data-max",
+        "sfixed64/data-min",
+        "sfixed64/data-zero",
+        "sint32/data-max",
+        "sint32/data-min",
+        "sint32/data-neg",
+        "sint32/data-pos",
+        "sint32/data-zero",
+        "sint64/data-max",
+        "sint64/data-min",
+        "sint64/data-neg",
+        "sint64/data-pos",
+        "sint64/data-zero",
+        "string/data-empty",
+        "string/data-one",
+        "string/data-string",
+        "tags/data-tag-1",
+        "tags/data-tag-200000",
+        "tags/data-tag-200",
+        "tags/data-tag-max",
+        "uint32/data-max",
+        "uint32/data-pos",
+        "uint32/data-zero",
+        "uint64/data-max",
+        "uint64/data-pos",
+        "uint64/data-zero",
+    };
+
+    for (const auto& filename : filenames) {
+        const std::string buffer = load_data(filename);
+
+        protozero::pbf_reader item{buffer};
+
+        REQUIRE(item.next());
+        item.skip();
+        REQUIRE_FALSE(item);
+    }
+}
+
+TEST_CASE("exceptional cases") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+    pw.add_fixed32(1, 123);
+
+    SECTION("check that next() throws on unknown field type") {
+        buffer[0] += 1; // hack to create illegal field type
+
+        protozero::pbf_reader item{buffer};
+
+        REQUIRE_THROWS_AS(item.next(), const protozero::unknown_pbf_wire_type_exception&);
+    }
+
+    SECTION("check that skip() throws on short buffer") {
+        buffer.resize(buffer.size() - 1); // "remove" last byte from buffer
+        protozero::pbf_reader item{buffer};
+
+        REQUIRE(item.next());
+        REQUIRE_THROWS_AS(item.skip(), const protozero::end_of_buffer_exception&);
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-empty.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-empty.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-empty.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-empty.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-empty.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-one.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-one.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-one.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+x
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-string.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-string.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/data-string.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+foobar
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,106 @@
+
+#include <test.hpp>
+
+TEST_CASE("read string field using get_string: empty") {
+    const std::string buffer = load_data("string/data-empty");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_string().empty());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_string: one") {
+    const std::string buffer = load_data("string/data-one");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_string() == "x");
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_string: string") {
+    const std::string buffer = load_data("string/data-string");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.get_string() == "foobar");
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_string: end of buffer") {
+    const std::string buffer = load_data("string/data-string");
+
+    for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+        protozero::pbf_reader item{buffer.data(), i};
+        REQUIRE(item.next());
+        REQUIRE_THROWS_AS(item.get_string(), const protozero::end_of_buffer_exception&);
+    }
+}
+
+TEST_CASE("read string field using get_view: empty") {
+    const std::string buffer = load_data("string/data-empty");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    const auto v = item.get_view();
+    REQUIRE(v.empty());
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_view: one") {
+    const std::string buffer = load_data("string/data-one");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    const auto v = item.get_view();
+    REQUIRE(*v.data() == 'x');
+    REQUIRE(v.size() == 1);
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_view: string") {
+    const std::string buffer = load_data("string/data-string");
+
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(std::string(item.get_view()) == "foobar");
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_view: end of buffer") {
+    const std::string buffer = load_data("string/data-string");
+
+    for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+        protozero::pbf_reader item{buffer.data(), i};
+        REQUIRE(item.next());
+        REQUIRE_THROWS_AS(item.get_view(), const protozero::end_of_buffer_exception&);
+    }
+}
+
+TEST_CASE("write string field") {
+    std::string buffer_test;
+    protozero::pbf_writer pbf_test{buffer_test};
+
+    SECTION("empty") {
+        pbf_test.add_string(1, "");
+        REQUIRE(buffer_test == load_data("string/data-empty"));
+    }
+
+    SECTION("one") {
+        pbf_test.add_string(1, "x");
+        REQUIRE(buffer_test == load_data("string/data-one"));
+    }
+
+    SECTION("string") {
+        pbf_test.add_string(1, "foobar");
+        REQUIRE(buffer_test == load_data("string/data-string"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/string_testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/string_testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/string_testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package TestString;
+
+message Test {
+
+    required string s = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,17 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestString::Test msg;
+
+    msg.set_s("");
+    write_to_file(msg, "data-empty.pbf");
+
+    msg.set_s("x");
+    write_to_file(msg, "data-one.pbf");
+
+    msg.set_s("foobar");
+    write_to_file(msg, "data-string.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/writer_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/writer_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/string/writer_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,38 @@
+
+#include <test.hpp>
+
+#include "t/string/string_testcase.pb.h"
+
+TEST_CASE("write string field and check with libprotobuf") {
+
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    TestString::Test msg;
+
+    SECTION("empty") {
+        pw.add_string(1, "");
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.s().empty());
+    }
+
+    SECTION("one") {
+        pw.add_string(1, "x");
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.s() == "x");
+    }
+
+    SECTION("string") {
+        pw.add_string(1, "foobar");
+
+        msg.ParseFromString(buffer);
+
+        REQUIRE(msg.s() == "foobar");
+    }
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-combined.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-combined.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-combined.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,3 @@
+
+
+ 
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-not-packed.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-not-packed.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-not-packed.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-packed.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-packed.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/data-packed.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,89 @@
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include <test.hpp>
+
+enum class ExampleMsg : protozero::pbf_tag_type {
+    repeated_uint32_x = 1
+};
+
+inline std::vector<uint32_t> read_data(const std::string& data) {
+    std::vector<uint32_t> values;
+
+    protozero::pbf_message<ExampleMsg> message{data};
+    while (message.next()) {
+        switch (message.tag_and_type()) {
+            case tag_and_type(ExampleMsg::repeated_uint32_x, protozero::pbf_wire_type::length_delimited): {
+                    const auto xit = message.get_packed_uint32();
+                    for (const auto value : xit) {
+                        values.push_back(value);
+                    }
+                }
+                break;
+            case tag_and_type(ExampleMsg::repeated_uint32_x, protozero::pbf_wire_type::varint): {
+                    const auto value = message.get_uint32();
+                    values.push_back(value);
+                }
+                break;
+            default:
+                REQUIRE(false); // should never be here
+        }
+    }
+
+    return values;
+}
+
+inline std::vector<uint32_t> read_data_packed(const std::string& data) {
+    std::vector<uint32_t> values;
+
+    protozero::pbf_message<ExampleMsg> message{data};
+    while (message.next(ExampleMsg::repeated_uint32_x, protozero::pbf_wire_type::length_delimited)) {
+        const auto xit = message.get_packed_uint32();
+        for (const auto value : xit) {
+            values.push_back(value);
+        }
+    }
+
+    return values;
+}
+
+TEST_CASE("read not packed repeated field with tag_and_type") {
+    const auto values = read_data(load_data("tag_and_type/data-not-packed"));
+
+    REQUIRE(values.size() == 3);
+    const std::vector<uint32_t> result{10, 11, 12};
+    REQUIRE(values == result);
+}
+
+TEST_CASE("read not packed repeated field with tag_and_type using next(...)") {
+    const auto values = read_data_packed(load_data("tag_and_type/data-not-packed"));
+
+    REQUIRE(values.empty());
+}
+
+TEST_CASE("read packed repeated field with tag_and_type") {
+    const auto values = read_data(load_data("tag_and_type/data-packed"));
+
+    REQUIRE(values.size() == 3);
+    const std::vector<uint32_t> result{20, 21, 22};
+    REQUIRE(values == result);
+}
+
+TEST_CASE("read packed repeated field with tag_and_type using next(...)") {
+    const auto values = read_data_packed(load_data("tag_and_type/data-packed"));
+
+    REQUIRE(values.size() == 3);
+    const std::vector<uint32_t> result{20, 21, 22};
+    REQUIRE(values == result);
+}
+
+TEST_CASE("read combined packed and not-packed repeated field with tag_and_type") {
+    const auto values = read_data(load_data("tag_and_type/data-combined"));
+
+    REQUIRE(values.size() == 9);
+    const std::vector<uint32_t> result{10, 11, 12, 20, 21, 22, 30, 31, 32};
+    REQUIRE(values == result);
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,42 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+
+    std::string out;
+
+    {
+        TestTagAndType::TestNotPacked msg;
+        for (uint32_t x = 10; x < 13; ++x) {
+            msg.add_x(x);
+        }
+
+        out.append(write_to_file(msg, "data-not-packed.pbf"));
+    }
+
+    {
+        TestTagAndType::TestPacked msg;
+        for (uint32_t x = 20; x < 23; ++x) {
+            msg.add_x(x);
+        }
+
+        out.append(write_to_file(msg, "data-packed.pbf"));
+    }
+
+    {
+        TestTagAndType::TestNotPacked msg;
+        for (uint32_t x = 30; x < 33; ++x) {
+            msg.add_x(x);
+        }
+
+        std::string mout;
+        msg.SerializeToString(&mout);
+        out.append(mout);
+    }
+
+    std::ofstream d("data-combined.pbf", std::ios_base::out|std::ios_base::binary);
+    assert(d.is_open());
+    d << out;
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tag_and_type/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,15 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestTagAndType;
+
+message TestNotPacked {
+    repeated int32 x = 1;
+    optional string s = 2;
+}
+
+message TestPacked {
+    repeated int32 x = 1 [packed=true];
+    optional string s = 2;
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-1.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-1.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-1.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+Í
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-200.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-200.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+ÀÍ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-200000.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-200000.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-200000.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+€ÔaÍ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-max.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-max.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/data-tag-max.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,53 @@
+
+#include <test.hpp>
+
+inline void check_tag(const std::string& buffer, protozero::pbf_tag_type tag) {
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.next());
+    REQUIRE(item.tag() == tag);
+    REQUIRE(item.get_int32() == 333L);
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read tag: 1") {
+    check_tag(load_data("tags/data-tag-1"), 1ul);
+}
+
+TEST_CASE("read tag: 200") {
+    check_tag(load_data("tags/data-tag-200"), 200ul);
+}
+
+TEST_CASE("read tag: 200000") {
+    check_tag(load_data("tags/data-tag-200000"), 200000ul);
+}
+
+TEST_CASE("read tag: max") {
+    check_tag(load_data("tags/data-tag-max"), (1ul << 29u) - 1u);
+}
+
+TEST_CASE("write tags") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("tag 1") {
+        pw.add_int32(1L, 333L);
+        REQUIRE(buffer == load_data("tags/data-tag-1"));
+    }
+
+    SECTION("tag 200") {
+        pw.add_int32(200L, 333L);
+        REQUIRE(buffer == load_data("tags/data-tag-200"));
+    }
+
+    SECTION("tag 200000") {
+        pw.add_int32(200000L, 333L);
+        REQUIRE(buffer == load_data("tags/data-tag-200000"));
+    }
+
+    SECTION("tag max") {
+        pw.add_int32(static_cast<int32_t>((1ul << 29u) - 1u), 333L);
+        REQUIRE(buffer == load_data("tags/data-tag-max"));
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,32 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+
+    {
+        TestTags::Test1 msg;
+        msg.set_i(333);
+        write_to_file(msg, "data-tag-1.pbf");
+    }
+
+    {
+        TestTags::Test200 msg;
+        msg.set_i(333);
+        write_to_file(msg, "data-tag-200.pbf");
+    }
+
+    {
+        TestTags::Test200000 msg;
+        msg.set_i(333);
+        write_to_file(msg, "data-tag-200000.pbf");
+    }
+
+    {
+        TestTags::TestMax msg;
+        msg.set_i(333);
+        write_to_file(msg, "data-tag-max.pbf");
+    }
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/tags/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,29 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestTags;
+
+message Test1 {
+
+    required int32 i = 1;
+
+}
+
+message Test200 {
+
+    required int32 i = 200;
+
+}
+
+message Test200000 {
+
+    required int32 i = 200000;
+
+}
+
+message TestMax {
+
+    required int32 i = 536870911;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-max.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+ÿÿÿÿ
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-pos.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-pos200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-pos200.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-pos200.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+È
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE uint32
+#define PBF_TYPE_IS_SIGNED 0
+using cpp_type = uint32_t;
+
+#include <scalar_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,20 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestUInt32::Test msg;
+
+    msg.set_i(0ul);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_i(1);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_i(200);
+    write_to_file(msg, "data-pos200.pbf");
+
+    msg.set_i(std::numeric_limits<uint32_t>::max());
+    write_to_file(msg, "data-max.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint32/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestUInt32;
+
+message Test {
+
+    required uint32 i = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-max.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-max.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-max.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-max.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-max.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-pos.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-pos.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-pos.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-pos200.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-pos200.pbf	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-pos200.pbf	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+È
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-zero.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-zero.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-zero.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-zero.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/data-zero.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,9 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE uint64
+#define PBF_TYPE_IS_SIGNED 0
+using cpp_type = uint64_t;
+
+#include <scalar_access.hpp>
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/testcase.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/testcase.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/testcase.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,20 @@
+
+#include <testcase.hpp>
+#include "testcase.pb.h"
+
+int main(int c, char *argv[]) {
+    TestUInt64::Test msg;
+
+    msg.set_i(0ul);
+    write_to_file(msg, "data-zero.pbf");
+
+    msg.set_i(1);
+    write_to_file(msg, "data-pos.pbf");
+
+    msg.set_i(200);
+    write_to_file(msg, "data-pos200.pbf");
+
+    msg.set_i(std::numeric_limits<uint64_t>::max());
+    write_to_file(msg, "data-max.pbf");
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/testcase.proto
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/testcase.proto	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/uint64/testcase.proto	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+option optimize_for = LITE_RUNTIME;
+
+package TestUInt64;
+
+message Test {
+
+    required uint64 i = 1;
+
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/vector_tile/data.vector.pbf
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/vector_tile/data.vector.pbf
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/vector_tile/data.vector.pbf	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/vector_tile/data.vector.pbf	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/vector_tile/data.vector.pbf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/vector_tile/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/vector_tile/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/vector_tile/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,155 @@
+
+#include <test.hpp>
+
+#include <string>
+#include <vector>
+
+// Input data.vector is encoded according to
+// https://github.com/mapbox/mapnik-vector-tile/blob/master/proto/vector_tile.proto
+
+static std::string get_name(protozero::pbf_reader layer) { // copy!
+    while (layer.next(1)) { // required string name
+        return layer.get_string();
+    }
+    REQUIRE(false); // should never be here
+    return "";
+}
+
+TEST_CASE("reading vector tiles") {
+    static const std::vector<std::string> expected_layer_names = {
+        "landuse", "waterway", "water", "aeroway", "barrier_line", "building",
+        "landuse_overlay", "tunnel", "road", "bridge", "admin",
+        "country_label_line", "country_label", "marine_label", "state_label",
+        "place_label", "water_label", "area_label", "rail_station_label",
+        "airport_label", "road_label", "waterway_label", "building_label"
+    };
+
+    const std::string buffer = load_data("vector_tile/data.vector");
+    protozero::pbf_reader item{buffer};
+    std::vector<std::string> layer_names;
+
+    SECTION("iterate over message using next()") {
+        while (item.next()) {
+            if (item.tag() == 3) { // repeated message Layer
+                protozero::pbf_reader layer{item.get_message()};
+                while (layer.next()) {
+                    switch (layer.tag()) {
+                        case 1: // required string name
+                            layer_names.push_back(layer.get_string());
+                            break;
+                        default:
+                            layer.skip();
+                    }
+                }
+            } else {
+                item.skip();
+                REQUIRE(false); // should never be here
+            }
+        }
+
+        REQUIRE(layer_names == expected_layer_names);
+    }
+
+    SECTION("iterate over message using next(tag)") {
+        while (item.next(3)) { // repeated message Layer
+            protozero::pbf_reader layermsg{item.get_message()};
+            while (layermsg.next(1)) { // required string name
+                layer_names.push_back(layermsg.get_string());
+            }
+        }
+
+        REQUIRE(layer_names == expected_layer_names);
+    }
+
+    SECTION("iterate over message using next(tag, type)") {
+        while (item.next(3, protozero::pbf_wire_type::length_delimited)) { // repeated message Layer
+            protozero::pbf_reader layermsg{item.get_message()};
+            while (layermsg.next(1, protozero::pbf_wire_type::length_delimited)) { // required string name
+                layer_names.push_back(layermsg.get_string());
+            }
+        }
+
+        REQUIRE(layer_names == expected_layer_names);
+    }
+
+    SECTION("iterate over features in road layer") {
+        int n=0;
+        int n_id = 0;
+        int n_geomtype = 0;
+        while (item.next(3)) { // repeated message Layer
+            protozero::pbf_reader layer{item.get_message()};
+            std::string name = get_name(layer);
+            if (name == "road") {
+                while (layer.next(2)) { // repeated Feature
+                    ++n;
+                    protozero::pbf_reader feature{layer.get_message()};
+                    while (feature.next()) {
+                        switch (feature.tag()) {
+                            case 1: { // optional uint64 id
+                                const auto id = feature.get_uint64();
+                                REQUIRE(id >=   1ULL);
+                                REQUIRE(id <= 504ULL);
+                                ++n_id;
+                                break;
+                            }
+                            case 3: { // optional GeomType
+                                const auto geom_type = feature.get_uint32();
+                                REQUIRE(geom_type >= 1UL);
+                                REQUIRE(geom_type <= 3UL);
+                                ++n_geomtype;
+                                break;
+                            }
+                            default:
+                                feature.skip();
+                        }
+                    }
+                }
+            }
+        }
+
+        REQUIRE(n == 502);
+        REQUIRE(n_id == 502);
+        REQUIRE(n_geomtype == 502);
+    }
+
+    SECTION("iterate over features in road layer using tag_and_type") {
+        int n=0;
+        int n_id = 0;
+        int n_geomtype = 0;
+        while (item.next(3)) { // repeated message Layer
+            protozero::pbf_reader layer{item.get_message()};
+            std::string name = get_name(layer);
+            if (name == "road") {
+                while (layer.next(2)) { // repeated Feature
+                    ++n;
+                    protozero::pbf_reader feature{layer.get_message()};
+                    while (feature.next()) {
+                        switch (feature.tag_and_type()) {
+                            case protozero::tag_and_type(1, protozero::pbf_wire_type::varint): { // optional uint64 id
+                                const auto id = feature.get_uint64();
+                                REQUIRE(id >=   1ULL);
+                                REQUIRE(id <= 504ULL);
+                                ++n_id;
+                                break;
+                            }
+                            case protozero::tag_and_type(3, protozero::pbf_wire_type::varint): { // optional GeomType
+                                const auto geom_type = feature.get_uint32();
+                                REQUIRE(geom_type >= 1UL);
+                                REQUIRE(geom_type <= 3UL);
+                                ++n_geomtype;
+                                break;
+                            }
+                            default:
+                                feature.skip();
+                        }
+                    }
+                }
+            }
+        }
+
+        REQUIRE(n == 502);
+        REQUIRE(n_id == 502);
+        REQUIRE(n_geomtype == 502);
+    }
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/wrong_type_access/reader_test_cases.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/wrong_type_access/reader_test_cases.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/t/wrong_type_access/reader_test_cases.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,55 @@
+
+#include <test.hpp>
+
+// protobuf wire type 0
+TEST_CASE("check assert on non-varint access to varint") {
+    const std::string buffer = load_data("int32/data-zero");
+
+    protozero::pbf_reader item{buffer};
+    REQUIRE(item.next());
+
+    REQUIRE(item.get_int32() == 0);
+    REQUIRE_THROWS_AS(item.get_fixed64(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_string(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_fixed32(), const assert_error&);
+}
+
+// protobuf wire type 1
+TEST_CASE("check assert on non-fixed access to fixed64") {
+    const std::string buffer = load_data("fixed64/data-zero");
+
+    protozero::pbf_reader item{buffer};
+    REQUIRE(item.next());
+
+    REQUIRE_THROWS_AS(item.get_int32(), const assert_error&);
+    REQUIRE(item.get_fixed64() == 0);
+    REQUIRE_THROWS_AS(item.get_string(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_fixed32(), const assert_error&);
+}
+
+// protobuf wire type 2
+TEST_CASE("check assert on non-string access to string") {
+    const std::string buffer = load_data("string/data-string");
+
+    protozero::pbf_reader item{buffer};
+    REQUIRE(item.next());
+
+    REQUIRE_THROWS_AS(item.get_int32(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_fixed64(), const assert_error&);
+    REQUIRE(item.get_string() == "foobar");
+    REQUIRE_THROWS_AS(item.get_fixed32(), const assert_error&);
+}
+
+// protobuf wire type 5
+TEST_CASE("check assert on non-fixed access to fixed32") {
+    const std::string buffer = load_data("fixed32/data-zero");
+
+    protozero::pbf_reader item{buffer};
+    REQUIRE(item.next());
+
+    REQUIRE_THROWS_AS(item.get_int32(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_fixed64(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_string(), const assert_error&);
+    REQUIRE(item.get_fixed32() == 0);
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/CMakeLists.txt
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/CMakeLists.txt	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/CMakeLists.txt	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,24 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake config
+#
+#  protozero unit tests
+#
+#-----------------------------------------------------------------------------
+
+set(UNIT_TESTS data_view
+               basic
+               endian
+               exceptions
+               iterators
+               varint
+               zigzag)
+
+string(REGEX REPLACE "([^;]+)" "test_\\1.cpp" _test_sources "${UNIT_TESTS}")
+
+add_executable(unit_tests main.cpp ${_test_sources})
+
+add_test(NAME unit_tests COMMAND unit_tests)
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/main.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/main.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/main.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,4 @@
+
+#define CATCH_CONFIG_MAIN
+#include <test.hpp> // IWYU pragma: keep
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_basic.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_basic.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_basic.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,141 @@
+
+#include <test.hpp>
+
+#include <type_traits>
+
+template <typename T>
+struct movable_not_copyable {
+    constexpr static bool value = !std::is_copy_constructible<T>::value &&
+                                  !std::is_copy_assignable<T>::value    &&
+                                   std::is_nothrow_move_constructible<T>::value &&
+                                   std::is_nothrow_move_assignable<T>::value;
+};
+
+static_assert(movable_not_copyable<protozero::pbf_writer>::value, "pbf_writer should be nothrow movable, but not copyable");
+
+enum class dummy : protozero::pbf_tag_type {};
+static_assert(movable_not_copyable<protozero::pbf_builder<dummy>>::value, "pbf_builder should be nothrow movable, but not copyable");
+
+static_assert(movable_not_copyable<protozero::packed_field_bool>::value, "packed_field_bool should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_enum>::value, "packed_field_enum should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_int32>::value, "packed_field_int32 should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_sint32>::value, "packed_field_sint32 should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_uint32>::value, "packed_field_uint32 should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_int64>::value, "packed_field_int64 should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_sint64>::value, "packed_field_sint64 should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_uint64>::value, "packed_field_uint64 should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_fixed32>::value, "packed_field_fixed32 should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_sfixed32>::value, "packed_field_sfixed32 should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_fixed64>::value, "packed_field_fixed64 should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_sfixed64>::value, "packed_field_sfixed64 should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_float>::value, "packed_field_float should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<protozero::packed_field_double>::value, "packed_field_double should be nothrow movable, but not copyable");
+
+TEST_CASE("default constructed pbf_reader is okay") {
+    protozero::pbf_reader item;
+
+    REQUIRE(item.length() == 0);
+    REQUIRE_FALSE(item); // test operator bool()
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("empty buffer in pbf_reader is okay") {
+    const std::string buffer;
+    protozero::pbf_reader item{buffer};
+
+    REQUIRE(item.length() == 0);
+    REQUIRE_FALSE(item); // test operator bool()
+    REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("check every possible value for single byte in buffer") {
+    char buffer[1];
+    for (int i = 0; i <= 255; ++i) {
+        buffer[0] = static_cast<char>(i);
+        protozero::pbf_reader item{buffer, 1};
+
+        REQUIRE(item.length() == 1);
+        REQUIRE_FALSE(!item); // test operator bool()
+        REQUIRE_THROWS((item.next(), item.skip()));
+    }
+}
+
+TEST_CASE("next() should throw when illegal wire type is encountered") {
+    const char buffer[1] = {1u << 3u | 7u};
+
+    protozero::pbf_reader item{buffer, 1};
+    REQUIRE_THROWS_AS(item.next(), const protozero::unknown_pbf_wire_type_exception&);
+}
+
+TEST_CASE("next() should throw when illegal tag 0 is encountered") {
+    std::string data;
+    protozero::write_varint(std::back_inserter(data), 0u << 3u | 1u);
+    protozero::pbf_reader item{data};
+    REQUIRE_THROWS_AS(item.next(), const protozero::invalid_tag_exception&);
+}
+
+TEST_CASE("next() should throw when illegal tag 19000 is encountered") {
+    std::string data;
+    protozero::write_varint(std::back_inserter(data), 19000u << 3u | 1u);
+    protozero::pbf_reader item{data};
+    REQUIRE_THROWS_AS(item.next(), const protozero::invalid_tag_exception&);
+}
+
+TEST_CASE("next() should throw when illegal tag 19001 is encountered") {
+    std::string data;
+    protozero::write_varint(std::back_inserter(data), 19001u << 3u | 1u);
+    protozero::pbf_reader item{data};
+    REQUIRE_THROWS_AS(item.next(), const protozero::invalid_tag_exception&);
+}
+
+TEST_CASE("next() should throw when illegal tag 19999 is encountered") {
+    std::string data;
+    protozero::write_varint(std::back_inserter(data), 19999u << 3u | 1u);
+    protozero::pbf_reader item{data};
+    REQUIRE_THROWS_AS(item.next(), const protozero::invalid_tag_exception&);
+}
+
+TEST_CASE("next() works when legal tag 1 is encountered") {
+    std::string data;
+    protozero::write_varint(std::back_inserter(data), 1u << 3u | 1u);
+    protozero::pbf_reader item{data};
+    REQUIRE(item.next());
+}
+
+TEST_CASE("next() works when legal tag 18999 is encountered") {
+    std::string data;
+    protozero::write_varint(std::back_inserter(data), 18999u << 3u | 1u);
+    protozero::pbf_reader item{data};
+    REQUIRE(item.next());
+}
+
+TEST_CASE("next() works when legal tag 20000 is encountered") {
+    std::string data;
+    protozero::write_varint(std::back_inserter(data), 20000u << 3u | 1u);
+    protozero::pbf_reader item{data};
+    REQUIRE(item.next());
+}
+
+TEST_CASE("next() works when legal tag 1^29 - 1 is encountered") {
+    std::string data;
+    protozero::write_varint(std::back_inserter(data), ((1ul << 29u) - 1u) << 3u | 1u);
+    protozero::pbf_reader item{data};
+    REQUIRE(item.next());
+}
+
+TEST_CASE("pbf_writer asserts on invalid tags") {
+    std::string data;
+    protozero::pbf_writer writer{data};
+
+    REQUIRE_THROWS_AS(writer.add_int32(0, 123), const assert_error&);
+    writer.add_int32(1, 123);
+    writer.add_int32(2, 123);
+    writer.add_int32(18999, 123);
+    REQUIRE_THROWS_AS(writer.add_int32(19000, 123), const assert_error&);
+    REQUIRE_THROWS_AS(writer.add_int32(19001, 123), const assert_error&);
+    REQUIRE_THROWS_AS(writer.add_int32(19999, 123), const assert_error&);
+    writer.add_int32(20000, 123);
+    writer.add_int32((1u << 29u) - 1u, 123);
+    REQUIRE_THROWS_AS(writer.add_int32(1u << 29u, 123), const assert_error&);
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_data_view.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_data_view.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_data_view.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,162 @@
+
+#include <array>
+
+#include <test.hpp>
+
+#include <protozero/types.hpp>
+
+TEST_CASE("default constructed data_view") {
+    const protozero::data_view view{};
+    REQUIRE(view.data() == nullptr);
+    REQUIRE(view.size() == 0); // NOLINT(readability-container-size-empty)
+    REQUIRE(view.empty());
+}
+
+TEST_CASE("data_view from C string") {
+    const protozero::data_view view{"foobar"};
+    REQUIRE(view.data());
+    REQUIRE(view.size() == 6);
+    REQUIRE_FALSE(view.empty());
+}
+
+TEST_CASE("data_view from std::string") {
+    const std::string str{"foobar"};
+    const protozero::data_view view{str};
+    REQUIRE(view.data());
+    REQUIRE(view.size() == 6);
+}
+
+TEST_CASE("data_view from ptr, size") {
+    const std::string str{"foobar"};
+    const protozero::data_view view{str.data(), str.size()};
+    REQUIRE(view.data());
+    REQUIRE(view.size() == 6);
+}
+
+TEST_CASE("data_view from C array") {
+    const char* str = "foobar";
+    const protozero::data_view view{str};
+    REQUIRE(view.data());
+    REQUIRE(view.size() == 6);
+}
+
+TEST_CASE("data_view from std::array") {
+    const std::array<char, 7> str{"foobar"};
+    const protozero::data_view view{str.data(), 6};
+    REQUIRE(view.data());
+    REQUIRE(view.size() == 6);
+}
+
+TEST_CASE("convert data_view to std::string") {
+    const protozero::data_view view{"foobar"};
+
+    const std::string s = std::string(view);
+    REQUIRE(s == "foobar");
+    REQUIRE(std::string(view) == "foobar");
+    REQUIRE(view.to_string() == "foobar");
+}
+
+#ifndef PROTOZERO_USE_VIEW
+// This test only works with our own data_view implementation, because only
+// that one contains the protozero_assert() which generates the exception.
+TEST_CASE("converting default constructed data_view to string fails") {
+    const protozero::data_view view{};
+    REQUIRE_THROWS_AS(view.to_string(), const assert_error&);
+}
+#endif
+
+TEST_CASE("swapping data_view") {
+    protozero::data_view view1{"foo"};
+    protozero::data_view view2{"bar"};
+
+    REQUIRE(view1.to_string() == "foo");
+    REQUIRE(view2.to_string() == "bar");
+
+    using std::swap;
+    swap(view1, view2);
+
+    REQUIRE(view2.to_string() == "foo");
+    REQUIRE(view1.to_string() == "bar");
+}
+
+TEST_CASE("comparing data_views") {
+    const protozero::data_view v1{"foo"};
+    const protozero::data_view v2{"bar"};
+    const protozero::data_view v3{"foox"};
+    const protozero::data_view v4{"foo"};
+    const protozero::data_view v5{"fooooooo", 3};
+    const protozero::data_view v6{"f\0o", 3};
+    const protozero::data_view v7{"f\0obar", 3};
+
+    REQUIRE_FALSE(v1 == v2);
+    REQUIRE_FALSE(v1 == v3);
+    REQUIRE(v1 == v4);
+    REQUIRE(v1 == v5);
+    REQUIRE_FALSE(v1 == v6);
+    REQUIRE_FALSE(v1 == v7);
+    REQUIRE_FALSE(v2 == v3);
+    REQUIRE_FALSE(v2 == v4);
+    REQUIRE_FALSE(v3 == v4);
+    REQUIRE(v4 == v5);
+    REQUIRE(v6 == v7);
+
+    REQUIRE(v1 != v2);
+    REQUIRE(v1 != v3);
+    REQUIRE_FALSE(v1 != v4);
+    REQUIRE_FALSE(v1 != v5);
+    REQUIRE(v1 != v6);
+    REQUIRE(v1 != v7);
+    REQUIRE(v2 != v3);
+    REQUIRE(v2 != v4);
+    REQUIRE(v3 != v4);
+    REQUIRE_FALSE(v4 != v5);
+    REQUIRE_FALSE(v6 != v7);
+}
+
+TEST_CASE("ordering of data_views") {
+    const protozero::data_view v1{"foo"};
+    const protozero::data_view v2{"foo"};
+    const protozero::data_view v3{"bar"};
+    const protozero::data_view v4{"foox"};
+    const protozero::data_view v5{"zzz"};
+
+    REQUIRE(v1.compare(v1) == 0);
+    REQUIRE(v1.compare(v2) == 0);
+    REQUIRE(v1.compare(v3) > 0);
+    REQUIRE(v1.compare(v4) < 0);
+    REQUIRE(v1.compare(v5) < 0);
+
+    REQUIRE(v2.compare(v1) == 0);
+    REQUIRE(v2.compare(v2) == 0);
+    REQUIRE(v2.compare(v3) > 0);
+    REQUIRE(v2.compare(v4) < 0);
+    REQUIRE(v2.compare(v5) < 0);
+
+    REQUIRE(v3.compare(v1) < 0);
+    REQUIRE(v3.compare(v2) < 0);
+    REQUIRE(v3.compare(v3) == 0);
+    REQUIRE(v3.compare(v4) < 0);
+    REQUIRE(v3.compare(v5) < 0);
+
+    REQUIRE(v4.compare(v1) > 0);
+    REQUIRE(v4.compare(v2) > 0);
+    REQUIRE(v4.compare(v3) > 0);
+    REQUIRE(v4.compare(v4) == 0);
+    REQUIRE(v4.compare(v5) < 0);
+
+    REQUIRE(v5.compare(v1) > 0);
+    REQUIRE(v5.compare(v2) > 0);
+    REQUIRE(v5.compare(v3) > 0);
+    REQUIRE(v5.compare(v4) > 0);
+    REQUIRE(v5.compare(v5) == 0);
+
+    REQUIRE(v1 == v2);
+    REQUIRE(v1 <= v2);
+    REQUIRE(v1 >= v2);
+    REQUIRE(v1 < v4);
+    REQUIRE(v3 < v1);
+    REQUIRE(v3 <= v1);
+    REQUIRE(v5 > v1);
+    REQUIRE(v5 >= v1);
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_endian.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_endian.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_endian.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,72 @@
+
+#include <cstdint>
+#include <limits>
+
+#include <test.hpp>
+
+#include <protozero/byteswap.hpp>
+
+static int32_t check_swap_4(int32_t data) noexcept {
+    protozero::byteswap_inplace(&data);
+    protozero::byteswap_inplace(&data);
+    return data;
+}
+
+static int64_t check_swap_8(int64_t data) noexcept {
+    protozero::byteswap_inplace(&data);
+    protozero::byteswap_inplace(&data);
+    return data;
+}
+
+TEST_CASE("byte swapping") {
+    REQUIRE(0 == check_swap_4(0));
+    REQUIRE(1 == check_swap_4(1));
+    REQUIRE(-1 == check_swap_4(-1));
+    REQUIRE(395503 == check_swap_4(395503));
+    REQUIRE(-804022 == check_swap_4(-804022));
+    REQUIRE(std::numeric_limits<int32_t>::max() == check_swap_4(std::numeric_limits<int32_t>::max()));
+    REQUIRE(std::numeric_limits<int32_t>::min() == check_swap_4(std::numeric_limits<int32_t>::min()));
+
+    REQUIRE(0 == check_swap_8(0));
+    REQUIRE(1 == check_swap_8(1));
+    REQUIRE(-1 == check_swap_8(-1));
+    REQUIRE(395503ll == check_swap_8(395503ll));
+    REQUIRE(-804022ll == check_swap_8(-804022ll));
+    REQUIRE(3280329805ll == check_swap_8(3280329805ll));
+    REQUIRE(-2489204041ll == check_swap_8(-2489204041ll));
+    REQUIRE(std::numeric_limits<int64_t>::max() == check_swap_8(std::numeric_limits<int64_t>::max()));
+    REQUIRE(std::numeric_limits<int64_t>::min() == check_swap_8(std::numeric_limits<int64_t>::min()));
+}
+
+TEST_CASE("byte swap uint32_t") {
+    uint32_t a = 17;
+    protozero::byteswap_inplace(&a);
+    protozero::byteswap_inplace(&a);
+
+    REQUIRE(17 == a);
+}
+
+TEST_CASE("byte swap uint64_t") {
+    uint64_t a = 347529808;
+    protozero::byteswap_inplace(&a);
+    protozero::byteswap_inplace(&a);
+
+    REQUIRE(347529808 == a);
+}
+
+TEST_CASE("byte swap double") {
+    double a = 1.1;
+    protozero::byteswap_inplace(&a);
+    protozero::byteswap_inplace(&a);
+
+    REQUIRE(a == Approx(1.1));
+}
+
+TEST_CASE("byte swap float") {
+    float a = 1.1f;
+    protozero::byteswap_inplace(&a);
+    protozero::byteswap_inplace(&a);
+
+    REQUIRE(a == Approx(1.1f));
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_exceptions.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_exceptions.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_exceptions.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,33 @@
+
+#include <test.hpp>
+
+TEST_CASE("exceptions messages for pbf exception") {
+    protozero::exception e;
+    REQUIRE(std::string{e.what()} == std::string{"pbf exception"});
+}
+
+TEST_CASE("exceptions messages for varint too long") {
+    protozero::varint_too_long_exception e;
+    REQUIRE(std::string{e.what()} == std::string{"varint too long exception"});
+}
+
+TEST_CASE("exceptions messages for unknown pbf field type") {
+    protozero::unknown_pbf_wire_type_exception e;
+    REQUIRE(std::string{e.what()} == std::string{"unknown pbf field type exception"});
+}
+
+TEST_CASE("exceptions messages for end of buffer") {
+    protozero::end_of_buffer_exception e;
+    REQUIRE(std::string{e.what()} == std::string{"end of buffer exception"});
+}
+
+TEST_CASE("exceptions messages for invalid tag") {
+    protozero::invalid_tag_exception e;
+    REQUIRE(std::string{e.what()} == std::string{"invalid tag exception"});
+}
+
+TEST_CASE("exceptions messages for invalid length") {
+    protozero::invalid_length_exception e;
+    REQUIRE(std::string{e.what()} == std::string{"invalid length exception"});
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_iterators.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_iterators.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_iterators.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,18 @@
+
+#include <test.hpp>
+
+TEST_CASE("default constructed varint_iterators are equal") {
+    protozero::const_varint_iterator<uint32_t> a{};
+    protozero::const_varint_iterator<uint32_t> b{};
+
+    protozero::iterator_range<protozero::const_varint_iterator<uint32_t>> r{};
+
+    REQUIRE(a == a);
+    REQUIRE(a == b);
+    REQUIRE(a == r.begin());
+    REQUIRE(a == r.end());
+    REQUIRE(r.empty());
+    REQUIRE(r.size() == 0); // NOLINT(readability-container-size-empty)
+    REQUIRE(r.begin() == r.end());
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_varint.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_varint.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_varint.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,241 @@
+
+#include <test.hpp>
+
+TEST_CASE("max varint length") {
+    REQUIRE(protozero::max_varint_length == 10);
+}
+
+TEST_CASE("varint") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("encode/decode int32") {
+        pw.add_int32(1, 17);
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+
+        SECTION("get") {
+            REQUIRE(17 == item.get_int32());
+        }
+
+        SECTION("skip") {
+            item.skip();
+        }
+
+        REQUIRE_FALSE(item.next());
+    }
+
+    SECTION("encode/decode uint32") {
+        pw.add_uint32(1, 17u);
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+
+        SECTION("get") {
+            REQUIRE(17u == item.get_uint32());
+        }
+
+        SECTION("skip") {
+            item.skip();
+        }
+
+        REQUIRE_FALSE(item.next());
+    }
+
+    SECTION("encode/decode uint64") {
+        pw.add_uint64(1, (1ull << 40u));
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+
+        SECTION("get") {
+            REQUIRE((1ull << 40u) == item.get_uint64());
+        }
+
+        SECTION("skip") {
+            item.skip();
+        }
+
+        REQUIRE_FALSE(item.next());
+    }
+
+    SECTION("short buffer while parsing varint") {
+        pw.add_uint64(1, (1ull << 40u));
+        buffer.resize(buffer.size() - 1); // "remove" last byte from buffer
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+
+        SECTION("get") {
+            REQUIRE_THROWS_AS(item.get_uint64(), const protozero::end_of_buffer_exception&);
+        }
+
+        SECTION("skip") {
+            REQUIRE_THROWS_AS(item.skip(), const protozero::end_of_buffer_exception&);
+        }
+    }
+
+    SECTION("data corruption in buffer while parsing varint)") {
+        pw.add_uint64(1, (1ull << 20u));
+        buffer[buffer.size() - 1] += 0x80; // pretend the varint goes on
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+
+        SECTION("get") {
+            REQUIRE_THROWS_AS(item.get_uint64(), const protozero::end_of_buffer_exception&);
+        }
+
+        SECTION("skip") {
+            REQUIRE_THROWS_AS(item.skip(), const protozero::end_of_buffer_exception&);
+        }
+    }
+
+    SECTION("data corruption in buffer while parsing varint (max length varint)") {
+        pw.add_uint64(1, std::numeric_limits<uint64_t>::max());
+        buffer[buffer.size() - 1] += 0x80; // pretend the varint goes on
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+
+        SECTION("get") {
+            REQUIRE_THROWS_AS(item.get_uint64(), const protozero::varint_too_long_exception&);
+        }
+
+        SECTION("skip") {
+            REQUIRE_THROWS_AS(item.skip(), const protozero::varint_too_long_exception&);
+        }
+    }
+}
+
+TEST_CASE("10-byte varint") {
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+    pw.add_uint64(1, 1);
+    buffer.back() = static_cast<char>(0xffu);
+    for (int i = 0; i < 9; ++i) {
+        buffer.push_back(static_cast<char>(0xffu));
+    }
+    buffer.push_back(0x02);
+
+    protozero::pbf_reader item{buffer};
+    REQUIRE(item.next());
+    REQUIRE_THROWS_AS(item.get_uint64(), const protozero::varint_too_long_exception&);
+}
+
+TEST_CASE("lots of varints back and forth") {
+    std::string buffer;
+
+    for (uint32_t n = 0; n < 70000; ++n) {
+        protozero::pbf_writer pw{buffer};
+        pw.add_uint32(1, n);
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+        REQUIRE(n == item.get_uint32());
+        REQUIRE_FALSE(item.next());
+        buffer.clear();
+    }
+
+    for (int32_t n = -70000; n < 70000; ++n) {
+        protozero::pbf_writer pw{buffer};
+        pw.add_int32(1, n);
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+        REQUIRE(n == item.get_int32());
+        REQUIRE_FALSE(item.next());
+        buffer.clear();
+    }
+
+    for (int32_t n = -70000; n < 70000; ++n) {
+        protozero::pbf_writer pw{buffer};
+        pw.add_sint32(1, n);
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+        REQUIRE(n == item.get_sint32());
+        REQUIRE_FALSE(item.next());
+        buffer.clear();
+    }
+
+    for (uint32_t i = 0; i < 63; ++i) {
+        const auto n = static_cast<int64_t>(1ull << i);
+        protozero::pbf_writer pw{buffer};
+        pw.add_int64(1, n);
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+        REQUIRE(n == item.get_int64());
+        REQUIRE_FALSE(item.next());
+        buffer.clear();
+    }
+
+    for (uint32_t i = 0; i < 63; ++i) {
+        const int64_t n = - static_cast<int64_t>(1ull << i);
+        protozero::pbf_writer pw{buffer};
+        pw.add_int64(1, n);
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+        REQUIRE(n == item.get_int64());
+        REQUIRE_FALSE(item.next());
+        buffer.clear();
+    }
+
+    for (uint32_t i = 0; i < 64; ++i) {
+        const uint64_t n = 1ull << i;
+        protozero::pbf_writer pw{buffer};
+        pw.add_uint64(1, n);
+        protozero::pbf_reader item{buffer};
+        REQUIRE(item.next());
+        REQUIRE(n == item.get_uint64());
+        REQUIRE_FALSE(item.next());
+        buffer.clear();
+    }
+}
+
+TEST_CASE("skip_varint with empty buffer throws") {
+    const char* buffer = "";
+    REQUIRE_THROWS_AS(protozero::skip_varint(&buffer, buffer), const protozero::end_of_buffer_exception&);
+}
+
+TEST_CASE("call skip_varint with every possible value for single byte in buffer") {
+    char buffer[1];
+    for (int i = 0; i <= 127; ++i) {
+        buffer[0] = static_cast<char>(i);
+        const char* b = buffer;
+        protozero::skip_varint(&b, buffer + 1);
+        REQUIRE(b == buffer + 1);
+    }
+    for (int i = 128; i <= 255; ++i) {
+        buffer[0] = static_cast<char>(i);
+        const char* b = buffer;
+        REQUIRE_THROWS_AS(protozero::skip_varint(&b, buffer + 1), const protozero::end_of_buffer_exception&);
+    }
+}
+
+TEST_CASE("decode_varint with empty buffer throws") {
+    const char* buffer = "";
+    REQUIRE_THROWS_AS(protozero::decode_varint(&buffer, buffer), const protozero::end_of_buffer_exception&);
+}
+
+TEST_CASE("call decode_varint with every possible value for single byte in buffer") {
+    char buffer[1];
+    for (int i = 0; i <= 127; ++i) {
+        REQUIRE(protozero::length_of_varint(i) == 1);
+        buffer[0] = static_cast<char>(i);
+        const char* b = buffer;
+        REQUIRE(protozero::decode_varint(&b, buffer + 1) == i);
+        REQUIRE(b == buffer + 1);
+    }
+    for (int i = 128; i <= 255; ++i) {
+        REQUIRE(protozero::length_of_varint(i) == 2);
+        buffer[0] = static_cast<char>(i);
+        const char* b = buffer;
+        REQUIRE_THROWS_AS(protozero::decode_varint(&b, buffer + 1), const protozero::end_of_buffer_exception&);
+    }
+}
+
+TEST_CASE("check lengths of varint") {
+    REQUIRE(protozero::length_of_varint(0) == 1);
+    REQUIRE(protozero::length_of_varint(127) == 1);
+    REQUIRE(protozero::length_of_varint(128) == 2);
+    REQUIRE(protozero::length_of_varint(16383) == 2);
+    REQUIRE(protozero::length_of_varint(16384) == 3);
+    REQUIRE(protozero::length_of_varint(2097151) == 3);
+    REQUIRE(protozero::length_of_varint(2097152) == 4);
+    REQUIRE(protozero::length_of_varint(0xffffffffull) == 5);
+    REQUIRE(protozero::length_of_varint(0xffffffffffffffffull) == 10);
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_zigzag.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_zigzag.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/unit/test_zigzag.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,85 @@
+
+#include <test.hpp>
+
+static_assert(protozero::encode_zigzag32( 0L) == 0UL, "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag32(-1L) == 1UL, "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag32( 1L) == 2UL, "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag32(-2L) == 3UL, "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag32( 2L) == 4UL, "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag32( std::numeric_limits<int32_t>::max()) == 2 * static_cast<uint32_t>(std::numeric_limits<int32_t>::max()), "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag32(-std::numeric_limits<int32_t>::max()) == 2 * static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) - 1, "test constexpr zigzag functions");
+
+static_assert(protozero::encode_zigzag64( 0LL) == 0ULL, "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag64(-1LL) == 1ULL, "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag64( 1LL) == 2ULL, "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag64(-2LL) == 3ULL, "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag64( 2LL) == 4ULL, "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag64( std::numeric_limits<int64_t>::max()) == 2 * static_cast<uint64_t>(std::numeric_limits<int64_t>::max()), "test constexpr zigzag functions");
+static_assert(protozero::encode_zigzag64(-std::numeric_limits<int64_t>::max()) == 2 * static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) - 1, "test constexpr zigzag functions");
+
+static_assert(protozero::decode_zigzag32(0UL) ==  0L, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag32(1UL) == -1L, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag32(2UL) ==  1L, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag32(3UL) == -2L, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag32(4UL) ==  2L, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag32(0xfffffffeUL) ==  0x7fffffffL, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag32(0xfffffffdUL) == -0x7fffffffL, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag32(2 * static_cast<uint32_t>(std::numeric_limits<int32_t>::max())    ) ==  std::numeric_limits<int32_t>::max(), "test constexpr zigzag functions");
+
+// fails on Visual Studio 2017
+//static_assert(protozero::decode_zigzag32(2 * static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) - 1) == -std::numeric_limits<int32_t>::max(), "test constexpr zigzag functions");
+
+static_assert(protozero::decode_zigzag64(0ULL) ==  0LL, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag64(1ULL) == -1LL, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag64(2ULL) ==  1LL, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag64(3ULL) == -2LL, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag64(4ULL) ==  2LL, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag64(0xfffffffffffffffeULL) ==  0x7fffffffffffffffLL, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag64(0xfffffffffffffffdULL) == -0x7fffffffffffffffLL, "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag64(2 * static_cast<uint64_t>(std::numeric_limits<int64_t>::max())    ) ==  std::numeric_limits<int64_t>::max(), "test constexpr zigzag functions");
+static_assert(protozero::decode_zigzag64(2 * static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) - 1) == -std::numeric_limits<int64_t>::max(), "test constexpr zigzag functions");
+
+inline constexpr int32_t zz32(int32_t val) noexcept {
+    return protozero::decode_zigzag32(protozero::encode_zigzag32(val));
+}
+
+inline constexpr int64_t zz64(int64_t val) noexcept {
+    return protozero::decode_zigzag64(protozero::encode_zigzag64(val));
+}
+
+TEST_CASE("zigzag encode some 32 bit values") {
+    REQUIRE(protozero::encode_zigzag32( 0L) == 0UL);
+    REQUIRE(protozero::encode_zigzag32(-1L) == 1UL);
+    REQUIRE(protozero::encode_zigzag32( 1L) == 2UL);
+    REQUIRE(protozero::encode_zigzag32(-2L) == 3UL);
+    REQUIRE(protozero::encode_zigzag32( 2L) == 4UL);
+    REQUIRE(protozero::encode_zigzag32( std::numeric_limits<int32_t>::max()) == 2 * static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
+    REQUIRE(protozero::encode_zigzag32(-std::numeric_limits<int32_t>::max()) == 2 * static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) - 1);
+}
+
+TEST_CASE("zigzag encode some 64 bit values") {
+    REQUIRE(protozero::encode_zigzag64( 0LL) == 0ULL);
+    REQUIRE(protozero::encode_zigzag64(-1LL) == 1ULL);
+    REQUIRE(protozero::encode_zigzag64( 1LL) == 2ULL);
+    REQUIRE(protozero::encode_zigzag64(-2LL) == 3ULL);
+    REQUIRE(protozero::encode_zigzag64( 2LL) == 4ULL);
+    REQUIRE(protozero::encode_zigzag64( std::numeric_limits<int64_t>::max()) == 2 * static_cast<uint64_t>(std::numeric_limits<int64_t>::max()));
+    REQUIRE(protozero::encode_zigzag64(-std::numeric_limits<int64_t>::max()) == 2 * static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) - 1);
+}
+
+TEST_CASE("zigzag and back - 32bit") {
+    REQUIRE(zz32( 0L) ==  0L);
+    REQUIRE(zz32( 1L) ==  1L);
+    REQUIRE(zz32(-1L) == -1L);
+    REQUIRE(zz32(std::numeric_limits<int32_t>::max()) == std::numeric_limits<int32_t>::max());
+    REQUIRE(zz32(std::numeric_limits<int32_t>::min()) == std::numeric_limits<int32_t>::min());
+}
+
+TEST_CASE("zigzag and back - 64bit") {
+    REQUIRE(zz64( 0LL) ==  0LL);
+    REQUIRE(zz64( 1LL) ==  1LL);
+    REQUIRE(zz64(-1LL) == -1LL);
+    REQUIRE(zz64(std::numeric_limits<int64_t>::max()) == std::numeric_limits<int64_t>::max());
+    REQUIRE(zz64(std::numeric_limits<int64_t>::min()) == std::numeric_limits<int64_t>::min());
+}
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/test/writer_tests.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/test/writer_tests.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/test/writer_tests.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,4 @@
+
+#define CATCH_CONFIG_MAIN
+#include <test.hpp> // IWYU pragma: keep
+

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/tools/CMakeLists.txt
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/tools/CMakeLists.txt	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/tools/CMakeLists.txt	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,51 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake config
+#
+#  protozero tools
+#
+#-----------------------------------------------------------------------------
+
+# Needs getopt, which is not available on Windows
+if(NOT MSVC)
+    add_executable(pbf-decoder pbf-decoder.cpp)
+
+    add_test(NAME pbf-decoder-no-args
+             COMMAND pbf-decoder)
+    set_tests_properties(pbf-decoder-no-args PROPERTIES
+                         PASS_REGULAR_EXPRESSION "^Usage:")
+
+    add_test(NAME pbf-decoder-help
+             COMMAND pbf-decoder --help)
+    set_tests_properties(pbf-decoder-help PROPERTIES
+                         PASS_REGULAR_EXPRESSION "^Usage:")
+
+    add_test(NAME pbf-decoder-empty
+             COMMAND pbf-decoder "${CMAKE_SOURCE_DIR}/test/t/message/data-opt-empty.pbf")
+    set_tests_properties(pbf-decoder-empty PROPERTIES
+                         PASS_REGULAR_EXPRESSION "^$")
+
+    add_test(NAME pbf-decoder-data
+             COMMAND pbf-decoder "${CMAKE_SOURCE_DIR}/test/t/message/data-message.pbf")
+    set_tests_properties(pbf-decoder-data PROPERTIES
+                         PASS_REGULAR_EXPRESSION "^1:")
+
+    add_test(NAME pbf-decoder-vt
+             COMMAND pbf-decoder -l 999999 -o 0 "${CMAKE_SOURCE_DIR}/test/t/vector_tile/data.vector.pbf")
+    set_tests_properties(pbf-decoder-vt PROPERTIES
+                         PASS_REGULAR_EXPRESSION "^3:")
+
+    add_test(NAME pbf-decoder-fail
+             COMMAND pbf-decoder -l 1 "${CMAKE_SOURCE_DIR}/test/t/vector_tile/data.vector.pbf")
+    set_tests_properties(pbf-decoder-fail PROPERTIES
+                         WILL_FAIL true)
+
+    add_test(NAME pbf-decoder-fail-msg
+             COMMAND pbf-decoder -l 1 "${CMAKE_SOURCE_DIR}/test/t/vector_tile/data.vector.pbf")
+    set_tests_properties(pbf-decoder-fail-msg PROPERTIES
+                         PASS_REGULAR_EXPRESSION "^end of buffer exception")
+
+endif()
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/protozero-1.6.7/tools/pbf-decoder.cpp
===================================================================
--- sandbox/jng/mvt/Oem/protozero-1.6.7/tools/pbf-decoder.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/protozero-1.6.7/tools/pbf-decoder.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,273 @@
+/*****************************************************************************
+
+Protobuf decoder tool
+
+Tool to decode unknown protocol buffer encoded messages. The protocol buffer
+format doesn't contain enough information about the contents of a file to make
+it decodable without the format description usually found in a `.proto` file,
+so this tool does some informed guessing.
+
+Usage:
+
+    pbf-decoder [OPTIONS] [FILENAME]
+
+Use "-" as a file name to read from STDIN.
+
+The output always goes to STDOUT.
+
+Call with --help/-h to see more options.
+
+*****************************************************************************/
+
+#include <protozero/pbf_reader.hpp>
+
+#include <algorithm>
+#include <cctype>
+#include <cstddef>
+#include <exception>
+#include <fstream>
+#include <getopt.h>
+#include <iostream>
+#include <limits>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+std::string decode(const char* data, std::size_t len, const std::string& indent);
+
+// Try decoding as a nested message
+bool decode_message(std::stringstream& out, const std::string& indent, const protozero::data_view view) {
+    try {
+        const auto nested = decode(view.data(), view.size(), indent + "  ");
+        out << '\n' << nested;
+        return true;
+    } catch (const protozero::exception&) {
+    }
+    return false;
+}
+
+// Try decoding as a string (only printable characters allowed).
+bool decode_printable_string(std::stringstream& out, const protozero::data_view view) {
+    static constexpr const std::size_t max_string_length = 60;
+
+    const std::string str{view.data(), view.size()};
+    if (str.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_:-") != std::string::npos) {
+        return false;
+    }
+
+    if (str.size() > max_string_length) {
+        out << '"' << str.substr(0, max_string_length) << "\"...\n";
+    } else {
+        out << '"' << str << '"' << '\n';
+    }
+    return true;
+}
+
+// Try decoding as a string.
+bool decode_string(std::stringstream& out, const protozero::data_view view) {
+    static constexpr const std::size_t max_string_length = 60;
+
+    std::string str{view.data(), std::min(view.size(), max_string_length)};
+    out << '"';
+
+    for (const auto c : str) {
+        if (std::isprint(c) != 0) {
+            out << c;
+        } else {
+            out << '.';
+        }
+    }
+
+    out << '"' << '\n';
+
+    return true;
+}
+
+// Print a list of numbers from a range
+template <typename TRange>
+void print_number_range(std::stringstream& out, const TRange& range) {
+    bool first = true;
+    for (auto val : range) {
+        if (first) {
+            first = false;
+        } else {
+            out << ',';
+        }
+        out << val;
+    }
+    out << '\n';
+}
+
+// Try decoding as packed repeated double
+bool decode_packed_double(std::stringstream& out, std::size_t size, protozero::pbf_reader& message) {
+    if (size % 8 != 0) {
+        return false;
+    }
+    try {
+        print_number_range(out, message.get_packed_double());
+        return true;
+    } catch (const protozero::exception&) {
+    }
+
+    return false;
+}
+
+// Try decoding as packed repeated float
+bool decode_packed_float(std::stringstream& out, std::size_t size, protozero::pbf_reader& message) {
+    if (size % 4 != 0) {
+        return false;
+    }
+    try {
+        print_number_range(out, message.get_packed_float());
+        return true;
+    } catch (const protozero::exception&) {
+    }
+
+    return false;
+}
+
+// Try decoding as packed repeated varint
+bool decode_packed_varint(std::stringstream& out, protozero::pbf_reader& message) {
+    try {
+        print_number_range(out, message.get_packed_int64());
+        return true;
+    } catch (const protozero::exception&) {
+    }
+
+    return false;
+}
+
+std::string decode(const char* data, std::size_t len, const std::string& indent) {
+    std::stringstream stream;
+    protozero::pbf_reader message{data, len};
+    while (message.next()) {
+        stream << indent << message.tag() << ": ";
+        switch (message.wire_type()) {
+            case protozero::pbf_wire_type::varint: {
+                // This is int32, int64, uint32, uint64, sint32, sint64, bool, or enum.
+                // Try decoding as int64.
+                stream << message.get_int64() << '\n';
+                break;
+            }
+            case protozero::pbf_wire_type::fixed64:
+                // This is fixed64, sfixed64, or double.
+                // Try decoding as a double, because int64_t or uint64_t
+                // would probably be encoded as varint.
+                stream << message.get_double() << '\n';
+                break;
+            case protozero::pbf_wire_type::length_delimited: {
+                // This is string, bytes, embedded messages, or packed repeated fields.
+                protozero::pbf_reader message_copy{message};
+                const auto view = message.get_view();
+
+                decode_message(stream, indent, view) ||
+                    decode_printable_string(stream, view) ||
+                    decode_packed_double(stream, view.size(), message_copy) ||
+                    decode_packed_float(stream, view.size(), message_copy) ||
+                    decode_packed_varint(stream, message_copy) ||
+                    decode_string(stream, view);
+                break;
+            }
+            case protozero::pbf_wire_type::fixed32:
+                // This is fixed32, sfixed32, or float.
+                // Try decoding as a float, because int32_t or uint32_t
+                // would probably be encoded as varint.
+                stream << message.get_float() << '\n';
+                break;
+            default:
+                throw protozero::unknown_pbf_wire_type_exception{};
+        }
+    }
+
+    return stream.str();
+}
+
+void print_help() {
+    std::cout << "Usage: pbf-decoder [OPTIONS] [INPUT_FILE]\n\n"
+              << "Dump raw contents of protobuf encoded file.\n"
+              << "To read from STDIN use '-' as INPUT_FILE.\n"
+              << "\nOptions:\n"
+              << "  -h, --help           This help message\n"
+              << "  -l, --length=LENGTH  Read only LENGTH bytes\n"
+              << "  -o, --offset=OFFSET  Start reading from OFFSET bytes\n";
+}
+
+std::string read_from_file(const char* filename) {
+    std::ifstream file{filename, std::ios::binary};
+    return std::string{std::istreambuf_iterator<char>(file.rdbuf()),
+                       std::istreambuf_iterator<char>()};
+}
+
+std::string read_from_stdin() {
+    return std::string{std::istreambuf_iterator<char>(std::cin.rdbuf()),
+                       std::istreambuf_iterator<char>()};
+}
+
+int main(int argc, char* argv[]) {
+    static struct option long_options[] = {
+        {"help",         no_argument, nullptr, 'h'},
+        {"length", required_argument, nullptr, 'l'},
+        {"offset", required_argument, nullptr, 'o'},
+        {nullptr, 0, nullptr, 0}
+    };
+
+    std::size_t offset = 0;
+    std::size_t length = std::numeric_limits<std::size_t>::max();
+
+    while (true) {
+        const int c = getopt_long(argc, argv, "hl:o:", long_options, nullptr);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'h':
+                print_help();
+                return 0;
+            case 'l':
+                length = std::atoll(optarg); // NOLINT(cert-err34-c)
+                                             // good enough for a limited-use tool
+                break;
+            case 'o':
+                offset = std::atoll(optarg); // NOLINT(cert-err34-c)
+                                             // good enough for a limited-use tool
+                break;
+            default:
+                return 1;
+        }
+    }
+
+    const int remaining_args = argc - optind;
+    if (remaining_args != 1) {
+        std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INPUT_FILE]\n\n"
+                  << "Call with --help/-h to see options.\n";
+        return 1;
+    }
+
+    const std::string filename{argv[optind]};
+
+    try {
+        std::string buffer{filename == "-" ? read_from_stdin() :
+                                             read_from_file(argv[optind])};
+
+        if (offset > buffer.size()) {
+            throw std::runtime_error{"offset is larger than file size"};
+        }
+
+        if (offset > 0) {
+            buffer.erase(0, offset);
+        }
+
+        if (length < buffer.size()) {
+            buffer.resize(length);
+        }
+
+        std::cout << decode(buffer.data(), buffer.size(), "");
+    } catch (const std::exception& ex) {
+        std::cerr << ex.what() << '\n';
+        return 1;
+    }
+
+    return 0;
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/.clang-tidy
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/.clang-tidy	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/.clang-tidy	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,48 @@
+---
+Checks: '*,-cert-dcl21-cpp,-cert-err60-cpp,-clang-analyzer-core.CallAndMessage,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-fuchsia-*,-google-runtime-references,-hicpp-no-array-decay,-readability-avoid-const-params-in-decls,-readability-implicit-bool-cast,-readability-implicit-bool-conversion'
+#
+#  Disabled checks:
+#
+#  cert-dcl21-cpp
+#    It is unclear whether this is still a good recommendation in modern C++.
+#
+#  cert-err60-cpp
+#    Reports std::runtime_error as broken which we can't do anything about.
+#
+#  clang-analyzer-core.CallAndMessage
+#    Produces false positives
+#
+#  cppcoreguidelines-owning-memory
+#    Don't want to add dependency on gsl library.
+#
+#  cppcoreguidelines-pro-bounds-array-to-pointer-decay
+#    Limited use and many false positives including for all asserts.
+#
+#  cppcoreguidelines-pro-bounds-pointer-arithmetic
+#    This is a low-level library, it needs to do pointer arithmetic.
+#
+#  fuchsia-*
+#    Much too strict.
+#
+#  google-runtime-references
+#    This is just a matter of preference, and we can't change the interfaces
+#    now anyways.
+#
+#  hicpp-no-array-decay
+#    Limited use and many false positives including for all asserts.
+#
+#  readability-avoid-const-params-in-decls
+#    Inconsistently complaines about some cases but not others. It is nice
+#    to have const in parameters if we don't change them just like with any
+#    other variables.
+#
+#  readability-implicit-bool-cast
+#    Old name for readability-implicit-bool-conversion.
+#
+#  readability-implicit-bool-conversion
+#    I don't think this makes the code more readable.
+#
+WarningsAsErrors: '*'
+HeaderFilterRegex: '\/include\/'
+AnalyzeTemporaryDtors: false
+...

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/.gitignore
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/.gitignore	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/.gitignore	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1 @@
+build

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/.gitmodules
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/.gitmodules	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/.gitmodules	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,3 @@
+[submodule "test/mvt-fixtures"]
+	path = test/mvt-fixtures
+	url = https://github.com/mapbox/mvt-fixtures.git

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/.travis.yml
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/.travis.yml	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/.travis.yml	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,178 @@
+#-----------------------------------------------------------------------------
+#
+#  Configuration for continuous integration service at travis-ci.org
+#
+#-----------------------------------------------------------------------------
+
+language: generic
+
+sudo: false
+
+dist: trusty
+
+#-----------------------------------------------------------------------------
+
+# Save common build configurations as shortcuts, so we can reference them later.
+addons_shortcuts:
+  addons_clang35: &clang35
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.5' ]
+      packages: [ 'libboost1.55-dev', 'clang-3.5' ]
+  addons_clang38: &clang38
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.8' ]
+      packages: [ 'libboost1.55-dev', 'clang-3.8' ]
+  addons_clang39: &clang39
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.9' ]
+      packages: [ 'libboost1.55-dev', 'clang-3.9' ]
+  addons_clang40: &clang40
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0' ]
+      packages: [ 'libboost1.55-dev', 'clang-4.0' ]
+  addons_clang50: &clang50
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0' ]
+      packages: [ 'libboost1.55-dev', 'clang-5.0', 'clang-tidy-5.0' ]
+  addons_clang60: &clang60
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0' ]
+      packages: [ 'libboost1.55-dev', 'clang-6.0', 'clang-tidy-6.0' ]
+  addons_gcc48: &gcc48
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libboost1.55-dev', 'g++-4.8', 'gcc-4.8' ]
+  addons_gcc49: &gcc49
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libboost1.55-dev', 'g++-4.9', 'gcc-4.9' ]
+  addons_gcc5: &gcc5
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libboost1.55-dev', 'g++-5', 'gcc-5' ]
+  addons_gcc6: &gcc6
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test' ]
+      packages: [ 'libboost1.55-dev', 'g++-6', 'gcc-6' ]
+
+#-----------------------------------------------------------------------------
+
+matrix:
+  include:
+    - os: linux
+      compiler: "clang-3.5"
+      env: BUILD='Debug' CC=clang-3.5 CXX=clang++-3.5
+      addons: *clang35
+    - os: linux
+      compiler: "clang-3.8"
+      env: BUILD='Debug' CC=clang-3.8 CXX=clang++-3.8
+      addons: *clang38
+    - os: linux
+      compiler: "clang-3.9"
+      env: BUILD='Debug' CC=clang-3.9 CXX=clang++-3.9
+      addons: *clang39
+    - os: linux
+      compiler: "clang-4.0"
+      env: BUILD='Debug' CC=clang-4.0 CXX=clang++-4.0
+      addons: *clang40
+    - os: linux
+      compiler: "clang-5.0"
+      env: BUILD='Debug' CC=clang-5.0 CXX=clang++-5.0
+           CLANG_TIDY=clang-tidy-5.0
+      addons: *clang50
+    - os: linux
+      compiler: "clang-5.0"
+      env: BUILD='Release' CC=clang-5.0 CXX=clang++-5.0
+      addons: *clang50
+    - os: linux
+      compiler: "clang-5.0"
+      env: BUILD='Debug' CC=clang-5.0 CXX=clang++-5.0
+           CXXFLAGS="-fsanitize=address,undefined,integer -fno-sanitize-recover=all -fno-omit-frame-pointer"
+           LDFLAGS="-fsanitize=address,undefined,integer"
+      # LSAN doesn't work on container-based system
+      sudo: required
+      addons: *clang50
+    - os: linux
+      compiler: "clang-6.0"
+      env: BUILD='Debug' CC=clang-6.0 CXX=clang++-6.0
+      addons: *clang60
+    - os: linux
+      compiler: "gcc-4.8"
+      env: BUILD='Debug' CC=gcc-4.8 CXX=g++-4.8
+      addons: *gcc48
+    - os: linux
+      compiler: "gcc-4.9"
+      env: BUILD='Debug' CC=gcc-4.9 CXX=g++-4.9
+           COVERAGE=gcov-4.9
+           CXXFLAGS="--coverage" LDFLAGS="--coverage"
+      addons: *gcc49
+    - os: linux
+      compiler: "gcc-5"
+      env: BUILD='Debug' CC=gcc-5 CXX=g++-5
+           CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0"
+      addons: *gcc5
+    - os: linux
+      compiler: "gcc-5"
+      env: BUILD='Debug' CC=gcc-5 CXX=g++-5
+           CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=1"
+      addons: *gcc5
+    - os: linux
+      compiler: "gcc-6"
+      env: BUILD='Debug' CC=gcc-6 CXX=g++-6
+      addons: *gcc6
+    - os: linux
+      compiler: "gcc-6"
+      env: BUILD='Debug' CC=gcc-6 CXX=g++-6
+           PROTOZERO_DATA_VIEW=std::experimental::string_view
+      addons: *gcc6
+    - os: linux
+      compiler: "gcc-6"
+      env: BUILD='Release' CC=gcc-6 CXX=g++-6
+      addons: *gcc6
+    - os: osx
+      osx_image: xcode6.4
+      compiler: clang
+      env: BUILD='Debug'
+    - os: osx
+      osx_image: xcode7.3
+      compiler: clang
+      env: BUILD='Debug'
+    - os: osx
+      osx_image: xcode8.3
+      compiler: clang
+      env: BUILD='Debug'
+    - os: osx
+      osx_image: xcode9.1
+      compiler: clang
+      env: BUILD='Debug'
+    - os: osx
+      osx_image: xcode9.1
+      compiler: clang
+      env: BUILD='Release'
+
+#-----------------------------------------------------------------------------
+
+install:
+  - git submodule update --init
+  - (cd ..; git clone --depth=1 https://github.com/mapbox/protozero)
+
+script:
+  - mkdir build
+  - cd build
+  - cmake .. -LA -DCMAKE_BUILD_TYPE=${BUILD} -DPROTOZERO_DATA_VIEW=$PROTOZERO_DATA_VIEW -DCLANG_TIDY=$(which ${CLANG_TIDY})
+  - make VERBOSE=1
+  - ctest --output-on-failure
+  - if [ -n "${CLANG_TIDY}" ]; then make clang-tidy; fi
+  - |
+    if [ -n "${COVERAGE}" ]; then
+      which ${COVERAGE}
+      curl -S -f https://codecov.io/bash -o codecov
+      chmod +x codecov
+      ${COVERAGE} -p $(find test -name 'test_*.o')
+      ./codecov -Z -c -X gcov -F unit_tests
+      ${COVERAGE} -p $(find test -name 'fixture_tests.cpp.o')
+      ./codecov -Z -c -X gcov -F fixture_tests
+    fi
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/.ycm_extra_conf.py
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/.ycm_extra_conf.py	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/.ycm_extra_conf.py	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,50 @@
+#-----------------------------------------------------------------------------
+#
+#  Configuration for YouCompleteMe Vim plugin
+#
+#  http://valloric.github.io/YouCompleteMe/
+#
+#-----------------------------------------------------------------------------
+
+from os.path import realpath, dirname
+
+basedir = dirname(realpath(__file__))
+
+# some default flags
+# for more information install clang-3.2-doc package and
+# check UsersManual.html
+flags = [
+'-Werror',
+'-Wall',
+'-Wextra',
+'-pedantic',
+'-Wno-return-type',
+'-Wno-unused-parameter',
+'-Wno-unused-variable',
+
+'-std=c++11',
+
+# '-x' and 'c++' also required
+# use 'c' for C projects
+'-x',
+'c++',
+
+# workaround for https://github.com/Valloric/YouCompleteMe/issues/303
+# also see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=800618
+'-isystem',
+'/usr/lib/ycmd/clang_includes/',
+
+'-I%s/../protozero/include' % basedir,
+'-I%s/include' % basedir,
+'-I%s/test/include' % basedir,
+'-I%s/test/catch' % basedir,
+]
+
+# youcompleteme is calling this function to get flags
+# You can also set database for flags. Check: JSONCompilationDatabase.html in
+# clang-3.2-doc package
+def FlagsForFile( filename ):
+  return {
+    'flags': flags,
+    'do_cache': True
+  }

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/CHANGELOG.md
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/CHANGELOG.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/CHANGELOG.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,72 @@
+
+# Changelog
+
+All notable changes to this project will be documented in this file.
+The format is based on [Keep a Changelog](https://keepachangelog.com/)
+This project adheres to [Semantic Versioning](https://semver.org/).
+
+## [unreleased] -
+
+### Added
+
+### Changed
+
+### Fixed
+
+
+## [1.0.3] - 2018-07-17
+
+### Added
+
+* New `copy_id()` helper function on feature builder copies ID (if it exists)
+  from an existing feature.
+* New `copy_properties()` helper funtion on feature builder copies all
+  properties from an existing feature, optionally using a `property_mapper`.
+* New `feature::for_each_property_indexes()` member function.
+
+### Fixed
+
+* The example program `vtzero-stats` now catches exceptions and exists with
+  an error message.
+* Fix an assert where a wrong iterator was checked.
+
+
+## [1.0.2] - 2018-06-26
+
+### Fixed
+
+* `layer_builder::add_feature()` did not work, because it didn't commit
+  the features it added.
+
+
+## [1.0.1] - 2018-04-12
+
+### Added
+
+* Some documentation and tests.
+
+### Changed
+
+* Catch exceptions in vtzero-streets example and output error message.
+* Adds a template parameter to the `create_property_map` function allowing
+  mapping between value types.
+
+### Fixed
+
+* The indexes returned by `feature::next_property_indexes()` are now
+  checked against the size of the key/value tables in the layer. If
+  an index is too large a `vtzero::out_of_range_exception` is returned.
+  This way the user code doesn't have to check this. The function
+  `feature::for_each_property()` now also uses these checks.
+
+
+## [1.0.0] - 2018-03-09
+
+First release
+
+
+[unreleased]: https://github.com/osmcode/libosmium/compare/v1.0.3...HEAD
+[1.0.3]: https://github.com/osmcode/libosmium/compare/v1.0.2...v1.0.3
+[1.0.2]: https://github.com/osmcode/libosmium/compare/v1.0.1...v1.0.2
+[1.0.1]: https://github.com/osmcode/libosmium/compare/v1.0.0...v1.0.1
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/CMakeLists.txt
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/CMakeLists.txt	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/CMakeLists.txt	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,157 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake config
+#
+#  vtzero
+#
+#-----------------------------------------------------------------------------
+
+cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+
+#-----------------------------------------------------------------------------
+
+project(vtzero)
+
+set(VTZERO_VERSION_MAJOR 1)
+set(VTZERO_VERSION_MINOR 0)
+set(VTZERO_VERSION_PATCH 3)
+
+set(VTZERO_VERSION
+    "${VTZERO_VERSION_MAJOR}.${VTZERO_VERSION_MINOR}.${VTZERO_VERSION_PATCH}")
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+#-----------------------------------------------------------------------------
+
+# This variable must be set to the directory where the mvt-fixtures from the
+# https://github.com/mapbox/mvt-fixtures repository are to be found. Usually
+# this is the directory where the submodule is checked out as described in
+# the README, but you can also set this to a different path, for instance
+# to change the setting while doing development.
+
+set(MVT_FIXTURES "${CMAKE_SOURCE_DIR}/test/mvt-fixtures" CACHE PATH "mvt-fixtures directory for tests")
+
+#-----------------------------------------------------------------------------
+
+option(WERROR "Add -Werror flag to build (turns warnings into errors)" ON)
+
+if(MSVC)
+    add_definitions(-std=c++11 /W3)
+    add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)
+else()
+    add_definitions(-std=c++11 -Wall -Wextra -pedantic -Wsign-compare -Wconversion)
+#    add_definitions(-Weverything -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-padded -Wno-documentation-unknown-command -Wno-exit-time-destructors)
+    if(WERROR)
+        add_definitions(-Werror)
+    endif()
+endif()
+
+include_directories("${CMAKE_SOURCE_DIR}/include")
+
+set(PROTOZERO_DATA_VIEW "" CACHE STRING "Type used for vtzero::data_view")
+if(NOT PROTOZERO_DATA_VIEW STREQUAL "")
+    add_definitions(-DPROTOZERO_DATA_VIEW=${PROTOZERO_DATA_VIEW})
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+#  Find dependencies
+#
+#-----------------------------------------------------------------------------
+
+find_package(Protozero 1.6.0 REQUIRED)
+
+include_directories(SYSTEM ${PROTOZERO_INCLUDE_DIR})
+
+find_package(Boost)
+
+
+#-----------------------------------------------------------------------------
+#
+#  Optional "clang-tidy" target
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for clang-tidy")
+find_program(CLANG_TIDY NAMES clang-tidy clang-tidy-6.0 clang-tidy-5.0)
+
+if(CLANG_TIDY)
+    message(STATUS "Looking for clang-tidy - found ${CLANG_TIDY}")
+    add_custom_target(clang-tidy
+        ${CLANG_TIDY}
+        -p ${CMAKE_BINARY_DIR}
+        ${CMAKE_SOURCE_DIR}/examples/*.cpp
+        ${CMAKE_SOURCE_DIR}/test/*.cpp
+        ${CMAKE_SOURCE_DIR}/test/t/*.cpp
+    )
+else()
+    message(STATUS "Looking for clang-tidy - not found")
+    message(STATUS "  Build target 'clang-tidy' will not be available.")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+#  Optional "cppcheck" target
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for cppcheck")
+find_program(CPPCHECK NAMES cppcheck)
+
+if(CPPCHECK)
+    message(STATUS "Looking for cppcheck - found")
+    add_custom_target(cppcheck
+        ${CPPCHECK}
+        -Uassert --std=c++11 --enable=all
+        ${CMAKE_SOURCE_DIR}/examples/*.cpp
+        ${CMAKE_SOURCE_DIR}/test/*.cpp
+        ${CMAKE_SOURCE_DIR}/test/t/*.cpp
+    )
+else()
+    message(STATUS "Looking for cppcheck - not found")
+    message(STATUS "  Build target 'cppcheck' will not be available.")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+#  Include what you use
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for iwyu")
+find_program(IWYU_TOOL NAMES iwyu_tool)
+
+if(IWYU_TOOL)
+    message(STATUS "Looking for iwyu - found")
+    add_custom_target(iwyu
+        ${IWYU_TOOL} -p ${CMAKE_BINARY_DIR}
+    )
+else()
+    message(STATUS "Looking for iwyu - not found")
+    message(STATUS "  Build target 'iwyu' will not be available.")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+#  Installation
+#
+#-----------------------------------------------------------------------------
+
+install(DIRECTORY include/vtzero DESTINATION include)
+
+
+#-----------------------------------------------------------------------------
+
+enable_testing()
+
+add_subdirectory(doc)
+
+add_subdirectory(examples)
+
+add_subdirectory(test)
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/CONTRIBUTING.md
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/CONTRIBUTING.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/CONTRIBUTING.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,25 @@
+# Contributing to vtzero
+
+## Releasing
+
+To release a new vtzero version:
+
+ - Make sure all tests are passing locally and on travis/appveyor
+ - Update version number in
+   - `CMakeLists.txt` (one place)
+   - `include/vtzero/version.hpp` (two places)
+ - Update CHANGELOG.md
+ - Update UPGRADING.md if necessary
+ - `git commit -m "Release X.Y.Z" include/vtzero/version.hpp CMakeLists.txt CHANGELOG.md UPGRADING.md`
+ - `git tag vX.Y.Z`
+ - `git push`
+ - `git push --tags`
+ - Go to https://github.com/mapbox/vtzero/releases
+   and edit the new release. Put "Version x.y.z" in title and
+   cut-and-paste entry from CHANGELOG.md.
+
+## Updating submodules
+
+Call `git submodule update --recursive --remote` to update to the newest
+version of the mvt fixtures used for testing.
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/EXTERNAL_LICENSES.txt
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/EXTERNAL_LICENSES.txt	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/EXTERNAL_LICENSES.txt	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,28 @@
+
+==== clara.hpp
+
+Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/LICENSE
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/LICENSE	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/LICENSE	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,25 @@
+BSD 2-Clause License
+
+Copyright (c) 2017, Mapbox
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+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 HOLDER 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.

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/README.md
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/README.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/README.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,93 @@
+# vtzero
+
+Tiny and fast vector tile decoder and encoder in C++.
+
+Implements the [Mapbox Vector Tile Specification 2.x](https://www.mapbox.com/vector-tiles/specification).
+
+[![Build Status](https://travis-ci.org/mapbox/vtzero.svg?branch=master)](https://travis-ci.org/mapbox/vtzero)
+[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/mapbox/vtzero?svg=true)](https://ci.appveyor.com/project/Mapbox/vtzero)
+[![Coverage Status](https://codecov.io/gh/mapbox/vtzero/branch/master/graph/badge.svg)](https://codecov.io/gh/mapbox/vtzero)
+
+
+## Depends
+
+* C++11 compiler (GCC 4.8 or higher, clang 3.5 or higher, ...)
+* CMake
+* [Protozero](https://github.com/mapbox/protozero) version >= 1.6.0
+
+
+## Build
+
+First clone `protozero`:
+
+```
+git clone git at github.com:mapbox/protozero.git
+```
+
+Then clone `vtzero` beside `protozero`. The `vtzero` build system will, among
+several places, look for `protozero` at `../protozero`. (If you would like to
+use `protozero` from a different path you can set `PROTOZERO_INCLUDE_DIR` in
+the CMake configuration step.)
+
+Then, inside the `vtzero` directory do:
+
+```
+git submodule update --init
+```
+
+Finally, to build the examples and tests do:
+
+```
+mkdir build
+cd build
+cmake ..
+make
+```
+
+Call `ctest` to run the tests.
+
+
+## Examples
+
+Several examples are provided to show usage of the library.
+
+Call
+
+    examples/vtzero-create
+
+to create test tile named `test.mvt`.
+
+Call
+
+    examples/vtzero-show TILE-FILE
+
+to show the contents of `TILE-FILE`.
+
+You can use
+
+    examples/vtzero-check TILE-FILE
+
+to check vector tile for validity.
+
+
+## Docs
+
+Extensive documentation is available:
+* [Tutorial](doc/tutorial.md) (start here)
+* [Reading vector tiles](doc/reading.md)
+* [Writing vector tiles](doc/writing.md)
+* [Advanced vtzero topics](doc/advanced.md)
+
+Make sure to read all of it before using vtzero. Vtzero isn't the simplest
+library to use, because it always chooses performance over ease of use.
+
+If [Doxygen](http://www.stack.nl/~dimitri/doxygen/) is installed on your
+system, the build process will automatically create the API docs for you.
+The results will be in your build directory under `doc/html`.
+
+
+## Authors
+
+Jochen Topf (jochen at topf.org),
+Dane Springmeyer (dane at mapbox.com)
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/appveyor.yml
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/appveyor.yml	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/appveyor.yml	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,61 @@
+#-----------------------------------------------------------------------------
+#
+#  Configuration for continuous integration service at appveyor.com
+#
+#-----------------------------------------------------------------------------
+
+platform: x64
+
+image: Visual Studio 2017
+
+clone_depth: 1
+
+#-----------------------------------------------------------------------------
+
+environment:
+  matrix:
+  - config: MSYS2
+    autocrlf: true
+  - config: Debug
+    autocrlf: true
+  - config: RelWithDebInfo
+    autocrlf: true
+  - config: Debug
+    autocrlf: false
+  - config: RelWithDebInfo
+    autocrlf: false
+
+#-----------------------------------------------------------------------------
+
+init:
+  - git config --global core.autocrlf %autocrlf%
+  - git config --get core.autocrlf
+
+# The option --ask=20 is a workaround for a problem with the MSYS2 update
+# process. Without it the following error is printed and the appveyor script
+# halts: "msys2-runtime and catgets are in conflict. Remove catgets?"
+# See also: https://github.com/Alexpux/MSYS2-packages/issues/1141
+install:
+  - cd c:\projects
+  - git clone --depth=1 https://github.com/mapbox/protozero
+  - if [%config%]==[MSYS2] (
+          C:\msys64\usr\bin\pacman --noconfirm --sync --refresh --refresh --sysupgrade --sysupgrade --ask=20
+       && C:\msys64\usr\bin\pacman -Rc --noconfirm mingw-w64-x86_64-gcc-libs
+    )
+
+build_script:
+  - cd c:\projects\vtzero
+  - git submodule update --init
+  - if [%config%]==[MSYS2] (
+        build-msys2.bat
+    ) else (
+        build-appveyor.bat
+    )
+
+# remove garbage VS messages
+# https://help.appveyor.com/discussions/problems/4569-the-target-_convertpdbfiles-listed-in-a-beforetargets-attribute-at-c-does-not-exist-in-the-project-and-will-be-ignored
+before_build:
+  - del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets"
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/build-appveyor.bat
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/build-appveyor.bat	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/build-appveyor.bat	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,58 @@
+ at ECHO OFF
+SETLOCAL
+SET EL=0
+
+ECHO ~~~~~~ %~f0 ~~~~~~
+
+::show all available env vars
+SET
+ECHO cmake on AppVeyor
+cmake -version
+
+ECHO activating VS cmd prompt && CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+IF EXIST build ECHO deleting build dir... && RD /Q /S build
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+MKDIR build
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+CD build
+ECHO config^: %config%
+
+::This will produce lots of LNK4099 warnings which can be ignored.
+::Unfortunately they can't be disabled, see
+::https://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings
+SET CMAKE_CMD=cmake .. ^
+-LA -G "Visual Studio 14 Win64"
+
+ECHO calling^: %CMAKE_CMD%
+%CMAKE_CMD%
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+SET avlogger=
+IF /I "%APPVEYOR%"=="True" SET avlogger=/logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
+
+msbuild vtzero.sln ^
+/p:Configuration=%config% ^
+/toolsversion:14.0 ^
+/p:Platform=x64 ^
+/p:PlatformToolset=v140 %avlogger%
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+ctest --output-on-failure ^
+-C %config% ^
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+GOTO DONE
+
+:ERROR
+ECHO ~~~~~~ ERROR %~f0 ~~~~~~
+SET EL=%ERRORLEVEL%
+
+:DONE
+IF %EL% NEQ 0 ECHO. && ECHO !!! ERRORLEVEL^: %EL% !!! && ECHO.
+ECHO ~~~~~~ DONE %~f0 ~~~~~~
+
+EXIT /b %EL%

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/build-msys2.bat
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/build-msys2.bat	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/build-msys2.bat	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,18 @@
+echo "Adding MSYS2 to path..."
+SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%"
+echo %PATH%
+
+echo "Installing MSYS2 packages..."
+bash -lc "pacman -S --needed --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-boost"
+
+echo "Generating makefiles"
+mkdir build
+cd build
+cmake .. -LA -G "MSYS Makefiles"
+
+echo "Building"
+make VERBOSE=1
+
+echo "Testing"
+ctest --output-on-failure
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/cmake/FindProtozero.cmake
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/cmake/FindProtozero.cmake	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/cmake/FindProtozero.cmake	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,63 @@
+#----------------------------------------------------------------------
+#
+#  FindProtozero.cmake
+#
+#  Find the protozero headers.
+#
+#----------------------------------------------------------------------
+#
+#  Usage:
+#
+#    Copy this file somewhere into your project directory, where cmake can
+#    find it. Usually this will be a directory called "cmake" which you can
+#    add to the CMake module search path with the following line in your
+#    CMakeLists.txt:
+#
+#      list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+#
+#    Then add the following in your CMakeLists.txt:
+#
+#      find_package(Protozero [version] [REQUIRED])
+#      include_directories(SYSTEM ${PROTOZERO_INCLUDE_DIR})
+#
+#    The version number is optional. If it is not set, any version of
+#    protozero will do.
+#
+#      if(NOT PROTOZERO_FOUND)
+#          message(WARNING "Protozero not found!\n")
+#      endif()
+#
+#----------------------------------------------------------------------
+#
+#  Variables:
+#
+#    PROTOZERO_FOUND        - True if Protozero was found.
+#    PROTOZERO_INCLUDE_DIR  - Where to find include files.
+#
+#----------------------------------------------------------------------
+
+# find include path
+find_path(PROTOZERO_INCLUDE_DIR protozero/version.hpp
+    PATH_SUFFIXES include
+    PATHS ../protozero
+)
+
+# Check version number
+if(Protozero_FIND_VERSION)
+    file(STRINGS "${PROTOZERO_INCLUDE_DIR}/protozero/version.hpp" _version_define REGEX "#define PROTOZERO_VERSION_STRING")
+    if("${_version_define}" MATCHES "#define PROTOZERO_VERSION_STRING \"([0-9.]+)\"")
+        set(_version "${CMAKE_MATCH_1}")
+    else()
+        set(_version "unknown")
+    endif()
+endif()
+
+#set(PROTOZERO_INCLUDE_DIRS "${PROTOZERO_INCLUDE_DIR}")
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Protozero
+                                  REQUIRED_VARS PROTOZERO_INCLUDE_DIR
+                                  VERSION_VAR _version)
+
+
+#----------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/codecov.yml
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/codecov.yml	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/codecov.yml	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,3 @@
+ignore:
+  - "bench"
+  - "test"
\ No newline at end of file

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/CMakeLists.txt
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/CMakeLists.txt	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/CMakeLists.txt	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,36 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake Config
+#
+#  vtzero documentation
+#
+#-----------------------------------------------------------------------------
+
+message(STATUS "Configuring documentation")
+
+message(STATUS "Looking for doxygen")
+find_package(Doxygen)
+
+if(DOXYGEN_FOUND)
+    message(STATUS "Looking for doxygen - found")
+    configure_file(Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+    file(GLOB HEADER_FILES "${CMAKE_SOURCE_DIR}/include/vtzero/*.hpp")
+    add_custom_command(OUTPUT html/index.html
+        COMMAND ${DOXYGEN_EXECUTABLE}
+        ARGS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+        DEPENDS Doxyfile.in advanced.md doc.md
+                ${HEADER_FILES}
+        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+        COMMENT "Generating API documentation with Doxygen" VERBATIM)
+    add_custom_target(doc ALL
+                      DEPENDS html/index.html)
+else()
+    message(STATUS "Looking for doxygen - not found")
+    message(STATUS "  Disabled making of documentation.")
+endif()
+
+#-----------------------------------------------------------------------------
+message(STATUS "Configuring documentation - done")
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/Doxyfile.in
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/Doxyfile.in	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/Doxyfile.in	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,2353 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "vtzero"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = @VTZERO_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "Tiny and fast vector tile decoder and encoder in C++."
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = "@PROJECT_BINARY_DIR@/doc"
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        = @PROJECT_SOURCE_DIR@
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = @PROJECT_SOURCE_DIR@/include/vtzero \
+                         @PROJECT_SOURCE_DIR@/doc/doc.md
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        = vtzero::detail vtzero_assert
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = @PROJECT_SOURCE_DIR@/doc/doc.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH      =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/advanced.md
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/advanced.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/advanced.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,112 @@
+
+# Advanced vtzero topics
+
+## Differences between the protocol buffer specification and the vtzero implementation
+
+The [protobuf specification
+says](https://developers.google.com/protocol-buffers/docs/encoding#optional)
+that a decoder library must handle repeated *non-packed* fields if repeated
+*packed* fields are expected and it must handle multiple repeated packed fields
+as if the items are concatenated. Encoders should never encode fields in this
+way, though, so it is very unlikely that this would ever happen. For
+performance reasons vtzero doesn't handle this case.
+
+## Differences between the vector tile specification and the vtzero implementation
+
+The [vector tile specification](https://github.com/mapbox/vector-tile-spec/blob/master/2.1/README.md#41-layers)
+clearly says that you can not have two layers with the same
+name in a vector tile. For performance reasons this is neither checked on
+reading nor on writing.
+
+## The `create_vtzero_point` customization point
+
+The vtzero builder classes have several functions which take a `vtzero::point`
+as argument. But chances are that you are using a different point type in your
+code. That's why these functions have overloads taking any type `TPoint` that
+can be converted to a `vtzero::point`. This conversion is done by calling the
+function `create_vtzero_point()`. Vtzero supplies a version of this function
+which will work with any type with members `x` and `y`:
+
+```cpp
+template <typename TPoint>
+vtzero::point create_vtzero_point(TPoint p) noexcept {
+    return {p.x, p.y};
+}
+```
+
+You can define your own overload of that function taking your own point type
+as parameter and returning a `vtzero::point`. Vtzero will find your function
+using [ADL](http://en.cppreference.com/w/cpp/language/adl) which magically
+makes the vtzero builders work with your point type.
+
+## Using the `property_mapper` class when copying layers
+
+Sometimes you want to copy some features of a layer into a new layer. Because
+you only copy some features (and/or only some properties of the features), the
+key and value tables in the layer have to be rebuilt. This is where the
+`property_mapper` class helps you. It keeps the mapping between the index
+values of the old and the new table adding property keys and values as needed
+to the new table.
+
+Here is some code that shows you how to use it:
+
+```cpp
+#include <vtzero/property_mapper.hpp> // you have to include this
+
+vtzero::layer layer = ...; // layer you got from an existing tile
+vtzero::layer_builder layer_builder{...}; // create new layer
+
+// instantiate the property mapper with the old and new layers
+vtzero::property_mapper mapper{layer, layer_builder};
+
+// you'll probably want to iterate over all features in the old layer...
+while (auto feature = layer.next_feature()) {
+    // ... and decide somehow which ones you want to keep
+    if (keep_feature(feature)) {
+        // instantiate a feature builder as usual and copy id and geometry
+        vtzero::geometry_feature_builder feature_builder{layer_builder};
+        feature_builder.copy_id(feature);
+        feature_builder.set_geometry(feature.geometry());
+
+        // now iterate over all properties...
+        while (auto idxs = feature.next_property_indexes()) {
+            // ... decide which ones to keep,
+            if (keep_property(idxs)) {
+                // ... and add them to the new layer using the mapper
+                feature_builder.add_property(mapper(idxs));
+            }
+        }
+    }
+}
+```
+
+## Protection against huge memory use
+
+When decoding a vector tile we got from an unknown source, we don't know what
+surprises it might contain. Building data structures based on the vector tile
+sometimes means we have to allocate memory and in the worst case this might be
+quite a lot of memory. Vtzero usually doesn't allocate any memory when decoding
+a tile, except when reading properties, when there is space for lookup tables
+allocated. The memory use for these lookup tables is `sizeof(data_view)` times
+the number of entries in the key/value table. In the worst case, when a vector
+tile basically only contains such a table, memory use is proportional to the
+size of the vector tile. But memory use can be an order of magnitude larger
+than the tile size! If you are concerned about memory use, limit the size
+of the vector tiles you give to vtzero.
+
+When reading geometries from vector tiles, vtzero doesn't need much memory
+itself, but the users of vtzero might. In a typical case you might reserve
+enough memory to store, say, a linestring, and then fill that memory. To allow
+you to do this, vtzero tells you about the number of points in the linestring.
+This number comes from the tile and it might be rather large. Vtzero does a
+consistency check comparing the number of points the geometry says it has with
+the number of bytes used for the geometry and it will throw an exception if the
+numbers can't fit. So you are protected against tiny tiles pretending to
+contain a huge geometry. But there still could be a medium-sized tile which
+gets "blown up" into a huge memory hog. Your representation of a linestring
+can be an order of magnitude larger than the minimum 2 bytes per point
+needed in the encoded tile.
+
+So again: If you are concerned about memory use, limit the size of the vector
+tiles you give to vtzero.
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/doc.md
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/doc.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/doc.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,13 @@
+
+Tiny and fast vector tile decoder and encoder in C++.
+
+This is the API documentation that was automatically created from the
+source code. For more information about vtzero go to
+https://github.com/mapbox/vtzero .
+
+Vtzero is a header-only library. You do not need to compile and link it,
+just include the headers you need.
+
+Everything in namespaces called "detail" is for internal vtzero use only,
+do not depend on it in your code.
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/reading.md
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/reading.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/reading.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,459 @@
+
+# Reading vector tiles
+
+To access the contents of vector tiles with vtzero create a `vector_tile`
+object first with the data of the tile as first argument:
+
+```cpp
+#include <vtzero/vector_tile.hpp> // always needed when reading vector tiles
+
+std::string vt_data = ...;
+vtzero::vector_tile tile{vt_data};
+```
+
+Instead of a string, you can also initialize the `vector_tile` using a
+`vtzero::data_view`. This class contains only a pointer and size referencing
+some data similar to the C++17 `std::string_view` class. It is typedef'd from
+the `protozero::data_view`. See [the protozero
+doc](https://github.com/mapbox/protozero/blob/master/doc/advanced.md#protozero_use_view)
+for more details.
+
+```cpp
+vtzero::data_view vt_data = ...;
+vtzero::vector_tile tile{vt_data};
+```
+
+In both cases the `vector_tile` object contains references to the original
+tile data. You have to make sure this data stays available through the whole
+lifetime of the `vector_tile` object and all the other objects we'll create
+in this tutorial for accessing parts of the vector tile. The data is **not**
+copied by vtzero when accessing vector tiles.
+
+You can think of the `vector_tile` class as a "proxy" class giving you access
+to the decoded data, similarly the classes `layer`, `feature`, and
+`property` described in the next chapters are "proxy" classes, too.
+
+## Accessing layers
+
+Vector tiles consist of a list of layers. The list of layers can be empty
+in which case `tile.empty()` will return true.
+
+The simplest and fasted way to access the layers is through the `next_layer()`
+function:
+
+```cpp
+while (auto layer = tile.next_layer()) {
+    ...
+}
+```
+
+Note that this creates new layer objects on the fly referencing the layer you
+are currently looking at. Once you have iterated over all the layers,
+`next_layer()` will return the "invalid" (default constructed) layer object
+which converts to false in an boolean context.
+
+You can reset the layer iterator to the beginning again if you need to go
+over the layers again:
+
+```cpp
+tile.reset_layer();
+```
+
+Instead of using this external iterator, you can use a different function with
+an internal iterator that calls a function defined by you for each layer. Your
+function must take a `layer&&` as parameter and return `true` if the iteration
+should continue and `false` otherwise:
+
+```cpp
+tile.for_each_layer([&](layer&& l) {
+    // do something with layer
+    return true;
+});
+```
+
+Both the external and internal iteration do basically the same and have the
+same performance characteristics.
+
+You can also access layers through their index or name:
+
+```cpp
+tile.get_layer(3);
+```
+
+will give you the 4th layer in the tile. With
+
+```cpp
+tile.get_layer_by_name("foobar");
+```
+
+you'll get the layer with the specified name. Both will return the invalid
+layer if that layer doesn't exist.
+
+Note that accessing layers by index or name is less efficient than iterating
+over them using `next_layer()` if you are accessing several layers. So usually
+you should only use those function if you want to access one specific layer
+only.
+
+If you need the number of layers, you can call `tile.count_layers()`. This
+function still has to iterate over the layers internally decoding some of the
+data, so it is not cheap.
+
+## The layer
+
+Once you have a layer as described in the previous chapter you can access the
+metadata of this layer easily:
+
+* The version is available with `layer.version()`. Only version 1 and 2 are
+  currently supported by this library.
+* The extent of the tile is available through `layer.extent()`. This is usually
+  4096.
+* The function `layer.name()` returns the name of the layer as `data_view`.
+  This does **not** include a final 0-byte!
+* The number of features is returned by the `layer.num_features()` function.
+  If it doesn't contain any features `layer.empty()` will return true.
+  (Different then the `vector_tile::count_layers()`, the `layer::num_features()`
+  function is `O(1)`).
+
+To access the features call the `next_feature()` function until it returns
+the invalid (default constructed) feature:
+
+```cpp
+while (auto feature = layer.next_feature()) {
+    ...
+}
+```
+
+Use `reset_feature()` to restart the feature iterator from the beginning.
+
+Instead of using this external iterator, you can use a different function with
+an internal iterator that calls a function defined by you for each feature.
+Your function must take a `feature&&` as parameter and return `true` if the
+iteration should continue and `false` otherwise:
+
+```cpp
+layer.for_each_feature([&](feature&& f) {
+    // do something with the feature
+    return true;
+});
+```
+
+Both the external and internal iteration do basically the same and have the
+same performance characteristics.
+
+If you know the ID of a feature you can get the feature using
+`get_feature_by_id()`, but note that this will do a linear search through
+all the features in the layer, decoding each one until it finds the right ID.
+This is almost always **not** what you want.
+
+Note that the feature returned by `next_feature()` or `get_feature_by_id()`
+will internally contain a pointer to the layer it came from. The layer has to
+stay valid as long as the feature is used.
+
+## The feature
+
+You get features from the layer as described in the previous chapter. The
+`feature` class gives you access to the ID, the geometry and the properties
+of the feature. Access the ID using the `id()` method which will return 0
+if no ID is set. You can ask for the existence of the ID using `has_id()`:
+
+```cpp
+auto feature = layer...;
+if (feature.has_id()) {
+    cout << feature.id() << '\n';
+}
+```
+
+The `geometry()` method returns an object of the `geometry` class. It contains
+the geometry type and a reference to the (un-decoded) geometry data. See a
+later chapter on the details of decoding this geometry. You can also directly
+add this geometry to a new feature you are writing.
+
+The number of properties in the feature is returned by the
+`feature::num_properties()` function. If the feature doesn't contain any
+properties `feature.empty()` will return true. (Different then the
+`vector_tile::count_layers()`, the `feature::num_properties()` function is
+`O(1)`).
+
+To access the properties call the `next_property()` function until it returns
+the invalid (default constructed) property:
+
+```cpp
+while (auto property = feature.next_property()) {
+    ...
+}
+```
+
+Use `reset_property()` to restart the property iterator from the beginning.
+
+Instead of using this external iterator, you can use a different function with
+an internal iterator that calls a function defined by you for each property.
+Your function must take a `property&&` as parameter and return `true` if the
+iteration should continue and `false` otherwise:
+
+```cpp
+feature.for_each_property([&](property&& p) {
+    ...
+    return true;
+});
+```
+
+Both the external and internal iteration do basically the same and have the
+same performance characteristics.
+
+## The property
+
+Each property you get from the feature is an object of the `property` class. It
+contains a view of the property key and value. The key is always a string
+encoded in a `vtzero::data_view`, the value can be of different types but is
+always encapsulated in a `property_value` type, a variant type that can be
+converted into whatever type the value really has.
+
+```cpp
+auto property = ...;
+std::string pkey = property.key(); // returns a vtzero::data_view which can
+                                   // be converted to std::string
+property_value pvalue = property.value();
+```
+
+To get the type of the property value, call `type()`:
+
+```cpp
+const auto type = pvalue.type();
+```
+
+If the property value is an int, for instance, you can get it like this:
+
+```cpp
+if (pvalue.type() == property_value_type::int_value)
+    int64_t v = pvalue.int_value();
+}
+```
+
+Instead of accessing the values this way, you'll often use the visitor
+interface. Here is an example where the `print_visitor` struct is used to print
+out the values. In this case one overload is used for all primitive types
+(`double`, `float`, `int`, `uint`, `bool`), one overload is used for the `string_value`
+type which is encoded in a `data_view`. You must make sure your visitor handles
+all those types.
+
+```cpp
+struct print_visitor {
+
+    template <typename T>
+    void operator()(T value) {
+        std::cout << value;
+    }
+
+    void operator()(vtzero::data_view value) {
+        std::cout << std::string(value);
+    }
+
+};
+
+vtzero::apply_visitor(print_visitor{}, pvalue));
+```
+
+All call operators of your visitor class have to return the same type. In the
+case above this was `void`, but it can be something else. That return type
+will be the return type of the `apply_visitor` function. This can be used,
+for instance, to convert the values into one type:
+
+```cpp
+struct to_string_visitor {
+
+    template <typename T>
+    std::string operator()(T value) {
+        reutrn std::to_string(value);
+    }
+
+    std::string operator()(vtzero::data_view value) {
+        return std::string(value);
+    }
+
+};
+
+std::string v = vtzero::apply_visitor(to_string_visitor{}, pvalue);
+```
+
+Sometimes you want to convert the `property_value` type into your own variant
+type. You can use the `vtzero::convert_property_value()` free function for
+this.
+
+Lets say you are using `boost` and this is your variant:
+
+```cpp
+using variant_type = boost::variant<std::string, float, double, int64_t, uint64_t, bool>;
+```
+
+You can then use the following line to convert the data:
+```cpp
+variant_type v = vtzero::convert_property_value<variant_type>(pvalue);
+```
+
+Your variant type must be constructible from all the types `std::string`,
+`float`, `double`, `int64_t`, `uint64_t`, and `bool`. If it is not, you can
+define a mapping between those types and the types you use in your variant
+class.
+
+```cpp
+using variant_type = boost::variant<mystring, double, int64_t, uint64_t, bool>;
+
+struct mapping : vtzero::property_value_mapping {
+    using string_type = mystring; // use your own string type which must be
+                                  // convertible from data_view
+    using float_type = double; // no float in variant, so convert to double
+};
+
+variant_type v = vtzero::convert_property_value<variant_type, mapping>(pvalue);
+```
+
+## Creating a properties map
+
+This linear access to the properties with lazy decoding of each property only
+when it is accessed saves memory allocations, especially if you are only
+interested in very few properties. But sometimes it is easier to create a
+mapping (based on `std::unordered_map` for instance) between keys and values. This is where
+the `vtzero::create_properties_map()` templated free function comes in. It
+needs the map type as template parameter:
+
+```cpp
+using key_type = std::string; // must be something that can be converted from data_view
+using value_type = boost::variant<std::string, float, double, int64_t, uint64_t, bool>;
+using map_type = std::map<key_type, value_type>;
+
+auto feature = ...;
+auto map = create_properties_map<map_type>(feature);
+```
+
+Both `std::map` and `std::unordered_map` are supported as map type, but this
+should also work with any other map type that has an `emplace()` method.
+
+## Geometries
+
+Features must contain a geometry of type UNKNOWN, POINT, LINESTRING, or
+POLYGON. The UNKNOWN type is not further specified by the vector tile spec,
+this library doesn't allow you to do anything with this type. Note that
+multipoint, multilinestring, and multipolygon geometries are also possible,
+they don't have special types.
+
+You can get the geometry type with `feature.geometry_type()`, but usually
+you'll get the geometry with `feature.geometry()`. This will return an object
+of type `vtzero::geometry` which contains the geometry type and a view of
+the raw geometry data. To decode the data you have to call one of the decoder
+free functions `decode_geometry()`, `decode_point_geometry()`,
+`decode_linestring_geometry()`, or `decode_polygon_geometry()`. The first of
+these functions can decode any point, linestring, or polygon geometry. The
+others must be called with a geometry of the specified type and will only
+decode that type.
+
+For all the decoder functions the first parameter is the geometry (as returned
+by `feature.geometry()`), the second parameter is a *handler* object that you
+must implement. The decoder function will call certain callbacks on this object
+that give you part of the geometry data which allows you to use this data in
+any way you like.
+
+The handler for `decode_point_geometry()` must implement the following
+functions:
+
+* `void points_begin(uint32_t count)`: This is called once at the beginning
+  with the number of points. For a point geometry, this will be 1, for
+  multipoint geometries this will be larger.
+* `void points_point(vtzero::point point)`: This is called once for each
+  point.
+* `void points_end()`: This is called once at the end.
+
+The handler for `decode_linestring_geometry()` must implement the following
+functions:
+
+* `void linestring_begin(uint32_t count)`: This is called at the beginning
+  of each linestring with the number of points in this linestring. For a simple
+  linestring this function will only be called once, for a multilinestring
+  it will be called several times.
+* `void linestring_point(vtzero::point point)`: This is called once for each
+  point.
+* `void linestring_end()`: This is called at the end of each linestring.
+
+The handler for `decode_polygon_geometry` must implement the following
+functions:
+
+* `void ring_begin(uint32_t count)`: This is called at the beginning
+  of each ring with the number of points in this ring. For a simple polygon
+  with only one outer ring, this function will only be called once, if there
+  are inner rings or if this is a multipolygon, it will be called several
+  times.
+* `void ring_point(vtzero::point point)`: This is called once for each
+  point.
+* `void ring_end(vtzero::ring_type)`: This is called at the end of each ring.
+  The parameter tells you whether the ring is an outer or inner ring or whether
+  the ring was invalid (if the area is 0).
+
+The handler for `decode_geometry()` must implement all of the functions
+mentioned above for the different types. It is guaranteed that only one
+set of functions will be called depending on the geometry type.
+
+If your handler implements the `result()` method, the decode functions will
+have the return type of the `result()` method and will return whatever
+result returns. If the `result()` method is not available, the decode functions
+return void.
+
+Here is a typical implementation of a linestring handler:
+
+```cpp
+struct linestring_handler {
+
+    using linestring = std::vector<my_point_type>;
+
+    linestring points;
+
+    void linestring_begin(uint32_t count) {
+        points.reserve(count);
+    }
+
+    void linestring_point(vtzero::point point) noexcept {
+        points.push_back(convert_to_my_point(point));
+    }
+
+    void linestring_end() const noexcept {
+    }
+
+    linestring result() {
+        return std::move(points);
+    }
+
+};
+```
+
+Note that the `count` given to the `linestring_begin()` method is used here to
+reserve memory. This is potentially problematic if the count is large. Please
+keep this in mind.
+
+## Accessing the key/value lookup tables in a layer
+
+Vector tile layers contain two tables with all the property keys and all
+property values used in the features in that layer. Vtzero usually handles
+those table lookups internally without you noticing. But sometimes it might
+be necessary to access this data directly.
+
+From the layer object you can get references to the tables:
+
+```cpp
+vtzero::layer layer = ...;
+const auto& kt = layer.key_table();
+const auto& vt = layer.value_table();
+```
+
+Instead you can also lookup keys and values using methods on the layer object:
+```cpp
+vtzero::layer layer = ...;
+const vtzero::data_view k = layer.key(17);
+const vtzero::property_value_view v = layer.value(42);
+```
+
+As usual in vtzero you only get views back, so you need to keep the layer
+object around as long as you are accessing the results of those methods.
+
+Note that the lookup tables are created on first access from the layer data. As
+long as you are not accessing those tables directly or by looking up any
+properties in a feature, the tables are not created and no extra memory is
+used.
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/tutorial.md
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/tutorial.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/tutorial.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,94 @@
+
+# Vtzero Tutorial
+
+The vtzero header-only library is used to read and write vector tile data
+as specified in the [Mapbox Vector Tile
+Specification](https://github.com/mapbox/vector-tile-spec). This document
+assumes that you are familiar with that specification.
+
+## Overview
+
+The library has basically two parts: The part concerned with decoding existing
+vector tiles and the part concerned with creating new vector tiles. You can
+use either one without knowing much about the other side, but it is, of course
+also possible to read parts of a vector tile and stick it into a new one.
+
+Vtzero is trying to do as little work as possible while still giving you a
+reasonably easy to use interface. This means that it will, as much as feasible,
+decode the different parts of a vector tile only when you ask for them. Most
+importantly it will try to avoid memory allocation and it will not copy data
+around unnecessarily but work with references instead.
+
+On the writing side it means that you have to call the API in a specific order
+when adding more data to a vector tile. This allows vtzero to avoid multiple
+copies of the data.
+
+## Basic types
+
+Vtzero contains several basic small (value) types such as `GeomType`,
+`property_value_type`, `index_value`, `index_value_pair`, and `point` which
+hold basic values in a type-safe way. Most of them are defined in `types.hpp`
+(`point` is in `geometry.hpp`).
+
+Sometimes it is useful to be able to print the values of those types, for
+instance when debugging. For this overloads of `operator<<` on `basic_ostream`
+are available in `vtzero/output.hpp`. Include this file and you can use the
+usual `std::cout << some_value;` to print those values.
+
+## Use of asserts and exceptions
+
+The vtzero library uses a lot of asserts to help you use it correctly. It is
+recommended you use debug builds while developing your code, because you'll
+get asserts from vtzero telling you when you use it in a wrong way. This is
+especially important when writing tiles using the builder classes, because
+their methods have to be called in a certain order that might not always be
+obvious but is checked by the asserts.
+
+Exceptions, on the other hand, are used when errors occur during the normal run
+of vtzero. This is especially important on the reading side when vtzero makes
+every effort to handle any kind of input, even if the input data is corrupt
+in some way. (Vtzero can't detect all problems though, your code still has to
+do its own checking, see the [advanced topics](advanced.md) for some more
+information.)
+
+Many vtzero functions can throw exceptions. Most of them fall into these
+categories:
+
+* If the underlying protocol buffers data has some kind of problem, you'll
+  get an exception from the [protozero
+  library](https://github.com/mapbox/protozero/blob/master/doc/tutorial.md#asserts-and-exceptions-in-the-protozero-library).
+  They are all derived from `protozero::exception`.
+* If the protocol buffers data is okay, but the vector tile data is invalid
+  in some way, you'll get an exception from the vtzero library.
+* If any memory allocation failed, you'll get a `std::bad_alloc` exception.
+
+All the exceptions thrown directly by the vtzero library are derived from
+`vtzero::exception`. These exceptions are:
+
+* A `format_exception` is thrown when vector tile encoding isn't valid
+  according to the vector tile specification.
+* A `geometry_exception` is thrown when a geometry encoding isn't valid
+  according to the vector tile specification.
+* A `type_exception` is thrown when a property value is accessed using the
+  wrong type.
+* A `version_exception` is thrown when an unknown version number is found in
+  the layer. Currently vtzero only supports version 1 and 2.
+* An `out_of_range_exception` is thrown when an index into the key or value
+  table in a layer is out of range. This can only happen if the tile data is
+  invalid.
+
+## Include files
+
+Usually you only directly include the following files:
+
+* When reading: `<vtzero/vector_tile.hpp>`
+* When writing: `<vtzero/builder.hpp>`
+* If you need any of the special indexes: `<vtzero/index.hpp>`
+* If you want overloads of `operator<<` for basic types: `<vtzero/output.hpp>`
+* If you need the version: `<vtzero/version.hpp>`
+
+## Reading and writing vector tiles
+
+* [Reading vector tiles](reading.md)
+* [Writing vector tiles](writing.md)
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/writing.md
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/writing.md	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/doc/writing.md	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,539 @@
+
+# Writing vector tiles
+
+Writing vector tiles start with creating a `tile_builder`. This builder will
+then be used to add layers and features in those layers. Once all this is done,
+you call `serialize()` to actually build the vector tile from the data you
+provided to the builders:
+
+```cpp
+#include <vtzero/builder.hpp> // always needed when writing vector tiles
+
+vtzero::tile_builder tbuilder;
+// add lots of data to builder...
+std::string buffer = tbuilder.serialize();
+```
+
+You can also serialize the data into an existing buffer instead:
+
+```cpp
+std::string buffer; // got buffer from somewhere
+tbuilder.serialize(buffer);
+```
+
+## Adding layers to tiles
+
+Once you have a tile builder, you'll first need some layers:
+
+```cpp
+vtzero::tile_builder tbuilder;
+vtzero::layer_builder layer_pois{tbuilder, "pois", 2, 4096};
+vtzero::layer_builder layer_roads{tbuilder, "roads"};
+vtzero::layer_builder layer_forests{tbuilder, "forests"};
+```
+
+Here three layers called "pois", "roads", and "forests" are added. The first
+one explicitly specifies the vector tile version used and the extent. The
+values specified here are the default, so all layers in this example will have
+a version of 2 and an extent of 4096.
+
+If you have read a layer from an existing vector tile and want to copy over
+some of the data, you can use this layer to initialize the new layer in the
+new vector tile with the name, version and extent from the existing layer like
+this:
+
+```cpp
+vtzero::layer some_layer = ...;
+vtzero::layer_builder layer_pois{tbuilder, some_layer};
+// same as...
+vtzero::layer_builder layer_pois{tbuilder, some_layer.name(),
+                                           some_layer.version(),
+                                           some_layer.extent()};
+```
+
+If you want to copy over an existing layer completely, you can use the
+`add_existing_layer()` function instead:
+
+```cpp
+vtzero::layer some_layer = ...;
+vtzero::tile_builder tbuilder;
+tbuilder.add_existing_layer(some_layer);
+```
+
+Or, if you have the encoded layer data available in a `data_view` this also
+works:
+
+```cpp
+vtzero::data_view layer_data = ...;
+vtzero::tile_builder tbuilder;
+tbuilder.add_existing_layer(layer_data);
+```
+
+Note that this call will only store a reference to the data to be added in the
+tile builder. The data will only be copied when the final `serialize()` is
+called, so the input data must still be available then!
+
+You can mix any of the ways of adding a layer to the tile mentioned above. The
+layers will be added to the tile in the order you add them to the
+`tile_builder`.
+
+The tile builder is smart enough to not add empty layers, so you can start
+out with all the layers you might need and if some of them stay empty, they
+will not be added to the tile when `serialize()` is called.
+
+## Adding features to layers
+
+Once we have one or more `layer_builder`s instantiated, we can add features
+to them. This is done through the following feature builder classes:
+
+* `point_feature_builder` to add a feature with a (multi)point geometry,
+* `linestring_feature_builder` to add a feature with a (multi)linestring
+  geometry,
+* `polygon_feature_builder` to add a feature with a (multi)polygon geometry, or
+* `geometry_feature_builder` to add a feature with an existing geometry you
+  got from reading a vector tile.
+
+In all cases you need to instantiate the feature builder class, optionally
+add the feature ID using the `set_id()` method, add the geometry and then
+add all the properties of this feature. You have to keep to this order!
+
+```cpp
+...
+vtzero::layer_builder lbuilder{...};
+{
+    vtzero::point_feature_builder fbuilder{lbuilder};
+    // optionally set the ID
+    fbuilder.set_id(23);
+    // add the geometry (exact calls are different for different feature builders)
+    fbuilder.add_point(99, 33);
+    // add the properties
+    fbuilder.add_property("amenity", "restaurant");
+    // call commit() when you are done
+    fbuilder.commit()
+}
+```
+
+You have to call `commit()` on the feature builder object after you set all the
+data to actually add it to the layer. If you don't do this, the feature will
+not be added to the layer! This can be useful, for instance, if you detect that
+you have an invalid geometry while you are adding the geometry to the feature
+builder. In that case you can call `rollback()` explicitly or just let the
+feature builder go out of scope and it will do the rollback automatically.
+
+Only the first call to `commit()` or `rollback()` will take effect, any further
+calls to these functions on the same feature builder object are ignored.
+
+## Adding a geometry to the feature
+
+There are different ways of adding the geometry to the feature, depending on
+the geometry type.
+
+### Adding a point geometry
+
+Simply call `add_point()` to set the point geometry. There are three different
+overloads for this function. One takes a `vtzero::point`, one takes two
+`uint32_t`s with the x and y coordinates and one takes any type `T` that can
+be converted to a `vtzero::point` using the `create_vtzero_point` function.
+This templated function works on any type that has `x` and `y` members and
+you can create your own overload of this function. See the
+[advanced.md](advanced topics documentation).
+
+### Adding a multipoint geometry
+
+Call `add_points()` with the number of points in the geometry as the only argument.
+After that call `set_point()` for each of those points. `set_point()` has
+multiple overloads just like the `add_point()` method described above.
+
+There is also the `add_points_from_container()` function which copies the
+point from any container type supporting the `size()` function and which
+iterator yields a `vtzero::point` or something convertible to it.
+
+### Adding a linestring geometry
+
+Call `add_linestring()` with the number of points in the linestring as only
+argument. After that call `set_point()` for each of those points. `set_point()`
+has multiple overloads just like the `add_point()` method described above.
+
+```cpp
+...
+vtzero::layer_builder lbuilder{...};
+try {
+    vtzero::linestring_feature_builder fbuilder{lbuilder};
+    // optionally set the ID
+    fbuilder.set_id(23);
+    // add the geometry
+    fbuilder.add_linestring(2);
+    fbuilder.set_point(1, 2);
+    fbuilder.set_point(3, 4);
+    // add the properties
+    fbuilder.add_property("highway", "primary");
+    fbuilder.add_property("maxspeed", 80);
+    // call commit() when you are done
+    fbuilder.commit()
+} catch (const vtzero::geometry_exception& e) {
+    // if we are here, something was wrong with the geometry.
+}
+```
+
+Note that we have wrapped the feature builder in a try-catch-block here. This
+will ignore all geometry errors (which can happen if two consective points
+are the same creating a zero-length segment).
+
+There are two other versions of the `add_linestring()` function. They take two
+iterators defining a range to get the points from. Dereferencing those
+iterators must yield a `vtzero::point` or something convertible to it. One of
+these functions takes a third argument, the number of points the iterator will
+yield. If this is not available `std::distance(begin, end)` is called which
+internally by the `add_linestring()` function which might be slow depending on
+your iterator type.
+
+### Adding a multilinestring geometry
+
+Adding a multilinestring works just like adding a linestring, just do the
+calls to `add_linestring()` etc. repeatedly for each of the linestrings.
+
+### Adding a polygon geometry
+
+A polygon consists of one outer ring and zero or more inner rings. You have
+to first add the outer ring and then the inner rings, if any.
+
+Call `add_ring()` with the number of points in the ring as only argument. After
+that call `set_point()` for each of those points. `set_point()` has multiple
+overloads just like the `add_point()` method described above. The minimum
+number of points is 4 and the last point must be the same as the first point
+(or call `close_ring()` instead of the last `set_point()`).
+
+```cpp
+...
+vtzero::layer_builder lbuilder{...};
+try {
+    vtzero::polygon_feature_builder fbuilder{lbuilder};
+    // optionally set the ID
+    fbuilder.set_id(23);
+    // add the geometry
+    fbuilder.add_ring(5);
+    fbuilder.set_point(1, 1);
+    fbuilder.set_point(1, 2);
+    fbuilder.set_point(2, 2);
+    fbuilder.set_point(2, 1);
+    fbuilder.set_point(1, 1); // or call fbuilder.close_ring() instead
+    // add the properties
+    fbuilder.add_property("landuse", "forest");
+    // call commit() when you are done
+    fbuilder.commit()
+} catch (const vtzero::geometry_exception& e) {
+    // if we are here, something was wrong with the geometry.
+}
+```
+
+Note that we have wrapped the feature builder in a try-catch-block here. This
+will ignore all geometry errors (which can happen if two consective points
+are the same creating a zero-length segment or if the last point is not the
+same as the first point).
+
+There are two other versions of the `add_ring()` function. They take two
+iterators defining a range to get the points from. Dereferencing those
+iterators must yield a `vtzero::point` or something convertible to it. One of
+these functions takes a third argument, the number of points the iterator will
+yield. If this is not available `std::distance(begin, end)` is called which
+internally by the `add_ring()` function which might be slow depending on your
+iterator type.
+
+### Adding a multipolygon geometry
+
+Adding a multipolygon works just like adding a polygon, just do the calls to
+`add_ring()` etc. repeatedly for each of the rings. Make sure to always first
+add an outer ring, then the inner rings in this outer ring, then the next
+outer ring and so on.
+
+### Adding an existing geometry
+
+The `geometry_feature_builder` class is used to add geometries you got from
+reading a vector tile. This is useful when you want to copy over a geometry
+from a feature without decoding it.
+
+```cpp
+auto geom = ... // get geometry from a feature you are reading
+...
+vtzero::tile_builder tb;
+vtzero::layer_builder lb{tb};
+vtzero::geometry_feature_builder fb{lb};
+fb.set_id(123); // optionally set ID
+fb.add_geometry(geom) // add geometry
+fb.add_property("foo", "bar"); // add properties
+fb.commit();
+...
+```
+
+## Adding properties to the feature
+
+A feature can have any number of properties. They are added with the
+`add_property()` method called on the feature builder. There are two different
+ways of doing this. The *simple approach* which does all the work for you and
+the *advanced approach* which can be more efficient, but you have to to some
+more work. It is recommended that you start out with the simple approach and
+only switch to the advanced approach once you have a working program and want
+to get the last bit of performance out of it.
+
+The difference stems from the way properties are encoded in vector tiles. While
+properties "belong" to features, they are really stored in two tables (for the
+keys and values) in the layer. The individual feature only references the
+entries in those tables by index. This make the encoded tile smaller, but it
+means somebody has to manage those tables. In the simple approach this is done
+behind the scenes by the `layer_builder` object, in the advanced approach you
+handle that yourself.
+
+Do not mix the simple and the advanced approach unless you know what you are
+doing.
+
+### The simple approach to adding properties
+
+For the simple approach call `add_property()` with two arguments. The first is
+the key, it must have some kind of string type (`std::string`, `const char*`,
+`vtzero::data_view`, anything really that converts to a `data_view`). The
+second argument is the value, for which most basic C++ types are allowed
+(string types, integer types, double, ...). See the API documentation for the
+constructors of the `encoded_property_value` class for a list.
+
+```cpp
+vtzero::layer_builder lb{...};
+vtzero::linestring_feature_builder fb{lb};
+...
+fb.add_property("waterway", "stream"); // string value
+fb.add_property("name", "Little Creek");
+fb.add_property("width", 1.5); // double value
+...
+```
+
+Sometimes you need to specify exactly which type should be used in the
+encoding. The `encoded_property_value` constructor can take special types for
+that like in the following example, where you force the `sint` encoding:
+
+```cpp
+fb.add_property("layer", vtzero::sint_value_type(2));
+```
+
+You can also call `add_property()` with a single `vtzero::property` argument
+(which is handy if you are copying this property over from a tile you are
+reading):
+
+```cpp
+while (auto property = feature.next_property()) {
+    if (property.key() == "name") {
+        feature_builder.add_property(property);
+    }
+}
+```
+
+### The advanced approach to adding properties
+
+In the advanced approach you have to do the indexing yourself. Here is a very
+basic example:
+
+```cpp
+vtzero::tile_builder tbuilder;
+vtzero::layer_builder lbuilder{tbuilder, "test"};
+const vtzero::index_value highway = lbuilder.add_key("highway");
+const vtzero::index_value primary = lbuilder.add_value("primary");
+...
+vtzero::point_feature_builder fbuilder{lbuilder};
+...
+fbuilder.add_property(highway, primary);
+...
+```
+
+The methods `add_key()` and `add_value()` on the layer builder are used to add
+keys and values to the tables in the layer. They both return the index (of type
+`vtzero::index_value`) of those keys or values in the tables. You store
+those index values somewhere (in this case in the `highway` and `primary`
+variables) and use them when calling `add_property()` on the feature builder.
+
+In some cases you only have a few property keys and know them beforehand,
+then storing the key indexes in individual variables might work. But for
+values this usually doesn't make much sense, and if all your keys and values
+are only known at runtime, it doesn't work either. For this you need some kind
+of index data structure mapping from keys/values to index values. You can
+implement this yourself, but it is easier to use some classes provided by
+vtzero. Then the code looks like this:
+
+```cpp
+#include <vtzero/index.hpp> // use this include to get the index classes
+...
+vtzero::layer_builder lb{...};
+vtzero::key_index<std::map> key_index{lb};
+vtzero::value_index_internal<std::unordered_map> value_index{lb};
+...
+vtzero::point_feature_builder fb{lb};
+...
+fb.add_property(key_index("highway"), value_index("primary"));
+...
+```
+
+In this example the `key_index` template class is used for keys, it uses
+`std::map` internally as can be seen by its template argument. The
+`value_index_internal` template class is used for values, it uses
+`std::unordered_map` internally in this example. Whether you specify `std::map`
+or `std::unordered_map` or something else (that needs to be compatible to those
+classes) is up to you. Benchmark your use case and decide then.
+
+Keys are always strings, so they are easy to handle. For keys there is only the
+single `key_index` in vtzero.
+
+For values this is more difficult. Basically there are two choices:
+
+1. Encode the value according to the vector tile encoding rules which results
+   in a string and store this in the index. This is what the
+   `value_index_internal` class does.
+2. Store the un-encoded value in the index. The index lookup will be faster,
+   but you need a different index type for each value type. This is what the
+   `value_index` classes do.
+
+The `value_index` template classes need three template arguments: The type
+used internally to encode the value, the type used externally, and the map
+type.
+
+In this example the user program has the values as `int`, the index will store
+them in a `std::map<int>`. The integer value is then encoded in an `sint`
+int the vector tile:
+
+```cpp
+vtzero::value_index<vtzero::sint_value:type, int, std::map> index;
+```
+
+Sometimes these generic indexes based on `std::map` or `std::unordered_map`
+are inefficient, that's why there are specialized indexes for special cases:
+
+* The `value_index_bool` class can only index boolean values.
+* The `value_index_small_uint` class can only index small unsigned integer
+  values (up to `uint16_t`). It uses a vector internally, so if all your
+  numbers are small and densely packed, this is very efficient. This is
+  especially useful for `enum` types.
+
+## The `add_property()` function.
+
+The last chapters already talked about the `add_property()` function of the
+`feature_builder` class. But because it is a bit difficult to see all the
+different ways `add_property()` can be called, here is some more information.
+
+The `add_property()` function is called with either two parameters for the
+key and value or with one parameter that combines the key and value.
+
+If it is called with an `index_value` for the key or value, that index value is
+stored directly into the feature. If it is called with an `index_value_pair`,
+the index values in the `index_value_pair` are stored directly in the feature.
+
+If it is called with something that is not an `index_value` or
+`index_value_pair`, the function will interpret the data as keys or values.
+It will add those keys and values to the layer (if they are not already there),
+find the corresponding index values and store them in the feature.
+
+You can mix index-use with non-index use. For instance
+
+```cpp
+index_value key_maxspeed = lbuilder.add_key("maxspeed");
+...
+fbuilder.add_property(key_maxspeed, 30);
+```
+
+In this case the key ("maxspeed") was added to the layer once and its index
+value (`key_maxspeed`) can later be reused. The value (30), on the other hand,
+is only added to the layer in the `add_property()` call.
+
+So for keys, you can have as argument:
+* An `index_value`.
+* A `data_view` or something that converts to it like a `const char*` or `std::string`.
+
+For values, you can have as argument:
+* An `index_value`.
+* A `property_value`.
+* An `encoded_property_value` or anything that converts to it.
+
+For combined keys and values, you can have as argument:
+* An `index_value_pair`.
+* A `property`.
+
+
+## Deriving from `layer_builder` and `feature_builder`
+
+The `vtzero::layer_builder` and `vtzero::feature_builder` classes have been
+designed in a way that they can be derived from easily. This allows you to
+encapsulate part of your vector tile writing code if some aspects of your
+layers/features are always the same, such as the layer name and the names
+and types of properties.
+
+Say you want to write a layer named "restaurants" with point geometries.
+Each feature should have a name and a 5-star-rating. First you create a
+class derived from the `layer_builder` with all the indexes you want to use.
+For the keys you don't need indexes in this case, because there are only
+two keys for which we can easily store the index values in the layer.
+
+```cpp
+class restaurant_layer_builder : public vtzero::layer_builder {
+
+public:
+
+    // The index we'll use for the "name" property values
+    vtzero::value_index<vtzero::string_value_type, std::string, std::unordered_map> string_index;
+
+    // The index we'll use for the "stars" property values
+    vtzero::value_index_small_uint stars_index;
+
+    // The index value of the "name" key
+    vtzero::index_value key_name;
+
+    // The index value of the "stars" key
+    vtzero::index_value key_stars;
+
+    restaurant_layer_builder(vtzero::tile_builder& tile) :
+        layer_builder(tile, "restaurants"), // the name of the layer
+        string_index(*this),
+        stars_index(*this),
+        key_name(add_key_without_dup_check("name")),
+        key_stars(add_key_without_dup_check("stars")) {
+    }
+
+};
+```
+
+The we'll add a class derived from `feature_builder` to help with adding
+features:
+
+```cpp
+class restaurant_feature_builder : public vtzero::feature_builder {
+
+    restaurant_layer_builder& m_layer;
+
+public:
+
+    restaurant_feature_builder(restaurant_layer_builder& layer, uint64_t id) :
+        vtzero::point_feature_builder(layer), // always a point geometry
+        m_layer(layer) {
+        set_id(id); // we always have an ID in this case
+    }
+
+    void add_location(mylocation& loc) { // restaurant location is stored in your own type
+        add_point(loc.lon(), loc.lat());
+    }
+
+    void set_name(const std::string& name) {
+        add_property(m_layer.key_name,
+                     m_layer.string_index(vtzero::encoded_property_value{name}));
+    }
+
+    void set_stars(stars s) { // your own "stars" type
+        vtzero::encoded_property_value svalue{ s.num_stars() }; // convert stars type to small integer
+
+        add_property(m_layer.key_stars,
+                     m_layer.stars_index(svalue));
+    }
+
+};
+```
+
+This example only shows a general pattern you can follow to derive from the
+`layer_builder` and `feature_builder` classes. In some cases this makes more
+sense then in others. The derived classes make it easy for you to mix your
+own functions (for instance when you need to convert from your own types to
+vtzero types like with the `mylocation` and `stars` types above) or just use
+the functions in the base classes.
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/CMakeLists.txt
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/CMakeLists.txt	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/CMakeLists.txt	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,88 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake config
+#
+#  vtzero examples
+#
+#-----------------------------------------------------------------------------
+
+include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/include-external")
+
+set(TEST_FILE "${CMAKE_SOURCE_DIR}/test/data/mapbox-streets-v6-14-8714-8017.mvt")
+
+add_executable(vtzero-check vtzero-check.cpp utils.cpp)
+
+add_executable(vtzero-create vtzero-create.cpp utils.cpp)
+
+add_executable(vtzero-encode-geom vtzero-encode-geom.cpp utils.cpp)
+
+add_executable(vtzero-stats vtzero-stats.cpp utils.cpp)
+
+add_executable(vtzero-streets vtzero-streets.cpp utils.cpp)
+
+#-------------------------------------------------------------
+
+add_executable(vtzero-filter vtzero-filter.cpp utils.cpp)
+
+add_test(NAME vtzero-filter-empty
+            COMMAND vtzero-filter)
+set_tests_properties(vtzero-filter-empty PROPERTIES
+                        PASS_REGULAR_EXPRESSION "^Error in command line: Missing file name of vector tile to read")
+
+add_test(NAME vtzero-filter-help
+            COMMAND vtzero-filter -h)
+set_tests_properties(vtzero-filter-help PROPERTIES
+                        PASS_REGULAR_EXPRESSION "^usage:\n  vtzero-filter")
+
+add_test(NAME vtzero-filter-layer
+            COMMAND vtzero-filter -o ${CMAKE_CURRENT_BINARY_DIR}/bridges.mvt ${TEST_FILE} bridge)
+
+add_test(NAME vtzero-filter-feature
+            COMMAND vtzero-filter -o ${CMAKE_CURRENT_BINARY_DIR}/bridges.mvt ${TEST_FILE} waterway_label 221925711)
+
+add_test(NAME vtzero-filter-invalid-id
+            COMMAND vtzero-filter -o ${CMAKE_CURRENT_BINARY_DIR}/bridges.mvt ${TEST_FILE} waterway_label abc)
+set_tests_properties(vtzero-filter-invalid-id PROPERTIES
+                        WILL_FAIL true)
+
+#-------------------------------------------------------------
+
+add_executable(vtzero-show vtzero-show.cpp utils.cpp)
+
+add_test(NAME vtzero-show-empty
+            COMMAND vtzero-show)
+set_tests_properties(vtzero-show-empty PROPERTIES
+                        PASS_REGULAR_EXPRESSION "^Error in command line: Missing file name of vector tile to read")
+
+add_test(NAME vtzero-show-help
+            COMMAND vtzero-show -h)
+set_tests_properties(vtzero-show-help PROPERTIES
+                        PASS_REGULAR_EXPRESSION "^usage:\n  vtzero-show")
+
+add_test(NAME vtzero-show-layers
+            COMMAND vtzero-show -l ${TEST_FILE})
+set_tests_properties(vtzero-show-layers PROPERTIES
+                        PASS_REGULAR_EXPRESSION "^landuse 78\nwaterway 327\n.*\nwaterway_label 4\n$")
+
+add_test(NAME vtzero-show-layer-num
+            COMMAND vtzero-show ${TEST_FILE} 2)
+set_tests_properties(vtzero-show-layer-num PROPERTIES
+                        PASS_REGULAR_EXPRESSION "layer: [0-9]+\n  name: water\n")
+
+add_test(NAME vtzero-show-layer-name
+            COMMAND vtzero-show ${CMAKE_SOURCE_DIR}/test/data/mapbox-streets-v6-14-8714-8017.mvt water)
+set_tests_properties(vtzero-show-layer-name PROPERTIES
+                        PASS_REGULAR_EXPRESSION "layer: [0-9]+\n  name: water\n")
+
+#-------------------------------------------------------------
+
+file(GLOB ext_tests RELATIVE ${CMAKE_SOURCE_DIR}/test/data/ ${CMAKE_SOURCE_DIR}/test/data/*.mvt)
+
+foreach(_test IN LISTS ext_tests)
+    message(STATUS "Adding ext test: ${_test}")
+    add_test(NAME ext-tests-${_test}
+             COMMAND vtzero-show ${CMAKE_SOURCE_DIR}/test/data/${_test})
+endforeach()
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/utils.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/utils.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/utils.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,100 @@
+/*****************************************************************************
+
+  Utility functions for vtzero example programs.
+
+*****************************************************************************/
+
+#include "utils.hpp"
+
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <stdexcept>
+#include <string>
+
+/**
+ * Read complete contents of a file into a string.
+ *
+ * The file is read in binary mode.
+ *
+ * @param filename The file name. Can be empty or "-" to read from STDIN.
+ * @returns a string with the contents of the file.
+ * @throws various exceptions if there is an error
+ */
+std::string read_file(const std::string& filename) {
+    if (filename.empty() || (filename.size() == 1 && filename[0] == '-')) {
+        return std::string{std::istreambuf_iterator<char>(std::cin.rdbuf()),
+                           std::istreambuf_iterator<char>()};
+    }
+
+    std::ifstream stream{filename, std::ios_base::in | std::ios_base::binary};
+    if (!stream) {
+        throw std::runtime_error{std::string{"Can not open file '"} + filename + "'"};
+    }
+
+    stream.exceptions(std::ifstream::failbit);
+
+    std::string buffer{std::istreambuf_iterator<char>(stream.rdbuf()),
+                       std::istreambuf_iterator<char>()};
+    stream.close();
+
+    return buffer;
+}
+
+/**
+ * Write contents of a buffer into a file.
+ *
+ * The file is written in binary mode.
+ *
+ * @param buffer The data to be written.
+ * @param filename The file name.
+ * @throws various exceptions if there is an error
+ */
+void write_data_to_file(const std::string& buffer, const std::string& filename) {
+    std::ofstream stream{filename, std::ios_base::out | std::ios_base::binary};
+    if (!stream) {
+        throw std::runtime_error{std::string{"Can not open file '"} + filename + "'"};
+    }
+
+    stream.exceptions(std::ifstream::failbit);
+
+    stream.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
+
+    stream.close();
+}
+
+/**
+ * Get a specific layer from a vector tile. The layer can be specified as a
+ * number n in which case the nth layer in this tile is returned. Or it can
+ * be specified as text, in which case the layer with that name is returned.
+ *
+ * Calls exit(1) if there is an error.
+ *
+ * @param tile The vector tile.
+ * @param layer_name_or_num specifies the layer.
+ */
+vtzero::layer get_layer(const vtzero::vector_tile& tile, const std::string& layer_name_or_num) {
+    vtzero::layer layer;
+    char* str_end = nullptr;
+    const long num = std::strtol(layer_name_or_num.c_str(), &str_end, 10); // NOLINT(google-runtime-int)
+
+    if (str_end == layer_name_or_num.data() + layer_name_or_num.size()) {
+        if (num >= 0 && num < std::numeric_limits<long>::max()) { // NOLINT(google-runtime-int)
+            layer = tile.get_layer(static_cast<std::size_t>(num));
+            if (!layer) {
+                std::cerr << "No such layer: " << num << '\n';
+                std::exit(1);
+            }
+            return layer;
+        }
+    }
+
+    layer = tile.get_layer_by_name(layer_name_or_num);
+    if (!layer) {
+        std::cerr << "No layer named '" << layer_name_or_num << "'.\n";
+        std::exit(1);
+    }
+    return layer;
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/utils.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/utils.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/utils.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11 @@
+
+#include <vtzero/vector_tile.hpp>
+
+#include <string>
+
+std::string read_file(const std::string& filename);
+
+void write_data_to_file(const std::string& buffer, const std::string& filename);
+
+vtzero::layer get_layer(const vtzero::vector_tile& tile, const std::string& layer_name_or_num);
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-check.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-check.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-check.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,225 @@
+/*****************************************************************************
+
+  Example program for vtzero library.
+
+  vtzero-check - Check vector tiles for validity
+
+*****************************************************************************/
+
+#include "utils.hpp"
+
+#include <vtzero/vector_tile.hpp>
+
+#include <iostream>
+#include <set>
+#include <stdexcept>
+#include <string>
+
+class result {
+
+    int m_return_code = 0;
+
+public:
+
+    void has_warning() noexcept {
+        if (m_return_code < 1) {
+            m_return_code = 1;
+        }
+    }
+
+    void has_error() noexcept {
+        if (m_return_code < 2) {
+            m_return_code = 2;
+        }
+    }
+
+    void has_fatal_error() noexcept {
+        if (m_return_code < 3) {
+            m_return_code = 3;
+        }
+    }
+
+    int return_code() const noexcept {
+        return m_return_code;
+    }
+
+} result;
+
+class CheckGeomHandler {
+
+    vtzero::point m_prev_point{};
+    int m_layer_num;
+    int m_feature_num;
+    int64_t m_extent;
+    bool m_is_first_point = false;
+    int m_count = 0;
+
+    void print_context() const {
+        std::cerr << " in layer " << m_layer_num
+                  << " in feature " << m_feature_num
+                  << " in geometry " << m_count
+                  << ": ";
+    }
+
+    void print_error(const char* message) const {
+        result.has_error();
+        std::cerr << "Error";
+        print_context();
+        std::cerr << message << '\n';
+    }
+
+    void print_warning(const char* message) const {
+        result.has_warning();
+        std::cerr << "Warning";
+        print_context();
+        std::cerr << message << '\n';
+    }
+
+    void check_point_location(const vtzero::point point) const {
+        if (point.x < -m_extent ||
+            point.y < -m_extent ||
+            point.x > 2 * m_extent ||
+            point.y > 2 * m_extent) {
+            print_warning("point waaaay beyond the extent");
+        }
+    }
+
+public:
+
+    CheckGeomHandler(uint32_t extent, int layer_num, int feature_num) :
+        m_layer_num(layer_num),
+        m_feature_num(feature_num),
+        m_extent(static_cast<int64_t>(extent)) {
+    }
+
+    // ----------------------------------------------------------------------
+
+    void points_begin(const uint32_t /*count*/) const {
+    }
+
+    void points_point(const vtzero::point point) const {
+        check_point_location(point);
+    }
+
+    void points_end() const {
+    }
+
+    // ----------------------------------------------------------------------
+
+    void linestring_begin(const uint32_t count) {
+        if (count < 2) {
+            print_error("Not enough points in linestring");
+        }
+        m_is_first_point = true;
+    }
+
+    void linestring_point(const vtzero::point point) {
+        if (m_is_first_point) {
+            m_is_first_point = false;
+        } else {
+            if (point == m_prev_point) {
+                print_error("Duplicate point in linestring");
+            }
+        }
+        m_prev_point = point;
+
+        check_point_location(point);
+    }
+
+    void linestring_end() {
+        ++m_count;
+    }
+
+    // ----------------------------------------------------------------------
+
+    void ring_begin(const uint32_t count) {
+        if (count < 4) {
+            print_error("Not enough points in ring");
+        }
+        m_is_first_point = true;
+    }
+
+    void ring_point(const vtzero::point point) {
+        if (m_is_first_point) {
+            m_is_first_point = false;
+        } else {
+            if (point == m_prev_point) {
+                print_error("Duplicate point in ring");
+            }
+        }
+        m_prev_point = point;
+
+        check_point_location(point);
+    }
+
+    void ring_end(const vtzero::ring_type rt) {
+        if (rt == vtzero::ring_type::invalid) {
+            print_error("Invalid ring with area 0");
+        }
+        if (m_count == 0 && rt != vtzero::ring_type::outer) {
+            print_error("First ring isn't an outer ring");
+        }
+        ++m_count;
+    }
+
+}; // class CheckGeomHandler
+
+int main(int argc, char* argv[]) {
+    if (argc != 2) {
+        std::cerr << "Usage: " << argv[0] << " TILE\n";
+        return 1;
+    }
+
+    std::string input_file{argv[1]};
+    const auto data = read_file(input_file);
+
+    std::set<std::string> layer_names;
+
+    vtzero::vector_tile tile{data};
+
+    int layer_num = 0;
+    int feature_num = -1;
+    try {
+        while (auto layer = tile.next_layer()) {
+            if (layer.name().empty()) {
+                std::cerr << "Error in layer " << layer_num << ": name is empty (spec 4.1)\n";
+                result.has_error();
+            }
+
+            std::string name(layer.name());
+            if (layer_names.count(name) > 0) {
+                std::cerr << "Error in layer " << layer_num << ": name is duplicate of previous layer ('" << name << "') (spec 4.1)\n";
+                result.has_error();
+            }
+
+            layer_names.insert(name);
+
+            feature_num = 0;
+            while (auto feature = layer.next_feature()) {
+                CheckGeomHandler handler{layer.extent(), layer_num, feature_num};
+                vtzero::decode_geometry(feature.geometry(), handler);
+                ++feature_num;
+            }
+            if (feature_num == 0) {
+                std::cerr << "Warning: No features in layer " << layer_num << " (spec 4.1)\n";
+                result.has_warning();
+            }
+            feature_num = -1;
+            ++layer_num;
+        }
+        if (layer_num == 0) {
+            std::cerr << "Warning: No layers in vector tile (spec 4.1)\n";
+            result.has_warning();
+        }
+    } catch (const std::exception& e) {
+        std::cerr << "Fatal error in layer " << layer_num;
+        if (feature_num >= 0) {
+            std::cerr << " in feature " << feature_num;
+        }
+        std::cerr << ": " << e.what() << '\n';
+        result.has_fatal_error();
+    }
+
+    return result.return_code();
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-create.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-create.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-create.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,101 @@
+/*****************************************************************************
+
+  Example program for vtzero library.
+
+  vtzero-create - Create a vector tile
+
+*****************************************************************************/
+
+#include "utils.hpp"
+
+#include <vtzero/builder.hpp>
+#include <vtzero/index.hpp>
+
+#include <cstdint>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+int main() {
+    vtzero::tile_builder tile;
+    vtzero::layer_builder layer_points{tile, "points"};
+    vtzero::layer_builder layer_lines{tile, "lines"};
+    vtzero::layer_builder layer_polygons{tile, "polygons"};
+
+    vtzero::key_index<std::unordered_map> idx{layer_points};
+
+    {
+        vtzero::point_feature_builder feature{layer_points};
+        feature.set_id(1);
+        feature.add_points(1);
+        feature.set_point(10, 10);
+        feature.add_property("foo", "bar");
+        feature.add_property("x", "y");
+        feature.rollback();
+    }
+
+    const auto some = idx("some");
+
+    {
+        vtzero::point_feature_builder feature{layer_points};
+        feature.set_id(2);
+        feature.add_point(20, 20);
+        feature.add_property(some, "attr");
+    }
+    {
+        vtzero::point_feature_builder feature{layer_points};
+        feature.set_id(3);
+        feature.add_point(20, 20);
+        feature.add_property(idx("some"), "attr");
+    }
+
+    {
+        vtzero::point_feature_builder feature{layer_points};
+        feature.set_id(4);
+        feature.add_point(20, 20);
+        feature.add_property(idx("some"), "otherattr");
+    }
+
+
+    vtzero::point_feature_builder feature1{layer_points};
+    feature1.set_id(5);
+    feature1.add_point(vtzero::point{20, 20});
+    feature1.add_property("otherkey", "attr");
+    feature1.commit();
+
+    vtzero::value_index<vtzero::sint_value_type, int32_t, std::unordered_map> maxspeed_index{layer_lines};
+    {
+        vtzero::linestring_feature_builder feature{layer_lines};
+        feature.set_id(6);
+        feature.add_linestring(3);
+        feature.set_point(10, 10);
+        feature.set_point(10, 20);
+        feature.set_point(vtzero::point{20, 20});
+        std::vector<vtzero::point> points = {{11, 11}, {12, 13}};
+        feature.add_linestring_from_container(points);
+        feature.add_property("highway", "primary");
+        feature.add_property(std::string{"maxspeed"}, maxspeed_index(50));
+    }
+
+    {
+        vtzero::polygon_feature_builder feature{layer_polygons};
+        feature.set_id(7);
+        feature.add_ring(5);
+        feature.set_point(0, 0);
+        feature.set_point(10, 0);
+        feature.set_point(10, 10);
+        feature.set_point(0, 10);
+        feature.set_point(0, 0);
+        feature.add_ring(4);
+        feature.set_point(3, 3);
+        feature.set_point(3, 5);
+        feature.set_point(5, 5);
+        feature.close_ring();
+        feature.add_property("natural", "wood");
+        feature.add_property("number_of_trees", vtzero::sint_value_type{23402752});
+    }
+
+    const auto data = tile.serialize();
+    write_data_to_file(data, "test.mvt");
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-encode-geom.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-encode-geom.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-encode-geom.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,142 @@
+/*****************************************************************************
+
+  Example program for vtzero library.
+
+  vtzero-encode-geom - Encode geometry on command line
+
+  This can be used for debugging. Uses internals of vtzero!
+
+*****************************************************************************/
+
+#include "utils.hpp"
+
+#include <vtzero/geometry.hpp>
+
+#include <cctype>
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+int64_t get_int(const char* arg) {
+    char* endptr = nullptr;
+    const int64_t value = std::strtoll(arg, &endptr, 10);
+
+    if (*endptr == '\0') {
+        return value;
+    }
+
+    throw std::runtime_error{"not a valid number"};
+}
+
+uint32_t move_to(const char* arg) {
+    if (!std::isdigit(arg[0])) {
+        throw std::runtime_error{"need count after M command"};
+    }
+
+    const auto scount = get_int(arg);
+    if (scount <= 0) {
+        throw std::runtime_error{"count after M command must be 1 or larger"};
+    }
+    const auto count = static_cast<uint32_t>(scount);
+    std::cout << "MOVE_TO(" << count << ")\t" << vtzero::detail::command_move_to(count) << '\n';
+
+    return vtzero::detail::command_move_to(count);
+}
+
+uint32_t line_to(const char* arg) {
+    if (!std::isdigit(arg[0])) {
+        throw std::runtime_error{"need count after L command"};
+    }
+
+    const auto scount = get_int(arg);
+    if (scount <= 0) {
+        throw std::runtime_error{"count after L command must be 1 or larger"};
+    }
+    const auto count = static_cast<uint32_t>(scount);
+    std::cout << "LINE_TO(" << count << ")\t" << vtzero::detail::command_line_to(count) << '\n';
+
+    return vtzero::detail::command_line_to(count);
+}
+
+uint32_t close_path(const char* arg) {
+    if (arg[0] != '\0') {
+        throw std::runtime_error{"extra data after C command"};
+    }
+    std::cout << "CLOSE_PATH\t" << vtzero::detail::command_close_path() << '\n';
+
+    return vtzero::detail::command_close_path();
+}
+
+uint32_t number(const char* arg) {
+    const auto num = static_cast<int32_t>(get_int(arg));
+    std::cout << "number(" << num << ")\t" << protozero::encode_zigzag32(num) << '\n';
+
+    return protozero::encode_zigzag32(num);
+}
+
+int main(int argc, char* argv[]) {
+    if (argc < 2) {
+        std::cerr << "Usage: " << argv[0] << " GEOMETRY ELEMENTS...\n"
+                  << "GEOMETRY ELEMENTS are:\n"
+                  << "  M[count] -- MOVE_TO count\n"
+                  << "  L[count] -- LINE_TO count\n"
+                  << "  C        -- CLOSE_PATH\n"
+                  << "  [number] -- number that will be zigzag encoded\n";
+        return 1;
+    }
+
+    std::vector<uint32_t> values;
+
+    std::cout << "raw data\tencoded\n-----------------------------------\n";
+    for (int i = 1; i < argc; ++i) {
+        try {
+            switch (argv[i][0]) {
+                case '\0':
+                    break;
+                case 'M':
+                    values.push_back(move_to(argv[i] + 1));
+                    break;
+                case 'L':
+                    values.push_back(line_to(argv[i] + 1));
+                    break;
+                case 'C':
+                    values.push_back(close_path(argv[i] + 1));
+                    break;
+                case '-':
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                    values.push_back(number(argv[i]));
+                    break;
+                default:
+                    throw std::runtime_error{std::string{"unknown data: "} + argv[i]};
+                    return 1;
+            }
+        } catch (const std::runtime_error& e) {
+            std::cerr << "error(" << i << "): " << e.what() << '\n';
+            return 1;
+        }
+    }
+
+    std::string out{"["};
+
+    for (auto value : values) {
+        out += ' ';
+        out += std::to_string(value);
+        out += ',';
+    }
+
+    out.back() = ' ';
+
+    std::cout << '\n' << out << "]\n";
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-filter.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-filter.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-filter.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,101 @@
+/*****************************************************************************
+
+  Example program for vtzero library.
+
+  vtzero-filter - Copy parts of a vector tile into a new tile.
+
+*****************************************************************************/
+
+#include "utils.hpp"
+
+#include <vtzero/builder.hpp>
+#include <vtzero/vector_tile.hpp>
+
+#include <clara.hpp>
+
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <limits>
+#include <string>
+
+int main(int argc, char* argv[]) {
+    std::string filename;
+    std::string layer_num_or_name;
+    std::string idstr;
+    std::string output_file{"filtered.mvt"};
+
+    bool help = false;
+
+    const auto cli
+        = clara::Opt(output_file, "FILE")
+            ["-o"]["--output"]
+            ("write output to FILE")
+        | clara::Help(help)
+        | clara::Arg(filename, "FILENAME").required()
+            ("vector tile")
+        | clara::Arg(layer_num_or_name, "LAYER-NUM|LAYER-NAME").required()
+            ("layer")
+        | clara::Arg(idstr, "ID")
+            ("feature_id");
+
+    const auto result = cli.parse(clara::Args(argc, argv));
+    if (!result) {
+        std::cerr << "Error in command line: " << result.errorMessage() << '\n';
+        return 1;
+    }
+
+    if (help) {
+        std::cout << cli
+                  << "\nFilter contents of vector tile.\n";
+        return 0;
+    }
+
+    if (filename.empty()) {
+        std::cerr << "Error in command line: Missing file name of vector tile to read\n";
+        return 1;
+    }
+
+    if (layer_num_or_name.empty()) {
+        std::cerr << "Error in command line: Missing layer number or name\n";
+        return 1;
+    }
+
+    const auto data = read_file(filename);
+    vtzero::vector_tile tile{data};
+
+    auto layer = get_layer(tile, layer_num_or_name);
+    std::cerr << "Found layer: " << std::string(layer.name()) << "\n";
+
+    vtzero::tile_builder tb;
+
+    if (idstr.empty()) {
+        tb.add_existing_layer(layer);
+    } else {
+        char* str_end = nullptr;
+        const int64_t id = std::strtoll(idstr.c_str(), &str_end, 10);
+        if (str_end != idstr.c_str() + idstr.size()) {
+            std::cerr << "Feature ID must be numeric.\n";
+            return 1;
+        }
+        if (id < 0) {
+            std::cerr << "Feature ID must be >= 0.\n";
+            return 1;
+        }
+
+        const auto feature = layer.get_feature_by_id(static_cast<uint64_t>(id));
+        if (!feature.valid()) {
+            std::cerr << "No feature with that id: " << id << '\n';
+            return 1;
+        }
+
+        vtzero::layer_builder layer_builder{tb, layer};
+        layer_builder.add_feature(feature);
+    }
+
+    std::string output = tb.serialize();
+
+    write_data_to_file(output, output_file);
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-show.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-show.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-show.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,242 @@
+/*****************************************************************************
+
+  Example program for vtzero library.
+
+  vtzero-show - Show content of vector tile
+
+*****************************************************************************/
+
+#include "utils.hpp"
+
+#include <vtzero/vector_tile.hpp>
+
+#include <clara.hpp>
+
+#include <cstdint>
+#include <exception>
+#include <iostream>
+#include <string>
+
+class geom_handler {
+
+    std::string output{};
+
+public:
+
+    void points_begin(const uint32_t /*count*/) const noexcept {
+    }
+
+    void points_point(const vtzero::point point) const {
+        std::cout << "      POINT(" << point.x << ',' << point.y << ")\n";
+    }
+
+    void points_end() const noexcept {
+    }
+
+    void linestring_begin(const uint32_t count) {
+        output = "      LINESTRING[count=";
+        output += std::to_string(count);
+        output += "](";
+    }
+
+    void linestring_point(const vtzero::point point) {
+        output += std::to_string(point.x);
+        output += ' ';
+        output += std::to_string(point.y);
+        output += ',';
+    }
+
+    void linestring_end() {
+        if (output.empty()) {
+            return;
+        }
+        if (output.back() == ',') {
+            output.resize(output.size() - 1);
+        }
+        output += ")\n";
+        std::cout << output;
+    }
+
+    void ring_begin(const uint32_t count) {
+        output = "      RING[count=";
+        output += std::to_string(count);
+        output += "](";
+    }
+
+    void ring_point(const vtzero::point point) {
+        output += std::to_string(point.x);
+        output += ' ';
+        output += std::to_string(point.y);
+        output += ',';
+    }
+
+    void ring_end(const vtzero::ring_type rt) {
+        if (output.empty()) {
+            return;
+        }
+        if (output.back() == ',') {
+            output.back() = ')';
+        }
+        switch (rt) {
+            case vtzero::ring_type::outer:
+                output += "[OUTER]\n";
+                break;
+            case vtzero::ring_type::inner:
+                output += "[INNER]\n";
+                break;
+            default:
+                output += "[INVALID]\n";
+        }
+        std::cout << output;
+    }
+
+}; // class geom_handler
+
+template <typename TChar, typename TTraits>
+std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, vtzero::data_view value) {
+    out.write(value.data(), static_cast<std::streamsize>(value.size()));
+    return out;
+}
+
+struct print_value {
+
+    template <typename T>
+    void operator()(T value) const {
+        std::cout << value;
+    }
+
+    void operator()(const vtzero::data_view value) const {
+        std::cout << '"' << value << '"';
+    }
+
+}; // struct print_value
+
+static void print_layer(vtzero::layer& layer, bool print_tables, bool print_value_types, int& layer_num, int& feature_num) {
+    std::cout << "=============================================================\n"
+              << "layer: " << layer_num << '\n'
+              << "  name: " << std::string(layer.name()) << '\n'
+              << "  version: " << layer.version() << '\n'
+              << "  extent: " << layer.extent() << '\n';
+
+    if (print_tables) {
+        std::cout << "  keys:\n";
+        int n = 0;
+        for (const auto& key : layer.key_table()) {
+            std::cout << "    " << n++ << ": " << key << '\n';
+        }
+        std::cout << "  values:\n";
+        n = 0;
+        for (const vtzero::property_value& value : layer.value_table()) {
+            std::cout << "    " << n++ << ": ";
+            vtzero::apply_visitor(print_value{}, value);
+            if (print_value_types) {
+                std::cout << " [" << vtzero::property_value_type_name(value.type()) << "]\n";
+            } else {
+                std::cout << '\n';
+            }
+        }
+    }
+
+    feature_num = 0;
+    while (auto feature = layer.next_feature()) {
+        std::cout << "  feature: " << feature_num << '\n'
+                  << "    id: ";
+        if (feature.has_id()) {
+            std::cout << feature.id() << '\n';
+        } else {
+            std::cout << "(none)\n";
+        }
+        std::cout << "    geomtype: " << vtzero::geom_type_name(feature.geometry_type()) << '\n'
+                  << "    geometry:\n";
+        vtzero::decode_geometry(feature.geometry(), geom_handler{});
+        std::cout << "    properties:\n";
+        while (auto property = feature.next_property()) {
+            std::cout << "      " << property.key() << '=';
+            vtzero::apply_visitor(print_value{}, property.value());
+            if (print_value_types) {
+                std::cout << " [" << vtzero::property_value_type_name(property.value().type()) << "]\n";
+            } else {
+                std::cout << '\n';
+            }
+        }
+        ++feature_num;
+    }
+}
+
+static void print_layer_overview(const vtzero::layer& layer) {
+    std::cout << layer.name() << ' ' << layer.num_features() << '\n';
+}
+
+int main(int argc, char* argv[]) {
+    std::string filename;
+    std::string layer_num_or_name;
+    bool layer_overview = false;
+    bool print_tables = false;
+    bool print_value_types = false;
+    bool help = false;
+
+    const auto cli
+        = clara::Opt(layer_overview)
+            ["-l"]["--layers"]
+            ("show layer overview with feature count")
+        | clara::Opt(print_tables)
+            ["-t"]["--tables"]
+            ("also print key/value tables")
+        | clara::Opt(print_value_types)
+            ["-T"]["--value-types"]
+            ("also show value types")
+        | clara::Help(help)
+        | clara::Arg(filename, "FILENAME").required()
+            ("vector tile")
+        | clara::Arg(layer_num_or_name, "LAYER-NUM|LAYER-NAME")
+            ("layer");
+
+    const auto result = cli.parse(clara::Args(argc, argv));
+    if (!result) {
+        std::cerr << "Error in command line: " << result.errorMessage() << '\n';
+        return 1;
+    }
+
+    if (help) {
+        std::cout << cli
+                  << "\nShow contents of vector tile FILENAME.\n";
+        return 0;
+    }
+
+    if (filename.empty()) {
+        std::cerr << "Error in command line: Missing file name of vector tile to read\n";
+        return 1;
+    }
+
+    int layer_num = 0;
+    int feature_num = 0;
+    try {
+        const auto data = read_file(filename);
+
+        vtzero::vector_tile tile{data};
+
+        if (layer_num_or_name.empty()) {
+            while (auto layer = tile.next_layer()) {
+                if (layer_overview) {
+                    print_layer_overview(layer);
+                } else {
+                    print_layer(layer, print_tables, print_value_types, layer_num, feature_num);
+                }
+                ++layer_num;
+            }
+        } else {
+            auto layer = get_layer(tile, layer_num_or_name);
+            if (layer_overview) {
+                print_layer_overview(layer);
+            } else {
+                print_layer(layer, print_tables, print_value_types, layer_num, feature_num);
+            }
+        }
+    } catch (const std::exception& e) {
+        std::cerr << "Error in layer " << layer_num << " (feature " << feature_num << "): " << e.what() << '\n';
+        return 1;
+    }
+
+    return 0;
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-stats.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-stats.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-stats.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,40 @@
+/*****************************************************************************
+
+  Example program for vtzero library.
+
+  vtzero-stats - Output some stats on layers
+
+*****************************************************************************/
+
+#include "utils.hpp"
+
+#include <vtzero/vector_tile.hpp>
+
+#include <iostream>
+#include <stdexcept>
+#include <string>
+
+int main(int argc, char* argv[]) {
+    if (argc != 2) {
+        std::cerr << "Usage: " << argv[0] << " TILE\n";
+        return 1;
+    }
+
+    try {
+        std::string input_file{argv[1]};
+        const auto data = read_file(input_file);
+
+        vtzero::vector_tile tile{data};
+
+        while (const auto layer = tile.next_layer()) {
+            std::cout.write(layer.name().data(), static_cast<std::streamsize>(layer.name().size()));
+            std::cout << ' '
+                      << layer.num_features() << ' '
+                      << layer.key_table().size() << ' '
+                      << layer.value_table().size() << '\n';
+        }
+    } catch (const std::exception& e) {
+        std::cerr << "Error: " << e.what() << '\n';
+        return 1;
+    }
+}

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-streets.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-streets.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/examples/vtzero-streets.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,79 @@
+/*****************************************************************************
+
+  Example program for vtzero library.
+
+  vtzero-streets - Copy features from road_label layer if they have property
+                   class="street". Output is always in file "streets.mvt".
+
+*****************************************************************************/
+
+#include "utils.hpp"
+
+#include <vtzero/builder.hpp>
+#include <vtzero/property_mapper.hpp>
+#include <vtzero/vector_tile.hpp>
+
+#include <iostream>
+#include <string>
+
+static bool keep_feature(const vtzero::feature& feature) {
+    static const std::string key{"class"};
+    static const std::string val{"street"};
+
+    bool found = false;
+
+    feature.for_each_property([&](const vtzero::property& prop) {
+        found = key == prop.key() && val == prop.value().string_value();
+        return !found;
+    });
+
+    return found;
+}
+
+int main(int argc, char* argv[]) {
+    if (argc != 2) {
+        std::cerr << "Usage: " << argv[0] << " TILE\n";
+        return 1;
+    }
+
+    std::string input_file{argv[1]};
+    std::string output_file{"streets.mvt"};
+
+    const auto data = read_file(input_file);
+
+    try {
+        vtzero::vector_tile tile{data};
+
+        auto layer = get_layer(tile, "road_label");
+        if (!layer) {
+            std::cerr << "No 'road_label' layer found\n";
+            return 1;
+        }
+
+        vtzero::tile_builder tb;
+        vtzero::layer_builder layer_builder{tb, layer};
+
+        vtzero::property_mapper mapper{layer, layer_builder};
+
+        while (auto feature = layer.next_feature()) {
+            if (keep_feature(feature)) {
+                vtzero::geometry_feature_builder feature_builder{layer_builder};
+                if (feature.has_id()) {
+                    feature_builder.set_id(feature.id());
+                }
+                feature_builder.set_geometry(feature.geometry());
+
+                while (auto idxs = feature.next_property_indexes()) {
+                    feature_builder.add_property(mapper(idxs));
+                }
+            }
+        }
+
+        std::string output = tb.serialize();
+        write_data_to_file(output, output_file);
+    } catch (const std::exception& e) {
+        std::cerr << "Error: " << e.what() << '\n';
+        return 1;
+    }
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/builder.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/builder.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/builder.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,1363 @@
+#ifndef VTZERO_BUILDER_HPP
+#define VTZERO_BUILDER_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file builder.hpp
+ *
+ * @brief Contains the classes and functions to build vector tiles.
+ */
+
+#include "builder_impl.hpp"
+#include "feature_builder_impl.hpp"
+#include "geometry.hpp"
+#include "types.hpp"
+#include "vector_tile.hpp"
+
+#include <protozero/pbf_builder.hpp>
+
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+namespace vtzero {
+
+    /**
+     * Used to build vector tiles. Whenever you are building a new vector
+     * tile, start with an object of this class and add layers. After all
+     * the data is added, call serialize().
+     *
+     * @code
+     * layer some_existing_layer = ...;
+     *
+     * tile_builder builder;
+     * layer_builder layer_roads{builder, "roads"};
+     * builder.add_existing_layer(some_existing_layer);
+     * ...
+     * std::string data = builder.serialize();
+     * @endcode
+     */
+    class tile_builder {
+
+        friend class layer_builder;
+
+        std::vector<std::unique_ptr<detail::layer_builder_base>> m_layers;
+
+        /**
+         * Add a new layer to the vector tile based on an existing layer. The
+         * new layer will have the same name, version, and extent as the
+         * existing layer. The new layer will not contain any features. This
+         * method is handy when copying some (but not all) data from an
+         * existing layer.
+         */
+        detail::layer_builder_impl* add_layer(const layer& layer) {
+            const auto ptr = new detail::layer_builder_impl{layer.name(), layer.version(), layer.extent()};
+            m_layers.emplace_back(ptr);
+            return ptr;
+        }
+
+        /**
+         * Add a new layer to the vector tile with the specified name, version,
+         * and extent.
+         *
+         * @tparam TString Some string type (const char*, std::string,
+         *         vtzero::data_view) or something that converts to one of
+         *         these types.
+         * @param name Name of this layer.
+         * @param version Version of this layer (only version 1 and 2 are
+         *                supported)
+         * @param extent Extent used for this layer.
+         */
+        template <typename TString>
+        detail::layer_builder_impl* add_layer(TString&& name, uint32_t version, uint32_t extent) {
+            const auto ptr = new detail::layer_builder_impl{std::forward<TString>(name), version, extent};
+            m_layers.emplace_back(ptr);
+            return ptr;
+        }
+
+    public:
+
+        /// Constructor
+        tile_builder() = default;
+
+        /// Destructor
+        ~tile_builder() noexcept = default;
+
+        /// Tile builders can not be copied.
+        tile_builder(const tile_builder&) = delete;
+
+        /// Tile builders can not be copied.
+        tile_builder& operator=(const tile_builder&) = delete;
+
+        /// Tile builders can be moved.
+        tile_builder(tile_builder&&) = default;
+
+        /// Tile builders can be moved.
+        tile_builder& operator=(tile_builder&&) = default;
+
+        /**
+         * Add an existing layer to the vector tile. The layer data will be
+         * copied over into the new vector_tile when the serialize() method
+         * is called. Until then, the data referenced here must stay available.
+         *
+         * @param data Reference to some data that must be a valid encoded
+         *        layer.
+         */
+        void add_existing_layer(data_view&& data) {
+            m_layers.emplace_back(new detail::layer_builder_existing{std::forward<data_view>(data)});
+        }
+
+        /**
+         * Add an existing layer to the vector tile. The layer data will be
+         * copied over into the new vector_tile when the serialize() method
+         * is called. Until then, the data referenced here must stay available.
+         *
+         * @param layer Reference to the layer to be copied.
+         */
+        void add_existing_layer(const layer& layer) {
+            add_existing_layer(layer.data());
+        }
+
+        /**
+         * Serialize the data accumulated in this builder into a vector tile.
+         * The data will be appended to the specified buffer. The buffer
+         * doesn't have to be empty.
+         *
+         * @param buffer Buffer to append the encoded vector tile to.
+         */
+        void serialize(std::string& buffer) const {
+            std::size_t estimated_size = 0;
+            for (const auto& layer : m_layers) {
+                estimated_size += layer->estimated_size();
+            }
+
+            buffer.reserve(buffer.size() + estimated_size);
+
+            protozero::pbf_builder<detail::pbf_tile> pbf_tile_builder{buffer};
+            for (const auto& layer : m_layers) {
+                layer->build(pbf_tile_builder);
+            }
+        }
+
+        /**
+         * Serialize the data accumulated in this builder into a vector_tile
+         * and return it.
+         *
+         * If you want to use an existing buffer instead, use the serialize()
+         * method taking a std::string& as parameter.
+         *
+         * @returns std::string Buffer with encoded vector_tile data.
+         */
+        std::string serialize() const {
+            std::string data;
+            serialize(data);
+            return data;
+        }
+
+    }; // class tile_builder
+
+    /**
+     * The layer_builder is used to add a new layer to a vector tile that is
+     * being built.
+     */
+    class layer_builder {
+
+        vtzero::detail::layer_builder_impl* m_layer;
+
+        friend class geometry_feature_builder;
+        friend class point_feature_builder;
+        friend class linestring_feature_builder;
+        friend class polygon_feature_builder;
+
+        vtzero::detail::layer_builder_impl& get_layer_impl() noexcept {
+            return *m_layer;
+        }
+
+        template <typename T>
+        using is_layer = std::is_same<typename std::remove_cv<typename std::remove_reference<T>::type>::type, layer>;
+
+    public:
+
+        /**
+         * Construct a layer_builder to build a new layer with the same name,
+         * version, and extent as an existing layer.
+         *
+         * @param tile The tile builder we want to create this layer in.
+         * @param layer Existing layer we want to use the name, version, and
+         *        extent from
+         */
+        layer_builder(vtzero::tile_builder& tile, const layer& layer) :
+            m_layer(tile.add_layer(layer)) {
+        }
+
+        /**
+         * Construct a layer_builder to build a completely new layer.
+         *
+         * @tparam TString Some string type (such as std::string or const char*)
+         * @param tile The tile builder we want to create this layer in.
+         * @param name The name of the new layer.
+         * @param version The vector tile spec version of the new layer.
+         * @param extent The extent of the new layer.
+         */
+        template <typename TString, typename std::enable_if<!is_layer<TString>::value, int>::type = 0>
+        layer_builder(vtzero::tile_builder& tile, TString&& name, uint32_t version = 2, uint32_t extent = 4096) :
+            m_layer(tile.add_layer(std::forward<TString>(name), version, extent)) {
+        }
+
+        /**
+         * Add key to the keys table without checking for duplicates. This
+         * function is usually used when an external index is used which takes
+         * care of the duplication check.
+         *
+         * @param text The key.
+         * @returns The index value of this key.
+         */
+        index_value add_key_without_dup_check(const data_view text) {
+            return m_layer->add_key_without_dup_check(text);
+        }
+
+        /**
+         * Add key to the keys table. This function will consult the internal
+         * index in the layer to make sure the key is only in the table once.
+         * It will either return the index value of an existing key or add the
+         * new key and return its index value.
+         *
+         * @param text The key.
+         * @returns The index value of this key.
+         */
+        index_value add_key(const data_view text) {
+            return m_layer->add_key(text);
+        }
+
+        /**
+         * Add value to the values table without checking for duplicates. This
+         * function is usually used when an external index is used which takes
+         * care of the duplication check.
+         *
+         * @param value The property value.
+         * @returns The index value of this value.
+         */
+        index_value add_value_without_dup_check(const property_value value) {
+            return m_layer->add_value_without_dup_check(value);
+        }
+
+        /**
+         * Add value to the values table without checking for duplicates. This
+         * function is usually used when an external index is used which takes
+         * care of the duplication check.
+         *
+         * @param value The property value.
+         * @returns The index value of this value.
+         */
+        index_value add_value_without_dup_check(const encoded_property_value& value) {
+            return m_layer->add_value_without_dup_check(value);
+        }
+
+        /**
+         * Add value to the values table. This function will consult the
+         * internal index in the layer to make sure the value is only in the
+         * table once. It will either return the index value of an existing
+         * value or add the new value and return its index value.
+         *
+         * @param value The property value.
+         * @returns The index value of this value.
+         */
+        index_value add_value(const property_value value) {
+            return m_layer->add_value(value);
+        }
+
+        /**
+         * Add value to the values table. This function will consult the
+         * internal index in the layer to make sure the value is only in the
+         * table once. It will either return the index value of an existing
+         * value or add the new value and return its index value.
+         *
+         * @param value The property value.
+         * @returns The index value of this value.
+         */
+        index_value add_value(const encoded_property_value& value) {
+            return m_layer->add_value(value);
+        }
+
+        /**
+         * Add a feature from an existing layer to the new layer. The feature
+         * will be copied completely over to the new layer including its
+         * geometry and all its properties.
+         */
+        void add_feature(const feature& feature);
+
+    }; // class layer_builder
+
+    /**
+     * Parent class for the point_feature_builder, linestring_feature_builder
+     * and polygon_feature_builder classes. You can not instantiate this class
+     * directly, use it through its derived classes.
+     */
+    class feature_builder : public detail::feature_builder_base {
+
+        class countdown_value {
+
+            uint32_t m_value = 0;
+
+        public:
+
+            countdown_value() noexcept = default;
+
+            ~countdown_value() noexcept {
+                assert_is_zero();
+            }
+
+            countdown_value(const countdown_value&) = delete;
+
+            countdown_value& operator=(const countdown_value&) = delete;
+
+            countdown_value(countdown_value&& other) noexcept :
+                m_value(other.m_value) {
+                other.m_value = 0;
+            }
+
+            countdown_value& operator=(countdown_value&& other) noexcept {
+                m_value = other.m_value;
+                other.m_value = 0;
+                return *this;
+            }
+
+            uint32_t value() const noexcept {
+                return m_value;
+            }
+
+            void set(const uint32_t value) noexcept {
+                m_value = value;
+            }
+
+            void decrement() {
+                vtzero_assert(m_value > 0 && "too many calls to set_point()");
+                --m_value;
+            }
+
+            void assert_is_zero() const noexcept {
+                vtzero_assert_in_noexcept_function(m_value == 0 &&
+                                                   "not enough calls to set_point()");
+            }
+
+        }; // countdown_value
+
+    protected:
+
+        /// Encoded geometry.
+        protozero::packed_field_uint32 m_pbf_geometry{};
+
+        /// Number of points still to be set for the geometry to be complete.
+        countdown_value m_num_points;
+
+        /// Last point (used to calculate delta between coordinates)
+        point m_cursor{0, 0};
+
+        /// Constructor.
+        explicit feature_builder(detail::layer_builder_impl* layer) :
+            feature_builder_base(layer) {
+        }
+
+        /// Helper function to check size isn't too large
+        template <typename T>
+        uint32_t check_num_points(T size) {
+            if (size >= (1ul << 29u)) {
+                throw geometry_exception{"Maximum of 2^29 - 1 points allowed in geometry"};
+            }
+            return static_cast<uint32_t>(size);
+        }
+
+        /// Helper function to make sure we have everything before adding a property
+        void prepare_to_add_property() {
+            if (m_pbf_geometry.valid()) {
+                m_num_points.assert_is_zero();
+                m_pbf_geometry.commit();
+            }
+            if (!m_pbf_tags.valid()) {
+                m_pbf_tags = {m_feature_writer, detail::pbf_feature::tags};
+            }
+        }
+
+    public:
+
+        /**
+         * If the feature was not committed, the destructor will roll back all
+         * the changes.
+         */
+        ~feature_builder() {
+            try {
+                rollback();
+            } catch (...) {
+                // ignore exceptions
+            }
+        }
+
+        /// Builder classes can not be copied
+        feature_builder(const feature_builder&) = delete;
+
+        /// Builder classes can not be copied
+        feature_builder& operator=(const feature_builder&) = delete;
+
+        /// Builder classes can be moved
+        feature_builder(feature_builder&& other) noexcept = default;
+
+        /// Builder classes can be moved
+        feature_builder& operator=(feature_builder&& other) noexcept = default;
+
+        /**
+         * Set the ID of this feature.
+         *
+         * You can only call this method once and it must be before calling
+         * any method manipulating the geometry.
+         *
+         * @param id The ID.
+         */
+        void set_id(uint64_t id) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call set_id() after commit() or rollback()");
+            vtzero_assert(!m_pbf_geometry.valid() &&
+                          !m_pbf_tags.valid() &&
+                          "Call set_id() before setting the geometry or adding properties");
+            set_id_impl(id);
+        }
+
+        /**
+         * Copy the ID of an existing feature to this feature. If the
+         * feature doesn't have an ID, no ID is set.
+         *
+         * You can only call this method once and it must be before calling
+         * any method manipulating the geometry.
+         *
+         * @param feature The feature to copy the ID from.
+         */
+        void copy_id(const feature& feature) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call copy_id() after commit() or rollback()");
+            vtzero_assert(!m_pbf_geometry.valid() &&
+                          !m_pbf_tags.valid() &&
+                          "Call copy_id() before setting the geometry or adding properties");
+            if (feature.has_id()) {
+                set_id_impl(feature.id());
+            }
+        }
+
+        /**
+         * Add a property to this feature. Can only be called after all the
+         * methods manipulating the geometry.
+         *
+         * @tparam TProp Can be type index_value_pair or property.
+         * @param prop The property to add.
+         */
+        template <typename TProp>
+        void add_property(TProp&& prop) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call add_property() after commit() or rollback()");
+            prepare_to_add_property();
+            add_property_impl(std::forward<TProp>(prop));
+        }
+
+        /**
+         * Copy all properties of an existing feature to the one being built.
+         *
+         * @param feature The feature to copy the properties from.
+         */
+        void copy_properties(const feature& feature) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call copy_properties() after commit() or rollback()");
+            prepare_to_add_property();
+            feature.for_each_property([this](const property& prop) {
+                add_property_impl(prop);
+                return true;
+            });
+        }
+
+        /**
+         * Copy all properties of an existing feature to the one being built
+         * using a property_mapper.
+         *
+         * @tparam TMapper Must be the property_mapper class or something
+         *                 equivalent.
+         * @param feature The feature to copy the properties from.
+         * @param mapper Instance of the property_mapper class.
+         */
+        template <typename TMapper>
+        void copy_properties(const feature& feature, TMapper& mapper) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call copy_properties() after commit() or rollback()");
+            prepare_to_add_property();
+            feature.for_each_property_indexes([this, &mapper](const index_value_pair& idxs) {
+                add_property_impl(mapper(idxs));
+                return true;
+            });
+        }
+
+        /**
+         * Add a property to this feature. Can only be called after all the
+         * methods manipulating the geometry.
+         *
+         * @tparam TKey Can be type index_value or data_view or anything that
+         *         converts to it.
+         * @tparam TValue Can be type index_value or property_value or
+         *         encoded_property or anything that converts to it.
+         * @param key The key.
+         * @param value The value.
+         */
+        template <typename TKey, typename TValue>
+        void add_property(TKey&& key, TValue&& value) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call add_property() after commit() or rollback()");
+            prepare_to_add_property();
+            add_property_impl(std::forward<TKey>(key), std::forward<TValue>(value));
+        }
+
+        /**
+         * Commit this feature. Call this after all the details of this
+         * feature have been added. If this is not called, the feature
+         * will be rolled back when the destructor of the feature_builder is
+         * called.
+         *
+         * Once a feature has been committed or rolled back, further calls
+         * to commit() or rollback() don't do anything.
+         */
+        void commit() {
+            if (m_feature_writer.valid()) {
+                vtzero_assert((m_pbf_geometry.valid() || m_pbf_tags.valid()) &&
+                              "Can not call commit before geometry was added");
+                if (m_pbf_geometry.valid()) {
+                    m_pbf_geometry.commit();
+                }
+                do_commit();
+            }
+        }
+
+        /**
+         * Rollback this feature. Removed all traces of this feature from
+         * the layer_builder. Useful when you started creating a feature
+         * but then find out that its geometry is invalid or something like
+         * it. This will also happen automatically when the feature_builder
+         * is destructed and commit() hasn't been called on it.
+         *
+         * Once a feature has been committed or rolled back, further calls
+         * to commit() or rollback() don't do anything.
+         */
+        void rollback() {
+            if (m_feature_writer.valid()) {
+                if (m_pbf_geometry.valid()) {
+                    m_pbf_geometry.rollback();
+                }
+                do_rollback();
+            }
+        }
+
+    }; // class feature_builder
+
+    /**
+     * Used for adding a feature with a point geometry to a layer. After
+     * creating an object of this class you can add data to the feature in a
+     * specific order:
+     *
+     * * Optionally add the ID using set_id().
+     * * Add the (multi)point geometry using add_point(), add_points() and
+     *   set_point(), or add_points_from_container().
+     * * Optionally add any number of properties using add_property().
+     *
+     * @code
+     * vtzero::tile_builder tb;
+     * vtzero::layer_builder lb{tb};
+     * vtzero::point_feature_builder fb{lb};
+     * fb.set_id(123); // optionally set ID
+     * fb.add_point(10, 20) // add point geometry
+     * fb.add_property("foo", "bar"); // add property
+     * @endcode
+     */
+    class point_feature_builder : public feature_builder {
+
+    public:
+
+        /**
+         * Constructor
+         *
+         * @param layer The layer we want to create this feature in.
+         */
+        explicit point_feature_builder(layer_builder layer) :
+            feature_builder(&layer.get_layer_impl()) {
+            m_feature_writer.add_enum(detail::pbf_feature::type, static_cast<int32_t>(GeomType::POINT));
+        }
+
+        /**
+         * Add a single point as the geometry to this feature.
+         *
+         * @param p The point to add.
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void add_point(const point p) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not add geometry after commit() or rollback()");
+            vtzero_assert(!m_pbf_geometry.valid() &&
+                          !m_pbf_tags.valid() &&
+                          "add_point() can only be called once");
+            m_pbf_geometry = {m_feature_writer, detail::pbf_feature::geometry};
+            m_pbf_geometry.add_element(detail::command_move_to(1));
+            m_pbf_geometry.add_element(protozero::encode_zigzag32(p.x));
+            m_pbf_geometry.add_element(protozero::encode_zigzag32(p.y));
+        }
+
+        /**
+         * Add a single point as the geometry to this feature.
+         *
+         * @param x X coordinate of the point to add.
+         * @param y Y coordinate of the point to add.
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void add_point(const int32_t x, const int32_t y) {
+            add_point(point{x, y});
+        }
+
+        /**
+         * Add a single point as the geometry to this feature.
+         *
+         * @tparam TPoint A type that can be converted to vtzero::point using
+         *         the create_vtzero_point function.
+         * @param p The point to add.
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        template <typename TPoint>
+        void add_point(TPoint&& p) {
+            add_point(create_vtzero_point(std::forward<TPoint>(p)));
+        }
+
+        /**
+         * Declare the intent to add a multipoint geometry with *count* points
+         * to this feature.
+         *
+         * @param count The number of points in the multipoint geometry.
+         *
+         * @pre @code count > 0 && count < 2^29 @endcode
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void add_points(uint32_t count) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not add geometry after commit() or rollback()");
+            vtzero_assert(!m_pbf_geometry.valid() &&
+                          "can not call add_points() twice or mix with add_point()");
+            vtzero_assert(!m_pbf_tags.valid() &&
+                          "add_points() has to be called before properties are added");
+            vtzero_assert(count > 0 && count < (1ul << 29u) && "add_points() must be called with 0 < count < 2^29");
+            m_num_points.set(count);
+            m_pbf_geometry = {m_feature_writer, detail::pbf_feature::geometry};
+            m_pbf_geometry.add_element(detail::command_move_to(count));
+        }
+
+        /**
+         * Set a point in the multipoint geometry.
+         *
+         * @param p The point.
+         *
+         * @pre There must have been less than *count* calls to set_point()
+         *      already after a call to add_points(count).
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void set_point(const point p) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not add geometry after commit() or rollback()");
+            vtzero_assert(m_pbf_geometry.valid() &&
+                          "call add_points() before set_point()");
+            vtzero_assert(!m_pbf_tags.valid() &&
+                          "set_point() has to be called before properties are added");
+            m_num_points.decrement();
+            m_pbf_geometry.add_element(protozero::encode_zigzag32(p.x - m_cursor.x));
+            m_pbf_geometry.add_element(protozero::encode_zigzag32(p.y - m_cursor.y));
+            m_cursor = p;
+        }
+
+        /**
+         * Set a point in the multipoint geometry.
+         *
+         * @param x X coordinate of the point to set.
+         * @param y Y coordinate of the point to set.
+         *
+         * @pre There must have been less than *count* calls to set_point()
+         *      already after a call to add_points(count).
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void set_point(const int32_t x, const int32_t y) {
+            set_point(point{x, y});
+        }
+
+        /**
+         * Set a point in the multipoint geometry.
+         *
+         * @tparam TPoint A type that can be converted to vtzero::point using
+         *         the create_vtzero_point function.
+         * @param p The point to add.
+         *
+         * @pre There must have been less than *count* calls to set_point()
+         *      already after a call to add_points(count).
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        template <typename TPoint>
+        void set_point(TPoint&& p) {
+            set_point(create_vtzero_point(std::forward<TPoint>(p)));
+        }
+
+        /**
+         * Add the points from the specified container as multipoint geometry
+         * to this feature.
+         *
+         * @tparam TContainer The container type. Must support the size()
+         *         method, be iterable using a range for loop, and contain
+         *         objects of type vtzero::point or something convertible to
+         *         it.
+         * @param container The container to read the points from.
+         *
+         * @throws geometry_exception If there are more than 2^32-1 members in
+         *         the container.
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        template <typename TContainer>
+        void add_points_from_container(const TContainer& container) {
+            add_points(check_num_points(container.size()));
+            for (const auto& element : container) {
+                set_point(element);
+            }
+        }
+
+    }; // class point_feature_builder
+
+    /**
+     * Used for adding a feature with a (multi)linestring geometry to a layer.
+     * After creating an object of this class you can add data to the
+     * feature in a specific order:
+     *
+     * * Optionally add the ID using set_id().
+     * * Add the (multi)linestring geometry using add_linestring() or
+     *   add_linestring_from_container().
+     * * Optionally add any number of properties using add_property().
+     *
+     * @code
+     * vtzero::tile_builder tb;
+     * vtzero::layer_builder lb{tb};
+     * vtzero::linestring_feature_builder fb{lb};
+     * fb.set_id(123); // optionally set ID
+     * fb.add_linestring(2);
+     * fb.set_point(10, 10);
+     * fb.set_point(10, 20);
+     * fb.add_property("foo", "bar"); // add property
+     * @endcode
+     */
+    class linestring_feature_builder : public feature_builder {
+
+        bool m_start_line = false;
+
+    public:
+
+        /**
+         * Constructor
+         *
+         * @param layer The layer we want to create this feature in.
+         */
+        explicit linestring_feature_builder(layer_builder layer) :
+            feature_builder(&layer.get_layer_impl()) {
+            m_feature_writer.add_enum(detail::pbf_feature::type, static_cast<int32_t>(GeomType::LINESTRING));
+        }
+
+        /**
+         * Declare the intent to add a linestring geometry with *count* points
+         * to this feature.
+         *
+         * @param count The number of points in the linestring.
+         *
+         * @pre @code count > 1 && count < 2^29 @endcode
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void add_linestring(const uint32_t count) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not add geometry after commit() or rollback()");
+            vtzero_assert(!m_pbf_tags.valid() &&
+                          "add_linestring() has to be called before properties are added");
+            vtzero_assert(count > 1 && count < (1ul << 29u) && "add_linestring() must be called with 1 < count < 2^29");
+            m_num_points.assert_is_zero();
+            if (!m_pbf_geometry.valid()) {
+                m_pbf_geometry = {m_feature_writer, detail::pbf_feature::geometry};
+            }
+            m_num_points.set(count);
+            m_start_line = true;
+        }
+
+        /**
+         * Set a point in the multilinestring geometry opened with
+         * add_linestring().
+         *
+         * @param p The point.
+         *
+         * @throws geometry_exception if the point set is the same as the
+         *         previous point. This would create zero-length segments
+         *         which are not allowed according to the vector tile spec.
+         *
+         * @pre There must have been less than *count* calls to set_point()
+         *      already after a call to add_linestring(count).
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void set_point(const point p) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not add geometry after commit() or rollback()");
+            vtzero_assert(m_pbf_geometry.valid() &&
+                          "call add_linestring() before set_point()");
+            vtzero_assert(!m_pbf_tags.valid() &&
+                          "set_point() has to be called before properties are added");
+            m_num_points.decrement();
+            if (m_start_line) {
+                m_pbf_geometry.add_element(detail::command_move_to(1));
+                m_pbf_geometry.add_element(protozero::encode_zigzag32(p.x - m_cursor.x));
+                m_pbf_geometry.add_element(protozero::encode_zigzag32(p.y - m_cursor.y));
+                m_pbf_geometry.add_element(detail::command_line_to(m_num_points.value()));
+                m_start_line = false;
+            } else {
+                if (p == m_cursor) {
+                    throw geometry_exception{"Zero-length segments in linestrings are not allowed."};
+                }
+                m_pbf_geometry.add_element(protozero::encode_zigzag32(p.x - m_cursor.x));
+                m_pbf_geometry.add_element(protozero::encode_zigzag32(p.y - m_cursor.y));
+            }
+            m_cursor = p;
+        }
+
+        /**
+         * Set a point in the multilinestring geometry opened with
+         * add_linestring().
+         *
+         * @param x X coordinate of the point to set.
+         * @param y Y coordinate of the point to set.
+         *
+         * @throws geometry_exception if the point set is the same as the
+         *         previous point. This would create zero-length segments
+         *         which are not allowed according to the vector tile spec.
+         *
+         * @pre There must have been less than *count* calls to set_point()
+         *      already after a call to add_linestring(count).
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void set_point(const int32_t x, const int32_t y) {
+            set_point(point{x, y});
+        }
+
+        /**
+         * Set a point in the multilinestring geometry opened with
+         * add_linestring().
+         *
+         * @tparam TPoint A type that can be converted to vtzero::point using
+         *         the create_vtzero_point function.
+         * @param p The point to add.
+         *
+         * @throws geometry_exception if the point set is the same as the
+         *         previous point. This would create zero-length segments
+         *         which are not allowed according to the vector tile spec.
+         *
+         * @pre There must have been less than *count* calls to set_point()
+         *      already after a call to add_linestring(count).
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        template <typename TPoint>
+        void set_point(TPoint&& p) {
+            set_point(create_vtzero_point(std::forward<TPoint>(p)));
+        }
+
+        /**
+         * Add the points from the specified container as a linestring geometry
+         * to this feature.
+         *
+         * @tparam TContainer The container type. Must support the size()
+         *         method, be iterable using a range for loop, and contain
+         *         objects of type vtzero::point or something convertible to
+         *         it.
+         * @param container The container to read the points from.
+         *
+         * @throws geometry_exception If there are more than 2^32-1 members in
+         *         the container or if two consecutive points in the container
+         *         are identical.
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        template <typename TContainer>
+        void add_linestring_from_container(const TContainer& container) {
+            add_linestring(check_num_points(container.size()));
+            for (const auto& element : container) {
+                set_point(element);
+            }
+        }
+
+    }; // class linestring_feature_builder
+
+    /**
+     * Used for adding a feature with a (multi)polygon geometry to a layer.
+     * After creating an object of this class you can add data to the
+     * feature in a specific order:
+     *
+     * * Optionally add the ID using set_id().
+     * * Add the (multi)polygon geometry using add_ring() or
+     *   add_ring_from_container().
+     * * Optionally add any number of properties using add_property().
+     *
+     * @code
+     * vtzero::tile_builder tb;
+     * vtzero::layer_builder lb{tb};
+     * vtzero::polygon_feature_builder fb{lb};
+     * fb.set_id(123); // optionally set ID
+     * fb.add_ring(5);
+     * fb.set_point(10, 10);
+     * ...
+     * fb.add_property("foo", "bar"); // add property
+     * @endcode
+     */
+    class polygon_feature_builder : public feature_builder {
+
+        point m_first_point{0, 0};
+        bool m_start_ring = false;
+
+    public:
+
+        /**
+         * Constructor
+         *
+         * @param layer The layer we want to create this feature in.
+         */
+        explicit polygon_feature_builder(layer_builder layer) :
+            feature_builder(&layer.get_layer_impl()) {
+            m_feature_writer.add_enum(detail::pbf_feature::type, static_cast<int32_t>(GeomType::POLYGON));
+        }
+
+        /**
+         * Declare the intent to add a ring with *count* points to this
+         * feature.
+         *
+         * @param count The number of points in the ring.
+         *
+         * @pre @code count > 3 && count < 2^29 @endcode
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void add_ring(const uint32_t count) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not add geometry after commit() or rollback()");
+            vtzero_assert(!m_pbf_tags.valid() &&
+                          "add_ring() has to be called before properties are added");
+            vtzero_assert(count > 3 && count < (1ul << 29u) && "add_ring() must be called with 3 < count < 2^29");
+            m_num_points.assert_is_zero();
+            if (!m_pbf_geometry.valid()) {
+                m_pbf_geometry = {m_feature_writer, detail::pbf_feature::geometry};
+            }
+            m_num_points.set(count);
+            m_start_ring = true;
+        }
+
+        /**
+         * Set a point in the ring opened with add_ring().
+         *
+         * @param p The point.
+         *
+         * @throws geometry_exception if the point set is the same as the
+         *         previous point. This would create zero-length segments
+         *         which are not allowed according to the vector tile spec.
+         *         This exception is also thrown when the last point in the
+         *         ring is not equal to the first point, because this would
+         *         not create a closed ring.
+         *
+         * @pre There must have been less than *count* calls to set_point()
+         *      already after a call to add_ring(count).
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void set_point(const point p) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not add geometry after commit() or rollback()");
+            vtzero_assert(m_pbf_geometry.valid() &&
+                          "call add_ring() before set_point()");
+            vtzero_assert(!m_pbf_tags.valid() &&
+                          "set_point() has to be called before properties are added");
+            m_num_points.decrement();
+            if (m_start_ring) {
+                m_first_point = p;
+                m_pbf_geometry.add_element(detail::command_move_to(1));
+                m_pbf_geometry.add_element(protozero::encode_zigzag32(p.x - m_cursor.x));
+                m_pbf_geometry.add_element(protozero::encode_zigzag32(p.y - m_cursor.y));
+                m_pbf_geometry.add_element(detail::command_line_to(m_num_points.value() - 1));
+                m_start_ring = false;
+                m_cursor = p;
+            } else if (m_num_points.value() == 0) {
+                if (p != m_first_point) {
+                    throw geometry_exception{"Last point in a ring must be the same as the first point."};
+                }
+                // spec 4.3.3.3 "A ClosePath command MUST have a command count of 1"
+                m_pbf_geometry.add_element(detail::command_close_path());
+            } else {
+                if (p == m_cursor) {
+                    throw geometry_exception{"Zero-length segments in linestrings are not allowed."};
+                }
+                m_pbf_geometry.add_element(protozero::encode_zigzag32(p.x - m_cursor.x));
+                m_pbf_geometry.add_element(protozero::encode_zigzag32(p.y - m_cursor.y));
+                m_cursor = p;
+            }
+        }
+
+        /**
+         * Set a point in the ring opened with add_ring().
+         *
+         * @param x X coordinate of the point to set.
+         * @param y Y coordinate of the point to set.
+         *
+         * @throws geometry_exception if the point set is the same as the
+         *         previous point. This would create zero-length segments
+         *         which are not allowed according to the vector tile spec.
+         *         This exception is also thrown when the last point in the
+         *         ring is not equal to the first point, because this would
+         *         not create a closed ring.
+         *
+         * @pre There must have been less than *count* calls to set_point()
+         *      already after a call to add_ring(count).
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void set_point(const int32_t x, const int32_t y) {
+            set_point(point{x, y});
+        }
+
+        /**
+         * Set a point in the ring opened with add_ring().
+         *
+         * @tparam TPoint A type that can be converted to vtzero::point using
+         *         the create_vtzero_point function.
+         * @param p The point to add.
+         *
+         * @throws geometry_exception if the point set is the same as the
+         *         previous point. This would create zero-length segments
+         *         which are not allowed according to the vector tile spec.
+         *         This exception is also thrown when the last point in the
+         *         ring is not equal to the first point, because this would
+         *         not create a closed ring.
+         *
+         * @pre There must have been less than *count* calls to set_point()
+         *      already after a call to add_ring(count).
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        template <typename TPoint>
+        void set_point(TPoint&& p) {
+            set_point(create_vtzero_point(std::forward<TPoint>(p)));
+        }
+
+        /**
+         * Close a ring opened with add_ring(). This can be called for the
+         * last point (which will be equal to the first point) in the ring
+         * instead of calling set_point().
+         *
+         * @pre There must have been *count* - 1 calls to set_point()
+         *      already after a call to add_ring(count).
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        void close_ring() {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not add geometry after commit() or rollback()");
+            vtzero_assert(m_pbf_geometry.valid() &&
+                          "Call add_ring() before you can call close_ring()");
+            vtzero_assert(!m_pbf_tags.valid() &&
+                          "close_ring() has to be called before properties are added");
+            vtzero_assert(m_num_points.value() == 1 &&
+                          "wrong number of points in ring");
+            m_pbf_geometry.add_element(detail::command_close_path());
+            m_num_points.decrement();
+        }
+
+        /**
+         * Add the points from the specified container as a ring to this
+         * feature.
+         *
+         * @tparam TContainer The container type. Must support the size()
+         *         method, be iterable using a range for loop, and contain
+         *         objects of type vtzero::point or something convertible to
+         *         it.
+         * @param container The container to read the points from.
+         *
+         * @throws geometry_exception If there are more than 2^32-1 members in
+         *         the container or if two consecutive points in the container
+         *         are identical or if the last point is not the same as the
+         *         first point.
+         *
+         * @pre You must not have any calls to add_property() before calling
+         *      this method.
+         */
+        template <typename TContainer>
+        void add_ring_from_container(const TContainer& container) {
+            add_ring(check_num_points(container.size()));
+            for (const auto& element : container) {
+                set_point(element);
+            }
+        }
+
+    }; // class polygon_feature_builder
+
+    /**
+     * Used for adding a feature to a layer using an existing geometry. After
+     * creating an object of this class you can add data to the feature in a
+     * specific order:
+     *
+     * * Optionally add the ID using set_id().
+     * * Add the geometry using set_geometry().
+     * * Optionally add any number of properties using add_property().
+     *
+     * @code
+     * auto geom = ... // get geometry from a feature you are reading
+     * ...
+     * vtzero::tile_builder tb;
+     * vtzero::layer_builder lb{tb};
+     * vtzero::geometry_feature_builder fb{lb};
+     * fb.set_id(123); // optionally set ID
+     * fb.set_geometry(geom) // add geometry
+     * fb.add_property("foo", "bar"); // add property
+     * @endcode
+     */
+    class geometry_feature_builder : public detail::feature_builder_base {
+
+    public:
+
+        /**
+         * Constructor
+         *
+         * @param layer The layer we want to create this feature in.
+         */
+        explicit geometry_feature_builder(layer_builder layer) :
+            feature_builder_base(&layer.get_layer_impl()) {
+        }
+
+        /**
+         * If the feature was not committed, the destructor will roll back all
+         * the changes.
+         */
+        ~geometry_feature_builder() noexcept {
+            try {
+                rollback();
+            } catch (...) {
+                // ignore exceptions
+            }
+        }
+
+        /// Feature builders can not be copied.
+        geometry_feature_builder(const geometry_feature_builder&) = delete;
+
+        /// Feature builders can not be copied.
+        geometry_feature_builder& operator=(const geometry_feature_builder&) = delete;
+
+        /// Feature builders can be moved.
+        geometry_feature_builder(geometry_feature_builder&&) noexcept = default;
+
+        /// Feature builders can be moved.
+        geometry_feature_builder& operator=(geometry_feature_builder&&) noexcept = default;
+
+        /**
+         * Set the ID of this feature.
+         *
+         * You can only call this function once and it must be before calling
+         * set_geometry().
+         *
+         * @param id The ID.
+         */
+        void set_id(uint64_t id) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call set_id() after commit() or rollback()");
+            vtzero_assert(!m_pbf_tags.valid());
+            set_id_impl(id);
+        }
+
+        /**
+         * Copy the ID of an existing feature to this feature. If the
+         * feature doesn't have an ID, no ID is set.
+         *
+         * You can only call this function once and it must be before calling
+         * set_geometry().
+         *
+         * @param feature The feature to copy the ID from.
+         */
+        void copy_id(const feature& feature) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call copy_id() after commit() or rollback()");
+            vtzero_assert(!m_pbf_tags.valid());
+            if (feature.has_id()) {
+                set_id_impl(feature.id());
+            }
+        }
+
+        /**
+         * Set the geometry of this feature.
+         *
+         * You can only call this method once and it must be before calling the
+         * add_property() method.
+         *
+         * @param geometry The geometry.
+         */
+        void set_geometry(const geometry& geometry) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not add geometry after commit() or rollback()");
+            vtzero_assert(!m_pbf_tags.valid());
+            m_feature_writer.add_enum(detail::pbf_feature::type, static_cast<int32_t>(geometry.type()));
+            m_feature_writer.add_string(detail::pbf_feature::geometry, geometry.data());
+            m_pbf_tags = {m_feature_writer, detail::pbf_feature::tags};
+        }
+
+        /**
+         * Add a property to this feature. Can only be called after the
+         * set_geometry method.
+         *
+         * @tparam TProp Can be type index_value_pair or property.
+         * @param prop The property to add.
+         */
+        template <typename TProp>
+        void add_property(TProp&& prop) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call add_property() after commit() or rollback()");
+            add_property_impl(std::forward<TProp>(prop));
+        }
+
+        /**
+         * Add a property to this feature. Can only be called after the
+         * set_geometry method.
+         *
+         * @tparam TKey Can be type index_value or data_view or anything that
+         *         converts to it.
+         * @tparam TValue Can be type index_value or property_value or
+         *         encoded_property or anything that converts to it.
+         * @param key The key.
+         * @param value The value.
+         */
+        template <typename TKey, typename TValue>
+        void add_property(TKey&& key, TValue&& value) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call add_property() after commit() or rollback()");
+            add_property_impl(std::forward<TKey>(key), std::forward<TValue>(value));
+        }
+
+        /**
+         * Copy all properties of an existing feature to the one being built.
+         *
+         * @param feature The feature to copy the properties from.
+         */
+        void copy_properties(const feature& feature) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call copy_properties() after commit() or rollback()");
+            feature.for_each_property([this](const property& prop) {
+                add_property_impl(prop);
+                return true;
+            });
+        }
+
+        /**
+         * Copy all properties of an existing feature to the one being built
+         * using a property_mapper.
+         *
+         * @tparam TMapper Must be the property_mapper class or something
+         *                 equivalent.
+         * @param feature The feature to copy the properties from.
+         * @param mapper Instance of the property_mapper class.
+         */
+        template <typename TMapper>
+        void copy_properties(const feature& feature, TMapper& mapper) {
+            vtzero_assert(m_feature_writer.valid() &&
+                          "Can not call copy_properties() after commit() or rollback()");
+            feature.for_each_property_indexes([this, &mapper](const index_value_pair& idxs) {
+                add_property_impl(mapper(idxs));
+                return true;
+            });
+        }
+
+        /**
+         * Commit this feature. Call this after all the details of this
+         * feature have been added. If this is not called, the feature
+         * will be rolled back when the destructor of the feature_builder is
+         * called.
+         *
+         * Once a feature has been committed or rolled back, further calls
+         * to commit() or rollback() don't do anything.
+         */
+        void commit() {
+            if (m_feature_writer.valid()) {
+                vtzero_assert(m_pbf_tags.valid() &&
+                              "Can not call commit before geometry was added");
+                do_commit();
+            }
+        }
+
+        /**
+         * Rollback this feature. Removed all traces of this feature from
+         * the layer_builder. Useful when you started creating a feature
+         * but then find out that its geometry is invalid or something like
+         * it. This will also happen automatically when the feature_builder
+         * is destructed and commit() hasn't been called on it.
+         *
+         * Once a feature has been committed or rolled back, further calls
+         * to commit() or rollback() don't do anything.
+         */
+        void rollback() {
+            if (m_feature_writer.valid()) {
+                do_rollback();
+            }
+        }
+
+    }; // class geometry_feature_builder
+
+    inline void layer_builder::add_feature(const feature& feature) {
+        geometry_feature_builder feature_builder{*this};
+        if (feature.has_id()) {
+            feature_builder.set_id(feature.id());
+        }
+        feature_builder.set_geometry(feature.geometry());
+        feature.for_each_property([&feature_builder](const property& p) {
+            feature_builder.add_property(p);
+            return true;
+        });
+        feature_builder.commit();
+    }
+
+} // namespace vtzero
+
+#endif // VTZERO_BUILDER_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/builder_impl.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/builder_impl.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/builder_impl.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,274 @@
+#ifndef VTZERO_BUILDER_IMPL_HPP
+#define VTZERO_BUILDER_IMPL_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file builder_impl.hpp
+ *
+ * @brief Contains classes internal to the builder.
+ */
+
+#include "encoded_property_value.hpp"
+#include "property_value.hpp"
+#include "types.hpp"
+
+#include <protozero/pbf_builder.hpp>
+#include <protozero/pbf_message.hpp>
+
+#include <cstdlib>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+namespace vtzero {
+
+    namespace detail {
+
+        class layer_builder_base {
+
+        public:
+
+            layer_builder_base() noexcept = default;
+
+            virtual ~layer_builder_base() noexcept = default;
+
+            layer_builder_base(const layer_builder_base&) noexcept = default;
+            layer_builder_base& operator=(const layer_builder_base&) noexcept = default;
+
+            layer_builder_base(layer_builder_base&&) noexcept = default;
+            layer_builder_base& operator=(layer_builder_base&&) noexcept = default;
+
+            virtual std::size_t estimated_size() const = 0;
+
+            virtual void build(protozero::pbf_builder<detail::pbf_tile>& pbf_tile_builder) const = 0;
+
+        }; // class layer_builder_base
+
+        class layer_builder_impl : public layer_builder_base {
+
+            // Buffer containing the encoded layer metadata and features
+            std::string m_data;
+
+            // Buffer containing the encoded keys table
+            std::string m_keys_data;
+
+            // Buffer containing the encoded values table
+            std::string m_values_data;
+
+            protozero::pbf_builder<detail::pbf_layer> m_pbf_message_layer;
+            protozero::pbf_builder<detail::pbf_layer> m_pbf_message_keys;
+            protozero::pbf_builder<detail::pbf_layer> m_pbf_message_values;
+
+            // The number of features in the layer
+            std::size_t m_num_features = 0;
+
+            // The number of keys in the keys table
+            uint32_t m_num_keys = 0;
+
+            // The number of values in the values table
+            uint32_t m_num_values = 0;
+
+            // Below this value, no index will be used to find entries in the
+            // key/value tables. This number is based on some initial
+            // benchmarking but probably needs some tuning.
+            // See also https://github.com/mapbox/vtzero/issues/30
+            static constexpr const uint32_t max_entries_flat = 20;
+
+            using map_type = std::unordered_map<std::string, index_value>;
+            map_type m_keys_index;
+            map_type m_values_index;
+
+            static index_value find_in_table(const data_view text, const std::string& data) {
+                uint32_t index = 0;
+                protozero::pbf_message<detail::pbf_layer> pbf_table{data};
+
+                while (pbf_table.next()) {
+                    const auto v = pbf_table.get_view();
+                    if (v == text) {
+                        return index_value{index};
+                    }
+                    ++index;
+                }
+
+                return index_value{};
+            }
+
+            // Read the key or value table and populate an index from its
+            // entries. This is done once the table becomes too large to do
+            // linear search in it.
+            static void populate_index(const std::string& data, map_type& map) {
+                uint32_t index = 0;
+                protozero::pbf_message<detail::pbf_layer> pbf_table{data};
+
+                while (pbf_table.next()) {
+                    map[pbf_table.get_string()] = index++;
+                }
+            }
+
+            index_value add_value_without_dup_check(const data_view text) {
+                m_pbf_message_values.add_string(detail::pbf_layer::values, text);
+                return m_num_values++;
+            }
+
+            index_value add_value(const data_view text) {
+                const auto index = find_in_values_table(text);
+                if (index.valid()) {
+                    return index;
+                }
+                return add_value_without_dup_check(text);
+            }
+
+            index_value find_in_keys_table(const data_view text) {
+                if (m_num_keys < max_entries_flat) {
+                    return find_in_table(text, m_keys_data);
+                }
+
+                if (m_keys_index.empty()) {
+                    populate_index(m_keys_data, m_keys_index);
+                }
+
+                auto& v = m_keys_index[std::string(text)];
+                if (!v.valid()) {
+                    v = add_key_without_dup_check(text);
+                }
+                return v;
+            }
+
+            index_value find_in_values_table(const data_view text) {
+                if (m_num_values < max_entries_flat) {
+                    return find_in_table(text, m_values_data);
+                }
+
+                if (m_values_index.empty()) {
+                    populate_index(m_values_data, m_values_index);
+                }
+
+                auto& v = m_values_index[std::string(text)];
+                if (!v.valid()) {
+                    v = add_value_without_dup_check(text);
+                }
+                return v;
+            }
+
+        public:
+
+            template <typename TString>
+            layer_builder_impl(TString&& name, uint32_t version, uint32_t extent) :
+                m_pbf_message_layer(m_data),
+                m_pbf_message_keys(m_keys_data),
+                m_pbf_message_values(m_values_data) {
+                m_pbf_message_layer.add_uint32(detail::pbf_layer::version, version);
+                m_pbf_message_layer.add_string(detail::pbf_layer::name, std::forward<TString>(name));
+                m_pbf_message_layer.add_uint32(detail::pbf_layer::extent, extent);
+            }
+
+            ~layer_builder_impl() noexcept override = default;
+
+            layer_builder_impl(const layer_builder_impl&) = delete;
+            layer_builder_impl& operator=(const layer_builder_impl&) = delete;
+
+            layer_builder_impl(layer_builder_impl&&) = default;
+            layer_builder_impl& operator=(layer_builder_impl&&) = default;
+
+            index_value add_key_without_dup_check(const data_view text) {
+                m_pbf_message_keys.add_string(detail::pbf_layer::keys, text);
+                return m_num_keys++;
+            }
+
+            index_value add_key(const data_view text) {
+                const auto index = find_in_keys_table(text);
+                if (index.valid()) {
+                    return index;
+                }
+                return add_key_without_dup_check(text);
+            }
+
+            index_value add_value_without_dup_check(const property_value value) {
+                return add_value_without_dup_check(value.data());
+            }
+
+            index_value add_value_without_dup_check(const encoded_property_value& value) {
+                return add_value_without_dup_check(value.data());
+            }
+
+            index_value add_value(const property_value value) {
+                return add_value(value.data());
+            }
+
+            index_value add_value(const encoded_property_value& value) {
+                return add_value(value.data());
+            }
+
+            const std::string& data() const noexcept {
+                return m_data;
+            }
+
+            const std::string& keys_data() const noexcept {
+                return m_keys_data;
+            }
+
+            const std::string& values_data() const noexcept {
+                return m_values_data;
+            }
+
+            protozero::pbf_builder<detail::pbf_layer>& message() noexcept {
+                return m_pbf_message_layer;
+            }
+
+            void increment_feature_count() noexcept {
+                ++m_num_features;
+            }
+
+            std::size_t estimated_size() const override {
+                constexpr const std::size_t estimated_overhead_for_pbf_encoding = 8;
+                return data().size() +
+                       keys_data().size() +
+                       values_data().size() +
+                       estimated_overhead_for_pbf_encoding;
+            }
+
+            void build(protozero::pbf_builder<detail::pbf_tile>& pbf_tile_builder) const override {
+                if (m_num_features > 0) {
+                    pbf_tile_builder.add_bytes_vectored(detail::pbf_tile::layers,
+                                                        data(),
+                                                        keys_data(),
+                                                        values_data());
+                }
+            }
+
+        }; // class layer_builder_impl
+
+        class layer_builder_existing : public layer_builder_base {
+
+            data_view m_data;
+
+        public:
+
+            explicit layer_builder_existing(const data_view data) :
+                m_data(data) {
+            }
+
+            std::size_t estimated_size() const override {
+                constexpr const std::size_t estimated_overhead_for_pbf_encoding = 8;
+                return m_data.size() + estimated_overhead_for_pbf_encoding;
+            }
+
+            void build(protozero::pbf_builder<detail::pbf_tile>& pbf_tile_builder) const override {
+                pbf_tile_builder.add_bytes(detail::pbf_tile::layers, m_data);
+            }
+
+        }; // class layer_builder_existing
+
+    } // namespace detail
+
+} // namespace vtzero
+
+#endif // VTZERO_BUILDER_IMPL_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/encoded_property_value.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/encoded_property_value.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/encoded_property_value.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,244 @@
+#ifndef VTZERO_ENCODED_PROPERTY_VALUE_HPP
+#define VTZERO_ENCODED_PROPERTY_VALUE_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file encoded_property_value.hpp
+ *
+ * @brief Contains the encoded_property_value class.
+ */
+
+#include "types.hpp"
+
+#include <protozero/pbf_builder.hpp>
+
+#include <functional>
+#include <string>
+
+namespace vtzero {
+
+    /**
+     * A property value encoded in the vector_tile internal format. Can be
+     * created from values of many different types and then later added to
+     * a layer/feature.
+     */
+    class encoded_property_value {
+
+        std::string m_data;
+
+    public:
+
+        /// Construct from vtzero::string_value_type.
+        explicit encoded_property_value(string_value_type value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_string(detail::pbf_value::string_value, value.value);
+        }
+
+        /// Construct from const char*.
+        explicit encoded_property_value(const char* value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_string(detail::pbf_value::string_value, value);
+        }
+
+        /// Construct from const char* and size_t.
+        explicit encoded_property_value(const char* value, std::size_t size) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_string(detail::pbf_value::string_value, value, size);
+        }
+
+        /// Construct from std::string.
+        explicit encoded_property_value(const std::string& value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_string(detail::pbf_value::string_value, value);
+        }
+
+        /// Construct from vtzero::data_view.
+        explicit encoded_property_value(const data_view& value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_string(detail::pbf_value::string_value, value);
+        }
+
+        // ------------------
+
+        /// Construct from vtzero::float_value_type.
+        explicit encoded_property_value(float_value_type value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_float(detail::pbf_value::float_value, value.value);
+        }
+
+        /// Construct from float.
+        explicit encoded_property_value(float value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_float(detail::pbf_value::float_value, value);
+        }
+
+        // ------------------
+
+        /// Construct from vtzero::double_value_type.
+        explicit encoded_property_value(double_value_type value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_double(detail::pbf_value::double_value, value.value);
+        }
+
+        /// Construct from double.
+        explicit encoded_property_value(double value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_double(detail::pbf_value::double_value, value);
+        }
+
+        // ------------------
+
+        /// Construct from vtzero::int_value_type.
+        explicit encoded_property_value(int_value_type value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_int64(detail::pbf_value::int_value, value.value);
+        }
+
+        /// Construct from int64_t.
+        explicit encoded_property_value(int64_t value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_int64(detail::pbf_value::int_value, value);
+        }
+
+        /// Construct from int32_t.
+        explicit encoded_property_value(int32_t value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_int64(detail::pbf_value::int_value, static_cast<int64_t>(value));
+        }
+
+        /// Construct from int16_t.
+        explicit encoded_property_value(int16_t value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_int64(detail::pbf_value::int_value, static_cast<int64_t>(value));
+        }
+
+        // ------------------
+
+        /// Construct from vtzero::uint_value_type.
+        explicit encoded_property_value(uint_value_type value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_uint64(detail::pbf_value::uint_value, value.value);
+        }
+
+        /// Construct from uint64_t.
+        explicit encoded_property_value(uint64_t value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_uint64(detail::pbf_value::uint_value, value);
+        }
+
+        /// Construct from uint32_t.
+        explicit encoded_property_value(uint32_t value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_uint64(detail::pbf_value::uint_value, static_cast<uint64_t>(value));
+        }
+
+        /// Construct from uint16_t.
+        explicit encoded_property_value(uint16_t value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_uint64(detail::pbf_value::uint_value, static_cast<uint64_t>(value));
+        }
+
+        // ------------------
+
+        /// Construct from vtzero::sint_value_type.
+        explicit encoded_property_value(sint_value_type value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_sint64(detail::pbf_value::sint_value, value.value);
+        }
+
+        // ------------------
+
+        /// Construct from vtzero::bool_value_type.
+        explicit encoded_property_value(bool_value_type value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_bool(detail::pbf_value::bool_value, value.value);
+        }
+
+        /// Construct from bool.
+        explicit encoded_property_value(bool value) {
+            protozero::pbf_builder<detail::pbf_value> pbf_message_value{m_data};
+            pbf_message_value.add_bool(detail::pbf_value::bool_value, value);
+        }
+
+        // ------------------
+
+        /**
+         * Get view of the raw data stored inside.
+         */
+        data_view data() const noexcept {
+            return {m_data.data(), m_data.size()};
+        }
+
+        /**
+         * Hash function compatible with std::hash.
+         */
+        std::size_t hash() const noexcept {
+            return std::hash<std::string>{}(m_data);
+        }
+
+    }; // class encoded_property_value
+
+    /// Encoded property values are equal if they contain the same data.
+    inline bool operator==(const encoded_property_value& lhs, const encoded_property_value& rhs) noexcept {
+        return lhs.data() == rhs.data();
+    }
+
+    /// Encoded property values are unequal if they are not equal.
+    inline bool operator!=(const encoded_property_value& lhs, const encoded_property_value& rhs) noexcept {
+        return !(lhs == rhs);
+    }
+
+    /// Arbitrary ordering based on internal data.
+    inline bool operator<(const encoded_property_value& lhs, const encoded_property_value& rhs) noexcept {
+        return lhs.data() < rhs.data();
+    }
+
+    /// Arbitrary ordering based on internal data.
+    inline bool operator<=(const encoded_property_value& lhs, const encoded_property_value& rhs) noexcept {
+        return lhs.data() <= rhs.data();
+    }
+
+    /// Arbitrary ordering based on internal data.
+    inline bool operator>(const encoded_property_value& lhs, const encoded_property_value& rhs) noexcept {
+        return lhs.data() > rhs.data();
+    }
+
+    /// Arbitrary ordering based on internal data.
+    inline bool operator>=(const encoded_property_value& lhs, const encoded_property_value& rhs) noexcept {
+        return lhs.data() >= rhs.data();
+    }
+
+} // namespace vtzero
+
+namespace std {
+
+    /**
+     * Specialization of std::hash for encoded_property_value.
+     */
+    template <>
+    struct hash<vtzero::encoded_property_value> {
+
+        /// key vtzero::encoded_property_value
+        using argument_type = vtzero::encoded_property_value;
+
+        /// hash result: size_t
+        using result_type = std::size_t;
+
+        /// calculate the hash of the argument
+        std::size_t operator()(const vtzero::encoded_property_value& value) const noexcept {
+            return value.hash();
+        }
+
+    }; // struct hash
+
+} // namespace std
+
+#endif // VTZERO_ENCODED_PROPERTY_VALUE_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/exception.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/exception.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/exception.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,134 @@
+#ifndef VTZERO_EXCEPTION_HPP
+#define VTZERO_EXCEPTION_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file exception.hpp
+ *
+ * @brief Contains the exceptions used in the vtzero library.
+ */
+
+#include <cstdint>
+#include <stdexcept>
+#include <string>
+
+namespace vtzero {
+
+    /**
+     * Base class for all exceptions directly thrown by the vtzero library.
+     */
+    class exception : public std::runtime_error {
+
+    public:
+
+        /// Constructor
+        explicit exception(const char* message) :
+            std::runtime_error(message) {
+        }
+
+        /// Constructor
+        explicit exception(const std::string& message) :
+            std::runtime_error(message) {
+        }
+
+    }; // class exception
+
+    /**
+     * This exception is thrown when vector tile encoding isn't valid according
+     * to the vector tile specification.
+     */
+    class format_exception : public exception {
+
+    public:
+
+        /// Constructor
+        explicit format_exception(const char* message) :
+            exception(message) {
+        }
+
+        /// Constructor
+        explicit format_exception(const std::string& message) :
+            exception(message) {
+        }
+
+    }; // class format_exception
+
+    /**
+     * This exception is thrown when a geometry encoding isn't valid according
+     * to the vector tile specification.
+     */
+    class geometry_exception : public format_exception {
+
+    public:
+
+        /// Constructor
+        explicit geometry_exception(const char* message) :
+            format_exception(message) {
+        }
+
+        /// Constructor
+        explicit geometry_exception(const std::string& message) :
+            format_exception(message) {
+        }
+
+    }; // class geometry_exception
+
+    /**
+     * This exception is thrown when a property value is accessed using the
+     * wrong type.
+     */
+    class type_exception : public exception {
+
+    public:
+
+        /// Constructor
+        explicit type_exception() :
+            exception("wrong property value type") {
+        }
+
+    }; // class type_exception
+
+    /**
+     * This exception is thrown when an unknown version number is found in the
+     * layer.
+     */
+    class version_exception : public exception {
+
+    public:
+
+        /// Constructor
+        explicit version_exception(const uint32_t version) :
+            exception(std::string{"unknown vector tile version: "} +
+                      std::to_string(version)) {
+        }
+
+    }; // version_exception
+
+    /**
+     * This exception is thrown when an index into the key or value table
+     * in a layer is out of range. This can only happen if the tile data is
+     * invalid.
+     */
+    class out_of_range_exception : public exception {
+
+    public:
+
+        /// Constructor
+        explicit out_of_range_exception(const uint32_t index) :
+            exception(std::string{"index out of range: "} +
+                      std::to_string(index)) {
+        }
+
+    }; // out_of_range_exception
+
+} // namespace vtzero
+
+#endif // VTZERO_EXCEPTION_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/feature.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/feature.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/feature.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,315 @@
+#ifndef VTZERO_FEATURE_HPP
+#define VTZERO_FEATURE_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file feature.hpp
+ *
+ * @brief Contains the feature class.
+ */
+
+#include "exception.hpp"
+#include "property.hpp"
+#include "property_value.hpp"
+#include "types.hpp"
+
+#include <protozero/pbf_message.hpp>
+
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <utility>
+
+namespace vtzero {
+
+    class layer;
+
+    /**
+     * A feature according to spec 4.2.
+     *
+     * Note that a feature will internally contain a pointer to the layer it
+     * came from. The layer has to stay valid as long as the feature is used.
+     */
+    class feature {
+
+        using uint32_it_range = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>;
+
+        const layer* m_layer = nullptr;
+        uint64_t m_id = 0; // defaults to 0, see https://github.com/mapbox/vector-tile-spec/blob/master/2.1/vector_tile.proto#L32
+        uint32_it_range m_properties{};
+        protozero::pbf_reader::const_uint32_iterator m_property_iterator{};
+        std::size_t m_num_properties = 0;
+        data_view m_geometry{};
+        GeomType m_geometry_type = GeomType::UNKNOWN; // defaults to UNKNOWN, see https://github.com/mapbox/vector-tile-spec/blob/master/2.1/vector_tile.proto#L41
+        bool m_has_id = false;
+
+    public:
+
+        /**
+         * Construct an invalid feature object.
+         */
+        feature() = default;
+
+        /**
+         * Construct a feature object.
+         *
+         * @throws format_exception if the layer data is ill-formed.
+         */
+        feature(const layer* layer, const data_view data) :
+            m_layer(layer) {
+            vtzero_assert(layer);
+            vtzero_assert(data.data());
+
+            protozero::pbf_message<detail::pbf_feature> reader{data};
+
+            while (reader.next()) {
+                switch (reader.tag_and_type()) {
+                    case protozero::tag_and_type(detail::pbf_feature::id, protozero::pbf_wire_type::varint):
+                        m_id = reader.get_uint64();
+                        m_has_id = true;
+                        break;
+                    case protozero::tag_and_type(detail::pbf_feature::tags, protozero::pbf_wire_type::length_delimited):
+                        if (m_properties.begin() != protozero::pbf_reader::const_uint32_iterator{}) {
+                            throw format_exception{"Feature has more than one tags field"};
+                        }
+                        m_properties = reader.get_packed_uint32();
+                        m_property_iterator = m_properties.begin();
+                        break;
+                    case protozero::tag_and_type(detail::pbf_feature::type, protozero::pbf_wire_type::varint): {
+                            const auto type = reader.get_enum();
+                            // spec 4.3.4 "Geometry Types"
+                            if (type < 0 || type > 3) {
+                                throw format_exception{"Unknown geometry type (spec 4.3.4)"};
+                            }
+                            m_geometry_type = static_cast<GeomType>(type);
+                        }
+                        break;
+                    case protozero::tag_and_type(detail::pbf_feature::geometry, protozero::pbf_wire_type::length_delimited):
+                        if (!m_geometry.empty()) {
+                            throw format_exception{"Feature has more than one geometry field"};
+                        }
+                        m_geometry = reader.get_view();
+                        break;
+                    default:
+                        reader.skip(); // ignore unknown fields
+                }
+            }
+
+            // spec 4.2 "A feature MUST contain a geometry field."
+            if (m_geometry.empty()) {
+                throw format_exception{"Missing geometry field in feature (spec 4.2)"};
+            }
+
+            const auto size = m_properties.size();
+            if (size % 2 != 0) {
+                throw format_exception{"unpaired property key/value indexes (spec 4.4)"};
+            }
+            m_num_properties = size / 2;
+        }
+
+        /**
+         * Is this a valid feature? Valid features are those not created from
+         * the default constructor.
+         *
+         * Complexity: Constant.
+         */
+        bool valid() const noexcept {
+            return m_geometry.data() != nullptr;
+        }
+
+        /**
+         * Is this a valid feature? Valid features are those not created from
+         * the default constructor.
+         *
+         * Complexity: Constant.
+         */
+        explicit operator bool() const noexcept {
+            return valid();
+        }
+
+        /**
+         * The ID of this feature. According to the spec IDs should be unique
+         * in a layer if they are set (spec 4.2).
+         *
+         * Complexity: Constant.
+         *
+         * Always returns 0 for invalid features.
+         */
+        uint64_t id() const noexcept {
+            return m_id;
+        }
+
+        /**
+         * Does this feature have an ID?
+         *
+         * Complexity: Constant.
+         *
+         * Always returns false for invalid features.
+         */
+        bool has_id() const noexcept {
+            return m_has_id;
+        }
+
+        /**
+         * The geometry type of this feature.
+         *
+         * Complexity: Constant.
+         *
+         * Always returns GeomType::UNKNOWN for invalid features.
+         */
+        GeomType geometry_type() const noexcept {
+            return m_geometry_type;
+        }
+
+        /**
+         * Get the geometry of this feature.
+         *
+         * Complexity: Constant.
+         *
+         * @pre @code valid() @endcode
+         */
+        vtzero::geometry geometry() const noexcept {
+            vtzero_assert_in_noexcept_function(valid());
+            return {m_geometry, m_geometry_type};
+        }
+
+        /**
+         * Returns true if this feature doesn't have any properties.
+         *
+         * Complexity: Constant.
+         *
+         * Always returns true for invalid features.
+         */
+        bool empty() const noexcept {
+            return m_num_properties == 0;
+        }
+
+        /**
+         * Returns the number of properties in this feature.
+         *
+         * Complexity: Constant.
+         *
+         * Always returns 0 for invalid features.
+         */
+        std::size_t num_properties() const noexcept {
+            return m_num_properties;
+        }
+
+        /**
+         * Get the next property in this feature.
+         *
+         * Complexity: Constant.
+         *
+         * @returns The next property or the invalid property if there are no
+         *          more properties.
+         * @throws format_exception if the feature data is ill-formed.
+         * @throws any protozero exception if the protobuf encoding is invalid.
+         * @pre @code valid() @endcode
+         */
+        property next_property();
+
+        /**
+         * Get the indexes into the key/value table for the next property in
+         * this feature.
+         *
+         * Complexity: Constant.
+         *
+         * @returns The next index_value_pair or an invalid index_value_pair
+         *          if there are no more properties.
+         * @throws format_exception if the feature data is ill-formed.
+         * @throws out_of_range_exception if the key or value index is not
+         *         within the range of indexes in the layer key/value table.
+         * @throws any protozero exception if the protobuf encoding is invalid.
+         * @pre @code valid() @endcode
+         */
+        index_value_pair next_property_indexes();
+
+        /**
+         * Reset the property iterator. The next time next_property() or
+         * next_property_indexes() is called, it will begin from the first
+         * property again.
+         *
+         * Complexity: Constant.
+         *
+         * @pre @code valid() @endcode
+         */
+        void reset_property() noexcept {
+            vtzero_assert_in_noexcept_function(valid());
+            m_property_iterator = m_properties.begin();
+        }
+
+        /**
+         * Call a function for each property of this feature.
+         *
+         * @tparam TFunc The type of the function. It must take a single
+         *         argument of type property&& and return a bool. If the
+         *         function returns false, the iteration will be stopped.
+         * @param func The function to call.
+         * @returns true if the iteration was completed and false otherwise.
+         * @pre @code valid() @endcode
+         */
+        template <typename TFunc>
+        bool for_each_property(TFunc&& func) const;
+
+        /**
+         * Call a function for each key/value index of this feature.
+         *
+         * @tparam TFunc The type of the function. It must take a single
+         *         argument of type index_value_pair&& and return a bool.
+         *         If the function returns false, the iteration will be stopped.
+         * @param func The function to call.
+         * @returns true if the iteration was completed and false otherwise.
+         * @pre @code valid() @endcode
+         */
+        template <typename TFunc>
+        bool for_each_property_indexes(TFunc&& func) const;
+
+    }; // class feature
+
+    /**
+     * Create some kind of mapping from property keys to property values.
+     *
+     * This can be used to read all properties into a std::map or similar
+     * object.
+     *
+     * @tparam TMap Map type (std::map, std::unordered_map, ...) Must support
+     *              the emplace() method.
+     * @tparam TKey Key type, usually the key of the map type. The data_view
+     *              of the property key is converted to this type before
+     *              adding it to the map.
+     * @tparam TValue Value type, usally the value of the map type. The
+     *                property_value is converted to this type before
+     *                adding it to the map.
+     * @tparam TMapping A struct derived from property_value_mapping with the
+     *         mapping for vtzero property value types to TValue-constructing
+     *         types. (See convert_property_value() for details.)
+     * @param feature The feature to get the properties from.
+     * @returns An object of type TMap with all the properties.
+     * @pre @code feature.valid() @endcode
+     */
+    template <typename TMap,
+              typename TKey = typename TMap::key_type,
+              typename TValue = typename TMap::mapped_type,
+              typename TMapping = property_value_mapping>
+    TMap create_properties_map(const vtzero::feature& feature) {
+        TMap map;
+
+        feature.for_each_property([&map](const property& p) {
+            map.emplace(TKey(p.key()), convert_property_value<TValue, TMapping>(p.value()));
+            return true;
+        });
+
+        return map;
+    }
+
+} // namespace vtzero
+
+#endif // VTZERO_FEATURE_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/feature_builder_impl.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/feature_builder_impl.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/feature_builder_impl.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,122 @@
+#ifndef VTZERO_FEATURE_BUILDER_IMPL_HPP
+#define VTZERO_FEATURE_BUILDER_IMPL_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file feature_builder_impl.hpp
+ *
+ * @brief Contains classes internal to the builder.
+ */
+
+#include "builder_impl.hpp"
+#include "encoded_property_value.hpp"
+#include "geometry.hpp"
+#include "property.hpp"
+#include "property_value.hpp"
+
+#include <utility>
+
+namespace vtzero {
+
+    namespace detail {
+
+        class feature_builder_base {
+
+            layer_builder_impl* m_layer;
+
+            void add_key_internal(index_value idx) {
+                vtzero_assert(idx.valid());
+                m_pbf_tags.add_element(idx.value());
+            }
+
+            template <typename T>
+            void add_key_internal(T&& key) {
+                add_key_internal(m_layer->add_key(data_view{std::forward<T>(key)}));
+            }
+
+            void add_value_internal(index_value idx) {
+                vtzero_assert(idx.valid());
+                m_pbf_tags.add_element(idx.value());
+            }
+
+            void add_value_internal(property_value value) {
+                add_value_internal(m_layer->add_value(value));
+            }
+
+            template <typename T>
+            void add_value_internal(T&& value) {
+                encoded_property_value v{std::forward<T>(value)};
+                add_value_internal(m_layer->add_value(v));
+            }
+
+        protected:
+
+            protozero::pbf_builder<detail::pbf_feature> m_feature_writer;
+            protozero::packed_field_uint32 m_pbf_tags;
+
+            explicit feature_builder_base(layer_builder_impl* layer) :
+                m_layer(layer),
+                m_feature_writer(layer->message(), detail::pbf_layer::features) {
+            }
+
+            ~feature_builder_base() noexcept = default;
+
+            feature_builder_base(const feature_builder_base&) = delete; // NOLINT(hicpp-use-equals-delete, modernize-use-equals-delete)
+
+            feature_builder_base& operator=(const feature_builder_base&) = delete; // NOLINT(hicpp-use-equals-delete, modernize-use-equals-delete)
+                                                                                   // The check wants these functions to be public...
+
+            feature_builder_base(feature_builder_base&&) noexcept = default;
+
+            feature_builder_base& operator=(feature_builder_base&&) noexcept = default;
+
+            void set_id_impl(uint64_t id) {
+                m_feature_writer.add_uint64(detail::pbf_feature::id, id);
+            }
+
+            void add_property_impl(const property& property) {
+                add_key_internal(property.key());
+                add_value_internal(property.value());
+            }
+
+            void add_property_impl(const index_value_pair idxs) {
+                add_key_internal(idxs.key());
+                add_value_internal(idxs.value());
+            }
+
+            template <typename TKey, typename TValue>
+            void add_property_impl(TKey&& key, TValue&& value) {
+                add_key_internal(std::forward<TKey>(key));
+                add_value_internal(std::forward<TValue>(value));
+            }
+
+            void do_commit() {
+                if (m_pbf_tags.valid()) {
+                    m_pbf_tags.commit();
+                }
+                m_feature_writer.commit();
+                m_layer->increment_feature_count();
+            }
+
+            void do_rollback() {
+                if (m_pbf_tags.valid()) {
+                    m_pbf_tags.rollback();
+                }
+                m_feature_writer.rollback();
+            }
+
+        }; // class feature_builder_base
+
+    } // namespace detail
+
+} // namespace vtzero
+
+#endif // VTZERO_FEATURE_BUILDER_IMPL_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/geometry.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/geometry.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/geometry.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,444 @@
+#ifndef VTZERO_GEOMETRY_HPP
+#define VTZERO_GEOMETRY_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file geometry.hpp
+ *
+ * @brief Contains classes and functions related to geometry handling.
+ */
+
+#include "exception.hpp"
+#include "types.hpp"
+
+#include <protozero/pbf_reader.hpp>
+
+#include <cstdint>
+#include <limits>
+#include <utility>
+
+namespace vtzero {
+
+    /// A simple point class
+    struct point {
+
+        /// X coordinate
+        int32_t x = 0;
+
+        /// Y coordinate
+        int32_t y = 0;
+
+        /// Default construct to 0 coordinates
+        constexpr point() noexcept = default;
+
+        /// Constructor
+        constexpr point(int32_t x_, int32_t y_) noexcept :
+            x(x_),
+            y(y_) {
+        }
+
+    }; // struct point
+
+    /**
+     * Type of a polygon ring. This can either be "outer", "inner", or
+     * "invalid". Invalid is used when the area of the ring is 0.
+     */
+    enum class ring_type {
+        outer = 0,
+        inner = 1,
+        invalid = 2
+    }; // enum class ring_type
+
+    /**
+     * Helper function to create a point from any type that has members x
+     * and y.
+     *
+     * If your point type doesn't have members x any y, you can overload this
+     * function for your type and it will be used by vtzero.
+     */
+    template <typename TPoint>
+    point create_vtzero_point(const TPoint& p) noexcept {
+        return {p.x, p.y};
+    }
+
+    /// Points are equal if their coordinates are
+    inline constexpr bool operator==(const point a, const point b) noexcept {
+        return a.x == b.x && a.y == b.y;
+    }
+
+    /// Points are not equal if their coordinates aren't
+    inline constexpr bool operator!=(const point a, const point b) noexcept {
+        return !(a == b);
+    }
+
+    namespace detail {
+
+        /// The command id type as specified in the vector tile spec
+        enum class CommandId : uint32_t {
+            MOVE_TO = 1,
+            LINE_TO = 2,
+            CLOSE_PATH = 7
+        };
+
+        inline constexpr uint32_t command_integer(CommandId id, const uint32_t count) noexcept {
+            return (static_cast<uint32_t>(id) & 0x7u) | (count << 3u);
+        }
+
+        inline constexpr uint32_t command_move_to(const uint32_t count) noexcept {
+            return command_integer(CommandId::MOVE_TO, count);
+        }
+
+        inline constexpr uint32_t command_line_to(const uint32_t count) noexcept {
+            return command_integer(CommandId::LINE_TO, count);
+        }
+
+        inline constexpr uint32_t command_close_path() noexcept {
+            return command_integer(CommandId::CLOSE_PATH, 1);
+        }
+
+        inline constexpr uint32_t get_command_id(const uint32_t command_integer) noexcept {
+            return command_integer & 0x7u;
+        }
+
+        inline constexpr uint32_t get_command_count(const uint32_t command_integer) noexcept {
+            return command_integer >> 3u;
+        }
+
+        // The maximum value for the command count according to the spec.
+        inline constexpr uint32_t max_command_count() noexcept {
+            return get_command_count(std::numeric_limits<uint32_t>::max());
+        }
+
+        inline constexpr int64_t det(const point a, const point b) noexcept {
+            return static_cast<int64_t>(a.x) * static_cast<int64_t>(b.y) -
+                   static_cast<int64_t>(b.x) * static_cast<int64_t>(a.y);
+        }
+
+        template <typename T, typename Enable = void>
+        struct get_result {
+
+            using type = void;
+
+            template <typename TGeomHandler>
+            void operator()(TGeomHandler&& /*geom_handler*/) const noexcept {
+            }
+
+        };
+
+        template <typename T>
+        struct get_result<T, typename std::enable_if<!std::is_same<decltype(std::declval<T>().result()), void>::value>::type> {
+
+            using type = decltype(std::declval<T>().result());
+
+            template <typename TGeomHandler>
+            type operator()(TGeomHandler&& geom_handler) {
+                return std::forward<TGeomHandler>(geom_handler).result();
+            }
+
+        };
+
+        /**
+         * Decode a geometry as specified in spec 4.3 from a sequence of 32 bit
+         * unsigned integers. This templated base class can be instantiated
+         * with a different iterator type for testing than for normal use.
+         */
+        template <typename TIterator>
+        class geometry_decoder {
+
+        public:
+
+            using iterator_type = TIterator;
+
+        private:
+
+            iterator_type m_it;
+            iterator_type m_end;
+
+            point m_cursor{0, 0};
+
+            // maximum value for m_count before we throw an exception
+            uint32_t m_max_count;
+
+            /**
+             * The current count value is set from the CommandInteger and
+             * then counted down with each next_point() call. So it must be
+             * greater than 0 when next_point() is called and 0 when
+             * next_command() is called.
+             */
+            uint32_t m_count = 0;
+
+        public:
+
+            geometry_decoder(iterator_type begin, iterator_type end, std::size_t max) :
+                m_it(begin),
+                m_end(end),
+                m_max_count(static_cast<uint32_t>(max)) {
+                vtzero_assert(max <= detail::max_command_count());
+            }
+
+            uint32_t count() const noexcept {
+                return m_count;
+            }
+
+            bool done() const noexcept {
+                return m_it == m_end;
+            }
+
+            bool next_command(const CommandId expected_command_id) {
+                vtzero_assert(m_count == 0);
+
+                if (m_it == m_end) {
+                    return false;
+                }
+
+                const auto command_id = get_command_id(*m_it);
+                if (command_id != static_cast<uint32_t>(expected_command_id)) {
+                    throw geometry_exception{std::string{"expected command "} +
+                                             std::to_string(static_cast<uint32_t>(expected_command_id)) +
+                                             " but got " +
+                                             std::to_string(command_id)};
+                }
+
+                if (expected_command_id == CommandId::CLOSE_PATH) {
+                    // spec 4.3.3.3 "A ClosePath command MUST have a command count of 1"
+                    if (get_command_count(*m_it) != 1) {
+                        throw geometry_exception{"ClosePath command count is not 1"};
+                    }
+                } else {
+                    m_count = get_command_count(*m_it);
+                    if (m_count > m_max_count) {
+                        throw geometry_exception{"count too large"};
+                    }
+                }
+
+                ++m_it;
+
+                return true;
+            }
+
+            point next_point() {
+                vtzero_assert(m_count > 0);
+
+                if (m_it == m_end || std::next(m_it) == m_end) {
+                    throw geometry_exception{"too few points in geometry"};
+                }
+
+                // spec 4.3.2 "A ParameterInteger is zigzag encoded"
+                int64_t x = protozero::decode_zigzag32(*m_it++);
+                int64_t y = protozero::decode_zigzag32(*m_it++);
+
+                // x and y are int64_t so this addition can never overflow
+                x += m_cursor.x;
+                y += m_cursor.y;
+
+                // The cast is okay, because a valid vector tile can never
+                // contain values that would overflow here and we don't care
+                // what happens to invalid tiles here.
+                m_cursor.x = static_cast<int32_t>(x);
+                m_cursor.y = static_cast<int32_t>(y);
+
+                --m_count;
+
+                return m_cursor;
+            }
+
+            template <typename TGeomHandler>
+            typename detail::get_result<TGeomHandler>::type decode_point(TGeomHandler&& geom_handler) {
+                // spec 4.3.4.2 "MUST consist of a single MoveTo command"
+                if (!next_command(CommandId::MOVE_TO)) {
+                    throw geometry_exception{"expected MoveTo command (spec 4.3.4.2)"};
+                }
+
+                // spec 4.3.4.2 "command count greater than 0"
+                if (count() == 0) {
+                    throw geometry_exception{"MoveTo command count is zero (spec 4.3.4.2)"};
+                }
+
+                std::forward<TGeomHandler>(geom_handler).points_begin(count());
+                while (count() > 0) {
+                    std::forward<TGeomHandler>(geom_handler).points_point(next_point());
+                }
+
+                // spec 4.3.4.2 "MUST consist of of a single ... command"
+                if (!done()) {
+                    throw geometry_exception{"additional data after end of geometry (spec 4.3.4.2)"};
+                }
+
+                std::forward<TGeomHandler>(geom_handler).points_end();
+
+                return detail::get_result<TGeomHandler>{}(std::forward<TGeomHandler>(geom_handler));
+            }
+
+            template <typename TGeomHandler>
+            typename detail::get_result<TGeomHandler>::type decode_linestring(TGeomHandler&& geom_handler) {
+                // spec 4.3.4.3 "1. A MoveTo command"
+                while (next_command(CommandId::MOVE_TO)) {
+                    // spec 4.3.4.3 "with a command count of 1"
+                    if (count() != 1) {
+                        throw geometry_exception{"MoveTo command count is not 1 (spec 4.3.4.3)"};
+                    }
+
+                    const auto first_point = next_point();
+
+                    // spec 4.3.4.3 "2. A LineTo command"
+                    if (!next_command(CommandId::LINE_TO)) {
+                        throw geometry_exception{"expected LineTo command (spec 4.3.4.3)"};
+                    }
+
+                    // spec 4.3.4.3 "with a command count greater than 0"
+                    if (count() == 0) {
+                        throw geometry_exception{"LineTo command count is zero (spec 4.3.4.3)"};
+                    }
+
+                    std::forward<TGeomHandler>(geom_handler).linestring_begin(count() + 1);
+
+                    std::forward<TGeomHandler>(geom_handler).linestring_point(first_point);
+                    while (count() > 0) {
+                        std::forward<TGeomHandler>(geom_handler).linestring_point(next_point());
+                    }
+
+                    std::forward<TGeomHandler>(geom_handler).linestring_end();
+                }
+
+                return detail::get_result<TGeomHandler>{}(std::forward<TGeomHandler>(geom_handler));
+            }
+
+            template <typename TGeomHandler>
+            typename detail::get_result<TGeomHandler>::type decode_polygon(TGeomHandler&& geom_handler) {
+                // spec 4.3.4.4 "1. A MoveTo command"
+                while (next_command(CommandId::MOVE_TO)) {
+                    // spec 4.3.4.4 "with a command count of 1"
+                    if (count() != 1) {
+                        throw geometry_exception{"MoveTo command count is not 1 (spec 4.3.4.4)"};
+                    }
+
+                    int64_t sum = 0;
+                    const point start_point = next_point();
+                    point last_point = start_point;
+
+                    // spec 4.3.4.4 "2. A LineTo command"
+                    if (!next_command(CommandId::LINE_TO)) {
+                        throw geometry_exception{"expected LineTo command (spec 4.3.4.4)"};
+                    }
+
+                    std::forward<TGeomHandler>(geom_handler).ring_begin(count() + 2);
+
+                    std::forward<TGeomHandler>(geom_handler).ring_point(start_point);
+
+                    while (count() > 0) {
+                        const point p = next_point();
+                        sum += detail::det(last_point, p);
+                        last_point = p;
+                        std::forward<TGeomHandler>(geom_handler).ring_point(p);
+                    }
+
+                    // spec 4.3.4.4 "3. A ClosePath command"
+                    if (!next_command(CommandId::CLOSE_PATH)) {
+                        throw geometry_exception{"expected ClosePath command (4.3.4.4)"};
+                    }
+
+                    sum += detail::det(last_point, start_point);
+
+                    std::forward<TGeomHandler>(geom_handler).ring_point(start_point);
+
+                    std::forward<TGeomHandler>(geom_handler).ring_end(sum > 0 ? ring_type::outer :
+                                                                      sum < 0 ? ring_type::inner : ring_type::invalid);
+                }
+
+                return detail::get_result<TGeomHandler>{}(std::forward<TGeomHandler>(geom_handler));
+            }
+
+        }; // class geometry_decoder
+
+    } // namespace detail
+
+    /**
+     * Decode a point geometry.
+     *
+     * @tparam TGeomHandler Handler class. See tutorial for details.
+     * @param geometry The geometry as returned by feature.geometry().
+     * @param geom_handler An object of TGeomHandler.
+     * @throws geometry_error If there is a problem with the geometry.
+     * @pre Geometry must be a point geometry.
+     */
+    template <typename TGeomHandler>
+    typename detail::get_result<TGeomHandler>::type decode_point_geometry(const geometry& geometry, TGeomHandler&& geom_handler) {
+        vtzero_assert(geometry.type() == GeomType::POINT);
+        detail::geometry_decoder<decltype(geometry.begin())> decoder{geometry.begin(), geometry.end(), geometry.data().size() / 2};
+        return decoder.decode_point(std::forward<TGeomHandler>(geom_handler));
+    }
+
+    /**
+     * Decode a linestring geometry.
+     *
+     * @tparam TGeomHandler Handler class. See tutorial for details.
+     * @param geometry The geometry as returned by feature.geometry().
+     * @param geom_handler An object of TGeomHandler.
+     * @returns whatever geom_handler.result() returns if that function exists,
+     *          void otherwise
+     * @throws geometry_error If there is a problem with the geometry.
+     * @pre Geometry must be a linestring geometry.
+     */
+    template <typename TGeomHandler>
+    typename detail::get_result<TGeomHandler>::type decode_linestring_geometry(const geometry& geometry, TGeomHandler&& geom_handler) {
+        vtzero_assert(geometry.type() == GeomType::LINESTRING);
+        detail::geometry_decoder<decltype(geometry.begin())> decoder{geometry.begin(), geometry.end(), geometry.data().size() / 2};
+        return decoder.decode_linestring(std::forward<TGeomHandler>(geom_handler));
+    }
+
+    /**
+     * Decode a polygon geometry.
+     *
+     * @tparam TGeomHandler Handler class. See tutorial for details.
+     * @param geometry The geometry as returned by feature.geometry().
+     * @param geom_handler An object of TGeomHandler.
+     * @returns whatever geom_handler.result() returns if that function exists,
+     *          void otherwise
+     * @throws geometry_error If there is a problem with the geometry.
+     * @pre Geometry must be a polygon geometry.
+     */
+    template <typename TGeomHandler>
+    typename detail::get_result<TGeomHandler>::type decode_polygon_geometry(const geometry& geometry, TGeomHandler&& geom_handler) {
+        vtzero_assert(geometry.type() == GeomType::POLYGON);
+        detail::geometry_decoder<decltype(geometry.begin())> decoder{geometry.begin(), geometry.end(), geometry.data().size() / 2};
+        return decoder.decode_polygon(std::forward<TGeomHandler>(geom_handler));
+    }
+
+    /**
+     * Decode a geometry.
+     *
+     * @tparam TGeomHandler Handler class. See tutorial for details.
+     * @param geometry The geometry as returned by feature.geometry().
+     * @param geom_handler An object of TGeomHandler.
+     * @returns whatever geom_handler.result() returns if that function exists,
+     *          void otherwise
+     * @throws geometry_error If the geometry has type UNKNOWN of if there is
+     *                        a problem with the geometry.
+     */
+    template <typename TGeomHandler>
+    typename detail::get_result<TGeomHandler>::type decode_geometry(const geometry& geometry, TGeomHandler&& geom_handler) {
+        detail::geometry_decoder<decltype(geometry.begin())> decoder{geometry.begin(), geometry.end(), geometry.data().size() / 2};
+        switch (geometry.type()) {
+            case GeomType::POINT:
+                return decoder.decode_point(std::forward<TGeomHandler>(geom_handler));
+            case GeomType::LINESTRING:
+                return decoder.decode_linestring(std::forward<TGeomHandler>(geom_handler));
+            case GeomType::POLYGON:
+                return decoder.decode_polygon(std::forward<TGeomHandler>(geom_handler));
+            default:
+                break;
+        }
+        throw geometry_exception{"unknown geometry type"};
+    }
+
+} // namespace vtzero
+
+#endif // VTZERO_GEOMETRY_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/index.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/index.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/index.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,264 @@
+#ifndef VTZERO_INDEX_HPP
+#define VTZERO_INDEX_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file index.hpp
+ *
+ * @brief Contains classes for indexing the key/value tables inside layers.
+ */
+
+#include "builder.hpp"
+#include "types.hpp"
+
+#include <array>
+#include <cstdint>
+#include <vector>
+
+namespace vtzero {
+
+    /**
+     * Used to store the mapping between property keys and the index value
+     * in the table stored in a layer.
+     *
+     * @tparam TMap The map class to use (std::map, std::unordered_map or
+     *         something compatible).
+     */
+    template <template <typename...> class TMap>
+    class key_index {
+
+        layer_builder& m_builder;
+
+        TMap<std::string, index_value> m_index;
+
+    public:
+
+        /**
+         * Construct index.
+         *
+         * @param builder The layer we are building containing the key table
+         *        we are creating the index for.
+         */
+        explicit key_index(layer_builder& builder) :
+            m_builder(builder) {
+        }
+
+        /**
+         * Get the index value for the specified key. If the key was not in
+         * the table, it will be added.
+         *
+         * @param key The key to store.
+         * @returns The index value of they key.
+         */
+        index_value operator()(const data_view key) {
+            std::string text(key);
+            const auto it = m_index.find(text);
+            if (it == m_index.end()) {
+                const auto idx = m_builder.add_key_without_dup_check(key);
+                m_index.emplace(std::move(text), idx);
+                return idx;
+            }
+            return it->second;
+        }
+
+    }; // class key_index
+
+    /**
+     * Used to store the mapping between property values and the index value
+     * in the table stored in a layer. Stores the values in their original
+     * form (as type TExternal) which is more efficient than the way
+     * value_index_internal does it, but you need an instance of this class
+     * for each value type you use.
+     *
+     * @tparam TInternal The type used in the vector tile to encode the value.
+     *         Must be one of string/float/double/int/uint/sint/bool_value_type.
+     * @tparam TExternal The type for the value used by the user of this class.
+     * @tparam TMap The map class to use (std::map, std::unordered_map or
+     *         something compatible).
+     */
+    template <typename TInternal, typename TExternal, template <typename...> class TMap>
+    class value_index {
+
+        layer_builder& m_builder;
+
+        TMap<TExternal, index_value> m_index;
+
+    public:
+
+        /**
+         * Construct index.
+         *
+         * @param builder The layer we are building containing the value
+         *        table we are creating the index for.
+         */
+        explicit value_index(layer_builder& builder) :
+            m_builder(builder) {
+        }
+
+        /**
+         * Get the index value for the specified value. If the value was not in
+         * the table, it will be added.
+         *
+         * @param value The value to store.
+         * @returns The index value of they value.
+         */
+        index_value operator()(const TExternal& value) {
+            const auto it = m_index.find(value);
+            if (it == m_index.end()) {
+                const auto idx = m_builder.add_value_without_dup_check(encoded_property_value{TInternal{value}});
+                m_index.emplace(value, idx);
+                return idx;
+            }
+            return it->second;
+        }
+
+    }; // class value_index
+
+    /**
+     * Used to store the mapping between bool property values and the index
+     * value in the table stored in a layer.
+     *
+     * This is the most efficient index if you know that your property values
+     * are bools.
+     */
+    class value_index_bool {
+
+        layer_builder& m_builder;
+
+        std::array<index_value, 2> m_index;
+
+    public:
+
+        /**
+         * Construct index.
+         *
+         * @param builder The layer we are building containing the value
+         *        table we are creating the index for.
+         */
+        explicit value_index_bool(layer_builder& builder) :
+            m_builder(builder) {
+        }
+
+        /**
+         * Get the index value for the specified value. If the value was not in
+         * the table, it will be added.
+         *
+         * @param value The value to store.
+         * @returns The index value of they value.
+         */
+        index_value operator()(const bool value) {
+            auto& idx = m_index[static_cast<std::size_t>(value)]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
+            if (!idx.valid()) {
+                idx = m_builder.add_value_without_dup_check(encoded_property_value{value});
+            }
+            return idx;
+        }
+
+    }; // class value_index_bool
+
+    /**
+     * Used to store the mapping between small unsigned int property values and
+     * the index value in the table stored in a layer.
+     *
+     * This is the most efficient index if you know that your property values
+     * are densly used small unsigned integers. This is usually the case for
+     * enums.
+     *
+     * Interally a simple vector<index_value> is used and the value is used
+     * as is to look up the index value in the vector.
+     */
+    class value_index_small_uint {
+
+        layer_builder& m_builder;
+
+        std::vector<index_value> m_index;
+
+    public:
+
+        /**
+         * Construct index.
+         *
+         * @param builder The layer we are building containing the value
+         *        table we are creating the index for.
+         */
+        explicit value_index_small_uint(layer_builder& builder) :
+            m_builder(builder) {
+        }
+
+        /**
+         * Get the index value for the specified value. If the value was not in
+         * the table, it will be added.
+         *
+         * @param value The value to store.
+         * @returns The index value of they value.
+         */
+        index_value operator()(const uint16_t value) {
+            if (value >= m_index.size()) {
+                m_index.resize(value + 1);
+            }
+            if (!m_index[value].valid()) {
+                m_index[value] = m_builder.add_value_without_dup_check(encoded_property_value{value});
+            }
+            return m_index[value];
+        }
+
+    }; // class value_index_small_uint
+
+    /**
+     * Used to store the mapping between property values and the index value
+     * in the table stored in a layer. Stores the values in the already
+     * encoded form. This is simpler to use than the value_index class, but
+     * has a higher overhead.
+     *
+     * @tparam TMap The map class to use (std::map, std::unordered_map or
+     *         something compatible).
+     */
+    template <template <typename...> class TMap>
+    class value_index_internal {
+
+        layer_builder& m_builder;
+
+        TMap<encoded_property_value, index_value> m_index;
+
+    public:
+
+        /**
+         * Construct index.
+         *
+         * @param builder The layer we are building containing the value
+         *        table we are creating the index for.
+         */
+        explicit value_index_internal(layer_builder& builder) :
+            m_builder(builder) {
+        }
+
+        /**
+         * Get the index value for the specified value. If the value was not in
+         * the table, it will be added.
+         *
+         * @param value The value to store.
+         * @returns The index value of they value.
+         */
+        index_value operator()(const encoded_property_value& value) {
+            const auto it = m_index.find(value);
+            if (it == m_index.end()) {
+                const auto idx = m_builder.add_value_without_dup_check(value);
+                m_index.emplace(value, idx);
+                return idx;
+            }
+            return it->second;
+        }
+
+    }; // class value_index_internal
+
+} // namespace vtzero
+
+#endif // VTZERO_INDEX_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/layer.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/layer.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/layer.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,512 @@
+#ifndef VTZERO_LAYER_HPP
+#define VTZERO_LAYER_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file layer.hpp
+ *
+ * @brief Contains the layer class.
+ */
+
+#include "exception.hpp"
+#include "feature.hpp"
+#include "geometry.hpp"
+#include "property_value.hpp"
+#include "types.hpp"
+
+#include <protozero/pbf_message.hpp>
+
+#include <cstdint>
+#include <iterator>
+#include <vector>
+
+namespace vtzero {
+
+    /**
+     * A layer according to spec 4.1. It contains a version, the extent,
+     * and a name. For the most efficient way to access the features in this
+     * layer call next_feature() until it returns an invalid feature:
+     *
+     * @code
+     *   std::string data = ...;
+     *   vector_tile tile{data};
+     *   layer = tile.next_layer();
+     *   while (auto feature = layer.next_feature()) {
+     *     ...
+     *   }
+     * @endcode
+     *
+     * If you know the ID of a feature, you can get it directly with
+     * @code
+     *   layer.get_feature_by_id(7);
+     * @endcode
+     *
+     * Note that the layer class uses mutable members inside to cache the
+     * key and value tables. It can not be used safely in several threads
+     * at once!
+     */
+    class layer {
+
+        data_view m_data{};
+        uint32_t m_version = 1; // defaults to 1, see https://github.com/mapbox/vector-tile-spec/blob/master/2.1/vector_tile.proto#L55
+        uint32_t m_extent = 4096; // defaults to 4096, see https://github.com/mapbox/vector-tile-spec/blob/master/2.1/vector_tile.proto#L70
+        std::size_t m_num_features = 0;
+        data_view m_name{};
+        protozero::pbf_message<detail::pbf_layer> m_layer_reader{m_data};
+        mutable std::vector<data_view> m_key_table;
+        mutable std::vector<property_value> m_value_table;
+        mutable std::size_t m_key_table_size = 0;
+        mutable std::size_t m_value_table_size = 0;
+
+        void initialize_tables() const {
+            m_key_table.reserve(m_key_table_size);
+            m_key_table_size = 0;
+
+            m_value_table.reserve(m_value_table_size);
+            m_value_table_size = 0;
+
+            protozero::pbf_message<detail::pbf_layer> reader{m_data};
+            while (reader.next()) {
+                switch (reader.tag_and_type()) {
+                    case protozero::tag_and_type(detail::pbf_layer::keys, protozero::pbf_wire_type::length_delimited):
+                        m_key_table.push_back(reader.get_view());
+                        break;
+                    case protozero::tag_and_type(detail::pbf_layer::values, protozero::pbf_wire_type::length_delimited):
+                        m_value_table.emplace_back(reader.get_view());
+                        break;
+                    default:
+                        reader.skip(); // ignore unknown fields
+                }
+            }
+        }
+
+    public:
+
+        /**
+         * Construct an invalid layer object.
+         */
+        layer() = default;
+
+        /**
+         * Construct a layer object. This is usually not something done in
+         * user code, because layers are created by the tile_iterator.
+         *
+         * @throws format_exception if the layer data is ill-formed.
+         * @throws version_exception if the layer contains an unsupported version
+         *                           number (only version 1 and 2 are supported)
+         * @throws any protozero exception if the protobuf encoding is invalid.
+         */
+        explicit layer(const data_view data) :
+            m_data(data) {
+            protozero::pbf_message<detail::pbf_layer> reader{data};
+            while (reader.next()) {
+                switch (reader.tag_and_type()) {
+                    case protozero::tag_and_type(detail::pbf_layer::version, protozero::pbf_wire_type::varint):
+                        m_version = reader.get_uint32();
+                        break;
+                    case protozero::tag_and_type(detail::pbf_layer::name, protozero::pbf_wire_type::length_delimited):
+                        m_name = reader.get_view();
+                        break;
+                    case protozero::tag_and_type(detail::pbf_layer::features, protozero::pbf_wire_type::length_delimited):
+                        reader.skip(); // ignore features for now
+                        ++m_num_features;
+                        break;
+                    case protozero::tag_and_type(detail::pbf_layer::keys, protozero::pbf_wire_type::length_delimited):
+                        reader.skip();
+                        ++m_key_table_size;
+                        break;
+                    case protozero::tag_and_type(detail::pbf_layer::values, protozero::pbf_wire_type::length_delimited):
+                        reader.skip();
+                        ++m_value_table_size;
+                        break;
+                    case protozero::tag_and_type(detail::pbf_layer::extent, protozero::pbf_wire_type::varint):
+                        m_extent = reader.get_uint32();
+                        break;
+                    default:
+                        throw format_exception{"unknown field in layer (tag=" +
+                                               std::to_string(static_cast<uint32_t>(reader.tag())) +
+                                               ", type=" +
+                                               std::to_string(static_cast<uint32_t>(reader.wire_type())) +
+                                               ")"};
+                }
+            }
+
+            // This library can only handle version 1 and 2.
+            if (m_version < 1 || m_version > 2) {
+                throw version_exception{m_version};
+            }
+
+            // 4.1 "A layer MUST contain a name field."
+            if (m_name.data() == nullptr) {
+                throw format_exception{"missing name field in layer (spec 4.1)"};
+            }
+        }
+
+        /**
+         * Is this a valid layer? Valid layers are those not created from the
+         * default constructor.
+         */
+        bool valid() const noexcept {
+            return m_data.data() != nullptr;
+        }
+
+        /**
+         * Is this a valid layer? Valid layers are those not created from the
+         * default constructor.
+         */
+        explicit operator bool() const noexcept {
+            return valid();
+        }
+
+        /**
+         * Get a reference to the raw data this layer is created from.
+         */
+        data_view data() const noexcept {
+            return m_data;
+        }
+
+        /**
+         * Return the name of the layer.
+         *
+         * @pre @code valid() @endcode
+         */
+        data_view name() const noexcept {
+            vtzero_assert_in_noexcept_function(valid());
+
+            return m_name;
+        }
+
+        /**
+         * Return the version of this layer.
+         *
+         * @pre @code valid() @endcode
+         */
+        std::uint32_t version() const noexcept {
+            vtzero_assert_in_noexcept_function(valid());
+
+            return m_version;
+        }
+
+        /**
+         * Return the extent of this layer.
+         *
+         * @pre @code valid() @endcode
+         */
+        std::uint32_t extent() const noexcept {
+            vtzero_assert_in_noexcept_function(valid());
+
+            return m_extent;
+        }
+
+        /**
+         * Does this layer contain any features?
+         *
+         * Complexity: Constant.
+         */
+        bool empty() const noexcept {
+            return m_num_features == 0;
+        }
+
+        /**
+         * The number of features in this layer.
+         *
+         * Complexity: Constant.
+         */
+        std::size_t num_features() const noexcept {
+            return m_num_features;
+        }
+
+        /**
+         * Return a reference to the key table.
+         *
+         * Complexity: Amortized constant. First time the table is needed
+         *             it needs to be created.
+         *
+         * @pre @code valid() @endcode
+         */
+        const std::vector<data_view>& key_table() const {
+            vtzero_assert(valid());
+
+            if (m_key_table_size > 0) {
+                initialize_tables();
+            }
+            return m_key_table;
+        }
+
+        /**
+         * Return a reference to the value table.
+         *
+         * Complexity: Amortized constant. First time the table is needed
+         *             it needs to be created.
+         *
+         * @pre @code valid() @endcode
+         */
+        const std::vector<property_value>& value_table() const {
+            vtzero_assert(valid());
+
+            if (m_value_table_size > 0) {
+                initialize_tables();
+            }
+            return m_value_table;
+        }
+
+        /**
+         * Return the size of the key table. This returns the correct value
+         * whether the key table was already built or not.
+         *
+         * Complexity: Constant.
+         *
+         * @returns Size of the key table.
+         */
+        std::size_t key_table_size() const noexcept {
+            return m_key_table_size > 0 ? m_key_table_size : m_key_table.size();
+        }
+
+        /**
+         * Return the size of the value table. This returns the correct value
+         * whether the value table was already built or not.
+         *
+         * Complexity: Constant.
+         *
+         * @returns Size of the value table.
+         */
+        std::size_t value_table_size() const noexcept {
+            return m_value_table_size > 0 ? m_value_table_size : m_value_table.size();
+        }
+
+        /**
+         * Get the property key with the given index.
+         *
+         * Complexity: Amortized constant. First time the table is needed
+         *             it needs to be created.
+         *
+         * @throws out_of_range_exception if the index is out of range.
+         * @pre @code valid() @endcode
+         */
+        data_view key(index_value index) const {
+            vtzero_assert(valid());
+
+            const auto& table = key_table();
+            if (index.value() >= table.size()) {
+                throw out_of_range_exception{index.value()};
+            }
+
+            return table[index.value()];
+        }
+
+        /**
+         * Get the property value with the given index.
+         *
+         * Complexity: Amortized constant. First time the table is needed
+         *             it needs to be created.
+         *
+         * @throws out_of_range_exception if the index is out of range.
+         * @pre @code valid() @endcode
+         */
+        property_value value(index_value index) const {
+            vtzero_assert(valid());
+
+            const auto& table = value_table();
+            if (index.value() >= table.size()) {
+                throw out_of_range_exception{index.value()};
+            }
+
+            return table[index.value()];
+        }
+
+        /**
+         * Get the next feature in this layer.
+         *
+         * Note that the feature returned will internally contain a pointer to
+         * the layer it came from. The layer has to stay valid as long as the
+         * feature is used.
+         *
+         * Complexity: Constant.
+         *
+         * @returns The next feature or the invalid feature if there are no
+         *          more features.
+         * @throws format_exception if the layer data is ill-formed.
+         * @throws any protozero exception if the protobuf encoding is invalid.
+         * @pre @code valid() @endcode
+         */
+        feature next_feature() {
+            vtzero_assert(valid());
+
+            const bool has_next = m_layer_reader.next(detail::pbf_layer::features,
+                                                      protozero::pbf_wire_type::length_delimited);
+
+            return has_next ? feature{this, m_layer_reader.get_view()} : feature{};
+        }
+
+        /**
+         * Reset the feature iterator. The next time next_feature() is called,
+         * it will begin from the first feature again.
+         *
+         * Complexity: Constant.
+         *
+         * @pre @code valid() @endcode
+         */
+        void reset_feature() noexcept {
+            vtzero_assert_in_noexcept_function(valid());
+
+            m_layer_reader = protozero::pbf_message<detail::pbf_layer>{m_data};
+        }
+
+        /**
+         * Call a function for each feature in this layer.
+         *
+         * @tparam The type of the function. It must take a single argument
+         *         of type feature&& and return a bool. If the function returns
+         *         false, the iteration will be stopped.
+         * @param func The function to call.
+         * @returns true if the iteration was completed and false otherwise.
+         * @pre @code valid() @endcode
+         */
+        template <typename TFunc>
+        bool for_each_feature(TFunc&& func) const {
+            vtzero_assert(valid());
+
+            protozero::pbf_message<detail::pbf_layer> layer_reader{m_data};
+            while (layer_reader.next(detail::pbf_layer::features,
+                                     protozero::pbf_wire_type::length_delimited)) {
+                if (!std::forward<TFunc>(func)(feature{this, layer_reader.get_view()})) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        /**
+         * Get the feature with the specified ID. If there are several features
+         * with the same ID, it is undefined which one you'll get.
+         *
+         * Note that the feature returned will internally contain a pointer to
+         * the layer it came from. The layer has to stay valid as long as the
+         * feature is used.
+         *
+         * Complexity: Linear in the number of features.
+         *
+         * @param id The ID to look for.
+         * @returns Feature with the specified ID or the invalid feature if
+         *          there is no feature with this ID.
+         * @throws format_exception if the layer data is ill-formed.
+         * @throws any protozero exception if the protobuf encoding is invalid.
+         * @pre @code valid() @endcode
+         */
+        feature get_feature_by_id(uint64_t id) const {
+            vtzero_assert(valid());
+
+            protozero::pbf_message<detail::pbf_layer> layer_reader{m_data};
+            while (layer_reader.next(detail::pbf_layer::features, protozero::pbf_wire_type::length_delimited)) {
+                const auto feature_data = layer_reader.get_view();
+                protozero::pbf_message<detail::pbf_feature> feature_reader{feature_data};
+                if (feature_reader.next(detail::pbf_feature::id, protozero::pbf_wire_type::varint)) {
+                    if (feature_reader.get_uint64() == id) {
+                        return feature{this, feature_data};
+                    }
+                }
+            }
+
+            return feature{};
+        }
+
+    }; // class layer
+
+    inline property feature::next_property() {
+        const auto idxs = next_property_indexes();
+        property p{};
+        if (idxs.valid()) {
+            p = {m_layer->key(idxs.key()),
+                 m_layer->value(idxs.value())};
+        }
+        return p;
+    }
+
+    inline index_value_pair feature::next_property_indexes() {
+        vtzero_assert(valid());
+        if (m_property_iterator == m_properties.end()) {
+            return {};
+        }
+
+        const auto ki = *m_property_iterator++;
+        if (!index_value{ki}.valid()) {
+            throw out_of_range_exception{ki};
+        }
+
+        assert(m_property_iterator != m_properties.end());
+        const auto vi = *m_property_iterator++;
+        if (!index_value{vi}.valid()) {
+            throw out_of_range_exception{vi};
+        }
+
+        if (ki >= m_layer->key_table_size()) {
+            throw out_of_range_exception{ki};
+        }
+
+        if (vi >= m_layer->value_table_size()) {
+            throw out_of_range_exception{vi};
+        }
+
+        return {ki, vi};
+    }
+
+    template <typename TFunc>
+    bool feature::for_each_property(TFunc&& func) const {
+        vtzero_assert(valid());
+
+        for (auto it = m_properties.begin(); it != m_properties.end();) {
+            const uint32_t ki = *it++;
+            if (!index_value{ki}.valid()) {
+                throw out_of_range_exception{ki};
+            }
+
+            assert(it != m_properties.end());
+            const uint32_t vi = *it++;
+            if (!index_value{vi}.valid()) {
+                throw out_of_range_exception{vi};
+            }
+
+            if (!std::forward<TFunc>(func)(property{m_layer->key(ki), m_layer->value(vi)})) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    template <typename TFunc>
+    bool feature::for_each_property_indexes(TFunc&& func) const {
+        vtzero_assert(valid());
+
+        for (auto it = m_properties.begin(); it != m_properties.end();) {
+            const uint32_t ki = *it++;
+            if (!index_value{ki}.valid()) {
+                throw out_of_range_exception{ki};
+            }
+
+            assert(it != m_properties.end());
+            const uint32_t vi = *it++;
+            if (!index_value{vi}.valid()) {
+                throw out_of_range_exception{vi};
+            }
+
+            if (!std::forward<TFunc>(func)(index_value_pair{ki, vi})) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+} // namespace vtzero
+
+#endif // VTZERO_LAYER_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/output.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/output.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/output.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,64 @@
+#ifndef VTZERO_OUTPUT_HPP
+#define VTZERO_OUTPUT_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file output.hpp
+ *
+ * @brief Contains overloads of operator<< for basic vtzero types.
+ */
+
+#include <vtzero/geometry.hpp>
+#include <vtzero/types.hpp>
+
+#include <iosfwd>
+
+namespace vtzero {
+
+    /// Overload of the << operator for GeomType
+    template <typename TChar, typename TTraits>
+    std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const GeomType type) {
+        return out << geom_type_name(type);
+    }
+
+    /// Overload of the << operator for property_value_type
+    template <typename TChar, typename TTraits>
+    std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const property_value_type type) {
+        return out << property_value_type_name(type);
+    }
+
+    /// Overload of the << operator for index_value
+    template <typename TChar, typename TTraits>
+    std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const index_value index) {
+        if (index.valid()) {
+            return out << index.value();
+        }
+        return out << "invalid";
+    }
+
+    /// Overload of the << operator for index_value_pair
+    template <typename TChar, typename TTraits>
+    std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const index_value_pair index_pair) {
+        if (index_pair.valid()) {
+            return out << '[' << index_pair.key() << ',' << index_pair.value() << ']';
+        }
+        return out << "invalid";
+    }
+
+    /// Overload of the << operator for points
+    template <typename TChar, typename TTraits>
+    std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const point p) {
+        return out << '(' << p.x << ',' << p.y << ')';
+    }
+
+} // namespace vtzero
+
+#endif // VTZERO_OUTPUT_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,89 @@
+#ifndef VTZERO_PROPERTY_HPP
+#define VTZERO_PROPERTY_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file property.hpp
+ *
+ * @brief Contains the property class.
+ */
+
+#include "property_value.hpp"
+#include "types.hpp"
+
+namespace vtzero {
+
+    /**
+     * A view of a vector tile property (key and value).
+     *
+     * Doesn't hold any data itself, just views of the key and value.
+     */
+    class property {
+
+        data_view m_key{};
+        property_value m_value{};
+
+    public:
+
+        /**
+         * The default constructor creates an invalid (empty) property.
+         */
+        constexpr property() noexcept = default;
+
+        /**
+         * Create a (valid) property from a key and value.
+         */
+        constexpr property(const data_view key, const property_value value) noexcept :
+            m_key(key),
+            m_value(value) {
+        }
+
+        /**
+         * Is this a valid property? Properties are valid if they were
+         * constructed using the non-default constructor.
+         */
+        constexpr bool valid() const noexcept {
+            return m_key.data() != nullptr;
+        }
+
+        /**
+         * Is this a valid property? Properties are valid if they were
+         * constructed using the non-default constructor.
+         */
+        explicit constexpr operator bool() const noexcept {
+            return valid();
+        }
+
+        /// Return the property key.
+        constexpr data_view key() const noexcept {
+            return m_key;
+        }
+
+        /// Return the property value.
+        constexpr property_value value() const noexcept {
+            return m_value;
+        }
+
+    }; // class property
+
+    /// properties are equal if they contain the same key & value data.
+    inline constexpr bool operator==(const property& lhs, const property& rhs) noexcept {
+        return lhs.key() == rhs.key() && lhs.value() == rhs.value();
+    }
+
+    /// properties are unequal if they do not contain them same key and value data.
+    inline constexpr bool operator!=(const property& lhs, const property& rhs) noexcept {
+        return !(lhs == rhs);
+    }
+
+} // namespace vtzero
+
+#endif // VTZERO_PROPERTY_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property_mapper.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property_mapper.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property_mapper.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,103 @@
+#ifndef VTZERO_PROPERTY_MAPPER_HPP
+#define VTZERO_PROPERTY_MAPPER_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file property_mapper.hpp
+ *
+ * @brief Contains the property_mapper class.
+ */
+
+#include "builder.hpp"
+#include "layer.hpp"
+
+#include <vector>
+
+namespace vtzero {
+
+    /**
+     * Establishes a mapping between index values of properties of an existing
+     * layer and a new layer. Can be used when copying some features from an
+     * existing layer to a new layer.
+     */
+    class property_mapper {
+
+        const layer& m_layer;
+        layer_builder& m_layer_builder;
+
+        std::vector<index_value> m_keys;
+        std::vector<index_value> m_values;
+
+    public:
+
+        /**
+         * Construct the mapping between the specified layers
+         *
+         * @param layer The existing layer from which (some) properties will
+         *        be copied.
+         * @param layer_builder The new layer that is being created.
+         */
+        property_mapper(const layer& layer, layer_builder& layer_builder) :
+            m_layer(layer),
+            m_layer_builder(layer_builder) {
+            m_keys.resize(layer.key_table().size());
+            m_values.resize(layer.value_table().size());
+        }
+
+        /**
+         * Map the value index of a key.
+         *
+         * @param index The value index of the key in the existing table.
+         * @returns The value index of the same key in the new table.
+         */
+        index_value map_key(index_value index) {
+            auto& k = m_keys[index.value()];
+
+            if (!k.valid()) {
+                k = m_layer_builder.add_key_without_dup_check(m_layer.key(index));
+            }
+
+            return k;
+        }
+
+        /**
+         * Map the value index of a value.
+         *
+         * @param index The value index of the value in the existing table.
+         * @returns The value index of the same value in the new table.
+         */
+        index_value map_value(index_value index) {
+            auto& v = m_values[index.value()];
+
+            if (!v.valid()) {
+                v = m_layer_builder.add_value_without_dup_check(m_layer.value(index));
+            }
+
+            return v;
+        }
+
+        /**
+         * Map the value indexes of a key/value pair.
+         *
+         * @param idxs The value indexes of the key/value pair in the existing
+         *        table.
+         * @returns The value indexes of the same key/value pair in the new
+         *          table.
+         */
+        index_value_pair operator()(index_value_pair idxs) {
+            return {map_key(idxs.key()), map_value(idxs.value())};
+        }
+
+    }; // class property_mapper
+
+} // namespace vtzero
+
+#endif // VTZERO_PROPERTY_MAPPER_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property_value.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property_value.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/property_value.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,398 @@
+#ifndef VTZERO_PROPERTY_VALUE_HPP
+#define VTZERO_PROPERTY_VALUE_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file property_value.hpp
+ *
+ * @brief Contains the property_value class.
+ */
+
+#include "exception.hpp"
+#include "types.hpp"
+
+#include <protozero/pbf_message.hpp>
+
+#include <array>
+#include <cstdint>
+#include <cstring>
+#include <utility>
+
+namespace vtzero {
+
+    /**
+     * A view of a vector tile property value.
+     *
+     * Doesn't hold any data itself.
+     */
+    class property_value {
+
+        data_view m_value{};
+
+        static bool check_tag_and_type(protozero::pbf_tag_type tag, protozero::pbf_wire_type type) noexcept {
+            static constexpr const std::array<protozero::pbf_wire_type, 7> types{{
+                string_value_type::wire_type,
+                float_value_type::wire_type,
+                double_value_type::wire_type,
+                int_value_type::wire_type,
+                uint_value_type::wire_type,
+                sint_value_type::wire_type,
+                bool_value_type::wire_type,
+            }};
+
+            if (tag < 1 || tag > types.size()) {
+                return false;
+            }
+
+            return types[tag - 1] == type; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
+        }
+
+        static data_view get_value_impl(protozero::pbf_message<detail::pbf_value>& value_message, string_value_type /* dummy */) {
+            return value_message.get_view();
+        }
+
+        static float get_value_impl(protozero::pbf_message<detail::pbf_value>& value_message, float_value_type /* dummy */) {
+            return value_message.get_float();
+        }
+
+        static double get_value_impl(protozero::pbf_message<detail::pbf_value>& value_message, double_value_type /* dummy */) {
+            return value_message.get_double();
+        }
+
+        static int64_t get_value_impl(protozero::pbf_message<detail::pbf_value>& value_message, int_value_type /* dummy */) {
+            return value_message.get_int64();
+        }
+
+        static uint64_t get_value_impl(protozero::pbf_message<detail::pbf_value>& value_message, uint_value_type /* dummy */) {
+            return value_message.get_uint64();
+        }
+
+        static int64_t get_value_impl(protozero::pbf_message<detail::pbf_value>& value_message, sint_value_type /* dummy */) {
+            return value_message.get_sint64();
+        }
+
+        static bool get_value_impl(protozero::pbf_message<detail::pbf_value>& value_message, bool_value_type /* dummy */) {
+            return value_message.get_bool();
+        }
+
+        template <typename T>
+        typename T::type get_value() const {
+            vtzero_assert(valid());
+            protozero::pbf_message<detail::pbf_value> value_message{m_value};
+
+            typename T::type result{};
+            bool has_result = false;
+            while (value_message.next(T::pvtype, T::wire_type)) {
+                result = get_value_impl(value_message, T());
+                has_result = true;
+            }
+
+            if (has_result) {
+                return result;
+            }
+
+            throw type_exception{};
+        }
+
+    public:
+
+        /**
+         * The default constructor creates an invalid (empty) property_value.
+         */
+        constexpr property_value() noexcept = default;
+
+        /**
+         * Create a (valid) property_value from a data_view.
+         */
+        explicit constexpr property_value(const data_view value) noexcept :
+            m_value(value) {
+        }
+
+        /**
+         * Is this a valid property value? Property values are valid if they
+         * were constructed using the non-default constructor.
+         */
+        constexpr bool valid() const noexcept {
+            return m_value.data() != nullptr;
+        }
+
+        /**
+         * Get the type of this property.
+         *
+         * @pre @code valid() @endcode
+         * @throws format_exception if the encoding is invalid
+         */
+        property_value_type type() const {
+            vtzero_assert(valid());
+            protozero::pbf_message<detail::pbf_value> value_message{m_value};
+            if (value_message.next()) {
+                const auto tag_val = static_cast<protozero::pbf_tag_type>(value_message.tag());
+                if (!check_tag_and_type(tag_val, value_message.wire_type())) {
+                    throw format_exception{"illegal property value type"};
+                }
+                return value_message.tag();
+            }
+            throw format_exception{"missing tag value"};
+        }
+
+        /**
+         * Get the internal data_view this object was constructed with.
+         */
+        constexpr data_view data() const noexcept {
+            return m_value;
+        }
+
+        /**
+         * Get string value of this object.
+         *
+         * @pre @code valid() @endcode
+         * @throws type_exception if the type of this property value is
+         *                        something other than string.
+         */
+        data_view string_value() const {
+            return get_value<string_value_type>();
+        }
+
+        /**
+         * Get float value of this object.
+         *
+         * @pre @code valid() @endcode
+         * @throws type_exception if the type of this property value is
+         *                        something other than float.
+         */
+        float float_value() const {
+            return get_value<float_value_type>();
+        }
+
+        /**
+         * Get double value of this object.
+         *
+         * @pre @code valid() @endcode
+         * @throws type_exception if the type of this property value is
+         *                        something other than double.
+         */
+        double double_value() const {
+            return get_value<double_value_type>();
+        }
+
+        /**
+         * Get int value of this object.
+         *
+         * @pre @code valid() @endcode
+         * @throws type_exception if the type of this property value is
+         *                        something other than int.
+         */
+        std::int64_t int_value() const {
+            return get_value<int_value_type>();
+        }
+
+        /**
+         * Get uint value of this object.
+         *
+         * @pre @code valid() @endcode
+         * @throws type_exception if the type of this property value is
+         *                        something other than uint.
+         */
+        std::uint64_t uint_value() const {
+            return get_value<uint_value_type>();
+        }
+
+        /**
+         * Get sint value of this object.
+         *
+         * @pre @code valid() @endcode
+         * @throws type_exception if the type of this property value is
+         *                        something other than sint.
+         */
+        std::int64_t sint_value() const {
+            return get_value<sint_value_type>();
+        }
+
+        /**
+         * Get bool value of this object.
+         *
+         * @pre @code valid() @endcode
+         * @throws type_exception if the type of this property value is
+         *                        something other than bool.
+         */
+        bool bool_value() const {
+            return get_value<bool_value_type>();
+        }
+
+    }; // class property_value
+
+    /// property_values are equal if they contain the same data.
+    inline constexpr bool operator==(const property_value lhs, const property_value rhs) noexcept {
+        return lhs.data() == rhs.data();
+    }
+
+    /// property_values are unequal if they do not contain the same data.
+    inline constexpr bool operator!=(const property_value lhs, const property_value rhs) noexcept {
+        return lhs.data() != rhs.data();
+    }
+
+    /// property_values are ordered in the same way as the underlying data
+    inline bool operator<(const property_value lhs, const property_value rhs) noexcept {
+        return lhs.data() < rhs.data();
+    }
+
+    /// property_values are ordered in the same way as the underlying data
+    inline bool operator<=(const property_value lhs, const property_value rhs) noexcept {
+        return lhs.data() <= rhs.data();
+    }
+
+    /// property_values are ordered in the same way as the underlying data
+    inline bool operator>(const property_value lhs, const property_value rhs) noexcept {
+        return lhs.data() > rhs.data();
+    }
+
+    /// property_values are ordered in the same way as the underlying data
+    inline bool operator>=(const property_value lhs, const property_value rhs) noexcept {
+        return lhs.data() >= rhs.data();
+    }
+
+    /**
+     * Apply the value to a visitor.
+     *
+     * The visitor must have an overloaded call operator taking a single
+     * argument of each of the types data_view, float, double, int64_t,
+     * uint64_t, and bool. All call operators must return the same type which
+     * will be the return type of this function.
+     */
+    template <typename V>
+    decltype(std::declval<V>()(data_view{})) apply_visitor(V&& visitor, const property_value value) {
+        switch (value.type()) {
+            case property_value_type::string_value:
+                return std::forward<V>(visitor)(value.string_value());
+            case property_value_type::float_value:
+                return std::forward<V>(visitor)(value.float_value());
+            case property_value_type::double_value:
+                return std::forward<V>(visitor)(value.double_value());
+            case property_value_type::int_value:
+                return std::forward<V>(visitor)(value.int_value());
+            case property_value_type::uint_value:
+                return std::forward<V>(visitor)(value.uint_value());
+            case property_value_type::sint_value:
+                return std::forward<V>(visitor)(value.sint_value());
+            default: // case property_value_type::bool_value:
+                return std::forward<V>(visitor)(value.bool_value());
+        }
+    }
+
+    namespace detail {
+
+        template <typename TVariant, typename TMapping>
+        struct convert_visitor {
+
+            TVariant operator()(data_view value) const {
+                return TVariant(typename TMapping::string_type(value));
+            }
+
+            TVariant operator()(float value) const {
+                return TVariant(typename TMapping::float_type(value));
+            }
+
+            TVariant operator()(double value) const {
+                return TVariant(typename TMapping::double_type(value));
+            }
+
+            TVariant operator()(int64_t value) const {
+                return TVariant(typename TMapping::int_type(value));
+            }
+
+            TVariant operator()(uint64_t value) const {
+                return TVariant(typename TMapping::uint_type(value));
+            }
+
+            TVariant operator()(bool value) const {
+                return TVariant(typename TMapping::bool_type(value));
+            }
+
+        }; // struct convert_visitor
+
+    } // namespace detail
+
+    /**
+     * Default mapping between the different types of a property_value to
+     * the types needed for a variant. Derive from this class, overwrite
+     * the types you want and use that class as second template parameter
+     * in the convert_property_value class.
+     */
+    struct property_value_mapping {
+
+        /// mapping for string type
+        using string_type = std::string;
+
+        /// mapping for float type
+        using float_type = float;
+
+        /// mapping for double type
+        using double_type = double;
+
+        /// mapping for int type
+        using int_type = int64_t;
+
+        /// mapping for uint type
+        using uint_type = uint64_t;
+
+        /// mapping for bool type
+        using bool_type = bool;
+
+    }; // struct property_value_mapping
+
+    /**
+     * Convert a property_value to a different (usually variant-based)
+     * class.
+     *
+     * Usage: If you have a variant type like
+     *
+     * @code
+     *   using variant_type = boost::variant<std::string, float, double, int64_t, uint64_t, bool>;
+     * @endcode
+     *
+     * you can use
+     * @code
+     *   property_value x = ...;
+     *   auto v = convert_property_value<variant_type>(x);
+     * @endcode
+     *
+     * to convert the data.
+     *
+     * Usually your variant type has to support all of the following types:
+     * std::string, float, double, int64_t, uint64_t, and bool. If your type
+     * doesn't, you can add a second template parameter with a struct
+     * containing the mapping between the vtzero types and your types:
+     *
+     * @code
+     *   struct mapping : vtzero::property_value_mapping {
+     *     using float_type = double; // convert all floats to doubles
+     *     using bool_type = int; // convert all bools to ints
+     *     // use default types for the rest
+     *     // see the class vtzero::property_value_mapping for the defaults
+     *   };
+     *   property_value x = ...;
+     *   auto v = convert_property_value<variant_type, mapping>(x);
+     * @endcode
+     *
+     * @tparam TVariant The variant type to convert to.
+     * @tparam TMapping A struct derived from property_value_mapping with the
+     *         mapping for the types.
+     * @param value The property value to convert.
+     *
+     */
+    template <typename TVariant, typename TMapping = property_value_mapping>
+    TVariant convert_property_value(const property_value value) {
+        return apply_visitor(detail::convert_visitor<TVariant, TMapping>{}, value);
+    }
+
+} // namespace vtzero
+
+#endif // VTZERO_PROPERTY_VALUE_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/types.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/types.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/types.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,429 @@
+#ifndef VTZERO_TYPES_HPP
+#define VTZERO_TYPES_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+#include <protozero/pbf_reader.hpp>
+
+#include <cassert>
+
+// @cond internal
+// Wrappers for assert() used for testing
+#ifndef vtzero_assert
+# define vtzero_assert(x) assert(x)
+#endif
+#ifndef vtzero_assert_in_noexcept_function
+# define vtzero_assert_in_noexcept_function(x) assert(x)
+#endif
+// @endcond
+
+/**
+ * @file types.hpp
+ *
+ * @brief Contains the declaration of low-level types.
+ */
+
+/**
+ * @brief All parts of the vtzero header-only library are in this namespace.
+ */
+namespace vtzero {
+
+    /**
+     * Using data_view class from protozero. See the protozero documentation
+     * on how to change this to use a different implementation.
+     * https://github.com/mapbox/protozero/blob/master/doc/advanced.md#protozero_use_view
+     */
+    using data_view = protozero::data_view;
+
+    // based on https://github.com/mapbox/vector-tile-spec/blob/master/2.1/vector_tile.proto
+
+    /// The geometry type as specified in the vector tile spec
+    enum class GeomType {
+        UNKNOWN    = 0,
+        POINT      = 1,
+        LINESTRING = 2,
+        POLYGON    = 3
+    };
+
+    /**
+     * Return the name of a GeomType (for debug output etc.)
+     */
+    inline const char* geom_type_name(GeomType type) noexcept {
+        static const char* names[] = {
+            "unknown", "point", "linestring", "polygon"
+        };
+        return names[static_cast<int>(type)]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
+    }
+
+    /// The property value type as specified in the vector tile spec
+    enum class property_value_type : protozero::pbf_tag_type {
+        string_value = 1,
+        float_value  = 2,
+        double_value = 3,
+        int_value    = 4,
+        uint_value   = 5,
+        sint_value   = 6,
+        bool_value   = 7
+    };
+
+    /**
+     * Return the name of a property value type (for debug output etc.)
+     */
+    inline const char* property_value_type_name(property_value_type type) noexcept {
+        static const char* names[] = {
+            "", "string", "float", "double", "int", "uint", "sint", "bool"
+        };
+        return names[static_cast<int>(type)]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
+    }
+
+    namespace detail {
+
+        enum class pbf_tile : protozero::pbf_tag_type {
+            layers = 3
+        };
+
+        enum class pbf_layer : protozero::pbf_tag_type {
+            name     =  1,
+            features =  2,
+            keys     =  3,
+            values   =  4,
+            extent   =  5,
+            version  = 15
+        };
+
+        enum class pbf_feature : protozero::pbf_tag_type {
+            id       = 1,
+            tags     = 2,
+            type     = 3,
+            geometry = 4
+        };
+
+        using pbf_value = property_value_type;
+
+    } // namespace detail
+
+    /// property value type holding a reference to a string
+    struct string_value_type {
+
+        /// the underlying storage type
+        using type = data_view;
+
+        /// @cond internal
+        constexpr static const property_value_type pvtype = property_value_type::string_value;
+        constexpr static const protozero::pbf_wire_type wire_type = protozero::pbf_wire_type::length_delimited;
+        /// @endcond
+
+        /// value
+        data_view value{};
+
+        /// Construct empty string_value_type
+        constexpr string_value_type() noexcept = default;
+
+        /// Construct string_value_type
+        explicit constexpr string_value_type(data_view v) :
+            value(v) {
+        }
+
+    }; // struct string_value_type
+
+    /// property value type holding a float
+    struct float_value_type {
+
+        /// the underlying storage type
+        using type = float;
+
+        /// @cond internal
+        constexpr static const property_value_type pvtype = property_value_type::float_value;
+        constexpr static const protozero::pbf_wire_type wire_type = protozero::pbf_wire_type::fixed32;
+        /// @endcond
+
+        /// value
+        float value = 0.0f;
+
+        /// Construct float_value_type with value 0.0
+        constexpr float_value_type() noexcept = default;
+
+        /// Construct float_value_type
+        explicit constexpr float_value_type(float v) :
+            value(v) {
+        }
+
+    }; // struct float_value_type
+
+    /// property value type holding a double
+    struct double_value_type {
+
+        /// the underlying storage type
+        using type = double;
+
+        /// @cond internal
+        constexpr static const property_value_type pvtype = property_value_type::double_value;
+        constexpr static const protozero::pbf_wire_type wire_type = protozero::pbf_wire_type::fixed64;
+        /// @endcond
+
+        /// value
+        double value = 0.0;
+
+        /// Construct double_value_type with value 0.0
+        constexpr double_value_type() noexcept = default;
+
+        /// Construct double_value_type
+        explicit constexpr double_value_type(double v) :
+            value(v) {
+        }
+
+    }; // struct double_value_type
+
+    /// property value type holding an int
+    struct int_value_type {
+
+        /// the underlying storage type
+        using type = int64_t;
+
+        /// @cond internal
+        constexpr static const property_value_type pvtype = property_value_type::int_value;
+        constexpr static const protozero::pbf_wire_type wire_type = protozero::pbf_wire_type::varint;
+        /// @endcond
+
+        /// value
+        int64_t value = 0;
+
+        /// Construct int_value_type with value 0
+        constexpr int_value_type() noexcept = default;
+
+        /// Construct int_value_type
+        explicit constexpr int_value_type(int64_t v) :
+            value(v) {
+        }
+
+    }; // struct int_value_type
+
+    /// property value type holding a uint
+    struct uint_value_type {
+
+        /// the underlying storage type
+        using type = uint64_t;
+
+        /// @cond internal
+        constexpr static const property_value_type pvtype = property_value_type::uint_value;
+        constexpr static const protozero::pbf_wire_type wire_type = protozero::pbf_wire_type::varint;
+        /// @endcond
+
+        /// value
+        uint64_t value = 0;
+
+        /// Construct uint_value_type with value 0
+        constexpr uint_value_type() noexcept = default;
+
+        /// Construct uint_value_type
+        explicit constexpr uint_value_type(uint64_t v) :
+            value(v) {
+        }
+
+    }; // struct uint_value_type
+
+    /// property value type holding an sint
+    struct sint_value_type {
+
+        /// the underlying storage type
+        using type = int64_t;
+
+        /// @cond internal
+        constexpr static const property_value_type pvtype = property_value_type::sint_value;
+        constexpr static const protozero::pbf_wire_type wire_type = protozero::pbf_wire_type::varint;
+        /// @endcond
+
+        /// value
+        int64_t value = 0;
+
+        /// Construct sint_value_type with value 0
+        constexpr sint_value_type() noexcept = default;
+
+        /// Construct sint_value_type
+        explicit constexpr sint_value_type(int64_t v) :
+            value(v) {
+        }
+
+    }; // struct sint_value_type
+
+    /// property value type holding a bool
+    struct bool_value_type {
+
+        /// the underlying storage type
+        using type = bool;
+
+        /// @cond internal
+        constexpr static const property_value_type pvtype = property_value_type::bool_value;
+        constexpr static const protozero::pbf_wire_type wire_type = protozero::pbf_wire_type::varint;
+        /// @endcond
+
+        /// value
+        bool value = false;
+
+        /// Construct bool_value_type with false value
+        constexpr bool_value_type() noexcept = default;
+
+        /// Construct bool_value_type
+        explicit constexpr bool_value_type(bool v) :
+            value(v) {
+        }
+
+    }; // struct bool_value_type
+
+    /**
+     * This class wraps the uint32_t used for looking up keys/values in the
+     * key/values tables.
+     */
+    class index_value {
+
+        static const uint32_t invalid_value = std::numeric_limits<uint32_t>::max();
+
+        uint32_t m_value = invalid_value;
+
+    public:
+
+        /// Default construct to an invalid value.
+        constexpr index_value() noexcept = default;
+
+        /// Construct with the given value.
+        constexpr index_value(uint32_t value) noexcept : // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
+            m_value(value) {
+        }
+
+        /**
+         * Is this index value valid? Index values are valid if they have
+         * been initialized with something other than the default constructor.
+         */
+        constexpr bool valid() const noexcept {
+            return m_value != invalid_value;
+        }
+
+        /**
+         * Get the value.
+         *
+         * @pre Must be valid.
+         */
+        uint32_t value() const noexcept {
+            vtzero_assert_in_noexcept_function(valid());
+            return m_value;
+        }
+
+    }; // class index_value
+
+    /// Index values are equal if their values are.
+    inline bool operator==(const index_value lhs, const index_value rhs) noexcept {
+        return lhs.value() == rhs.value();
+    }
+
+    /// Index values are not equal if their values are not equal.
+    inline bool operator!=(const index_value lhs, const index_value rhs) noexcept {
+        return lhs.value() != rhs.value();
+    }
+
+    /**
+     * This class holds two index_values, one for a key and one for a value.
+     */
+    class index_value_pair {
+
+        index_value m_key{};
+        index_value m_value{};
+
+    public:
+
+        /// Default construct to an invalid value.
+        constexpr index_value_pair() noexcept = default;
+
+        /// Construct with the given values.
+        constexpr index_value_pair(index_value key, index_value value) noexcept :
+            m_key(key),
+            m_value(value) {
+        }
+
+        /**
+         * Is this index value pair valid? Index values pairs are valid if
+         * both the key and the value index value are valid.
+         */
+        constexpr bool valid() const noexcept {
+            return m_key.valid() && m_value.valid();
+        }
+
+        /**
+         * Is this index value pair valid? Index values pairs are valid if
+         * both the key and the value index value are valid.
+         */
+        constexpr explicit operator bool() const noexcept {
+            return valid();
+        }
+
+        /// Get the key index value.
+        constexpr index_value key() const noexcept {
+            return m_key;
+        }
+
+        /// Get the value index value.
+        constexpr index_value value() const noexcept {
+            return m_value;
+        }
+
+    }; // class index_value_pair
+
+    /**
+     * The geometry class holds a geometry type and a reference to the data
+     * defining this geometry. To actually decode these geometries, use the
+     * decode_point_geometry(), decode_linestring_geometry(), and
+     * decode_polygon_geometry() classes.
+     */
+    class geometry {
+
+        data_view m_data{};
+        GeomType m_type = GeomType::UNKNOWN;
+
+    public:
+
+        /**
+         * A forward iterator yielding 32bit unsigned integers with the
+         * geometry encoded according to spec 4.3.
+         */
+        using const_iterator = protozero::pbf_reader::const_uint32_iterator;
+
+        /// Default construct to an invalid value.
+        constexpr geometry() noexcept = default;
+
+        /// Construct with the given values.
+        constexpr geometry(data_view data, GeomType type) noexcept :
+            m_data(data),
+            m_type(type) {
+        }
+
+        /// The data of this geometry
+        constexpr data_view data() const noexcept {
+            return m_data;
+        }
+
+        /// The type of this geometry
+        constexpr GeomType type() const noexcept {
+            return m_type;
+        }
+
+        /// Return iterator to the beginning of the data.
+        const_iterator begin() const noexcept {
+            return {m_data.data(), m_data.data() + m_data.size()};
+        }
+
+        /// Return iterator to one past the end of the data.
+        const_iterator end() const noexcept {
+            return {m_data.data() + m_data.size(), m_data.data() + m_data.size()};
+        }
+
+    }; // class geometry
+
+} // namespace vtzero
+
+#endif // VTZERO_TYPES_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/vector_tile.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/vector_tile.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/vector_tile.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,290 @@
+#ifndef VTZERO_VECTOR_TILE_HPP
+#define VTZERO_VECTOR_TILE_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file vector_tile.hpp
+ *
+ * @brief Contains the vector_tile class.
+ */
+
+#include "exception.hpp"
+#include "layer.hpp"
+#include "types.hpp"
+
+#include <protozero/pbf_message.hpp>
+
+#include <cstddef>
+#include <cstring>
+#include <iterator>
+#include <string>
+
+namespace vtzero {
+
+    /**
+     * A vector tile is basically nothing more than an ordered collection
+     * of named layers. For the most efficient way to access the layers,
+     * call next_layer() until it returns an invalid layer:
+     *
+     * @code
+     *   std::string data = ...;
+     *   vector_tile tile{data};
+     *   while (auto layer = tile.next_layer()) {
+     *     ...
+     *   }
+     * @endcode
+     *
+     * If you know the index of the layer, you can get it directly with
+     * @code
+     *   tile.get_layer(4);
+     * @endcode
+     *
+     * You can also access the layer by name:
+     * @code
+     *   tile.get_layer_by_name("foobar");
+     * @endcode
+     */
+    class vector_tile {
+
+        data_view m_data;
+        protozero::pbf_message<detail::pbf_tile> m_tile_reader;
+
+    public:
+
+        /**
+         * Construct the vector_tile from a data_view. The vector_tile object
+         * will keep a reference to the data referenced by the data_view. No
+         * copy of the data is created.
+         */
+        explicit vector_tile(const data_view data) noexcept :
+            m_data(data),
+            m_tile_reader(m_data) {
+        }
+
+        /**
+         * Construct the vector_tile from a string. The vector_tile object
+         * will keep a reference to the data referenced by the string. No
+         * copy of the data is created.
+         */
+        explicit vector_tile(const std::string& data) noexcept :
+            m_data(data.data(), data.size()),
+            m_tile_reader(m_data) {
+        }
+
+        /**
+         * Construct the vector_tile from a ptr and size. The vector_tile
+         * object will keep a reference to the data. No copy of the data is
+         * created.
+         */
+        vector_tile(const char* data, std::size_t size) noexcept :
+            m_data(data, size),
+            m_tile_reader(m_data) {
+        }
+
+        /**
+         * Is this vector tile empty?
+         *
+         * @returns true if there are no layers in this vector tile, false
+         *          otherwise
+         * Complexity: Constant.
+         */
+        bool empty() const noexcept {
+            return m_data.empty();
+        }
+
+        /**
+         * Return the number of layers in this tile.
+         *
+         * Complexity: Linear in the number of layers.
+         *
+         * @returns the number of layers in this tile
+         * @throws any protozero exception if the protobuf encoding is invalid.
+         */
+        std::size_t count_layers() const {
+            std::size_t size = 0;
+
+            protozero::pbf_message<detail::pbf_tile> tile_reader{m_data};
+            while (tile_reader.next(detail::pbf_tile::layers,
+                                    protozero::pbf_wire_type::length_delimited)) {
+                tile_reader.skip();
+                ++size;
+            }
+
+            return size;
+        }
+
+        /**
+         * Get the next layer in this tile.
+         *
+         * Complexity: Constant.
+         *
+         * @returns layer The next layer or the invalid layer if there are no
+         *                more layers.
+         * @throws format_exception if the tile data is ill-formed.
+         * @throws any protozero exception if the protobuf encoding is invalid.
+         */
+        layer next_layer() {
+            const bool has_next = m_tile_reader.next(detail::pbf_tile::layers,
+                                                     protozero::pbf_wire_type::length_delimited);
+
+            return has_next ? layer{m_tile_reader.get_view()} : layer{};
+        }
+
+        /**
+         * Reset the layer iterator. The next time next_layer() is called,
+         * it will begin from the first layer again.
+         *
+         * Complexity: Constant.
+         */
+        void reset_layer() noexcept {
+            m_tile_reader = protozero::pbf_message<detail::pbf_tile>{m_data};
+        }
+
+        /**
+         * Call a function for each layer in this tile.
+         *
+         * @tparam The type of the function. It must take a single argument
+         *         of type layer&& and return a bool. If the function returns
+         *         false, the iteration will be stopped.
+         * @param func The function to call.
+         * @returns true if the iteration was completed and false otherwise.
+         */
+        template <typename TFunc>
+        bool for_each_layer(TFunc&& func) const {
+            protozero::pbf_message<detail::pbf_tile> tile_reader{m_data};
+
+            while (tile_reader.next(detail::pbf_tile::layers,
+                                    protozero::pbf_wire_type::length_delimited)) {
+                if (!std::forward<TFunc>(func)(layer{tile_reader.get_view()})) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        /**
+         * Returns the layer with the specified zero-based index.
+         *
+         * Complexity: Linear in the number of layers.
+         *
+         * @returns The specified layer or the invalid layer if index is
+         *          larger than the number of layers.
+         * @throws format_exception if the tile data is ill-formed.
+         * @throws any protozero exception if the protobuf encoding is invalid.
+         */
+        layer get_layer(std::size_t index) const {
+            protozero::pbf_message<detail::pbf_tile> tile_reader{m_data};
+
+            while (tile_reader.next(detail::pbf_tile::layers,
+                                    protozero::pbf_wire_type::length_delimited)) {
+                if (index == 0) {
+                    return layer{tile_reader.get_view()};
+                }
+                tile_reader.skip();
+                --index;
+            }
+
+            return layer{};
+        }
+
+        /**
+         * Returns the layer with the specified name.
+         *
+         * Complexity: Linear in the number of layers.
+         *
+         * If there are several layers with the same name (which is against
+         * the spec 4.1 "A Vector Tile MUST NOT contain two or more layers
+         * whose name values are byte-for-byte identical.") it is unspecified
+         * which will be returned.
+         *
+         * @returns The specified layer or the invalid layer if there is no
+         *          layer with this name.
+         * @throws format_exception if the tile data is ill-formed.
+         * @throws any protozero exception if the protobuf encoding is invalid.
+         */
+        layer get_layer_by_name(const data_view name) const {
+            protozero::pbf_message<detail::pbf_tile> tile_reader{m_data};
+
+            while (tile_reader.next(detail::pbf_tile::layers,
+                                    protozero::pbf_wire_type::length_delimited)) {
+                const auto layer_data = tile_reader.get_view();
+                protozero::pbf_message<detail::pbf_layer> layer_reader{layer_data};
+                if (layer_reader.next(detail::pbf_layer::name,
+                                      protozero::pbf_wire_type::length_delimited)) {
+                    if (layer_reader.get_view() == name) {
+                        return layer{layer_data};
+                    }
+                } else {
+                    // 4.1 "A layer MUST contain a name field."
+                    throw format_exception{"missing name in layer (spec 4.1)"};
+                }
+            }
+
+            return layer{};
+        }
+
+        /**
+         * Returns the layer with the specified name.
+         *
+         * Complexity: Linear in the number of layers.
+         *
+         * If there are several layers with the same name (which is against
+         * the spec 4.1 "A Vector Tile MUST NOT contain two or more layers
+         * whose name values are byte-for-byte identical.") it is unspecified
+         * which will be returned.
+         *
+         * @returns The specified layer or the invalid layer if there is no
+         *          layer with this name.
+         * @throws format_exception if the tile data is ill-formed.
+         * @throws any protozero exception if the protobuf encoding is invalid.
+         */
+        layer get_layer_by_name(const std::string& name) const {
+            return get_layer_by_name(data_view{name.data(), name.size()});
+        }
+
+        /**
+         * Returns the layer with the specified name.
+         *
+         * Complexity: Linear in the number of layers.
+         *
+         * If there are several layers with the same name (which is against
+         * the spec 4.1 "A Vector Tile MUST NOT contain two or more layers
+         * whose name values are byte-for-byte identical.") it is unspecified
+         * which will be returned.
+         *
+         * @returns The specified layer or the invalid layer if there is no
+         *          layer with this name.
+         * @throws format_exception if the tile data is ill-formed.
+         * @throws any protozero exception if the protobuf encoding is invalid.
+         */
+        layer get_layer_by_name(const char* name) const {
+            return get_layer_by_name(data_view{name, std::strlen(name)});
+        }
+
+    }; // class vector_tile
+
+    /**
+     * Helper function to determine whether some data could represent a
+     * vector tile. This takes advantage of the fact that the first byte of
+     * a vector tile is always 0x1a. It can't be 100% reliable though, because
+     * some other data could still contain that byte.
+     *
+     * @returns false if this is definitely no vector tile
+     *          true if this could be a vector tile
+     */
+    inline bool is_vector_tile(const data_view data) noexcept {
+        return !data.empty() && data.data()[0] == 0x1a;
+    }
+
+} // namespace vtzero
+
+#endif // VTZERO_VECTOR_TILE_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/version.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/version.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include/vtzero/version.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,36 @@
+#ifndef VTZERO_VERSION_HPP
+#define VTZERO_VERSION_HPP
+
+/*****************************************************************************
+
+vtzero - Tiny and fast vector tile decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/vtzero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file version.hpp
+ *
+ * @brief Contains the version number macros for the vtzero library.
+ */
+
+/// The major version number
+#define VTZERO_VERSION_MAJOR 1
+
+/// The minor version number
+#define VTZERO_VERSION_MINOR 0
+
+/// The patch number
+#define VTZERO_VERSION_PATCH 3
+
+/// The complete version number
+#define VTZERO_VERSION_CODE                                      \
+    (VTZERO_VERSION_MAJOR * 10000 + VTZERO_VERSION_MINOR * 100 + \
+     VTZERO_VERSION_PATCH)
+
+/// Version number as string
+#define VTZERO_VERSION_STRING "1.0.3"
+
+#endif // VTZERO_VERSION_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/include-external/clara.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/include-external/clara.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/include-external/clara.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,1239 @@
+// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// See https://github.com/philsquared/Clara for more details
+
+// Clara v1.1.2
+
+#ifndef CLARA_HPP_INCLUDED
+#define CLARA_HPP_INCLUDED
+
+#ifndef CLARA_CONFIG_CONSOLE_WIDTH
+#define CLARA_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+#ifndef CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
+#define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+// ----------- #included from clara_textflow.hpp -----------
+
+// TextFlowCpp
+//
+// A single-header library for wrapping and laying out basic text, by Phil Nash
+//
+// This work is licensed under the BSD 2-Clause license.
+// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause
+//
+// This project is hosted at https://github.com/philsquared/textflowcpp
+
+#ifndef CLARA_TEXTFLOW_HPP_INCLUDED
+#define CLARA_TEXTFLOW_HPP_INCLUDED
+
+#include <cassert>
+#include <ostream>
+#include <sstream>
+#include <vector>
+
+#ifndef CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
+#define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+
+namespace clara { namespace TextFlow {
+
+    inline auto isWhitespace( char c ) -> bool {
+        static std::string chars = " \t\n\r";
+        return chars.find( c ) != std::string::npos;
+    }
+    inline auto isBreakableBefore( char c ) -> bool {
+        static std::string chars = "[({<|";
+        return chars.find( c ) != std::string::npos;
+    }
+    inline auto isBreakableAfter( char c ) -> bool {
+        static std::string chars = "])}>.,:;*+-=&/\\";
+        return chars.find( c ) != std::string::npos;
+    }
+
+    class Columns;
+
+    class Column {
+        std::vector<std::string> m_strings;
+        size_t m_width = CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
+        size_t m_indent = 0;
+        size_t m_initialIndent = std::string::npos;
+
+    public:
+        class iterator {
+            friend Column;
+
+            Column const& m_column;
+            size_t m_stringIndex = 0;
+            size_t m_pos = 0;
+
+            size_t m_len = 0;
+            size_t m_end = 0;
+            bool m_suffix = false;
+
+            iterator( Column const& column, size_t stringIndex )
+            :   m_column( column ),
+                m_stringIndex( stringIndex )
+            {}
+
+            auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
+
+            auto isBoundary( size_t at ) const -> bool {
+                assert( at > 0 );
+                assert( at <= line().size() );
+
+                return at == line().size() ||
+                       ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) ||
+                       isBreakableBefore( line()[at] ) ||
+                       isBreakableAfter( line()[at-1] );
+            }
+
+            void calcLength() {
+                assert( m_stringIndex < m_column.m_strings.size() );
+
+                m_suffix = false;
+                auto width = m_column.m_width-indent();
+                m_end = m_pos;
+                while( m_end < line().size() && line()[m_end] != '\n' )
+                    ++m_end;
+
+                if( m_end < m_pos + width ) {
+                    m_len = m_end - m_pos;
+                }
+                else {
+                    size_t len = width;
+                    while (len > 0 && !isBoundary(m_pos + len))
+                        --len;
+                    while (len > 0 && isWhitespace( line()[m_pos + len - 1] ))
+                        --len;
+
+                    if (len > 0) {
+                        m_len = len;
+                    } else {
+                        m_suffix = true;
+                        m_len = width - 1;
+                    }
+                }
+            }
+
+            auto indent() const -> size_t {
+                auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
+                return initial == std::string::npos ? m_column.m_indent : initial;
+            }
+
+            auto addIndentAndSuffix(std::string const &plain) const -> std::string {
+                return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain);
+            }
+
+        public:
+            explicit iterator( Column const& column ) : m_column( column ) {
+                assert( m_column.m_width > m_column.m_indent );
+                assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent );
+                calcLength();
+                if( m_len == 0 )
+                    m_stringIndex++; // Empty string
+            }
+
+            auto operator *() const -> std::string {
+                assert( m_stringIndex < m_column.m_strings.size() );
+                assert( m_pos <= m_end );
+                if( m_pos + m_column.m_width < m_end )
+                    return addIndentAndSuffix(line().substr(m_pos, m_len));
+                else
+                    return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos));
+            }
+
+            auto operator ++() -> iterator& {
+                m_pos += m_len;
+                if( m_pos < line().size() && line()[m_pos] == '\n' )
+                    m_pos += 1;
+                else
+                    while( m_pos < line().size() && isWhitespace( line()[m_pos] ) )
+                        ++m_pos;
+
+                if( m_pos == line().size() ) {
+                    m_pos = 0;
+                    ++m_stringIndex;
+                }
+                if( m_stringIndex < m_column.m_strings.size() )
+                    calcLength();
+                return *this;
+            }
+            auto operator ++(int) -> iterator {
+                iterator prev( *this );
+                operator++();
+                return prev;
+            }
+
+            auto operator ==( iterator const& other ) const -> bool {
+                return
+                    m_pos == other.m_pos &&
+                    m_stringIndex == other.m_stringIndex &&
+                    &m_column == &other.m_column;
+            }
+            auto operator !=( iterator const& other ) const -> bool {
+                return !operator==( other );
+            }
+        };
+        using const_iterator = iterator;
+
+        explicit Column( std::string const& text ) { m_strings.push_back( text ); }
+
+        auto width( size_t newWidth ) -> Column& {
+            assert( newWidth > 0 );
+            m_width = newWidth;
+            return *this;
+        }
+        auto indent( size_t newIndent ) -> Column& {
+            m_indent = newIndent;
+            return *this;
+        }
+        auto initialIndent( size_t newIndent ) -> Column& {
+            m_initialIndent = newIndent;
+            return *this;
+        }
+
+        auto width() const -> size_t { return m_width; }
+        auto begin() const -> iterator { return iterator( *this ); }
+        auto end() const -> iterator { return { *this, m_strings.size() }; }
+
+        inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) {
+            bool first = true;
+            for( auto line : col ) {
+                if( first )
+                    first = false;
+                else
+                    os << "\n";
+                os <<  line;
+            }
+            return os;
+        }
+
+        auto operator + ( Column const& other ) -> Columns;
+
+        auto toString() const -> std::string {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+    };
+
+    class Spacer : public Column {
+
+    public:
+        explicit Spacer( size_t spaceWidth ) : Column( "" ) {
+            width( spaceWidth );
+        }
+    };
+
+    class Columns {
+        std::vector<Column> m_columns;
+
+    public:
+
+        class iterator {
+            friend Columns;
+            struct EndTag {};
+
+            std::vector<Column> const& m_columns;
+            std::vector<Column::iterator> m_iterators;
+            size_t m_activeIterators;
+
+            iterator( Columns const& columns, EndTag )
+            :   m_columns( columns.m_columns ),
+                m_activeIterators( 0 )
+            {
+                m_iterators.reserve( m_columns.size() );
+
+                for( auto const& col : m_columns )
+                    m_iterators.push_back( col.end() );
+            }
+
+        public:
+            explicit iterator( Columns const& columns )
+            :   m_columns( columns.m_columns ),
+                m_activeIterators( m_columns.size() )
+            {
+                m_iterators.reserve( m_columns.size() );
+
+                for( auto const& col : m_columns )
+                    m_iterators.push_back( col.begin() );
+            }
+
+            auto operator ==( iterator const& other ) const -> bool {
+                return m_iterators == other.m_iterators;
+            }
+            auto operator !=( iterator const& other ) const -> bool {
+                return m_iterators != other.m_iterators;
+            }
+            auto operator *() const -> std::string {
+                std::string row, padding;
+
+                for( size_t i = 0; i < m_columns.size(); ++i ) {
+                    auto width = m_columns[i].width();
+                    if( m_iterators[i] != m_columns[i].end() ) {
+                        std::string col = *m_iterators[i];
+                        row += padding + col;
+                        if( col.size() < width )
+                            padding = std::string( width - col.size(), ' ' );
+                        else
+                            padding = "";
+                    }
+                    else {
+                        padding += std::string( width, ' ' );
+                    }
+                }
+                return row;
+            }
+            auto operator ++() -> iterator& {
+                for( size_t i = 0; i < m_columns.size(); ++i ) {
+                    if (m_iterators[i] != m_columns[i].end())
+                        ++m_iterators[i];
+                }
+                return *this;
+            }
+            auto operator ++(int) -> iterator {
+                iterator prev( *this );
+                operator++();
+                return prev;
+            }
+        };
+        using const_iterator = iterator;
+
+        auto begin() const -> iterator { return iterator( *this ); }
+        auto end() const -> iterator { return { *this, iterator::EndTag() }; }
+
+        auto operator += ( Column const& col ) -> Columns& {
+            m_columns.push_back( col );
+            return *this;
+        }
+        auto operator + ( Column const& col ) -> Columns {
+            Columns combined = *this;
+            combined += col;
+            return combined;
+        }
+
+        inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) {
+
+            bool first = true;
+            for( auto line : cols ) {
+                if( first )
+                    first = false;
+                else
+                    os << "\n";
+                os << line;
+            }
+            return os;
+        }
+
+        auto toString() const -> std::string {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+    };
+
+    inline auto Column::operator + ( Column const& other ) -> Columns {
+        Columns cols;
+        cols += *this;
+        cols += other;
+        return cols;
+    }
+}} // namespace clara::TextFlow
+
+#endif // CLARA_TEXTFLOW_HPP_INCLUDED
+
+// ----------- end of #include from clara_textflow.hpp -----------
+// ........... back in clara.hpp
+
+
+#include <memory>
+#include <set>
+#include <algorithm>
+
+#if !defined(CLARA_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )
+#define CLARA_PLATFORM_WINDOWS
+#endif
+
+namespace clara {
+namespace detail {
+
+    // Traits for extracting arg and return type of lambdas (for single argument lambdas)
+    template<typename L>
+    struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};
+
+    template<typename ClassT, typename ReturnT, typename... Args>
+    struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {
+        static const bool isValid = false;
+    };
+
+    template<typename ClassT, typename ReturnT, typename ArgT>
+    struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
+        static const bool isValid = true;
+        using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
+        using ReturnType = ReturnT;
+    };
+
+    class TokenStream;
+
+    // Transport for raw args (copied from main args, or supplied via init list for testing)
+    class Args {
+        friend TokenStream;
+        std::string m_exeName;
+        std::vector<std::string> m_args;
+
+    public:
+        Args( int argc, char *argv[] ) {
+            m_exeName = argv[0];
+            for( int i = 1; i < argc; ++i )
+                m_args.push_back( argv[i] );
+        }
+
+        Args( std::initializer_list<std::string> args )
+        :   m_exeName( *args.begin() ),
+            m_args( args.begin()+1, args.end() )
+        {}
+
+        auto exeName() const -> std::string {
+            return m_exeName;
+        }
+    };
+
+    // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string
+    // may encode an option + its argument if the : or = form is used
+    enum class TokenType {
+        Option, Argument
+    };
+    struct Token {
+        TokenType type;
+        std::string token;
+    };
+
+    inline auto isOptPrefix( char c ) -> bool {
+        return c == '-'
+#ifdef CLARA_PLATFORM_WINDOWS
+            || c == '/'
+#endif
+        ;
+    }
+
+    // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled
+    class TokenStream {
+        using Iterator = std::vector<std::string>::const_iterator;
+        Iterator it;
+        Iterator itEnd;
+        std::vector<Token> m_tokenBuffer;
+
+        void loadBuffer() {
+            m_tokenBuffer.resize( 0 );
+
+            // Skip any empty strings
+            while( it != itEnd && it->empty() )
+                ++it;
+
+            if( it != itEnd ) {
+                auto const &next = *it;
+                if( isOptPrefix( next[0] ) ) {
+                    auto delimiterPos = next.find_first_of( " :=" );
+                    if( delimiterPos != std::string::npos ) {
+                        m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
+                        m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );
+                    } else {
+                        if( next[1] != '-' && next.size() > 2 ) {
+                            std::string opt = "- ";
+                            for( size_t i = 1; i < next.size(); ++i ) {
+                                opt[1] = next[i];
+                                m_tokenBuffer.push_back( { TokenType::Option, opt } );
+                            }
+                        } else {
+                            m_tokenBuffer.push_back( { TokenType::Option, next } );
+                        }
+                    }
+                } else {
+                    m_tokenBuffer.push_back( { TokenType::Argument, next } );
+                }
+            }
+        }
+
+    public:
+        explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {}
+
+        TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) {
+            loadBuffer();
+        }
+
+        explicit operator bool() const {
+            return !m_tokenBuffer.empty() || it != itEnd;
+        }
+
+        auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
+
+        auto operator*() const -> Token {
+            assert( !m_tokenBuffer.empty() );
+            return m_tokenBuffer.front();
+        }
+
+        auto operator->() const -> Token const * {
+            assert( !m_tokenBuffer.empty() );
+            return &m_tokenBuffer.front();
+        }
+
+        auto operator++() -> TokenStream & {
+            if( m_tokenBuffer.size() >= 2 ) {
+                m_tokenBuffer.erase( m_tokenBuffer.begin() );
+            } else {
+                if( it != itEnd )
+                    ++it;
+                loadBuffer();
+            }
+            return *this;
+        }
+    };
+
+
+    class ResultBase {
+    public:
+        enum Type {
+            Ok, LogicError, RuntimeError
+        };
+
+    protected:
+        ResultBase( Type type ) : m_type( type ) {}
+        virtual ~ResultBase() = default;
+
+        virtual void enforceOk() const = 0;
+
+        Type m_type;
+    };
+
+    template<typename T>
+    class ResultValueBase : public ResultBase {
+    public:
+        auto value() const -> T const & {
+            enforceOk();
+            return m_value;
+        }
+
+    protected:
+        ResultValueBase( Type type ) : ResultBase( type ) {}
+
+        ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {
+            if( m_type == ResultBase::Ok )
+                new( &m_value ) T( other.m_value );
+        }
+
+        ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {
+            new( &m_value ) T( value );
+        }
+
+        auto operator=( ResultValueBase const &other ) -> ResultValueBase & {
+            if( m_type == ResultBase::Ok )
+                m_value.~T();
+            ResultBase::operator=(other);
+            if( m_type == ResultBase::Ok )
+                new( &m_value ) T( other.m_value );
+            return *this;
+        }
+
+        ~ResultValueBase() override {
+            if( m_type == Ok )
+                m_value.~T();
+        }
+
+        union {
+            T m_value;
+        };
+    };
+
+    template<>
+    class ResultValueBase<void> : public ResultBase {
+    protected:
+        using ResultBase::ResultBase;
+    };
+
+    template<typename T = void>
+    class BasicResult : public ResultValueBase<T> {
+    public:
+        template<typename U>
+        explicit BasicResult( BasicResult<U> const &other )
+        :   ResultValueBase<T>( other.type() ),
+            m_errorMessage( other.errorMessage() )
+        {
+            assert( type() != ResultBase::Ok );
+        }
+
+        template<typename U>
+        static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; }
+        static auto ok() -> BasicResult { return { ResultBase::Ok }; }
+        static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }
+        static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }
+
+        explicit operator bool() const { return m_type == ResultBase::Ok; }
+        auto type() const -> ResultBase::Type { return m_type; }
+        auto errorMessage() const -> std::string { return m_errorMessage; }
+
+    protected:
+        void enforceOk() const override {
+            // !TBD: If no exceptions, std::terminate here or something
+            switch( m_type ) {
+                case ResultBase::LogicError:
+                    throw std::logic_error( m_errorMessage );
+                case ResultBase::RuntimeError:
+                    throw std::runtime_error( m_errorMessage );
+                case ResultBase::Ok:
+                    break;
+            }
+        }
+
+        std::string m_errorMessage; // Only populated if resultType is an error
+
+        BasicResult( ResultBase::Type type, std::string const &message )
+        :   ResultValueBase<T>(type),
+            m_errorMessage(message)
+        {
+            assert( m_type != ResultBase::Ok );
+        }
+
+        using ResultValueBase<T>::ResultValueBase;
+        using ResultBase::m_type;
+    };
+
+    enum class ParseResultType {
+        Matched, NoMatch, ShortCircuitAll, ShortCircuitSame
+    };
+
+    class ParseState {
+    public:
+
+        ParseState( ParseResultType type, TokenStream const &remainingTokens )
+        : m_type(type),
+          m_remainingTokens( remainingTokens )
+        {}
+
+        auto type() const -> ParseResultType { return m_type; }
+        auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
+
+    private:
+        ParseResultType m_type;
+        TokenStream m_remainingTokens;
+    };
+
+    using Result = BasicResult<void>;
+    using ParserResult = BasicResult<ParseResultType>;
+    using InternalParseResult = BasicResult<ParseState>;
+
+    struct HelpColumns {
+        std::string left;
+        std::string right;
+    };
+
+    template<typename T>
+    inline auto convertInto( std::string const &source, T& target ) -> ParserResult {
+        std::stringstream ss;
+        ss << source;
+        ss >> target;
+        if( ss.fail() )
+            return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" );
+        else
+            return ParserResult::ok( ParseResultType::Matched );
+    }
+    inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult {
+        target = source;
+        return ParserResult::ok( ParseResultType::Matched );
+    }
+    inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
+        std::string srcLC = source;
+        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } );
+        if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
+            target = true;
+        else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
+            target = false;
+        else
+            return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
+        return ParserResult::ok( ParseResultType::Matched );
+    }
+
+    struct NonCopyable {
+        NonCopyable() = default;
+        NonCopyable( NonCopyable const & ) = delete;
+        NonCopyable( NonCopyable && ) = delete;
+        NonCopyable &operator=( NonCopyable const & ) = delete;
+        NonCopyable &operator=( NonCopyable && ) = delete;
+    };
+
+    struct BoundRef : NonCopyable {
+        virtual ~BoundRef() = default;
+        virtual auto isContainer() const -> bool { return false; }
+        virtual auto isFlag() const -> bool { return false; }
+    };
+    struct BoundValueRefBase : BoundRef {
+        virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
+    };
+    struct BoundFlagRefBase : BoundRef {
+        virtual auto setFlag( bool flag ) -> ParserResult = 0;
+        virtual auto isFlag() const -> bool { return true; }
+    };
+
+    template<typename T>
+    struct BoundValueRef : BoundValueRefBase {
+        T &m_ref;
+
+        explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
+
+        auto setValue( std::string const &arg ) -> ParserResult override {
+            return convertInto( arg, m_ref );
+        }
+    };
+
+    template<typename T>
+    struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
+        std::vector<T> &m_ref;
+
+        explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
+
+        auto isContainer() const -> bool override { return true; }
+
+        auto setValue( std::string const &arg ) -> ParserResult override {
+            T temp;
+            auto result = convertInto( arg, temp );
+            if( result )
+                m_ref.push_back( temp );
+            return result;
+        }
+    };
+
+    struct BoundFlagRef : BoundFlagRefBase {
+        bool &m_ref;
+
+        explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {}
+
+        auto setFlag( bool flag ) -> ParserResult override {
+            m_ref = flag;
+            return ParserResult::ok( ParseResultType::Matched );
+        }
+    };
+
+    template<typename ReturnType>
+    struct LambdaInvoker {
+        static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" );
+
+        template<typename L, typename ArgType>
+        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
+            return lambda( arg );
+        }
+    };
+
+    template<>
+    struct LambdaInvoker<void> {
+        template<typename L, typename ArgType>
+        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
+            lambda( arg );
+            return ParserResult::ok( ParseResultType::Matched );
+        }
+    };
+
+    template<typename ArgType, typename L>
+    inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
+        ArgType temp{};
+        auto result = convertInto( arg, temp );
+        return !result
+           ? result
+           : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
+    }
+
+
+    template<typename L>
+    struct BoundLambda : BoundValueRefBase {
+        L m_lambda;
+
+        static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
+        explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {}
+
+        auto setValue( std::string const &arg ) -> ParserResult override {
+            return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );
+        }
+    };
+
+    template<typename L>
+    struct BoundFlagLambda : BoundFlagRefBase {
+        L m_lambda;
+
+        static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
+        static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" );
+
+        explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {}
+
+        auto setFlag( bool flag ) -> ParserResult override {
+            return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );
+        }
+    };
+
+    enum class Optionality { Optional, Required };
+
+    struct Parser;
+
+    class ParserBase {
+    public:
+        virtual ~ParserBase() = default;
+        virtual auto validate() const -> Result { return Result::ok(); }
+        virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult  = 0;
+        virtual auto cardinality() const -> size_t { return 1; }
+
+        auto parse( Args const &args ) const -> InternalParseResult {
+            return parse( args.exeName(), TokenStream( args ) );
+        }
+    };
+
+    template<typename DerivedT>
+    class ComposableParserImpl : public ParserBase {
+    public:
+        template<typename T>
+        auto operator|( T const &other ) const -> Parser;
+
+		template<typename T>
+        auto operator+( T const &other ) const -> Parser;
+    };
+
+    // Common code and state for Args and Opts
+    template<typename DerivedT>
+    class ParserRefImpl : public ComposableParserImpl<DerivedT> {
+    protected:
+        Optionality m_optionality = Optionality::Optional;
+        std::shared_ptr<BoundRef> m_ref;
+        std::string m_hint;
+        std::string m_description;
+
+        explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
+
+    public:
+        template<typename T>
+        ParserRefImpl( T &ref, std::string const &hint )
+        :   m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
+            m_hint( hint )
+        {}
+
+        template<typename LambdaT>
+        ParserRefImpl( LambdaT const &ref, std::string const &hint )
+        :   m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
+            m_hint(hint)
+        {}
+
+        auto operator()( std::string const &description ) -> DerivedT & {
+            m_description = description;
+            return static_cast<DerivedT &>( *this );
+        }
+
+        auto optional() -> DerivedT & {
+            m_optionality = Optionality::Optional;
+            return static_cast<DerivedT &>( *this );
+        };
+
+        auto required() -> DerivedT & {
+            m_optionality = Optionality::Required;
+            return static_cast<DerivedT &>( *this );
+        };
+
+        auto isOptional() const -> bool {
+            return m_optionality == Optionality::Optional;
+        }
+
+        auto cardinality() const -> size_t override {
+            if( m_ref->isContainer() )
+                return 0;
+            else
+                return 1;
+        }
+
+        auto hint() const -> std::string { return m_hint; }
+    };
+
+    class ExeName : public ComposableParserImpl<ExeName> {
+        std::shared_ptr<std::string> m_name;
+        std::shared_ptr<BoundValueRefBase> m_ref;
+
+        template<typename LambdaT>
+        static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
+            return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
+        }
+
+    public:
+        ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
+
+        explicit ExeName( std::string &ref ) : ExeName() {
+            m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
+        }
+
+        template<typename LambdaT>
+        explicit ExeName( LambdaT const& lambda ) : ExeName() {
+            m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda );
+        }
+
+        // The exe name is not parsed out of the normal tokens, but is handled specially
+        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
+            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
+        }
+
+        auto name() const -> std::string { return *m_name; }
+        auto set( std::string const& newName ) -> ParserResult {
+
+            auto lastSlash = newName.find_last_of( "\\/" );
+            auto filename = ( lastSlash == std::string::npos )
+                    ? newName
+                    : newName.substr( lastSlash+1 );
+
+            *m_name = filename;
+            if( m_ref )
+                return m_ref->setValue( filename );
+            else
+                return ParserResult::ok( ParseResultType::Matched );
+        }
+    };
+
+    class Arg : public ParserRefImpl<Arg> {
+    public:
+        using ParserRefImpl::ParserRefImpl;
+
+        auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override {
+            auto validationResult = validate();
+            if( !validationResult )
+                return InternalParseResult( validationResult );
+
+            auto remainingTokens = tokens;
+            auto const &token = *remainingTokens;
+            if( token.type != TokenType::Argument )
+                return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
+
+            assert( !m_ref->isFlag() );
+            auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
+
+            auto result = valueRef->setValue( remainingTokens->token );
+            if( !result )
+                return InternalParseResult( result );
+            else
+                return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
+        }
+    };
+
+    inline auto normaliseOpt( std::string const &optName ) -> std::string {
+#ifdef CLARA_PLATFORM_WINDOWS
+        if( optName[0] == '/' )
+            return "-" + optName.substr( 1 );
+        else
+#endif
+            return optName;
+    }
+
+    class Opt : public ParserRefImpl<Opt> {
+    protected:
+        std::vector<std::string> m_optNames;
+
+    public:
+        template<typename LambdaT>
+        explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {}
+
+        explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {}
+
+        template<typename LambdaT>
+        Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
+
+        template<typename T>
+        Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
+
+        auto operator[]( std::string const &optName ) -> Opt & {
+            m_optNames.push_back( optName );
+            return *this;
+        }
+
+        auto getHelpColumns() const -> std::vector<HelpColumns> {
+            std::ostringstream oss;
+            bool first = true;
+            for( auto const &opt : m_optNames ) {
+                if (first)
+                    first = false;
+                else
+                    oss << ", ";
+                oss << opt;
+            }
+            if( !m_hint.empty() )
+                oss << " <" << m_hint << ">";
+            return { { oss.str(), m_description } };
+        }
+
+        auto isMatch( std::string const &optToken ) const -> bool {
+            auto normalisedToken = normaliseOpt( optToken );
+            for( auto const &name : m_optNames ) {
+                if( normaliseOpt( name ) == normalisedToken )
+                    return true;
+            }
+            return false;
+        }
+
+        using ParserBase::parse;
+
+        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
+            auto validationResult = validate();
+            if( !validationResult )
+                return InternalParseResult( validationResult );
+
+            auto remainingTokens = tokens;
+            if( remainingTokens && remainingTokens->type == TokenType::Option ) {
+                auto const &token = *remainingTokens;
+                if( isMatch(token.token ) ) {
+                    if( m_ref->isFlag() ) {
+                        auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
+                        auto result = flagRef->setFlag( true );
+                        if( !result )
+                            return InternalParseResult( result );
+                        if( result.value() == ParseResultType::ShortCircuitAll )
+                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
+                    } else {
+                        auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
+                        ++remainingTokens;
+                        if( !remainingTokens )
+                            return InternalParseResult::runtimeError( "Expected argument following " + token.token );
+                        auto const &argToken = *remainingTokens;
+                        if( argToken.type != TokenType::Argument )
+                            return InternalParseResult::runtimeError( "Expected argument following " + token.token );
+                        auto result = valueRef->setValue( argToken.token );
+                        if( !result )
+                            return InternalParseResult( result );
+                        if( result.value() == ParseResultType::ShortCircuitAll )
+                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
+                    }
+                    return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
+                }
+            }
+            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
+        }
+
+        auto validate() const -> Result override {
+            if( m_optNames.empty() )
+                return Result::logicError( "No options supplied to Opt" );
+            for( auto const &name : m_optNames ) {
+                if( name.empty() )
+                    return Result::logicError( "Option name cannot be empty" );
+#ifdef CLARA_PLATFORM_WINDOWS
+                if( name[0] != '-' && name[0] != '/' )
+                    return Result::logicError( "Option name must begin with '-' or '/'" );
+#else
+                if( name[0] != '-' )
+                    return Result::logicError( "Option name must begin with '-'" );
+#endif
+            }
+            return ParserRefImpl::validate();
+        }
+    };
+
+    struct Help : Opt {
+        Help( bool &showHelpFlag )
+        :   Opt([&]( bool flag ) {
+                showHelpFlag = flag;
+                return ParserResult::ok( ParseResultType::ShortCircuitAll );
+            })
+        {
+            static_cast<Opt &>( *this )
+                    ("display usage information")
+                    ["-?"]["-h"]["--help"]
+                    .optional();
+        }
+    };
+
+
+    struct Parser : ParserBase {
+
+        mutable ExeName m_exeName;
+        std::vector<Opt> m_options;
+        std::vector<Arg> m_args;
+
+        auto operator|=( ExeName const &exeName ) -> Parser & {
+            m_exeName = exeName;
+            return *this;
+        }
+
+        auto operator|=( Arg const &arg ) -> Parser & {
+            m_args.push_back(arg);
+            return *this;
+        }
+
+        auto operator|=( Opt const &opt ) -> Parser & {
+            m_options.push_back(opt);
+            return *this;
+        }
+
+        auto operator|=( Parser const &other ) -> Parser & {
+            m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());
+            m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());
+            return *this;
+        }
+
+        template<typename T>
+        auto operator|( T const &other ) const -> Parser {
+            return Parser( *this ) |= other;
+        }
+
+        // Forward deprecated interface with '+' instead of '|'
+        template<typename T>
+        auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
+        template<typename T>
+        auto operator+( T const &other ) const -> Parser { return operator|( other ); }
+
+        auto getHelpColumns() const -> std::vector<HelpColumns> {
+            std::vector<HelpColumns> cols;
+            for (auto const &o : m_options) {
+                auto childCols = o.getHelpColumns();
+                cols.insert( cols.end(), childCols.begin(), childCols.end() );
+            }
+            return cols;
+        }
+
+        void writeToStream( std::ostream &os ) const {
+            if (!m_exeName.name().empty()) {
+                os << "usage:\n" << "  " << m_exeName.name() << " ";
+                bool required = true, first = true;
+                for( auto const &arg : m_args ) {
+                    if (first)
+                        first = false;
+                    else
+                        os << " ";
+                    if( arg.isOptional() && required ) {
+                        os << "[";
+                        required = false;
+                    }
+                    os << "<" << arg.hint() << ">";
+                    if( arg.cardinality() == 0 )
+                        os << " ... ";
+                }
+                if( !required )
+                    os << "]";
+                if( !m_options.empty() )
+                    os << " options";
+                os << "\n\nwhere options are:" << std::endl;
+            }
+
+            auto rows = getHelpColumns();
+            size_t consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
+            size_t optWidth = 0;
+            for( auto const &cols : rows )
+                optWidth = (std::max)(optWidth, cols.left.size() + 2);
+
+            optWidth = (std::min)(optWidth, consoleWidth/2);
+
+            for( auto const &cols : rows ) {
+                auto row =
+                        TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
+                        TextFlow::Spacer(4) +
+                        TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );
+                os << row << std::endl;
+            }
+        }
+
+        friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {
+            parser.writeToStream( os );
+            return os;
+        }
+
+        auto validate() const -> Result override {
+            for( auto const &opt : m_options ) {
+                auto result = opt.validate();
+                if( !result )
+                    return result;
+            }
+            for( auto const &arg : m_args ) {
+                auto result = arg.validate();
+                if( !result )
+                    return result;
+            }
+            return Result::ok();
+        }
+
+        using ParserBase::parse;
+
+        auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override {
+
+            struct ParserInfo {
+                ParserBase const* parser = nullptr;
+                size_t count = 0;
+            };
+            const size_t totalParsers = m_options.size() + m_args.size();
+            assert( totalParsers < 512 );
+            // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do
+            ParserInfo parseInfos[512];
+
+            {
+                size_t i = 0;
+                for (auto const &opt : m_options) parseInfos[i++].parser = &opt;
+                for (auto const &arg : m_args) parseInfos[i++].parser = &arg;
+            }
+
+            m_exeName.set( exeName );
+
+            auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
+            while( result.value().remainingTokens() ) {
+                bool tokenParsed = false;
+
+                for( size_t i = 0; i < totalParsers; ++i ) {
+                    auto&  parseInfo = parseInfos[i];
+                    if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {
+                        result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
+                        if (!result)
+                            return result;
+                        if (result.value().type() != ParseResultType::NoMatch) {
+                            tokenParsed = true;
+                            ++parseInfo.count;
+                            break;
+                        }
+                    }
+                }
+
+                if( result.value().type() == ParseResultType::ShortCircuitAll )
+                    return result;
+                if( !tokenParsed )
+                    return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token );
+            }
+            // !TBD Check missing required options
+            return result;
+        }
+    };
+
+    template<typename DerivedT>
+    template<typename T>
+    auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {
+        return Parser() | static_cast<DerivedT const &>( *this ) | other;
+    }
+} // namespace detail
+
+
+// A Combined parser
+using detail::Parser;
+
+// A parser for options
+using detail::Opt;
+
+// A parser for arguments
+using detail::Arg;
+
+// Wrapper for argc, argv from main()
+using detail::Args;
+
+// Specifies the name of the executable
+using detail::ExeName;
+
+// Convenience wrapper for option parser that specifies the help option
+using detail::Help;
+
+// enum of result types from a parse
+using detail::ParseResultType;
+
+// Result type for parser operation
+using detail::ParserResult;
+
+
+} // namespace clara
+
+#endif // CLARA_HPP_INCLUDED

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/CMakeLists.txt
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/CMakeLists.txt	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/CMakeLists.txt	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,81 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake config
+#
+#  vtzero tests
+#
+#-----------------------------------------------------------------------------
+
+if(Boost_FOUND)
+    message(STATUS "Boost library found: enable testing with boost::variant")
+    add_definitions(-DVTZERO_TEST_WITH_VARIANT)
+    include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
+else()
+    message(STATUS "Boost library not found: disable testing with boost::variant")
+endif()
+
+include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/catch")
+include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
+
+set(TEST_SOURCES builder
+                 builder_linestring
+                 builder_point
+                 builder_polygon
+                 exceptions
+                 feature
+                 geometry
+                 geometry_linestring
+                 geometry_point
+                 geometry_polygon
+                 index
+                 layer
+                 output
+                 point
+                 property_map
+                 property_value
+                 types
+                 vector_tile)
+
+string(REGEX REPLACE "([^;]+)" "t/test_\\1.cpp" _test_sources "${TEST_SOURCES}")
+
+add_executable(unit-tests test_main.cpp ${_test_sources})
+
+add_executable(fixture-tests test_main.cpp fixture_tests.cpp)
+
+add_test(NAME unit-tests
+         COMMAND unit-tests
+         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(_fixtures ${MVT_FIXTURES}/fixtures)
+if(EXISTS ${_fixtures})
+    message(STATUS "Found test fixtures. Enabled mvt fixture tests.")
+    add_test(NAME fixture-tests
+             COMMAND fixture-tests)
+
+    set_tests_properties(fixture-tests PROPERTIES
+                         ENVIRONMENT "FIXTURES_DIR=${_fixtures}")
+
+    if(NOT WIN32)
+        set(_real_world_dir ${MVT_FIXTURES}/real-world)
+        file(GLOB real_world ${_real_world_dir}/bangkok/*
+                             ${_real_world_dir}/chicago/*
+                             ${_real_world_dir}/nepal/*
+                             ${_real_world_dir}/norway/*
+                             ${_real_world_dir}/sanfrancisco/*
+                             ${_real_world_dir}/uruguay/*)
+
+        if(NOT "${real_world}" STREQUAL "")
+            execute_process(COMMAND cat ${real_world}
+                            OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/real-world-all.mvt)
+
+            add_test(NAME vtzero-show-real-world
+                    COMMAND vtzero-show ${CMAKE_BINARY_DIR}/test/real-world-all.mvt)
+        endif()
+    endif()
+else()
+    message(WARNING "Disabled mvt fixture tests, because fixtures not found.\n  Install them by calling 'git submodule update --init' in ${CMAKE_SOURCE_DIR}.")
+endif()
+
+
+
+#-----------------------------------------------------------------------------

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/catch/catch.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/catch/catch.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/catch/catch.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,11678 @@
+/*
+ *  Catch v1.12.0
+ *  Generated: 2018-01-11 21:56:34.893972
+ *  ----------------------------------------------------------
+ *  This file has been merged from multiple headers. Please don't edit it directly
+ *  Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
+#define TWOBLUECUBES_CATCH_HPP_INCLUDED
+
+#ifdef __clang__
+#    pragma clang system_header
+#elif defined __GNUC__
+#    pragma GCC system_header
+#endif
+
+// #included from: internal/catch_suppress_warnings.h
+
+#ifdef __clang__
+#   ifdef __ICC // icpc defines the __clang__ macro
+#       pragma warning(push)
+#       pragma warning(disable: 161 1682)
+#   else // __ICC
+#       pragma clang diagnostic ignored "-Wglobal-constructors"
+#       pragma clang diagnostic ignored "-Wvariadic-macros"
+#       pragma clang diagnostic ignored "-Wc99-extensions"
+#       pragma clang diagnostic ignored "-Wunused-variable"
+#       pragma clang diagnostic push
+#       pragma clang diagnostic ignored "-Wpadded"
+#       pragma clang diagnostic ignored "-Wc++98-compat"
+#       pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#       pragma clang diagnostic ignored "-Wswitch-enum"
+#       pragma clang diagnostic ignored "-Wcovered-switch-default"
+#    endif
+#elif defined __GNUC__
+#    pragma GCC diagnostic ignored "-Wvariadic-macros"
+#    pragma GCC diagnostic ignored "-Wunused-variable"
+#    pragma GCC diagnostic ignored "-Wparentheses"
+
+#    pragma GCC diagnostic push
+#    pragma GCC diagnostic ignored "-Wpadded"
+#endif
+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
+#  define CATCH_IMPL
+#endif
+
+#ifdef CATCH_IMPL
+#  ifndef CLARA_CONFIG_MAIN
+#    define CLARA_CONFIG_MAIN_NOT_DEFINED
+#    define CLARA_CONFIG_MAIN
+#  endif
+#endif
+
+// #included from: internal/catch_notimplemented_exception.h
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
+
+// #included from: catch_common.h
+#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
+
+// #included from: catch_compiler_capabilities.h
+#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
+// The following features are defined:
+//
+// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported?
+// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
+// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
+// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported?
+// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported
+// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported?
+// CATCH_CONFIG_CPP11_OVERRIDE : is override supported?
+// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
+// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported?
+// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported?
+
+// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
+
+// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
+// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
+// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
+// ****************
+// Note to maintainers: if new toggles are added please document them
+// in configuration.md, too
+// ****************
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
+
+#ifdef __cplusplus
+
+#  if __cplusplus >= 201103L
+#    define CATCH_CPP11_OR_GREATER
+#  endif
+
+#  if __cplusplus >= 201402L
+#    define CATCH_CPP14_OR_GREATER
+#  endif
+
+#endif
+
+#ifdef __clang__
+
+#  if __has_feature(cxx_nullptr)
+#    define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#  endif
+
+#  if __has_feature(cxx_noexcept)
+#    define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#  endif
+
+#   if defined(CATCH_CPP11_OR_GREATER)
+#       define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+            _Pragma( "clang diagnostic push" ) \
+            _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" )
+#       define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+            _Pragma( "clang diagnostic pop" )
+
+#       define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+            _Pragma( "clang diagnostic push" ) \
+            _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
+#       define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+            _Pragma( "clang diagnostic pop" )
+#   endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// We know some environments not to support full POSIX signals
+#if defined(__CYGWIN__) || defined(__QNX__)
+
+#   if !defined(CATCH_CONFIG_POSIX_SIGNALS)
+#       define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+#   endif
+
+#endif
+
+#ifdef __OS400__
+#       define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+#       define CATCH_CONFIG_COLOUR_NONE
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Cygwin
+#ifdef __CYGWIN__
+
+// Required for some versions of Cygwin to declare gettimeofday
+// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
+#   define _BSD_SOURCE
+
+#endif // __CYGWIN__
+
+////////////////////////////////////////////////////////////////////////////////
+// Borland
+#ifdef __BORLANDC__
+
+#endif // __BORLANDC__
+
+////////////////////////////////////////////////////////////////////////////////
+// EDG
+#ifdef __EDG_VERSION__
+
+#endif // __EDG_VERSION__
+
+////////////////////////////////////////////////////////////////////////////////
+// Digital Mars
+#ifdef __DMC__
+
+#endif // __DMC__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+#   if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
+#       define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#   endif
+
+// - otherwise more recent versions define __cplusplus >= 201103L
+// and will get picked up below
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
+
+#if (_MSC_VER >= 1600)
+#   define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#   define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
+#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
+#endif
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Use variadic macros if the compiler supports them
+#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
+    ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
+    ( defined __GNUC__ && __GNUC__ >= 3 ) || \
+    ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
+
+#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+
+#endif
+
+// Use __COUNTER__ if the compiler supports it
+#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
+    ( defined __GNUC__  && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \
+    ( defined __clang__ && __clang_major__ >= 3 )
+
+// Use of __COUNTER__ is suppressed during code analysis in CLion/AppCode 2017.2.x and former,
+// because __COUNTER__ is not properly handled by it.
+// This does not affect compilation
+#if ( !defined __JETBRAINS_IDE__ || __JETBRAINS_IDE__ >= 20170300L )
+    #define CATCH_INTERNAL_CONFIG_COUNTER
+#endif
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if defined(CATCH_CPP11_OR_GREATER)
+
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
+#    define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#    define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#    define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+#    define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+#    define CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+#    define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+#  endif
+
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG)
+#    define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG
+#  endif
+
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE)
+#    define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE
+#  endif
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
+#    define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#  endif
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE)
+#   define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
+#  endif
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS)
+#  define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
+# endif
+
+#endif // __cplusplus >= 201103L
+
+// Now set the actual defines based on the above + anything the user has configured
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_NULLPTR
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_NOEXCEPT
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_GENERATED_METHODS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_IS_ENUM
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_TUPLE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS)
+#   define CATCH_CONFIG_VARIADIC_MACROS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_LONG_LONG
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_OVERRIDE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_UNIQUE_PTR
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
+#   define CATCH_CONFIG_COUNTER
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_SHUFFLE
+#endif
+# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11)
+#  define CATCH_CONFIG_CPP11_TYPE_TRAITS
+# endif
+#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
+#   define CATCH_CONFIG_WINDOWS_SEH
+#endif
+// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
+#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
+#   define CATCH_CONFIG_POSIX_SIGNALS
+#endif
+
+#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
+#   define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
+#   define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+#endif
+
+// noexcept support:
+#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
+#  define CATCH_NOEXCEPT noexcept
+#  define CATCH_NOEXCEPT_IS(x) noexcept(x)
+#else
+#  define CATCH_NOEXCEPT throw()
+#  define CATCH_NOEXCEPT_IS(x)
+#endif
+
+// nullptr support
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+#   define CATCH_NULL nullptr
+#else
+#   define CATCH_NULL NULL
+#endif
+
+// override support
+#ifdef CATCH_CONFIG_CPP11_OVERRIDE
+#   define CATCH_OVERRIDE override
+#else
+#   define CATCH_OVERRIDE
+#endif
+
+// unique_ptr support
+#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR
+#   define CATCH_AUTO_PTR( T ) std::unique_ptr<T>
+#else
+#   define CATCH_AUTO_PTR( T ) std::auto_ptr<T>
+#endif
+
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
+#ifdef CATCH_CONFIG_COUNTER
+#  define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
+#else
+#  define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
+#endif
+
+#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
+#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
+
+#include <sstream>
+#include <algorithm>
+
+namespace Catch {
+
+    struct IConfig;
+
+    struct CaseSensitive { enum Choice {
+        Yes,
+        No
+    }; };
+
+    class NonCopyable {
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        NonCopyable( NonCopyable const& )              = delete;
+        NonCopyable( NonCopyable && )                  = delete;
+        NonCopyable& operator = ( NonCopyable const& ) = delete;
+        NonCopyable& operator = ( NonCopyable && )     = delete;
+#else
+        NonCopyable( NonCopyable const& info );
+        NonCopyable& operator = ( NonCopyable const& );
+#endif
+
+    protected:
+        NonCopyable() {}
+        virtual ~NonCopyable();
+    };
+
+    class SafeBool {
+    public:
+        typedef void (SafeBool::*type)() const;
+
+        static type makeSafe( bool value ) {
+            return value ? &SafeBool::trueValue : 0;
+        }
+    private:
+        void trueValue() const {}
+    };
+
+    template<typename ContainerT>
+    void deleteAll( ContainerT& container ) {
+        typename ContainerT::const_iterator it = container.begin();
+        typename ContainerT::const_iterator itEnd = container.end();
+        for(; it != itEnd; ++it )
+            delete *it;
+    }
+    template<typename AssociativeContainerT>
+    void deleteAllValues( AssociativeContainerT& container ) {
+        typename AssociativeContainerT::const_iterator it = container.begin();
+        typename AssociativeContainerT::const_iterator itEnd = container.end();
+        for(; it != itEnd; ++it )
+            delete it->second;
+    }
+
+    bool startsWith( std::string const& s, std::string const& prefix );
+    bool startsWith( std::string const& s, char prefix );
+    bool endsWith( std::string const& s, std::string const& suffix );
+    bool endsWith( std::string const& s, char suffix );
+    bool contains( std::string const& s, std::string const& infix );
+    void toLowerInPlace( std::string& s );
+    std::string toLower( std::string const& s );
+    std::string trim( std::string const& str );
+    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
+
+    struct pluralise {
+        pluralise( std::size_t count, std::string const& label );
+
+        friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
+
+        std::size_t m_count;
+        std::string m_label;
+    };
+
+    struct SourceLineInfo {
+
+        SourceLineInfo();
+        SourceLineInfo( char const* _file, std::size_t _line );
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        SourceLineInfo(SourceLineInfo const& other)          = default;
+        SourceLineInfo( SourceLineInfo && )                  = default;
+        SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
+        SourceLineInfo& operator = ( SourceLineInfo && )     = default;
+#  endif
+        bool empty() const;
+        bool operator == ( SourceLineInfo const& other ) const;
+        bool operator < ( SourceLineInfo const& other ) const;
+
+        char const* file;
+        std::size_t line;
+    };
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
+
+    // This is just here to avoid compiler warnings with macro constants and boolean literals
+    inline bool isTrue( bool value ){ return value; }
+    inline bool alwaysTrue() { return true; }
+    inline bool alwaysFalse() { return false; }
+
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
+
+    void seedRng( IConfig const& config );
+    unsigned int rngSeed();
+
+    // Use this in variadic streaming macros to allow
+    //    >> +StreamEndStop
+    // as well as
+    //    >> stuff +StreamEndStop
+    struct StreamEndStop {
+        std::string operator+() {
+            return std::string();
+        }
+    };
+    template<typename T>
+    T const& operator + ( T const& value, StreamEndStop ) {
+        return value;
+    }
+}
+
+#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
+#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
+
+namespace Catch {
+
+    class NotImplementedException : public std::exception
+    {
+    public:
+        NotImplementedException( SourceLineInfo const& lineInfo );
+
+        virtual ~NotImplementedException() CATCH_NOEXCEPT {}
+
+        virtual const char* what() const CATCH_NOEXCEPT;
+
+    private:
+        std::string m_what;
+        SourceLineInfo m_lineInfo;
+    };
+
+} // end namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
+
+// #included from: internal/catch_context.h
+#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
+
+// #included from: catch_interfaces_generators.h
+#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct IGeneratorInfo {
+        virtual ~IGeneratorInfo();
+        virtual bool moveNext() = 0;
+        virtual std::size_t getCurrentIndex() const = 0;
+    };
+
+    struct IGeneratorsForTest {
+        virtual ~IGeneratorsForTest();
+
+        virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
+        virtual bool moveNext() = 0;
+    };
+
+    IGeneratorsForTest* createGeneratorsForTest();
+
+} // end namespace Catch
+
+// #included from: catch_ptr.hpp
+#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    // An intrusive reference counting smart pointer.
+    // T must implement addRef() and release() methods
+    // typically implementing the IShared interface
+    template<typename T>
+    class Ptr {
+    public:
+        Ptr() : m_p( CATCH_NULL ){}
+        Ptr( T* p ) : m_p( p ){
+            if( m_p )
+                m_p->addRef();
+        }
+        Ptr( Ptr const& other ) : m_p( other.m_p ){
+            if( m_p )
+                m_p->addRef();
+        }
+        ~Ptr(){
+            if( m_p )
+                m_p->release();
+        }
+        void reset() {
+            if( m_p )
+                m_p->release();
+            m_p = CATCH_NULL;
+        }
+        Ptr& operator = ( T* p ){
+            Ptr temp( p );
+            swap( temp );
+            return *this;
+        }
+        Ptr& operator = ( Ptr const& other ){
+            Ptr temp( other );
+            swap( temp );
+            return *this;
+        }
+        void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
+        T* get() const{ return m_p; }
+        T& operator*() const { return *m_p; }
+        T* operator->() const { return m_p; }
+        bool operator !() const { return m_p == CATCH_NULL; }
+        operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); }
+
+    private:
+        T* m_p;
+    };
+
+    struct IShared : NonCopyable {
+        virtual ~IShared();
+        virtual void addRef() const = 0;
+        virtual void release() const = 0;
+    };
+
+    template<typename T = IShared>
+    struct SharedImpl : T {
+
+        SharedImpl() : m_rc( 0 ){}
+
+        virtual void addRef() const {
+            ++m_rc;
+        }
+        virtual void release() const {
+            if( --m_rc == 0 )
+                delete this;
+        }
+
+        mutable unsigned int m_rc;
+    };
+
+} // end namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+    class TestCase;
+    class Stream;
+    struct IResultCapture;
+    struct IRunner;
+    struct IGeneratorsForTest;
+    struct IConfig;
+
+    struct IContext
+    {
+        virtual ~IContext();
+
+        virtual IResultCapture* getResultCapture() = 0;
+        virtual IRunner* getRunner() = 0;
+        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
+        virtual bool advanceGeneratorsForCurrentTest() = 0;
+        virtual Ptr<IConfig const> getConfig() const = 0;
+    };
+
+    struct IMutableContext : IContext
+    {
+        virtual ~IMutableContext();
+        virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
+        virtual void setRunner( IRunner* runner ) = 0;
+        virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
+    };
+
+    IContext& getCurrentContext();
+    IMutableContext& getCurrentMutableContext();
+    void cleanUpContext();
+    Stream createStream( std::string const& streamName );
+
+}
+
+// #included from: internal/catch_test_registry.hpp
+#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_interfaces_testcase.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
+
+#include <vector>
+
+namespace Catch {
+
+    class TestSpec;
+
+    struct ITestCase : IShared {
+        virtual void invoke () const = 0;
+    protected:
+        virtual ~ITestCase();
+    };
+
+    class TestCase;
+    struct IConfig;
+
+    struct ITestCaseRegistry {
+        virtual ~ITestCaseRegistry();
+        virtual std::vector<TestCase> const& getAllTests() const = 0;
+        virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
+    };
+
+    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
+    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
+    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
+
+}
+
+namespace Catch {
+
+template<typename C>
+class MethodTestCase : public SharedImpl<ITestCase> {
+
+public:
+    MethodTestCase( void (C::*method)() ) : m_method( method ) {}
+
+    virtual void invoke() const {
+        C obj;
+        (obj.*m_method)();
+    }
+
+private:
+    virtual ~MethodTestCase() {}
+
+    void (C::*m_method)();
+};
+
+typedef void(*TestFunction)();
+
+struct NameAndDesc {
+    NameAndDesc( const char* _name = "", const char* _description= "" )
+    : name( _name ), description( _description )
+    {}
+
+    const char* name;
+    const char* description;
+};
+
+void registerTestCase
+    (   ITestCase* testCase,
+        char const* className,
+        NameAndDesc const& nameAndDesc,
+        SourceLineInfo const& lineInfo );
+
+struct AutoReg {
+
+    AutoReg
+        (   TestFunction function,
+            SourceLineInfo const& lineInfo,
+            NameAndDesc const& nameAndDesc );
+
+    template<typename C>
+    AutoReg
+        (   void (C::*method)(),
+            char const* className,
+            NameAndDesc const& nameAndDesc,
+            SourceLineInfo const& lineInfo ) {
+
+        registerTestCase
+            (   new MethodTestCase<C>( method ),
+                className,
+                nameAndDesc,
+                lineInfo );
+    }
+
+    ~AutoReg();
+
+private:
+    AutoReg( AutoReg const& );
+    void operator= ( AutoReg const& );
+};
+
+void registerTestCaseFunction
+    (   TestFunction function,
+        SourceLineInfo const& lineInfo,
+        NameAndDesc const& nameAndDesc );
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
+        static void TestName(); \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        static void TestName()
+    #define INTERNAL_CATCH_TESTCASE( ... ) \
+        INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ \
+            struct TestName : ClassName{ \
+                void test(); \
+            }; \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \
+        } \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        void TestName::test()
+    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
+        INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+#else
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
+        static void TestName(); \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); } /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        static void TestName()
+    #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
+        INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ \
+            struct TestCaseName : ClassName{ \
+                void test(); \
+            }; \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \
+        } \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        void TestCaseName::test()
+    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
+        INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); /* NOLINT */ \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+#endif
+
+// #included from: internal/catch_capture.hpp
+#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
+
+// #included from: catch_result_builder.h
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
+
+// #included from: catch_result_type.h
+#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
+
+namespace Catch {
+
+    // ResultWas::OfType enum
+    struct ResultWas { enum OfType {
+        Unknown = -1,
+        Ok = 0,
+        Info = 1,
+        Warning = 2,
+
+        FailureBit = 0x10,
+
+        ExpressionFailed = FailureBit | 1,
+        ExplicitFailure = FailureBit | 2,
+
+        Exception = 0x100 | FailureBit,
+
+        ThrewException = Exception | 1,
+        DidntThrowException = Exception | 2,
+
+        FatalErrorCondition = 0x200 | FailureBit
+
+    }; };
+
+    inline bool isOk( ResultWas::OfType resultType ) {
+        return ( resultType & ResultWas::FailureBit ) == 0;
+    }
+    inline bool isJustInfo( int flags ) {
+        return flags == ResultWas::Info;
+    }
+
+    // ResultDisposition::Flags enum
+    struct ResultDisposition { enum Flags {
+        Normal = 0x01,
+
+        ContinueOnFailure = 0x02,   // Failures fail test, but execution continues
+        FalseTest = 0x04,           // Prefix expression with !
+        SuppressFail = 0x08         // Failures are reported but do not fail the test
+    }; };
+
+    inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
+        return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
+    }
+
+    inline bool shouldContinueOnFailure( int flags )    { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
+    inline bool isFalseTest( int flags )                { return ( flags & ResultDisposition::FalseTest ) != 0; }
+    inline bool shouldSuppressFailure( int flags )      { return ( flags & ResultDisposition::SuppressFail ) != 0; }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.h
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
+
+    struct DecomposedExpression
+    {
+        virtual ~DecomposedExpression() {}
+        virtual bool isBinaryExpression() const {
+            return false;
+        }
+        virtual void reconstructExpression( std::string& dest ) const = 0;
+
+        // Only simple binary comparisons can be decomposed.
+        // If more complex check is required then wrap sub-expressions in parentheses.
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
+
+    private:
+        DecomposedExpression& operator = (DecomposedExpression const&);
+    };
+
+    struct AssertionInfo
+    {
+        AssertionInfo();
+        AssertionInfo(  char const * _macroName,
+                        SourceLineInfo const& _lineInfo,
+                        char const * _capturedExpression,
+                        ResultDisposition::Flags _resultDisposition,
+                        char const * _secondArg = "");
+
+        char const * macroName;
+        SourceLineInfo lineInfo;
+        char const * capturedExpression;
+        ResultDisposition::Flags resultDisposition;
+        char const * secondArg;
+    };
+
+    struct AssertionResultData
+    {
+        AssertionResultData() : decomposedExpression( CATCH_NULL )
+                              , resultType( ResultWas::Unknown )
+                              , negated( false )
+                              , parenthesized( false ) {}
+
+        void negate( bool parenthesize ) {
+            negated = !negated;
+            parenthesized = parenthesize;
+            if( resultType == ResultWas::Ok )
+                resultType = ResultWas::ExpressionFailed;
+            else if( resultType == ResultWas::ExpressionFailed )
+                resultType = ResultWas::Ok;
+        }
+
+        std::string const& reconstructExpression() const {
+            if( decomposedExpression != CATCH_NULL ) {
+                decomposedExpression->reconstructExpression( reconstructedExpression );
+                if( parenthesized ) {
+                    reconstructedExpression.insert( 0, 1, '(' );
+                    reconstructedExpression.append( 1, ')' );
+                }
+                if( negated ) {
+                    reconstructedExpression.insert( 0, 1, '!' );
+                }
+                decomposedExpression = CATCH_NULL;
+            }
+            return reconstructedExpression;
+        }
+
+        mutable DecomposedExpression const* decomposedExpression;
+        mutable std::string reconstructedExpression;
+        std::string message;
+        ResultWas::OfType resultType;
+        bool negated;
+        bool parenthesized;
+    };
+
+    class AssertionResult {
+    public:
+        AssertionResult();
+        AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
+        ~AssertionResult();
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+         AssertionResult( AssertionResult const& )              = default;
+         AssertionResult( AssertionResult && )                  = default;
+         AssertionResult& operator = ( AssertionResult const& ) = default;
+         AssertionResult& operator = ( AssertionResult && )     = default;
+#  endif
+
+        bool isOk() const;
+        bool succeeded() const;
+        ResultWas::OfType getResultType() const;
+        bool hasExpression() const;
+        bool hasMessage() const;
+        std::string getExpression() const;
+        std::string getExpressionInMacro() const;
+        bool hasExpandedExpression() const;
+        std::string getExpandedExpression() const;
+        std::string getMessage() const;
+        SourceLineInfo getSourceInfo() const;
+        std::string getTestMacroName() const;
+        void discardDecomposedExpression() const;
+        void expandDecomposedExpression() const;
+
+    protected:
+        AssertionInfo m_info;
+        AssertionResultData m_resultData;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_matchers.hpp
+#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+    namespace Impl {
+
+        template<typename ArgT> struct MatchAllOf;
+        template<typename ArgT> struct MatchAnyOf;
+        template<typename ArgT> struct MatchNotOf;
+
+        class MatcherUntypedBase {
+        public:
+            std::string toString() const {
+                if( m_cachedToString.empty() )
+                    m_cachedToString = describe();
+                return m_cachedToString;
+            }
+
+        protected:
+            virtual ~MatcherUntypedBase();
+            virtual std::string describe() const = 0;
+            mutable std::string m_cachedToString;
+        private:
+            MatcherUntypedBase& operator = ( MatcherUntypedBase const& );
+        };
+
+        template<typename ObjectT>
+        struct MatcherMethod {
+            virtual bool match( ObjectT const& arg ) const = 0;
+        };
+        template<typename PtrT>
+        struct MatcherMethod<PtrT*> {
+            virtual bool match( PtrT* arg ) const = 0;
+        };
+
+        template<typename ObjectT, typename ComparatorT = ObjectT>
+        struct MatcherBase : MatcherUntypedBase, MatcherMethod<ObjectT> {
+
+            MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const;
+            MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const;
+            MatchNotOf<ComparatorT> operator ! () const;
+        };
+
+        template<typename ArgT>
+        struct MatchAllOf : MatcherBase<ArgT> {
+            virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if (!m_matchers[i]->match(arg))
+                        return false;
+                }
+                return true;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                std::string description;
+                description.reserve( 4 + m_matchers.size()*32 );
+                description += "( ";
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if( i != 0 )
+                        description += " and ";
+                    description += m_matchers[i]->toString();
+                }
+                description += " )";
+                return description;
+            }
+
+            MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
+                m_matchers.push_back( &other );
+                return *this;
+            }
+
+            std::vector<MatcherBase<ArgT> const*> m_matchers;
+        };
+        template<typename ArgT>
+        struct MatchAnyOf : MatcherBase<ArgT> {
+
+            virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if (m_matchers[i]->match(arg))
+                        return true;
+                }
+                return false;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                std::string description;
+                description.reserve( 4 + m_matchers.size()*32 );
+                description += "( ";
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if( i != 0 )
+                        description += " or ";
+                    description += m_matchers[i]->toString();
+                }
+                description += " )";
+                return description;
+            }
+
+            MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
+                m_matchers.push_back( &other );
+                return *this;
+            }
+
+            std::vector<MatcherBase<ArgT> const*> m_matchers;
+        };
+
+        template<typename ArgT>
+        struct MatchNotOf : MatcherBase<ArgT> {
+
+            MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
+
+            virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+                return !m_underlyingMatcher.match( arg );
+            }
+
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "not " + m_underlyingMatcher.toString();
+            }
+            MatcherBase<ArgT> const& m_underlyingMatcher;
+        };
+
+        template<typename ObjectT, typename ComparatorT>
+        MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const {
+            return MatchAllOf<ComparatorT>() && *this && other;
+        }
+        template<typename ObjectT, typename ComparatorT>
+        MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const {
+            return MatchAnyOf<ComparatorT>() || *this || other;
+        }
+        template<typename ObjectT, typename ComparatorT>
+        MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const {
+            return MatchNotOf<ComparatorT>( *this );
+        }
+
+    } // namespace Impl
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+    // - deprecated: prefer ||, && and !
+    template<typename T>
+    Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
+        return Impl::MatchNotOf<T>( underlyingMatcher );
+    }
+    template<typename T>
+    Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+        return Impl::MatchAllOf<T>() && m1 && m2;
+    }
+    template<typename T>
+    Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+        return Impl::MatchAllOf<T>() && m1 && m2 && m3;
+    }
+    template<typename T>
+    Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+        return Impl::MatchAnyOf<T>() || m1 || m2;
+    }
+    template<typename T>
+    Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+        return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
+    }
+
+} // namespace Matchers
+
+using namespace Matchers;
+using Matchers::Impl::MatcherBase;
+
+} // namespace Catch
+
+namespace Catch {
+
+    struct TestFailureException{};
+
+    template<typename T> class ExpressionLhs;
+
+    struct CopyableStream {
+        CopyableStream() {}
+        CopyableStream( CopyableStream const& other ) {
+            oss << other.oss.str();
+        }
+        CopyableStream& operator=( CopyableStream const& other ) {
+            oss.str(std::string());
+            oss << other.oss.str();
+            return *this;
+        }
+        std::ostringstream oss;
+    };
+
+    class ResultBuilder : public DecomposedExpression {
+    public:
+        ResultBuilder(  char const* macroName,
+                        SourceLineInfo const& lineInfo,
+                        char const* capturedExpression,
+                        ResultDisposition::Flags resultDisposition,
+                        char const* secondArg = "" );
+        ~ResultBuilder();
+
+        template<typename T>
+        ExpressionLhs<T const&> operator <= ( T const& operand );
+        ExpressionLhs<bool> operator <= ( bool value );
+
+        template<typename T>
+        ResultBuilder& operator << ( T const& value ) {
+            stream().oss << value;
+            return *this;
+        }
+
+        ResultBuilder& setResultType( ResultWas::OfType result );
+        ResultBuilder& setResultType( bool result );
+
+        void endExpression( DecomposedExpression const& expr );
+
+        virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE;
+
+        AssertionResult build() const;
+        AssertionResult build( DecomposedExpression const& expr ) const;
+
+        void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
+        void captureResult( ResultWas::OfType resultType );
+        void captureExpression();
+        void captureExpectedException( std::string const& expectedMessage );
+        void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher );
+        void handleResult( AssertionResult const& result );
+        void react();
+        bool shouldDebugBreak() const;
+        bool allowThrows() const;
+
+        template<typename ArgT, typename MatcherT>
+        void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
+
+        void setExceptionGuard();
+        void unsetExceptionGuard();
+
+    private:
+        AssertionInfo m_assertionInfo;
+        AssertionResultData m_data;
+
+        CopyableStream &stream()
+        {
+            if(!m_usedStream)
+            {
+                m_usedStream = true;
+                m_stream().oss.str("");
+            }
+            return m_stream();
+        }
+
+        static CopyableStream &m_stream()
+        {
+            static CopyableStream s;
+            return s;
+        }
+
+        bool m_shouldDebugBreak;
+        bool m_shouldThrow;
+        bool m_guardException;
+        bool m_usedStream;
+    };
+
+} // namespace Catch
+
+// Include after due to circular dependency:
+// #included from: catch_expression_lhs.hpp
+#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
+
+// #included from: catch_evaluate.hpp
+#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+#pragma warning(disable:4018) // more "signed/unsigned mismatch"
+#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
+#endif
+
+#include <cstddef>
+
+namespace Catch {
+namespace Internal {
+
+    enum Operator {
+        IsEqualTo,
+        IsNotEqualTo,
+        IsLessThan,
+        IsGreaterThan,
+        IsLessThanOrEqualTo,
+        IsGreaterThanOrEqualTo
+    };
+
+    template<Operator Op> struct OperatorTraits             { static const char* getName(){ return "*error*"; } };
+    template<> struct OperatorTraits<IsEqualTo>             { static const char* getName(){ return "=="; } };
+    template<> struct OperatorTraits<IsNotEqualTo>          { static const char* getName(){ return "!="; } };
+    template<> struct OperatorTraits<IsLessThan>            { static const char* getName(){ return "<"; } };
+    template<> struct OperatorTraits<IsGreaterThan>         { static const char* getName(){ return ">"; } };
+    template<> struct OperatorTraits<IsLessThanOrEqualTo>   { static const char* getName(){ return "<="; } };
+    template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
+
+    template<typename T>
+    T& opCast(T const& t) { return const_cast<T&>(t); }
+
+// nullptr_t support based on pull request #154 from Konstantin Baumann
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+    inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+    // So the compare overloads can be operator agnostic we convey the operator as a template
+    // enum, which is used to specialise an Evaluator for doing the comparison.
+    template<typename T1, typename T2, Operator Op>
+    struct Evaluator{};
+
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs) {
+            return bool( opCast( lhs ) ==  opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsNotEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) != opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsLessThan> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) < opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsGreaterThan> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) > opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) >= opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) <= opCast( rhs ) );
+        }
+    };
+
+    template<Operator Op, typename T1, typename T2>
+    bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
+        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+    }
+
+    // This level of indirection allows us to specialise for integer types
+    // to avoid signed/ unsigned warnings
+
+    // "base" overload
+    template<Operator Op, typename T1, typename T2>
+    bool compare( T1 const& lhs, T2 const& rhs ) {
+        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+    }
+
+    // unsigned X to int
+    template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+
+    // unsigned X to long
+    template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+
+    // int to unsigned X
+    template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+
+    // long to unsigned X
+    template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+
+    // pointer to long (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+
+    // pointer to int (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+    // long long to unsigned X
+    template<Operator Op> bool compare( long long lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long long lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long long lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+
+    // unsigned long long to X
+    template<Operator Op> bool compare( unsigned long long lhs, int rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( unsigned long long lhs, long rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( unsigned long long lhs, char rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+
+    // pointer to long long (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+#endif // CATCH_CONFIG_CPP11_LONG_LONG
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+    // pointer to nullptr_t (when comparing against nullptr)
+    template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr );
+    }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+} // end of namespace Internal
+} // end of namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// #included from: catch_tostring.h
+#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
+
+#include <sstream>
+#include <iomanip>
+#include <limits>
+#include <vector>
+#include <cstddef>
+
+#ifdef __OBJC__
+// #included from: catch_objc_arc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
+
+#import <Foundation/Foundation.h>
+
+#ifdef __has_feature
+#define CATCH_ARC_ENABLED __has_feature(objc_arc)
+#else
+#define CATCH_ARC_ENABLED 0
+#endif
+
+void arcSafeRelease( NSObject* obj );
+id performOptionalSelector( id obj, SEL sel );
+
+#if !CATCH_ARC_ENABLED
+inline void arcSafeRelease( NSObject* obj ) {
+    [obj release];
+}
+inline id performOptionalSelector( id obj, SEL sel ) {
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED
+#define CATCH_ARC_STRONG
+#else
+inline void arcSafeRelease( NSObject* ){}
+inline id performOptionalSelector( id obj, SEL sel ) {
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+#endif
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
+#define CATCH_ARC_STRONG __strong
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+#include <tuple>
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_IS_ENUM
+#include <type_traits>
+#endif
+
+namespace Catch {
+
+// Why we're here.
+template<typename T>
+std::string toString( T const& value );
+
+// Built in overloads
+
+std::string toString( std::string const& value );
+std::string toString( std::wstring const& value );
+std::string toString( const char* const value );
+std::string toString( char* const value );
+std::string toString( const wchar_t* const value );
+std::string toString( wchar_t* const value );
+std::string toString( int value );
+std::string toString( unsigned long value );
+std::string toString( unsigned int value );
+std::string toString( const double value );
+std::string toString( const float value );
+std::string toString( bool value );
+std::string toString( char value );
+std::string toString( signed char value );
+std::string toString( unsigned char value );
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString( long long value );
+std::string toString( unsigned long long value );
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t );
+#endif
+
+#ifdef __OBJC__
+    std::string toString( NSString const * const& nsstring );
+    std::string toString( NSString * CATCH_ARC_STRONG & nsstring );
+    std::string toString( NSObject* const& nsObject );
+#endif
+
+namespace Detail {
+
+    extern const std::string unprintableString;
+
+ #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK)
+    struct BorgType {
+        template<typename T> BorgType( T const& );
+    };
+
+    struct TrueType { char sizer[1]; };
+    struct FalseType { char sizer[2]; };
+
+    TrueType& testStreamable( std::ostream& );
+    FalseType testStreamable( FalseType );
+
+    FalseType operator<<( std::ostream const&, BorgType const& );
+
+    template<typename T>
+    struct IsStreamInsertable {
+        static std::ostream &s;
+        static T  const&t;
+        enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
+    };
+#else
+    template<typename T>
+    class IsStreamInsertable {
+        template<typename SS, typename TT>
+        static auto test(int)
+        -> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() );
+
+        template<typename, typename>
+        static auto test(...) -> std::false_type;
+
+    public:
+        static const bool value = decltype(test<std::ostream,const T&>(0))::value;
+    };
+#endif
+
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+    template<typename T,
+             bool IsEnum = std::is_enum<T>::value
+             >
+    struct EnumStringMaker
+    {
+        static std::string convert( T const& ) { return unprintableString; }
+    };
+
+    template<typename T>
+    struct EnumStringMaker<T,true>
+    {
+        static std::string convert( T const& v )
+        {
+            return ::Catch::toString(
+                static_cast<typename std::underlying_type<T>::type>(v)
+                );
+        }
+    };
+#endif
+    template<bool C>
+    struct StringMakerBase {
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+        template<typename T>
+        static std::string convert( T const& v )
+        {
+            return EnumStringMaker<T>::convert( v );
+        }
+#else
+        template<typename T>
+        static std::string convert( T const& ) { return unprintableString; }
+#endif
+    };
+
+    template<>
+    struct StringMakerBase<true> {
+        template<typename T>
+        static std::string convert( T const& _value ) {
+            std::ostringstream oss;
+            oss << _value;
+            return oss.str();
+        }
+    };
+
+    std::string rawMemoryToString( const void *object, std::size_t size );
+
+    template<typename T>
+    std::string rawMemoryToString( const T& object ) {
+      return rawMemoryToString( &object, sizeof(object) );
+    }
+
+} // end namespace Detail
+
+template<typename T>
+struct StringMaker :
+    Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
+
+template<typename T>
+struct StringMaker<T*> {
+    template<typename U>
+    static std::string convert( U* p ) {
+        if( !p )
+            return "NULL";
+        else
+            return Detail::rawMemoryToString( p );
+    }
+};
+
+template<typename R, typename C>
+struct StringMaker<R C::*> {
+    static std::string convert( R C::* p ) {
+        if( !p )
+            return "NULL";
+        else
+            return Detail::rawMemoryToString( p );
+    }
+};
+
+namespace Detail {
+    template<typename InputIterator>
+    std::string rangeToString( InputIterator first, InputIterator last );
+}
+
+//template<typename T, typename Allocator>
+//struct StringMaker<std::vector<T, Allocator> > {
+//    static std::string convert( std::vector<T,Allocator> const& v ) {
+//        return Detail::rangeToString( v.begin(), v.end() );
+//    }
+//};
+
+template<typename T, typename Allocator>
+std::string toString( std::vector<T,Allocator> const& v ) {
+    return Detail::rangeToString( v.begin(), v.end() );
+}
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+
+// toString for tuples
+namespace TupleDetail {
+  template<
+      typename Tuple,
+      std::size_t N = 0,
+      bool = (N < std::tuple_size<Tuple>::value)
+      >
+  struct ElementPrinter {
+      static void print( const Tuple& tuple, std::ostream& os )
+      {
+          os << ( N ? ", " : " " )
+             << Catch::toString(std::get<N>(tuple));
+          ElementPrinter<Tuple,N+1>::print(tuple,os);
+      }
+  };
+
+  template<
+      typename Tuple,
+      std::size_t N
+      >
+  struct ElementPrinter<Tuple,N,false> {
+      static void print( const Tuple&, std::ostream& ) {}
+  };
+
+}
+
+template<typename ...Types>
+struct StringMaker<std::tuple<Types...>> {
+
+    static std::string convert( const std::tuple<Types...>& tuple )
+    {
+        std::ostringstream os;
+        os << '{';
+        TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os );
+        os << " }";
+        return os.str();
+    }
+};
+#endif // CATCH_CONFIG_CPP11_TUPLE
+
+namespace Detail {
+    template<typename T>
+    std::string makeString( T const& value ) {
+        return StringMaker<T>::convert( value );
+    }
+} // end namespace Detail
+
+/// \brief converts any type to a string
+///
+/// The default template forwards on to ostringstream - except when an
+/// ostringstream overload does not exist - in which case it attempts to detect
+/// that and writes {?}.
+/// Overload (not specialise) this template for custom typs that you don't want
+/// to provide an ostream overload for.
+template<typename T>
+std::string toString( T const& value ) {
+    return StringMaker<T>::convert( value );
+}
+
+    namespace Detail {
+    template<typename InputIterator>
+    std::string rangeToString( InputIterator first, InputIterator last ) {
+        std::ostringstream oss;
+        oss << "{ ";
+        if( first != last ) {
+            oss << Catch::toString( *first );
+            for( ++first ; first != last ; ++first )
+                oss << ", " << Catch::toString( *first );
+        }
+        oss << " }";
+        return oss.str();
+    }
+}
+
+} // end namespace Catch
+
+namespace Catch {
+
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+class BinaryExpression;
+
+template<typename ArgT, typename MatcherT>
+class MatchExpression;
+
+// Wraps the LHS of an expression and overloads comparison operators
+// for also capturing those and RHS (if any)
+template<typename T>
+class ExpressionLhs : public DecomposedExpression {
+public:
+    ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
+
+    ExpressionLhs& operator = ( const ExpressionLhs& );
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
+    operator == ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
+    operator != ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsNotEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsLessThan, RhsT const&>
+    operator < ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsLessThan>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
+    operator > ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsGreaterThan>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
+    operator <= ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
+    operator >= ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
+    }
+
+    BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) {
+        return captureExpression<Internal::IsEqualTo>( rhs );
+    }
+
+    BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) {
+        return captureExpression<Internal::IsNotEqualTo>( rhs );
+    }
+
+    void endExpression() {
+        m_truthy = m_lhs ? true : false;
+        m_rb
+            .setResultType( m_truthy )
+            .endExpression( *this );
+    }
+
+    virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+        dest = Catch::toString( m_lhs );
+    }
+
+private:
+    template<Internal::Operator Op, typename RhsT>
+    BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
+        return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
+    }
+
+    template<Internal::Operator Op>
+    BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
+        return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
+    }
+
+private:
+    ResultBuilder& m_rb;
+    T m_lhs;
+    bool m_truthy;
+};
+
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+class BinaryExpression : public DecomposedExpression {
+public:
+    BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs )
+        : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {}
+
+    BinaryExpression& operator = ( BinaryExpression& );
+
+    void endExpression() const {
+        m_rb
+            .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) )
+            .endExpression( *this );
+    }
+
+    virtual bool isBinaryExpression() const CATCH_OVERRIDE {
+        return true;
+    }
+
+    virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+        std::string lhs = Catch::toString( m_lhs );
+        std::string rhs = Catch::toString( m_rhs );
+        char delim = lhs.size() + rhs.size() < 40 &&
+                     lhs.find('\n') == std::string::npos &&
+                     rhs.find('\n') == std::string::npos ? ' ' : '\n';
+        dest.reserve( 7 + lhs.size() + rhs.size() );
+                   // 2 for spaces around operator
+                   // 2 for operator
+                   // 2 for parentheses (conditionally added later)
+                   // 1 for negation (conditionally added later)
+        dest = lhs;
+        dest += delim;
+        dest += Internal::OperatorTraits<Op>::getName();
+        dest += delim;
+        dest += rhs;
+    }
+
+private:
+    ResultBuilder& m_rb;
+    LhsT m_lhs;
+    RhsT m_rhs;
+};
+
+template<typename ArgT, typename MatcherT>
+class MatchExpression : public DecomposedExpression {
+public:
+    MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString )
+        : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {}
+
+    virtual bool isBinaryExpression() const CATCH_OVERRIDE {
+        return true;
+    }
+
+    virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+        std::string matcherAsString = m_matcher.toString();
+        dest = Catch::toString( m_arg );
+        dest += ' ';
+        if( matcherAsString == Detail::unprintableString )
+            dest += m_matcherString;
+        else
+            dest += matcherAsString;
+    }
+
+private:
+    ArgT m_arg;
+    MatcherT m_matcher;
+    char const* m_matcherString;
+};
+
+} // end namespace Catch
+
+
+namespace Catch {
+
+    template<typename T>
+    ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
+        return ExpressionLhs<T const&>( *this, operand );
+    }
+
+    inline ExpressionLhs<bool> ResultBuilder::operator <= ( bool value ) {
+        return ExpressionLhs<bool>( *this, value );
+    }
+
+    template<typename ArgT, typename MatcherT>
+    void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
+                                             char const* matcherString ) {
+        MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
+        setResultType( matcher.match( arg ) );
+        endExpression( expr );
+    }
+
+} // namespace Catch
+
+// #included from: catch_message.h
+#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct MessageInfo {
+        MessageInfo(    std::string const& _macroName,
+                        SourceLineInfo const& _lineInfo,
+                        ResultWas::OfType _type );
+
+        std::string macroName;
+        SourceLineInfo lineInfo;
+        ResultWas::OfType type;
+        std::string message;
+        unsigned int sequence;
+
+        bool operator == ( MessageInfo const& other ) const {
+            return sequence == other.sequence;
+        }
+        bool operator < ( MessageInfo const& other ) const {
+            return sequence < other.sequence;
+        }
+    private:
+        static unsigned int globalCount;
+    };
+
+    struct MessageBuilder {
+        MessageBuilder( std::string const& macroName,
+                        SourceLineInfo const& lineInfo,
+                        ResultWas::OfType type )
+        : m_info( macroName, lineInfo, type )
+        {}
+
+        template<typename T>
+        MessageBuilder& operator << ( T const& value ) {
+            m_stream << value;
+            return *this;
+        }
+
+        MessageInfo m_info;
+        std::ostringstream m_stream;
+    };
+
+    class ScopedMessage {
+    public:
+        ScopedMessage( MessageBuilder const& builder );
+        ScopedMessage( ScopedMessage const& other );
+        ~ScopedMessage();
+
+        MessageInfo m_info;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_capture.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    class TestCase;
+    class AssertionResult;
+    struct AssertionInfo;
+    struct SectionInfo;
+    struct SectionEndInfo;
+    struct MessageInfo;
+    class ScopedMessageBuilder;
+    struct Counts;
+
+    struct IResultCapture {
+
+        virtual ~IResultCapture();
+
+        virtual void assertionEnded( AssertionResult const& result ) = 0;
+        virtual bool sectionStarted(    SectionInfo const& sectionInfo,
+                                        Counts& assertions ) = 0;
+        virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
+        virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
+        virtual void pushScopedMessage( MessageInfo const& message ) = 0;
+        virtual void popScopedMessage( MessageInfo const& message ) = 0;
+
+        virtual std::string getCurrentTestName() const = 0;
+        virtual const AssertionResult* getLastResult() const = 0;
+
+        virtual void exceptionEarlyReported() = 0;
+
+        virtual void handleFatalErrorCondition( std::string const& message ) = 0;
+
+        virtual bool lastAssertionPassed() = 0;
+        virtual void assertionPassed() = 0;
+        virtual void assertionRun() = 0;
+    };
+
+    IResultCapture& getResultCapture();
+}
+
+// #included from: catch_debugger.h
+#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
+
+// #included from: catch_platform.h
+#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
+
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#  define CATCH_PLATFORM_MAC
+#elif  defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+#  define CATCH_PLATFORM_IPHONE
+#elif defined(linux) || defined(__linux) || defined(__linux__)
+#  define CATCH_PLATFORM_LINUX
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#  define CATCH_PLATFORM_WINDOWS
+#  if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
+#    define CATCH_DEFINES_NOMINMAX
+#  endif
+#  if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
+#    define CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+#  endif
+#endif
+
+#include <string>
+
+namespace Catch{
+
+    bool isDebuggerActive();
+    void writeToDebugConsole( std::string const& text );
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+    // The following code snippet based on:
+    // http://cocoawithlove.com/2008/03/break-into-debugger.html
+    #if defined(__ppc64__) || defined(__ppc__)
+        #define CATCH_TRAP() \
+                __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
+                : : : "memory","r0","r3","r4" ) /* NOLINT */
+    #else
+        #define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ )
+    #endif
+
+#elif defined(CATCH_PLATFORM_LINUX)
+    // If we can use inline assembler, do it because this allows us to break
+    // directly at the location of the failing check instead of breaking inside
+    // raise() called from it, i.e. one stack frame below.
+    #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
+        #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
+    #else // Fall back to the generic way.
+        #include <signal.h>
+
+        #define CATCH_TRAP() raise(SIGTRAP)
+    #endif
+#elif defined(_MSC_VER)
+    #define CATCH_TRAP() __debugbreak()
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+    #define CATCH_TRAP() DebugBreak()
+#endif
+
+#ifdef CATCH_TRAP
+    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
+#else
+    #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
+#endif
+
+// #included from: catch_interfaces_runner.h
+#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
+
+namespace Catch {
+    class TestCase;
+
+    struct IRunner {
+        virtual ~IRunner();
+        virtual bool aborting() const = 0;
+    };
+}
+
+#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
+# define CATCH_INTERNAL_STRINGIFY(expr) #expr
+#else
+# define CATCH_INTERNAL_STRINGIFY(expr) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
+#endif
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+///////////////////////////////////////////////////////////////////////////////
+// We can speedup compilation significantly by breaking into debugger lower in
+// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER
+// macro in each assertion
+#define INTERNAL_CATCH_REACT( resultBuilder ) \
+    resultBuilder.react();
+
+///////////////////////////////////////////////////////////////////////////////
+// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
+// macros.
+// This can potentially cause false negative, if the test code catches
+// the exception before it propagates back up to the runner.
+#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
+        __catchResult.setExceptionGuard(); \
+        CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+        ( __catchResult <= expr ).endExpression(); \
+        CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+        __catchResult.unsetExceptionGuard(); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+
+#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+        __catchResult.setExceptionGuard(); \
+        __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
+        __catchResult.unsetExceptionGuard(); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+#else
+///////////////////////////////////////////////////////////////////////////////
+// In the event of a failure works out if the debugger needs to be invoked
+// and/or an exception thrown and takes appropriate action.
+// This needs to be done as a macro so the debugger will stop in the user
+// source code rather than in Catch library code
+#define INTERNAL_CATCH_REACT( resultBuilder ) \
+    if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
+    resultBuilder.react();
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
+        try { \
+            CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+            ( __catchResult <= expr ).endExpression(); \
+            CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+        } \
+        catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+    // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \
+    INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
+    if( Catch::getResultCapture().lastAssertionPassed() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \
+    INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
+    if( !Catch::getResultCapture().lastAssertionPassed() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
+        try { \
+            static_cast<void>(expr); \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        } \
+        catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition, CATCH_INTERNAL_STRINGIFY(matcher) ); \
+        if( __catchResult.allowThrows() ) \
+            try { \
+                static_cast<void>(expr); \
+                __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+            } \
+            catch( ... ) { \
+                __catchResult.captureExpectedException( matcher ); \
+            } \
+        else \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
+        if( __catchResult.allowThrows() ) \
+            try { \
+                static_cast<void>(expr); \
+                __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+            } \
+            catch( exceptionType ) { \
+                __catchResult.captureResult( Catch::ResultWas::Ok ); \
+            } \
+            catch( ... ) { \
+                __catchResult.useActiveException( resultDisposition ); \
+            } \
+        else \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
+        do { \
+            Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+            __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
+            __catchResult.captureResult( messageType ); \
+            INTERNAL_CATCH_REACT( __catchResult ) \
+        } while( Catch::alwaysFalse() )
+#else
+    #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \
+        do { \
+            Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+            __catchResult << log + ::Catch::StreamEndStop(); \
+            __catchResult.captureResult( messageType ); \
+            INTERNAL_CATCH_REACT( __catchResult ) \
+        } while( Catch::alwaysFalse() )
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO( macroName, log ) \
+    Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+        try { \
+            __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
+        } catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+// #included from: internal/catch_section.h
+#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
+
+// #included from: catch_section_info.h
+#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
+
+// #included from: catch_totals.hpp
+#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
+
+#include <cstddef>
+
+namespace Catch {
+
+    struct Counts {
+        Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {}
+
+        Counts operator - ( Counts const& other ) const {
+            Counts diff;
+            diff.passed = passed - other.passed;
+            diff.failed = failed - other.failed;
+            diff.failedButOk = failedButOk - other.failedButOk;
+            return diff;
+        }
+        Counts& operator += ( Counts const& other ) {
+            passed += other.passed;
+            failed += other.failed;
+            failedButOk += other.failedButOk;
+            return *this;
+        }
+
+        std::size_t total() const {
+            return passed + failed + failedButOk;
+        }
+        bool allPassed() const {
+            return failed == 0 && failedButOk == 0;
+        }
+        bool allOk() const {
+            return failed == 0;
+        }
+
+        std::size_t passed;
+        std::size_t failed;
+        std::size_t failedButOk;
+    };
+
+    struct Totals {
+
+        Totals operator - ( Totals const& other ) const {
+            Totals diff;
+            diff.assertions = assertions - other.assertions;
+            diff.testCases = testCases - other.testCases;
+            return diff;
+        }
+
+        Totals delta( Totals const& prevTotals ) const {
+            Totals diff = *this - prevTotals;
+            if( diff.assertions.failed > 0 )
+                ++diff.testCases.failed;
+            else if( diff.assertions.failedButOk > 0 )
+                ++diff.testCases.failedButOk;
+            else
+                ++diff.testCases.passed;
+            return diff;
+        }
+
+        Totals& operator += ( Totals const& other ) {
+            assertions += other.assertions;
+            testCases += other.testCases;
+            return *this;
+        }
+
+        Counts assertions;
+        Counts testCases;
+    };
+}
+
+#include <string>
+
+namespace Catch {
+
+    struct SectionInfo {
+        SectionInfo
+            (   SourceLineInfo const& _lineInfo,
+                std::string const& _name,
+                std::string const& _description = std::string() );
+
+        std::string name;
+        std::string description;
+        SourceLineInfo lineInfo;
+    };
+
+    struct SectionEndInfo {
+        SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
+        : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
+        {}
+
+        SectionInfo sectionInfo;
+        Counts prevAssertions;
+        double durationInSeconds;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_timer.h
+#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
+
+#ifdef _MSC_VER
+
+namespace Catch {
+    typedef unsigned long long UInt64;
+}
+#else
+#include <stdint.h>
+namespace Catch {
+    typedef uint64_t UInt64;
+}
+#endif
+
+namespace Catch {
+    class Timer {
+    public:
+        Timer() : m_ticks( 0 ) {}
+        void start();
+        unsigned int getElapsedMicroseconds() const;
+        unsigned int getElapsedMilliseconds() const;
+        double getElapsedSeconds() const;
+
+    private:
+        UInt64 m_ticks;
+    };
+
+} // namespace Catch
+
+#include <string>
+
+namespace Catch {
+
+    class Section : NonCopyable {
+    public:
+        Section( SectionInfo const& info );
+        ~Section();
+
+        // This indicates whether the section should be executed or not
+        operator bool() const;
+
+    private:
+        SectionInfo m_info;
+
+        std::string m_name;
+        Counts m_assertions;
+        bool m_sectionIncluded;
+        Timer m_timer;
+    };
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define INTERNAL_CATCH_SECTION( ... ) \
+        if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
+#else
+    #define INTERNAL_CATCH_SECTION( name, desc ) \
+        if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) )
+#endif
+
+// #included from: internal/catch_generators.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <stdlib.h>
+
+namespace Catch {
+
+template<typename T>
+struct IGenerator {
+    virtual ~IGenerator() {}
+    virtual T getValue( std::size_t index ) const = 0;
+    virtual std::size_t size () const = 0;
+};
+
+template<typename T>
+class BetweenGenerator : public IGenerator<T> {
+public:
+    BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
+
+    virtual T getValue( std::size_t index ) const {
+        return m_from+static_cast<int>( index );
+    }
+
+    virtual std::size_t size() const {
+        return static_cast<std::size_t>( 1+m_to-m_from );
+    }
+
+private:
+
+    T m_from;
+    T m_to;
+};
+
+template<typename T>
+class ValuesGenerator : public IGenerator<T> {
+public:
+    ValuesGenerator(){}
+
+    void add( T value ) {
+        m_values.push_back( value );
+    }
+
+    virtual T getValue( std::size_t index ) const {
+        return m_values[index];
+    }
+
+    virtual std::size_t size() const {
+        return m_values.size();
+    }
+
+private:
+    std::vector<T> m_values;
+};
+
+template<typename T>
+class CompositeGenerator {
+public:
+    CompositeGenerator() : m_totalSize( 0 ) {}
+
+    // *** Move semantics, similar to auto_ptr ***
+    CompositeGenerator( CompositeGenerator& other )
+    :   m_fileInfo( other.m_fileInfo ),
+        m_totalSize( 0 )
+    {
+        move( other );
+    }
+
+    CompositeGenerator& setFileInfo( const char* fileInfo ) {
+        m_fileInfo = fileInfo;
+        return *this;
+    }
+
+    ~CompositeGenerator() {
+        deleteAll( m_composed );
+    }
+
+    operator T () const {
+        size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
+
+        typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
+        typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
+        for( size_t index = 0; it != itEnd; ++it )
+        {
+            const IGenerator<T>* generator = *it;
+            if( overallIndex >= index && overallIndex < index + generator->size() )
+            {
+                return generator->getValue( overallIndex-index );
+            }
+            index += generator->size();
+        }
+        CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
+        return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
+    }
+
+    void add( const IGenerator<T>* generator ) {
+        m_totalSize += generator->size();
+        m_composed.push_back( generator );
+    }
+
+    CompositeGenerator& then( CompositeGenerator& other ) {
+        move( other );
+        return *this;
+    }
+
+    CompositeGenerator& then( T value ) {
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( value );
+        add( valuesGen );
+        return *this;
+    }
+
+private:
+
+    void move( CompositeGenerator& other ) {
+        m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() );
+        m_totalSize += other.m_totalSize;
+        other.m_composed.clear();
+    }
+
+    std::vector<const IGenerator<T>*> m_composed;
+    std::string m_fileInfo;
+    size_t m_totalSize;
+};
+
+namespace Generators
+{
+    template<typename T>
+    CompositeGenerator<T> between( T from, T to ) {
+        CompositeGenerator<T> generators;
+        generators.add( new BetweenGenerator<T>( from, to ) );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2 ) {
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2, T val3 ){
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        valuesGen->add( val3 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        valuesGen->add( val3 );
+        valuesGen->add( val4 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+} // end namespace Generators
+
+using namespace Generators;
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_LINESTR2( line ) #line
+#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
+
+#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
+
+// #included from: internal/catch_interfaces_exception.h
+#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
+
+#include <string>
+#include <vector>
+
+// #included from: catch_interfaces_registry_hub.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    class TestCase;
+    struct ITestCaseRegistry;
+    struct IExceptionTranslatorRegistry;
+    struct IExceptionTranslator;
+    struct IReporterRegistry;
+    struct IReporterFactory;
+    struct ITagAliasRegistry;
+
+    struct IRegistryHub {
+        virtual ~IRegistryHub();
+
+        virtual IReporterRegistry const& getReporterRegistry() const = 0;
+        virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+        virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
+
+        virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
+    };
+
+    struct IMutableRegistryHub {
+        virtual ~IMutableRegistryHub();
+        virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0;
+        virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
+        virtual void registerTest( TestCase const& testInfo ) = 0;
+        virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
+        virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
+    };
+
+    IRegistryHub& getRegistryHub();
+    IMutableRegistryHub& getMutableRegistryHub();
+    void cleanUp();
+    std::string translateActiveException();
+
+}
+
+namespace Catch {
+
+    typedef std::string(*exceptionTranslateFunction)();
+
+    struct IExceptionTranslator;
+    typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
+
+    struct IExceptionTranslator {
+        virtual ~IExceptionTranslator();
+        virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
+    };
+
+    struct IExceptionTranslatorRegistry {
+        virtual ~IExceptionTranslatorRegistry();
+
+        virtual std::string translateActiveException() const = 0;
+    };
+
+    class ExceptionTranslatorRegistrar {
+        template<typename T>
+        class ExceptionTranslator : public IExceptionTranslator {
+        public:
+
+            ExceptionTranslator( std::string(*translateFunction)( T& ) )
+            : m_translateFunction( translateFunction )
+            {}
+
+            virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE {
+                try {
+                    if( it == itEnd )
+                        throw;
+                    else
+                        return (*it)->translate( it+1, itEnd );
+                }
+                catch( T& ex ) {
+                    return m_translateFunction( ex );
+                }
+            }
+
+        protected:
+            std::string(*m_translateFunction)( T& );
+        };
+
+    public:
+        template<typename T>
+        ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
+            getMutableRegistryHub().registerTranslator
+                ( new ExceptionTranslator<T>( translateFunction ) );
+        }
+    };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
+    static std::string translatorName( signature ); \
+    namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
+    static std::string translatorName( signature )
+
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
+
+// #included from: internal/catch_approx.hpp
+#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
+
+#include <cmath>
+#include <limits>
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+#include <type_traits>
+#endif
+
+namespace Catch {
+namespace Detail {
+
+    class Approx {
+    public:
+        explicit Approx ( double value )
+        :   m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
+            m_margin( 0.0 ),
+            m_scale( 1.0 ),
+            m_value( value )
+        {}
+
+        static Approx custom() {
+            return Approx( 0 );
+        }
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx operator()( T value ) {
+            Approx approx( static_cast<double>(value) );
+            approx.epsilon( m_epsilon );
+            approx.margin( m_margin );
+            approx.scale( m_scale );
+            return approx;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        explicit Approx( T value ): Approx(static_cast<double>(value))
+        {}
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator == ( const T& lhs, Approx const& rhs ) {
+            // Thanks to Richard Harris for his help refining this formula
+            auto lhs_v = double(lhs);
+            bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value)));
+            if (relativeOK) {
+                return true;
+            }
+
+            return std::fabs(lhs_v - rhs.m_value) <= rhs.m_margin;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator == ( Approx const& lhs, const T& rhs ) {
+            return operator==( rhs, lhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator != ( T lhs, Approx const& rhs ) {
+            return !operator==( lhs, rhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator != ( Approx const& lhs, T rhs ) {
+            return !operator==( rhs, lhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator <= ( T lhs, Approx const& rhs ) {
+            return double(lhs) < rhs.m_value || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator <= ( Approx const& lhs, T rhs ) {
+            return lhs.m_value < double(rhs) || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator >= ( T lhs, Approx const& rhs ) {
+            return double(lhs) > rhs.m_value || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator >= ( Approx const& lhs, T rhs ) {
+            return lhs.m_value > double(rhs) || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& epsilon( T newEpsilon ) {
+            m_epsilon = double(newEpsilon);
+            return *this;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& margin( T newMargin ) {
+            m_margin = double(newMargin);
+            return *this;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& scale( T newScale ) {
+            m_scale = double(newScale);
+            return *this;
+        }
+
+#else
+
+        Approx operator()( double value ) {
+            Approx approx( value );
+            approx.epsilon( m_epsilon );
+            approx.margin( m_margin );
+            approx.scale( m_scale );
+            return approx;
+        }
+
+        friend bool operator == ( double lhs, Approx const& rhs ) {
+            // Thanks to Richard Harris for his help refining this formula
+            bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) );
+            if (relativeOK) {
+                return true;
+            }
+            return std::fabs(lhs - rhs.m_value) <= rhs.m_margin;
+        }
+
+        friend bool operator == ( Approx const& lhs, double rhs ) {
+            return operator==( rhs, lhs );
+        }
+
+        friend bool operator != ( double lhs, Approx const& rhs ) {
+            return !operator==( lhs, rhs );
+        }
+
+        friend bool operator != ( Approx const& lhs, double rhs ) {
+            return !operator==( rhs, lhs );
+        }
+
+        friend bool operator <= ( double lhs, Approx const& rhs ) {
+            return lhs < rhs.m_value || lhs == rhs;
+        }
+
+        friend bool operator <= ( Approx const& lhs, double rhs ) {
+            return lhs.m_value < rhs || lhs == rhs;
+        }
+
+        friend bool operator >= ( double lhs, Approx const& rhs ) {
+            return lhs > rhs.m_value || lhs == rhs;
+        }
+
+        friend bool operator >= ( Approx const& lhs, double rhs ) {
+            return lhs.m_value > rhs || lhs == rhs;
+        }
+
+        Approx& epsilon( double newEpsilon ) {
+            m_epsilon = newEpsilon;
+            return *this;
+        }
+
+        Approx& margin( double newMargin ) {
+            m_margin = newMargin;
+            return *this;
+        }
+
+        Approx& scale( double newScale ) {
+            m_scale = newScale;
+            return *this;
+        }
+#endif
+
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << "Approx( " << Catch::toString( m_value ) << " )";
+            return oss.str();
+        }
+
+    private:
+        double m_epsilon;
+        double m_margin;
+        double m_scale;
+        double m_value;
+    };
+}
+
+template<>
+inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
+    return value.toString();
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_matchers_string.h
+#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+
+    namespace StdString {
+
+        struct CasedString
+        {
+            CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity );
+            std::string adjustString( std::string const& str ) const;
+            std::string caseSensitivitySuffix() const;
+
+            CaseSensitive::Choice m_caseSensitivity;
+            std::string m_str;
+        };
+
+        struct StringMatcherBase : MatcherBase<std::string> {
+            StringMatcherBase( std::string const& operation, CasedString const& comparator );
+            virtual std::string describe() const CATCH_OVERRIDE;
+
+            CasedString m_comparator;
+            std::string m_operation;
+        };
+
+        struct EqualsMatcher : StringMatcherBase {
+            EqualsMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+        struct ContainsMatcher : StringMatcherBase {
+            ContainsMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+        struct StartsWithMatcher : StringMatcherBase {
+            StartsWithMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+        struct EndsWithMatcher : StringMatcherBase {
+            EndsWithMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+
+    } // namespace StdString
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+
+    StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+
+} // namespace Matchers
+} // namespace Catch
+
+// #included from: internal/catch_matchers_vector.h
+#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+
+    namespace Vector {
+
+        template<typename T>
+        struct ContainsElementMatcher : MatcherBase<std::vector<T>, T> {
+
+            ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
+
+            bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+                return std::find(v.begin(), v.end(), m_comparator) != v.end();
+            }
+
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "Contains: " + Catch::toString( m_comparator );
+            }
+
+            T const& m_comparator;
+        };
+
+        template<typename T>
+        struct ContainsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
+
+            ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+            bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+                // !TBD: see note in EqualsMatcher
+                if (m_comparator.size() > v.size())
+                    return false;
+                for (size_t i = 0; i < m_comparator.size(); ++i)
+                    if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end())
+                        return false;
+                return true;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "Contains: " + Catch::toString( m_comparator );
+            }
+
+            std::vector<T> const& m_comparator;
+        };
+
+        template<typename T>
+        struct EqualsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
+
+            EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+            bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+                // !TBD: This currently works if all elements can be compared using !=
+                // - a more general approach would be via a compare template that defaults
+                // to using !=. but could be specialised for, e.g. std::vector<T> etc
+                // - then just call that directly
+                if (m_comparator.size() != v.size())
+                    return false;
+                for (size_t i = 0; i < v.size(); ++i)
+                    if (m_comparator[i] != v[i])
+                        return false;
+                return true;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "Equals: " + Catch::toString( m_comparator );
+            }
+            std::vector<T> const& m_comparator;
+        };
+
+    } // namespace Vector
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+
+    template<typename T>
+    Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
+        return Vector::ContainsMatcher<T>( comparator );
+    }
+
+    template<typename T>
+    Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
+        return Vector::ContainsElementMatcher<T>( comparator );
+    }
+
+    template<typename T>
+    Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
+        return Vector::EqualsMatcher<T>( comparator );
+    }
+
+} // namespace Matchers
+} // namespace Catch
+
+// #included from: internal/catch_interfaces_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+// #included from: catch_tag_alias.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct TagAlias {
+        TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
+
+        std::string tag;
+        SourceLineInfo lineInfo;
+    };
+
+    struct RegistrarForTagAliases {
+        RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+    };
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); }
+// #included from: catch_option.hpp
+#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
+
+namespace Catch {
+
+    // An optional type
+    template<typename T>
+    class Option {
+    public:
+        Option() : nullableValue( CATCH_NULL ) {}
+        Option( T const& _value )
+        : nullableValue( new( storage ) T( _value ) )
+        {}
+        Option( Option const& _other )
+        : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL )
+        {}
+
+        ~Option() {
+            reset();
+        }
+
+        Option& operator= ( Option const& _other ) {
+            if( &_other != this ) {
+                reset();
+                if( _other )
+                    nullableValue = new( storage ) T( *_other );
+            }
+            return *this;
+        }
+        Option& operator = ( T const& _value ) {
+            reset();
+            nullableValue = new( storage ) T( _value );
+            return *this;
+        }
+
+        void reset() {
+            if( nullableValue )
+                nullableValue->~T();
+            nullableValue = CATCH_NULL;
+        }
+
+        T& operator*() { return *nullableValue; }
+        T const& operator*() const { return *nullableValue; }
+        T* operator->() { return nullableValue; }
+        const T* operator->() const { return nullableValue; }
+
+        T valueOr( T const& defaultValue ) const {
+            return nullableValue ? *nullableValue : defaultValue;
+        }
+
+        bool some() const { return nullableValue != CATCH_NULL; }
+        bool none() const { return nullableValue == CATCH_NULL; }
+
+        bool operator !() const { return nullableValue == CATCH_NULL; }
+        operator SafeBool::type() const {
+            return SafeBool::makeSafe( some() );
+        }
+
+    private:
+        T *nullableValue;
+        union {
+            char storage[sizeof(T)];
+
+            // These are here to force alignment for the storage
+            long double dummy1;
+            void (*dummy2)();
+            long double dummy3;
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+            long long dummy4;
+#endif
+        };
+    };
+
+} // end namespace Catch
+
+namespace Catch {
+
+    struct ITagAliasRegistry {
+        virtual ~ITagAliasRegistry();
+        virtual Option<TagAlias> find( std::string const& alias ) const = 0;
+        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
+
+        static ITagAliasRegistry const& get();
+    };
+
+} // end namespace Catch
+
+// These files are included here so the single_include script doesn't put them
+// in the conditionally compiled sections
+// #included from: internal/catch_test_case_info.h
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
+
+#include <string>
+#include <set>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    struct ITestCase;
+
+    struct TestCaseInfo {
+        enum SpecialProperties{
+            None = 0,
+            IsHidden = 1 << 1,
+            ShouldFail = 1 << 2,
+            MayFail = 1 << 3,
+            Throws = 1 << 4,
+            NonPortable = 1 << 5
+        };
+
+        TestCaseInfo(   std::string const& _name,
+                        std::string const& _className,
+                        std::string const& _description,
+                        std::set<std::string> const& _tags,
+                        SourceLineInfo const& _lineInfo );
+
+        TestCaseInfo( TestCaseInfo const& other );
+
+        friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags );
+
+        bool isHidden() const;
+        bool throws() const;
+        bool okToFail() const;
+        bool expectedToFail() const;
+
+        std::string name;
+        std::string className;
+        std::string description;
+        std::set<std::string> tags;
+        std::set<std::string> lcaseTags;
+        std::string tagsAsString;
+        SourceLineInfo lineInfo;
+        SpecialProperties properties;
+    };
+
+    class TestCase : public TestCaseInfo {
+    public:
+
+        TestCase( ITestCase* testCase, TestCaseInfo const& info );
+        TestCase( TestCase const& other );
+
+        TestCase withName( std::string const& _newName ) const;
+
+        void invoke() const;
+
+        TestCaseInfo const& getTestCaseInfo() const;
+
+        void swap( TestCase& other );
+        bool operator == ( TestCase const& other ) const;
+        bool operator < ( TestCase const& other ) const;
+        TestCase& operator = ( TestCase const& other );
+
+    private:
+        Ptr<ITestCase> test;
+    };
+
+    TestCase makeTestCase(  ITestCase* testCase,
+                            std::string const& className,
+                            std::string const& name,
+                            std::string const& description,
+                            SourceLineInfo const& lineInfo );
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+
+#ifdef __OBJC__
+// #included from: internal/catch_objc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
+
+#import <objc/runtime.h>
+
+#include <string>
+
+// NB. Any general catch headers included here must be included
+// in catch.hpp first to make sure they are included by the single
+// header for non obj-usage
+
+///////////////////////////////////////////////////////////////////////////////
+// This protocol is really only here for (self) documenting purposes, since
+// all its methods are optional.
+ at protocol OcFixture
+
+ at optional
+
+-(void) setUp;
+-(void) tearDown;
+
+ at end
+
+namespace Catch {
+
+    class OcMethod : public SharedImpl<ITestCase> {
+
+    public:
+        OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
+
+        virtual void invoke() const {
+            id obj = [[m_cls alloc] init];
+
+            performOptionalSelector( obj, @selector(setUp)  );
+            performOptionalSelector( obj, m_sel );
+            performOptionalSelector( obj, @selector(tearDown)  );
+
+            arcSafeRelease( obj );
+        }
+    private:
+        virtual ~OcMethod() {}
+
+        Class m_cls;
+        SEL m_sel;
+    };
+
+    namespace Detail{
+
+        inline std::string getAnnotation(   Class cls,
+                                            std::string const& annotationName,
+                                            std::string const& testCaseName ) {
+            NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
+            SEL sel = NSSelectorFromString( selStr );
+            arcSafeRelease( selStr );
+            id value = performOptionalSelector( cls, sel );
+            if( value )
+                return [(NSString*)value UTF8String];
+            return "";
+        }
+    }
+
+    inline size_t registerTestMethods() {
+        size_t noTestMethods = 0;
+        int noClasses = objc_getClassList( CATCH_NULL, 0 );
+
+        Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
+        objc_getClassList( classes, noClasses );
+
+        for( int c = 0; c < noClasses; c++ ) {
+            Class cls = classes[c];
+            {
+                u_int count;
+                Method* methods = class_copyMethodList( cls, &count );
+                for( u_int m = 0; m < count ; m++ ) {
+                    SEL selector = method_getName(methods[m]);
+                    std::string methodName = sel_getName(selector);
+                    if( startsWith( methodName, "Catch_TestCase_" ) ) {
+                        std::string testCaseName = methodName.substr( 15 );
+                        std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
+                        std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
+                        const char* className = class_getName( cls );
+
+                        getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
+                        noTestMethods++;
+                    }
+                }
+                free(methods);
+            }
+        }
+        return noTestMethods;
+    }
+
+    namespace Matchers {
+        namespace Impl {
+        namespace NSStringMatchers {
+
+            struct StringHolder : MatcherBase<NSString*>{
+                StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
+                StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
+                StringHolder() {
+                    arcSafeRelease( m_substr );
+                }
+
+                virtual bool match( NSString* arg ) const CATCH_OVERRIDE {
+                    return false;
+                }
+
+                NSString* m_substr;
+            };
+
+            struct Equals : StringHolder {
+                Equals( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const CATCH_OVERRIDE {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str isEqualToString:m_substr];
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "equals string: " + Catch::toString( m_substr );
+                }
+            };
+
+            struct Contains : StringHolder {
+                Contains( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location != NSNotFound;
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "contains string: " + Catch::toString( m_substr );
+                }
+            };
+
+            struct StartsWith : StringHolder {
+                StartsWith( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == 0;
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "starts with: " + Catch::toString( m_substr );
+                }
+            };
+            struct EndsWith : StringHolder {
+                EndsWith( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "ends with: " + Catch::toString( m_substr );
+                }
+            };
+
+        } // namespace NSStringMatchers
+        } // namespace Impl
+
+        inline Impl::NSStringMatchers::Equals
+            Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
+
+        inline Impl::NSStringMatchers::Contains
+            Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
+
+        inline Impl::NSStringMatchers::StartsWith
+            StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
+
+        inline Impl::NSStringMatchers::EndsWith
+            EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
+
+    } // namespace Matchers
+
+    using namespace Matchers;
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define OC_TEST_CASE( name, desc )\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
+{\
+return @ name; \
+}\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
+{ \
+return @ desc; \
+} \
+-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
+
+#endif
+
+#ifdef CATCH_IMPL
+
+// !TBD: Move the leak detector code into a separate header
+#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
+#include <crtdbg.h>
+class LeakDetector {
+public:
+    LeakDetector() {
+        int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+        flag |= _CRTDBG_LEAK_CHECK_DF;
+        flag |= _CRTDBG_ALLOC_MEM_DF;
+        _CrtSetDbgFlag(flag);
+        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+        _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+        // Change this to leaking allocation's number to break there
+        _CrtSetBreakAlloc(-1);
+    }
+};
+#else
+class LeakDetector {};
+#endif
+
+LeakDetector leakDetector;
+
+// #included from: internal/catch_impl.hpp
+#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
+
+// Collect all the implementation files together here
+// These are the equivalent of what would usually be cpp files
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// #included from: ../catch_session.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
+
+// #included from: internal/catch_commandline.hpp
+#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
+
+// #included from: catch_config.hpp
+#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
+
+// #included from: catch_test_spec_parser.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_test_spec.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_wildcard_pattern.hpp
+#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+
+#include <stdexcept>
+
+namespace Catch
+{
+    class WildcardPattern {
+        enum WildcardPosition {
+            NoWildcard = 0,
+            WildcardAtStart = 1,
+            WildcardAtEnd = 2,
+            WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+        };
+
+    public:
+
+        WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity )
+        :   m_caseSensitivity( caseSensitivity ),
+            m_wildcard( NoWildcard ),
+            m_pattern( adjustCase( pattern ) )
+        {
+            if( startsWith( m_pattern, '*' ) ) {
+                m_pattern = m_pattern.substr( 1 );
+                m_wildcard = WildcardAtStart;
+            }
+            if( endsWith( m_pattern, '*' ) ) {
+                m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
+                m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
+            }
+        }
+        virtual ~WildcardPattern();
+        virtual bool matches( std::string const& str ) const {
+            switch( m_wildcard ) {
+                case NoWildcard:
+                    return m_pattern == adjustCase( str );
+                case WildcardAtStart:
+                    return endsWith( adjustCase( str ), m_pattern );
+                case WildcardAtEnd:
+                    return startsWith( adjustCase( str ), m_pattern );
+                case WildcardAtBothEnds:
+                    return contains( adjustCase( str ), m_pattern );
+            }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+            throw std::logic_error( "Unknown enum" );
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+        }
+    private:
+        std::string adjustCase( std::string const& str ) const {
+            return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
+        }
+        CaseSensitive::Choice m_caseSensitivity;
+        WildcardPosition m_wildcard;
+        std::string m_pattern;
+    };
+}
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    class TestSpec {
+        struct Pattern : SharedImpl<> {
+            virtual ~Pattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+        };
+        class NamePattern : public Pattern {
+        public:
+            NamePattern( std::string const& name )
+            : m_wildcardPattern( toLower( name ), CaseSensitive::No )
+            {}
+            virtual ~NamePattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const {
+                return m_wildcardPattern.matches( toLower( testCase.name ) );
+            }
+        private:
+            WildcardPattern m_wildcardPattern;
+        };
+
+        class TagPattern : public Pattern {
+        public:
+            TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
+            virtual ~TagPattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const {
+                return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end();
+            }
+        private:
+            std::string m_tag;
+        };
+
+        class ExcludedPattern : public Pattern {
+        public:
+            ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
+            virtual ~ExcludedPattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
+        private:
+            Ptr<Pattern> m_underlyingPattern;
+        };
+
+        struct Filter {
+            std::vector<Ptr<Pattern> > m_patterns;
+
+            bool matches( TestCaseInfo const& testCase ) const {
+                // All patterns in a filter must match for the filter to be a match
+                for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
+                    if( !(*it)->matches( testCase ) )
+                        return false;
+                }
+                return true;
+            }
+        };
+
+    public:
+        bool hasFilters() const {
+            return !m_filters.empty();
+        }
+        bool matches( TestCaseInfo const& testCase ) const {
+            // A TestSpec matches if any filter matches
+            for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it )
+                if( it->matches( testCase ) )
+                    return true;
+            return false;
+        }
+
+    private:
+        std::vector<Filter> m_filters;
+
+        friend class TestSpecParser;
+    };
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+    class TestSpecParser {
+        enum Mode{ None, Name, QuotedName, Tag, EscapedName };
+        Mode m_mode;
+        bool m_exclusion;
+        std::size_t m_start, m_pos;
+        std::string m_arg;
+        std::vector<std::size_t> m_escapeChars;
+        TestSpec::Filter m_currentFilter;
+        TestSpec m_testSpec;
+        ITagAliasRegistry const* m_tagAliases;
+
+    public:
+        TestSpecParser( ITagAliasRegistry const& tagAliases ) :m_mode(None), m_exclusion(false), m_start(0), m_pos(0), m_tagAliases( &tagAliases ) {}
+
+        TestSpecParser& parse( std::string const& arg ) {
+            m_mode = None;
+            m_exclusion = false;
+            m_start = std::string::npos;
+            m_arg = m_tagAliases->expandAliases( arg );
+            m_escapeChars.clear();
+            for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
+                visitChar( m_arg[m_pos] );
+            if( m_mode == Name )
+                addPattern<TestSpec::NamePattern>();
+            return *this;
+        }
+        TestSpec testSpec() {
+            addFilter();
+            return m_testSpec;
+        }
+    private:
+        void visitChar( char c ) {
+            if( m_mode == None ) {
+                switch( c ) {
+                case ' ': return;
+                case '~': m_exclusion = true; return;
+                case '[': return startNewMode( Tag, ++m_pos );
+                case '"': return startNewMode( QuotedName, ++m_pos );
+                case '\\': return escape();
+                default: startNewMode( Name, m_pos ); break;
+                }
+            }
+            if( m_mode == Name ) {
+                if( c == ',' ) {
+                    addPattern<TestSpec::NamePattern>();
+                    addFilter();
+                }
+                else if( c == '[' ) {
+                    if( subString() == "exclude:" )
+                        m_exclusion = true;
+                    else
+                        addPattern<TestSpec::NamePattern>();
+                    startNewMode( Tag, ++m_pos );
+                }
+                else if( c == '\\' )
+                    escape();
+            }
+            else if( m_mode == EscapedName )
+                m_mode = Name;
+            else if( m_mode == QuotedName && c == '"' )
+                addPattern<TestSpec::NamePattern>();
+            else if( m_mode == Tag && c == ']' )
+                addPattern<TestSpec::TagPattern>();
+        }
+        void startNewMode( Mode mode, std::size_t start ) {
+            m_mode = mode;
+            m_start = start;
+        }
+        void escape() {
+            if( m_mode == None )
+                m_start = m_pos;
+            m_mode = EscapedName;
+            m_escapeChars.push_back( m_pos );
+        }
+        std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
+        template<typename T>
+        void addPattern() {
+            std::string token = subString();
+            for( size_t i = 0; i < m_escapeChars.size(); ++i )
+                token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
+            m_escapeChars.clear();
+            if( startsWith( token, "exclude:" ) ) {
+                m_exclusion = true;
+                token = token.substr( 8 );
+            }
+            if( !token.empty() ) {
+                Ptr<TestSpec::Pattern> pattern = new T( token );
+                if( m_exclusion )
+                    pattern = new TestSpec::ExcludedPattern( pattern );
+                m_currentFilter.m_patterns.push_back( pattern );
+            }
+            m_exclusion = false;
+            m_mode = None;
+        }
+        void addFilter() {
+            if( !m_currentFilter.m_patterns.empty() ) {
+                m_testSpec.m_filters.push_back( m_currentFilter );
+                m_currentFilter = TestSpec::Filter();
+            }
+        }
+    };
+    inline TestSpec parseTestSpec( std::string const& arg ) {
+        return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
+    }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// #included from: catch_interfaces_config.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    struct Verbosity { enum Level {
+        NoOutput = 0,
+        Quiet,
+        Normal
+    }; };
+
+    struct WarnAbout { enum What {
+        Nothing = 0x00,
+        NoAssertions = 0x01
+    }; };
+
+    struct ShowDurations { enum OrNot {
+        DefaultForReporter,
+        Always,
+        Never
+    }; };
+    struct RunTests { enum InWhatOrder {
+        InDeclarationOrder,
+        InLexicographicalOrder,
+        InRandomOrder
+    }; };
+    struct UseColour { enum YesOrNo {
+        Auto,
+        Yes,
+        No
+    }; };
+    struct WaitForKeypress { enum When {
+        Never,
+        BeforeStart = 1,
+        BeforeExit = 2,
+        BeforeStartAndExit = BeforeStart | BeforeExit
+    }; };
+
+    class TestSpec;
+
+    struct IConfig : IShared {
+
+        virtual ~IConfig();
+
+        virtual bool allowThrows() const = 0;
+        virtual std::ostream& stream() const = 0;
+        virtual std::string name() const = 0;
+        virtual bool includeSuccessfulResults() const = 0;
+        virtual bool shouldDebugBreak() const = 0;
+        virtual bool warnAboutMissingAssertions() const = 0;
+        virtual int abortAfter() const = 0;
+        virtual bool showInvisibles() const = 0;
+        virtual ShowDurations::OrNot showDurations() const = 0;
+        virtual TestSpec const& testSpec() const = 0;
+        virtual RunTests::InWhatOrder runOrder() const = 0;
+        virtual unsigned int rngSeed() const = 0;
+        virtual UseColour::YesOrNo useColour() const = 0;
+        virtual std::vector<std::string> const& getSectionsToRun() const = 0;
+
+    };
+}
+
+// #included from: catch_stream.h
+#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+
+// #included from: catch_streambuf.h
+#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
+
+#include <streambuf>
+
+namespace Catch {
+
+    class StreamBufBase : public std::streambuf {
+    public:
+        virtual ~StreamBufBase() CATCH_NOEXCEPT;
+    };
+}
+
+#include <streambuf>
+#include <ostream>
+#include <fstream>
+#include <memory>
+
+namespace Catch {
+
+    std::ostream& cout();
+    std::ostream& cerr();
+    std::ostream& clog();
+
+    struct IStream {
+        virtual ~IStream() CATCH_NOEXCEPT;
+        virtual std::ostream& stream() const = 0;
+    };
+
+    class FileStream : public IStream {
+        mutable std::ofstream m_ofs;
+    public:
+        FileStream( std::string const& filename );
+        virtual ~FileStream() CATCH_NOEXCEPT;
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
+
+    class CoutStream : public IStream {
+        mutable std::ostream m_os;
+    public:
+        CoutStream();
+        virtual ~CoutStream() CATCH_NOEXCEPT;
+
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
+
+    class DebugOutStream : public IStream {
+        CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
+        mutable std::ostream m_os;
+    public:
+        DebugOutStream();
+        virtual ~DebugOutStream() CATCH_NOEXCEPT;
+
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
+}
+
+#include <memory>
+#include <vector>
+#include <string>
+#include <stdexcept>
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+
+    struct ConfigData {
+
+        ConfigData()
+        :   listTests( false ),
+            listTags( false ),
+            listReporters( false ),
+            listTestNamesOnly( false ),
+            listExtraInfo( false ),
+            showSuccessfulTests( false ),
+            shouldDebugBreak( false ),
+            noThrow( false ),
+            showHelp( false ),
+            showInvisibles( false ),
+            filenamesAsTags( false ),
+            libIdentify( false ),
+            abortAfter( -1 ),
+            rngSeed( 0 ),
+            verbosity( Verbosity::Normal ),
+            warnings( WarnAbout::Nothing ),
+            showDurations( ShowDurations::DefaultForReporter ),
+            runOrder( RunTests::InDeclarationOrder ),
+            useColour( UseColour::Auto ),
+            waitForKeypress( WaitForKeypress::Never )
+        {}
+
+        bool listTests;
+        bool listTags;
+        bool listReporters;
+        bool listTestNamesOnly;
+        bool listExtraInfo;
+
+        bool showSuccessfulTests;
+        bool shouldDebugBreak;
+        bool noThrow;
+        bool showHelp;
+        bool showInvisibles;
+        bool filenamesAsTags;
+        bool libIdentify;
+
+        int abortAfter;
+        unsigned int rngSeed;
+
+        Verbosity::Level verbosity;
+        WarnAbout::What warnings;
+        ShowDurations::OrNot showDurations;
+        RunTests::InWhatOrder runOrder;
+        UseColour::YesOrNo useColour;
+        WaitForKeypress::When waitForKeypress;
+
+        std::string outputFilename;
+        std::string name;
+        std::string processName;
+
+        std::vector<std::string> reporterNames;
+        std::vector<std::string> testsOrTags;
+        std::vector<std::string> sectionsToRun;
+    };
+
+    class Config : public SharedImpl<IConfig> {
+    private:
+        Config( Config const& other );
+        Config& operator = ( Config const& other );
+        virtual void dummy();
+    public:
+
+        Config()
+        {}
+
+        Config( ConfigData const& data )
+        :   m_data( data ),
+            m_stream( openStream() )
+        {
+            if( !data.testsOrTags.empty() ) {
+                TestSpecParser parser( ITagAliasRegistry::get() );
+                for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
+                    parser.parse( data.testsOrTags[i] );
+                m_testSpec = parser.testSpec();
+            }
+        }
+
+        virtual ~Config() {}
+
+        std::string const& getFilename() const {
+            return m_data.outputFilename ;
+        }
+
+        bool listTests() const { return m_data.listTests; }
+        bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
+        bool listTags() const { return m_data.listTags; }
+        bool listReporters() const { return m_data.listReporters; }
+        bool listExtraInfo() const { return m_data.listExtraInfo; }
+
+        std::string getProcessName() const { return m_data.processName; }
+
+        std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
+        std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
+
+        virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; }
+
+        bool showHelp() const { return m_data.showHelp; }
+
+        // IConfig interface
+        virtual bool allowThrows() const CATCH_OVERRIDE                 { return !m_data.noThrow; }
+        virtual std::ostream& stream() const CATCH_OVERRIDE             { return m_stream->stream(); }
+        virtual std::string name() const CATCH_OVERRIDE                 { return m_data.name.empty() ? m_data.processName : m_data.name; }
+        virtual bool includeSuccessfulResults() const CATCH_OVERRIDE    { return m_data.showSuccessfulTests; }
+        virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE  { return m_data.warnings & WarnAbout::NoAssertions; }
+        virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; }
+        virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE   { return m_data.runOrder; }
+        virtual unsigned int rngSeed() const CATCH_OVERRIDE             { return m_data.rngSeed; }
+        virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE     { return m_data.useColour; }
+        virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; }
+        virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; }
+        virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; }
+
+    private:
+
+        IStream const* openStream() {
+            if( m_data.outputFilename.empty() )
+                return new CoutStream();
+            else if( m_data.outputFilename[0] == '%' ) {
+                if( m_data.outputFilename == "%debug" )
+                    return new DebugOutStream();
+                else
+                    throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename );
+            }
+            else
+                return new FileStream( m_data.outputFilename );
+        }
+        ConfigData m_data;
+
+        CATCH_AUTO_PTR( IStream const ) m_stream;
+        TestSpec m_testSpec;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_clara.h
+#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
+
+// Use Catch's value for console width (store Clara's off to the side, if present)
+#ifdef CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
+#undef CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+// Declare Clara inside the Catch namespace
+#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
+// #included from: ../external/clara.h
+
+// Version 0.0.2.4
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
+
+#ifndef STITCH_CLARA_OPEN_NAMESPACE
+#define TWOBLUECUBES_CLARA_H_INCLUDED
+#define STITCH_CLARA_OPEN_NAMESPACE
+#define STITCH_CLARA_CLOSE_NAMESPACE
+#else
+#define STITCH_CLARA_CLOSE_NAMESPACE }
+#endif
+
+#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
+
+// ----------- #included from tbc_text_format.h -----------
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
+#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#define TBC_TEXT_FORMAT_H_INCLUDED
+#endif
+
+#include <string>
+#include <vector>
+#include <sstream>
+#include <algorithm>
+#include <cctype>
+
+// Use optional outer namespace
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+    struct TextAttributes {
+        TextAttributes()
+        :   initialIndent( std::string::npos ),
+            indent( 0 ),
+            width( consoleWidth-1 ),
+            tabChar( '\t' )
+        {}
+
+        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
+        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
+        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
+        TextAttributes& setTabChar( char _value )               { tabChar = _value; return *this; }
+
+        std::size_t initialIndent;  // indent of first line, or npos
+        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
+        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
+        char tabChar;               // If this char is seen the indent is changed to current pos
+    };
+
+    class Text {
+    public:
+        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+        : attr( _attr )
+        {
+            std::string wrappableChars = " [({.,/|\\-";
+            std::size_t indent = _attr.initialIndent != std::string::npos
+                ? _attr.initialIndent
+                : _attr.indent;
+            std::string remainder = _str;
+
+            while( !remainder.empty() ) {
+                if( lines.size() >= 1000 ) {
+                    lines.push_back( "... message truncated due to excessive size" );
+                    return;
+                }
+                std::size_t tabPos = std::string::npos;
+                std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
+                std::size_t pos = remainder.find_first_of( '\n' );
+                if( pos <= width ) {
+                    width = pos;
+                }
+                pos = remainder.find_last_of( _attr.tabChar, width );
+                if( pos != std::string::npos ) {
+                    tabPos = pos;
+                    if( remainder[width] == '\n' )
+                        width--;
+                    remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
+                }
+
+                if( width == remainder.size() ) {
+                    spliceLine( indent, remainder, width );
+                }
+                else if( remainder[width] == '\n' ) {
+                    spliceLine( indent, remainder, width );
+                    if( width <= 1 || remainder.size() != 1 )
+                        remainder = remainder.substr( 1 );
+                    indent = _attr.indent;
+                }
+                else {
+                    pos = remainder.find_last_of( wrappableChars, width );
+                    if( pos != std::string::npos && pos > 0 ) {
+                        spliceLine( indent, remainder, pos );
+                        if( remainder[0] == ' ' )
+                            remainder = remainder.substr( 1 );
+                    }
+                    else {
+                        spliceLine( indent, remainder, width-1 );
+                        lines.back() += "-";
+                    }
+                    if( lines.size() == 1 )
+                        indent = _attr.indent;
+                    if( tabPos != std::string::npos )
+                        indent += tabPos;
+                }
+            }
+        }
+
+        void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
+            lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
+            _remainder = _remainder.substr( _pos );
+        }
+
+        typedef std::vector<std::string>::const_iterator const_iterator;
+
+        const_iterator begin() const { return lines.begin(); }
+        const_iterator end() const { return lines.end(); }
+        std::string const& last() const { return lines.back(); }
+        std::size_t size() const { return lines.size(); }
+        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+
+        friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+                it != itEnd; ++it ) {
+                if( it != _text.begin() )
+                    _stream << "\n";
+                _stream << *it;
+            }
+            return _stream;
+        }
+
+    private:
+        std::string str;
+        TextAttributes attr;
+        std::vector<std::string> lines;
+    };
+
+} // end namespace Tbc
+
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TBC_TEXT_FORMAT_H_INCLUDED
+
+// ----------- end of #include from tbc_text_format.h -----------
+// ........... back in clara.h
+
+#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
+
+// ----------- #included from clara_compilers.h -----------
+
+#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
+// The following features are defined:
+//
+// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported?
+// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
+// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
+// CLARA_CONFIG_CPP11_OVERRIDE : is override supported?
+// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
+
+// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
+
+// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11
+
+#ifdef __clang__
+
+#if __has_feature(cxx_nullptr)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#if __has_feature(cxx_noexcept)
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+// - otherwise more recent versions define __cplusplus >= 201103L
+// and will get picked up below
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#if (_MSC_VER >= 1600)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if defined(__cplusplus) && __cplusplus >= 201103L
+
+#define CLARA_CPP11_OR_GREATER
+
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE)
+#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE
+#endif
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
+#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#endif // __cplusplus >= 201103L
+
+// Now set the actual defines based on the above + anything the user has configured
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_NULLPTR
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_NOEXCEPT
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_GENERATED_METHODS
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_OVERRIDE
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+// noexcept support:
+#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT)
+#define CLARA_NOEXCEPT noexcept
+#  define CLARA_NOEXCEPT_IS(x) noexcept(x)
+#else
+#define CLARA_NOEXCEPT throw()
+#  define CLARA_NOEXCEPT_IS(x)
+#endif
+
+// nullptr support
+#ifdef CLARA_CONFIG_CPP11_NULLPTR
+#define CLARA_NULL nullptr
+#else
+#define CLARA_NULL NULL
+#endif
+
+// override support
+#ifdef CLARA_CONFIG_CPP11_OVERRIDE
+#define CLARA_OVERRIDE override
+#else
+#define CLARA_OVERRIDE
+#endif
+
+// unique_ptr support
+#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR
+#   define CLARA_AUTO_PTR( T ) std::unique_ptr<T>
+#else
+#   define CLARA_AUTO_PTR( T ) std::auto_ptr<T>
+#endif
+
+#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+
+// ----------- end of #include from clara_compilers.h -----------
+// ........... back in clara.h
+
+#include <map>
+#include <stdexcept>
+#include <memory>
+
+#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#define CLARA_PLATFORM_WINDOWS
+#endif
+
+// Use optional outer namespace
+#ifdef STITCH_CLARA_OPEN_NAMESPACE
+STITCH_CLARA_OPEN_NAMESPACE
+#endif
+
+namespace Clara {
+
+    struct UnpositionalTag {};
+
+    extern UnpositionalTag _;
+
+#ifdef CLARA_CONFIG_MAIN
+    UnpositionalTag _;
+#endif
+
+    namespace Detail {
+
+#ifdef CLARA_CONSOLE_WIDTH
+    const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+        using namespace Tbc;
+
+        inline bool startsWith( std::string const& str, std::string const& prefix ) {
+            return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix;
+        }
+
+        template<typename T> struct RemoveConstRef{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T&>{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T const&>{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T const>{ typedef T type; };
+
+        template<typename T>    struct IsBool       { static const bool value = false; };
+        template<>              struct IsBool<bool> { static const bool value = true; };
+
+        template<typename T>
+        void convertInto( std::string const& _source, T& _dest ) {
+            std::stringstream ss;
+            ss << _source;
+            ss >> _dest;
+            if( ss.fail() )
+                throw std::runtime_error( "Unable to convert " + _source + " to destination type" );
+        }
+        inline void convertInto( std::string const& _source, std::string& _dest ) {
+            _dest = _source;
+        }
+        char toLowerCh(char c) {
+            return static_cast<char>( std::tolower( c ) );
+        }
+        inline void convertInto( std::string const& _source, bool& _dest ) {
+            std::string sourceLC = _source;
+            std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh );
+            if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
+                _dest = true;
+            else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
+                _dest = false;
+            else
+                throw std::runtime_error( "Expected a boolean value but did not recognise:\n  '" + _source + "'" );
+        }
+
+        template<typename ConfigT>
+        struct IArgFunction {
+            virtual ~IArgFunction() {}
+#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS
+            IArgFunction()                      = default;
+            IArgFunction( IArgFunction const& ) = default;
+#endif
+            virtual void set( ConfigT& config, std::string const& value ) const = 0;
+            virtual bool takesArg() const = 0;
+            virtual IArgFunction* clone() const = 0;
+        };
+
+        template<typename ConfigT>
+        class BoundArgFunction {
+        public:
+            BoundArgFunction() : functionObj( CLARA_NULL ) {}
+            BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
+            BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {}
+            BoundArgFunction& operator = ( BoundArgFunction const& other ) {
+                IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL;
+                delete functionObj;
+                functionObj = newFunctionObj;
+                return *this;
+            }
+            ~BoundArgFunction() { delete functionObj; }
+
+            void set( ConfigT& config, std::string const& value ) const {
+                functionObj->set( config, value );
+            }
+            bool takesArg() const { return functionObj->takesArg(); }
+
+            bool isSet() const {
+                return functionObj != CLARA_NULL;
+            }
+        private:
+            IArgFunction<ConfigT>* functionObj;
+        };
+
+        template<typename C>
+        struct NullBinder : IArgFunction<C>{
+            virtual void set( C&, std::string const& ) const {}
+            virtual bool takesArg() const { return true; }
+            virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
+        };
+
+        template<typename C, typename M>
+        struct BoundDataMember : IArgFunction<C>{
+            BoundDataMember( M C::* _member ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                convertInto( stringValue, p.*member );
+            }
+            virtual bool takesArg() const { return !IsBool<M>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
+            M C::* member;
+        };
+        template<typename C, typename M>
+        struct BoundUnaryMethod : IArgFunction<C>{
+            BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                typename RemoveConstRef<M>::type value;
+                convertInto( stringValue, value );
+                (p.*member)( value );
+            }
+            virtual bool takesArg() const { return !IsBool<M>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
+            void (C::*member)( M );
+        };
+        template<typename C>
+        struct BoundNullaryMethod : IArgFunction<C>{
+            BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                bool value;
+                convertInto( stringValue, value );
+                if( value )
+                    (p.*member)();
+            }
+            virtual bool takesArg() const { return false; }
+            virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
+            void (C::*member)();
+        };
+
+        template<typename C>
+        struct BoundUnaryFunction : IArgFunction<C>{
+            BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
+            virtual void set( C& obj, std::string const& stringValue ) const {
+                bool value;
+                convertInto( stringValue, value );
+                if( value )
+                    function( obj );
+            }
+            virtual bool takesArg() const { return false; }
+            virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
+            void (*function)( C& );
+        };
+
+        template<typename C, typename T>
+        struct BoundBinaryFunction : IArgFunction<C>{
+            BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {}
+            virtual void set( C& obj, std::string const& stringValue ) const {
+                typename RemoveConstRef<T>::type value;
+                convertInto( stringValue, value );
+                function( obj, value );
+            }
+            virtual bool takesArg() const { return !IsBool<T>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
+            void (*function)( C&, T );
+        };
+
+    } // namespace Detail
+
+    inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
+        std::vector<std::string> args( static_cast<std::size_t>( argc ) );
+        for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i )
+            args[i] = argv[i];
+
+        return args;
+    }
+
+    class Parser {
+        enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional };
+        Mode mode;
+        std::size_t from;
+        bool inQuotes;
+    public:
+
+        struct Token {
+            enum Type { Positional, ShortOpt, LongOpt };
+            Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {}
+            Type type;
+            std::string data;
+        };
+
+        Parser() : mode( None ), from( 0 ), inQuotes( false ){}
+
+        void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
+            const std::string doubleDash = "--";
+            for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
+                parseIntoTokens( args[i], tokens);
+        }
+
+        void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
+            for( std::size_t i = 0; i < arg.size(); ++i ) {
+                char c = arg[i];
+                if( c == '"' )
+                    inQuotes = !inQuotes;
+                mode = handleMode( i, c, arg, tokens );
+            }
+            mode = handleMode( arg.size(), '\0', arg, tokens );
+        }
+        Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+            switch( mode ) {
+                case None: return handleNone( i, c );
+                case MaybeShortOpt: return handleMaybeShortOpt( i, c );
+                case ShortOpt:
+                case LongOpt:
+                case SlashOpt: return handleOpt( i, c, arg, tokens );
+                case Positional: return handlePositional( i, c, arg, tokens );
+                default: throw std::logic_error( "Unknown mode" );
+            }
+        }
+
+        Mode handleNone( std::size_t i, char c ) {
+            if( inQuotes ) {
+                from = i;
+                return Positional;
+            }
+            switch( c ) {
+                case '-': return MaybeShortOpt;
+#ifdef CLARA_PLATFORM_WINDOWS
+                case '/': from = i+1; return SlashOpt;
+#endif
+                default: from = i; return Positional;
+            }
+        }
+        Mode handleMaybeShortOpt( std::size_t i, char c ) {
+            switch( c ) {
+                case '-': from = i+1; return LongOpt;
+                default: from = i; return ShortOpt;
+            }
+        }
+
+        Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+            if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
+                return mode;
+
+            std::string optName = arg.substr( from, i-from );
+            if( mode == ShortOpt )
+                for( std::size_t j = 0; j < optName.size(); ++j )
+                    tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) );
+            else if( mode == SlashOpt && optName.size() == 1 )
+                tokens.push_back( Token( Token::ShortOpt, optName ) );
+            else
+                tokens.push_back( Token( Token::LongOpt, optName ) );
+            return None;
+        }
+        Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+            if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos )
+                return mode;
+
+            std::string data = arg.substr( from, i-from );
+            tokens.push_back( Token( Token::Positional, data ) );
+            return None;
+        }
+    };
+
+    template<typename ConfigT>
+    struct CommonArgProperties {
+        CommonArgProperties() {}
+        CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
+
+        Detail::BoundArgFunction<ConfigT> boundField;
+        std::string description;
+        std::string detail;
+        std::string placeholder; // Only value if boundField takes an arg
+
+        bool takesArg() const {
+            return !placeholder.empty();
+        }
+        void validate() const {
+            if( !boundField.isSet() )
+                throw std::logic_error( "option not bound" );
+        }
+    };
+    struct OptionArgProperties {
+        std::vector<std::string> shortNames;
+        std::string longName;
+
+        bool hasShortName( std::string const& shortName ) const {
+            return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end();
+        }
+        bool hasLongName( std::string const& _longName ) const {
+            return _longName == longName;
+        }
+    };
+    struct PositionalArgProperties {
+        PositionalArgProperties() : position( -1 ) {}
+        int position; // -1 means non-positional (floating)
+
+        bool isFixedPositional() const {
+            return position != -1;
+        }
+    };
+
+    template<typename ConfigT>
+    class CommandLine {
+
+        struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties {
+            Arg() {}
+            Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {}
+
+            using CommonArgProperties<ConfigT>::placeholder; // !TBD
+
+            std::string dbgName() const {
+                if( !longName.empty() )
+                    return "--" + longName;
+                if( !shortNames.empty() )
+                    return "-" + shortNames[0];
+                return "positional args";
+            }
+            std::string commands() const {
+                std::ostringstream oss;
+                bool first = true;
+                std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
+                for(; it != itEnd; ++it ) {
+                    if( first )
+                        first = false;
+                    else
+                        oss << ", ";
+                    oss << "-" << *it;
+                }
+                if( !longName.empty() ) {
+                    if( !first )
+                        oss << ", ";
+                    oss << "--" << longName;
+                }
+                if( !placeholder.empty() )
+                    oss << " <" << placeholder << ">";
+                return oss.str();
+            }
+        };
+
+        typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr;
+
+        friend void addOptName( Arg& arg, std::string const& optName )
+        {
+            if( optName.empty() )
+                return;
+            if( Detail::startsWith( optName, "--" ) ) {
+                if( !arg.longName.empty() )
+                    throw std::logic_error( "Only one long opt may be specified. '"
+                        + arg.longName
+                        + "' already specified, now attempting to add '"
+                        + optName + "'" );
+                arg.longName = optName.substr( 2 );
+            }
+            else if( Detail::startsWith( optName, "-" ) )
+                arg.shortNames.push_back( optName.substr( 1 ) );
+            else
+                throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" );
+        }
+        friend void setPositionalArg( Arg& arg, int position )
+        {
+            arg.position = position;
+        }
+
+        class ArgBuilder {
+        public:
+            ArgBuilder( Arg* arg ) : m_arg( arg ) {}
+
+            // Bind a non-boolean data member (requires placeholder string)
+            template<typename C, typename M>
+            void bind( M C::* field, std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundDataMember<C,M>( field );
+                m_arg->placeholder = placeholder;
+            }
+            // Bind a boolean data member (no placeholder required)
+            template<typename C>
+            void bind( bool C::* field ) {
+                m_arg->boundField = new Detail::BoundDataMember<C,bool>( field );
+            }
+
+            // Bind a method taking a single, non-boolean argument (requires a placeholder string)
+            template<typename C, typename M>
+            void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod );
+                m_arg->placeholder = placeholder;
+            }
+
+            // Bind a method taking a single, boolean argument (no placeholder string required)
+            template<typename C>
+            void bind( void (C::* unaryMethod)( bool ) ) {
+                m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod );
+            }
+
+            // Bind a method that takes no arguments (will be called if opt is present)
+            template<typename C>
+            void bind( void (C::* nullaryMethod)() ) {
+                m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod );
+            }
+
+            // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
+            template<typename C>
+            void bind( void (* unaryFunction)( C& ) ) {
+                m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction );
+            }
+
+            // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
+            template<typename C, typename T>
+            void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction );
+                m_arg->placeholder = placeholder;
+            }
+
+            ArgBuilder& describe( std::string const& description ) {
+                m_arg->description = description;
+                return *this;
+            }
+            ArgBuilder& detail( std::string const& detail ) {
+                m_arg->detail = detail;
+                return *this;
+            }
+
+        protected:
+            Arg* m_arg;
+        };
+
+        class OptBuilder : public ArgBuilder {
+        public:
+            OptBuilder( Arg* arg ) : ArgBuilder( arg ) {}
+            OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {}
+
+            OptBuilder& operator[]( std::string const& optName ) {
+                addOptName( *ArgBuilder::m_arg, optName );
+                return *this;
+            }
+        };
+
+    public:
+
+        CommandLine()
+        :   m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
+            m_highestSpecifiedArgPosition( 0 ),
+            m_throwOnUnrecognisedTokens( false )
+        {}
+        CommandLine( CommandLine const& other )
+        :   m_boundProcessName( other.m_boundProcessName ),
+            m_options ( other.m_options ),
+            m_positionalArgs( other.m_positionalArgs ),
+            m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
+            m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
+        {
+            if( other.m_floatingArg.get() )
+                m_floatingArg.reset( new Arg( *other.m_floatingArg ) );
+        }
+
+        CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
+            m_throwOnUnrecognisedTokens = shouldThrow;
+            return *this;
+        }
+
+        OptBuilder operator[]( std::string const& optName ) {
+            m_options.push_back( Arg() );
+            addOptName( m_options.back(), optName );
+            OptBuilder builder( &m_options.back() );
+            return builder;
+        }
+
+        ArgBuilder operator[]( int position ) {
+            m_positionalArgs.insert( std::make_pair( position, Arg() ) );
+            if( position > m_highestSpecifiedArgPosition )
+                m_highestSpecifiedArgPosition = position;
+            setPositionalArg( m_positionalArgs[position], position );
+            ArgBuilder builder( &m_positionalArgs[position] );
+            return builder;
+        }
+
+        // Invoke this with the _ instance
+        ArgBuilder operator[]( UnpositionalTag ) {
+            if( m_floatingArg.get() )
+                throw std::logic_error( "Only one unpositional argument can be added" );
+            m_floatingArg.reset( new Arg() );
+            ArgBuilder builder( m_floatingArg.get() );
+            return builder;
+        }
+
+        template<typename C, typename M>
+        void bindProcessName( M C::* field ) {
+            m_boundProcessName = new Detail::BoundDataMember<C,M>( field );
+        }
+        template<typename C, typename M>
+        void bindProcessName( void (C::*_unaryMethod)( M ) ) {
+            m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod );
+        }
+
+        void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const {
+            typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
+            std::size_t maxWidth = 0;
+            for( it = itBegin; it != itEnd; ++it )
+                maxWidth = (std::max)( maxWidth, it->commands().size() );
+
+            for( it = itBegin; it != itEnd; ++it ) {
+                Detail::Text usage( it->commands(), Detail::TextAttributes()
+                                                        .setWidth( maxWidth+indent )
+                                                        .setIndent( indent ) );
+                Detail::Text desc( it->description, Detail::TextAttributes()
+                                                        .setWidth( width - maxWidth - 3 ) );
+
+                for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
+                    std::string usageCol = i < usage.size() ? usage[i] : "";
+                    os << usageCol;
+
+                    if( i < desc.size() && !desc[i].empty() )
+                        os  << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' )
+                            << desc[i];
+                    os << "\n";
+                }
+            }
+        }
+        std::string optUsage() const {
+            std::ostringstream oss;
+            optUsage( oss );
+            return oss.str();
+        }
+
+        void argSynopsis( std::ostream& os ) const {
+            for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) {
+                if( i > 1 )
+                    os << " ";
+                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i );
+                if( it != m_positionalArgs.end() )
+                    os << "<" << it->second.placeholder << ">";
+                else if( m_floatingArg.get() )
+                    os << "<" << m_floatingArg->placeholder << ">";
+                else
+                    throw std::logic_error( "non consecutive positional arguments with no floating args" );
+            }
+            // !TBD No indication of mandatory args
+            if( m_floatingArg.get() ) {
+                if( m_highestSpecifiedArgPosition > 1 )
+                    os << " ";
+                os << "[<" << m_floatingArg->placeholder << "> ...]";
+            }
+        }
+        std::string argSynopsis() const {
+            std::ostringstream oss;
+            argSynopsis( oss );
+            return oss.str();
+        }
+
+        void usage( std::ostream& os, std::string const& procName ) const {
+            validate();
+            os << "usage:\n  " << procName << " ";
+            argSynopsis( os );
+            if( !m_options.empty() ) {
+                os << " [options]\n\nwhere options are: \n";
+                optUsage( os, 2 );
+            }
+            os << "\n";
+        }
+        std::string usage( std::string const& procName ) const {
+            std::ostringstream oss;
+            usage( oss, procName );
+            return oss.str();
+        }
+
+        ConfigT parse( std::vector<std::string> const& args ) const {
+            ConfigT config;
+            parseInto( args, config );
+            return config;
+        }
+
+        std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
+            std::string processName = args.empty() ? std::string() : args[0];
+            std::size_t lastSlash = processName.find_last_of( "/\\" );
+            if( lastSlash != std::string::npos )
+                processName = processName.substr( lastSlash+1 );
+            m_boundProcessName.set( config, processName );
+            std::vector<Parser::Token> tokens;
+            Parser parser;
+            parser.parseIntoTokens( args, tokens );
+            return populate( tokens, config );
+        }
+
+        std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            validate();
+            std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config );
+            unusedTokens = populateFixedArgs( unusedTokens, config );
+            unusedTokens = populateFloatingArgs( unusedTokens, config );
+            return unusedTokens;
+        }
+
+        std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            std::vector<Parser::Token> unusedTokens;
+            std::vector<std::string> errors;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
+                for(; it != itEnd; ++it ) {
+                    Arg const& arg = *it;
+
+                    try {
+                        if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) ||
+                            ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
+                            if( arg.takesArg() ) {
+                                if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
+                                    errors.push_back( "Expected argument to option: " + token.data );
+                                else
+                                    arg.boundField.set( config, tokens[++i].data );
+                            }
+                            else {
+                                arg.boundField.set( config, "true" );
+                            }
+                            break;
+                        }
+                    }
+                    catch( std::exception& ex ) {
+                        errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
+                    }
+                }
+                if( it == itEnd ) {
+                    if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
+                        unusedTokens.push_back( token );
+                    else if( errors.empty() && m_throwOnUnrecognisedTokens )
+                        errors.push_back( "unrecognised option: " + token.data );
+                }
+            }
+            if( !errors.empty() ) {
+                std::ostringstream oss;
+                for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
+                        it != itEnd;
+                        ++it ) {
+                    if( it != errors.begin() )
+                        oss << "\n";
+                    oss << *it;
+                }
+                throw std::runtime_error( oss.str() );
+            }
+            return unusedTokens;
+        }
+        std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            std::vector<Parser::Token> unusedTokens;
+            int position = 1;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position );
+                if( it != m_positionalArgs.end() )
+                    it->second.boundField.set( config, token.data );
+                else
+                    unusedTokens.push_back( token );
+                if( token.type == Parser::Token::Positional )
+                    position++;
+            }
+            return unusedTokens;
+        }
+        std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            if( !m_floatingArg.get() )
+                return tokens;
+            std::vector<Parser::Token> unusedTokens;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                if( token.type == Parser::Token::Positional )
+                    m_floatingArg->boundField.set( config, token.data );
+                else
+                    unusedTokens.push_back( token );
+            }
+            return unusedTokens;
+        }
+
+        void validate() const
+        {
+            if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() )
+                throw std::logic_error( "No options or arguments specified" );
+
+            for( typename std::vector<Arg>::const_iterator  it = m_options.begin(),
+                                                            itEnd = m_options.end();
+                    it != itEnd; ++it )
+                it->validate();
+        }
+
+    private:
+        Detail::BoundArgFunction<ConfigT> m_boundProcessName;
+        std::vector<Arg> m_options;
+        std::map<int, Arg> m_positionalArgs;
+        ArgAutoPtr m_floatingArg;
+        int m_highestSpecifiedArgPosition;
+        bool m_throwOnUnrecognisedTokens;
+    };
+
+} // end namespace Clara
+
+STITCH_CLARA_CLOSE_NAMESPACE
+#undef STITCH_CLARA_OPEN_NAMESPACE
+#undef STITCH_CLARA_CLOSE_NAMESPACE
+
+#endif // TWOBLUECUBES_CLARA_H_INCLUDED
+#undef STITCH_CLARA_OPEN_NAMESPACE
+
+// Restore Clara's value for console width, if present
+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+#include <fstream>
+#include <ctime>
+
+namespace Catch {
+
+    inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
+    inline void abortAfterX( ConfigData& config, int x ) {
+        if( x < 1 )
+            throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
+        config.abortAfter = x;
+    }
+    inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
+    inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); }
+    inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
+
+    inline void addWarning( ConfigData& config, std::string const& _warning ) {
+        if( _warning == "NoAssertions" )
+            config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
+        else
+            throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' );
+    }
+    inline void setOrder( ConfigData& config, std::string const& order ) {
+        if( startsWith( "declared", order ) )
+            config.runOrder = RunTests::InDeclarationOrder;
+        else if( startsWith( "lexical", order ) )
+            config.runOrder = RunTests::InLexicographicalOrder;
+        else if( startsWith( "random", order ) )
+            config.runOrder = RunTests::InRandomOrder;
+        else
+            throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' );
+    }
+    inline void setRngSeed( ConfigData& config, std::string const& seed ) {
+        if( seed == "time" ) {
+            config.rngSeed = static_cast<unsigned int>( std::time(0) );
+        }
+        else {
+            std::stringstream ss;
+            ss << seed;
+            ss >> config.rngSeed;
+            if( ss.fail() )
+                throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" );
+        }
+    }
+    inline void setVerbosity( ConfigData& config, int level ) {
+        // !TBD: accept strings?
+        config.verbosity = static_cast<Verbosity::Level>( level );
+    }
+    inline void setShowDurations( ConfigData& config, bool _showDurations ) {
+        config.showDurations = _showDurations
+            ? ShowDurations::Always
+            : ShowDurations::Never;
+    }
+    inline void setUseColour( ConfigData& config, std::string const& value ) {
+        std::string mode = toLower( value );
+
+        if( mode == "yes" )
+            config.useColour = UseColour::Yes;
+        else if( mode == "no" )
+            config.useColour = UseColour::No;
+        else if( mode == "auto" )
+            config.useColour = UseColour::Auto;
+        else
+            throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
+    }
+    inline void setWaitForKeypress( ConfigData& config, std::string const& keypress ) {
+        std::string keypressLc = toLower( keypress );
+        if( keypressLc == "start" )
+            config.waitForKeypress = WaitForKeypress::BeforeStart;
+        else if( keypressLc == "exit" )
+            config.waitForKeypress = WaitForKeypress::BeforeExit;
+        else if( keypressLc == "both" )
+            config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
+        else
+            throw std::runtime_error( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
+    };
+
+    inline void forceColour( ConfigData& config ) {
+        config.useColour = UseColour::Yes;
+    }
+    inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
+        std::ifstream f( _filename.c_str() );
+        if( !f.is_open() )
+            throw std::domain_error( "Unable to load input file: " + _filename );
+
+        std::string line;
+        while( std::getline( f, line ) ) {
+            line = trim(line);
+            if( !line.empty() && !startsWith( line, '#' ) ) {
+                if( !startsWith( line, '"' ) )
+                    line = '"' + line + '"';
+                addTestOrTags( config, line + ',' );
+            }
+        }
+    }
+
+    inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
+
+        using namespace Clara;
+        CommandLine<ConfigData> cli;
+
+        cli.bindProcessName( &ConfigData::processName );
+
+        cli["-?"]["-h"]["--help"]
+            .describe( "display usage information" )
+            .bind( &ConfigData::showHelp );
+
+        cli["-l"]["--list-tests"]
+            .describe( "list all/matching test cases" )
+            .bind( &ConfigData::listTests );
+
+        cli["-t"]["--list-tags"]
+            .describe( "list all/matching tags" )
+            .bind( &ConfigData::listTags );
+
+        cli["-s"]["--success"]
+            .describe( "include successful tests in output" )
+            .bind( &ConfigData::showSuccessfulTests );
+
+        cli["-b"]["--break"]
+            .describe( "break into debugger on failure" )
+            .bind( &ConfigData::shouldDebugBreak );
+
+        cli["-e"]["--nothrow"]
+            .describe( "skip exception tests" )
+            .bind( &ConfigData::noThrow );
+
+        cli["-i"]["--invisibles"]
+            .describe( "show invisibles (tabs, newlines)" )
+            .bind( &ConfigData::showInvisibles );
+
+        cli["-o"]["--out"]
+            .describe( "output filename" )
+            .bind( &ConfigData::outputFilename, "filename" );
+
+        cli["-r"]["--reporter"]
+//            .placeholder( "name[:filename]" )
+            .describe( "reporter to use (defaults to console)" )
+            .bind( &addReporterName, "name" );
+
+        cli["-n"]["--name"]
+            .describe( "suite name" )
+            .bind( &ConfigData::name, "name" );
+
+        cli["-a"]["--abort"]
+            .describe( "abort at first failure" )
+            .bind( &abortAfterFirst );
+
+        cli["-x"]["--abortx"]
+            .describe( "abort after x failures" )
+            .bind( &abortAfterX, "no. failures" );
+
+        cli["-w"]["--warn"]
+            .describe( "enable warnings" )
+            .bind( &addWarning, "warning name" );
+
+// - needs updating if reinstated
+//        cli.into( &setVerbosity )
+//            .describe( "level of verbosity (0=no output)" )
+//            .shortOpt( "v")
+//            .longOpt( "verbosity" )
+//            .placeholder( "level" );
+
+        cli[_]
+            .describe( "which test or tests to use" )
+            .bind( &addTestOrTags, "test name, pattern or tags" );
+
+        cli["-d"]["--durations"]
+            .describe( "show test durations" )
+            .bind( &setShowDurations, "yes|no" );
+
+        cli["-f"]["--input-file"]
+            .describe( "load test names to run from a file" )
+            .bind( &loadTestNamesFromFile, "filename" );
+
+        cli["-#"]["--filenames-as-tags"]
+            .describe( "adds a tag for the filename" )
+            .bind( &ConfigData::filenamesAsTags );
+
+        cli["-c"]["--section"]
+                .describe( "specify section to run" )
+                .bind( &addSectionToRun, "section name" );
+
+        // Less common commands which don't have a short form
+        cli["--list-test-names-only"]
+            .describe( "list all/matching test cases names only" )
+            .bind( &ConfigData::listTestNamesOnly );
+
+        cli["--list-extra-info"]
+            .describe( "list all/matching test cases with more info" )
+            .bind( &ConfigData::listExtraInfo );
+
+        cli["--list-reporters"]
+            .describe( "list all reporters" )
+            .bind( &ConfigData::listReporters );
+
+        cli["--order"]
+            .describe( "test case order (defaults to decl)" )
+            .bind( &setOrder, "decl|lex|rand" );
+
+        cli["--rng-seed"]
+            .describe( "set a specific seed for random numbers" )
+            .bind( &setRngSeed, "'time'|number" );
+
+        cli["--force-colour"]
+            .describe( "force colourised output (deprecated)" )
+            .bind( &forceColour );
+
+        cli["--use-colour"]
+            .describe( "should output be colourised" )
+            .bind( &setUseColour, "yes|no" );
+
+        cli["--libidentify"]
+            .describe( "report name and version according to libidentify standard" )
+            .bind( &ConfigData::libIdentify );
+
+        cli["--wait-for-keypress"]
+                .describe( "waits for a keypress before exiting" )
+                .bind( &setWaitForKeypress, "start|exit|both" );
+
+        return cli;
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_list.hpp
+#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
+
+// #included from: catch_text.h
+#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
+
+#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
+// #included from: ../external/tbc_text_format.h
+// Only use header guard if we are not using an outer namespace
+#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+#  ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#   define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#  endif
+# else
+#  define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+# endif
+#endif
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#include <string>
+#include <vector>
+#include <sstream>
+
+// Use optional outer namespace
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+    struct TextAttributes {
+        TextAttributes()
+        :   initialIndent( std::string::npos ),
+            indent( 0 ),
+            width( consoleWidth-1 )
+        {}
+
+        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
+        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
+        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
+
+        std::size_t initialIndent;  // indent of first line, or npos
+        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
+        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
+    };
+
+    class Text {
+    public:
+        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+        : attr( _attr )
+        {
+            const std::string wrappableBeforeChars = "[({<\t";
+            const std::string wrappableAfterChars = "])}>-,./|\\";
+            const std::string wrappableInsteadOfChars = " \n\r";
+            std::string indent = _attr.initialIndent != std::string::npos
+                ? std::string( _attr.initialIndent, ' ' )
+                : std::string( _attr.indent, ' ' );
+
+            typedef std::string::const_iterator iterator;
+            iterator it = _str.begin();
+            const iterator strEnd = _str.end();
+
+            while( it != strEnd ) {
+
+                if( lines.size() >= 1000 ) {
+                    lines.push_back( "... message truncated due to excessive size" );
+                    return;
+                }
+
+                std::string suffix;
+                std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) );
+                iterator itEnd = it+width;
+                iterator itNext = _str.end();
+
+                iterator itNewLine = std::find( it, itEnd, '\n' );
+                if( itNewLine != itEnd )
+                    itEnd = itNewLine;
+
+                if( itEnd != strEnd  ) {
+                    bool foundWrapPoint = false;
+                    iterator findIt = itEnd;
+                    do {
+                        if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) {
+                            itEnd = findIt+1;
+                            itNext = findIt+1;
+                            foundWrapPoint = true;
+                        }
+                        else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) {
+                            itEnd = findIt;
+                            itNext = findIt;
+                            foundWrapPoint = true;
+                        }
+                        else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) {
+                            itNext = findIt+1;
+                            itEnd = findIt;
+                            foundWrapPoint = true;
+                        }
+                        if( findIt == it )
+                            break;
+                        else
+                            --findIt;
+                    }
+                    while( !foundWrapPoint );
+
+                    if( !foundWrapPoint ) {
+                        // No good wrap char, so we'll break mid word and add a hyphen
+                        --itEnd;
+                        itNext = itEnd;
+                        suffix = "-";
+                    }
+                    else {
+                        while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos )
+                            --itEnd;
+                    }
+                }
+                lines.push_back( indent + std::string( it, itEnd ) + suffix );
+
+                if( indent.size() != _attr.indent )
+                    indent = std::string( _attr.indent, ' ' );
+                it = itNext;
+            }
+        }
+
+        typedef std::vector<std::string>::const_iterator const_iterator;
+
+        const_iterator begin() const { return lines.begin(); }
+        const_iterator end() const { return lines.end(); }
+        std::string const& last() const { return lines.back(); }
+        std::size_t size() const { return lines.size(); }
+        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+
+        inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+                it != itEnd; ++it ) {
+                if( it != _text.begin() )
+                    _stream << "\n";
+                _stream << *it;
+            }
+            return _stream;
+        }
+
+    private:
+        std::string str;
+        TextAttributes attr;
+        std::vector<std::string> lines;
+    };
+
+} // end namespace Tbc
+
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+
+namespace Catch {
+    using Tbc::Text;
+    using Tbc::TextAttributes;
+}
+
+// #included from: catch_console_colour.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+
+namespace Catch {
+
+    struct Colour {
+        enum Code {
+            None = 0,
+
+            White,
+            Red,
+            Green,
+            Blue,
+            Cyan,
+            Yellow,
+            Grey,
+
+            Bright = 0x10,
+
+            BrightRed = Bright | Red,
+            BrightGreen = Bright | Green,
+            LightGrey = Bright | Grey,
+            BrightWhite = Bright | White,
+
+            // By intention
+            FileName = LightGrey,
+            Warning = Yellow,
+            ResultError = BrightRed,
+            ResultSuccess = BrightGreen,
+            ResultExpectedFailure = Warning,
+
+            Error = BrightRed,
+            Success = Green,
+
+            OriginalExpression = Cyan,
+            ReconstructedExpression = Yellow,
+
+            SecondaryText = LightGrey,
+            Headers = White
+        };
+
+        // Use constructed object for RAII guard
+        Colour( Code _colourCode );
+        Colour( Colour const& other );
+        ~Colour();
+
+        // Use static method for one-shot changes
+        static void use( Code _colourCode );
+
+    private:
+        bool m_moved;
+    };
+
+    inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; }
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_reporter.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
+
+#include <string>
+#include <ostream>
+#include <map>
+
+namespace Catch
+{
+    struct ReporterConfig {
+        explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig )
+        :   m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
+
+        ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream )
+        :   m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
+
+        std::ostream& stream() const    { return *m_stream; }
+        Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
+
+    private:
+        std::ostream* m_stream;
+        Ptr<IConfig const> m_fullConfig;
+    };
+
+    struct ReporterPreferences {
+        ReporterPreferences()
+        : shouldRedirectStdOut( false )
+        {}
+
+        bool shouldRedirectStdOut;
+    };
+
+    template<typename T>
+    struct LazyStat : Option<T> {
+        LazyStat() : used( false ) {}
+        LazyStat& operator=( T const& _value ) {
+            Option<T>::operator=( _value );
+            used = false;
+            return *this;
+        }
+        void reset() {
+            Option<T>::reset();
+            used = false;
+        }
+        bool used;
+    };
+
+    struct TestRunInfo {
+        TestRunInfo( std::string const& _name ) : name( _name ) {}
+        std::string name;
+    };
+    struct GroupInfo {
+        GroupInfo(  std::string const& _name,
+                    std::size_t _groupIndex,
+                    std::size_t _groupsCount )
+        :   name( _name ),
+            groupIndex( _groupIndex ),
+            groupsCounts( _groupsCount )
+        {}
+
+        std::string name;
+        std::size_t groupIndex;
+        std::size_t groupsCounts;
+    };
+
+    struct AssertionStats {
+        AssertionStats( AssertionResult const& _assertionResult,
+                        std::vector<MessageInfo> const& _infoMessages,
+                        Totals const& _totals )
+        :   assertionResult( _assertionResult ),
+            infoMessages( _infoMessages ),
+            totals( _totals )
+        {
+            if( assertionResult.hasMessage() ) {
+                // Copy message into messages list.
+                // !TBD This should have been done earlier, somewhere
+                MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
+                builder << assertionResult.getMessage();
+                builder.m_info.message = builder.m_stream.str();
+
+                infoMessages.push_back( builder.m_info );
+            }
+        }
+        virtual ~AssertionStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        AssertionStats( AssertionStats const& )              = default;
+        AssertionStats( AssertionStats && )                  = default;
+        AssertionStats& operator = ( AssertionStats const& ) = default;
+        AssertionStats& operator = ( AssertionStats && )     = default;
+#  endif
+
+        AssertionResult assertionResult;
+        std::vector<MessageInfo> infoMessages;
+        Totals totals;
+    };
+
+    struct SectionStats {
+        SectionStats(   SectionInfo const& _sectionInfo,
+                        Counts const& _assertions,
+                        double _durationInSeconds,
+                        bool _missingAssertions )
+        :   sectionInfo( _sectionInfo ),
+            assertions( _assertions ),
+            durationInSeconds( _durationInSeconds ),
+            missingAssertions( _missingAssertions )
+        {}
+        virtual ~SectionStats();
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        SectionStats( SectionStats const& )              = default;
+        SectionStats( SectionStats && )                  = default;
+        SectionStats& operator = ( SectionStats const& ) = default;
+        SectionStats& operator = ( SectionStats && )     = default;
+#  endif
+
+        SectionInfo sectionInfo;
+        Counts assertions;
+        double durationInSeconds;
+        bool missingAssertions;
+    };
+
+    struct TestCaseStats {
+        TestCaseStats(  TestCaseInfo const& _testInfo,
+                        Totals const& _totals,
+                        std::string const& _stdOut,
+                        std::string const& _stdErr,
+                        bool _aborting )
+        : testInfo( _testInfo ),
+            totals( _totals ),
+            stdOut( _stdOut ),
+            stdErr( _stdErr ),
+            aborting( _aborting )
+        {}
+        virtual ~TestCaseStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestCaseStats( TestCaseStats const& )              = default;
+        TestCaseStats( TestCaseStats && )                  = default;
+        TestCaseStats& operator = ( TestCaseStats const& ) = default;
+        TestCaseStats& operator = ( TestCaseStats && )     = default;
+#  endif
+
+        TestCaseInfo testInfo;
+        Totals totals;
+        std::string stdOut;
+        std::string stdErr;
+        bool aborting;
+    };
+
+    struct TestGroupStats {
+        TestGroupStats( GroupInfo const& _groupInfo,
+                        Totals const& _totals,
+                        bool _aborting )
+        :   groupInfo( _groupInfo ),
+            totals( _totals ),
+            aborting( _aborting )
+        {}
+        TestGroupStats( GroupInfo const& _groupInfo )
+        :   groupInfo( _groupInfo ),
+            aborting( false )
+        {}
+        virtual ~TestGroupStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestGroupStats( TestGroupStats const& )              = default;
+        TestGroupStats( TestGroupStats && )                  = default;
+        TestGroupStats& operator = ( TestGroupStats const& ) = default;
+        TestGroupStats& operator = ( TestGroupStats && )     = default;
+#  endif
+
+        GroupInfo groupInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+    struct TestRunStats {
+        TestRunStats(   TestRunInfo const& _runInfo,
+                        Totals const& _totals,
+                        bool _aborting )
+        :   runInfo( _runInfo ),
+            totals( _totals ),
+            aborting( _aborting )
+        {}
+        virtual ~TestRunStats();
+
+#  ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestRunStats( TestRunStats const& _other )
+        :   runInfo( _other.runInfo ),
+            totals( _other.totals ),
+            aborting( _other.aborting )
+        {}
+#  else
+        TestRunStats( TestRunStats const& )              = default;
+        TestRunStats( TestRunStats && )                  = default;
+        TestRunStats& operator = ( TestRunStats const& ) = default;
+        TestRunStats& operator = ( TestRunStats && )     = default;
+#  endif
+
+        TestRunInfo runInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+    class MultipleReporters;
+
+    struct IStreamingReporter : IShared {
+        virtual ~IStreamingReporter();
+
+        // Implementing class must also provide the following static method:
+        // static std::string getDescription();
+
+        virtual ReporterPreferences getPreferences() const = 0;
+
+        virtual void noMatchingTestCases( std::string const& spec ) = 0;
+
+        virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
+
+        virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
+
+        virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
+
+        // The return value indicates if the messages buffer should be cleared:
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
+
+        virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
+        virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
+
+        virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
+
+        virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
+    };
+
+    struct IReporterFactory : IShared {
+        virtual ~IReporterFactory();
+        virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
+        virtual std::string getDescription() const = 0;
+    };
+
+    struct IReporterRegistry {
+        typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap;
+        typedef std::vector<Ptr<IReporterFactory> > Listeners;
+
+        virtual ~IReporterRegistry();
+        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0;
+        virtual FactoryMap const& getFactories() const = 0;
+        virtual Listeners const& getListeners() const = 0;
+    };
+
+    Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter );
+
+}
+
+#include <limits>
+#include <algorithm>
+
+namespace Catch {
+
+    inline std::size_t listTests( Config const& config ) {
+
+        TestSpec testSpec = config.testSpec();
+        if( config.testSpec().hasFilters() )
+            Catch::cout() << "Matching test cases:\n";
+        else {
+            Catch::cout() << "All available test cases:\n";
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        }
+
+        std::size_t matchedTests = 0;
+        TextAttributes nameAttr, descAttr, tagsAttr;
+        nameAttr.setInitialIndent( 2 ).setIndent( 4 );
+        descAttr.setIndent( 4 );
+        tagsAttr.setIndent( 6 );
+
+        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            matchedTests++;
+            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+            Colour::Code colour = testCaseInfo.isHidden()
+                ? Colour::SecondaryText
+                : Colour::None;
+            Colour colourGuard( colour );
+
+            Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
+            if( config.listExtraInfo() ) {
+                Catch::cout() << "    " << testCaseInfo.lineInfo << std::endl;
+                std::string description = testCaseInfo.description;
+                if( description.empty() )
+                    description = "(NO DESCRIPTION)";
+                Catch::cout() << Text( description, descAttr ) << std::endl;
+            }
+            if( !testCaseInfo.tags.empty() )
+                Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
+        }
+
+        if( !config.testSpec().hasFilters() )
+            Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
+        else
+            Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
+        return matchedTests;
+    }
+
+    inline std::size_t listTestsNamesOnly( Config const& config ) {
+        TestSpec testSpec = config.testSpec();
+        if( !config.testSpec().hasFilters() )
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        std::size_t matchedTests = 0;
+        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            matchedTests++;
+            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+            if( startsWith( testCaseInfo.name, '#' ) )
+               Catch::cout() << '"' << testCaseInfo.name << '"';
+            else
+               Catch::cout() << testCaseInfo.name;
+            if ( config.listExtraInfo() )
+                Catch::cout() << "\t@" << testCaseInfo.lineInfo;
+            Catch::cout() << std::endl;
+        }
+        return matchedTests;
+    }
+
+    struct TagInfo {
+        TagInfo() : count ( 0 ) {}
+        void add( std::string const& spelling ) {
+            ++count;
+            spellings.insert( spelling );
+        }
+        std::string all() const {
+            std::string out;
+            for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
+                        it != itEnd;
+                        ++it )
+                out += "[" + *it + "]";
+            return out;
+        }
+        std::set<std::string> spellings;
+        std::size_t count;
+    };
+
+    inline std::size_t listTags( Config const& config ) {
+        TestSpec testSpec = config.testSpec();
+        if( config.testSpec().hasFilters() )
+            Catch::cout() << "Tags for matching test cases:\n";
+        else {
+            Catch::cout() << "All available tags:\n";
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        }
+
+        std::map<std::string, TagInfo> tagCounts;
+
+        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            for( std::set<std::string>::const_iterator  tagIt = it->getTestCaseInfo().tags.begin(),
+                                                        tagItEnd = it->getTestCaseInfo().tags.end();
+                    tagIt != tagItEnd;
+                    ++tagIt ) {
+                std::string tagName = *tagIt;
+                std::string lcaseTagName = toLower( tagName );
+                std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName );
+                if( countIt == tagCounts.end() )
+                    countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
+                countIt->second.add( tagName );
+            }
+        }
+
+        for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
+                                                            countItEnd = tagCounts.end();
+                countIt != countItEnd;
+                ++countIt ) {
+            std::ostringstream oss;
+            oss << "  " << std::setw(2) << countIt->second.count << "  ";
+            Text wrapper( countIt->second.all(), TextAttributes()
+                                                    .setInitialIndent( 0 )
+                                                    .setIndent( oss.str().size() )
+                                                    .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
+            Catch::cout() << oss.str() << wrapper << '\n';
+        }
+        Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
+        return tagCounts.size();
+    }
+
+    inline std::size_t listReporters( Config const& /*config*/ ) {
+        Catch::cout() << "Available reporters:\n";
+        IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+        IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
+        std::size_t maxNameLen = 0;
+        for(it = itBegin; it != itEnd; ++it )
+            maxNameLen = (std::max)( maxNameLen, it->first.size() );
+
+        for(it = itBegin; it != itEnd; ++it ) {
+            Text wrapper( it->second->getDescription(), TextAttributes()
+                                                        .setInitialIndent( 0 )
+                                                        .setIndent( 7+maxNameLen )
+                                                        .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
+            Catch::cout() << "  "
+                    << it->first
+                    << ':'
+                    << std::string( maxNameLen - it->first.size() + 2, ' ' )
+                    << wrapper << '\n';
+        }
+        Catch::cout() << std::endl;
+        return factories.size();
+    }
+
+    inline Option<std::size_t> list( Config const& config ) {
+        Option<std::size_t> listedCount;
+        if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) )
+            listedCount = listedCount.valueOr(0) + listTests( config );
+        if( config.listTestNamesOnly() )
+            listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
+        if( config.listTags() )
+            listedCount = listedCount.valueOr(0) + listTags( config );
+        if( config.listReporters() )
+            listedCount = listedCount.valueOr(0) + listReporters( config );
+        return listedCount;
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_run_context.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
+
+// #included from: catch_test_case_tracker.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+
+#include <algorithm>
+#include <string>
+#include <assert.h>
+#include <vector>
+#include <stdexcept>
+
+CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
+
+namespace Catch {
+namespace TestCaseTracking {
+
+    struct NameAndLocation {
+        std::string name;
+        SourceLineInfo location;
+
+        NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
+        :   name( _name ),
+            location( _location )
+        {}
+    };
+
+    struct ITracker : SharedImpl<> {
+        virtual ~ITracker();
+
+        // static queries
+        virtual NameAndLocation const& nameAndLocation() const = 0;
+
+        // dynamic queries
+        virtual bool isComplete() const = 0; // Successfully completed or failed
+        virtual bool isSuccessfullyCompleted() const = 0;
+        virtual bool isOpen() const = 0; // Started but not complete
+        virtual bool hasChildren() const = 0;
+
+        virtual ITracker& parent() = 0;
+
+        // actions
+        virtual void close() = 0; // Successfully complete
+        virtual void fail() = 0;
+        virtual void markAsNeedingAnotherRun() = 0;
+
+        virtual void addChild( Ptr<ITracker> const& child ) = 0;
+        virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0;
+        virtual void openChild() = 0;
+
+        // Debug/ checking
+        virtual bool isSectionTracker() const = 0;
+        virtual bool isIndexTracker() const = 0;
+    };
+
+    class  TrackerContext {
+
+        enum RunState {
+            NotStarted,
+            Executing,
+            CompletedCycle
+        };
+
+        Ptr<ITracker> m_rootTracker;
+        ITracker* m_currentTracker;
+        RunState m_runState;
+
+    public:
+
+        static TrackerContext& instance() {
+            static TrackerContext s_instance;
+            return s_instance;
+        }
+
+        TrackerContext()
+        :   m_currentTracker( CATCH_NULL ),
+            m_runState( NotStarted )
+        {}
+
+        ITracker& startRun();
+
+        void endRun() {
+            m_rootTracker.reset();
+            m_currentTracker = CATCH_NULL;
+            m_runState = NotStarted;
+        }
+
+        void startCycle() {
+            m_currentTracker = m_rootTracker.get();
+            m_runState = Executing;
+        }
+        void completeCycle() {
+            m_runState = CompletedCycle;
+        }
+
+        bool completedCycle() const {
+            return m_runState == CompletedCycle;
+        }
+        ITracker& currentTracker() {
+            return *m_currentTracker;
+        }
+        void setCurrentTracker( ITracker* tracker ) {
+            m_currentTracker = tracker;
+        }
+    };
+
+    class TrackerBase : public ITracker {
+    protected:
+        enum CycleState {
+            NotStarted,
+            Executing,
+            ExecutingChildren,
+            NeedsAnotherRun,
+            CompletedSuccessfully,
+            Failed
+        };
+        class TrackerHasName {
+            NameAndLocation m_nameAndLocation;
+        public:
+            TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
+            bool operator ()( Ptr<ITracker> const& tracker ) {
+                return
+                    tracker->nameAndLocation().name == m_nameAndLocation.name &&
+                    tracker->nameAndLocation().location == m_nameAndLocation.location;
+            }
+        };
+        typedef std::vector<Ptr<ITracker> > Children;
+        NameAndLocation m_nameAndLocation;
+        TrackerContext& m_ctx;
+        ITracker* m_parent;
+        Children m_children;
+        CycleState m_runState;
+    public:
+        TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+        :   m_nameAndLocation( nameAndLocation ),
+            m_ctx( ctx ),
+            m_parent( parent ),
+            m_runState( NotStarted )
+        {}
+        virtual ~TrackerBase();
+
+        virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE {
+            return m_nameAndLocation;
+        }
+        virtual bool isComplete() const CATCH_OVERRIDE {
+            return m_runState == CompletedSuccessfully || m_runState == Failed;
+        }
+        virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE {
+            return m_runState == CompletedSuccessfully;
+        }
+        virtual bool isOpen() const CATCH_OVERRIDE {
+            return m_runState != NotStarted && !isComplete();
+        }
+        virtual bool hasChildren() const CATCH_OVERRIDE {
+            return !m_children.empty();
+        }
+
+        virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE {
+            m_children.push_back( child );
+        }
+
+        virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE {
+            Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
+            return( it != m_children.end() )
+                ? it->get()
+                : CATCH_NULL;
+        }
+        virtual ITracker& parent() CATCH_OVERRIDE {
+            assert( m_parent ); // Should always be non-null except for root
+            return *m_parent;
+        }
+
+        virtual void openChild() CATCH_OVERRIDE {
+            if( m_runState != ExecutingChildren ) {
+                m_runState = ExecutingChildren;
+                if( m_parent )
+                    m_parent->openChild();
+            }
+        }
+
+        virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
+        virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
+
+        void open() {
+            m_runState = Executing;
+            moveToThis();
+            if( m_parent )
+                m_parent->openChild();
+        }
+
+        virtual void close() CATCH_OVERRIDE {
+
+            // Close any still open children (e.g. generators)
+            while( &m_ctx.currentTracker() != this )
+                m_ctx.currentTracker().close();
+
+            switch( m_runState ) {
+                case NotStarted:
+                case CompletedSuccessfully:
+                case Failed:
+                    throw std::logic_error( "Illogical state" );
+
+                case NeedsAnotherRun:
+                    break;;
+
+                case Executing:
+                    m_runState = CompletedSuccessfully;
+                    break;
+                case ExecutingChildren:
+                    if( m_children.empty() || m_children.back()->isComplete() )
+                        m_runState = CompletedSuccessfully;
+                    break;
+
+                default:
+                    throw std::logic_error( "Unexpected state" );
+            }
+            moveToParent();
+            m_ctx.completeCycle();
+        }
+        virtual void fail() CATCH_OVERRIDE {
+            m_runState = Failed;
+            if( m_parent )
+                m_parent->markAsNeedingAnotherRun();
+            moveToParent();
+            m_ctx.completeCycle();
+        }
+        virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE {
+            m_runState = NeedsAnotherRun;
+        }
+    private:
+        void moveToParent() {
+            assert( m_parent );
+            m_ctx.setCurrentTracker( m_parent );
+        }
+        void moveToThis() {
+            m_ctx.setCurrentTracker( this );
+        }
+    };
+
+    class SectionTracker : public TrackerBase {
+        std::vector<std::string> m_filters;
+    public:
+        SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+        :   TrackerBase( nameAndLocation, ctx, parent )
+        {
+            if( parent ) {
+                while( !parent->isSectionTracker() )
+                    parent = &parent->parent();
+
+                SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
+                addNextFilters( parentSection.m_filters );
+            }
+        }
+        virtual ~SectionTracker();
+
+        virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
+
+        static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
+            SectionTracker* section = CATCH_NULL;
+
+            ITracker& currentTracker = ctx.currentTracker();
+            if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
+                assert( childTracker );
+                assert( childTracker->isSectionTracker() );
+                section = static_cast<SectionTracker*>( childTracker );
+            }
+            else {
+                section = new SectionTracker( nameAndLocation, ctx, &currentTracker );
+                currentTracker.addChild( section );
+            }
+            if( !ctx.completedCycle() )
+                section->tryOpen();
+            return *section;
+        }
+
+        void tryOpen() {
+            if( !isComplete() && (m_filters.empty() || m_filters[0].empty() ||  m_filters[0] == m_nameAndLocation.name ) )
+                open();
+        }
+
+        void addInitialFilters( std::vector<std::string> const& filters ) {
+            if( !filters.empty() ) {
+                m_filters.push_back(""); // Root - should never be consulted
+                m_filters.push_back(""); // Test Case - not a section filter
+                m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
+            }
+        }
+        void addNextFilters( std::vector<std::string> const& filters ) {
+            if( filters.size() > 1 )
+                m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
+        }
+    };
+
+    class IndexTracker : public TrackerBase {
+        int m_size;
+        int m_index;
+    public:
+        IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
+        :   TrackerBase( nameAndLocation, ctx, parent ),
+            m_size( size ),
+            m_index( -1 )
+        {}
+        virtual ~IndexTracker();
+
+        virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
+
+        static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
+            IndexTracker* tracker = CATCH_NULL;
+
+            ITracker& currentTracker = ctx.currentTracker();
+            if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
+                assert( childTracker );
+                assert( childTracker->isIndexTracker() );
+                tracker = static_cast<IndexTracker*>( childTracker );
+            }
+            else {
+                tracker = new IndexTracker( nameAndLocation, ctx, &currentTracker, size );
+                currentTracker.addChild( tracker );
+            }
+
+            if( !ctx.completedCycle() && !tracker->isComplete() ) {
+                if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
+                    tracker->moveNext();
+                tracker->open();
+            }
+
+            return *tracker;
+        }
+
+        int index() const { return m_index; }
+
+        void moveNext() {
+            m_index++;
+            m_children.clear();
+        }
+
+        virtual void close() CATCH_OVERRIDE {
+            TrackerBase::close();
+            if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
+                m_runState = Executing;
+        }
+    };
+
+    inline ITracker& TrackerContext::startRun() {
+        m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL );
+        m_currentTracker = CATCH_NULL;
+        m_runState = Executing;
+        return *m_rootTracker;
+    }
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+using TestCaseTracking::IndexTracker;
+
+} // namespace Catch
+
+CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+// #included from: catch_fatal_condition.hpp
+#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
+
+namespace Catch {
+
+    // Report the error condition
+    inline void reportFatal( std::string const& message ) {
+        IContext& context = Catch::getCurrentContext();
+        IResultCapture* resultCapture = context.getResultCapture();
+        resultCapture->handleFatalErrorCondition( message );
+    }
+
+} // namespace Catch
+
+#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
+// #included from: catch_windows_h_proxy.h
+
+#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED
+
+#ifdef CATCH_DEFINES_NOMINMAX
+#  define NOMINMAX
+#endif
+#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+#ifdef CATCH_DEFINES_NOMINMAX
+#  undef NOMINMAX
+#endif
+#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+#  undef WIN32_LEAN_AND_MEAN
+#endif
+
+
+#  if !defined ( CATCH_CONFIG_WINDOWS_SEH )
+
+namespace Catch {
+    struct FatalConditionHandler {
+        void reset() {}
+    };
+}
+
+#  else // CATCH_CONFIG_WINDOWS_SEH is defined
+
+namespace Catch {
+
+    struct SignalDefs { DWORD id; const char* name; };
+    extern SignalDefs signalDefs[];
+    // There is no 1-1 mapping between signals and windows exceptions.
+    // Windows can easily distinguish between SO and SigSegV,
+    // but SigInt, SigTerm, etc are handled differently.
+    SignalDefs signalDefs[] = {
+        { EXCEPTION_ILLEGAL_INSTRUCTION,  "SIGILL - Illegal instruction signal" },
+        { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
+        { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
+        { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
+    };
+
+    struct FatalConditionHandler {
+
+        static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
+            for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+                if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
+                    reportFatal(signalDefs[i].name);
+                }
+            }
+            // If its not an exception we care about, pass it along.
+            // This stops us from eating debugger breaks etc.
+            return EXCEPTION_CONTINUE_SEARCH;
+        }
+
+        FatalConditionHandler() {
+            isSet = true;
+            // 32k seems enough for Catch to handle stack overflow,
+            // but the value was found experimentally, so there is no strong guarantee
+            guaranteeSize = 32 * 1024;
+            exceptionHandlerHandle = CATCH_NULL;
+            // Register as first handler in current chain
+            exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
+            // Pass in guarantee size to be filled
+            SetThreadStackGuarantee(&guaranteeSize);
+        }
+
+        static void reset() {
+            if (isSet) {
+                // Unregister handler and restore the old guarantee
+                RemoveVectoredExceptionHandler(exceptionHandlerHandle);
+                SetThreadStackGuarantee(&guaranteeSize);
+                exceptionHandlerHandle = CATCH_NULL;
+                isSet = false;
+            }
+        }
+
+        ~FatalConditionHandler() {
+            reset();
+        }
+    private:
+        static bool isSet;
+        static ULONG guaranteeSize;
+        static PVOID exceptionHandlerHandle;
+    };
+
+    bool FatalConditionHandler::isSet = false;
+    ULONG FatalConditionHandler::guaranteeSize = 0;
+    PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL;
+
+} // namespace Catch
+
+#  endif // CATCH_CONFIG_WINDOWS_SEH
+
+#else // Not Windows - assumed to be POSIX compatible //////////////////////////
+
+#  if !defined(CATCH_CONFIG_POSIX_SIGNALS)
+
+namespace Catch {
+    struct FatalConditionHandler {
+        void reset() {}
+    };
+}
+
+#  else // CATCH_CONFIG_POSIX_SIGNALS is defined
+
+#include <signal.h>
+
+namespace Catch {
+
+    struct SignalDefs {
+        int id;
+        const char* name;
+    };
+    extern SignalDefs signalDefs[];
+    SignalDefs signalDefs[] = {
+            { SIGINT,  "SIGINT - Terminal interrupt signal" },
+            { SIGILL,  "SIGILL - Illegal instruction signal" },
+            { SIGFPE,  "SIGFPE - Floating point error signal" },
+            { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
+            { SIGTERM, "SIGTERM - Termination request signal" },
+            { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
+    };
+
+    struct FatalConditionHandler {
+
+        static bool isSet;
+        static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
+        static stack_t oldSigStack;
+        static char altStackMem[SIGSTKSZ];
+
+        static void handleSignal( int sig ) {
+            std::string name = "<unknown signal>";
+            for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+                SignalDefs &def = signalDefs[i];
+                if (sig == def.id) {
+                    name = def.name;
+                    break;
+                }
+            }
+            reset();
+            reportFatal(name);
+            raise( sig );
+        }
+
+        FatalConditionHandler() {
+            isSet = true;
+            stack_t sigStack;
+            sigStack.ss_sp = altStackMem;
+            sigStack.ss_size = SIGSTKSZ;
+            sigStack.ss_flags = 0;
+            sigaltstack(&sigStack, &oldSigStack);
+            struct sigaction sa = { 0 };
+
+            sa.sa_handler = handleSignal;
+            sa.sa_flags = SA_ONSTACK;
+            for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
+                sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
+            }
+        }
+
+        ~FatalConditionHandler() {
+            reset();
+        }
+        static void reset() {
+            if( isSet ) {
+                // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
+                for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
+                    sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL);
+                }
+                // Return the old stack
+                sigaltstack(&oldSigStack, CATCH_NULL);
+                isSet = false;
+            }
+        }
+    };
+
+    bool FatalConditionHandler::isSet = false;
+    struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
+    stack_t FatalConditionHandler::oldSigStack = {};
+    char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
+
+} // namespace Catch
+
+#  endif // CATCH_CONFIG_POSIX_SIGNALS
+
+#endif // not Windows
+
+#include <set>
+#include <string>
+
+namespace Catch {
+
+    class StreamRedirect {
+
+    public:
+        StreamRedirect( std::ostream& stream, std::string& targetString )
+        :   m_stream( stream ),
+            m_prevBuf( stream.rdbuf() ),
+            m_targetString( targetString )
+        {
+            stream.rdbuf( m_oss.rdbuf() );
+        }
+
+        ~StreamRedirect() {
+            m_targetString += m_oss.str();
+            m_stream.rdbuf( m_prevBuf );
+        }
+
+    private:
+        std::ostream& m_stream;
+        std::streambuf* m_prevBuf;
+        std::ostringstream m_oss;
+        std::string& m_targetString;
+    };
+
+    // StdErr has two constituent streams in C++, std::cerr and std::clog
+    // This means that we need to redirect 2 streams into 1 to keep proper
+    // order of writes and cannot use StreamRedirect on its own
+    class StdErrRedirect {
+    public:
+        StdErrRedirect(std::string& targetString)
+        :m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()),
+        m_targetString(targetString){
+            cerr().rdbuf(m_oss.rdbuf());
+            clog().rdbuf(m_oss.rdbuf());
+        }
+        ~StdErrRedirect() {
+            m_targetString += m_oss.str();
+            cerr().rdbuf(m_cerrBuf);
+            clog().rdbuf(m_clogBuf);
+        }
+    private:
+        std::streambuf* m_cerrBuf;
+        std::streambuf* m_clogBuf;
+        std::ostringstream m_oss;
+        std::string& m_targetString;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class RunContext : public IResultCapture, public IRunner {
+
+        RunContext( RunContext const& );
+        void operator =( RunContext const& );
+
+    public:
+
+        explicit RunContext( Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter )
+        :   m_runInfo( _config->name() ),
+            m_context( getCurrentMutableContext() ),
+            m_activeTestCase( CATCH_NULL ),
+            m_config( _config ),
+            m_reporter( reporter ),
+            m_shouldReportUnexpected ( true )
+        {
+            m_context.setRunner( this );
+            m_context.setConfig( m_config );
+            m_context.setResultCapture( this );
+            m_reporter->testRunStarting( m_runInfo );
+        }
+
+        virtual ~RunContext() {
+            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
+        }
+
+        void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
+            m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
+        }
+        void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
+            m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
+        }
+
+        Totals runTest( TestCase const& testCase ) {
+            Totals prevTotals = m_totals;
+
+            std::string redirectedCout;
+            std::string redirectedCerr;
+
+            TestCaseInfo testInfo = testCase.getTestCaseInfo();
+
+            m_reporter->testCaseStarting( testInfo );
+
+            m_activeTestCase = &testCase;
+
+            do {
+                ITracker& rootTracker = m_trackerContext.startRun();
+                assert( rootTracker.isSectionTracker() );
+                static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() );
+                do {
+                    m_trackerContext.startCycle();
+                    m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
+                    runCurrentTest( redirectedCout, redirectedCerr );
+                }
+                while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
+            }
+            // !TBD: deprecated - this will be replaced by indexed trackers
+            while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
+
+            Totals deltaTotals = m_totals.delta( prevTotals );
+            if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
+                deltaTotals.assertions.failed++;
+                deltaTotals.testCases.passed--;
+                deltaTotals.testCases.failed++;
+            }
+            m_totals.testCases += deltaTotals.testCases;
+            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
+                                                        deltaTotals,
+                                                        redirectedCout,
+                                                        redirectedCerr,
+                                                        aborting() ) );
+
+            m_activeTestCase = CATCH_NULL;
+            m_testCaseTracker = CATCH_NULL;
+
+            return deltaTotals;
+        }
+
+        Ptr<IConfig const> config() const {
+            return m_config;
+        }
+
+    private: // IResultCapture
+
+        virtual void assertionEnded( AssertionResult const& result ) {
+            if( result.getResultType() == ResultWas::Ok ) {
+                m_totals.assertions.passed++;
+            }
+            else if( !result.isOk() ) {
+                if( m_activeTestCase->getTestCaseInfo().okToFail() )
+                    m_totals.assertions.failedButOk++;
+                else
+                    m_totals.assertions.failed++;
+            }
+
+            // We have no use for the return value (whether messages should be cleared), because messages were made scoped
+            // and should be let to clear themselves out.
+            static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
+
+            // Reset working state
+            m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
+            m_lastResult = result;
+        }
+
+        virtual bool lastAssertionPassed()
+        {
+            return m_totals.assertions.passed == (m_prevPassed + 1);
+        }
+
+        virtual void assertionPassed()
+        {
+            m_totals.assertions.passed++;
+            m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}";
+            m_lastAssertionInfo.macroName = "";
+        }
+
+        virtual void assertionRun()
+        {
+            m_prevPassed = m_totals.assertions.passed;
+        }
+
+        virtual bool sectionStarted (
+            SectionInfo const& sectionInfo,
+            Counts& assertions
+        )
+        {
+            ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
+            if( !sectionTracker.isOpen() )
+                return false;
+            m_activeSections.push_back( &sectionTracker );
+
+            m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+            m_reporter->sectionStarting( sectionInfo );
+
+            assertions = m_totals.assertions;
+
+            return true;
+        }
+        bool testForMissingAssertions( Counts& assertions ) {
+            if( assertions.total() != 0 )
+                return false;
+            if( !m_config->warnAboutMissingAssertions() )
+                return false;
+            if( m_trackerContext.currentTracker().hasChildren() )
+                return false;
+            m_totals.assertions.failed++;
+            assertions.failed++;
+            return true;
+        }
+
+        virtual void sectionEnded( SectionEndInfo const& endInfo ) {
+            Counts assertions = m_totals.assertions - endInfo.prevAssertions;
+            bool missingAssertions = testForMissingAssertions( assertions );
+
+            if( !m_activeSections.empty() ) {
+                m_activeSections.back()->close();
+                m_activeSections.pop_back();
+            }
+
+            m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) );
+            m_messages.clear();
+        }
+
+        virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) {
+            if( m_unfinishedSections.empty() )
+                m_activeSections.back()->fail();
+            else
+                m_activeSections.back()->close();
+            m_activeSections.pop_back();
+
+            m_unfinishedSections.push_back( endInfo );
+        }
+
+        virtual void pushScopedMessage( MessageInfo const& message ) {
+            m_messages.push_back( message );
+        }
+
+        virtual void popScopedMessage( MessageInfo const& message ) {
+            m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
+        }
+
+        virtual std::string getCurrentTestName() const {
+            return m_activeTestCase
+                ? m_activeTestCase->getTestCaseInfo().name
+                : std::string();
+        }
+
+        virtual const AssertionResult* getLastResult() const {
+            return &m_lastResult;
+        }
+
+        virtual void exceptionEarlyReported() {
+            m_shouldReportUnexpected = false;
+        }
+
+        virtual void handleFatalErrorCondition( std::string const& message ) {
+            // Don't rebuild the result -- the stringification itself can cause more fatal errors
+            // Instead, fake a result data.
+            AssertionResultData tempResult;
+            tempResult.resultType = ResultWas::FatalErrorCondition;
+            tempResult.message = message;
+            AssertionResult result(m_lastAssertionInfo, tempResult);
+
+            getResultCapture().assertionEnded(result);
+
+            handleUnfinishedSections();
+
+            // Recreate section for test case (as we will lose the one that was in scope)
+            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+            SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
+
+            Counts assertions;
+            assertions.failed = 1;
+            SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false );
+            m_reporter->sectionEnded( testCaseSectionStats );
+
+            TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
+
+            Totals deltaTotals;
+            deltaTotals.testCases.failed = 1;
+            deltaTotals.assertions.failed = 1;
+            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
+                                                        deltaTotals,
+                                                        std::string(),
+                                                        std::string(),
+                                                        false ) );
+            m_totals.testCases.failed++;
+            testGroupEnded( std::string(), m_totals, 1, 1 );
+            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
+        }
+
+    public:
+        // !TBD We need to do this another way!
+        bool aborting() const {
+            return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
+        }
+
+    private:
+
+        void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
+            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+            SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
+            m_reporter->sectionStarting( testCaseSection );
+            Counts prevAssertions = m_totals.assertions;
+            double duration = 0;
+            m_shouldReportUnexpected = true;
+            try {
+                m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
+
+                seedRng( *m_config );
+
+                Timer timer;
+                timer.start();
+                if( m_reporter->getPreferences().shouldRedirectStdOut ) {
+                    StreamRedirect coutRedir( Catch::cout(), redirectedCout );
+                    StdErrRedirect errRedir( redirectedCerr );
+                    invokeActiveTestCase();
+                }
+                else {
+                    invokeActiveTestCase();
+                }
+                duration = timer.getElapsedSeconds();
+            }
+            catch( TestFailureException& ) {
+                // This just means the test was aborted due to failure
+            }
+            catch(...) {
+                // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
+                // are reported without translation at the point of origin.
+                if (m_shouldReportUnexpected) {
+                    makeUnexpectedResultBuilder().useActiveException();
+                }
+            }
+            m_testCaseTracker->close();
+            handleUnfinishedSections();
+            m_messages.clear();
+
+            Counts assertions = m_totals.assertions - prevAssertions;
+            bool missingAssertions = testForMissingAssertions( assertions );
+
+            SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
+            m_reporter->sectionEnded( testCaseSectionStats );
+        }
+
+        void invokeActiveTestCase() {
+            FatalConditionHandler fatalConditionHandler; // Handle signals
+            m_activeTestCase->invoke();
+            fatalConditionHandler.reset();
+        }
+
+    private:
+
+        ResultBuilder makeUnexpectedResultBuilder() const {
+            return ResultBuilder(   m_lastAssertionInfo.macroName,
+                                    m_lastAssertionInfo.lineInfo,
+                                    m_lastAssertionInfo.capturedExpression,
+                                    m_lastAssertionInfo.resultDisposition );
+        }
+
+        void handleUnfinishedSections() {
+            // If sections ended prematurely due to an exception we stored their
+            // infos here so we can tear them down outside the unwind process.
+            for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
+                        itEnd = m_unfinishedSections.rend();
+                    it != itEnd;
+                    ++it )
+                sectionEnded( *it );
+            m_unfinishedSections.clear();
+        }
+
+        TestRunInfo m_runInfo;
+        IMutableContext& m_context;
+        TestCase const* m_activeTestCase;
+        ITracker* m_testCaseTracker;
+        ITracker* m_currentSectionTracker;
+        AssertionResult m_lastResult;
+
+        Ptr<IConfig const> m_config;
+        Totals m_totals;
+        Ptr<IStreamingReporter> m_reporter;
+        std::vector<MessageInfo> m_messages;
+        AssertionInfo m_lastAssertionInfo;
+        std::vector<SectionEndInfo> m_unfinishedSections;
+        std::vector<ITracker*> m_activeSections;
+        TrackerContext m_trackerContext;
+        size_t m_prevPassed;
+        bool m_shouldReportUnexpected;
+    };
+
+    IResultCapture& getResultCapture() {
+        if( IResultCapture* capture = getCurrentContext().getResultCapture() )
+            return *capture;
+        else
+            throw std::logic_error( "No result capture instance" );
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_version.h
+#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
+
+namespace Catch {
+
+    // Versioning information
+    struct Version {
+        Version(    unsigned int _majorVersion,
+                    unsigned int _minorVersion,
+                    unsigned int _patchNumber,
+                    char const * const _branchName,
+                    unsigned int _buildNumber );
+
+        unsigned int const majorVersion;
+        unsigned int const minorVersion;
+        unsigned int const patchNumber;
+
+        // buildNumber is only used if branchName is not null
+        char const * const branchName;
+        unsigned int const buildNumber;
+
+        friend std::ostream& operator << ( std::ostream& os, Version const& version );
+
+    private:
+        void operator=( Version const& );
+    };
+
+    inline Version libraryVersion();
+}
+
+#include <fstream>
+#include <stdlib.h>
+#include <limits>
+
+namespace Catch {
+
+    Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) {
+        Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() );
+        if( !reporter ) {
+            std::ostringstream oss;
+            oss << "No reporter registered with name: '" << reporterName << "'";
+            throw std::domain_error( oss.str() );
+        }
+        return reporter;
+    }
+
+#if !defined(CATCH_CONFIG_DEFAULT_REPORTER)
+#define CATCH_CONFIG_DEFAULT_REPORTER "console"
+#endif
+
+    Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
+        std::vector<std::string> reporters = config->getReporterNames();
+        if( reporters.empty() )
+            reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER );
+
+        Ptr<IStreamingReporter> reporter;
+        for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
+                it != itEnd;
+                ++it )
+            reporter = addReporter( reporter, createReporter( *it, config ) );
+        return reporter;
+    }
+    Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) {
+        IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
+        for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
+                it != itEnd;
+                ++it )
+            reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) );
+        return reporters;
+    }
+
+    Totals runTests( Ptr<Config> const& config ) {
+
+        Ptr<IConfig const> iconfig = config.get();
+
+        Ptr<IStreamingReporter> reporter = makeReporter( config );
+        reporter = addListeners( iconfig, reporter );
+
+        RunContext context( iconfig, reporter );
+
+        Totals totals;
+
+        context.testGroupStarting( config->name(), 1, 1 );
+
+        TestSpec testSpec = config->testSpec();
+        if( !testSpec.hasFilters() )
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
+
+        std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig );
+        for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
+                it != itEnd;
+                ++it ) {
+            if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) )
+                totals += context.runTest( *it );
+            else
+                reporter->skipTest( *it );
+        }
+
+        context.testGroupEnded( iconfig->name(), totals, 1, 1 );
+        return totals;
+    }
+
+    void applyFilenamesAsTags( IConfig const& config ) {
+        std::vector<TestCase> const& tests = getAllTestCasesSorted( config );
+        for(std::size_t i = 0; i < tests.size(); ++i ) {
+            TestCase& test = const_cast<TestCase&>( tests[i] );
+            std::set<std::string> tags = test.tags;
+
+            std::string filename = test.lineInfo.file;
+            std::string::size_type lastSlash = filename.find_last_of( "\\/" );
+            if( lastSlash != std::string::npos )
+                filename = filename.substr( lastSlash+1 );
+
+            std::string::size_type lastDot = filename.find_last_of( '.' );
+            if( lastDot != std::string::npos )
+                filename = filename.substr( 0, lastDot );
+
+            tags.insert( '#' + filename );
+            setTags( test, tags );
+        }
+    }
+
+    class Session : NonCopyable {
+        static bool alreadyInstantiated;
+
+    public:
+
+        struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
+
+        Session()
+        : m_cli( makeCommandLineParser() ) {
+            if( alreadyInstantiated ) {
+                std::string msg = "Only one instance of Catch::Session can ever be used";
+                Catch::cerr() << msg << std::endl;
+                throw std::logic_error( msg );
+            }
+            alreadyInstantiated = true;
+        }
+        ~Session() {
+            Catch::cleanUp();
+        }
+
+        void showHelp( std::string const& processName ) {
+            Catch::cout() << "\nCatch v" << libraryVersion() << "\n";
+
+            m_cli.usage( Catch::cout(), processName );
+            Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
+        }
+        void libIdentify() {
+            Catch::cout()
+                    << std::left << std::setw(16) << "description: " << "A Catch test executable\n"
+                    << std::left << std::setw(16) << "category: " << "testframework\n"
+                    << std::left << std::setw(16) << "framework: " << "Catch Test\n"
+                    << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
+        }
+
+        int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
+            try {
+                m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
+                m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
+                if( m_configData.showHelp )
+                    showHelp( m_configData.processName );
+                if( m_configData.libIdentify )
+                    libIdentify();
+                m_config.reset();
+            }
+            catch( std::exception& ex ) {
+                {
+                    Colour colourGuard( Colour::Red );
+                    Catch::cerr()
+                        << "\nError(s) in input:\n"
+                        << Text( ex.what(), TextAttributes().setIndent(2) )
+                        << "\n\n";
+                }
+                m_cli.usage( Catch::cout(), m_configData.processName );
+                return (std::numeric_limits<int>::max)();
+            }
+            return 0;
+        }
+
+        void useConfigData( ConfigData const& _configData ) {
+            m_configData = _configData;
+            m_config.reset();
+        }
+
+        int run( int argc, char const* const* const argv ) {
+
+            int returnCode = applyCommandLine( argc, argv );
+            if( returnCode == 0 )
+                returnCode = run();
+            return returnCode;
+        }
+
+    #if defined(WIN32) && defined(UNICODE)
+        int run( int argc, wchar_t const* const* const argv ) {
+
+            char **utf8Argv = new char *[ argc ];
+
+            for ( int i = 0; i < argc; ++i ) {
+                int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
+
+                utf8Argv[ i ] = new char[ bufSize ];
+
+                WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
+            }
+
+            int returnCode = applyCommandLine( argc, utf8Argv );
+            if( returnCode == 0 )
+                returnCode = run();
+
+            for ( int i = 0; i < argc; ++i )
+                delete [] utf8Argv[ i ];
+
+            delete [] utf8Argv;
+
+            return returnCode;
+        }
+    #endif
+
+        int run() {
+            if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
+                Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
+                static_cast<void>(std::getchar());
+            }
+            int exitCode = runInternal();
+            if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
+                Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
+                static_cast<void>(std::getchar());
+            }
+            return exitCode;
+        }
+
+        Clara::CommandLine<ConfigData> const& cli() const {
+            return m_cli;
+        }
+        std::vector<Clara::Parser::Token> const& unusedTokens() const {
+            return m_unusedTokens;
+        }
+        ConfigData& configData() {
+            return m_configData;
+        }
+        Config& config() {
+            if( !m_config )
+                m_config = new Config( m_configData );
+            return *m_config;
+        }
+    private:
+
+        int runInternal() {
+            if( m_configData.showHelp || m_configData.libIdentify )
+                return 0;
+
+            try
+            {
+                config(); // Force config to be constructed
+
+                seedRng( *m_config );
+
+                if( m_configData.filenamesAsTags )
+                    applyFilenamesAsTags( *m_config );
+
+                // Handle list request
+                if( Option<std::size_t> listed = list( config() ) )
+                    return static_cast<int>( *listed );
+
+                return static_cast<int>( runTests( m_config ).assertions.failed );
+            }
+            catch( std::exception& ex ) {
+                Catch::cerr() << ex.what() << std::endl;
+                return (std::numeric_limits<int>::max)();
+            }
+        }
+
+        Clara::CommandLine<ConfigData> m_cli;
+        std::vector<Clara::Parser::Token> m_unusedTokens;
+        ConfigData m_configData;
+        Ptr<Config> m_config;
+    };
+
+    bool Session::alreadyInstantiated = false;
+
+} // end namespace Catch
+
+// #included from: catch_registry_hub.hpp
+#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
+
+// #included from: catch_test_case_registry_impl.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <set>
+#include <sstream>
+#include <algorithm>
+
+namespace Catch {
+
+    struct RandomNumberGenerator {
+        typedef unsigned int result_type;
+
+        result_type operator()( result_type n ) const { return std::rand() % n; }
+
+#ifdef CATCH_CONFIG_CPP11_SHUFFLE
+        static constexpr result_type min() { return 0; }
+        static constexpr result_type max() { return 1000000; }
+        result_type operator()() const { return std::rand() % max(); }
+#endif
+        template<typename V>
+        static void shuffle( V& vector ) {
+            RandomNumberGenerator rng;
+#ifdef CATCH_CONFIG_CPP11_SHUFFLE
+            std::shuffle( vector.begin(), vector.end(), rng );
+#else
+            std::random_shuffle( vector.begin(), vector.end(), rng );
+#endif
+        }
+    };
+
+    inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
+
+        std::vector<TestCase> sorted = unsortedTestCases;
+
+        switch( config.runOrder() ) {
+            case RunTests::InLexicographicalOrder:
+                std::sort( sorted.begin(), sorted.end() );
+                break;
+            case RunTests::InRandomOrder:
+                {
+                    seedRng( config );
+                    RandomNumberGenerator::shuffle( sorted );
+                }
+                break;
+            case RunTests::InDeclarationOrder:
+                // already in declaration order
+                break;
+        }
+        return sorted;
+    }
+    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
+        return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
+    }
+
+    void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
+        std::set<TestCase> seenFunctions;
+        for( std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end();
+            it != itEnd;
+            ++it ) {
+            std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
+            if( !prev.second ) {
+                std::ostringstream ss;
+
+                ss  << Colour( Colour::Red )
+                    << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
+                    << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n'
+                    << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
+
+                throw std::runtime_error(ss.str());
+            }
+        }
+    }
+
+    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
+        std::vector<TestCase> filtered;
+        filtered.reserve( testCases.size() );
+        for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
+                it != itEnd;
+                ++it )
+            if( matchTest( *it, testSpec, config ) )
+                filtered.push_back( *it );
+        return filtered;
+    }
+    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
+        return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
+    }
+
+    class TestRegistry : public ITestCaseRegistry {
+    public:
+        TestRegistry()
+        :   m_currentSortOrder( RunTests::InDeclarationOrder ),
+            m_unnamedCount( 0 )
+        {}
+        virtual ~TestRegistry();
+
+        virtual void registerTest( TestCase const& testCase ) {
+            std::string name = testCase.getTestCaseInfo().name;
+            if( name.empty() ) {
+                std::ostringstream oss;
+                oss << "Anonymous test case " << ++m_unnamedCount;
+                return registerTest( testCase.withName( oss.str() ) );
+            }
+            m_functions.push_back( testCase );
+        }
+
+        virtual std::vector<TestCase> const& getAllTests() const {
+            return m_functions;
+        }
+        virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const {
+            if( m_sortedFunctions.empty() )
+                enforceNoDuplicateTestCases( m_functions );
+
+            if(  m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
+                m_sortedFunctions = sortTests( config, m_functions );
+                m_currentSortOrder = config.runOrder();
+            }
+            return m_sortedFunctions;
+        }
+
+    private:
+        std::vector<TestCase> m_functions;
+        mutable RunTests::InWhatOrder m_currentSortOrder;
+        mutable std::vector<TestCase> m_sortedFunctions;
+        size_t m_unnamedCount;
+        std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class FreeFunctionTestCase : public SharedImpl<ITestCase> {
+    public:
+
+        FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
+
+        virtual void invoke() const {
+            m_fun();
+        }
+
+    private:
+        virtual ~FreeFunctionTestCase();
+
+        TestFunction m_fun;
+    };
+
+    inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
+        std::string className = classOrQualifiedMethodName;
+        if( startsWith( className, '&' ) )
+        {
+            std::size_t lastColons = className.rfind( "::" );
+            std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
+            if( penultimateColons == std::string::npos )
+                penultimateColons = 1;
+            className = className.substr( penultimateColons, lastColons-penultimateColons );
+        }
+        return className;
+    }
+
+    void registerTestCase
+        (   ITestCase* testCase,
+            char const* classOrQualifiedMethodName,
+            NameAndDesc const& nameAndDesc,
+            SourceLineInfo const& lineInfo ) {
+
+        getMutableRegistryHub().registerTest
+            ( makeTestCase
+                (   testCase,
+                    extractClassName( classOrQualifiedMethodName ),
+                    nameAndDesc.name,
+                    nameAndDesc.description,
+                    lineInfo ) );
+    }
+    void registerTestCaseFunction
+        (   TestFunction function,
+            SourceLineInfo const& lineInfo,
+            NameAndDesc const& nameAndDesc ) {
+        registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    AutoReg::AutoReg
+        (   TestFunction function,
+            SourceLineInfo const& lineInfo,
+            NameAndDesc const& nameAndDesc ) {
+        registerTestCaseFunction( function, lineInfo, nameAndDesc );
+    }
+
+    AutoReg::~AutoReg() {}
+
+} // end namespace Catch
+
+// #included from: catch_reporter_registry.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+    class ReporterRegistry : public IReporterRegistry {
+
+    public:
+
+        virtual ~ReporterRegistry() CATCH_OVERRIDE {}
+
+        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE {
+            FactoryMap::const_iterator it =  m_factories.find( name );
+            if( it == m_factories.end() )
+                return CATCH_NULL;
+            return it->second->create( ReporterConfig( config ) );
+        }
+
+        void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) {
+            m_factories.insert( std::make_pair( name, factory ) );
+        }
+        void registerListener( Ptr<IReporterFactory> const& factory ) {
+            m_listeners.push_back( factory );
+        }
+
+        virtual FactoryMap const& getFactories() const CATCH_OVERRIDE {
+            return m_factories;
+        }
+        virtual Listeners const& getListeners() const CATCH_OVERRIDE {
+            return m_listeners;
+        }
+
+    private:
+        FactoryMap m_factories;
+        Listeners m_listeners;
+    };
+}
+
+// #included from: catch_exception_translator_registry.hpp
+#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+
+#ifdef __OBJC__
+#import "Foundation/Foundation.h"
+#endif
+
+namespace Catch {
+
+    class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
+    public:
+        ~ExceptionTranslatorRegistry() {
+            deleteAll( m_translators );
+        }
+
+        virtual void registerTranslator( const IExceptionTranslator* translator ) {
+            m_translators.push_back( translator );
+        }
+
+        virtual std::string translateActiveException() const {
+            try {
+#ifdef __OBJC__
+                // In Objective-C try objective-c exceptions first
+                @try {
+                    return tryTranslators();
+                }
+                @catch (NSException *exception) {
+                    return Catch::toString( [exception description] );
+                }
+#else
+                return tryTranslators();
+#endif
+            }
+            catch( TestFailureException& ) {
+                throw;
+            }
+            catch( std::exception& ex ) {
+                return ex.what();
+            }
+            catch( std::string& msg ) {
+                return msg;
+            }
+            catch( const char* msg ) {
+                return msg;
+            }
+            catch(...) {
+                return "Unknown exception";
+            }
+        }
+
+        std::string tryTranslators() const {
+            if( m_translators.empty() )
+                throw;
+            else
+                return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
+        }
+
+    private:
+        std::vector<const IExceptionTranslator*> m_translators;
+    };
+}
+
+// #included from: catch_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+    class TagAliasRegistry : public ITagAliasRegistry {
+    public:
+        virtual ~TagAliasRegistry();
+        virtual Option<TagAlias> find( std::string const& alias ) const;
+        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
+        void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
+
+    private:
+        std::map<std::string, TagAlias> m_registry;
+    };
+
+} // end namespace Catch
+
+namespace Catch {
+
+    namespace {
+
+        class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
+
+            RegistryHub( RegistryHub const& );
+            void operator=( RegistryHub const& );
+
+        public: // IRegistryHub
+            RegistryHub() {
+            }
+            virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE {
+                return m_reporterRegistry;
+            }
+            virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE {
+                return m_testCaseRegistry;
+            }
+            virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE {
+                return m_exceptionTranslatorRegistry;
+            }
+            virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE {
+                return m_tagAliasRegistry;
+            }
+
+        public: // IMutableRegistryHub
+            virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
+                m_reporterRegistry.registerReporter( name, factory );
+            }
+            virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
+                m_reporterRegistry.registerListener( factory );
+            }
+            virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE {
+                m_testCaseRegistry.registerTest( testInfo );
+            }
+            virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE {
+                m_exceptionTranslatorRegistry.registerTranslator( translator );
+            }
+            virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE {
+                m_tagAliasRegistry.add( alias, tag, lineInfo );
+            }
+
+        private:
+            TestRegistry m_testCaseRegistry;
+            ReporterRegistry m_reporterRegistry;
+            ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+            TagAliasRegistry m_tagAliasRegistry;
+        };
+
+        // Single, global, instance
+        inline RegistryHub*& getTheRegistryHub() {
+            static RegistryHub* theRegistryHub = CATCH_NULL;
+            if( !theRegistryHub )
+                theRegistryHub = new RegistryHub();
+            return theRegistryHub;
+        }
+    }
+
+    IRegistryHub& getRegistryHub() {
+        return *getTheRegistryHub();
+    }
+    IMutableRegistryHub& getMutableRegistryHub() {
+        return *getTheRegistryHub();
+    }
+    void cleanUp() {
+        delete getTheRegistryHub();
+        getTheRegistryHub() = CATCH_NULL;
+        cleanUpContext();
+    }
+    std::string translateActiveException() {
+        return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_notimplemented_exception.hpp
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
+
+#include <sstream>
+
+namespace Catch {
+
+    NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
+    :   m_lineInfo( lineInfo ) {
+        std::ostringstream oss;
+        oss << lineInfo << ": function ";
+        oss << "not implemented";
+        m_what = oss.str();
+    }
+
+    const char* NotImplementedException::what() const CATCH_NOEXCEPT {
+        return m_what.c_str();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_context_impl.hpp
+#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
+
+// #included from: catch_stream.hpp
+#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
+
+#include <stdexcept>
+#include <cstdio>
+#include <iostream>
+
+namespace Catch {
+
+    template<typename WriterF, size_t bufferSize=256>
+    class StreamBufImpl : public StreamBufBase {
+        char data[bufferSize];
+        WriterF m_writer;
+
+    public:
+        StreamBufImpl() {
+            setp( data, data + sizeof(data) );
+        }
+
+        ~StreamBufImpl() CATCH_NOEXCEPT {
+            sync();
+        }
+
+    private:
+        int overflow( int c ) {
+            sync();
+
+            if( c != EOF ) {
+                if( pbase() == epptr() )
+                    m_writer( std::string( 1, static_cast<char>( c ) ) );
+                else
+                    sputc( static_cast<char>( c ) );
+            }
+            return 0;
+        }
+
+        int sync() {
+            if( pbase() != pptr() ) {
+                m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
+                setp( pbase(), epptr() );
+            }
+            return 0;
+        }
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    FileStream::FileStream( std::string const& filename ) {
+        m_ofs.open( filename.c_str() );
+        if( m_ofs.fail() ) {
+            std::ostringstream oss;
+            oss << "Unable to open file: '" << filename << '\'';
+            throw std::domain_error( oss.str() );
+        }
+    }
+
+    std::ostream& FileStream::stream() const {
+        return m_ofs;
+    }
+
+    struct OutputDebugWriter {
+
+        void operator()( std::string const&str ) {
+            writeToDebugConsole( str );
+        }
+    };
+
+    DebugOutStream::DebugOutStream()
+    :   m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
+        m_os( m_streamBuf.get() )
+    {}
+
+    std::ostream& DebugOutStream::stream() const {
+        return m_os;
+    }
+
+    // Store the streambuf from cout up-front because
+    // cout may get redirected when running tests
+    CoutStream::CoutStream()
+    :   m_os( Catch::cout().rdbuf() )
+    {}
+
+    std::ostream& CoutStream::stream() const {
+        return m_os;
+    }
+
+#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
+    std::ostream& cout() {
+        return std::cout;
+    }
+    std::ostream& cerr() {
+        return std::cerr;
+    }
+    std::ostream& clog() {
+        return std::clog;
+    }
+#endif
+}
+
+namespace Catch {
+
+    class Context : public IMutableContext {
+
+        Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {}
+        Context( Context const& );
+        void operator=( Context const& );
+
+    public:
+        virtual ~Context() {
+            deleteAllValues( m_generatorsByTestName );
+        }
+
+    public: // IContext
+        virtual IResultCapture* getResultCapture() {
+            return m_resultCapture;
+        }
+        virtual IRunner* getRunner() {
+            return m_runner;
+        }
+        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
+            return getGeneratorsForCurrentTest()
+            .getGeneratorInfo( fileInfo, totalSize )
+            .getCurrentIndex();
+        }
+        virtual bool advanceGeneratorsForCurrentTest() {
+            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+            return generators && generators->moveNext();
+        }
+
+        virtual Ptr<IConfig const> getConfig() const {
+            return m_config;
+        }
+
+    public: // IMutableContext
+        virtual void setResultCapture( IResultCapture* resultCapture ) {
+            m_resultCapture = resultCapture;
+        }
+        virtual void setRunner( IRunner* runner ) {
+            m_runner = runner;
+        }
+        virtual void setConfig( Ptr<IConfig const> const& config ) {
+            m_config = config;
+        }
+
+        friend IMutableContext& getCurrentMutableContext();
+
+    private:
+        IGeneratorsForTest* findGeneratorsForCurrentTest() {
+            std::string testName = getResultCapture()->getCurrentTestName();
+
+            std::map<std::string, IGeneratorsForTest*>::const_iterator it =
+                m_generatorsByTestName.find( testName );
+            return it != m_generatorsByTestName.end()
+                ? it->second
+                : CATCH_NULL;
+        }
+
+        IGeneratorsForTest& getGeneratorsForCurrentTest() {
+            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+            if( !generators ) {
+                std::string testName = getResultCapture()->getCurrentTestName();
+                generators = createGeneratorsForTest();
+                m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
+            }
+            return *generators;
+        }
+
+    private:
+        Ptr<IConfig const> m_config;
+        IRunner* m_runner;
+        IResultCapture* m_resultCapture;
+        std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
+    };
+
+    namespace {
+        Context* currentContext = CATCH_NULL;
+    }
+    IMutableContext& getCurrentMutableContext() {
+        if( !currentContext )
+            currentContext = new Context();
+        return *currentContext;
+    }
+    IContext& getCurrentContext() {
+        return getCurrentMutableContext();
+    }
+
+    void cleanUpContext() {
+        delete currentContext;
+        currentContext = CATCH_NULL;
+    }
+}
+
+// #included from: catch_console_colour_impl.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
+
+// #included from: catch_errno_guard.hpp
+#define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED
+
+#include <cerrno>
+
+namespace Catch {
+
+    class ErrnoGuard {
+    public:
+        ErrnoGuard():m_oldErrno(errno){}
+        ~ErrnoGuard() { errno = m_oldErrno; }
+    private:
+        int m_oldErrno;
+    };
+
+}
+
+namespace Catch {
+    namespace {
+
+        struct IColourImpl {
+            virtual ~IColourImpl() {}
+            virtual void use( Colour::Code _colourCode ) = 0;
+        };
+
+        struct NoColourImpl : IColourImpl {
+            void use( Colour::Code ) {}
+
+            static IColourImpl* instance() {
+                static NoColourImpl s_instance;
+                return &s_instance;
+            }
+        };
+
+    } // anon namespace
+} // namespace Catch
+
+#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )
+#   ifdef CATCH_PLATFORM_WINDOWS
+#       define CATCH_CONFIG_COLOUR_WINDOWS
+#   else
+#       define CATCH_CONFIG_COLOUR_ANSI
+#   endif
+#endif
+
+#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
+
+namespace Catch {
+namespace {
+
+    class Win32ColourImpl : public IColourImpl {
+    public:
+        Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
+        {
+            CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+            GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
+            originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
+            originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
+        }
+
+        virtual void use( Colour::Code _colourCode ) {
+            switch( _colourCode ) {
+                case Colour::None:      return setTextAttribute( originalForegroundAttributes );
+                case Colour::White:     return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+                case Colour::Red:       return setTextAttribute( FOREGROUND_RED );
+                case Colour::Green:     return setTextAttribute( FOREGROUND_GREEN );
+                case Colour::Blue:      return setTextAttribute( FOREGROUND_BLUE );
+                case Colour::Cyan:      return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
+                case Colour::Yellow:    return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
+                case Colour::Grey:      return setTextAttribute( 0 );
+
+                case Colour::LightGrey:     return setTextAttribute( FOREGROUND_INTENSITY );
+                case Colour::BrightRed:     return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
+                case Colour::BrightGreen:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
+                case Colour::BrightWhite:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+
+                case Colour::Bright: throw std::logic_error( "not a colour" );
+            }
+        }
+
+    private:
+        void setTextAttribute( WORD _textAttribute ) {
+            SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );
+        }
+        HANDLE stdoutHandle;
+        WORD originalForegroundAttributes;
+        WORD originalBackgroundAttributes;
+    };
+
+    IColourImpl* platformColourInstance() {
+        static Win32ColourImpl s_instance;
+
+        Ptr<IConfig const> config = getCurrentContext().getConfig();
+        UseColour::YesOrNo colourMode = config
+            ? config->useColour()
+            : UseColour::Auto;
+        if( colourMode == UseColour::Auto )
+            colourMode = !isDebuggerActive()
+                ? UseColour::Yes
+                : UseColour::No;
+        return colourMode == UseColour::Yes
+            ? &s_instance
+            : NoColourImpl::instance();
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////
+
+#include <unistd.h>
+
+namespace Catch {
+namespace {
+
+    // use POSIX/ ANSI console terminal codes
+    // Thanks to Adam Strzelecki for original contribution
+    // (http://github.com/nanoant)
+    // https://github.com/philsquared/Catch/pull/131
+    class PosixColourImpl : public IColourImpl {
+    public:
+        virtual void use( Colour::Code _colourCode ) {
+            switch( _colourCode ) {
+                case Colour::None:
+                case Colour::White:     return setColour( "[0m" );
+                case Colour::Red:       return setColour( "[0;31m" );
+                case Colour::Green:     return setColour( "[0;32m" );
+                case Colour::Blue:      return setColour( "[0;34m" );
+                case Colour::Cyan:      return setColour( "[0;36m" );
+                case Colour::Yellow:    return setColour( "[0;33m" );
+                case Colour::Grey:      return setColour( "[1;30m" );
+
+                case Colour::LightGrey:     return setColour( "[0;37m" );
+                case Colour::BrightRed:     return setColour( "[1;31m" );
+                case Colour::BrightGreen:   return setColour( "[1;32m" );
+                case Colour::BrightWhite:   return setColour( "[1;37m" );
+
+                case Colour::Bright: throw std::logic_error( "not a colour" );
+            }
+        }
+        static IColourImpl* instance() {
+            static PosixColourImpl s_instance;
+            return &s_instance;
+        }
+
+    private:
+        void setColour( const char* _escapeCode ) {
+            Catch::cout() << '\033' << _escapeCode;
+        }
+    };
+
+    IColourImpl* platformColourInstance() {
+        ErrnoGuard guard;
+        Ptr<IConfig const> config = getCurrentContext().getConfig();
+        UseColour::YesOrNo colourMode = config
+            ? config->useColour()
+            : UseColour::Auto;
+        if( colourMode == UseColour::Auto )
+            colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) )
+                ? UseColour::Yes
+                : UseColour::No;
+        return colourMode == UseColour::Yes
+            ? PosixColourImpl::instance()
+            : NoColourImpl::instance();
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#else  // not Windows or ANSI ///////////////////////////////////////////////
+
+namespace Catch {
+
+    static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
+
+} // end namespace Catch
+
+#endif // Windows/ ANSI/ None
+
+namespace Catch {
+
+    Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
+    Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
+    Colour::~Colour(){ if( !m_moved ) use( None ); }
+
+    void Colour::use( Code _colourCode ) {
+        static IColourImpl* impl = platformColourInstance();
+        impl->use( _colourCode );
+    }
+
+} // end namespace Catch
+
+// #included from: catch_generators_impl.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <map>
+
+namespace Catch {
+
+    struct GeneratorInfo : IGeneratorInfo {
+
+        GeneratorInfo( std::size_t size )
+        :   m_size( size ),
+            m_currentIndex( 0 )
+        {}
+
+        bool moveNext() {
+            if( ++m_currentIndex == m_size ) {
+                m_currentIndex = 0;
+                return false;
+            }
+            return true;
+        }
+
+        std::size_t getCurrentIndex() const {
+            return m_currentIndex;
+        }
+
+        std::size_t m_size;
+        std::size_t m_currentIndex;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class GeneratorsForTest : public IGeneratorsForTest {
+
+    public:
+        ~GeneratorsForTest() {
+            deleteAll( m_generatorsInOrder );
+        }
+
+        IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
+            std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
+            if( it == m_generatorsByName.end() ) {
+                IGeneratorInfo* info = new GeneratorInfo( size );
+                m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
+                m_generatorsInOrder.push_back( info );
+                return *info;
+            }
+            return *it->second;
+        }
+
+        bool moveNext() {
+            std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
+            std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
+            for(; it != itEnd; ++it ) {
+                if( (*it)->moveNext() )
+                    return true;
+            }
+            return false;
+        }
+
+    private:
+        std::map<std::string, IGeneratorInfo*> m_generatorsByName;
+        std::vector<IGeneratorInfo*> m_generatorsInOrder;
+    };
+
+    IGeneratorsForTest* createGeneratorsForTest()
+    {
+        return new GeneratorsForTest();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.hpp
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
+
+namespace Catch {
+
+    AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){}
+
+    AssertionInfo::AssertionInfo(   char const * _macroName,
+                                    SourceLineInfo const& _lineInfo,
+                                    char const * _capturedExpression,
+                                    ResultDisposition::Flags _resultDisposition,
+                                    char const * _secondArg)
+    :   macroName( _macroName ),
+        lineInfo( _lineInfo ),
+        capturedExpression( _capturedExpression ),
+        resultDisposition( _resultDisposition ),
+        secondArg( _secondArg )
+    {}
+
+    AssertionResult::AssertionResult() {}
+
+    AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
+    :   m_info( info ),
+        m_resultData( data )
+    {}
+
+    AssertionResult::~AssertionResult() {}
+
+    // Result was a success
+    bool AssertionResult::succeeded() const {
+        return Catch::isOk( m_resultData.resultType );
+    }
+
+    // Result was a success, or failure is suppressed
+    bool AssertionResult::isOk() const {
+        return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
+    }
+
+    ResultWas::OfType AssertionResult::getResultType() const {
+        return m_resultData.resultType;
+    }
+
+    bool AssertionResult::hasExpression() const {
+        return m_info.capturedExpression[0] != 0;
+    }
+
+    bool AssertionResult::hasMessage() const {
+        return !m_resultData.message.empty();
+    }
+
+    std::string capturedExpressionWithSecondArgument( char const * capturedExpression, char const * secondArg ) {
+        return (secondArg[0] == 0 || secondArg[0] == '"' && secondArg[1] == '"')
+            ? capturedExpression
+            : std::string(capturedExpression) + ", " + secondArg;
+    }
+
+    std::string AssertionResult::getExpression() const {
+        if( isFalseTest( m_info.resultDisposition ) )
+            return "!(" + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + ")";
+        else
+            return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
+    }
+    std::string AssertionResult::getExpressionInMacro() const {
+        if( m_info.macroName[0] == 0 )
+            return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
+        else
+            return std::string(m_info.macroName) + "( " + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + " )";
+    }
+
+    bool AssertionResult::hasExpandedExpression() const {
+        return hasExpression() && getExpandedExpression() != getExpression();
+    }
+
+    std::string AssertionResult::getExpandedExpression() const {
+        return m_resultData.reconstructExpression();
+    }
+
+    std::string AssertionResult::getMessage() const {
+        return m_resultData.message;
+    }
+    SourceLineInfo AssertionResult::getSourceInfo() const {
+        return m_info.lineInfo;
+    }
+
+    std::string AssertionResult::getTestMacroName() const {
+        return m_info.macroName;
+    }
+
+    void AssertionResult::discardDecomposedExpression() const {
+        m_resultData.decomposedExpression = CATCH_NULL;
+    }
+
+    void AssertionResult::expandDecomposedExpression() const {
+        m_resultData.reconstructExpression();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_test_case_info.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
+
+#include <cctype>
+
+namespace Catch {
+
+    inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
+        if( startsWith( tag, '.' ) ||
+            tag == "hide" ||
+            tag == "!hide" )
+            return TestCaseInfo::IsHidden;
+        else if( tag == "!throws" )
+            return TestCaseInfo::Throws;
+        else if( tag == "!shouldfail" )
+            return TestCaseInfo::ShouldFail;
+        else if( tag == "!mayfail" )
+            return TestCaseInfo::MayFail;
+        else if( tag == "!nonportable" )
+            return TestCaseInfo::NonPortable;
+        else
+            return TestCaseInfo::None;
+    }
+    inline bool isReservedTag( std::string const& tag ) {
+        return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] );
+    }
+    inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
+        if( isReservedTag( tag ) ) {
+            std::ostringstream ss;
+            ss << Colour(Colour::Red)
+               << "Tag name [" << tag << "] not allowed.\n"
+               << "Tag names starting with non alpha-numeric characters are reserved\n"
+               << Colour(Colour::FileName)
+               << _lineInfo << '\n';
+            throw std::runtime_error(ss.str());
+        }
+    }
+
+    TestCase makeTestCase(  ITestCase* _testCase,
+                            std::string const& _className,
+                            std::string const& _name,
+                            std::string const& _descOrTags,
+                            SourceLineInfo const& _lineInfo )
+    {
+        bool isHidden( startsWith( _name, "./" ) ); // Legacy support
+
+        // Parse out tags
+        std::set<std::string> tags;
+        std::string desc, tag;
+        bool inTag = false;
+        for( std::size_t i = 0; i < _descOrTags.size(); ++i ) {
+            char c = _descOrTags[i];
+            if( !inTag ) {
+                if( c == '[' )
+                    inTag = true;
+                else
+                    desc += c;
+            }
+            else {
+                if( c == ']' ) {
+                    TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );
+                    if( prop == TestCaseInfo::IsHidden )
+                        isHidden = true;
+                    else if( prop == TestCaseInfo::None )
+                        enforceNotReservedTag( tag, _lineInfo );
+
+                    tags.insert( tag );
+                    tag.clear();
+                    inTag = false;
+                }
+                else
+                    tag += c;
+            }
+        }
+        if( isHidden ) {
+            tags.insert( "hide" );
+            tags.insert( "." );
+        }
+
+        TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
+        return TestCase( _testCase, info );
+    }
+
+    void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags )
+    {
+        testCaseInfo.tags = tags;
+        testCaseInfo.lcaseTags.clear();
+
+        std::ostringstream oss;
+        for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) {
+            oss << '[' << *it << ']';
+            std::string lcaseTag = toLower( *it );
+            testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
+            testCaseInfo.lcaseTags.insert( lcaseTag );
+        }
+        testCaseInfo.tagsAsString = oss.str();
+    }
+
+    TestCaseInfo::TestCaseInfo( std::string const& _name,
+                                std::string const& _className,
+                                std::string const& _description,
+                                std::set<std::string> const& _tags,
+                                SourceLineInfo const& _lineInfo )
+    :   name( _name ),
+        className( _className ),
+        description( _description ),
+        lineInfo( _lineInfo ),
+        properties( None )
+    {
+        setTags( *this, _tags );
+    }
+
+    TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
+    :   name( other.name ),
+        className( other.className ),
+        description( other.description ),
+        tags( other.tags ),
+        lcaseTags( other.lcaseTags ),
+        tagsAsString( other.tagsAsString ),
+        lineInfo( other.lineInfo ),
+        properties( other.properties )
+    {}
+
+    bool TestCaseInfo::isHidden() const {
+        return ( properties & IsHidden ) != 0;
+    }
+    bool TestCaseInfo::throws() const {
+        return ( properties & Throws ) != 0;
+    }
+    bool TestCaseInfo::okToFail() const {
+        return ( properties & (ShouldFail | MayFail ) ) != 0;
+    }
+    bool TestCaseInfo::expectedToFail() const {
+        return ( properties & (ShouldFail ) ) != 0;
+    }
+
+    TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
+
+    TestCase::TestCase( TestCase const& other )
+    :   TestCaseInfo( other ),
+        test( other.test )
+    {}
+
+    TestCase TestCase::withName( std::string const& _newName ) const {
+        TestCase other( *this );
+        other.name = _newName;
+        return other;
+    }
+
+    void TestCase::swap( TestCase& other ) {
+        test.swap( other.test );
+        name.swap( other.name );
+        className.swap( other.className );
+        description.swap( other.description );
+        tags.swap( other.tags );
+        lcaseTags.swap( other.lcaseTags );
+        tagsAsString.swap( other.tagsAsString );
+        std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties );
+        std::swap( lineInfo, other.lineInfo );
+    }
+
+    void TestCase::invoke() const {
+        test->invoke();
+    }
+
+    bool TestCase::operator == ( TestCase const& other ) const {
+        return  test.get() == other.test.get() &&
+                name == other.name &&
+                className == other.className;
+    }
+
+    bool TestCase::operator < ( TestCase const& other ) const {
+        return name < other.name;
+    }
+    TestCase& TestCase::operator = ( TestCase const& other ) {
+        TestCase temp( other );
+        swap( temp );
+        return *this;
+    }
+
+    TestCaseInfo const& TestCase::getTestCaseInfo() const
+    {
+        return *this;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_version.hpp
+#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
+
+namespace Catch {
+
+    Version::Version
+        (   unsigned int _majorVersion,
+            unsigned int _minorVersion,
+            unsigned int _patchNumber,
+            char const * const _branchName,
+            unsigned int _buildNumber )
+    :   majorVersion( _majorVersion ),
+        minorVersion( _minorVersion ),
+        patchNumber( _patchNumber ),
+        branchName( _branchName ),
+        buildNumber( _buildNumber )
+    {}
+
+    std::ostream& operator << ( std::ostream& os, Version const& version ) {
+        os  << version.majorVersion << '.'
+            << version.minorVersion << '.'
+            << version.patchNumber;
+        // branchName is never null -> 0th char is \0 if it is empty
+        if (version.branchName[0]) {
+            os << '-' << version.branchName
+               << '.' << version.buildNumber;
+        }
+        return os;
+    }
+
+    inline Version libraryVersion() {
+        static Version version( 1, 12, 0, "", 0 );
+        return version;
+    }
+
+}
+
+// #included from: catch_message.hpp
+#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
+
+namespace Catch {
+
+    MessageInfo::MessageInfo(   std::string const& _macroName,
+                                SourceLineInfo const& _lineInfo,
+                                ResultWas::OfType _type )
+    :   macroName( _macroName ),
+        lineInfo( _lineInfo ),
+        type( _type ),
+        sequence( ++globalCount )
+    {}
+
+    // This may need protecting if threading support is added
+    unsigned int MessageInfo::globalCount = 0;
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    ScopedMessage::ScopedMessage( MessageBuilder const& builder )
+    : m_info( builder.m_info )
+    {
+        m_info.message = builder.m_stream.str();
+        getResultCapture().pushScopedMessage( m_info );
+    }
+    ScopedMessage::ScopedMessage( ScopedMessage const& other )
+    : m_info( other.m_info )
+    {}
+
+    ScopedMessage::~ScopedMessage() {
+        if ( !std::uncaught_exception() ){
+            getResultCapture().popScopedMessage(m_info);
+        }
+    }
+
+} // end namespace Catch
+
+// #included from: catch_legacy_reporter_adapter.hpp
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
+
+// #included from: catch_legacy_reporter_adapter.h
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
+
+namespace Catch
+{
+    // Deprecated
+    struct IReporter : IShared {
+        virtual ~IReporter();
+
+        virtual bool shouldRedirectStdout() const = 0;
+
+        virtual void StartTesting() = 0;
+        virtual void EndTesting( Totals const& totals ) = 0;
+        virtual void StartGroup( std::string const& groupName ) = 0;
+        virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
+        virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
+        virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
+        virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
+        virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
+        virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
+        virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
+        virtual void Aborted() = 0;
+        virtual void Result( AssertionResult const& result ) = 0;
+    };
+
+    class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
+    {
+    public:
+        LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
+        virtual ~LegacyReporterAdapter();
+
+        virtual ReporterPreferences getPreferences() const;
+        virtual void noMatchingTestCases( std::string const& );
+        virtual void testRunStarting( TestRunInfo const& );
+        virtual void testGroupStarting( GroupInfo const& groupInfo );
+        virtual void testCaseStarting( TestCaseInfo const& testInfo );
+        virtual void sectionStarting( SectionInfo const& sectionInfo );
+        virtual void assertionStarting( AssertionInfo const& );
+        virtual bool assertionEnded( AssertionStats const& assertionStats );
+        virtual void sectionEnded( SectionStats const& sectionStats );
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats );
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats );
+        virtual void testRunEnded( TestRunStats const& testRunStats );
+        virtual void skipTest( TestCaseInfo const& );
+
+    private:
+        Ptr<IReporter> m_legacyReporter;
+    };
+}
+
+namespace Catch
+{
+    LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
+    :   m_legacyReporter( legacyReporter )
+    {}
+    LegacyReporterAdapter::~LegacyReporterAdapter() {}
+
+    ReporterPreferences LegacyReporterAdapter::getPreferences() const {
+        ReporterPreferences prefs;
+        prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
+        return prefs;
+    }
+
+    void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
+    void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
+        m_legacyReporter->StartTesting();
+    }
+    void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
+        m_legacyReporter->StartGroup( groupInfo.name );
+    }
+    void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
+        m_legacyReporter->StartTestCase( testInfo );
+    }
+    void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
+        m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
+    }
+    void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
+        // Not on legacy interface
+    }
+
+    bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
+        if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
+            for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+                    it != itEnd;
+                    ++it ) {
+                if( it->type == ResultWas::Info ) {
+                    ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal );
+                    rb << it->message;
+                    rb.setResultType( ResultWas::Info );
+                    AssertionResult result = rb.build();
+                    m_legacyReporter->Result( result );
+                }
+            }
+        }
+        m_legacyReporter->Result( assertionStats.assertionResult );
+        return true;
+    }
+    void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
+        if( sectionStats.missingAssertions )
+            m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
+        m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
+    }
+    void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+        m_legacyReporter->EndTestCase
+            (   testCaseStats.testInfo,
+                testCaseStats.totals,
+                testCaseStats.stdOut,
+                testCaseStats.stdErr );
+    }
+    void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+        if( testGroupStats.aborting )
+            m_legacyReporter->Aborted();
+        m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
+    }
+    void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
+        m_legacyReporter->EndTesting( testRunStats.totals );
+    }
+    void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) {
+    }
+}
+
+// #included from: catch_timer.hpp
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#endif
+
+#ifdef CATCH_PLATFORM_WINDOWS
+
+#else
+
+#include <sys/time.h>
+
+#endif
+
+namespace Catch {
+
+    namespace {
+#ifdef CATCH_PLATFORM_WINDOWS
+        UInt64 getCurrentTicks() {
+            static UInt64 hz=0, hzo=0;
+            if (!hz) {
+                QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) );
+                QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) );
+            }
+            UInt64 t;
+            QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) );
+            return ((t-hzo)*1000000)/hz;
+        }
+#else
+        UInt64 getCurrentTicks() {
+            timeval t;
+            gettimeofday(&t,CATCH_NULL);
+            return static_cast<UInt64>( t.tv_sec ) * 1000000ull + static_cast<UInt64>( t.tv_usec );
+        }
+#endif
+    }
+
+    void Timer::start() {
+        m_ticks = getCurrentTicks();
+    }
+    unsigned int Timer::getElapsedMicroseconds() const {
+        return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
+    }
+    unsigned int Timer::getElapsedMilliseconds() const {
+        return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
+    }
+    double Timer::getElapsedSeconds() const {
+        return getElapsedMicroseconds()/1000000.0;
+    }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+// #included from: catch_common.hpp
+#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+
+#include <cstring>
+#include <cctype>
+
+namespace Catch {
+
+    bool startsWith( std::string const& s, std::string const& prefix ) {
+        return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
+    }
+    bool startsWith( std::string const& s, char prefix ) {
+        return !s.empty() && s[0] == prefix;
+    }
+    bool endsWith( std::string const& s, std::string const& suffix ) {
+        return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
+    }
+    bool endsWith( std::string const& s, char suffix ) {
+        return !s.empty() && s[s.size()-1] == suffix;
+    }
+    bool contains( std::string const& s, std::string const& infix ) {
+        return s.find( infix ) != std::string::npos;
+    }
+    char toLowerCh(char c) {
+        return static_cast<char>( std::tolower( c ) );
+    }
+    void toLowerInPlace( std::string& s ) {
+        std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
+    }
+    std::string toLower( std::string const& s ) {
+        std::string lc = s;
+        toLowerInPlace( lc );
+        return lc;
+    }
+    std::string trim( std::string const& str ) {
+        static char const* whitespaceChars = "\n\r\t ";
+        std::string::size_type start = str.find_first_not_of( whitespaceChars );
+        std::string::size_type end = str.find_last_not_of( whitespaceChars );
+
+        return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
+    }
+
+    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
+        bool replaced = false;
+        std::size_t i = str.find( replaceThis );
+        while( i != std::string::npos ) {
+            replaced = true;
+            str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
+            if( i < str.size()-withThis.size() )
+                i = str.find( replaceThis, i+withThis.size() );
+            else
+                i = std::string::npos;
+        }
+        return replaced;
+    }
+
+    pluralise::pluralise( std::size_t count, std::string const& label )
+    :   m_count( count ),
+        m_label( label )
+    {}
+
+    std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
+        os << pluraliser.m_count << ' ' << pluraliser.m_label;
+        if( pluraliser.m_count != 1 )
+            os << 's';
+        return os;
+    }
+
+    SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){}
+    SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
+    :   file( _file ),
+        line( _line )
+    {}
+    bool SourceLineInfo::empty() const {
+        return file[0] == '\0';
+    }
+    bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
+        return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
+    }
+    bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
+        return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
+    }
+
+    void seedRng( IConfig const& config ) {
+        if( config.rngSeed() != 0 )
+            std::srand( config.rngSeed() );
+    }
+    unsigned int rngSeed() {
+        return getCurrentContext().getConfig()->rngSeed();
+    }
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
+#ifndef __GNUG__
+        os << info.file << '(' << info.line << ')';
+#else
+        os << info.file << ':' << info.line;
+#endif
+        return os;
+    }
+
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
+        std::ostringstream oss;
+        oss << locationInfo << ": Internal Catch error: '" << message << '\'';
+        if( alwaysTrue() )
+            throw std::logic_error( oss.str() );
+    }
+}
+
+// #included from: catch_section.hpp
+#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
+
+namespace Catch {
+
+    SectionInfo::SectionInfo
+        (   SourceLineInfo const& _lineInfo,
+            std::string const& _name,
+            std::string const& _description )
+    :   name( _name ),
+        description( _description ),
+        lineInfo( _lineInfo )
+    {}
+
+    Section::Section( SectionInfo const& info )
+    :   m_info( info ),
+        m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
+    {
+        m_timer.start();
+    }
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17
+#endif
+    Section::~Section() {
+        if( m_sectionIncluded ) {
+            SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
+            if( std::uncaught_exception() )
+                getResultCapture().sectionEndedEarly( endInfo );
+            else
+                getResultCapture().sectionEnded( endInfo );
+        }
+    }
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+    // This indicates whether the section should be executed or not
+    Section::operator bool() const {
+        return m_sectionIncluded;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_debugger.hpp
+#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
+
+#ifdef CATCH_PLATFORM_MAC
+
+    #include <assert.h>
+    #include <stdbool.h>
+    #include <sys/types.h>
+    #include <unistd.h>
+    #include <sys/sysctl.h>
+
+    namespace Catch{
+
+        // The following function is taken directly from the following technical note:
+        // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
+
+        // Returns true if the current process is being debugged (either
+        // running under the debugger or has a debugger attached post facto).
+        bool isDebuggerActive(){
+
+            int                 mib[4];
+            struct kinfo_proc   info;
+            size_t              size;
+
+            // Initialize the flags so that, if sysctl fails for some bizarre
+            // reason, we get a predictable result.
+
+            info.kp_proc.p_flag = 0;
+
+            // Initialize mib, which tells sysctl the info we want, in this case
+            // we're looking for information about a specific process ID.
+
+            mib[0] = CTL_KERN;
+            mib[1] = KERN_PROC;
+            mib[2] = KERN_PROC_PID;
+            mib[3] = getpid();
+
+            // Call sysctl.
+
+            size = sizeof(info);
+            if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) {
+                Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
+                return false;
+            }
+
+            // We're being debugged if the P_TRACED flag is set.
+
+            return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
+        }
+    } // namespace Catch
+
+#elif defined(CATCH_PLATFORM_LINUX)
+    #include <fstream>
+    #include <string>
+
+    namespace Catch{
+        // The standard POSIX way of detecting a debugger is to attempt to
+        // ptrace() the process, but this needs to be done from a child and not
+        // this process itself to still allow attaching to this process later
+        // if wanted, so is rather heavy. Under Linux we have the PID of the
+        // "debugger" (which doesn't need to be gdb, of course, it could also
+        // be strace, for example) in /proc/$PID/status, so just get it from
+        // there instead.
+        bool isDebuggerActive(){
+            // Libstdc++ has a bug, where std::ifstream sets errno to 0
+            // This way our users can properly assert over errno values
+            ErrnoGuard guard;
+            std::ifstream in("/proc/self/status");
+            for( std::string line; std::getline(in, line); ) {
+                static const int PREFIX_LEN = 11;
+                if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
+                    // We're traced if the PID is not 0 and no other PID starts
+                    // with 0 digit, so it's enough to check for just a single
+                    // character.
+                    return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
+                }
+            }
+
+            return false;
+        }
+    } // namespace Catch
+#elif defined(_MSC_VER)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#else
+    namespace Catch {
+       inline bool isDebuggerActive() { return false; }
+    }
+#endif // Platform
+
+#ifdef CATCH_PLATFORM_WINDOWS
+
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            ::OutputDebugStringA( text.c_str() );
+        }
+    }
+#else
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            // !TBD: Need a version for Mac/ XCode and other IDEs
+            Catch::cout() << text;
+        }
+    }
+#endif // Platform
+
+// #included from: catch_tostring.hpp
+#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
+
+namespace Catch {
+
+namespace Detail {
+
+    const std::string unprintableString = "{?}";
+
+    namespace {
+        const int hexThreshold = 255;
+
+        struct Endianness {
+            enum Arch { Big, Little };
+
+            static Arch which() {
+                union _{
+                    int asInt;
+                    char asChar[sizeof (int)];
+                } u;
+
+                u.asInt = 1;
+                return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
+            }
+        };
+    }
+
+    std::string rawMemoryToString( const void *object, std::size_t size )
+    {
+        // Reverse order for little endian architectures
+        int i = 0, end = static_cast<int>( size ), inc = 1;
+        if( Endianness::which() == Endianness::Little ) {
+            i = end-1;
+            end = inc = -1;
+        }
+
+        unsigned char const *bytes = static_cast<unsigned char const *>(object);
+        std::ostringstream os;
+        os << "0x" << std::setfill('0') << std::hex;
+        for( ; i != end; i += inc )
+             os << std::setw(2) << static_cast<unsigned>(bytes[i]);
+       return os.str();
+    }
+}
+
+std::string toString( std::string const& value ) {
+    std::string s = value;
+    if( getCurrentContext().getConfig()->showInvisibles() ) {
+        for(size_t i = 0; i < s.size(); ++i ) {
+            std::string subs;
+            switch( s[i] ) {
+            case '\n': subs = "\\n"; break;
+            case '\t': subs = "\\t"; break;
+            default: break;
+            }
+            if( !subs.empty() ) {
+                s = s.substr( 0, i ) + subs + s.substr( i+1 );
+                ++i;
+            }
+        }
+    }
+    return '"' + s + '"';
+}
+std::string toString( std::wstring const& value ) {
+
+    std::string s;
+    s.reserve( value.size() );
+    for(size_t i = 0; i < value.size(); ++i )
+        s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
+    return Catch::toString( s );
+}
+
+std::string toString( const char* const value ) {
+    return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
+}
+
+std::string toString( char* const value ) {
+    return Catch::toString( static_cast<const char*>( value ) );
+}
+
+std::string toString( const wchar_t* const value )
+{
+    return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
+}
+
+std::string toString( wchar_t* const value )
+{
+    return Catch::toString( static_cast<const wchar_t*>( value ) );
+}
+
+std::string toString( int value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+
+std::string toString( unsigned long value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+
+std::string toString( unsigned int value ) {
+    return Catch::toString( static_cast<unsigned long>( value ) );
+}
+
+template<typename T>
+std::string fpToString( T value, int precision ) {
+    std::ostringstream oss;
+    oss << std::setprecision( precision )
+        << std::fixed
+        << value;
+    std::string d = oss.str();
+    std::size_t i = d.find_last_not_of( '0' );
+    if( i != std::string::npos && i != d.size()-1 ) {
+        if( d[i] == '.' )
+            i++;
+        d = d.substr( 0, i+1 );
+    }
+    return d;
+}
+
+std::string toString( const double value ) {
+    return fpToString( value, 10 );
+}
+std::string toString( const float value ) {
+    return fpToString( value, 5 ) + 'f';
+}
+
+std::string toString( bool value ) {
+    return value ? "true" : "false";
+}
+
+std::string toString( char value ) {
+    if ( value == '\r' )
+        return "'\\r'";
+    if ( value == '\f' )
+        return "'\\f'";
+    if ( value == '\n' )
+        return "'\\n'";
+    if ( value == '\t' )
+        return "'\\t'";
+    if ( '\0' <= value && value < ' ' )
+        return toString( static_cast<unsigned int>( value ) );
+    char chstr[] = "' '";
+    chstr[1] = value;
+    return chstr;
+}
+
+std::string toString( signed char value ) {
+    return toString( static_cast<char>( value ) );
+}
+
+std::string toString( unsigned char value ) {
+    return toString( static_cast<char>( value ) );
+}
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString( long long value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+std::string toString( unsigned long long value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t ) {
+    return "nullptr";
+}
+#endif
+
+#ifdef __OBJC__
+    std::string toString( NSString const * const& nsstring ) {
+        if( !nsstring )
+            return "nil";
+        return "@" + toString([nsstring UTF8String]);
+    }
+    std::string toString( NSString * CATCH_ARC_STRONG & nsstring ) {
+        if( !nsstring )
+            return "nil";
+        return "@" + toString([nsstring UTF8String]);
+    }
+    std::string toString( NSObject* const& nsObject ) {
+        return toString( [nsObject description] );
+    }
+#endif
+
+} // end namespace Catch
+
+// #included from: catch_result_builder.hpp
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
+
+namespace Catch {
+
+    ResultBuilder::ResultBuilder(   char const* macroName,
+                                    SourceLineInfo const& lineInfo,
+                                    char const* capturedExpression,
+                                    ResultDisposition::Flags resultDisposition,
+                                    char const* secondArg )
+    :   m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ),
+        m_shouldDebugBreak( false ),
+        m_shouldThrow( false ),
+        m_guardException( false ),
+        m_usedStream( false )
+    {}
+
+    ResultBuilder::~ResultBuilder() {
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+        if ( m_guardException ) {
+            stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
+            captureResult( ResultWas::ThrewException );
+            getCurrentContext().getResultCapture()->exceptionEarlyReported();
+        }
+#endif
+    }
+
+    ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
+        m_data.resultType = result;
+        return *this;
+    }
+    ResultBuilder& ResultBuilder::setResultType( bool result ) {
+        m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
+        return *this;
+    }
+
+    void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
+        // Flip bool results if FalseTest flag is set
+        if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
+            m_data.negate( expr.isBinaryExpression() );
+        }
+
+        getResultCapture().assertionRun();
+
+        if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok)
+        {
+            AssertionResult result = build( expr );
+            handleResult( result );
+        }
+        else
+            getResultCapture().assertionPassed();
+    }
+
+    void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
+        m_assertionInfo.resultDisposition = resultDisposition;
+        stream().oss << Catch::translateActiveException();
+        captureResult( ResultWas::ThrewException );
+    }
+
+    void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
+        setResultType( resultType );
+        captureExpression();
+    }
+
+    void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
+        if( expectedMessage.empty() )
+            captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() );
+        else
+            captureExpectedException( Matchers::Equals( expectedMessage ) );
+    }
+
+    void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) {
+
+        assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
+        AssertionResultData data = m_data;
+        data.resultType = ResultWas::Ok;
+        data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
+
+        std::string actualMessage = Catch::translateActiveException();
+        if( !matcher.match( actualMessage ) ) {
+            data.resultType = ResultWas::ExpressionFailed;
+            data.reconstructedExpression = actualMessage;
+        }
+        AssertionResult result( m_assertionInfo, data );
+        handleResult( result );
+    }
+
+    void ResultBuilder::captureExpression() {
+        AssertionResult result = build();
+        handleResult( result );
+    }
+
+    void ResultBuilder::handleResult( AssertionResult const& result )
+    {
+        getResultCapture().assertionEnded( result );
+
+        if( !result.isOk() ) {
+            if( getCurrentContext().getConfig()->shouldDebugBreak() )
+                m_shouldDebugBreak = true;
+            if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) )
+                m_shouldThrow = true;
+        }
+    }
+
+    void ResultBuilder::react() {
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+        if (m_shouldDebugBreak) {
+            ///////////////////////////////////////////////////////////////////
+            // To inspect the state during test, you need to go one level up the callstack
+            // To go back to the test and change execution, jump over the throw statement
+            ///////////////////////////////////////////////////////////////////
+            CATCH_BREAK_INTO_DEBUGGER();
+        }
+#endif
+        if( m_shouldThrow )
+            throw Catch::TestFailureException();
+    }
+
+    bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
+    bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
+
+    AssertionResult ResultBuilder::build() const
+    {
+        return build( *this );
+    }
+
+    // CAVEAT: The returned AssertionResult stores a pointer to the argument expr,
+    //         a temporary DecomposedExpression, which in turn holds references to
+    //         operands, possibly temporary as well.
+    //         It should immediately be passed to handleResult; if the expression
+    //         needs to be reported, its string expansion must be composed before
+    //         the temporaries are destroyed.
+    AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const
+    {
+        assert( m_data.resultType != ResultWas::Unknown );
+        AssertionResultData data = m_data;
+
+        if(m_usedStream)
+            data.message = m_stream().oss.str();
+        data.decomposedExpression = &expr; // for lazy reconstruction
+        return AssertionResult( m_assertionInfo, data );
+    }
+
+    void ResultBuilder::reconstructExpression( std::string& dest ) const {
+        dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
+    }
+
+    void ResultBuilder::setExceptionGuard() {
+        m_guardException = true;
+    }
+    void ResultBuilder::unsetExceptionGuard() {
+        m_guardException = false;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_tag_alias_registry.hpp
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+namespace Catch {
+
+    TagAliasRegistry::~TagAliasRegistry() {}
+
+    Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const {
+        std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias );
+        if( it != m_registry.end() )
+            return it->second;
+        else
+            return Option<TagAlias>();
+    }
+
+    std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
+        std::string expandedTestSpec = unexpandedTestSpec;
+        for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
+                it != itEnd;
+                ++it ) {
+            std::size_t pos = expandedTestSpec.find( it->first );
+            if( pos != std::string::npos ) {
+                expandedTestSpec =  expandedTestSpec.substr( 0, pos ) +
+                                    it->second.tag +
+                                    expandedTestSpec.substr( pos + it->first.size() );
+            }
+        }
+        return expandedTestSpec;
+    }
+
+    void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
+
+        if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
+            std::ostringstream oss;
+            oss << Colour( Colour::Red )
+                << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n"
+                << Colour( Colour::FileName )
+                << lineInfo << '\n';
+            throw std::domain_error( oss.str().c_str() );
+        }
+        if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
+            std::ostringstream oss;
+            oss << Colour( Colour::Red )
+                << "error: tag alias, \"" << alias << "\" already registered.\n"
+                << "\tFirst seen at "
+                << Colour( Colour::Red ) << find(alias)->lineInfo << '\n'
+                << Colour( Colour::Red ) << "\tRedefined at "
+                << Colour( Colour::FileName) << lineInfo << '\n';
+            throw std::domain_error( oss.str().c_str() );
+        }
+    }
+
+    ITagAliasRegistry::~ITagAliasRegistry() {}
+
+    ITagAliasRegistry const& ITagAliasRegistry::get() {
+        return getRegistryHub().getTagAliasRegistry();
+    }
+
+    RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
+        getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo );
+    }
+
+} // end namespace Catch
+
+// #included from: catch_matchers_string.hpp
+
+namespace Catch {
+namespace Matchers {
+
+    namespace StdString {
+
+        CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
+        :   m_caseSensitivity( caseSensitivity ),
+            m_str( adjustString( str ) )
+        {}
+        std::string CasedString::adjustString( std::string const& str ) const {
+            return m_caseSensitivity == CaseSensitive::No
+                   ? toLower( str )
+                   : str;
+        }
+        std::string CasedString::caseSensitivitySuffix() const {
+            return m_caseSensitivity == CaseSensitive::No
+                   ? " (case insensitive)"
+                   : std::string();
+        }
+
+        StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )
+        : m_comparator( comparator ),
+          m_operation( operation ) {
+        }
+
+        std::string StringMatcherBase::describe() const {
+            std::string description;
+            description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
+                                        m_comparator.caseSensitivitySuffix().size());
+            description += m_operation;
+            description += ": \"";
+            description += m_comparator.m_str;
+            description += "\"";
+            description += m_comparator.caseSensitivitySuffix();
+            return description;
+        }
+
+        EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}
+
+        bool EqualsMatcher::match( std::string const& source ) const {
+            return m_comparator.adjustString( source ) == m_comparator.m_str;
+        }
+
+        ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}
+
+        bool ContainsMatcher::match( std::string const& source ) const {
+            return contains( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+        StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}
+
+        bool StartsWithMatcher::match( std::string const& source ) const {
+            return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+        EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}
+
+        bool EndsWithMatcher::match( std::string const& source ) const {
+            return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+    } // namespace StdString
+
+    StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+
+} // namespace Matchers
+} // namespace Catch
+// #included from: ../reporters/catch_reporter_multi.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED
+
+namespace Catch {
+
+class MultipleReporters : public SharedImpl<IStreamingReporter> {
+    typedef std::vector<Ptr<IStreamingReporter> > Reporters;
+    Reporters m_reporters;
+
+public:
+    void add( Ptr<IStreamingReporter> const& reporter ) {
+        m_reporters.push_back( reporter );
+    }
+
+public: // IStreamingReporter
+
+    virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+        return m_reporters[0]->getPreferences();
+    }
+
+    virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->noMatchingTestCases( spec );
+    }
+
+    virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testRunStarting( testRunInfo );
+    }
+
+    virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testGroupStarting( groupInfo );
+    }
+
+    virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testCaseStarting( testInfo );
+    }
+
+    virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->sectionStarting( sectionInfo );
+    }
+
+    virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->assertionStarting( assertionInfo );
+    }
+
+    // The return value indicates if the messages buffer should be cleared:
+    virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+        bool clearBuffer = false;
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            clearBuffer |= (*it)->assertionEnded( assertionStats );
+        return clearBuffer;
+    }
+
+    virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->sectionEnded( sectionStats );
+    }
+
+    virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testCaseEnded( testCaseStats );
+    }
+
+    virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testGroupEnded( testGroupStats );
+    }
+
+    virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testRunEnded( testRunStats );
+    }
+
+    virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->skipTest( testInfo );
+    }
+
+    virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE {
+        return this;
+    }
+
+};
+
+Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
+    Ptr<IStreamingReporter> resultingReporter;
+
+    if( existingReporter ) {
+        MultipleReporters* multi = existingReporter->tryAsMulti();
+        if( !multi ) {
+            multi = new MultipleReporters;
+            resultingReporter = Ptr<IStreamingReporter>( multi );
+            if( existingReporter )
+                multi->add( existingReporter );
+        }
+        else
+            resultingReporter = existingReporter;
+        multi->add( additionalReporter );
+    }
+    else
+        resultingReporter = additionalReporter;
+
+    return resultingReporter;
+}
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_xml.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
+
+// #included from: catch_reporter_bases.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+
+#include <cstring>
+#include <cfloat>
+#include <cstdio>
+#include <assert.h>
+
+namespace Catch {
+
+    namespace {
+        // Because formatting using c++ streams is stateful, drop down to C is required
+        // Alternatively we could use stringstream, but its performance is... not good.
+        std::string getFormattedDuration( double duration ) {
+            // Max exponent + 1 is required to represent the whole part
+            // + 1 for decimal point
+            // + 3 for the 3 decimal places
+            // + 1 for null terminator
+            const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
+            char buffer[maxDoubleSize];
+
+            // Save previous errno, to prevent sprintf from overwriting it
+            ErrnoGuard guard;
+#ifdef _MSC_VER
+            sprintf_s(buffer, "%.3f", duration);
+#else
+            sprintf(buffer, "%.3f", duration);
+#endif
+            return std::string(buffer);
+        }
+    }
+
+    struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
+
+        StreamingReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = false;
+        }
+
+        virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+            return m_reporterPrefs;
+        }
+
+        virtual ~StreamingReporterBase() CATCH_OVERRIDE;
+
+        virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {}
+
+        virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE {
+            currentTestRunInfo = _testRunInfo;
+        }
+        virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE {
+            currentGroupInfo = _groupInfo;
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE {
+            currentTestCaseInfo = _testInfo;
+        }
+        virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
+            m_sectionStack.push_back( _sectionInfo );
+        }
+
+        virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE {
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE {
+            currentTestCaseInfo.reset();
+        }
+        virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE {
+            currentGroupInfo.reset();
+        }
+        virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE {
+            currentTestCaseInfo.reset();
+            currentGroupInfo.reset();
+            currentTestRunInfo.reset();
+        }
+
+        virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {
+            // Don't do anything with this by default.
+            // It can optionally be overridden in the derived class.
+        }
+
+        Ptr<IConfig const> m_config;
+        std::ostream& stream;
+
+        LazyStat<TestRunInfo> currentTestRunInfo;
+        LazyStat<GroupInfo> currentGroupInfo;
+        LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+        std::vector<SectionInfo> m_sectionStack;
+        ReporterPreferences m_reporterPrefs;
+    };
+
+    struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
+        template<typename T, typename ChildNodeT>
+        struct Node : SharedImpl<> {
+            explicit Node( T const& _value ) : value( _value ) {}
+            virtual ~Node() {}
+
+            typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
+            T value;
+            ChildNodes children;
+        };
+        struct SectionNode : SharedImpl<> {
+            explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
+            virtual ~SectionNode();
+
+            bool operator == ( SectionNode const& other ) const {
+                return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+            }
+            bool operator == ( Ptr<SectionNode> const& other ) const {
+                return operator==( *other );
+            }
+
+            SectionStats stats;
+            typedef std::vector<Ptr<SectionNode> > ChildSections;
+            typedef std::vector<AssertionStats> Assertions;
+            ChildSections childSections;
+            Assertions assertions;
+            std::string stdOut;
+            std::string stdErr;
+        };
+
+        struct BySectionInfo {
+            BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
+            BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
+            bool operator() ( Ptr<SectionNode> const& node ) const {
+                return ((node->stats.sectionInfo.name == m_other.name) &&
+                        (node->stats.sectionInfo.lineInfo == m_other.lineInfo));
+            }
+        private:
+            void operator=( BySectionInfo const& );
+            SectionInfo const& m_other;
+        };
+
+        typedef Node<TestCaseStats, SectionNode> TestCaseNode;
+        typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
+        typedef Node<TestRunStats, TestGroupNode> TestRunNode;
+
+        CumulativeReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = false;
+        }
+        ~CumulativeReporterBase();
+
+        virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+            return m_reporterPrefs;
+        }
+
+        virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {}
+        virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {}
+
+        virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {}
+
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+            SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
+            Ptr<SectionNode> node;
+            if( m_sectionStack.empty() ) {
+                if( !m_rootSection )
+                    m_rootSection = new SectionNode( incompleteStats );
+                node = m_rootSection;
+            }
+            else {
+                SectionNode& parentNode = *m_sectionStack.back();
+                SectionNode::ChildSections::const_iterator it =
+                    std::find_if(   parentNode.childSections.begin(),
+                                    parentNode.childSections.end(),
+                                    BySectionInfo( sectionInfo ) );
+                if( it == parentNode.childSections.end() ) {
+                    node = new SectionNode( incompleteStats );
+                    parentNode.childSections.push_back( node );
+                }
+                else
+                    node = *it;
+            }
+            m_sectionStack.push_back( node );
+            m_deepestSection = node;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+            assert( !m_sectionStack.empty() );
+            SectionNode& sectionNode = *m_sectionStack.back();
+            sectionNode.assertions.push_back( assertionStats );
+            // AssertionResult holds a pointer to a temporary DecomposedExpression,
+            // which getExpandedExpression() calls to build the expression string.
+            // Our section stack copy of the assertionResult will likely outlive the
+            // temporary, so it must be expanded or discarded now to avoid calling
+            // a destroyed object later.
+            prepareExpandedExpression( sectionNode.assertions.back().assertionResult );
+            return true;
+        }
+        virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+            assert( !m_sectionStack.empty() );
+            SectionNode& node = *m_sectionStack.back();
+            node.stats = sectionStats;
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+            Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
+            assert( m_sectionStack.size() == 0 );
+            node->children.push_back( m_rootSection );
+            m_testCases.push_back( node );
+            m_rootSection.reset();
+
+            assert( m_deepestSection );
+            m_deepestSection->stdOut = testCaseStats.stdOut;
+            m_deepestSection->stdErr = testCaseStats.stdErr;
+        }
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+            Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
+            node->children.swap( m_testCases );
+            m_testGroups.push_back( node );
+        }
+        virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+            Ptr<TestRunNode> node = new TestRunNode( testRunStats );
+            node->children.swap( m_testGroups );
+            m_testRuns.push_back( node );
+            testRunEndedCumulative();
+        }
+        virtual void testRunEndedCumulative() = 0;
+
+        virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
+
+        virtual void prepareExpandedExpression( AssertionResult& result ) const {
+            if( result.isOk() )
+                result.discardDecomposedExpression();
+            else
+                result.expandDecomposedExpression();
+        }
+
+        Ptr<IConfig const> m_config;
+        std::ostream& stream;
+        std::vector<AssertionStats> m_assertions;
+        std::vector<std::vector<Ptr<SectionNode> > > m_sections;
+        std::vector<Ptr<TestCaseNode> > m_testCases;
+        std::vector<Ptr<TestGroupNode> > m_testGroups;
+
+        std::vector<Ptr<TestRunNode> > m_testRuns;
+
+        Ptr<SectionNode> m_rootSection;
+        Ptr<SectionNode> m_deepestSection;
+        std::vector<Ptr<SectionNode> > m_sectionStack;
+        ReporterPreferences m_reporterPrefs;
+
+    };
+
+    template<char C>
+    char const* getLineOfChars() {
+        static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
+        if( !*line ) {
+            std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
+            line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
+        }
+        return line;
+    }
+
+    struct TestEventListenerBase : StreamingReporterBase {
+        TestEventListenerBase( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config )
+        {}
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
+        virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE {
+            return false;
+        }
+    };
+
+} // end namespace Catch
+
+// #included from: ../internal/catch_reporter_registrars.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+
+namespace Catch {
+
+    template<typename T>
+    class LegacyReporterRegistrar {
+
+        class ReporterFactory : public IReporterFactory {
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new LegacyReporterAdapter( new T( config ) );
+            }
+
+            virtual std::string getDescription() const {
+                return T::getDescription();
+            }
+        };
+
+    public:
+
+        LegacyReporterRegistrar( std::string const& name ) {
+            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+        }
+    };
+
+    template<typename T>
+    class ReporterRegistrar {
+
+        class ReporterFactory : public SharedImpl<IReporterFactory> {
+
+            // *** Please Note ***:
+            // - If you end up here looking at a compiler error because it's trying to register
+            // your custom reporter class be aware that the native reporter interface has changed
+            // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
+            // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
+            // However please consider updating to the new interface as the old one is now
+            // deprecated and will probably be removed quite soon!
+            // Please contact me via github if you have any questions at all about this.
+            // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
+            // no idea who is actually using custom reporters at all (possibly no-one!).
+            // The new interface is designed to minimise exposure to interface changes in the future.
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new T( config );
+            }
+
+            virtual std::string getDescription() const {
+                return T::getDescription();
+            }
+        };
+
+    public:
+
+        ReporterRegistrar( std::string const& name ) {
+            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+        }
+    };
+
+    template<typename T>
+    class ListenerRegistrar {
+
+        class ListenerFactory : public SharedImpl<IReporterFactory> {
+
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new T( config );
+            }
+            virtual std::string getDescription() const {
+                return std::string();
+            }
+        };
+
+    public:
+
+        ListenerRegistrar() {
+            getMutableRegistryHub().registerListener( new ListenerFactory() );
+        }
+    };
+}
+
+#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
+    namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+
+#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
+    namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+
+// Deprecated - use the form without INTERNAL_
+#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
+    namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
+
+#define CATCH_REGISTER_LISTENER( listenerType ) \
+    namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
+
+// #included from: ../internal/catch_xmlwriter.hpp
+#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <iomanip>
+
+namespace Catch {
+
+    class XmlEncode {
+    public:
+        enum ForWhat { ForTextNodes, ForAttributes };
+
+        XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes )
+        :   m_str( str ),
+            m_forWhat( forWhat )
+        {}
+
+        void encodeTo( std::ostream& os ) const {
+
+            // Apostrophe escaping not necessary if we always use " to write attributes
+            // (see: http://www.w3.org/TR/xml/#syntax)
+
+            for( std::size_t i = 0; i < m_str.size(); ++ i ) {
+                char c = m_str[i];
+                switch( c ) {
+                    case '<':   os << "<"; break;
+                    case '&':   os << "&"; break;
+
+                    case '>':
+                        // See: http://www.w3.org/TR/xml/#syntax
+                        if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' )
+                            os << ">";
+                        else
+                            os << c;
+                        break;
+
+                    case '\"':
+                        if( m_forWhat == ForAttributes )
+                            os << """;
+                        else
+                            os << c;
+                        break;
+
+                    default:
+                        // Escape control chars - based on contribution by @espenalb in PR #465 and
+                        // by @mrpi PR #588
+                        if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) {
+                            // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
+                            os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
+                               << static_cast<int>( c );
+                        }
+                        else
+                            os << c;
+                }
+            }
+        }
+
+        friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
+            xmlEncode.encodeTo( os );
+            return os;
+        }
+
+    private:
+        std::string m_str;
+        ForWhat m_forWhat;
+    };
+
+    class XmlWriter {
+    public:
+
+        class ScopedElement {
+        public:
+            ScopedElement( XmlWriter* writer )
+            :   m_writer( writer )
+            {}
+
+            ScopedElement( ScopedElement const& other )
+            :   m_writer( other.m_writer ){
+                other.m_writer = CATCH_NULL;
+            }
+
+            ~ScopedElement() {
+                if( m_writer )
+                    m_writer->endElement();
+            }
+
+            ScopedElement& writeText( std::string const& text, bool indent = true ) {
+                m_writer->writeText( text, indent );
+                return *this;
+            }
+
+            template<typename T>
+            ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
+                m_writer->writeAttribute( name, attribute );
+                return *this;
+            }
+
+        private:
+            mutable XmlWriter* m_writer;
+        };
+
+        XmlWriter()
+        :   m_tagIsOpen( false ),
+            m_needsNewline( false ),
+            m_os( Catch::cout() )
+        {
+            writeDeclaration();
+        }
+
+        XmlWriter( std::ostream& os )
+        :   m_tagIsOpen( false ),
+            m_needsNewline( false ),
+            m_os( os )
+        {
+            writeDeclaration();
+        }
+
+        ~XmlWriter() {
+            while( !m_tags.empty() )
+                endElement();
+        }
+
+        XmlWriter& startElement( std::string const& name ) {
+            ensureTagClosed();
+            newlineIfNecessary();
+            m_os << m_indent << '<' << name;
+            m_tags.push_back( name );
+            m_indent += "  ";
+            m_tagIsOpen = true;
+            return *this;
+        }
+
+        ScopedElement scopedElement( std::string const& name ) {
+            ScopedElement scoped( this );
+            startElement( name );
+            return scoped;
+        }
+
+        XmlWriter& endElement() {
+            newlineIfNecessary();
+            m_indent = m_indent.substr( 0, m_indent.size()-2 );
+            if( m_tagIsOpen ) {
+                m_os << "/>";
+                m_tagIsOpen = false;
+            }
+            else {
+                m_os << m_indent << "</" << m_tags.back() << ">";
+            }
+            m_os << std::endl;
+            m_tags.pop_back();
+            return *this;
+        }
+
+        XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
+            if( !name.empty() && !attribute.empty() )
+                m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
+            return *this;
+        }
+
+        XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
+            m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
+            return *this;
+        }
+
+        template<typename T>
+        XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
+            std::ostringstream oss;
+            oss << attribute;
+            return writeAttribute( name, oss.str() );
+        }
+
+        XmlWriter& writeText( std::string const& text, bool indent = true ) {
+            if( !text.empty() ){
+                bool tagWasOpen = m_tagIsOpen;
+                ensureTagClosed();
+                if( tagWasOpen && indent )
+                    m_os << m_indent;
+                m_os << XmlEncode( text );
+                m_needsNewline = true;
+            }
+            return *this;
+        }
+
+        XmlWriter& writeComment( std::string const& text ) {
+            ensureTagClosed();
+            m_os << m_indent << "<!--" << text << "-->";
+            m_needsNewline = true;
+            return *this;
+        }
+
+        void writeStylesheetRef( std::string const& url ) {
+            m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
+        }
+
+        XmlWriter& writeBlankLine() {
+            ensureTagClosed();
+            m_os << '\n';
+            return *this;
+        }
+
+        void ensureTagClosed() {
+            if( m_tagIsOpen ) {
+                m_os << ">" << std::endl;
+                m_tagIsOpen = false;
+            }
+        }
+
+    private:
+        XmlWriter( XmlWriter const& );
+        void operator=( XmlWriter const& );
+
+        void writeDeclaration() {
+            m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+        }
+
+        void newlineIfNecessary() {
+            if( m_needsNewline ) {
+                m_os << std::endl;
+                m_needsNewline = false;
+            }
+        }
+
+        bool m_tagIsOpen;
+        bool m_needsNewline;
+        std::vector<std::string> m_tags;
+        std::string m_indent;
+        std::ostream& m_os;
+    };
+
+}
+
+namespace Catch {
+    class XmlReporter : public StreamingReporterBase {
+    public:
+        XmlReporter( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config ),
+            m_xml(_config.stream()),
+            m_sectionDepth( 0 )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = true;
+        }
+
+        virtual ~XmlReporter() CATCH_OVERRIDE;
+
+        static std::string getDescription() {
+            return "Reports test results as an XML document";
+        }
+
+        virtual std::string getStylesheetRef() const {
+            return std::string();
+        }
+
+        void writeSourceInfo( SourceLineInfo const& sourceInfo ) {
+            m_xml
+                .writeAttribute( "filename", sourceInfo.file )
+                .writeAttribute( "line", sourceInfo.line );
+        }
+
+    public: // StreamingReporterBase
+
+        virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE {
+            StreamingReporterBase::noMatchingTestCases( s );
+        }
+
+        virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::testRunStarting( testInfo );
+            std::string stylesheetRef = getStylesheetRef();
+            if( !stylesheetRef.empty() )
+                m_xml.writeStylesheetRef( stylesheetRef );
+            m_xml.startElement( "Catch" );
+            if( !m_config->name().empty() )
+                m_xml.writeAttribute( "name", m_config->name() );
+        }
+
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::testGroupStarting( groupInfo );
+            m_xml.startElement( "Group" )
+                .writeAttribute( "name", groupInfo.name );
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::testCaseStarting(testInfo);
+            m_xml.startElement( "TestCase" )
+                .writeAttribute( "name", trim( testInfo.name ) )
+                .writeAttribute( "description", testInfo.description )
+                .writeAttribute( "tags", testInfo.tagsAsString );
+
+            writeSourceInfo( testInfo.lineInfo );
+
+            if ( m_config->showDurations() == ShowDurations::Always )
+                m_testCaseTimer.start();
+            m_xml.ensureTagClosed();
+        }
+
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::sectionStarting( sectionInfo );
+            if( m_sectionDepth++ > 0 ) {
+                m_xml.startElement( "Section" )
+                    .writeAttribute( "name", trim( sectionInfo.name ) )
+                    .writeAttribute( "description", sectionInfo.description );
+                writeSourceInfo( sectionInfo.lineInfo );
+                m_xml.ensureTagClosed();
+            }
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { }
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+
+            AssertionResult const& result = assertionStats.assertionResult;
+
+            bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+            if( includeResults || result.getResultType() == ResultWas::Warning ) {
+                // Print any info messages in <Info> tags.
+                for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+                     it != itEnd;
+                     ++it ) {
+                    if( it->type == ResultWas::Info && includeResults ) {
+                        m_xml.scopedElement( "Info" )
+                                .writeText( it->message );
+                    } else if ( it->type == ResultWas::Warning ) {
+                        m_xml.scopedElement( "Warning" )
+                                .writeText( it->message );
+                    }
+                }
+            }
+
+            // Drop out if result was successful but we're not printing them.
+            if( !includeResults && result.getResultType() != ResultWas::Warning )
+                return true;
+
+            // Print the expression if there is one.
+            if( result.hasExpression() ) {
+                m_xml.startElement( "Expression" )
+                    .writeAttribute( "success", result.succeeded() )
+                    .writeAttribute( "type", result.getTestMacroName() );
+
+                writeSourceInfo( result.getSourceInfo() );
+
+                m_xml.scopedElement( "Original" )
+                    .writeText( result.getExpression() );
+                m_xml.scopedElement( "Expanded" )
+                    .writeText( result.getExpandedExpression() );
+            }
+
+            // And... Print a result applicable to each result type.
+            switch( result.getResultType() ) {
+                case ResultWas::ThrewException:
+                    m_xml.startElement( "Exception" );
+                    writeSourceInfo( result.getSourceInfo() );
+                    m_xml.writeText( result.getMessage() );
+                    m_xml.endElement();
+                    break;
+                case ResultWas::FatalErrorCondition:
+                    m_xml.startElement( "FatalErrorCondition" );
+                    writeSourceInfo( result.getSourceInfo() );
+                    m_xml.writeText( result.getMessage() );
+                    m_xml.endElement();
+                    break;
+                case ResultWas::Info:
+                    m_xml.scopedElement( "Info" )
+                        .writeText( result.getMessage() );
+                    break;
+                case ResultWas::Warning:
+                    // Warning will already have been written
+                    break;
+                case ResultWas::ExplicitFailure:
+                    m_xml.startElement( "Failure" );
+                    writeSourceInfo( result.getSourceInfo() );
+                    m_xml.writeText( result.getMessage() );
+                    m_xml.endElement();
+                    break;
+                default:
+                    break;
+            }
+
+            if( result.hasExpression() )
+                m_xml.endElement();
+
+            return true;
+        }
+
+        virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::sectionEnded( sectionStats );
+            if( --m_sectionDepth > 0 ) {
+                XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
+                e.writeAttribute( "successes", sectionStats.assertions.passed );
+                e.writeAttribute( "failures", sectionStats.assertions.failed );
+                e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
+
+                if ( m_config->showDurations() == ShowDurations::Always )
+                    e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
+
+                m_xml.endElement();
+            }
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testCaseEnded( testCaseStats );
+            XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
+            e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
+
+            if ( m_config->showDurations() == ShowDurations::Always )
+                e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
+
+            if( !testCaseStats.stdOut.empty() )
+                m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
+            if( !testCaseStats.stdErr.empty() )
+                m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
+
+            m_xml.endElement();
+        }
+
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testGroupEnded( testGroupStats );
+            // TODO: Check testGroupStats.aborting and act accordingly.
+            m_xml.scopedElement( "OverallResults" )
+                .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
+                .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
+                .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
+            m_xml.endElement();
+        }
+
+        virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testRunEnded( testRunStats );
+            m_xml.scopedElement( "OverallResults" )
+                .writeAttribute( "successes", testRunStats.totals.assertions.passed )
+                .writeAttribute( "failures", testRunStats.totals.assertions.failed )
+                .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
+            m_xml.endElement();
+        }
+
+    private:
+        Timer m_testCaseTimer;
+        XmlWriter m_xml;
+        int m_sectionDepth;
+    };
+
+     INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_junit.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
+
+#include <assert.h>
+
+namespace Catch {
+
+    namespace {
+        std::string getCurrentTimestamp() {
+            // Beware, this is not reentrant because of backward compatibility issues
+            // Also, UTC only, again because of backward compatibility (%z is C++11)
+            time_t rawtime;
+            std::time(&rawtime);
+            const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z");
+
+#ifdef _MSC_VER
+            std::tm timeInfo = {};
+            gmtime_s(&timeInfo, &rawtime);
+#else
+            std::tm* timeInfo;
+            timeInfo = std::gmtime(&rawtime);
+#endif
+
+            char timeStamp[timeStampSize];
+            const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+#ifdef _MSC_VER
+            std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+#else
+            std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
+#endif
+            return std::string(timeStamp);
+        }
+
+    }
+
+    class JunitReporter : public CumulativeReporterBase {
+    public:
+        JunitReporter( ReporterConfig const& _config )
+        :   CumulativeReporterBase( _config ),
+            xml( _config.stream() ),
+            unexpectedExceptions( 0 ),
+            m_okToFail( false )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = true;
+        }
+
+        virtual ~JunitReporter() CATCH_OVERRIDE;
+
+        static std::string getDescription() {
+            return "Reports test results in an XML format that looks like Ant's junitreport target";
+        }
+
+        virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {}
+
+        virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE {
+            CumulativeReporterBase::testRunStarting( runInfo );
+            xml.startElement( "testsuites" );
+        }
+
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+            suiteTimer.start();
+            stdOutForSuite.str("");
+            stdErrForSuite.str("");
+            unexpectedExceptions = 0;
+            CumulativeReporterBase::testGroupStarting( groupInfo );
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& testCaseInfo ) CATCH_OVERRIDE {
+            m_okToFail = testCaseInfo.okToFail();
+        }
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+            if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
+                unexpectedExceptions++;
+            return CumulativeReporterBase::assertionEnded( assertionStats );
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+            stdOutForSuite << testCaseStats.stdOut;
+            stdErrForSuite << testCaseStats.stdErr;
+            CumulativeReporterBase::testCaseEnded( testCaseStats );
+        }
+
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+            double suiteTime = suiteTimer.getElapsedSeconds();
+            CumulativeReporterBase::testGroupEnded( testGroupStats );
+            writeGroup( *m_testGroups.back(), suiteTime );
+        }
+
+        virtual void testRunEndedCumulative() CATCH_OVERRIDE {
+            xml.endElement();
+        }
+
+        void writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
+            XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
+            TestGroupStats const& stats = groupNode.value;
+            xml.writeAttribute( "name", stats.groupInfo.name );
+            xml.writeAttribute( "errors", unexpectedExceptions );
+            xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
+            xml.writeAttribute( "tests", stats.totals.assertions.total() );
+            xml.writeAttribute( "hostname", "tbd" ); // !TBD
+            if( m_config->showDurations() == ShowDurations::Never )
+                xml.writeAttribute( "time", "" );
+            else
+                xml.writeAttribute( "time", suiteTime );
+            xml.writeAttribute( "timestamp", getCurrentTimestamp() );
+
+            // Write test cases
+            for( TestGroupNode::ChildNodes::const_iterator
+                    it = groupNode.children.begin(), itEnd = groupNode.children.end();
+                    it != itEnd;
+                    ++it )
+                writeTestCase( **it );
+
+            xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false );
+            xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false );
+        }
+
+        void writeTestCase( TestCaseNode const& testCaseNode ) {
+            TestCaseStats const& stats = testCaseNode.value;
+
+            // All test cases have exactly one section - which represents the
+            // test case itself. That section may have 0-n nested sections
+            assert( testCaseNode.children.size() == 1 );
+            SectionNode const& rootSection = *testCaseNode.children.front();
+
+            std::string className = stats.testInfo.className;
+
+            if( className.empty() ) {
+                if( rootSection.childSections.empty() )
+                    className = "global";
+            }
+            writeSection( className, "", rootSection );
+        }
+
+        void writeSection(  std::string const& className,
+                            std::string const& rootName,
+                            SectionNode const& sectionNode ) {
+            std::string name = trim( sectionNode.stats.sectionInfo.name );
+            if( !rootName.empty() )
+                name = rootName + '/' + name;
+
+            if( !sectionNode.assertions.empty() ||
+                !sectionNode.stdOut.empty() ||
+                !sectionNode.stdErr.empty() ) {
+                XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
+                if( className.empty() ) {
+                    xml.writeAttribute( "classname", name );
+                    xml.writeAttribute( "name", "root" );
+                }
+                else {
+                    xml.writeAttribute( "classname", className );
+                    xml.writeAttribute( "name", name );
+                }
+                xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) );
+
+                writeAssertions( sectionNode );
+
+                if( !sectionNode.stdOut.empty() )
+                    xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
+                if( !sectionNode.stdErr.empty() )
+                    xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
+            }
+            for( SectionNode::ChildSections::const_iterator
+                    it = sectionNode.childSections.begin(),
+                    itEnd = sectionNode.childSections.end();
+                    it != itEnd;
+                    ++it )
+                if( className.empty() )
+                    writeSection( name, "", **it );
+                else
+                    writeSection( className, name, **it );
+        }
+
+        void writeAssertions( SectionNode const& sectionNode ) {
+            for( SectionNode::Assertions::const_iterator
+                    it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end();
+                    it != itEnd;
+                    ++it )
+                writeAssertion( *it );
+        }
+        void writeAssertion( AssertionStats const& stats ) {
+            AssertionResult const& result = stats.assertionResult;
+            if( !result.isOk() ) {
+                std::string elementName;
+                switch( result.getResultType() ) {
+                    case ResultWas::ThrewException:
+                    case ResultWas::FatalErrorCondition:
+                        elementName = "error";
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        elementName = "failure";
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        elementName = "failure";
+                        break;
+                    case ResultWas::DidntThrowException:
+                        elementName = "failure";
+                        break;
+
+                    // We should never see these here:
+                    case ResultWas::Info:
+                    case ResultWas::Warning:
+                    case ResultWas::Ok:
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        elementName = "internalError";
+                        break;
+                }
+
+                XmlWriter::ScopedElement e = xml.scopedElement( elementName );
+
+                xml.writeAttribute( "message", result.getExpandedExpression() );
+                xml.writeAttribute( "type", result.getTestMacroName() );
+
+                std::ostringstream oss;
+                if( !result.getMessage().empty() )
+                    oss << result.getMessage() << '\n';
+                for( std::vector<MessageInfo>::const_iterator
+                        it = stats.infoMessages.begin(),
+                        itEnd = stats.infoMessages.end();
+                            it != itEnd;
+                            ++it )
+                    if( it->type == ResultWas::Info )
+                        oss << it->message << '\n';
+
+                oss << "at " << result.getSourceInfo();
+                xml.writeText( oss.str(), false );
+            }
+        }
+
+        XmlWriter xml;
+        Timer suiteTimer;
+        std::ostringstream stdOutForSuite;
+        std::ostringstream stdErrForSuite;
+        unsigned int unexpectedExceptions;
+        bool m_okToFail;
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_console.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+
+#include <cfloat>
+#include <cstdio>
+
+namespace Catch {
+
+    struct ConsoleReporter : StreamingReporterBase {
+        ConsoleReporter( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config ),
+            m_headerPrinted( false )
+        {}
+
+        virtual ~ConsoleReporter() CATCH_OVERRIDE;
+        static std::string getDescription() {
+            return "Reports test results as plain lines of text";
+        }
+
+        virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
+            stream << "No test cases matched '" << spec << '\'' << std::endl;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {
+        }
+
+        virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE {
+            AssertionResult const& result = _assertionStats.assertionResult;
+
+            bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+            // Drop out if result was successful but we're not printing them.
+            if( !includeResults && result.getResultType() != ResultWas::Warning )
+                return false;
+
+            lazyPrint();
+
+            AssertionPrinter printer( stream, _assertionStats, includeResults );
+            printer.print();
+            stream << std::endl;
+            return true;
+        }
+
+        virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
+            m_headerPrinted = false;
+            StreamingReporterBase::sectionStarting( _sectionInfo );
+        }
+        virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE {
+            if( _sectionStats.missingAssertions ) {
+                lazyPrint();
+                Colour colour( Colour::ResultError );
+                if( m_sectionStack.size() > 1 )
+                    stream << "\nNo assertions in section";
+                else
+                    stream << "\nNo assertions in test case";
+                stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
+            }
+            if( m_config->showDurations() == ShowDurations::Always ) {
+                stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+            }
+            if( m_headerPrinted ) {
+                m_headerPrinted = false;
+            }
+            StreamingReporterBase::sectionEnded( _sectionStats );
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testCaseEnded( _testCaseStats );
+            m_headerPrinted = false;
+        }
+        virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE {
+            if( currentGroupInfo.used ) {
+                printSummaryDivider();
+                stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
+                printTotals( _testGroupStats.totals );
+                stream << '\n' << std::endl;
+            }
+            StreamingReporterBase::testGroupEnded( _testGroupStats );
+        }
+        virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE {
+            printTotalsDivider( _testRunStats.totals );
+            printTotals( _testRunStats.totals );
+            stream << std::endl;
+            StreamingReporterBase::testRunEnded( _testRunStats );
+        }
+
+    private:
+
+        class AssertionPrinter {
+            void operator= ( AssertionPrinter const& );
+        public:
+            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+            :   stream( _stream ),
+                stats( _stats ),
+                result( _stats.assertionResult ),
+                colour( Colour::None ),
+                message( result.getMessage() ),
+                messages( _stats.infoMessages ),
+                printInfoMessages( _printInfoMessages )
+            {
+                switch( result.getResultType() ) {
+                    case ResultWas::Ok:
+                        colour = Colour::Success;
+                        passOrFail = "PASSED";
+                        //if( result.hasMessage() )
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "with messages";
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        if( result.isOk() ) {
+                            colour = Colour::Success;
+                            passOrFail = "FAILED - but was ok";
+                        }
+                        else {
+                            colour = Colour::Error;
+                            passOrFail = "FAILED";
+                        }
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "with messages";
+                        break;
+                    case ResultWas::ThrewException:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "due to unexpected exception with ";
+                        if (_stats.infoMessages.size() == 1)
+                            messageLabel += "message";
+                        if (_stats.infoMessages.size() > 1)
+                            messageLabel += "messages";
+                        break;
+                    case ResultWas::FatalErrorCondition:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "due to a fatal error condition";
+                        break;
+                    case ResultWas::DidntThrowException:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "because no exception was thrown where one was expected";
+                        break;
+                    case ResultWas::Info:
+                        messageLabel = "info";
+                        break;
+                    case ResultWas::Warning:
+                        messageLabel = "warning";
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        passOrFail = "FAILED";
+                        colour = Colour::Error;
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "explicitly with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "explicitly with messages";
+                        break;
+                    // These cases are here to prevent compiler warnings
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        passOrFail = "** internal error **";
+                        colour = Colour::Error;
+                        break;
+                }
+            }
+
+            void print() const {
+                printSourceInfo();
+                if( stats.totals.assertions.total() > 0 ) {
+                    if( result.isOk() )
+                        stream << '\n';
+                    printResultType();
+                    printOriginalExpression();
+                    printReconstructedExpression();
+                }
+                else {
+                    stream << '\n';
+                }
+                printMessage();
+            }
+
+        private:
+            void printResultType() const {
+                if( !passOrFail.empty() ) {
+                    Colour colourGuard( colour );
+                    stream << passOrFail << ":\n";
+                }
+            }
+            void printOriginalExpression() const {
+                if( result.hasExpression() ) {
+                    Colour colourGuard( Colour::OriginalExpression );
+                    stream  << "  ";
+                    stream << result.getExpressionInMacro();
+                    stream << '\n';
+                }
+            }
+            void printReconstructedExpression() const {
+                if( result.hasExpandedExpression() ) {
+                    stream << "with expansion:\n";
+                    Colour colourGuard( Colour::ReconstructedExpression );
+                    stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n';
+                }
+            }
+            void printMessage() const {
+                if( !messageLabel.empty() )
+                    stream << messageLabel << ':' << '\n';
+                for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
+                        it != itEnd;
+                        ++it ) {
+                    // If this assertion is a warning ignore any INFO messages
+                    if( printInfoMessages || it->type != ResultWas::Info )
+                        stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n';
+                }
+            }
+            void printSourceInfo() const {
+                Colour colourGuard( Colour::FileName );
+                stream << result.getSourceInfo() << ": ";
+            }
+
+            std::ostream& stream;
+            AssertionStats const& stats;
+            AssertionResult const& result;
+            Colour::Code colour;
+            std::string passOrFail;
+            std::string messageLabel;
+            std::string message;
+            std::vector<MessageInfo> messages;
+            bool printInfoMessages;
+        };
+
+        void lazyPrint() {
+
+            if( !currentTestRunInfo.used )
+                lazyPrintRunInfo();
+            if( !currentGroupInfo.used )
+                lazyPrintGroupInfo();
+
+            if( !m_headerPrinted ) {
+                printTestCaseAndSectionHeader();
+                m_headerPrinted = true;
+            }
+        }
+        void lazyPrintRunInfo() {
+            stream  << '\n' << getLineOfChars<'~'>() << '\n';
+            Colour colour( Colour::SecondaryText );
+            stream  << currentTestRunInfo->name
+                    << " is a Catch v"  << libraryVersion() << " host application.\n"
+                    << "Run with -? for options\n\n";
+
+            if( m_config->rngSeed() != 0 )
+                stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
+
+            currentTestRunInfo.used = true;
+        }
+        void lazyPrintGroupInfo() {
+            if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
+                printClosedHeader( "Group: " + currentGroupInfo->name );
+                currentGroupInfo.used = true;
+            }
+        }
+        void printTestCaseAndSectionHeader() {
+            assert( !m_sectionStack.empty() );
+            printOpenHeader( currentTestCaseInfo->name );
+
+            if( m_sectionStack.size() > 1 ) {
+                Colour colourGuard( Colour::Headers );
+
+                std::vector<SectionInfo>::const_iterator
+                    it = m_sectionStack.begin()+1, // Skip first section (test case)
+                    itEnd = m_sectionStack.end();
+                for( ; it != itEnd; ++it )
+                    printHeaderString( it->name, 2 );
+            }
+
+            SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
+
+            if( !lineInfo.empty() ){
+                stream << getLineOfChars<'-'>() << '\n';
+                Colour colourGuard( Colour::FileName );
+                stream << lineInfo << '\n';
+            }
+            stream << getLineOfChars<'.'>() << '\n' << std::endl;
+        }
+
+        void printClosedHeader( std::string const& _name ) {
+            printOpenHeader( _name );
+            stream << getLineOfChars<'.'>() << '\n';
+        }
+        void printOpenHeader( std::string const& _name ) {
+            stream  << getLineOfChars<'-'>() << '\n';
+            {
+                Colour colourGuard( Colour::Headers );
+                printHeaderString( _name );
+            }
+        }
+
+        // if string has a : in first line will set indent to follow it on
+        // subsequent lines
+        void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
+            std::size_t i = _string.find( ": " );
+            if( i != std::string::npos )
+                i+=2;
+            else
+                i = 0;
+            stream << Text( _string, TextAttributes()
+                                        .setIndent( indent+i)
+                                        .setInitialIndent( indent ) ) << '\n';
+        }
+
+        struct SummaryColumn {
+
+            SummaryColumn( std::string const& _label, Colour::Code _colour )
+            :   label( _label ),
+                colour( _colour )
+            {}
+            SummaryColumn addRow( std::size_t count ) {
+                std::ostringstream oss;
+                oss << count;
+                std::string row = oss.str();
+                for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
+                    while( it->size() < row.size() )
+                        *it = ' ' + *it;
+                    while( it->size() > row.size() )
+                        row = ' ' + row;
+                }
+                rows.push_back( row );
+                return *this;
+            }
+
+            std::string label;
+            Colour::Code colour;
+            std::vector<std::string> rows;
+
+        };
+
+        void printTotals( Totals const& totals ) {
+            if( totals.testCases.total() == 0 ) {
+                stream << Colour( Colour::Warning ) << "No tests ran\n";
+            }
+            else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
+                stream << Colour( Colour::ResultSuccess ) << "All tests passed";
+                stream << " ("
+                        << pluralise( totals.assertions.passed, "assertion" ) << " in "
+                        << pluralise( totals.testCases.passed, "test case" ) << ')'
+                        << '\n';
+            }
+            else {
+
+                std::vector<SummaryColumn> columns;
+                columns.push_back( SummaryColumn( "", Colour::None )
+                                        .addRow( totals.testCases.total() )
+                                        .addRow( totals.assertions.total() ) );
+                columns.push_back( SummaryColumn( "passed", Colour::Success )
+                                        .addRow( totals.testCases.passed )
+                                        .addRow( totals.assertions.passed ) );
+                columns.push_back( SummaryColumn( "failed", Colour::ResultError )
+                                        .addRow( totals.testCases.failed )
+                                        .addRow( totals.assertions.failed ) );
+                columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
+                                        .addRow( totals.testCases.failedButOk )
+                                        .addRow( totals.assertions.failedButOk ) );
+
+                printSummaryRow( "test cases", columns, 0 );
+                printSummaryRow( "assertions", columns, 1 );
+            }
+        }
+        void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) {
+            for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) {
+                std::string value = it->rows[row];
+                if( it->label.empty() ) {
+                    stream << label << ": ";
+                    if( value != "0" )
+                        stream << value;
+                    else
+                        stream << Colour( Colour::Warning ) << "- none -";
+                }
+                else if( value != "0" ) {
+                    stream  << Colour( Colour::LightGrey ) << " | ";
+                    stream  << Colour( it->colour )
+                            << value << ' ' << it->label;
+                }
+            }
+            stream << '\n';
+        }
+
+        static std::size_t makeRatio( std::size_t number, std::size_t total ) {
+            std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0;
+            return ( ratio == 0 && number > 0 ) ? 1 : ratio;
+        }
+        static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
+            if( i > j && i > k )
+                return i;
+            else if( j > k )
+                return j;
+            else
+                return k;
+        }
+
+        void printTotalsDivider( Totals const& totals ) {
+            if( totals.testCases.total() > 0 ) {
+                std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() );
+                std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() );
+                std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() );
+                while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 )
+                    findMax( failedRatio, failedButOkRatio, passedRatio )++;
+                while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 )
+                    findMax( failedRatio, failedButOkRatio, passedRatio )--;
+
+                stream << Colour( Colour::Error ) << std::string( failedRatio, '=' );
+                stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' );
+                if( totals.testCases.allPassed() )
+                    stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' );
+                else
+                    stream << Colour( Colour::Success ) << std::string( passedRatio, '=' );
+            }
+            else {
+                stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
+            }
+            stream << '\n';
+        }
+        void printSummaryDivider() {
+            stream << getLineOfChars<'-'>() << '\n';
+        }
+
+    private:
+        bool m_headerPrinted;
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_compact.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
+
+namespace Catch {
+
+    struct CompactReporter : StreamingReporterBase {
+
+        CompactReporter( ReporterConfig const& _config )
+        : StreamingReporterBase( _config )
+        {}
+
+        virtual ~CompactReporter();
+
+        static std::string getDescription() {
+            return "Reports test results on a single line, suitable for IDEs";
+        }
+
+        virtual ReporterPreferences getPreferences() const {
+            ReporterPreferences prefs;
+            prefs.shouldRedirectStdOut = false;
+            return prefs;
+        }
+
+        virtual void noMatchingTestCases( std::string const& spec ) {
+            stream << "No test cases matched '" << spec << '\'' << std::endl;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) {}
+
+        virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
+            AssertionResult const& result = _assertionStats.assertionResult;
+
+            bool printInfoMessages = true;
+
+            // Drop out if result was successful and we're not printing those
+            if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+                if( result.getResultType() != ResultWas::Warning )
+                    return false;
+                printInfoMessages = false;
+            }
+
+            AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+            printer.print();
+
+            stream << std::endl;
+            return true;
+        }
+
+        virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE {
+            if (m_config->showDurations() == ShowDurations::Always) {
+                stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+            }
+        }
+
+        virtual void testRunEnded( TestRunStats const& _testRunStats ) {
+            printTotals( _testRunStats.totals );
+            stream << '\n' << std::endl;
+            StreamingReporterBase::testRunEnded( _testRunStats );
+        }
+
+    private:
+        class AssertionPrinter {
+            void operator= ( AssertionPrinter const& );
+        public:
+            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+            : stream( _stream )
+            , stats( _stats )
+            , result( _stats.assertionResult )
+            , messages( _stats.infoMessages )
+            , itMessage( _stats.infoMessages.begin() )
+            , printInfoMessages( _printInfoMessages )
+            {}
+
+            void print() {
+                printSourceInfo();
+
+                itMessage = messages.begin();
+
+                switch( result.getResultType() ) {
+                    case ResultWas::Ok:
+                        printResultType( Colour::ResultSuccess, passedString() );
+                        printOriginalExpression();
+                        printReconstructedExpression();
+                        if ( ! result.hasExpression() )
+                            printRemainingMessages( Colour::None );
+                        else
+                            printRemainingMessages();
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        if( result.isOk() )
+                            printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) );
+                        else
+                            printResultType( Colour::Error, failedString() );
+                        printOriginalExpression();
+                        printReconstructedExpression();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::ThrewException:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "unexpected exception with message:" );
+                        printMessage();
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::FatalErrorCondition:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "fatal error condition with message:" );
+                        printMessage();
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::DidntThrowException:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "expected exception, got none" );
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::Info:
+                        printResultType( Colour::None, "info" );
+                        printMessage();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::Warning:
+                        printResultType( Colour::None, "warning" );
+                        printMessage();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "explicitly" );
+                        printRemainingMessages( Colour::None );
+                        break;
+                    // These cases are here to prevent compiler warnings
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        printResultType( Colour::Error, "** internal error **" );
+                        break;
+                }
+            }
+
+        private:
+            // Colour::LightGrey
+
+            static Colour::Code dimColour() { return Colour::FileName; }
+
+#ifdef CATCH_PLATFORM_MAC
+            static const char* failedString() { return "FAILED"; }
+            static const char* passedString() { return "PASSED"; }
+#else
+            static const char* failedString() { return "failed"; }
+            static const char* passedString() { return "passed"; }
+#endif
+
+            void printSourceInfo() const {
+                Colour colourGuard( Colour::FileName );
+                stream << result.getSourceInfo() << ':';
+            }
+
+            void printResultType( Colour::Code colour, std::string const& passOrFail ) const {
+                if( !passOrFail.empty() ) {
+                    {
+                        Colour colourGuard( colour );
+                        stream << ' ' << passOrFail;
+                    }
+                    stream << ':';
+                }
+            }
+
+            void printIssue( std::string const& issue ) const {
+                stream << ' ' << issue;
+            }
+
+            void printExpressionWas() {
+                if( result.hasExpression() ) {
+                    stream << ';';
+                    {
+                        Colour colour( dimColour() );
+                        stream << " expression was:";
+                    }
+                    printOriginalExpression();
+                }
+            }
+
+            void printOriginalExpression() const {
+                if( result.hasExpression() ) {
+                    stream << ' ' << result.getExpression();
+                }
+            }
+
+            void printReconstructedExpression() const {
+                if( result.hasExpandedExpression() ) {
+                    {
+                        Colour colour( dimColour() );
+                        stream << " for: ";
+                    }
+                    stream << result.getExpandedExpression();
+                }
+            }
+
+            void printMessage() {
+                if ( itMessage != messages.end() ) {
+                    stream << " '" << itMessage->message << '\'';
+                    ++itMessage;
+                }
+            }
+
+            void printRemainingMessages( Colour::Code colour = dimColour() ) {
+                if ( itMessage == messages.end() )
+                    return;
+
+                // using messages.end() directly yields compilation error:
+                std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+                const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
+
+                {
+                    Colour colourGuard( colour );
+                    stream << " with " << pluralise( N, "message" ) << ':';
+                }
+
+                for(; itMessage != itEnd; ) {
+                    // If this assertion is a warning ignore any INFO messages
+                    if( printInfoMessages || itMessage->type != ResultWas::Info ) {
+                        stream << " '" << itMessage->message << '\'';
+                        if ( ++itMessage != itEnd ) {
+                            Colour colourGuard( dimColour() );
+                            stream << " and";
+                        }
+                    }
+                }
+            }
+
+        private:
+            std::ostream& stream;
+            AssertionStats const& stats;
+            AssertionResult const& result;
+            std::vector<MessageInfo> messages;
+            std::vector<MessageInfo>::const_iterator itMessage;
+            bool printInfoMessages;
+        };
+
+        // Colour, message variants:
+        // - white: No tests ran.
+        // -   red: Failed [both/all] N test cases, failed [both/all] M assertions.
+        // - white: Passed [both/all] N test cases (no assertions).
+        // -   red: Failed N tests cases, failed M assertions.
+        // - green: Passed [both/all] N tests cases with M assertions.
+
+        std::string bothOrAll( std::size_t count ) const {
+            return count == 1 ? std::string() : count == 2 ? "both " : "all " ;
+        }
+
+        void printTotals( const Totals& totals ) const {
+            if( totals.testCases.total() == 0 ) {
+                stream << "No tests ran.";
+            }
+            else if( totals.testCases.failed == totals.testCases.total() ) {
+                Colour colour( Colour::ResultError );
+                const std::string qualify_assertions_failed =
+                    totals.assertions.failed == totals.assertions.total() ?
+                        bothOrAll( totals.assertions.failed ) : std::string();
+                stream <<
+                    "Failed " << bothOrAll( totals.testCases.failed )
+                              << pluralise( totals.testCases.failed, "test case"  ) << ", "
+                    "failed " << qualify_assertions_failed <<
+                                 pluralise( totals.assertions.failed, "assertion" ) << '.';
+            }
+            else if( totals.assertions.total() == 0 ) {
+                stream <<
+                    "Passed " << bothOrAll( totals.testCases.total() )
+                              << pluralise( totals.testCases.total(), "test case" )
+                              << " (no assertions).";
+            }
+            else if( totals.assertions.failed ) {
+                Colour colour( Colour::ResultError );
+                stream <<
+                    "Failed " << pluralise( totals.testCases.failed, "test case"  ) << ", "
+                    "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.';
+            }
+            else {
+                Colour colour( Colour::ResultSuccess );
+                stream <<
+                    "Passed " << bothOrAll( totals.testCases.passed )
+                              << pluralise( totals.testCases.passed, "test case"  ) <<
+                    " with "  << pluralise( totals.assertions.passed, "assertion" ) << '.';
+            }
+        }
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter )
+
+} // end namespace Catch
+
+namespace Catch {
+    // These are all here to avoid warnings about not having any out of line
+    // virtual methods
+    NonCopyable::~NonCopyable() {}
+    IShared::~IShared() {}
+    IStream::~IStream() CATCH_NOEXCEPT {}
+    FileStream::~FileStream() CATCH_NOEXCEPT {}
+    CoutStream::~CoutStream() CATCH_NOEXCEPT {}
+    DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
+    StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
+    IContext::~IContext() {}
+    IResultCapture::~IResultCapture() {}
+    ITestCase::~ITestCase() {}
+    ITestCaseRegistry::~ITestCaseRegistry() {}
+    IRegistryHub::~IRegistryHub() {}
+    IMutableRegistryHub::~IMutableRegistryHub() {}
+    IExceptionTranslator::~IExceptionTranslator() {}
+    IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
+    IReporter::~IReporter() {}
+    IReporterFactory::~IReporterFactory() {}
+    IReporterRegistry::~IReporterRegistry() {}
+    IStreamingReporter::~IStreamingReporter() {}
+    AssertionStats::~AssertionStats() {}
+    SectionStats::~SectionStats() {}
+    TestCaseStats::~TestCaseStats() {}
+    TestGroupStats::~TestGroupStats() {}
+    TestRunStats::~TestRunStats() {}
+    CumulativeReporterBase::SectionNode::~SectionNode() {}
+    CumulativeReporterBase::~CumulativeReporterBase() {}
+
+    StreamingReporterBase::~StreamingReporterBase() {}
+    ConsoleReporter::~ConsoleReporter() {}
+    CompactReporter::~CompactReporter() {}
+    IRunner::~IRunner() {}
+    IMutableContext::~IMutableContext() {}
+    IConfig::~IConfig() {}
+    XmlReporter::~XmlReporter() {}
+    JunitReporter::~JunitReporter() {}
+    TestRegistry::~TestRegistry() {}
+    FreeFunctionTestCase::~FreeFunctionTestCase() {}
+    IGeneratorInfo::~IGeneratorInfo() {}
+    IGeneratorsForTest::~IGeneratorsForTest() {}
+    WildcardPattern::~WildcardPattern() {}
+    TestSpec::Pattern::~Pattern() {}
+    TestSpec::NamePattern::~NamePattern() {}
+    TestSpec::TagPattern::~TagPattern() {}
+    TestSpec::ExcludedPattern::~ExcludedPattern() {}
+    Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {}
+
+    void Config::dummy() {}
+
+    namespace TestCaseTracking {
+        ITracker::~ITracker() {}
+        TrackerBase::~TrackerBase() {}
+        SectionTracker::~SectionTracker() {}
+        IndexTracker::~IndexTracker() {}
+    }
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+// #included from: internal/catch_default_main.hpp
+#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
+
+#ifndef __OBJC__
+
+#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
+// Standard C/C++ Win32 Unicode wmain entry point
+extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
+#else
+// Standard C/C++ main entry point
+int main (int argc, char * argv[]) {
+#endif
+
+    int result = Catch::Session().run( argc, argv );
+    return ( result < 0xff ? result : 0xff );
+}
+
+#else // __OBJC__
+
+// Objective-C entry point
+int main (int argc, char * const argv[]) {
+#if !CATCH_ARC_ENABLED
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+#endif
+
+    Catch::registerTestMethods();
+    int result = Catch::Session().run( argc, (char* const*)argv );
+
+#if !CATCH_ARC_ENABLED
+    [pool drain];
+#endif
+
+    return ( result < 0xff ? result : 0xff );
+}
+
+#endif // __OBJC__
+
+#endif
+
+#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
+#  undef CLARA_CONFIG_MAIN
+#endif
+
+//////
+
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+#else
+#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr  )
+#endif
+
+#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
+
+#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
+#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
+
+#define CATCH_CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
+
+#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#else
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif
+
+#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
+#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+    #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+    #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+    #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+    #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+    #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+    #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+    #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#else
+    #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+    #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+    #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+    #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description )
+    #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+    #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
+    #define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
+    #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
+#endif
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
+#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define CATCH_GIVEN( desc )    CATCH_SECTION( std::string( "Given: ") + desc, "" )
+#define CATCH_WHEN( desc )     CATCH_SECTION( std::string( " When: ") + desc, "" )
+#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( "  And: ") + desc, "" )
+#define CATCH_THEN( desc )     CATCH_SECTION( std::string( " Then: ") + desc, "" )
+#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( "  And: ") + desc, "" )
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+
+#else
+#define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr  )
+#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+#endif
+
+#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
+#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
+
+#define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
+#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
+
+#define CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
+#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
+
+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#else
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif
+
+#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
+#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#else
+#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+    #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+    #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+    #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description )
+    #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+    #define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
+    #define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
+    #define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
+#endif
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
+#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define GIVEN( desc )    SECTION( std::string("   Given: ") + desc, "" )
+#define WHEN( desc )     SECTION( std::string("    When: ") + desc, "" )
+#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" )
+#define THEN( desc )     SECTION( std::string("    Then: ") + desc, "" )
+#define AND_THEN( desc ) SECTION( std::string("     And: ") + desc, "" )
+
+using Catch::Detail::Approx;
+
+// #included from: internal/catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#    ifdef __ICC // icpc defines the __clang__ macro
+#        pragma warning(pop)
+#    else
+#        pragma clang diagnostic pop
+#    endif
+#elif defined __GNUC__
+#    pragma GCC diagnostic pop
+#endif
+
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/data/mapbox-streets-v6-14-8714-8017.mvt
===================================================================
(Binary files differ)

Index: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/data/mapbox-streets-v6-14-8714-8017.mvt
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/data/mapbox-streets-v6-14-8714-8017.mvt	2019-05-29 16:42:14 UTC (rev 9522)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/data/mapbox-streets-v6-14-8714-8017.mvt	2019-05-29 16:52:57 UTC (rev 9523)

Property changes on: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/data/mapbox-streets-v6-14-8714-8017.mvt
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/fixture_tests.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/fixture_tests.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/fixture_tests.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,1015 @@
+
+#include <test.hpp>
+
+#include <vtzero/builder.hpp>
+#include <vtzero/geometry.hpp>
+#include <vtzero/vector_tile.hpp>
+
+#include <cstdint>
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+
+static std::string open_tile(const std::string& path) {
+    const auto fixtures_dir = std::getenv("FIXTURES_DIR");
+    if (fixtures_dir == nullptr) {
+        std::cerr << "Set FIXTURES_DIR environment variable to the directory where the mvt fixtures are!\n";
+        std::exit(2);
+    }
+
+    std::ifstream stream{std::string{fixtures_dir} + "/" + path,
+                         std::ios_base::in|std::ios_base::binary};
+    if (!stream.is_open()) {
+        throw std::runtime_error{"could not open: '" + path + "'"};
+    }
+
+    const std::string message{std::istreambuf_iterator<char>(stream.rdbuf()),
+                              std::istreambuf_iterator<char>()};
+
+    stream.close();
+    return message;
+}
+
+// ---------------------------------------------------------------------------
+
+struct point_handler {
+
+    std::vector<vtzero::point> data{};
+
+    void points_begin(uint32_t count) {
+        data.reserve(count);
+    }
+
+    void points_point(const vtzero::point point) {
+        data.push_back(point);
+    }
+
+    void points_end() const noexcept {
+    }
+
+}; // struct point_handler
+
+struct linestring_handler {
+
+    std::vector<std::vector<vtzero::point>> data{};
+
+    void linestring_begin(uint32_t count) {
+        data.emplace_back();
+        data.back().reserve(count);
+    }
+
+    void linestring_point(const vtzero::point point) {
+        data.back().push_back(point);
+    }
+
+    void linestring_end() const noexcept {
+    }
+
+}; // struct linestring_handler
+
+struct polygon_handler {
+
+    std::vector<std::vector<vtzero::point>> data{};
+
+    void ring_begin(uint32_t count) {
+        data.emplace_back();
+        data.back().reserve(count);
+    }
+
+    void ring_point(const vtzero::point point) {
+        data.back().push_back(point);
+    }
+
+    void ring_end(vtzero::ring_type /*dummy*/) const noexcept {
+    }
+
+}; // struct polygon_handler
+
+// ---------------------------------------------------------------------------
+
+struct geom_handler {
+
+    std::vector<vtzero::point> point_data{};
+    std::vector<std::vector<vtzero::point>> line_data{};
+
+    void points_begin(uint32_t count) {
+        point_data.reserve(count);
+    }
+
+    void points_point(const vtzero::point point) {
+        point_data.push_back(point);
+    }
+
+    void points_end() const noexcept {
+    }
+
+    void linestring_begin(uint32_t count) {
+        line_data.emplace_back();
+        line_data.back().reserve(count);
+    }
+
+    void linestring_point(const vtzero::point point) {
+        line_data.back().push_back(point);
+    }
+
+    void linestring_end() const noexcept {
+    }
+
+    void ring_begin(uint32_t count) {
+        line_data.emplace_back();
+        line_data.back().reserve(count);
+    }
+
+    void ring_point(const vtzero::point point) {
+        line_data.back().push_back(point);
+    }
+
+    void ring_end(vtzero::ring_type /*dummy*/) const noexcept {
+    }
+
+}; // struct geom_handler
+
+// ---------------------------------------------------------------------------
+
+static vtzero::feature check_layer(vtzero::vector_tile& tile) {
+    REQUIRE_FALSE(tile.empty());
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.name() == "hello");
+    REQUIRE(layer.version() == 2);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    return layer.next_feature();
+}
+
+// ---------------------------------------------------------------------------
+
+TEST_CASE("MVT test 001: Empty tile") {
+    std::string buffer{open_tile("001/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.empty());
+    REQUIRE(tile.count_layers() == 0); // NOLINT(readability-container-size-empty)
+}
+
+TEST_CASE("MVT test 002: Tile with single point feature without id") {
+    std::string buffer{open_tile("002/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    const auto feature = check_layer(tile);
+
+    REQUIRE_FALSE(feature.has_id());
+    REQUIRE(feature.id() == 0);
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::POINT);
+
+    point_handler handler;
+    vtzero::decode_point_geometry(feature.geometry(), handler);
+
+    std::vector<vtzero::point> expected = {{25, 17}};
+    REQUIRE(handler.data == expected);
+}
+
+TEST_CASE("MVT test 003: Tile with single point with missing geometry type") {
+    std::string buffer{open_tile("003/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    const auto feature = check_layer(tile);
+    REQUIRE(feature.has_id());
+    REQUIRE(feature.id() == 1);
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::UNKNOWN);
+}
+
+TEST_CASE("MVT test 004: Tile with single point with missing geometry") {
+    std::string buffer{open_tile("004/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE_THROWS_AS(check_layer(tile), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 005: Tile with single point with broken tags array") {
+    std::string buffer{open_tile("005/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE_FALSE(tile.empty());
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE_FALSE(layer.empty());
+
+    REQUIRE_THROWS_AS(layer.next_feature(), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 006: Tile with single point with invalid GeomType") {
+    std::string buffer{open_tile("006/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE_FALSE(layer.empty());
+
+    REQUIRE_THROWS_AS(layer.next_feature(), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 007: Layer version as string instead of as an int") {
+    std::string buffer{open_tile("007/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    REQUIRE_THROWS_AS(tile.get_layer(0), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 008: Tile layer extent encoded as string") {
+    std::string buffer{open_tile("008/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    REQUIRE_THROWS_AS(tile.next_layer(), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 009: Tile layer extent missing") {
+    std::string buffer{open_tile("009/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+
+    REQUIRE(layer.name() == "hello");
+    REQUIRE(layer.version() == 2);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.id() == 1);
+}
+
+TEST_CASE("MVT test 010: Tile layer value is encoded as int, but pretends to be string") {
+    std::string buffer{open_tile("010/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE_FALSE(layer.empty());
+
+    const auto pv = layer.value(0);
+    REQUIRE_THROWS_AS(pv.type(), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 011: Tile layer value is encoded as unknown type") {
+    std::string buffer{open_tile("011/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    const auto layer = tile.next_layer();
+    REQUIRE_FALSE(layer.empty());
+
+    const auto pv = layer.value(0);
+    REQUIRE_THROWS_AS(pv.type(), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 012: Unknown layer version") {
+    std::string buffer{open_tile("012/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    REQUIRE_THROWS_AS(tile.next_layer(), const vtzero::version_exception&);
+}
+
+TEST_CASE("MVT test 013: Tile with key in table encoded as int") {
+    std::string buffer{open_tile("013/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    REQUIRE_THROWS_AS(tile.next_layer(), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 014: Tile layer without a name") {
+    std::string buffer{open_tile("014/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    REQUIRE_THROWS_AS(tile.next_layer(), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 015: Two layers with the same name") {
+    std::string buffer{open_tile("015/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 2);
+
+    while (const auto layer = tile.next_layer()) {
+        REQUIRE(layer.name() == "hello");
+    }
+
+    const auto layer = tile.get_layer_by_name("hello");
+    REQUIRE(layer.name() == "hello");
+}
+
+TEST_CASE("MVT test 016: Valid unknown geometry") {
+    std::string buffer{open_tile("016/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    const auto feature = check_layer(tile);
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::UNKNOWN);
+}
+
+TEST_CASE("MVT test 017: Valid point geometry") {
+    std::string buffer{open_tile("017/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    const auto feature = check_layer(tile);
+
+    REQUIRE(feature.has_id());
+    REQUIRE(feature.id() == 1);
+
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::POINT);
+
+    const std::vector<vtzero::point> expected = {{25, 17}};
+
+    SECTION("decode_point_geometry") {
+        point_handler handler;
+        vtzero::decode_point_geometry(feature.geometry(), handler);
+        REQUIRE(handler.data == expected);
+    }
+
+    SECTION("decode_geometry") {
+        geom_handler handler;
+        vtzero::decode_geometry(feature.geometry(), handler);
+        REQUIRE(handler.point_data == expected);
+    }
+}
+
+TEST_CASE("MVT test 018: Valid linestring geometry") {
+    std::string buffer = open_tile("018/tile.mvt");
+    vtzero::vector_tile tile{buffer};
+
+    const auto feature = check_layer(tile);
+
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::LINESTRING);
+
+    const std::vector<std::vector<vtzero::point>> expected = {{{2, 2}, {2,10}, {10, 10}}};
+
+    SECTION("decode_linestring_geometry") {
+        linestring_handler handler;
+        vtzero::decode_linestring_geometry(feature.geometry(), handler);
+        REQUIRE(handler.data == expected);
+    }
+
+    SECTION("decode_geometry") {
+        geom_handler handler;
+        vtzero::decode_geometry(feature.geometry(), handler);
+        REQUIRE(handler.line_data == expected);
+    }
+}
+
+TEST_CASE("MVT test 019: Valid polygon geometry") {
+    std::string buffer = open_tile("019/tile.mvt");
+    vtzero::vector_tile tile{buffer};
+
+    const auto feature = check_layer(tile);
+
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::POLYGON);
+
+    const std::vector<std::vector<vtzero::point>> expected = {{{3, 6}, {8,12}, {20, 34}, {3, 6}}};
+
+    SECTION("deocode_polygon_geometry") {
+        polygon_handler handler;
+        vtzero::decode_polygon_geometry(feature.geometry(), handler);
+        REQUIRE(handler.data == expected);
+    }
+
+    SECTION("deocode_geometry") {
+        geom_handler handler;
+        vtzero::decode_geometry(feature.geometry(), handler);
+        REQUIRE(handler.line_data == expected);
+    }
+}
+
+TEST_CASE("MVT test 020: Valid multipoint geometry") {
+    std::string buffer = open_tile("020/tile.mvt");
+    vtzero::vector_tile tile{buffer};
+
+    const auto feature = check_layer(tile);
+
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::POINT);
+
+    point_handler handler;
+    vtzero::decode_point_geometry(feature.geometry(), handler);
+
+    const std::vector<vtzero::point> expected = {{5, 7}, {3,2}};
+
+    REQUIRE(handler.data == expected);
+}
+
+TEST_CASE("MVT test 021: Valid multilinestring geometry") {
+    std::string buffer = open_tile("021/tile.mvt");
+    vtzero::vector_tile tile{buffer};
+
+    const auto feature = check_layer(tile);
+
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::LINESTRING);
+
+    linestring_handler handler;
+    vtzero::decode_linestring_geometry(feature.geometry(), handler);
+
+    const std::vector<std::vector<vtzero::point>> expected = {{{2, 2}, {2,10}, {10, 10}}, {{1,1}, {3, 5}}};
+
+    REQUIRE(handler.data == expected);
+}
+
+TEST_CASE("MVT test 022: Valid multipolygon geometry") {
+    std::string buffer = open_tile("022/tile.mvt");
+    vtzero::vector_tile tile{buffer};
+
+    const auto feature = check_layer(tile);
+
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::POLYGON);
+
+    polygon_handler handler;
+    vtzero::decode_polygon_geometry(feature.geometry(), handler);
+
+    const std::vector<std::vector<vtzero::point>> expected = {
+        {{0, 0}, {10, 0}, {10, 10}, {0,10}, {0, 0}},
+        {{11, 11}, {20, 11}, {20, 20}, {11, 20}, {11, 11}},
+        {{13, 13}, {13, 17}, {17, 17}, {17, 13}, {13, 13}}
+    };
+
+    REQUIRE(handler.data == expected);
+}
+
+TEST_CASE("MVT test 023: Invalid layer: missing layer name") {
+    std::string buffer = open_tile("023/tile.mvt");
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    REQUIRE_THROWS_AS(tile.next_layer(), const vtzero::format_exception&);
+    REQUIRE_THROWS_AS(tile.get_layer_by_name("foo"), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 024: Missing layer version") {
+    std::string buffer = open_tile("024/tile.mvt");
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    const auto layer = tile.next_layer();
+    REQUIRE(layer.version() == 1);
+}
+
+TEST_CASE("MVT test 025: Layer without features") {
+    std::string buffer = open_tile("025/tile.mvt");
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    const auto layer = tile.next_layer();
+    REQUIRE(layer.empty());
+    REQUIRE(layer.num_features() == 0); // NOLINT(readability-container-size-empty)
+}
+
+TEST_CASE("MVT test 026: Extra value type") {
+    std::string buffer = open_tile("026/tile.mvt");
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+    REQUIRE(feature.empty());
+
+    const auto& table = layer.value_table();
+    REQUIRE(table.size() == 1);
+
+    const auto pvv = table[0];
+    REQUIRE(pvv.valid());
+    REQUIRE_THROWS_AS(pvv.type(), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 027: Layer with unused bool property value") {
+    std::string buffer{open_tile("027/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+    REQUIRE(feature.num_properties() == 0); // NOLINT(readability-container-size-empty)
+
+    const auto& vtab = layer.value_table();
+    REQUIRE(vtab.size() == 1);
+    REQUIRE(vtab[0].bool_value());
+}
+
+TEST_CASE("MVT test 030: Two geometry fields") {
+    std::string buffer = open_tile("030/tile.mvt");
+    vtzero::vector_tile tile{buffer};
+
+    auto layer = tile.next_layer();
+    REQUIRE_FALSE(layer.empty());
+
+    REQUIRE_THROWS_AS(layer.next_feature(), const vtzero::format_exception&);
+}
+
+TEST_CASE("MVT test 032: Layer with single feature with string property value") {
+    std::string buffer{open_tile("032/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE_FALSE(tile.empty());
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.num_properties() == 1);
+
+    auto prop = feature.next_property();
+    REQUIRE(prop.key() == "key1");
+    REQUIRE(prop.value().string_value() == "i am a string value");
+
+    feature.reset_property();
+    auto ii = feature.next_property_indexes();
+    REQUIRE(ii);
+    REQUIRE(ii.key().value() == 0);
+    REQUIRE(ii.value().value() == 0);
+    REQUIRE_FALSE(feature.next_property_indexes());
+
+    int32_t sum = 0;
+    int32_t count = 0;
+    feature.for_each_property_indexes([&](vtzero::index_value_pair&& ivp) {
+        sum += ivp.key().value();
+        sum += ivp.value().value();
+        ++count;
+        return true;
+    });
+
+    REQUIRE(sum == 0);
+    REQUIRE(count == 1);
+}
+
+TEST_CASE("MVT test 033: Layer with single feature with float property value") {
+    std::string buffer{open_tile("033/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.num_properties() == 1);
+
+    const auto prop = feature.next_property();
+    REQUIRE(prop.key() == "key1");
+    REQUIRE(prop.value().float_value() == Approx(3.1));
+}
+
+TEST_CASE("MVT test 034: Layer with single feature with double property value") {
+    std::string buffer{open_tile("034/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.num_properties() == 1);
+
+    const auto prop = feature.next_property();
+    REQUIRE(prop.key() == "key1");
+    REQUIRE(prop.value().double_value() == Approx(1.23));
+}
+
+TEST_CASE("MVT test 035: Layer with single feature with int property value") {
+    std::string buffer{open_tile("035/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.num_properties() == 1);
+
+    const auto prop = feature.next_property();
+    REQUIRE(prop.key() == "key1");
+    REQUIRE(prop.value().int_value() == 6);
+}
+
+TEST_CASE("MVT test 036: Layer with single feature with uint property value") {
+    std::string buffer{open_tile("036/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.num_properties() == 1);
+
+    const auto prop = feature.next_property();
+    REQUIRE(prop.key() == "key1");
+    REQUIRE(prop.value().uint_value() == 87948);
+}
+
+TEST_CASE("MVT test 037: Layer with single feature with sint property value") {
+    std::string buffer{open_tile("037/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.num_properties() == 1);
+
+    const auto prop = feature.next_property();
+    REQUIRE(prop.key() == "key1");
+    REQUIRE(prop.value().sint_value() == 87948);
+}
+
+TEST_CASE("MVT test 038: Layer with all types of property value") {
+    std::string buffer{open_tile("038/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+
+    const auto& vtab = layer.value_table();
+    REQUIRE(vtab.size() == 7);
+    REQUIRE(vtab[0].string_value() == "ello");
+    REQUIRE(vtab[1].bool_value());
+    REQUIRE(vtab[2].int_value() == 6);
+    REQUIRE(vtab[3].double_value() == Approx(1.23));
+    REQUIRE(vtab[4].float_value() == Approx(3.1));
+    REQUIRE(vtab[5].sint_value() == -87948);
+    REQUIRE(vtab[6].uint_value() == 87948);
+
+    REQUIRE_THROWS_AS(vtab[0].bool_value(), const vtzero::type_exception&);
+    REQUIRE_THROWS_AS(vtab[0].int_value(), const vtzero::type_exception&);
+    REQUIRE_THROWS_AS(vtab[0].double_value(), const vtzero::type_exception&);
+    REQUIRE_THROWS_AS(vtab[0].float_value(), const vtzero::type_exception&);
+    REQUIRE_THROWS_AS(vtab[0].sint_value(), const vtzero::type_exception&);
+    REQUIRE_THROWS_AS(vtab[0].uint_value(), const vtzero::type_exception&);
+    REQUIRE_THROWS_AS(vtab[1].string_value(), const vtzero::type_exception&);
+}
+
+TEST_CASE("MVT test 039: Default values are actually encoded in the tile") {
+    std::string buffer{open_tile("039/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.version() == 1);
+    REQUIRE(layer.name() == "hello");
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.id() == 0);
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::UNKNOWN);
+    REQUIRE(feature.empty());
+
+    REQUIRE_THROWS_AS(vtzero::decode_geometry(feature.geometry(), geom_handler{}), const vtzero::geometry_exception&);
+}
+
+TEST_CASE("MVT test 040: Feature has tags that point to non-existent Key in the layer.") {
+    std::string buffer{open_tile("040/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+    auto feature = layer.next_feature();
+    REQUIRE(feature.num_properties() == 1);
+    REQUIRE_THROWS_AS(feature.next_property(), const vtzero::out_of_range_exception&);
+}
+
+TEST_CASE("MVT test 040: Feature has tags that point to non-existent Key in the layer decoded using next_property_indexes().") {
+    std::string buffer{open_tile("040/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+    auto feature = layer.next_feature();
+    REQUIRE(feature.num_properties() == 1);
+    REQUIRE_THROWS_AS(feature.next_property_indexes(), const vtzero::out_of_range_exception&);
+}
+
+TEST_CASE("MVT test 041: Tags encoded as floats instead of as ints") {
+    std::string buffer{open_tile("041/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+    auto feature = layer.next_feature();
+    REQUIRE_THROWS_AS(feature.next_property(), const vtzero::out_of_range_exception&);
+}
+
+TEST_CASE("MVT test 042: Feature has tags that point to non-existent Value in the layer.") {
+    std::string buffer{open_tile("042/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+    auto feature = layer.next_feature();
+    REQUIRE(feature.num_properties() == 1);
+    REQUIRE_THROWS_AS(feature.next_property(), const vtzero::out_of_range_exception&);
+}
+
+TEST_CASE("MVT test 043: A layer with six points that all share the same key but each has a unique value.") {
+    std::string buffer{open_tile("043/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 6);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+    REQUIRE(feature.num_properties() == 1);
+
+    auto property = feature.next_property();
+    REQUIRE(property);
+    REQUIRE(property.key() == "poi");
+    REQUIRE(property.value().string_value() == "swing");
+
+    feature = layer.next_feature();
+    REQUIRE(feature);
+
+    property = feature.next_property();
+    REQUIRE(property);
+    REQUIRE(property.key() == "poi");
+    REQUIRE(property.value().string_value() == "water_fountain");
+}
+
+TEST_CASE("MVT test 044: Geometry field begins with a ClosePath command, which is invalid") {
+    std::string buffer{open_tile("044/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+    REQUIRE_THROWS_AS(vtzero::decode_geometry(geometry, geom_handler{}), const vtzero::geometry_exception&);
+}
+
+TEST_CASE("MVT test 045: Invalid point geometry that includes a MoveTo command and only half of the xy coordinates") {
+    std::string buffer{open_tile("045/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+    REQUIRE_THROWS_AS(vtzero::decode_geometry(geometry, geom_handler{}), const vtzero::geometry_exception&);
+    REQUIRE_THROWS_WITH(vtzero::decode_geometry(geometry, geom_handler{}), "too few points in geometry");
+}
+
+TEST_CASE("MVT test 046: Invalid linestring geometry that includes two points in the same position, which is not OGC valid") {
+    std::string buffer{open_tile("046/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+
+    geom_handler handler;
+    vtzero::decode_geometry(geometry, handler);
+
+    const std::vector<std::vector<vtzero::point>> expected = {{{2, 2}, {2, 10}, {2, 10}}};
+    REQUIRE(handler.line_data == expected);
+}
+
+TEST_CASE("MVT test 047: Invalid polygon with wrong ClosePath count 2 (must be count 1)") {
+    std::string buffer{open_tile("047/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+    REQUIRE_THROWS_AS(vtzero::decode_geometry(geometry, geom_handler{}), const vtzero::geometry_exception&);
+    REQUIRE_THROWS_WITH(vtzero::decode_geometry(geometry, geom_handler{}), "ClosePath command count is not 1");
+}
+
+TEST_CASE("MVT test 048: Invalid polygon with wrong ClosePath count 0 (must be count 1)") {
+    std::string buffer{open_tile("048/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+    REQUIRE_THROWS_AS(vtzero::decode_geometry(geometry, geom_handler{}), const vtzero::geometry_exception&);
+    REQUIRE_THROWS_WITH(vtzero::decode_geometry(geometry, geom_handler{}), "ClosePath command count is not 1");
+}
+
+TEST_CASE("MVT test 049: decoding linestring with int32 overflow in x coordinate") {
+    std::string buffer{open_tile("049/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+
+    geom_handler handler;
+    vtzero::decode_geometry(geometry, handler);
+
+    const std::vector<std::vector<vtzero::point>> expected = {{{std::numeric_limits<int32_t>::max(), 0}, {std::numeric_limits<int32_t>::min(), 1}}};
+    REQUIRE(handler.line_data == expected);
+}
+
+TEST_CASE("MVT test 050: decoding linestring with int32 overflow in y coordinate") {
+    std::string buffer{open_tile("050/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+
+    geom_handler handler;
+    vtzero::decode_geometry(geometry, handler);
+
+    const std::vector<std::vector<vtzero::point>> expected = {{{0, std::numeric_limits<int32_t>::min()}, {-1, std::numeric_limits<int32_t>::max()}}};
+    REQUIRE(handler.line_data == expected);
+}
+
+TEST_CASE("MVT test 051: multipoint with a huge count value, useful for ensuring no over-allocation errors. Example error message \"count too large\"") {
+    std::string buffer{open_tile("051/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+    REQUIRE_THROWS_AS(vtzero::decode_geometry(geometry, geom_handler{}), const vtzero::geometry_exception&);
+    REQUIRE_THROWS_WITH(vtzero::decode_geometry(geometry, geom_handler{}), "count too large");
+}
+
+TEST_CASE("MVT test 052: multipoint with not enough points") {
+    std::string buffer{open_tile("052/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+    REQUIRE_THROWS_AS(vtzero::decode_geometry(geometry, geom_handler{}), const vtzero::geometry_exception&);
+}
+
+TEST_CASE("MVT test 053: clipped square (exact extent): a polygon that covers the entire tile to the exact boundary") {
+    std::string buffer{open_tile("053/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+
+    geom_handler handler;
+    vtzero::decode_geometry(geometry, handler);
+
+    const std::vector<std::vector<vtzero::point>> expected = {{{0, 0}, {4096, 0}, {4096, 4096}, {0, 4096}, {0, 0}}};
+    REQUIRE(handler.line_data == expected);
+}
+
+TEST_CASE("MVT test 054: clipped square (one unit buffer): a polygon that covers the entire tile plus a one unit buffer") {
+    std::string buffer{open_tile("054/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+
+    geom_handler handler;
+    vtzero::decode_geometry(geometry, handler);
+
+    const std::vector<std::vector<vtzero::point>> expected = {{{-1, -1}, {4097, -1}, {4097, 4097}, {-1, 4097}, {-1, -1}}};
+    REQUIRE(handler.line_data == expected);
+}
+
+TEST_CASE("MVT test 055: clipped square (minus one unit buffer): a polygon that almost covers the entire tile minus one unit buffer") {
+    std::string buffer{open_tile("055/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+
+    geom_handler handler;
+    vtzero::decode_geometry(geometry, handler);
+
+    const std::vector<std::vector<vtzero::point>> expected = {{{1, 1}, {4095, 1}, {4095, 4095}, {1, 4095}, {1, 1}}};
+    REQUIRE(handler.line_data == expected);
+}
+
+TEST_CASE("MVT test 056: clipped square (large buffer): a polygon that covers the entire tile plus a 200 unit buffer") {
+    std::string buffer{open_tile("056/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+
+    geom_handler handler;
+    vtzero::decode_geometry(geometry, handler);
+
+    const std::vector<std::vector<vtzero::point>> expected = {{{-200, -200}, {4296, -200}, {4296, 4296}, {-200, 4296}, {-200, -200}}};
+    REQUIRE(handler.line_data == expected);
+}
+
+TEST_CASE("MVT test 057: A point fixture with a gigantic MoveTo command. Can be used to test decoders for memory overallocation situations") {
+    std::string buffer{open_tile("057/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+    REQUIRE_THROWS_AS(vtzero::decode_geometry(geometry, geom_handler{}), const vtzero::geometry_exception&);
+    REQUIRE_THROWS_WITH(vtzero::decode_geometry(geometry, geom_handler{}), "count too large");
+}
+
+TEST_CASE("MVT test 058: A linestring fixture with a gigantic LineTo command") {
+    std::string buffer{open_tile("058/tile.mvt")};
+    vtzero::vector_tile tile{buffer};
+    REQUIRE(tile.count_layers() == 1);
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+
+    const auto geometry = feature.geometry();
+    REQUIRE_THROWS_AS(vtzero::decode_geometry(geometry, geom_handler{}), const vtzero::geometry_exception&);
+    REQUIRE_THROWS_WITH(vtzero::decode_geometry(geometry, geom_handler{}), "count too large");
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/include/test.hpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/include/test.hpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/include/test.hpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,37 @@
+#ifndef TEST_HPP
+#define TEST_HPP
+
+#include <catch.hpp>
+
+#include <stdexcept>
+
+// Define vtzero_assert() to throw this error. This allows the tests to
+// check that the assert fails.
+struct assert_error : public std::runtime_error {
+    explicit assert_error(const char* what_arg) : std::runtime_error(what_arg) {
+    }
+};
+
+#define vtzero_assert(x) if (!(x)) { throw assert_error{#x}; }
+
+#define vtzero_assert_in_noexcept_function(x) if (!(x)) { got_an_assert = true; }
+
+extern bool got_an_assert;
+
+#define REQUIRE_ASSERT(x) x; REQUIRE(got_an_assert); got_an_assert = false;
+
+#include <vtzero/output.hpp>
+
+std::string load_test_tile();
+
+struct mypoint {
+    int64_t p1;
+    int64_t p2;
+};
+
+inline vtzero::point create_vtzero_point(mypoint p) noexcept {
+    return {static_cast<int32_t>(p.p1),
+            static_cast<int32_t>(p.p2)};
+}
+
+#endif // TEST_HPP

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,539 @@
+
+#include <test.hpp>
+
+#include <vtzero/builder.hpp>
+#include <vtzero/index.hpp>
+#include <vtzero/output.hpp>
+#include <vtzero/property_mapper.hpp>
+
+#include <cstdint>
+#include <string>
+#include <type_traits>
+
+template <typename T>
+struct movable_not_copyable {
+    constexpr static bool value = !std::is_copy_constructible<T>::value &&
+                                  !std::is_copy_assignable<T>::value    &&
+                                   std::is_nothrow_move_constructible<T>::value &&
+                                   std::is_nothrow_move_assignable<T>::value;
+};
+
+static_assert(movable_not_copyable<vtzero::tile_builder>::value, "tile_builder should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<vtzero::point_feature_builder>::value, "point_feature_builder should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<vtzero::linestring_feature_builder>::value, "linestring_feature_builder should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<vtzero::polygon_feature_builder>::value, "polygon_feature_builder should be nothrow movable, but not copyable");
+static_assert(movable_not_copyable<vtzero::geometry_feature_builder>::value, "geometry_feature_builder should be nothrow movable, but not copyable");
+
+TEST_CASE("Create tile from existing layers") {
+    const auto buffer = load_test_tile();
+    vtzero::vector_tile tile{buffer};
+
+    vtzero::tile_builder tbuilder;
+
+    SECTION("add_existing_layer(layer)") {
+        while (auto layer = tile.next_layer()) {
+            tbuilder.add_existing_layer(layer);
+        }
+    }
+
+    SECTION("add_existing_layer(data_view)") {
+        while (auto layer = tile.next_layer()) {
+            tbuilder.add_existing_layer(layer.data());
+        }
+    }
+
+    const std::string data = tbuilder.serialize();
+
+    REQUIRE(data == buffer);
+}
+
+TEST_CASE("Create layer based on existing layer") {
+    const auto buffer = load_test_tile();
+    vtzero::vector_tile tile{buffer};
+    const auto layer = tile.get_layer_by_name("place_label");
+
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, layer};
+    vtzero::point_feature_builder fbuilder{lbuilder};
+    fbuilder.set_id(42);
+    fbuilder.add_point(10, 20);
+    fbuilder.commit();
+
+    const std::string data = tbuilder.serialize();
+    vtzero::vector_tile new_tile{data};
+    const auto new_layer = new_tile.next_layer();
+    REQUIRE(std::string(new_layer.name()) == "place_label");
+    REQUIRE(new_layer.version() == 1);
+    REQUIRE(new_layer.extent() == 4096);
+}
+
+TEST_CASE("Create layer and add keys/values") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "name"};
+
+    const auto ki1 = lbuilder.add_key_without_dup_check("key1");
+    const auto ki2 = lbuilder.add_key("key2");
+    const auto ki3 = lbuilder.add_key("key1");
+
+    REQUIRE(ki1 != ki2);
+    REQUIRE(ki1 == ki3);
+
+    const auto vi1 = lbuilder.add_value_without_dup_check(vtzero::encoded_property_value{"value1"});
+    vtzero::encoded_property_value value2{"value2"};
+    const auto vi2 = lbuilder.add_value_without_dup_check(vtzero::property_value{value2.data()});
+
+    const auto vi3 = lbuilder.add_value(vtzero::encoded_property_value{"value1"});
+    const auto vi4 = lbuilder.add_value(vtzero::encoded_property_value{19});
+    const auto vi5 = lbuilder.add_value(vtzero::encoded_property_value{19.0});
+    const auto vi6 = lbuilder.add_value(vtzero::encoded_property_value{22});
+    vtzero::encoded_property_value nineteen{19};
+    const auto vi7 = lbuilder.add_value(vtzero::property_value{nineteen.data()});
+
+    REQUIRE(vi1 != vi2);
+    REQUIRE(vi1 == vi3);
+    REQUIRE(vi1 != vi4);
+    REQUIRE(vi1 != vi5);
+    REQUIRE(vi1 != vi6);
+    REQUIRE(vi4 != vi5);
+    REQUIRE(vi4 != vi6);
+    REQUIRE(vi4 == vi7);
+}
+
+TEST_CASE("Committing a feature succeeds after a geometry was added") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    { // explicit commit after geometry
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(1);
+        fbuilder.add_point(10, 10);
+        fbuilder.commit();
+    }
+
+    { // explicit commit after properties
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(2);
+        fbuilder.add_point(10, 10);
+        fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
+        fbuilder.commit();
+    }
+
+    { // extra commits or rollbacks are okay but no other calls
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(3);
+        fbuilder.add_point(10, 10);
+        fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
+        fbuilder.commit();
+
+        SECTION("superfluous commit()") {
+            fbuilder.commit();
+        }
+        SECTION("superfluous rollback()") {
+            fbuilder.rollback();
+        }
+
+        REQUIRE_THROWS_AS(fbuilder.set_id(10), const assert_error&);
+        REQUIRE_THROWS_AS(fbuilder.add_point(20, 20), const assert_error&);
+        REQUIRE_THROWS_AS(fbuilder.add_property("x", "y"), const assert_error&);
+    }
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+    auto layer = tile.next_layer();
+
+    uint64_t n = 1;
+    while (auto feature = layer.next_feature()) {
+        REQUIRE(feature.id() == n++);
+    }
+
+    REQUIRE(n == 4);
+}
+
+TEST_CASE("Committing a feature fails with assert if no geometry was added") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    SECTION("explicit immediate commit") {
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        REQUIRE_THROWS_AS(fbuilder.commit(), const assert_error&);
+    }
+
+    SECTION("explicit commit after setting id") {
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(2);
+        REQUIRE_THROWS_AS(fbuilder.commit(), const assert_error&);
+    }
+}
+
+TEST_CASE("Rollback feature") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    {
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(1);
+        fbuilder.add_point(10, 10);
+        fbuilder.commit();
+    }
+
+    { // immediate rollback
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(2);
+        fbuilder.rollback();
+    }
+
+    { // rollback after setting id
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(3);
+        fbuilder.rollback();
+    }
+
+    { // rollback after geometry
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(4);
+        fbuilder.add_point(20, 20);
+        fbuilder.rollback();
+    }
+
+    { // rollback after properties
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(5);
+        fbuilder.add_point(20, 20);
+        fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
+        fbuilder.rollback();
+    }
+
+    { // implicit rollback after geometry
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(6);
+        fbuilder.add_point(10, 10);
+    }
+
+    { // implicit rollback after properties
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(7);
+        fbuilder.add_point(10, 10);
+        fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
+    }
+
+    {
+        vtzero::point_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(8);
+        fbuilder.add_point(30, 30);
+        fbuilder.commit();
+    }
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+    auto layer = tile.next_layer();
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.id() == 1);
+
+    feature = layer.next_feature();
+    REQUIRE(feature.id() == 8);
+
+    feature = layer.next_feature();
+    REQUIRE_FALSE(feature);
+}
+
+static vtzero::layer next_nonempty_layer(vtzero::vector_tile& tile) {
+    while (auto layer = tile.next_layer()) {
+        if (layer && !layer.empty()) {
+            return layer;
+        }
+    }
+    return vtzero::layer{};
+}
+
+static bool vector_tile_equal(const std::string& t1, const std::string& t2) {
+    vtzero::vector_tile vt1{t1};
+    vtzero::vector_tile vt2{t2};
+
+    for (auto l1 = next_nonempty_layer(vt1), l2 = next_nonempty_layer(vt2);
+         l1 || l2;
+         l1 = next_nonempty_layer(vt1), l2 = next_nonempty_layer(vt2)) {
+
+        if (!l1 ||
+            !l2 ||
+            l1.version() != l2.version() ||
+            l1.extent() != l2.extent() ||
+            l1.num_features() != l2.num_features() ||
+            l1.name() != l2.name()) {
+            return false;
+        }
+
+        for (auto f1 = l1.next_feature(), f2 = l2.next_feature();
+             f1 || f2;
+             f1 = l1.next_feature(), f2 = l2.next_feature()) {
+            if (!f1 ||
+                !f2 ||
+                f1.id() != f2.id() ||
+                f1.geometry_type() != f2.geometry_type() ||
+                f1.num_properties() != f2.num_properties() ||
+                f1.geometry().data() != f2.geometry().data()) {
+                return false;
+            }
+            for (auto p1 = f1.next_property(), p2 = f2.next_property();
+                p1 || p2;
+                p1 = f1.next_property(), p2 = f2.next_property()) {
+                if (!p1 ||
+                    !p2 ||
+                    p1.key() != p2.key() ||
+                    p1.value() != p2.value()) {
+                    return false;
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+TEST_CASE("vector_tile_equal") {
+    REQUIRE(vector_tile_equal("", ""));
+
+    const auto buffer = load_test_tile();
+    REQUIRE(buffer.size() == 269388);
+    REQUIRE(vector_tile_equal(buffer, buffer));
+
+    REQUIRE_FALSE(vector_tile_equal(buffer, ""));
+}
+
+TEST_CASE("Copy tile") {
+    const auto buffer = load_test_tile();
+    vtzero::vector_tile tile{buffer};
+
+    vtzero::tile_builder tbuilder;
+
+    while (auto layer = tile.next_layer()) {
+        vtzero::layer_builder lbuilder{tbuilder, layer};
+        while (auto feature = layer.next_feature()) {
+            lbuilder.add_feature(feature);
+        }
+    }
+
+    const std::string data = tbuilder.serialize();
+    REQUIRE(vector_tile_equal(buffer, data));
+}
+
+TEST_CASE("Copy tile using geometry_feature_builder") {
+    const auto buffer = load_test_tile();
+    vtzero::vector_tile tile{buffer};
+
+    vtzero::tile_builder tbuilder;
+
+    while (auto layer = tile.next_layer()) {
+        vtzero::layer_builder lbuilder{tbuilder, layer};
+        while (auto feature = layer.next_feature()) {
+            vtzero::geometry_feature_builder fbuilder{lbuilder};
+            fbuilder.copy_id(feature);
+            fbuilder.set_geometry(feature.geometry());
+            fbuilder.copy_properties(feature);
+            fbuilder.commit();
+        }
+    }
+
+    const std::string data = tbuilder.serialize();
+    REQUIRE(vector_tile_equal(buffer, data));
+}
+
+TEST_CASE("Copy tile using geometry_feature_builder and property_mapper") {
+    const auto buffer = load_test_tile();
+    vtzero::vector_tile tile{buffer};
+
+    vtzero::tile_builder tbuilder;
+
+    while (auto layer = tile.next_layer()) {
+        vtzero::layer_builder lbuilder{tbuilder, layer};
+        vtzero::property_mapper mapper{layer, lbuilder};
+        while (auto feature = layer.next_feature()) {
+            vtzero::geometry_feature_builder fbuilder{lbuilder};
+            fbuilder.copy_id(feature);
+            fbuilder.set_geometry(feature.geometry());
+            fbuilder.copy_properties(feature, mapper);
+            fbuilder.commit();
+        }
+    }
+
+    const std::string data = tbuilder.serialize();
+    REQUIRE(vector_tile_equal(buffer, data));
+}
+
+TEST_CASE("Copy only point geometries using geometry_feature_builder") {
+    const auto buffer = load_test_tile();
+    vtzero::vector_tile tile{buffer};
+
+    vtzero::tile_builder tbuilder;
+
+    int n = 0;
+    while (auto layer = tile.next_layer()) {
+        vtzero::layer_builder lbuilder{tbuilder, layer};
+        while (auto feature = layer.next_feature()) {
+            vtzero::geometry_feature_builder fbuilder{lbuilder};
+            fbuilder.set_id(feature.id());
+            if (feature.geometry().type() == vtzero::GeomType::POINT) {
+                fbuilder.set_geometry(feature.geometry());
+                while (auto property = feature.next_property()) {
+                    fbuilder.add_property(property.key(), property.value());
+                }
+                fbuilder.commit();
+                ++n;
+            } else {
+                fbuilder.rollback();
+            }
+        }
+    }
+    REQUIRE(n == 17);
+
+    const std::string data = tbuilder.serialize();
+
+    n = 0;
+    vtzero::vector_tile result_tile{data};
+    while (auto layer = result_tile.next_layer()) {
+        while (auto feature = layer.next_feature()) {
+            ++n;
+        }
+    }
+
+    REQUIRE(n == 17);
+}
+
+struct points_to_vector {
+
+    std::vector<vtzero::point> m_points{};
+
+    void points_begin(const uint32_t count) {
+        m_points.reserve(count);
+    }
+
+    void points_point(const vtzero::point point) {
+        m_points.push_back(point);
+    }
+
+    void points_end() const {
+    }
+
+    std::vector<vtzero::point> result() {
+        return m_points;
+    }
+
+}; // struct points_to_vector
+
+TEST_CASE("Copy only point geometries using point_feature_builder") {
+    const auto buffer = load_test_tile();
+    vtzero::vector_tile tile{buffer};
+
+    vtzero::tile_builder tbuilder;
+
+    int n = 0;
+    while (auto layer = tile.next_layer()) {
+        vtzero::layer_builder lbuilder{tbuilder, layer};
+        while (auto feature = layer.next_feature()) {
+            vtzero::point_feature_builder fbuilder{lbuilder};
+            fbuilder.copy_id(feature);
+            if (feature.geometry().type() == vtzero::GeomType::POINT) {
+                const auto points = decode_point_geometry(feature.geometry(), points_to_vector{});
+                fbuilder.add_points_from_container(points);
+                fbuilder.copy_properties(feature);
+                fbuilder.commit();
+                ++n;
+            } else {
+                fbuilder.rollback();
+            }
+        }
+    }
+    REQUIRE(n == 17);
+
+    const std::string data = tbuilder.serialize();
+
+    n = 0;
+    vtzero::vector_tile result_tile{data};
+    while (auto layer = result_tile.next_layer()) {
+        while (auto feature = layer.next_feature()) {
+            ++n;
+        }
+    }
+
+    REQUIRE(n == 17);
+}
+
+TEST_CASE("Copy only point geometries using point_feature_builder using property_mapper") {
+    const auto buffer = load_test_tile();
+    vtzero::vector_tile tile{buffer};
+
+    vtzero::tile_builder tbuilder;
+
+    int n = 0;
+    while (auto layer = tile.next_layer()) {
+        vtzero::layer_builder lbuilder{tbuilder, layer};
+        vtzero::property_mapper mapper{layer, lbuilder};
+        while (auto feature = layer.next_feature()) {
+            vtzero::point_feature_builder fbuilder{lbuilder};
+            fbuilder.copy_id(feature);
+            if (feature.geometry().type() == vtzero::GeomType::POINT) {
+                const auto points = decode_point_geometry(feature.geometry(), points_to_vector{});
+                fbuilder.add_points_from_container(points);
+                fbuilder.copy_properties(feature, mapper);
+                fbuilder.commit();
+                ++n;
+            } else {
+                fbuilder.rollback();
+            }
+        }
+    }
+    REQUIRE(n == 17);
+
+    const std::string data = tbuilder.serialize();
+
+    n = 0;
+    vtzero::vector_tile result_tile{data};
+    while (auto layer = result_tile.next_layer()) {
+        while (auto feature = layer.next_feature()) {
+            ++n;
+        }
+    }
+
+    REQUIRE(n == 17);
+}
+
+TEST_CASE("Build point feature from container with too many points") {
+
+    // fake container pretending to contain too many points
+    struct test_container {
+
+        std::size_t size() const noexcept {
+            return 1ul << 29u;
+        }
+
+        vtzero::point* begin() const noexcept {
+            return nullptr;
+        }
+
+        vtzero::point* end() const noexcept {
+            return nullptr;
+        }
+
+    };
+
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::point_feature_builder fbuilder{lbuilder};
+
+    fbuilder.set_id(1);
+
+    test_container tc;
+    REQUIRE_THROWS_AS(fbuilder.add_points_from_container(tc), const vtzero::geometry_exception&);
+}
+
+TEST_CASE("Moving a feature builder is allowed") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::point_feature_builder fbuilder{lbuilder};
+
+    auto fbuilder2 = std::move(fbuilder);
+    vtzero::point_feature_builder fbuilder3{std::move(fbuilder2)};
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_linestring.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_linestring.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_linestring.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,312 @@
+
+#include <test.hpp>
+
+#include <vtzero/builder.hpp>
+#include <vtzero/geometry.hpp>
+#include <vtzero/index.hpp>
+
+#include <cstdint>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+using ls_type = std::vector<std::vector<vtzero::point>>;
+
+struct linestring_handler {
+
+    ls_type data;
+
+    void linestring_begin(uint32_t count) {
+        data.emplace_back();
+        data.back().reserve(count);
+    }
+
+    void linestring_point(const vtzero::point point) {
+        data.back().push_back(point);
+    }
+
+    void linestring_end() const noexcept {
+    }
+
+};
+
+static void test_linestring_builder(bool with_id, bool with_prop) {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    {
+        vtzero::linestring_feature_builder fbuilder{lbuilder};
+
+        if (with_id) {
+            fbuilder.set_id(17);
+        }
+
+        fbuilder.add_linestring(3);
+        fbuilder.set_point(10, 20);
+        fbuilder.set_point(vtzero::point{20, 30});
+        fbuilder.set_point(mypoint{30, 40});
+
+        if (with_prop) {
+            fbuilder.add_property("foo", "bar");
+        }
+
+        fbuilder.commit();
+    }
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.name() == "test");
+    REQUIRE(layer.version() == 2);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+    REQUIRE(feature.id() == (with_id ? 17 : 0));
+
+    linestring_handler handler;
+    vtzero::decode_linestring_geometry(feature.geometry(), handler);
+
+    const ls_type result = {{{10, 20}, {20, 30}, {30, 40}}};
+    REQUIRE(handler.data == result);
+}
+
+TEST_CASE("linestring builder without id/without properties") {
+    test_linestring_builder(false, false);
+}
+
+TEST_CASE("linestring builder without id/with properties") {
+    test_linestring_builder(false, true);
+}
+
+TEST_CASE("linestring builder with id/without properties") {
+    test_linestring_builder(true, false);
+}
+
+TEST_CASE("linestring builder with id/with properties") {
+    test_linestring_builder(true, true);
+}
+
+TEST_CASE("Calling add_linestring() with bad values throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::linestring_feature_builder fbuilder{lbuilder};
+
+    SECTION("0") {
+        REQUIRE_THROWS_AS(fbuilder.add_linestring(0), const assert_error&);
+    }
+    SECTION("1") {
+        REQUIRE_THROWS_AS(fbuilder.add_linestring(1), const assert_error&);
+    }
+    SECTION("2^29") {
+        REQUIRE_THROWS_AS(fbuilder.add_linestring(1ul << 29u), const assert_error&);
+    }
+}
+
+static void test_multilinestring_builder(bool with_id, bool with_prop) {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::linestring_feature_builder fbuilder{lbuilder};
+
+    if (with_id) {
+        fbuilder.set_id(17);
+    }
+
+    fbuilder.add_linestring(3);
+    fbuilder.set_point(10, 20);
+    fbuilder.set_point(vtzero::point{20, 30});
+    fbuilder.set_point(mypoint{30, 40});
+
+    fbuilder.add_linestring(2);
+    fbuilder.set_point(1, 2);
+    fbuilder.set_point(2, 1);
+
+    if (with_prop) {
+        fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
+    }
+
+    fbuilder.commit();
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.name() == "test");
+    REQUIRE(layer.version() == 2);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+    REQUIRE(feature.id() == (with_id ? 17 : 0));
+
+    linestring_handler handler;
+    vtzero::decode_linestring_geometry(feature.geometry(), handler);
+
+    const ls_type result = {{{10, 20}, {20, 30}, {30, 40}}, {{1, 2}, {2, 1}}};
+    REQUIRE(handler.data == result);
+}
+
+
+TEST_CASE("Multilinestring builder without id/without properties") {
+    test_multilinestring_builder(false, false);
+}
+
+TEST_CASE("Multilinestring builder without id/with properties") {
+    test_multilinestring_builder(false, true);
+}
+
+TEST_CASE("Multilinestring builder with id/without properties") {
+    test_multilinestring_builder(true, false);
+}
+
+TEST_CASE("Multilinestring builder with id/with properties") {
+    test_multilinestring_builder(true, true);
+}
+
+TEST_CASE("Calling add_linestring() twice throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::linestring_feature_builder fbuilder{lbuilder};
+
+    fbuilder.add_linestring(3);
+    REQUIRE_ASSERT(fbuilder.add_linestring(2));
+}
+
+TEST_CASE("Calling linestring_feature_builder::set_point() throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::linestring_feature_builder fbuilder{lbuilder};
+
+    REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const assert_error&);
+}
+
+TEST_CASE("Calling linestring_feature_builder::set_point() with same point throws") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::linestring_feature_builder fbuilder{lbuilder};
+
+    fbuilder.add_linestring(2);
+    fbuilder.set_point(10, 10);
+    REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const vtzero::geometry_exception&);
+}
+
+TEST_CASE("Calling linestring_feature_builder::set_point() too often throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::linestring_feature_builder fbuilder{lbuilder};
+
+    fbuilder.add_linestring(2);
+    fbuilder.set_point(10, 20);
+    fbuilder.set_point(20, 20);
+    REQUIRE_THROWS_AS(fbuilder.set_point(30, 20), const assert_error&);
+}
+
+TEST_CASE("Add linestring from container") {
+    const ls_type points = {{{10, 20}, {20, 30}, {30, 40}}};
+
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    {
+        vtzero::linestring_feature_builder fbuilder{lbuilder};
+
+#if 0
+        SECTION("using iterators") {
+            fbuilder.add_linestring(points[0].cbegin(), points[0].cend());
+        }
+
+        SECTION("using iterators and size") {
+            fbuilder.add_linestring(points[0].cbegin(), points[0].cend(), static_cast<uint32_t>(points[0].size()));
+        }
+#endif
+
+        SECTION("using container directly") {
+            fbuilder.add_linestring_from_container(points[0]);
+        }
+
+        fbuilder.commit();
+    }
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer);
+    REQUIRE(layer.name() == "test");
+    REQUIRE(layer.version() == 2);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+
+    linestring_handler handler;
+    vtzero::decode_linestring_geometry(feature.geometry(), handler);
+
+    REQUIRE(handler.data == points);
+}
+
+#if 0
+TEST_CASE("Add linestring from iterator with wrong count throws assert") {
+    const std::vector<vtzero::point> points = {{10, 20}, {20, 30}, {30, 40}};
+
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::linestring_feature_builder fbuilder{lbuilder};
+
+    REQUIRE_THROWS_AS(fbuilder.add_linestring(points.cbegin(),
+                                              points.cend(),
+                                              static_cast<uint32_t>(points.size() + 1)), const assert_error&);
+}
+#endif
+
+TEST_CASE("Adding several linestrings with feature rollback in the middle") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    {
+        vtzero::linestring_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(1);
+        fbuilder.add_linestring(2);
+        fbuilder.set_point(10, 10);
+        fbuilder.set_point(20, 20);
+        fbuilder.commit();
+    }
+
+    try {
+        vtzero::linestring_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(2);
+        fbuilder.add_linestring(2);
+        fbuilder.set_point(10, 10);
+        fbuilder.set_point(10, 10);
+        fbuilder.commit();
+    } catch (vtzero::geometry_exception&) {
+    }
+
+    {
+        vtzero::linestring_feature_builder fbuilder{lbuilder};
+        fbuilder.set_id(3);
+        fbuilder.add_linestring(2);
+        fbuilder.set_point(10, 20);
+        fbuilder.set_point(20, 10);
+        fbuilder.commit();
+    }
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer);
+    REQUIRE(layer.name() == "test");
+    REQUIRE(layer.num_features() == 2);
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.id() == 1);
+    feature = layer.next_feature();
+    REQUIRE(feature.id() == 3);
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_point.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_point.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_point.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,279 @@
+
+#include <test.hpp>
+
+#include <vtzero/builder.hpp>
+#include <vtzero/geometry.hpp>
+#include <vtzero/index.hpp>
+
+#include <cstdint>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+struct point_handler {
+
+    std::vector<vtzero::point> data;
+
+    void points_begin(uint32_t count) {
+        data.reserve(count);
+    }
+
+    void points_point(const vtzero::point point) {
+        data.push_back(point);
+    }
+
+    void points_end() const noexcept {
+    }
+
+};
+
+static void test_point_builder(bool with_id, bool with_prop) {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    {
+        vtzero::point_feature_builder fbuilder{lbuilder};
+
+        if (with_id) {
+            fbuilder.set_id(17);
+        }
+
+        SECTION("add point using coordinates / property using key/value") {
+            fbuilder.add_point(10, 20);
+            if (with_prop) {
+                fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
+            }
+        }
+
+        SECTION("add point using vtzero::point / property using key/value") {
+            fbuilder.add_point(vtzero::point{10, 20});
+            if (with_prop) {
+                fbuilder.add_property("foo", vtzero::encoded_property_value{22});
+            }
+        }
+
+        SECTION("add point using mypoint / property using property") {
+            vtzero::encoded_property_value pv{3.5};
+            vtzero::property p{"foo", vtzero::property_value{pv.data()}};
+            fbuilder.add_point(mypoint{10, 20});
+            if (with_prop) {
+                fbuilder.add_property(p);
+            }
+        }
+
+        fbuilder.commit();
+    }
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.name() == "test");
+    REQUIRE(layer.version() == 2);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+    REQUIRE(feature.id() == (with_id ? 17 : 0));
+
+    point_handler handler;
+    vtzero::decode_point_geometry(feature.geometry(), handler);
+
+    const std::vector<vtzero::point> result = {{10, 20}};
+    REQUIRE(handler.data == result);
+}
+
+TEST_CASE("Point builder without id/without properties") {
+    test_point_builder(false, false);
+}
+
+TEST_CASE("Point builder without id/with properties") {
+    test_point_builder(false, true);
+}
+
+TEST_CASE("Point builder with id/without properties") {
+    test_point_builder(true, false);
+}
+
+TEST_CASE("Point builder with id/with properties") {
+    test_point_builder(true, true);
+}
+
+TEST_CASE("Calling add_points() with bad values throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::point_feature_builder fbuilder{lbuilder};
+
+    SECTION("0") {
+        REQUIRE_THROWS_AS(fbuilder.add_points(0), const assert_error&);
+    }
+    SECTION("2^29") {
+        REQUIRE_THROWS_AS(fbuilder.add_points(1ul << 29u), const assert_error&);
+    }
+}
+
+static void test_multipoint_builder(bool with_id, bool with_prop) {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::point_feature_builder fbuilder{lbuilder};
+
+    if (with_id) {
+        fbuilder.set_id(17);
+    }
+
+    fbuilder.add_points(3);
+    fbuilder.set_point(10, 20);
+    fbuilder.set_point(vtzero::point{20, 30});
+    fbuilder.set_point(mypoint{30, 40});
+
+    if (with_prop) {
+        fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
+    }
+
+    fbuilder.commit();
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.name() == "test");
+    REQUIRE(layer.version() == 2);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+    REQUIRE(feature.id() == (with_id ? 17 : 0));
+
+    point_handler handler;
+    vtzero::decode_point_geometry(feature.geometry(), handler);
+
+    const std::vector<vtzero::point> result = {{10, 20}, {20, 30}, {30, 40}};
+    REQUIRE(handler.data == result);
+}
+
+
+TEST_CASE("Multipoint builder without id/without properties") {
+    test_multipoint_builder(false, false);
+}
+
+TEST_CASE("Multipoint builder without id/with properties") {
+    test_multipoint_builder(false, true);
+}
+
+TEST_CASE("Multipoint builder with id/without properties") {
+    test_multipoint_builder(true, false);
+}
+
+TEST_CASE("Multipoint builder with id/with properties") {
+    test_multipoint_builder(true, true);
+}
+
+TEST_CASE("Calling add_point() and then other geometry functions throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::point_feature_builder fbuilder{lbuilder};
+
+    fbuilder.add_point(10, 20);
+
+    SECTION("add_point()") {
+        REQUIRE_THROWS_AS(fbuilder.add_point(10, 20), const assert_error&);
+    }
+    SECTION("add_points()") {
+        REQUIRE_THROWS_AS(fbuilder.add_points(2), const assert_error&);
+    }
+    SECTION("set_point()") {
+        REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const assert_error&);
+    }
+}
+
+TEST_CASE("Calling point_feature_builder::set_point() throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::point_feature_builder fbuilder{lbuilder};
+
+    REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const assert_error&);
+}
+
+TEST_CASE("Calling add_points() and then other geometry functions throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::point_feature_builder fbuilder{lbuilder};
+
+    fbuilder.add_points(2);
+
+    SECTION("add_point()") {
+        REQUIRE_THROWS_AS(fbuilder.add_point(10, 20), const assert_error&);
+    }
+    SECTION("add_points()") {
+        REQUIRE_THROWS_AS(fbuilder.add_points(2), const assert_error&);
+    }
+}
+
+TEST_CASE("Calling point_feature_builder::set_point() too often throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::point_feature_builder fbuilder{lbuilder};
+
+    fbuilder.add_points(2);
+    fbuilder.set_point(10, 20);
+    fbuilder.set_point(20, 20);
+    REQUIRE_THROWS_AS(fbuilder.set_point(30, 20), const assert_error&);
+}
+
+TEST_CASE("Add points from container") {
+    const std::vector<vtzero::point> points = {{10, 20}, {20, 30}, {30, 40}};
+
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    {
+        vtzero::point_feature_builder fbuilder{lbuilder};
+
+/*        SECTION("using iterators") {
+            fbuilder.add_points(points.cbegin(), points.cend());
+        }
+
+        SECTION("using iterators and size") {
+            fbuilder.add_points(points.cbegin(), points.cend(), static_cast<uint32_t>(points.size()));
+        }*/
+
+        SECTION("using container directly") {
+            fbuilder.add_points_from_container(points);
+        }
+
+        fbuilder.commit();
+    }
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer);
+    REQUIRE(layer.name() == "test");
+    REQUIRE(layer.version() == 2);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+
+    point_handler handler;
+    vtzero::decode_point_geometry(feature.geometry(), handler);
+
+    REQUIRE(handler.data == points);
+}
+/*
+TEST_CASE("Add points from iterator with wrong count throws assert") {
+    const std::vector<vtzero::point> points = {{10, 20}, {20, 30}, {30, 40}};
+
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::point_feature_builder fbuilder{lbuilder};
+
+    REQUIRE_THROWS_AS(fbuilder.add_points(points.cbegin(),
+                                          points.cend(),
+                                          static_cast<uint32_t>(points.size() + 1)), const assert_error&);
+}*/
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_polygon.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_polygon.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_builder_polygon.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,307 @@
+
+#include <test.hpp>
+
+#include <vtzero/builder.hpp>
+#include <vtzero/geometry.hpp>
+#include <vtzero/index.hpp>
+
+#include <cstdint>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+using polygon_type = std::vector<std::vector<vtzero::point>>;
+
+struct polygon_handler {
+
+    polygon_type data;
+
+    void ring_begin(uint32_t count) {
+        data.emplace_back();
+        data.back().reserve(count);
+    }
+
+    void ring_point(const vtzero::point point) {
+        data.back().push_back(point);
+    }
+
+    void ring_end(vtzero::ring_type /* type */) const noexcept {
+    }
+
+};
+
+static void test_polygon_builder(bool with_id, bool with_prop) {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    {
+        vtzero::polygon_feature_builder fbuilder{lbuilder};
+
+        if (with_id) {
+            fbuilder.set_id(17);
+        }
+
+        fbuilder.add_ring(4);
+        fbuilder.set_point(10, 20);
+        fbuilder.set_point(vtzero::point{20, 30});
+        fbuilder.set_point(mypoint{30, 40});
+        fbuilder.set_point(10, 20);
+
+        if (with_prop) {
+            fbuilder.add_property("foo", "bar");
+        }
+
+        fbuilder.commit();
+    }
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.name() == "test");
+    REQUIRE(layer.version() == 2);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+    REQUIRE(feature.id() == (with_id ? 17 : 0));
+
+    polygon_handler handler;
+    vtzero::decode_polygon_geometry(feature.geometry(), handler);
+
+    const polygon_type result = {{{10, 20}, {20, 30}, {30, 40}, {10, 20}}};
+    REQUIRE(handler.data == result);
+}
+
+TEST_CASE("polygon builder without id/without properties") {
+    test_polygon_builder(false, false);
+}
+
+TEST_CASE("polygon builder without id/with properties") {
+    test_polygon_builder(false, true);
+}
+
+TEST_CASE("polygon builder with id/without properties") {
+    test_polygon_builder(true, false);
+}
+
+TEST_CASE("polygon builder with id/with properties") {
+    test_polygon_builder(true, true);
+}
+
+TEST_CASE("Calling add_ring() with bad values throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::polygon_feature_builder fbuilder{lbuilder};
+
+    SECTION("0") {
+        REQUIRE_THROWS_AS(fbuilder.add_ring(0), const assert_error&);
+    }
+    SECTION("1") {
+        REQUIRE_THROWS_AS(fbuilder.add_ring(1), const assert_error&);
+    }
+    SECTION("2") {
+        REQUIRE_THROWS_AS(fbuilder.add_ring(2), const assert_error&);
+    }
+    SECTION("3") {
+        REQUIRE_THROWS_AS(fbuilder.add_ring(3), const assert_error&);
+    }
+    SECTION("2^29") {
+        REQUIRE_THROWS_AS(fbuilder.add_ring(1ul << 29u), const assert_error&);
+    }
+}
+
+static void test_multipolygon_builder(bool with_id, bool with_prop) {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::polygon_feature_builder fbuilder{lbuilder};
+
+    if (with_id) {
+        fbuilder.set_id(17);
+    }
+
+    fbuilder.add_ring(4);
+    fbuilder.set_point(10, 20);
+    fbuilder.set_point(vtzero::point{20, 30});
+    fbuilder.set_point(mypoint{30, 40});
+    fbuilder.set_point(10, 20);
+
+    fbuilder.add_ring(5);
+    fbuilder.set_point(1, 1);
+    fbuilder.set_point(2, 1);
+    fbuilder.set_point(2, 2);
+    fbuilder.set_point(1, 2);
+
+    if (with_id) {
+        fbuilder.set_point(1, 1);
+    } else {
+        fbuilder.close_ring();
+    }
+
+    if (with_prop) {
+        fbuilder.add_property("foo", vtzero::encoded_property_value{"bar"});
+    }
+
+    fbuilder.commit();
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer.name() == "test");
+    REQUIRE(layer.version() == 2);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+    REQUIRE(feature.id() == (with_id ? 17 : 0));
+
+    polygon_handler handler;
+    vtzero::decode_polygon_geometry(feature.geometry(), handler);
+
+    const polygon_type result = {{{10, 20}, {20, 30}, {30, 40}, {10, 20}},
+                                 {{1, 1}, {2, 1}, {2, 2}, {1, 2}, {1, 1}}};
+    REQUIRE(handler.data == result);
+}
+
+
+TEST_CASE("Multipolygon builder without id/without properties") {
+    test_multipolygon_builder(false, false);
+}
+
+TEST_CASE("Multipolygon builder without id/with properties") {
+    test_multipolygon_builder(false, true);
+}
+
+TEST_CASE("Multipolygon builder with id/without properties") {
+    test_multipolygon_builder(true, false);
+}
+
+TEST_CASE("Multipolygon builder with id/with properties") {
+    test_multipolygon_builder(true, true);
+}
+
+TEST_CASE("Calling add_ring() twice throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::polygon_feature_builder fbuilder{lbuilder};
+
+    fbuilder.add_ring(4);
+    REQUIRE_ASSERT(fbuilder.add_ring(4));
+}
+
+TEST_CASE("Calling polygon_feature_builder::set_point()/close_ring() throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::polygon_feature_builder fbuilder{lbuilder};
+
+    SECTION("set_point") {
+        REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const assert_error&);
+    }
+    SECTION("close_ring") {
+        REQUIRE_THROWS_AS(fbuilder.close_ring(), const assert_error&);
+    }
+}
+
+TEST_CASE("Calling polygon_feature_builder::set_point()/close_ring() too often throws assert") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::polygon_feature_builder fbuilder{lbuilder};
+
+    fbuilder.add_ring(4);
+    fbuilder.set_point(10, 20);
+    fbuilder.set_point(20, 20);
+    fbuilder.set_point(30, 20);
+    fbuilder.set_point(10, 20);
+
+    SECTION("set_point") {
+        REQUIRE_THROWS_AS(fbuilder.set_point(50, 20), const assert_error&);
+    }
+    SECTION("close_ring") {
+        REQUIRE_THROWS_AS(fbuilder.close_ring(), const assert_error&);
+    }
+}
+
+TEST_CASE("Calling polygon_feature_builder::set_point() with same point throws") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::polygon_feature_builder fbuilder{lbuilder};
+
+    fbuilder.add_ring(4);
+    fbuilder.set_point(10, 10);
+    REQUIRE_THROWS_AS(fbuilder.set_point(10, 10), const vtzero::geometry_exception&);
+}
+
+TEST_CASE("Calling polygon_feature_builder::set_point() creating unclosed ring throws") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::polygon_feature_builder fbuilder{lbuilder};
+
+    fbuilder.add_ring(4);
+    fbuilder.set_point(10, 10);
+    fbuilder.set_point(10, 20);
+    fbuilder.set_point(20, 20);
+    REQUIRE_THROWS_AS(fbuilder.set_point(20, 30), const vtzero::geometry_exception&);
+}
+
+TEST_CASE("Add polygon from container") {
+    const polygon_type points = {{{10, 20}, {20, 30}, {30, 40}, {10, 20}}};
+
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    {
+        vtzero::polygon_feature_builder fbuilder{lbuilder};
+
+#if 0
+        SECTION("using iterators") {
+            fbuilder.add_ring(points[0].cbegin(), points[0].cend());
+        }
+
+        SECTION("using iterators and size") {
+            fbuilder.add_ring(points[0].cbegin(), points[0].cend(), static_cast<uint32_t>(points[0].size()));
+        }
+#endif
+
+        SECTION("using container directly") {
+            fbuilder.add_ring_from_container(points[0]);
+        }
+
+        fbuilder.commit();
+    }
+
+    const std::string data = tbuilder.serialize();
+
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.next_layer();
+    REQUIRE(layer);
+    REQUIRE(layer.name() == "test");
+    REQUIRE(layer.version() == 2);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+
+    polygon_handler handler;
+    vtzero::decode_polygon_geometry(feature.geometry(), handler);
+
+    REQUIRE(handler.data == points);
+}
+
+#if 0
+TEST_CASE("Add polygon from iterator with wrong count throws assert") {
+    const std::vector<vtzero::point> points = {{10, 20}, {20, 30}, {30, 40}, {10, 20}};
+
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::polygon_feature_builder fbuilder{lbuilder};
+
+    REQUIRE_THROWS_AS(fbuilder.add_ring(points.cbegin(),
+                                        points.cend(),
+                                        static_cast<uint32_t>(points.size() + 1)), const assert_error&);
+}
+#endif
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_exceptions.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_exceptions.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_exceptions.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,42 @@
+
+#include <test.hpp>
+
+#include <vtzero/exception.hpp>
+
+#include <string>
+
+TEST_CASE("construct format_exception with const char*") {
+    vtzero::format_exception e{"broken"};
+    REQUIRE(std::string{e.what()} == "broken");
+}
+
+TEST_CASE("construct format_exception with const std::string") {
+    vtzero::format_exception e{std::string{"broken"}};
+    REQUIRE(std::string{e.what()} == "broken");
+}
+
+TEST_CASE("construct geometry_exception with const char*") {
+    vtzero::geometry_exception e{"broken"};
+    REQUIRE(std::string{e.what()} == "broken");
+}
+
+TEST_CASE("construct geometry_exception with std::string") {
+    vtzero::geometry_exception e{std::string{"broken"}};
+    REQUIRE(std::string{e.what()} == "broken");
+}
+
+TEST_CASE("construct type_exception") {
+    vtzero::type_exception e;
+    REQUIRE(std::string{e.what()} == "wrong property value type");
+}
+
+TEST_CASE("construct version_exception") {
+    vtzero::version_exception e{42};
+    REQUIRE(std::string{e.what()} == "unknown vector tile version: 42");
+}
+
+TEST_CASE("construct out_of_range_exception") {
+    vtzero::out_of_range_exception e{99};
+    REQUIRE(std::string{e.what()} == "index out of range: 99");
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_feature.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_feature.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_feature.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,97 @@
+
+#include <test.hpp>
+
+#include <vtzero/feature.hpp>
+#include <vtzero/layer.hpp>
+#include <vtzero/vector_tile.hpp>
+
+TEST_CASE("default constructed feature") {
+    vtzero::feature feature{};
+
+    REQUIRE_FALSE(feature.valid());
+    REQUIRE_FALSE(feature);
+    REQUIRE(feature.id() == 0);
+    REQUIRE_FALSE(feature.has_id());
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::UNKNOWN);
+    REQUIRE_ASSERT(feature.geometry());
+    REQUIRE(feature.empty());
+    REQUIRE(feature.num_properties() == 0);
+}
+
+TEST_CASE("read a feature") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.get_layer_by_name("bridge");
+    REQUIRE(layer.valid());
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.valid());
+    REQUIRE(feature);
+    REQUIRE(feature.id() == 0);
+    REQUIRE(feature.has_id());
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::LINESTRING);
+    REQUIRE_FALSE(feature.empty());
+    REQUIRE(feature.num_properties() == 4);
+}
+
+TEST_CASE("iterate over all properties of a feature") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data};
+    auto layer = tile.get_layer_by_name("bridge");
+    auto feature = layer.next_feature();
+
+    int count = 0;
+    SECTION("external iterator") {
+        while (auto p = feature.next_property()) {
+            ++count;
+            if (p.key() == "type") {
+                REQUIRE(p.value().type() == vtzero::property_value_type::string_value);
+                REQUIRE(p.value().string_value() == "primary");
+            }
+        }
+    }
+
+    SECTION("internal iterator") {
+        feature.for_each_property([&count](const vtzero::property& p) {
+            ++count;
+            if (p.key() == "type") {
+                REQUIRE(p.value().type() == vtzero::property_value_type::string_value);
+                REQUIRE(p.value().string_value() == "primary");
+            }
+            return true;
+        });
+    }
+
+    REQUIRE(count == 4);
+}
+
+TEST_CASE("iterate over some properties of a feature") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data};
+    auto layer = tile.get_layer_by_name("bridge");
+    REQUIRE(layer.valid());
+
+    auto feature = layer.next_feature();
+    REQUIRE(feature.valid());
+
+    int count = 0;
+    SECTION("external iterator") {
+        while (auto p = feature.next_property()) {
+            ++count;
+            if (p.key() == "oneway") {
+                break;
+            }
+        }
+    }
+
+    SECTION("internal iterator") {
+        feature.for_each_property([&count](const vtzero::property& p) {
+            ++count;
+            return p.key() != "oneway";
+        });
+    }
+
+    REQUIRE(count == 2);
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,334 @@
+
+#include <test.hpp>
+
+#include <vtzero/geometry.hpp>
+
+#include <cstdint>
+#include <limits>
+#include <vector>
+
+using container = std::vector<uint32_t>;
+using iterator = container::const_iterator;
+
+TEST_CASE("geometry_decoder") {
+    const container g = {};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+
+    REQUIRE(decoder.count() == 0);
+    REQUIRE(decoder.done());
+    REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE_THROWS_AS(decoder.next_point(), const assert_error&);
+}
+
+TEST_CASE("geometry_decoder with point") {
+    const container g = {9, 50, 34};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE_THROWS_AS(decoder.next_point(), const assert_error&);
+
+    SECTION("trying to get LineTo command") {
+        REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::LINE_TO), const vtzero::geometry_exception&);
+    }
+
+    SECTION("trying to get ClosePath command") {
+        REQUIRE_THROWS_WITH(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH), "expected command 7 but got 1");
+    }
+
+    SECTION("trying to get MoveTo command") {
+        REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+        REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::MOVE_TO), const assert_error&);
+        REQUIRE(decoder.count() == 1);
+        REQUIRE(decoder.next_point() == vtzero::point(25, 17));
+
+        REQUIRE(decoder.done());
+        REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    }
+}
+
+TEST_CASE("geometry_decoder with incomplete point") {
+    container g = {9, 50, 34};
+
+    SECTION("half a point") {
+        g.pop_back();
+    }
+
+    SECTION("missing point") {
+        g.pop_back();
+        g.pop_back();
+    }
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), 100};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE_THROWS_AS(decoder.next_point(), const vtzero::geometry_exception&);
+}
+
+TEST_CASE("geometry_decoder with multipoint") {
+    const container g = {17, 10, 14, 3, 9};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 2);
+    REQUIRE(decoder.next_point() == vtzero::point(5, 7));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(3, 2));
+    REQUIRE(decoder.count() == 0);
+
+    REQUIRE(decoder.done());
+    REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+}
+
+TEST_CASE("geometry_decoder with linestring") {
+    const container g = {9, 4, 4, 18, 0, 16, 16, 0};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(2, 2));
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.count() == 2);
+    REQUIRE(decoder.next_point() == vtzero::point(2, 10));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(10, 10));
+    REQUIRE(decoder.count() == 0);
+
+    REQUIRE(decoder.done());
+    REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+}
+
+TEST_CASE("geometry_decoder with linestring with equal points") {
+    const container g = {9, 4, 4, 18, 0, 16, 0, 0};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(2, 2));
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.count() == 2);
+    REQUIRE(decoder.next_point() == vtzero::point(2, 10));
+    REQUIRE(decoder.count() == 1);
+
+    REQUIRE(decoder.next_point() == vtzero::point(2, 10));
+    REQUIRE(decoder.count() == 0);
+
+    REQUIRE(decoder.done());
+}
+
+TEST_CASE("geometry_decoder with multilinestring") {
+    const container g = {9, 4, 4, 18, 0, 16, 16, 0, 9, 17, 17, 10, 4, 8};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(2, 2));
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.count() == 2);
+    REQUIRE(decoder.next_point() == vtzero::point(2, 10));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(10, 10));
+    REQUIRE(decoder.count() == 0);
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(1, 1));
+    REQUIRE(decoder.count() == 0);
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(3, 5));
+    REQUIRE(decoder.count() == 0);
+
+    REQUIRE(decoder.done());
+    REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+}
+
+TEST_CASE("geometry_decoder with polygon") {
+    const container g = {9, 6, 12, 18, 10, 12, 24, 44, 15};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(3, 6));
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.count() == 2);
+    REQUIRE(decoder.next_point() == vtzero::point(8, 12));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(20, 34));
+    REQUIRE(decoder.count() == 0);
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH));
+    REQUIRE(decoder.count() == 0);
+
+    REQUIRE(decoder.done());
+    REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+}
+
+TEST_CASE("geometry_decoder with polygon with wrong ClosePath count 2") {
+    const container g = {9, 6, 12, 18, 10, 12, 24, 44, 23};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.next_point() == vtzero::point(3, 6));
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.next_point() == vtzero::point(8, 12));
+    REQUIRE(decoder.next_point() == vtzero::point(20, 34));
+    REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH), const vtzero::geometry_exception&);
+    REQUIRE_THROWS_WITH(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH), "ClosePath command count is not 1");
+}
+
+TEST_CASE("geometry_decoder with polygon with wrong ClosePath count 0") {
+    const container g = {9, 6, 12, 18, 10, 12, 24, 44, 7};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.next_point() == vtzero::point(3, 6));
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.next_point() == vtzero::point(8, 12));
+    REQUIRE(decoder.next_point() == vtzero::point(20, 34));
+    REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH), const vtzero::geometry_exception&);
+    REQUIRE_THROWS_WITH(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH), "ClosePath command count is not 1");
+}
+
+TEST_CASE("geometry_decoder with multipolygon") {
+    const container g = {9, 0, 0, 26, 20, 0, 0, 20, 19, 0, 15, 9, 22, 2, 26, 18,
+                         0, 0, 18, 17, 0, 15, 9, 4, 13, 26, 0, 8, 8, 0, 0, 7, 15};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(0, 0));
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.count() == 3);
+    REQUIRE(decoder.next_point() == vtzero::point(10, 0));
+    REQUIRE(decoder.count() == 2);
+    REQUIRE(decoder.next_point() == vtzero::point(10, 10));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(0, 10));
+    REQUIRE(decoder.count() == 0);
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH));
+    REQUIRE(decoder.count() == 0);
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(11, 11));
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.count() == 3);
+    REQUIRE(decoder.next_point() == vtzero::point(20, 11));
+    REQUIRE(decoder.count() == 2);
+    REQUIRE(decoder.next_point() == vtzero::point(20, 20));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(11, 20));
+    REQUIRE(decoder.count() == 0);
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH));
+    REQUIRE(decoder.count() == 0);
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(13, 13));
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.count() == 3);
+    REQUIRE(decoder.next_point() == vtzero::point(13, 17));
+    REQUIRE(decoder.count() == 2);
+    REQUIRE(decoder.next_point() == vtzero::point(17, 17));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(17, 13));
+    REQUIRE(decoder.count() == 0);
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::CLOSE_PATH));
+    REQUIRE(decoder.count() == 0);
+
+    REQUIRE(decoder.done());
+    REQUIRE_FALSE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+}
+
+TEST_CASE("geometry_decoder decoding linestring with int32 overflow in x coordinate") {
+    const container g = {vtzero::detail::command_move_to(1),
+                           protozero::encode_zigzag32(std::numeric_limits<int32_t>::max()),
+                           protozero::encode_zigzag32(0),
+                         vtzero::detail::command_line_to(1),
+                           protozero::encode_zigzag32(1),
+                           protozero::encode_zigzag32(1)
+                         };
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(std::numeric_limits<int32_t>::max(), 0));
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(std::numeric_limits<int32_t>::min(), 1));
+}
+
+TEST_CASE("geometry_decoder decoding linestring with int32 overflow in y coordinate") {
+    const container g = {vtzero::detail::command_move_to(1),
+                           protozero::encode_zigzag32(0),
+                           protozero::encode_zigzag32(std::numeric_limits<int32_t>::min()),
+                         vtzero::detail::command_line_to(1),
+                           protozero::encode_zigzag32(-1),
+                           protozero::encode_zigzag32(-1)
+                         };
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::MOVE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(0, std::numeric_limits<int32_t>::min()));
+    REQUIRE(decoder.next_command(vtzero::detail::CommandId::LINE_TO));
+    REQUIRE(decoder.count() == 1);
+    REQUIRE(decoder.next_point() == vtzero::point(-1, std::numeric_limits<int32_t>::max()));
+}
+
+TEST_CASE("geometry_decoder with multipoint with a huge count") {
+    const uint32_t huge_value = (1ul << 29u) - 1;
+    const container g = {vtzero::detail::command_move_to(huge_value), 10, 10};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), g.size() / 2};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::MOVE_TO), const vtzero::geometry_exception&);
+}
+
+TEST_CASE("geometry_decoder with multipoint with not enough points") {
+    const container g = {vtzero::detail::command_move_to(2), 10};
+
+    vtzero::detail::geometry_decoder<iterator> decoder{g.cbegin(), g.cend(), 1};
+    REQUIRE(decoder.count() == 0);
+    REQUIRE_FALSE(decoder.done());
+
+    REQUIRE_THROWS_AS(decoder.next_command(vtzero::detail::CommandId::MOVE_TO), const vtzero::geometry_exception&);
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_linestring.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_linestring.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_linestring.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,160 @@
+
+#include <test.hpp>
+
+#include <vtzero/geometry.hpp>
+
+#include <cstdint>
+#include <vector>
+
+using container = std::vector<uint32_t>;
+using iterator = container::const_iterator;
+
+class dummy_geom_handler {
+
+    int value = 0;
+
+public:
+
+    void linestring_begin(const uint32_t /*count*/) noexcept {
+        ++value;
+    }
+
+    void linestring_point(const vtzero::point /*point*/) noexcept {
+        value += 100;
+    }
+
+    void linestring_end() noexcept {
+        value += 10000;
+    }
+
+    int result() const noexcept {
+        return value;
+    }
+
+}; // class dummy_geom_handler
+
+TEST_CASE("Calling decode_linestring_geometry() with empty input") {
+    const container g;
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    dummy_geom_handler handler;
+    decoder.decode_linestring(dummy_geom_handler{});
+    REQUIRE(handler.result() == 0);
+}
+
+TEST_CASE("Calling decode_linestring_geometry() with a valid linestring") {
+    const container g = {9, 4, 4, 18, 0, 16, 16, 0};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    REQUIRE(decoder.decode_linestring(dummy_geom_handler{}) == 10301);
+}
+
+TEST_CASE("Calling decode_linestring_geometry() with a valid multilinestring") {
+    const container g = {9, 4, 4, 18, 0, 16, 16, 0, 9, 17, 17, 10, 4, 8};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    dummy_geom_handler handler;
+    decoder.decode_linestring(handler);
+    REQUIRE(handler.result() == 20502);
+}
+
+TEST_CASE("Calling decode_linestring_geometry() with a point geometry fails") {
+    const container g = {9, 50, 34}; // this is a point geometry
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
+                            "expected LineTo command (spec 4.3.4.3)");
+    }
+}
+
+TEST_CASE("Calling decode_linestring_geometry() with a polygon geometry fails") {
+    const container g = {9, 6, 12, 18, 10, 12, 24, 44, 15}; // this is a polygon geometry
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
+                            "expected command 1 but got 7");
+    }
+}
+
+TEST_CASE("Calling decode_linestring_geometry() with something other than MoveTo command") {
+    const container g = {vtzero::detail::command_line_to(3)};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
+                            "expected command 1 but got 2");
+    }
+}
+
+TEST_CASE("Calling decode_linestring_geometry() with a count of 0") {
+    const container g = {vtzero::detail::command_move_to(0)};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
+                            "MoveTo command count is not 1 (spec 4.3.4.3)");
+    }
+}
+
+TEST_CASE("Calling decode_linestring_geometry() with a count of 2") {
+    const container g = {vtzero::detail::command_move_to(2), 10, 20, 20, 10};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
+                            "MoveTo command count is not 1 (spec 4.3.4.3)");
+    }
+}
+
+TEST_CASE("Calling decode_linestring_geometry() with 2nd command not a LineTo") {
+    const container g = {vtzero::detail::command_move_to(1), 3, 4,
+                         vtzero::detail::command_move_to(1)};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
+                            "expected command 2 but got 1");
+    }
+}
+
+TEST_CASE("Calling decode_linestring_geometry() with LineTo and 0 count") {
+    const container g = {vtzero::detail::command_move_to(1), 3, 4,
+                         vtzero::detail::command_line_to(0)};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_linestring(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_linestring(dummy_geom_handler{}),
+                            "LineTo command count is zero (spec 4.3.4.3)");
+    }
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_point.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_point.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_point.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,135 @@
+
+#include <test.hpp>
+
+#include <vtzero/geometry.hpp>
+
+#include <cstdint>
+#include <vector>
+
+using container = std::vector<uint32_t>;
+using iterator = container::const_iterator;
+
+class dummy_geom_handler {
+
+    int value = 0;
+
+public:
+
+    void points_begin(const uint32_t /*count*/) noexcept {
+        ++value;
+    }
+
+    void points_point(const vtzero::point /*point*/) noexcept {
+        value += 100;
+    }
+
+    void points_end() noexcept {
+        value += 10000;
+    }
+
+    int result() const noexcept {
+        return value;
+    }
+
+}; // class dummy_geom_handler
+
+TEST_CASE("Calling decode_point() with empty input") {
+    const container g;
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
+                            "expected MoveTo command (spec 4.3.4.2)");
+    }
+}
+
+TEST_CASE("Calling decode_point() with a valid point") {
+    const container g = {9, 50, 34};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    dummy_geom_handler handler;
+    decoder.decode_point(handler);
+    REQUIRE(handler.result() == 10101);
+}
+
+TEST_CASE("Calling decode_point() with a valid multipoint") {
+    const container g = {17, 10, 14, 3, 9};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    REQUIRE(decoder.decode_point(dummy_geom_handler{}) == 10201);
+}
+
+TEST_CASE("Calling decode_point() with a linestring geometry fails") {
+    const container g = {9, 4, 4, 18, 0, 16, 16, 0}; // this is a linestring geometry
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
+                            "additional data after end of geometry (spec 4.3.4.2)");
+    }
+}
+
+TEST_CASE("Calling decode_point() with a polygon geometry fails") {
+    const container g = {9, 6, 12, 18, 10, 12, 24, 44, 15}; // this is a polygon geometry
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
+                            "additional data after end of geometry (spec 4.3.4.2)");
+    }
+}
+
+TEST_CASE("Calling decode_point() with something other than MoveTo command") {
+    const container g = {vtzero::detail::command_line_to(3)};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
+                            "expected command 1 but got 2");
+    }
+}
+
+TEST_CASE("Calling decode_point() with a count of 0") {
+    const container g = {vtzero::detail::command_move_to(0)};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
+                            "MoveTo command count is zero (spec 4.3.4.2)");
+    }
+}
+
+TEST_CASE("Calling decode_point() with more data then expected") {
+    const container g = {9, 50, 34, 9};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_point(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_point(dummy_geom_handler{}),
+                            "additional data after end of geometry (spec 4.3.4.2)");
+    }
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_polygon.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_polygon.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_geometry_polygon.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,204 @@
+
+#include <test.hpp>
+
+#include <vtzero/geometry.hpp>
+
+#include <cstdint>
+#include <vector>
+
+using container = std::vector<uint32_t>;
+using iterator = container::const_iterator;
+
+class dummy_geom_handler {
+
+    int value = 0;
+
+public:
+
+    void ring_begin(const uint32_t /*count*/) noexcept {
+        ++value;
+    }
+
+    void ring_point(const vtzero::point /*point*/) noexcept {
+        value += 100;
+    }
+
+    void ring_end(vtzero::ring_type /*is_outer*/) noexcept {
+        value += 10000;
+    }
+
+    int result() const noexcept {
+        return value;
+    }
+
+}; // class dummy_geom_handler
+
+TEST_CASE("Calling decode_polygon_geometry() with empty input") {
+    const container g;
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    dummy_geom_handler handler;
+    decoder.decode_polygon(dummy_geom_handler{});
+    REQUIRE(handler.result() == 0);
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with a valid polygon") {
+    const container g = {9, 6, 12, 18, 10, 12, 24, 44, 15};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    REQUIRE(decoder.decode_polygon(dummy_geom_handler{}) == 10401);
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with a duplicate end point") {
+    const container g = {9, 6, 12, 26, 10, 12, 24, 44, 33, 55, 15};
+
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+    dummy_geom_handler handler;
+    decoder.decode_polygon(handler);
+    REQUIRE(handler.result() == 10501);
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with a valid multipolygon") {
+    const container g = {9, 0, 0, 26, 20, 0, 0, 20, 19, 0, 15, 9, 22, 2, 26, 18,
+                         0, 0, 18, 17, 0, 15, 9, 4, 13, 26, 0, 8, 8, 0, 0, 7, 15};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    dummy_geom_handler handler;
+    decoder.decode_polygon(handler);
+    REQUIRE(handler.result() == 31503);
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with a point geometry fails") {
+    const container g = {9, 50, 34}; // this is a point geometry
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
+                            "expected LineTo command (spec 4.3.4.4)");
+    }
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with a linestring geometry fails") {
+    const container g = {9, 4, 4, 18, 0, 16, 16, 0}; // this is a linestring geometry
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
+                            "expected ClosePath command (4.3.4.4)");
+    }
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with something other than MoveTo command") {
+    const container g = {vtzero::detail::command_line_to(3)};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
+                            "expected command 1 but got 2");
+    }
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with a count of 0") {
+    const container g = {vtzero::detail::command_move_to(0)};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
+                            "MoveTo command count is not 1 (spec 4.3.4.4)");
+    }
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with a count of 2") {
+    const container g = {vtzero::detail::command_move_to(2), 1, 2, 3, 4};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
+                            "MoveTo command count is not 1 (spec 4.3.4.4)");
+    }
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with 2nd command not a LineTo") {
+    const container g = {vtzero::detail::command_move_to(1), 3, 4,
+                         vtzero::detail::command_move_to(1)};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
+                            "expected command 2 but got 1");
+    }
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with LineTo and 0 count") {
+    const container g = {vtzero::detail::command_move_to(1), 3, 4,
+                         vtzero::detail::command_line_to(0),
+                         vtzero::detail::command_close_path()};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    dummy_geom_handler handler;
+    decoder.decode_polygon(handler);
+    REQUIRE(handler.result() == 10201);
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with LineTo and 1 count") {
+    const container g = {vtzero::detail::command_move_to(1), 3, 4,
+                         vtzero::detail::command_line_to(1), 5, 6,
+                         vtzero::detail::command_close_path()};
+
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+    dummy_geom_handler handler;
+    decoder.decode_polygon(handler);
+    REQUIRE(handler.result() == 10301);
+}
+
+TEST_CASE("Calling decode_polygon_geometry() with 3nd command not a ClosePath") {
+    const container g = {vtzero::detail::command_move_to(1), 3, 4,
+                         vtzero::detail::command_line_to(2), 4, 5, 6, 7,
+                         vtzero::detail::command_line_to(0)};
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+
+    SECTION("check exception type") {
+        REQUIRE_THROWS_AS(decoder.decode_polygon(dummy_geom_handler{}),
+                          const vtzero::geometry_exception&);
+    }
+    SECTION("check exception message") {
+        REQUIRE_THROWS_WITH(decoder.decode_polygon(dummy_geom_handler{}),
+                            "expected command 7 but got 2");
+    }
+}
+
+TEST_CASE("Calling decode_polygon_geometry() on polygon with zero area") {
+    const container g = {vtzero::detail::command_move_to(1), 0, 0,
+                         vtzero::detail::command_line_to(3), 2, 0, 0, 4, 2, 0,
+                         vtzero::detail::command_close_path()};
+
+    vtzero::detail::geometry_decoder<container::const_iterator> decoder{g.begin(), g.end(), g.size() / 2};
+    dummy_geom_handler handler;
+    decoder.decode_polygon(handler);
+    REQUIRE(handler.result() == 10501);
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_index.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_index.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_index.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,343 @@
+
+#include <test.hpp>
+
+#include <vtzero/builder.hpp>
+#include <vtzero/index.hpp>
+
+#include <map>
+#include <string>
+#include <unordered_map>
+
+TEST_CASE("add keys to layer using key index built into layer") {
+    static constexpr const int max_keys = 100;
+
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    for (int n = 0; n < max_keys; ++n) {
+        const auto key = std::to_string(n);
+        const auto idx = lbuilder.add_key(key);
+        REQUIRE(n == idx.value());
+    }
+
+    for (int n = 0; n < max_keys; n += 2) {
+        const auto key = std::to_string(n);
+        const auto idx = lbuilder.add_key(key);
+        REQUIRE(n == idx.value());
+    }
+}
+
+TEST_CASE("add values to layer using value index built into layer") {
+    static constexpr const int max_values = 100;
+
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    for (int n = 0; n < max_values; ++n) {
+        const auto value = std::to_string(n);
+        const auto idx = lbuilder.add_value(vtzero::encoded_property_value{value});
+        REQUIRE(n == idx.value());
+    }
+
+    for (int n = 0; n < max_values; n += 2) {
+        const auto value = std::to_string(n);
+        const auto idx = lbuilder.add_value(vtzero::encoded_property_value{value});
+        REQUIRE(n == idx.value());
+    }
+}
+
+template <typename TIndex>
+static void test_key_index() {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    TIndex index{lbuilder};
+
+    const auto i1 = index({"foo"});
+    const auto i2 = index({"bar"});
+    const auto i3 = index({"baz"});
+    const auto i4 = index({"foo"});
+    const auto i5 = index({"foo"});
+    const auto i6 = index({""});
+    const auto i7 = index({"bar"});
+
+    REQUIRE(i1 != i2);
+    REQUIRE(i1 != i3);
+    REQUIRE(i1 == i4);
+    REQUIRE(i1 == i5);
+    REQUIRE(i1 != i6);
+    REQUIRE(i1 != i7);
+    REQUIRE(i2 != i3);
+    REQUIRE(i2 != i4);
+    REQUIRE(i2 != i5);
+    REQUIRE(i2 != i6);
+    REQUIRE(i2 == i7);
+    REQUIRE(i3 != i4);
+    REQUIRE(i3 != i5);
+    REQUIRE(i3 != i6);
+    REQUIRE(i3 != i7);
+    REQUIRE(i4 == i5);
+    REQUIRE(i4 != i6);
+    REQUIRE(i4 != i7);
+    REQUIRE(i5 != i6);
+    REQUIRE(i5 != i7);
+    REQUIRE(i6 != i7);
+}
+
+TEST_CASE("key index based on std::unordered_map") {
+    test_key_index<vtzero::key_index<std::unordered_map>>();
+}
+
+TEST_CASE("key index based on std::map") {
+    test_key_index<vtzero::key_index<std::map>>();
+}
+
+template <typename TIndex>
+static void test_value_index_internal() {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    TIndex index{lbuilder};
+
+    const auto i1 = index(vtzero::encoded_property_value{"foo"});
+    const auto i2 = index(vtzero::encoded_property_value{"bar"});
+    const auto i3 = index(vtzero::encoded_property_value{88});
+    const auto i4 = index(vtzero::encoded_property_value{"foo"});
+    const auto i5 = index(vtzero::encoded_property_value{77});
+    const auto i6 = index(vtzero::encoded_property_value{1.5});
+    const auto i7 = index(vtzero::encoded_property_value{"bar"});
+
+    REQUIRE(i1 != i2);
+    REQUIRE(i1 != i3);
+    REQUIRE(i1 == i4);
+    REQUIRE(i1 != i5);
+    REQUIRE(i1 != i6);
+    REQUIRE(i1 != i7);
+
+    REQUIRE(i2 != i3);
+    REQUIRE(i2 != i4);
+    REQUIRE(i2 != i5);
+    REQUIRE(i2 != i6);
+    REQUIRE(i2 == i7);
+
+    REQUIRE(i3 != i4);
+    REQUIRE(i3 != i5);
+    REQUIRE(i3 != i6);
+    REQUIRE(i3 != i7);
+
+    REQUIRE(i4 != i5);
+    REQUIRE(i4 != i6);
+    REQUIRE(i4 != i7);
+
+    REQUIRE(i5 != i6);
+    REQUIRE(i5 != i7);
+
+    REQUIRE(i6 != i7);
+}
+
+TEST_CASE("internal value index based on std::unordered_map") {
+    test_value_index_internal<vtzero::value_index_internal<std::unordered_map>>();
+}
+
+TEST_CASE("internal value index based on std::map") {
+    test_value_index_internal<vtzero::value_index_internal<std::map>>();
+}
+
+TEST_CASE("external value index") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    vtzero::value_index<vtzero::string_value_type, std::string, std::map> string_index{lbuilder};
+    vtzero::value_index<vtzero::int_value_type, int, std::unordered_map> int_index{lbuilder};
+    vtzero::value_index<vtzero::sint_value_type, int, std::unordered_map> sint_index{lbuilder};
+
+    const auto i1 = string_index("foo");
+    const auto i2 = string_index("bar");
+    const auto i3 = int_index(6);
+    const auto i4 = sint_index(6);
+    const auto i5 = string_index(std::string{"foo"});
+    const auto i6 = int_index(6);
+    const auto i7 = sint_index(2);
+    const auto i8 = sint_index(5);
+    const auto i9 = sint_index(6);
+
+    REQUIRE(i1 != i2);
+    REQUIRE(i1 != i3);
+    REQUIRE(i1 != i4);
+    REQUIRE(i1 == i5);
+    REQUIRE(i1 != i6);
+    REQUIRE(i1 != i7);
+    REQUIRE(i1 != i7);
+    REQUIRE(i1 != i9);
+
+    REQUIRE(i2 != i3);
+    REQUIRE(i2 != i4);
+    REQUIRE(i2 != i5);
+    REQUIRE(i2 != i6);
+    REQUIRE(i2 != i7);
+    REQUIRE(i2 != i8);
+    REQUIRE(i2 != i9);
+
+    REQUIRE(i3 != i4);
+    REQUIRE(i3 != i5);
+    REQUIRE(i3 == i6);
+    REQUIRE(i3 != i7);
+    REQUIRE(i3 != i8);
+    REQUIRE(i3 != i9);
+
+    REQUIRE(i4 != i5);
+    REQUIRE(i4 != i6);
+    REQUIRE(i4 != i7);
+    REQUIRE(i4 != i8);
+    REQUIRE(i4 == i9);
+
+    REQUIRE(i5 != i6);
+    REQUIRE(i5 != i7);
+    REQUIRE(i5 != i8);
+    REQUIRE(i5 != i9);
+
+    REQUIRE(i6 != i7);
+    REQUIRE(i6 != i8);
+    REQUIRE(i6 != i9);
+
+    REQUIRE(i7 != i8);
+    REQUIRE(i7 != i9);
+
+    REQUIRE(i8 != i9);
+}
+
+TEST_CASE("bool value index") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::value_index_bool index{lbuilder};
+
+    const auto i1 = index(false);
+    const auto i2 = index(true);
+    const auto i3 = index(true);
+    const auto i4 = index(false);
+
+    REQUIRE(i1 != i2);
+    REQUIRE(i1 != i3);
+    REQUIRE(i1 == i4);
+
+    REQUIRE(i2 == i3);
+    REQUIRE(i2 != i4);
+
+    REQUIRE(i3 != i4);
+}
+
+TEST_CASE("small unsigned int value index") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    vtzero::value_index_small_uint index{lbuilder};
+
+    const auto i1 = index(12);
+    const auto i2 = index(4);
+    const auto i3 = index(0);
+    const auto i4 = index(100);
+    const auto i5 = index(4);
+    const auto i6 = index(12);
+
+    REQUIRE(i1 != i2);
+    REQUIRE(i1 != i3);
+    REQUIRE(i1 != i4);
+    REQUIRE(i1 != i5);
+    REQUIRE(i1 == i6);
+
+    REQUIRE(i2 != i3);
+    REQUIRE(i2 != i4);
+    REQUIRE(i2 == i5);
+    REQUIRE(i2 != i6);
+
+    REQUIRE(i3 != i4);
+    REQUIRE(i3 != i5);
+    REQUIRE(i3 != i6);
+
+    REQUIRE(i4 != i5);
+    REQUIRE(i4 != i6);
+
+    REQUIRE(i5 != i6);
+}
+
+TEST_CASE("add features using a key index") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+
+    vtzero::point_feature_builder fbuilder{lbuilder};
+    fbuilder.set_id(7);
+    fbuilder.add_point(10, 20);
+
+    SECTION("no index") {
+        fbuilder.add_property("some_key", 12);
+    }
+
+    SECTION("key index using unordered_map") {
+        vtzero::key_index<std::unordered_map> index{lbuilder};
+        fbuilder.add_property(index("some_key"), 12);
+    }
+
+    SECTION("key index using map") {
+        vtzero::key_index<std::map> index{lbuilder};
+        fbuilder.add_property(index("some_key"), 12);
+    }
+
+    fbuilder.commit();
+
+    const std::string data = tbuilder.serialize();
+
+    // ============
+
+    vtzero::vector_tile tile{data};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+    auto feature = layer.next_feature();
+    REQUIRE(feature.id() == 7);
+    const auto property = feature.next_property();
+    REQUIRE(property.value().int_value() == 12);
+}
+
+TEST_CASE("add features using a value index") {
+    vtzero::tile_builder tbuilder;
+    vtzero::layer_builder lbuilder{tbuilder, "test"};
+    const auto key = lbuilder.add_key("some_key");
+
+    vtzero::point_feature_builder fbuilder{lbuilder};
+    fbuilder.set_id(17);
+    fbuilder.add_point(10, 20);
+
+    SECTION("no index") {
+        fbuilder.add_property(key, vtzero::sint_value_type{12});
+    }
+
+    SECTION("external value index using unordered_map") {
+        vtzero::value_index<vtzero::sint_value_type, int, std::unordered_map> index{lbuilder};
+        fbuilder.add_property(key, index(12));
+    }
+
+    SECTION("external value index using map") {
+        vtzero::value_index<vtzero::sint_value_type, int, std::map> index{lbuilder};
+        fbuilder.add_property(key, index(12));
+    }
+
+    SECTION("property_value_type index") {
+        vtzero::value_index_internal<std::unordered_map> index{lbuilder};
+        fbuilder.add_property(key, index(vtzero::encoded_property_value{vtzero::sint_value_type{12}}));
+    }
+
+    fbuilder.commit();
+
+    const std::string data = tbuilder.serialize();
+
+    // ============
+
+    vtzero::vector_tile tile{data};
+
+    REQUIRE(tile.count_layers() == 1);
+    auto layer = tile.next_layer();
+    REQUIRE(layer.num_features() == 1);
+    auto feature = layer.next_feature();
+    REQUIRE(feature.id() == 17);
+    const auto property = feature.next_property();
+    REQUIRE(property.value().sint_value() == 12);
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_layer.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_layer.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_layer.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,155 @@
+
+#include <test.hpp>
+
+#include <vtzero/layer.hpp>
+#include <vtzero/vector_tile.hpp>
+
+#include <cstddef>
+
+TEST_CASE("default constructed layer") {
+    vtzero::layer layer{};
+    REQUIRE_FALSE(layer.valid());
+    REQUIRE_FALSE(layer);
+
+    REQUIRE(layer.data() == vtzero::data_view{});
+    REQUIRE_ASSERT(layer.version());
+    REQUIRE_ASSERT(layer.extent());
+    REQUIRE_ASSERT(layer.name());
+
+    REQUIRE(layer.empty());
+    REQUIRE(layer.num_features() == 0);
+
+    REQUIRE_THROWS_AS(layer.key_table(), const assert_error&);
+    REQUIRE_THROWS_AS(layer.value_table(), const assert_error&);
+
+    REQUIRE_THROWS_AS(layer.key(0), const assert_error&);
+    REQUIRE_THROWS_AS(layer.value(0), const assert_error&);
+
+    REQUIRE_THROWS_AS(layer.get_feature_by_id(0), const assert_error&);
+    REQUIRE_THROWS_AS(layer.next_feature(), const assert_error&);
+    REQUIRE_ASSERT(layer.reset_feature());
+}
+
+TEST_CASE("read a layer") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.get_layer_by_name("bridge");
+    REQUIRE(layer.valid());
+    REQUIRE(layer);
+
+    REQUIRE(layer.version() == 1);
+    REQUIRE(layer.extent() == 4096);
+    REQUIRE(layer.name() == "bridge");
+
+    REQUIRE_FALSE(layer.empty());
+    REQUIRE(layer.num_features() == 2);
+
+    const auto& kt = layer.key_table();
+    REQUIRE(kt.size() == 4);
+    REQUIRE(kt[0] == "class");
+
+    const auto& vt = layer.value_table();
+    REQUIRE(vt.size() == 4);
+    REQUIRE(vt[0].type() == vtzero::property_value_type::string_value);
+    REQUIRE(vt[0].string_value() == "main");
+    REQUIRE(vt[1].type() == vtzero::property_value_type::int_value);
+    REQUIRE(vt[1].int_value() == 0);
+
+    REQUIRE(layer.key(0) == "class");
+    REQUIRE(layer.key(1) == "oneway");
+    REQUIRE(layer.key(2) == "osm_id");
+    REQUIRE(layer.key(3) == "type");
+    REQUIRE_THROWS_AS(layer.key(4), const vtzero::out_of_range_exception&);
+
+    REQUIRE(layer.value(0).string_value() == "main");
+    REQUIRE(layer.value(1).int_value() == 0);
+    REQUIRE(layer.value(2).string_value() == "primary");
+    REQUIRE(layer.value(3).string_value() == "tertiary");
+    REQUIRE_THROWS_AS(layer.value(4), const vtzero::out_of_range_exception&);
+}
+
+TEST_CASE("access features in a layer by id") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.get_layer_by_name("building");
+    REQUIRE(layer);
+
+    REQUIRE(layer.num_features() == 937);
+
+    const auto feature = layer.get_feature_by_id(122);
+    REQUIRE(feature.id() == 122);
+    REQUIRE(feature.num_properties() == 0);
+    REQUIRE(feature.geometry_type() == vtzero::GeomType::POLYGON);
+    REQUIRE(feature.geometry().type() == vtzero::GeomType::POLYGON);
+    REQUIRE_FALSE(feature.geometry().data().empty());
+
+    REQUIRE_FALSE(layer.get_feature_by_id(844));
+    REQUIRE_FALSE(layer.get_feature_by_id(999999));
+}
+
+TEST_CASE("iterate over all features in a layer") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.get_layer_by_name("building");
+    REQUIRE(layer);
+
+    std::size_t count = 0;
+
+    SECTION("external iterator") {
+        while (auto feature = layer.next_feature()) {
+            ++count;
+        }
+    }
+
+    SECTION("internal iterator") {
+        const bool done = layer.for_each_feature([&count](const vtzero::feature& /*feature*/) noexcept {
+            ++count;
+            return true;
+        });
+        REQUIRE(done);
+    }
+
+    REQUIRE(count == 937);
+}
+
+TEST_CASE("iterate over some features in a layer") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.get_layer_by_name("building");
+    REQUIRE(layer);
+
+    uint64_t id_sum = 0;
+
+    SECTION("external iterator") {
+        while (auto feature = layer.next_feature()) {
+            if (feature.id() == 10) {
+                break;
+            }
+            id_sum += feature.id();
+        }
+    }
+
+    SECTION("internal iterator") {
+        const bool done = layer.for_each_feature([&id_sum](const vtzero::feature& feature) noexcept {
+            if (feature.id() == 10) {
+                return false;
+            }
+            id_sum += feature.id();
+            return true;
+        });
+        REQUIRE_FALSE(done);
+    }
+
+    const uint64_t expected = (10 - 1) * 10 / 2;
+    REQUIRE(id_sum == expected);
+
+    layer.reset_feature();
+    auto feature = layer.next_feature();
+    REQUIRE(feature);
+    REQUIRE(feature.id() == 1);
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_output.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_output.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_output.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,42 @@
+
+#include <test.hpp>
+
+#include <sstream>
+#include <string>
+
+template <typename T>
+std::string get_output(T v) {
+    std::stringstream ss;
+    ss << v;
+    return ss.str();
+}
+
+TEST_CASE("output GeomType") {
+    REQUIRE(get_output(vtzero::GeomType::UNKNOWN)    == "unknown");
+    REQUIRE(get_output(vtzero::GeomType::POINT)      == "point");
+    REQUIRE(get_output(vtzero::GeomType::LINESTRING) == "linestring");
+    REQUIRE(get_output(vtzero::GeomType::POLYGON)    == "polygon");
+}
+
+TEST_CASE("output property_value_type") {
+    REQUIRE(get_output(vtzero::property_value_type::sint_value) == "sint");
+}
+
+TEST_CASE("output index_value") {
+    REQUIRE(get_output(vtzero::index_value{}) == "invalid");
+    REQUIRE(get_output(vtzero::index_value{5}) == "5");
+}
+
+TEST_CASE("output index_value_pair") {
+    const auto in = vtzero::index_value{};
+    const auto v2 = vtzero::index_value{2};
+    const auto v5 = vtzero::index_value{5};
+    REQUIRE(get_output(vtzero::index_value_pair{in, v2}) == "invalid");
+    REQUIRE(get_output(vtzero::index_value_pair{v2, v5}) == "[2,5]");
+}
+
+TEST_CASE("output point") {
+    REQUIRE(get_output(vtzero::point{}) == "(0,0)");
+    REQUIRE(get_output(vtzero::point{4, 7}) == "(4,7)");
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_point.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_point.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_point.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,25 @@
+
+#include <test.hpp>
+
+#include <vtzero/geometry.hpp>
+
+TEST_CASE("default constructed point") {
+    vtzero::point p{};
+
+    REQUIRE(p.x == 0);
+    REQUIRE(p.y == 0);
+}
+
+TEST_CASE("point") {
+    vtzero::point p1{4, 5};
+    vtzero::point p2{5, 4};
+    vtzero::point p3{4, 5};
+
+    REQUIRE(p1.x == 4);
+    REQUIRE(p1.y == 5);
+
+    REQUIRE_FALSE(p1 == p2);
+    REQUIRE(p1 != p2);
+    REQUIRE(p1 == p3);
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_property_map.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_property_map.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_property_map.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,62 @@
+
+#include <test.hpp>
+
+#include <vtzero/builder.hpp>
+
+#ifdef VTZERO_TEST_WITH_VARIANT
+# include <boost/variant.hpp>
+using variant_type = boost::variant<std::string, float, double, int64_t, uint64_t, bool>;
+#endif
+
+#include <map>
+#include <string>
+#include <unordered_map>
+
+TEST_CASE("property map") {
+    vtzero::tile_builder tile;
+    vtzero::layer_builder layer_points{tile, "points"};
+    {
+        vtzero::point_feature_builder fbuilder{layer_points};
+        fbuilder.set_id(1);
+        fbuilder.add_points(1);
+        fbuilder.set_point(10, 10);
+        fbuilder.add_property("foo", "bar");
+        fbuilder.add_property("x", "y");
+        fbuilder.add_property("abc", "def");
+        fbuilder.commit();
+    }
+
+    std::string data = tile.serialize();
+
+    vtzero::vector_tile vt{data};
+    REQUIRE(vt.count_layers() == 1);
+    auto layer = vt.next_layer();
+    REQUIRE(layer.valid());
+    REQUIRE(layer.num_features() == 1);
+
+    const auto feature = layer.next_feature();
+    REQUIRE(feature.valid());
+    REQUIRE(feature.num_properties() == 3);
+
+#ifdef VTZERO_TEST_WITH_VARIANT
+    SECTION("std::map") {
+        using prop_map_type = std::map<std::string, variant_type>;
+        auto map = vtzero::create_properties_map<prop_map_type>(feature);
+
+        REQUIRE(map.size() == 3);
+        REQUIRE(boost::get<std::string>(map["foo"]) == "bar");
+        REQUIRE(boost::get<std::string>(map["x"]) == "y");
+        REQUIRE(boost::get<std::string>(map["abc"]) == "def");
+    }
+    SECTION("std::unordered_map") {
+        using prop_map_type = std::unordered_map<std::string, variant_type>;
+        auto map = vtzero::create_properties_map<prop_map_type>(feature);
+
+        REQUIRE(map.size() == 3);
+        REQUIRE(boost::get<std::string>(map["foo"]) == "bar");
+        REQUIRE(boost::get<std::string>(map["x"]) == "y");
+        REQUIRE(boost::get<std::string>(map["abc"]) == "def");
+    }
+#endif
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_property_value.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_property_value.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_property_value.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,407 @@
+
+#include <test.hpp>
+
+#include <vtzero/encoded_property_value.hpp>
+#include <vtzero/property.hpp>
+#include <vtzero/property_value.hpp>
+#include <vtzero/types.hpp>
+
+#ifdef VTZERO_TEST_WITH_VARIANT
+# include <boost/variant.hpp>
+using variant_type = boost::variant<std::string, float, double, int64_t, uint64_t, bool>;
+
+struct variant_mapping : vtzero::property_value_mapping {
+    using float_type = int64_t;
+    using double_type = int64_t;
+};
+
+#endif
+
+#include <string>
+
+struct visitor_test_void {
+
+    int x = 0;
+
+    template <typename T>
+    void operator()(T /*value*/) {
+        x = 1;
+    }
+
+    void operator()(vtzero::data_view /*value*/) {
+        x = 2;
+    }
+
+};
+
+struct visitor_test_int {
+
+    template <typename T>
+    int operator()(T /*value*/) {
+        return 1;
+    }
+
+    int operator()(vtzero::data_view /*value*/) {
+        return 2;
+    }
+
+};
+
+struct visitor_test_to_string {
+
+    template <typename T>
+    std::string operator()(T value) {
+        return std::to_string(value);
+    }
+
+    std::string operator()(vtzero::data_view value) {
+        return std::string{value.data(), value.size()};
+    }
+
+};
+
+struct string_conv {
+
+    std::string s;
+
+    template <typename T>
+    explicit string_conv(T value) :
+        s(std::to_string(value)) {
+    }
+
+    explicit operator std::string() {
+        return s;
+    }
+
+};
+
+struct string_mapping : vtzero::property_value_mapping {
+    using string_type = std::string;
+    using float_type  = string_conv;
+    using double_type = string_conv;
+    using int_type    = string_conv;
+    using uint_type   = string_conv;
+    using bool_type   = string_conv;
+};
+
+TEST_CASE("default constructed property_value") {
+    vtzero::property_value pv;
+    REQUIRE_FALSE(pv.valid());
+    REQUIRE(pv.data().data() == nullptr);
+
+    REQUIRE(pv == vtzero::property_value{});
+    REQUIRE_FALSE(pv != vtzero::property_value{});
+}
+
+TEST_CASE("empty property_value") {
+    char x[1] = {0};
+    vtzero::data_view dv{x, 0};
+    vtzero::property_value pv{dv};
+    REQUIRE(pv.valid());
+    REQUIRE_THROWS_AS(pv.type(), const vtzero::format_exception&);
+}
+
+TEST_CASE("string value") {
+    vtzero::encoded_property_value epv{"foo"};
+    vtzero::property_value pv{epv.data()};
+    REQUIRE(pv.string_value() == "foo");
+
+    visitor_test_void vt;
+    vtzero::apply_visitor(vt, pv);
+    REQUIRE(vt.x == 2);
+
+    const auto result = vtzero::apply_visitor(visitor_test_int{}, pv);
+    REQUIRE(result == 2);
+
+    const auto str = vtzero::apply_visitor(visitor_test_to_string{}, pv);
+    REQUIRE(str == "foo");
+
+    const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
+    REQUIRE(cs == "foo");
+
+#ifdef VTZERO_TEST_WITH_VARIANT
+    const auto vari = vtzero::convert_property_value<variant_type>(pv);
+    REQUIRE(boost::get<std::string>(vari) == "foo");
+    const auto conv = vtzero::convert_property_value<variant_type, variant_mapping>(pv);
+    REQUIRE(boost::get<std::string>(conv) == "foo");
+#endif
+}
+
+TEST_CASE("float value") {
+    vtzero::encoded_property_value epv{1.2f};
+    vtzero::property_value pv{epv.data()};
+    REQUIRE(pv.float_value() == Approx(1.2));
+
+    visitor_test_void vt;
+    vtzero::apply_visitor(vt, pv);
+    REQUIRE(vt.x == 1);
+
+    const auto result = vtzero::apply_visitor(visitor_test_int{}, pv);
+    REQUIRE(result == 1);
+
+    const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
+    REQUIRE(cs == "1.200000");
+
+#ifdef VTZERO_TEST_WITH_VARIANT
+    const auto vari = vtzero::convert_property_value<variant_type>(pv);
+    REQUIRE(boost::get<float>(vari) == Approx(1.2));
+    const auto conv = vtzero::convert_property_value<variant_type, variant_mapping>(pv);
+    REQUIRE(boost::get<int64_t>(conv) == 1);
+#endif
+}
+
+TEST_CASE("double value") {
+    vtzero::encoded_property_value epv{3.4};
+    vtzero::property_value pv{epv.data()};
+    REQUIRE(pv.double_value() == Approx(3.4));
+
+    const auto result = vtzero::apply_visitor(visitor_test_int{}, pv);
+    REQUIRE(result == 1);
+
+    const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
+    REQUIRE(cs == "3.400000");
+}
+
+TEST_CASE("int value") {
+    vtzero::encoded_property_value epv{vtzero::int_value_type{42}};
+    vtzero::property_value pv{epv.data()};
+    REQUIRE(pv.int_value() == 42);
+
+    const auto str = vtzero::apply_visitor(visitor_test_to_string{}, pv);
+    REQUIRE(str == "42");
+
+    const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
+    REQUIRE(cs == "42");
+}
+
+TEST_CASE("uint value") {
+    vtzero::encoded_property_value epv{vtzero::uint_value_type{99}};
+    vtzero::property_value pv{epv.data()};
+    REQUIRE(pv.uint_value() == 99);
+
+    const auto str = vtzero::apply_visitor(visitor_test_to_string{}, pv);
+    REQUIRE(str == "99");
+
+    const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
+    REQUIRE(cs == "99");
+}
+
+TEST_CASE("sint value") {
+    vtzero::encoded_property_value epv{vtzero::sint_value_type{42}};
+    vtzero::property_value pv{epv.data()};
+    REQUIRE(pv.sint_value() == 42);
+
+    const auto str = vtzero::apply_visitor(visitor_test_to_string{}, pv);
+    REQUIRE(str == "42");
+
+    const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
+    REQUIRE(cs == "42");
+}
+
+TEST_CASE("bool value") {
+    vtzero::encoded_property_value epv{true};
+    vtzero::property_value pv{epv.data()};
+    REQUIRE(pv.bool_value());
+
+    const auto str = vtzero::apply_visitor(visitor_test_to_string{}, pv);
+    REQUIRE(str == "1");
+
+    const std::string cs = vtzero::convert_property_value<std::string, string_mapping>(pv);
+    REQUIRE(cs == "1");
+}
+
+TEST_CASE("property and property_value equality comparisons") {
+    vtzero::encoded_property_value t{true};
+    vtzero::encoded_property_value f{false};
+    vtzero::encoded_property_value v1{vtzero::int_value_type{1}};
+    vtzero::encoded_property_value vs{"foo"};
+
+    REQUIRE(t == t);
+    REQUIRE_FALSE(t != t);
+    REQUIRE_FALSE(t == f);
+    REQUIRE_FALSE(t == v1);
+    REQUIRE_FALSE(t == vs);
+
+    using pv = vtzero::property_value;
+    REQUIRE(pv{t.data()} == pv{t.data()});
+    REQUIRE_FALSE(pv{t.data()} != pv{t.data()});
+    REQUIRE_FALSE(pv{t.data()} == pv{f.data()});
+    REQUIRE_FALSE(pv{t.data()} == pv{v1.data()});
+    REQUIRE_FALSE(pv{t.data()} == pv{vs.data()});
+}
+
+TEST_CASE("property and property_value ordering") {
+    using pv = vtzero::property_value;
+
+    vtzero::encoded_property_value t{true};
+    vtzero::encoded_property_value f{false};
+
+    REQUIRE_FALSE(t <  f);
+    REQUIRE_FALSE(t <= f);
+    REQUIRE(t >  f);
+    REQUIRE(t >= f);
+
+    REQUIRE_FALSE(pv{t.data()} <  pv{f.data()});
+    REQUIRE_FALSE(pv{t.data()} <= pv{f.data()});
+    REQUIRE(pv{t.data()} >  pv{f.data()});
+    REQUIRE(pv{t.data()} >= pv{f.data()});
+
+    vtzero::encoded_property_value v1{vtzero::int_value_type{22}};
+    vtzero::encoded_property_value v2{vtzero::int_value_type{17}};
+
+    REQUIRE_FALSE(v1 <  v2);
+    REQUIRE_FALSE(v1 <= v2);
+    REQUIRE(v1 >  v2);
+    REQUIRE(v1 >= v2);
+
+    REQUIRE_FALSE(pv{v1.data()} <  pv{v2.data()});
+    REQUIRE_FALSE(pv{v1.data()} <= pv{v2.data()});
+    REQUIRE(pv{v1.data()} >  pv{v2.data()});
+    REQUIRE(pv{v1.data()} >= pv{v2.data()});
+
+    vtzero::encoded_property_value vsf{"foo"};
+    vtzero::encoded_property_value vsb{"bar"};
+    vtzero::encoded_property_value vsx{"foobar"};
+
+    REQUIRE_FALSE(vsf <  vsb);
+    REQUIRE_FALSE(vsf <= vsb);
+    REQUIRE(vsf >  vsb);
+    REQUIRE(vsf >= vsb);
+
+    REQUIRE_FALSE(pv{vsf.data()} <  pv{vsb.data()});
+    REQUIRE_FALSE(pv{vsf.data()} <= pv{vsb.data()});
+    REQUIRE(pv{vsf.data()} >  pv{vsb.data()});
+    REQUIRE(pv{vsf.data()} >= pv{vsb.data()});
+
+    REQUIRE(vsf <  vsx);
+    REQUIRE(vsf <= vsx);
+    REQUIRE_FALSE(vsf >  vsx);
+    REQUIRE_FALSE(vsf >= vsx);
+
+    REQUIRE(pv{vsf.data()} <  pv{vsx.data()});
+    REQUIRE(pv{vsf.data()} <= pv{vsx.data()});
+    REQUIRE_FALSE(pv{vsf.data()} >  pv{vsx.data()});
+    REQUIRE_FALSE(pv{vsf.data()} >= pv{vsx.data()});
+}
+
+TEST_CASE("default constructed property") {
+    vtzero::property p;
+    REQUIRE_FALSE(p.valid());
+    REQUIRE_FALSE(p);
+    REQUIRE(p.key().data() == nullptr);
+    REQUIRE(p.value().data().data() == nullptr);
+}
+
+TEST_CASE("valid property") {
+    vtzero::data_view k{"key"};
+    vtzero::encoded_property_value epv{"value"};
+    vtzero::property_value pv{epv.data()};
+
+    vtzero::property p{k, pv};
+    REQUIRE(p.key() == "key");
+    REQUIRE(p.value().string_value() == "value");
+}
+
+TEST_CASE("create encoded property values from different string types") {
+    const std::string v{"value"};
+
+    vtzero::encoded_property_value epv1{vtzero::string_value_type{"value"}};
+    vtzero::encoded_property_value epv2{"value"};
+    vtzero::encoded_property_value epv3{v};
+    vtzero::encoded_property_value epv4{vtzero::data_view{v}};
+    vtzero::encoded_property_value epv5{"valuexxxxxxxxx", 5};
+
+    REQUIRE(epv1 == epv2);
+    REQUIRE(epv1 == epv3);
+    REQUIRE(epv1 == epv4);
+    REQUIRE(epv1 == epv5);
+}
+
+TEST_CASE("create encoded property values from different floating point types") {
+    vtzero::encoded_property_value f1{vtzero::float_value_type{3.2f}};
+    vtzero::encoded_property_value f2{3.2f};
+    vtzero::encoded_property_value d1{vtzero::double_value_type{3.2}};
+    vtzero::encoded_property_value d2{3.2};
+
+    REQUIRE(f1 == f2);
+    REQUIRE(d1 == d2);
+
+    vtzero::property_value pvf{f1.data()};
+    vtzero::property_value pvd{d1.data()};
+
+    REQUIRE(pvf.float_value() == Approx(pvd.double_value()));
+}
+
+TEST_CASE("create encoded property values from different integer types") {
+    vtzero::encoded_property_value i1{vtzero::int_value_type{7}};
+    vtzero::encoded_property_value i2{int64_t(7)};
+    vtzero::encoded_property_value i3{int32_t(7)};
+    vtzero::encoded_property_value i4{int16_t(7)};
+    vtzero::encoded_property_value u1{vtzero::uint_value_type{7}};
+    vtzero::encoded_property_value u2{uint64_t(7)};
+    vtzero::encoded_property_value u3{uint32_t(7)};
+    vtzero::encoded_property_value u4{uint16_t(7)};
+    vtzero::encoded_property_value s1{vtzero::sint_value_type{7}};
+
+    REQUIRE(i1 == i2);
+    REQUIRE(i1 == i3);
+    REQUIRE(i1 == i4);
+    REQUIRE(u1 == u2);
+    REQUIRE(u1 == u3);
+    REQUIRE(u1 == u4);
+
+    REQUIRE_FALSE(i1 == u1);
+    REQUIRE_FALSE(i1 == s1);
+    REQUIRE_FALSE(u1 == s1);
+
+    REQUIRE(i1.hash() == i2.hash());
+    REQUIRE(u1.hash() == u2.hash());
+
+    vtzero::property_value pvi{i1.data()};
+    vtzero::property_value pvu{u1.data()};
+    vtzero::property_value pvs{s1.data()};
+
+    REQUIRE(pvi.int_value() == pvu.uint_value());
+    REQUIRE(pvi.int_value() == pvs.sint_value());
+}
+
+TEST_CASE("create encoded property values from different bool types") {
+    vtzero::encoded_property_value b1{vtzero::bool_value_type{true}};
+    vtzero::encoded_property_value b2{true};
+
+    REQUIRE(b1 == b2);
+    REQUIRE(b1.hash() == b2.hash());
+}
+
+TEST_CASE("property equality comparison operator") {
+    std::string k = "key";
+
+    vtzero::encoded_property_value epv1{"value"};
+    vtzero::encoded_property_value epv2{"another value"};
+    vtzero::property_value pv1{epv1.data()};
+    vtzero::property_value pv2{epv2.data()};
+
+    vtzero::property p1{k, pv1};
+    vtzero::property p2{k, pv1};
+    vtzero::property p3{k, pv2};
+    REQUIRE(p1 == p2);
+    REQUIRE_FALSE(p1 == p3);
+}
+
+TEST_CASE("property inequality comparison operator") {
+    std::string k1 = "key";
+    std::string k2 = "another_key";
+
+    vtzero::encoded_property_value epv1{"value"};
+    vtzero::encoded_property_value epv2{"another value"};
+    vtzero::property_value pv1{epv1.data()};
+    vtzero::property_value pv2{epv2.data()};
+
+    vtzero::property p1{k1, pv1};
+    vtzero::property p2{k1, pv1};
+    vtzero::property p3{k1, pv2};
+    vtzero::property p4{k2, pv2};
+    REQUIRE_FALSE(p1 != p2);
+    REQUIRE(p1 != p3);
+    REQUIRE(p3 != p4);
+}

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_types.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_types.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_types.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,116 @@
+
+#include <test.hpp>
+
+#include <vtzero/types.hpp>
+
+#include <string>
+
+TEST_CASE("default constructed string_value_type") {
+    vtzero::string_value_type v;
+    REQUIRE(v.value.data() == nullptr);
+}
+
+TEST_CASE("string_value_type with value") {
+    vtzero::string_value_type v{"foo"};
+    REQUIRE(v.value.data()[0] == 'f');
+    REQUIRE(v.value.size() == 3);
+}
+
+TEST_CASE("default constructed float_value_type") {
+    vtzero::float_value_type v;
+    REQUIRE(v.value == Approx(0.0));
+}
+
+TEST_CASE("float_value_type with value") {
+    float x = 2.7f;
+    vtzero::float_value_type v{x};
+    REQUIRE(v.value == Approx(x));
+}
+
+TEST_CASE("default constructed double_value_type") {
+    vtzero::double_value_type v;
+    REQUIRE(v.value == Approx(0.0));
+}
+
+TEST_CASE("double_value_type with value") {
+    double x = 2.7;
+    vtzero::double_value_type v{x};
+    REQUIRE(v.value == Approx(x));
+}
+
+TEST_CASE("default constructed int_value_type") {
+    vtzero::int_value_type v;
+    REQUIRE(v.value == 0);
+}
+
+TEST_CASE("int_value_type with value") {
+    vtzero::int_value_type v{123};
+    REQUIRE(v.value == 123);
+}
+
+TEST_CASE("default constructed uint_value_type") {
+    vtzero::uint_value_type v;
+    REQUIRE(v.value == 0);
+}
+
+TEST_CASE("uint_value_type with value") {
+    vtzero::uint_value_type v{123};
+    REQUIRE(v.value == 123);
+}
+
+TEST_CASE("default constructed sint_value_type") {
+    vtzero::sint_value_type v;
+    REQUIRE(v.value == 0);
+}
+
+TEST_CASE("sint_value_type with value") {
+    vtzero::sint_value_type v{-14};
+    REQUIRE(v.value == -14);
+}
+
+TEST_CASE("default constructed bool_value_type") {
+    vtzero::bool_value_type v;
+    REQUIRE_FALSE(v.value);
+}
+
+TEST_CASE("bool_value_type with value") {
+    bool x = true;
+    vtzero::bool_value_type v{x};
+    REQUIRE(v.value);
+}
+
+TEST_CASE("property_value_type names") {
+    REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::string_value)} == "string");
+    REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::float_value)} == "float");
+    REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::double_value)} == "double");
+    REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::int_value)} == "int");
+    REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::uint_value)} == "uint");
+    REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::sint_value)} == "sint");
+    REQUIRE(std::string{vtzero::property_value_type_name(vtzero::property_value_type::bool_value)} == "bool");
+}
+
+TEST_CASE("default constructed index value") {
+    vtzero::index_value v;
+    REQUIRE_FALSE(v.valid());
+    REQUIRE_ASSERT(v.value());
+}
+
+TEST_CASE("valid index value") {
+    vtzero::index_value v{32};
+    REQUIRE(v.valid());
+    REQUIRE(v.value() == 32);
+}
+
+TEST_CASE("default constructed geometry") {
+    vtzero::geometry geom;
+    REQUIRE(geom.type() == vtzero::GeomType::UNKNOWN);
+    REQUIRE(geom.data().empty());
+}
+
+TEST_CASE("GeomType names") {
+    REQUIRE(std::string{vtzero::geom_type_name(vtzero::GeomType::UNKNOWN)} == "unknown");
+    REQUIRE(std::string{vtzero::geom_type_name(vtzero::GeomType::POINT)} == "point");
+    REQUIRE(std::string{vtzero::geom_type_name(vtzero::GeomType::LINESTRING)} == "linestring");
+    REQUIRE(std::string{vtzero::geom_type_name(vtzero::GeomType::POLYGON)} == "polygon");
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_vector_tile.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_vector_tile.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/t/test_vector_tile.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,139 @@
+
+#include <test.hpp>
+
+#include <vtzero/vector_tile.hpp>
+
+#include <string>
+#include <vector>
+
+TEST_CASE("open a vector tile with string") {
+    const auto data = load_test_tile();
+    REQUIRE(vtzero::is_vector_tile(data));
+    vtzero::vector_tile tile{data};
+
+    REQUIRE_FALSE(tile.empty());
+    REQUIRE(tile.count_layers() == 12);
+}
+
+TEST_CASE("open a vector tile with data_view") {
+    const auto data = load_test_tile();
+    const vtzero::data_view dv{data};
+    vtzero::vector_tile tile{dv};
+
+    REQUIRE_FALSE(tile.empty());
+    REQUIRE(tile.count_layers() == 12);
+}
+
+TEST_CASE("open a vector tile with pointer and size") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data.data(), data.size()};
+
+    REQUIRE_FALSE(tile.empty());
+    REQUIRE(tile.count_layers() == 12);
+}
+
+TEST_CASE("get layer by index") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.get_layer(0);
+    REQUIRE(layer);
+    REQUIRE(layer.name() == "landuse");
+
+    layer = tile.get_layer(1);
+    REQUIRE(layer);
+    REQUIRE(layer.name() == "waterway");
+
+    layer = tile.get_layer(11);
+    REQUIRE(layer);
+    REQUIRE(layer.name() == "waterway_label");
+
+    layer = tile.get_layer(12);
+    REQUIRE_FALSE(layer);
+}
+
+TEST_CASE("get layer by name") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data};
+
+    auto layer = tile.get_layer_by_name("landuse");
+    REQUIRE(layer);
+    REQUIRE(layer.name() == "landuse");
+
+    layer = tile.get_layer_by_name(std::string{"road"});
+    REQUIRE(layer);
+    REQUIRE(layer.name() == "road");
+
+    const vtzero::data_view name{"poi_label"};
+    layer = tile.get_layer_by_name(name);
+    REQUIRE(layer);
+    REQUIRE(layer.name() == "poi_label");
+
+    layer = tile.get_layer_by_name("unknown");
+    REQUIRE_FALSE(layer);
+}
+
+TEST_CASE("iterate over layers") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data};
+
+    std::vector<std::string> names;
+
+    SECTION("external iterator") {
+        while (auto layer = tile.next_layer()) {
+            names.emplace_back(layer.name());
+        }
+    }
+
+    SECTION("internal iterator") {
+        const bool done = tile.for_each_layer([&names](const vtzero::layer& layer) {
+            names.emplace_back(layer.name());
+            return true;
+        });
+        REQUIRE(done);
+    }
+
+    REQUIRE(names.size() == 12);
+
+    static std::vector<std::string> expected = {
+        "landuse", "waterway", "water", "barrier_line", "building", "road",
+        "bridge", "place_label", "water_label", "poi_label", "road_label",
+        "waterway_label"
+    };
+
+    REQUIRE(names == expected);
+
+    tile.reset_layer();
+    int num = 0;
+    while (auto layer = tile.next_layer()) {
+        ++num;
+    }
+    REQUIRE(num == 12);
+}
+
+TEST_CASE("iterate over some of the layers") {
+    const auto data = load_test_tile();
+    vtzero::vector_tile tile{data};
+
+    int num_layers = 0;
+
+    SECTION("external iterator") {
+        while (auto layer = tile.next_layer()) {
+            ++num_layers;
+            if (layer.name() == "water") {
+                break;
+            }
+        }
+    }
+
+    SECTION("internal iterator") {
+        const bool done = tile.for_each_layer([&num_layers](const vtzero::layer& layer) noexcept {
+            ++num_layers;
+            return layer.name() != "water";
+        });
+        REQUIRE_FALSE(done);
+    }
+
+    REQUIRE(num_layers == 3);
+}
+

Added: sandbox/jng/mvt/Oem/vtzero-1.0.3/test/test_main.cpp
===================================================================
--- sandbox/jng/mvt/Oem/vtzero-1.0.3/test/test_main.cpp	                        (rev 0)
+++ sandbox/jng/mvt/Oem/vtzero-1.0.3/test/test_main.cpp	2019-05-29 16:52:57 UTC (rev 9523)
@@ -0,0 +1,25 @@
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
+
+#include <test.hpp>
+
+#include <fstream>
+#include <stdexcept>
+#include <string>
+
+bool got_an_assert = false;
+
+std::string load_test_tile() {
+    std::string path{"data/mapbox-streets-v6-14-8714-8017.mvt"};
+    std::ifstream stream{path, std::ios_base::in|std::ios_base::binary};
+    if (!stream.is_open()) {
+        throw std::runtime_error{"could not open: '" + path + "'"};
+    }
+
+    const std::string message{std::istreambuf_iterator<char>(stream.rdbuf()),
+                              std::istreambuf_iterator<char>()};
+
+    stream.close();
+    return message;
+}
+



More information about the mapguide-commits mailing list