Imported Upstream version 3.1.9 46/300046/1 upstream upstream/3.1.9
authorminje.ahn <minje.ahn@samsung.com>
Mon, 16 Oct 2023 07:33:53 +0000 (16:33 +0900)
committerminje.ahn <minje.ahn@samsung.com>
Mon, 16 Oct 2023 07:34:10 +0000 (16:34 +0900)
Change-Id: I501564820e672ec8cc37e4fe262b833f96101bdc

331 files changed:
.clang-format [new file with mode: 0644]
.git-blame-ignore-revs [new file with mode: 0644]
.github/workflows/analysis_workflow.yml [new file with mode: 0644]
.github/workflows/ci_workflow.yml [new file with mode: 0644]
.gitignore [new file with mode: 0644]
CHANGES.md [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
CODE_OF_CONDUCT.md [new file with mode: 0644]
CONTRIBUTING.md [new file with mode: 0644]
CONTRIBUTORS.md [new file with mode: 0644]
GOVERNANCE.md [new file with mode: 0644]
LICENSE.md [new file with mode: 0644]
README.md [new file with mode: 0644]
SECURITY.md [new file with mode: 0644]
cmake/FindPythonPackage.cmake [new file with mode: 0644]
cmake/FindSphinx.cmake [new file with mode: 0644]
cmake/SampleCTestScript.cmake [new file with mode: 0644]
cmake/Toolchain-Linux-VFX_Platform21.cmake [new file with mode: 0644]
cmake/Toolchain-mingw.cmake [new file with mode: 0644]
cmake/clang-format.cmake [new file with mode: 0644]
config/CMakeLists.txt [new file with mode: 0644]
config/Imath.pc.in [new file with mode: 0644]
config/ImathConfig.cmake.in [new file with mode: 0644]
config/ImathConfig.h.in [new file with mode: 0644]
config/ImathSetup.cmake [new file with mode: 0644]
config/LibraryDefine.cmake [new file with mode: 0644]
docs/CMakeLists.txt [new file with mode: 0644]
docs/Doxyfile.in [new file with mode: 0644]
docs/Makefile [new file with mode: 0644]
docs/PortingGuide.rst [new file with mode: 0644]
docs/PortingGuide2-3.md [new file with mode: 0644]
docs/SymbolVisibility.rst [new file with mode: 0644]
docs/about.rst [new file with mode: 0644]
docs/classes.rst [new file with mode: 0644]
docs/classes/Box.rst [new file with mode: 0644]
docs/classes/Color3.rst [new file with mode: 0644]
docs/classes/Color4.rst [new file with mode: 0644]
docs/classes/Euler.rst [new file with mode: 0644]
docs/classes/Frustum.rst [new file with mode: 0644]
docs/classes/Interval.rst [new file with mode: 0644]
docs/classes/Line3.rst [new file with mode: 0644]
docs/classes/Matrix22.rst [new file with mode: 0644]
docs/classes/Matrix33.rst [new file with mode: 0644]
docs/classes/Matrix44.rst [new file with mode: 0644]
docs/classes/Plane3.rst [new file with mode: 0644]
docs/classes/Quat.rst [new file with mode: 0644]
docs/classes/Rand32.rst [new file with mode: 0644]
docs/classes/Rand48.rst [new file with mode: 0644]
docs/classes/Shear6.rst [new file with mode: 0644]
docs/classes/Sphere3.rst [new file with mode: 0644]
docs/classes/Vec2.rst [new file with mode: 0644]
docs/classes/Vec3.rst [new file with mode: 0644]
docs/classes/Vec4.rst [new file with mode: 0644]
docs/classes/float.rst [new file with mode: 0644]
docs/classes/half.rst [new file with mode: 0644]
docs/classes/half_c.rst [new file with mode: 0644]
docs/classes/half_class.rst [new file with mode: 0644]
docs/classes/half_conversion.rst [new file with mode: 0644]
docs/classes/half_limits.rst [new file with mode: 0644]
docs/concepts.rst [new file with mode: 0644]
docs/conf.py [new file with mode: 0644]
docs/examples/Box.cpp [new file with mode: 0644]
docs/examples/CMakeLists.txt [new file with mode: 0644]
docs/examples/Color3.cpp [new file with mode: 0644]
docs/examples/Color4.cpp [new file with mode: 0644]
docs/examples/Euler.cpp [new file with mode: 0644]
docs/examples/Frustum.cpp [new file with mode: 0644]
docs/examples/Interval.cpp [new file with mode: 0644]
docs/examples/Line3.cpp [new file with mode: 0644]
docs/examples/Matrix22.cpp [new file with mode: 0644]
docs/examples/Matrix33.cpp [new file with mode: 0644]
docs/examples/Matrix44.cpp [new file with mode: 0644]
docs/examples/Plane3.cpp [new file with mode: 0644]
docs/examples/Quat.cpp [new file with mode: 0644]
docs/examples/Shear6.cpp [new file with mode: 0644]
docs/examples/Sphere3.cpp [new file with mode: 0644]
docs/examples/Vec2.cpp [new file with mode: 0644]
docs/examples/Vec3.cpp [new file with mode: 0644]
docs/examples/Vec4.cpp [new file with mode: 0644]
docs/examples/gl.cpp [new file with mode: 0644]
docs/examples/half.c [new file with mode: 0644]
docs/examples/half.cpp [new file with mode: 0644]
docs/examples/intro.cpp [new file with mode: 0644]
docs/examples/main.cpp [new file with mode: 0644]
docs/fixmanpages.sh [new file with mode: 0755]
docs/functions.rst [new file with mode: 0644]
docs/functions/box.rst [new file with mode: 0644]
docs/functions/color.rst [new file with mode: 0644]
docs/functions/frame.rst [new file with mode: 0644]
docs/functions/gl.rst [new file with mode: 0644]
docs/functions/glu.rst [new file with mode: 0644]
docs/functions/line.rst [new file with mode: 0644]
docs/functions/matrix.rst [new file with mode: 0644]
docs/functions/random.rst [new file with mode: 0644]
docs/functions/roots.rst [new file with mode: 0644]
docs/functions/vec.rst [new file with mode: 0644]
docs/images/imath-fav.ico [new file with mode: 0644]
docs/images/imath-logo-black.png [new file with mode: 0644]
docs/images/imath-logo-blue.png [new file with mode: 0644]
docs/images/imath-logo-white.png [new file with mode: 0644]
docs/index.rst [new file with mode: 0644]
docs/install.rst [new file with mode: 0644]
docs/license.rst [new file with mode: 0644]
docs/requirements.txt [new file with mode: 0644]
docs/toc_redirect.rst [new file with mode: 0644]
share/ci/scripts/linux/install_boost.sh [new file with mode: 0755]
share/ci/scripts/linux/install_cmake.sh [new file with mode: 0755]
share/ci/scripts/linux/install_gdb.sh [new file with mode: 0755]
share/ci/scripts/linux/install_six.sh [new file with mode: 0755]
share/ci/scripts/linux/install_sonar.sh [new file with mode: 0755]
share/ci/scripts/linux/install_valgrind.sh [new file with mode: 0755]
share/ci/scripts/linux/log_valgrind.sh [new file with mode: 0755]
share/ci/scripts/linux/run_gcov.sh [new file with mode: 0755]
share/ci/scripts/macos/install_boost.sh [new file with mode: 0755]
share/ci/scripts/macos/install_python.sh [new file with mode: 0755]
share/ci/scripts/windows/install_boost.ps1 [new file with mode: 0755]
share/ci/scripts/windows/install_cmake.ps1 [new file with mode: 0755]
share/ci/scripts/windows/install_python.ps1 [new file with mode: 0755]
share/ci/scripts/windows/install_zlib.ps1 [new file with mode: 0755]
sonar-project.properties [new file with mode: 0644]
src/Imath/CMakeLists.txt [new file with mode: 0644]
src/Imath/ImathBox.h [new file with mode: 0644]
src/Imath/ImathBoxAlgo.h [new file with mode: 0644]
src/Imath/ImathColor.h [new file with mode: 0644]
src/Imath/ImathColorAlgo.cpp [new file with mode: 0644]
src/Imath/ImathColorAlgo.h [new file with mode: 0644]
src/Imath/ImathEuler.h [new file with mode: 0644]
src/Imath/ImathExport.h [new file with mode: 0644]
src/Imath/ImathForward.h [new file with mode: 0644]
src/Imath/ImathFrame.h [new file with mode: 0644]
src/Imath/ImathFrustum.h [new file with mode: 0644]
src/Imath/ImathFrustumTest.h [new file with mode: 0644]
src/Imath/ImathFun.cpp [new file with mode: 0644]
src/Imath/ImathFun.h [new file with mode: 0644]
src/Imath/ImathGL.h [new file with mode: 0644]
src/Imath/ImathGLU.h [new file with mode: 0644]
src/Imath/ImathInt64.h [new file with mode: 0644]
src/Imath/ImathInterval.h [new file with mode: 0644]
src/Imath/ImathLine.h [new file with mode: 0644]
src/Imath/ImathLineAlgo.h [new file with mode: 0644]
src/Imath/ImathMath.h [new file with mode: 0644]
src/Imath/ImathMatrix.h [new file with mode: 0644]
src/Imath/ImathMatrixAlgo.cpp [new file with mode: 0644]
src/Imath/ImathMatrixAlgo.h [new file with mode: 0644]
src/Imath/ImathNamespace.h [new file with mode: 0644]
src/Imath/ImathPlane.h [new file with mode: 0644]
src/Imath/ImathPlatform.h [new file with mode: 0644]
src/Imath/ImathQuat.h [new file with mode: 0644]
src/Imath/ImathRandom.cpp [new file with mode: 0644]
src/Imath/ImathRandom.h [new file with mode: 0644]
src/Imath/ImathRoots.h [new file with mode: 0644]
src/Imath/ImathShear.h [new file with mode: 0644]
src/Imath/ImathSphere.h [new file with mode: 0644]
src/Imath/ImathTypeTraits.h [new file with mode: 0644]
src/Imath/ImathVec.h [new file with mode: 0644]
src/Imath/ImathVecAlgo.h [new file with mode: 0644]
src/Imath/half.cpp [new file with mode: 0644]
src/Imath/half.h [new file with mode: 0644]
src/Imath/halfFunction.h [new file with mode: 0644]
src/Imath/halfLimits.h [new file with mode: 0644]
src/Imath/toFloat.cpp [new file with mode: 0644]
src/Imath/toFloat.h [new file with mode: 0644]
src/ImathTest/CMakeLists.txt [new file with mode: 0644]
src/ImathTest/eLut.h [new file with mode: 0644]
src/ImathTest/half_c_main.c [new file with mode: 0644]
src/ImathTest/half_perf_test.cpp [new file with mode: 0644]
src/ImathTest/main.cpp [new file with mode: 0644]
src/ImathTest/testArithmetic.cpp [new file with mode: 0644]
src/ImathTest/testArithmetic.h [new file with mode: 0644]
src/ImathTest/testBitPatterns.cpp [new file with mode: 0644]
src/ImathTest/testBitPatterns.h [new file with mode: 0644]
src/ImathTest/testBox.cpp [new file with mode: 0644]
src/ImathTest/testBox.h [new file with mode: 0644]
src/ImathTest/testBoxAlgo.cpp [new file with mode: 0644]
src/ImathTest/testBoxAlgo.h [new file with mode: 0644]
src/ImathTest/testClassification.cpp [new file with mode: 0644]
src/ImathTest/testClassification.h [new file with mode: 0644]
src/ImathTest/testColor.cpp [new file with mode: 0644]
src/ImathTest/testColor.h [new file with mode: 0644]
src/ImathTest/testError.cpp [new file with mode: 0644]
src/ImathTest/testError.h [new file with mode: 0644]
src/ImathTest/testExtractEuler.cpp [new file with mode: 0644]
src/ImathTest/testExtractEuler.h [new file with mode: 0644]
src/ImathTest/testExtractSHRT.cpp [new file with mode: 0644]
src/ImathTest/testExtractSHRT.h [new file with mode: 0644]
src/ImathTest/testFrustum.cpp [new file with mode: 0644]
src/ImathTest/testFrustum.h [new file with mode: 0644]
src/ImathTest/testFrustumTest.cpp [new file with mode: 0644]
src/ImathTest/testFrustumTest.h [new file with mode: 0644]
src/ImathTest/testFun.cpp [new file with mode: 0644]
src/ImathTest/testFun.h [new file with mode: 0644]
src/ImathTest/testFunction.cpp [new file with mode: 0644]
src/ImathTest/testFunction.h [new file with mode: 0644]
src/ImathTest/testInterop.cpp [new file with mode: 0644]
src/ImathTest/testInterop.h [new file with mode: 0644]
src/ImathTest/testInterval.cpp [new file with mode: 0644]
src/ImathTest/testInterval.h [new file with mode: 0644]
src/ImathTest/testInvert.cpp [new file with mode: 0644]
src/ImathTest/testInvert.h [new file with mode: 0644]
src/ImathTest/testJacobiEigenSolver.cpp [new file with mode: 0644]
src/ImathTest/testJacobiEigenSolver.h [new file with mode: 0644]
src/ImathTest/testLimits.cpp [new file with mode: 0644]
src/ImathTest/testLimits.h [new file with mode: 0644]
src/ImathTest/testLineAlgo.cpp [new file with mode: 0644]
src/ImathTest/testLineAlgo.h [new file with mode: 0644]
src/ImathTest/testMatrix.cpp [new file with mode: 0644]
src/ImathTest/testMatrix.h [new file with mode: 0644]
src/ImathTest/testMiscMatrixAlgo.cpp [new file with mode: 0644]
src/ImathTest/testMiscMatrixAlgo.h [new file with mode: 0644]
src/ImathTest/testNoInterop.cpp [new file with mode: 0644]
src/ImathTest/testNoInterop.h [new file with mode: 0644]
src/ImathTest/testProcrustes.cpp [new file with mode: 0644]
src/ImathTest/testProcrustes.h [new file with mode: 0644]
src/ImathTest/testQuat.cpp [new file with mode: 0644]
src/ImathTest/testQuat.h [new file with mode: 0644]
src/ImathTest/testQuatSetRotation.cpp [new file with mode: 0644]
src/ImathTest/testQuatSetRotation.h [new file with mode: 0644]
src/ImathTest/testQuatSlerp.cpp [new file with mode: 0644]
src/ImathTest/testQuatSlerp.h [new file with mode: 0644]
src/ImathTest/testRandom.cpp [new file with mode: 0644]
src/ImathTest/testRandom.h [new file with mode: 0644]
src/ImathTest/testRoots.cpp [new file with mode: 0644]
src/ImathTest/testRoots.h [new file with mode: 0644]
src/ImathTest/testShear.cpp [new file with mode: 0644]
src/ImathTest/testShear.h [new file with mode: 0644]
src/ImathTest/testSize.cpp [new file with mode: 0644]
src/ImathTest/testSize.h [new file with mode: 0644]
src/ImathTest/testTinySVD.cpp [new file with mode: 0644]
src/ImathTest/testTinySVD.h [new file with mode: 0644]
src/ImathTest/testToFloat.cpp [new file with mode: 0644]
src/ImathTest/testToFloat.h [new file with mode: 0644]
src/ImathTest/testVec.cpp [new file with mode: 0644]
src/ImathTest/testVec.h [new file with mode: 0644]
src/python/CMakeLists.txt [new file with mode: 0644]
src/python/PyImath.pc.in [new file with mode: 0644]
src/python/PyImath/CMakeLists.txt [new file with mode: 0644]
src/python/PyImath/PyImath.cpp [new file with mode: 0644]
src/python/PyImath/PyImath.h [new file with mode: 0644]
src/python/PyImath/PyImathAPI.h [new file with mode: 0644]
src/python/PyImath/PyImathAutovectorize.cpp [new file with mode: 0644]
src/python/PyImath/PyImathAutovectorize.h [new file with mode: 0644]
src/python/PyImath/PyImathBasicTypes.cpp [new file with mode: 0644]
src/python/PyImath/PyImathBasicTypes.h [new file with mode: 0644]
src/python/PyImath/PyImathBox.cpp [new file with mode: 0644]
src/python/PyImath/PyImathBox.h [new file with mode: 0644]
src/python/PyImath/PyImathBox2Array.cpp [new file with mode: 0644]
src/python/PyImath/PyImathBox3Array.cpp [new file with mode: 0644]
src/python/PyImath/PyImathBoxArrayImpl.h [new file with mode: 0644]
src/python/PyImath/PyImathBufferProtocol.cpp [new file with mode: 0644]
src/python/PyImath/PyImathBufferProtocol.h [new file with mode: 0644]
src/python/PyImath/PyImathColor.h [new file with mode: 0644]
src/python/PyImath/PyImathColor3.cpp [new file with mode: 0644]
src/python/PyImath/PyImathColor3ArrayImpl.h [new file with mode: 0644]
src/python/PyImath/PyImathColor4.cpp [new file with mode: 0644]
src/python/PyImath/PyImathColor4Array2DImpl.h [new file with mode: 0644]
src/python/PyImath/PyImathColor4ArrayImpl.h [new file with mode: 0644]
src/python/PyImath/PyImathDecorators.h [new file with mode: 0644]
src/python/PyImath/PyImathEuler.cpp [new file with mode: 0644]
src/python/PyImath/PyImathEuler.h [new file with mode: 0644]
src/python/PyImath/PyImathExport.h [new file with mode: 0644]
src/python/PyImath/PyImathFixedArray.cpp [new file with mode: 0644]
src/python/PyImath/PyImathFixedArray.h [new file with mode: 0644]
src/python/PyImath/PyImathFixedArray2D.h [new file with mode: 0644]
src/python/PyImath/PyImathFixedArrayTraits.h [new file with mode: 0644]
src/python/PyImath/PyImathFixedMatrix.h [new file with mode: 0644]
src/python/PyImath/PyImathFixedVArray.cpp [new file with mode: 0644]
src/python/PyImath/PyImathFixedVArray.h [new file with mode: 0644]
src/python/PyImath/PyImathFrustum.cpp [new file with mode: 0644]
src/python/PyImath/PyImathFrustum.h [new file with mode: 0644]
src/python/PyImath/PyImathFun.cpp [new file with mode: 0644]
src/python/PyImath/PyImathFun.h [new file with mode: 0644]
src/python/PyImath/PyImathFunOperators.h [new file with mode: 0644]
src/python/PyImath/PyImathLine.cpp [new file with mode: 0644]
src/python/PyImath/PyImathLine.h [new file with mode: 0644]
src/python/PyImath/PyImathMathExc.h [new file with mode: 0644]
src/python/PyImath/PyImathMatrix.h [new file with mode: 0644]
src/python/PyImath/PyImathMatrix22.cpp [new file with mode: 0644]
src/python/PyImath/PyImathMatrix33.cpp [new file with mode: 0644]
src/python/PyImath/PyImathMatrix44.cpp [new file with mode: 0644]
src/python/PyImath/PyImathOperators.h [new file with mode: 0644]
src/python/PyImath/PyImathPlane.cpp [new file with mode: 0644]
src/python/PyImath/PyImathPlane.h [new file with mode: 0644]
src/python/PyImath/PyImathQuat.cpp [new file with mode: 0644]
src/python/PyImath/PyImathQuat.h [new file with mode: 0644]
src/python/PyImath/PyImathQuatOperators.h [new file with mode: 0644]
src/python/PyImath/PyImathRandom.cpp [new file with mode: 0644]
src/python/PyImath/PyImathRandom.h [new file with mode: 0644]
src/python/PyImath/PyImathShear.cpp [new file with mode: 0644]
src/python/PyImath/PyImathShear.h [new file with mode: 0644]
src/python/PyImath/PyImathStringArray.cpp [new file with mode: 0644]
src/python/PyImath/PyImathStringArray.h [new file with mode: 0644]
src/python/PyImath/PyImathStringArrayRegister.h [new file with mode: 0644]
src/python/PyImath/PyImathStringTable.cpp [new file with mode: 0644]
src/python/PyImath/PyImathStringTable.h [new file with mode: 0644]
src/python/PyImath/PyImathTask.cpp [new file with mode: 0644]
src/python/PyImath/PyImathTask.h [new file with mode: 0644]
src/python/PyImath/PyImathUtil.cpp [new file with mode: 0644]
src/python/PyImath/PyImathUtil.h [new file with mode: 0644]
src/python/PyImath/PyImathVec.h [new file with mode: 0644]
src/python/PyImath/PyImathVec2Impl.h [new file with mode: 0644]
src/python/PyImath/PyImathVec2fd.cpp [new file with mode: 0644]
src/python/PyImath/PyImathVec2si.cpp [new file with mode: 0644]
src/python/PyImath/PyImathVec3ArrayImpl.h [new file with mode: 0644]
src/python/PyImath/PyImathVec3Impl.h [new file with mode: 0644]
src/python/PyImath/PyImathVec3fd.cpp [new file with mode: 0644]
src/python/PyImath/PyImathVec3si.cpp [new file with mode: 0644]
src/python/PyImath/PyImathVec3siArray.cpp [new file with mode: 0644]
src/python/PyImath/PyImathVec4ArrayImpl.h [new file with mode: 0644]
src/python/PyImath/PyImathVec4Impl.h [new file with mode: 0644]
src/python/PyImath/PyImathVec4fd.cpp [new file with mode: 0644]
src/python/PyImath/PyImathVec4si.cpp [new file with mode: 0644]
src/python/PyImath/PyImathVec4siArray.cpp [new file with mode: 0644]
src/python/PyImath/PyImathVecOperators.h [new file with mode: 0644]
src/python/PyImath/imathmodule.cpp [new file with mode: 0644]
src/python/PyImath/varraySemantics.txt [new file with mode: 0644]
src/python/PyImathNumpy/CMakeLists.txt [new file with mode: 0644]
src/python/PyImathNumpy/imathnumpymodule.cpp [new file with mode: 0644]
src/python/PyImathNumpyTest/CMakeLists.txt [new file with mode: 0644]
src/python/PyImathNumpyTest/pyImathNumpyTest.in [new file with mode: 0755]
src/python/PyImathSpeedTest/CMakeLists.txt [new file with mode: 0644]
src/python/PyImathSpeedTest/pyImathSpeedTest.in [new file with mode: 0755]
src/python/PyImathTest/CMakeLists.txt [new file with mode: 0644]
src/python/PyImathTest/main.cpp [new file with mode: 0644]
src/python/PyImathTest/pyImathTest.in [new file with mode: 0644]
src/python/PyImathTest/testStringTable.cpp [new file with mode: 0644]
src/python/PyImathTest/testStringTable.h [new file with mode: 0644]
src/python/config/CMakeLists.txt [new file with mode: 0644]
src/python/config/ModuleDefine.cmake [new file with mode: 0644]
src/python/config/NumPyLocate.cmake [new file with mode: 0644]
src/python/config/PyImathConfig.h.in [new file with mode: 0644]
src/python/config/PyImathSetup.cmake [new file with mode: 0644]

diff --git a/.clang-format b/.clang-format
new file mode 100644 (file)
index 0000000..1f6f585
--- /dev/null
@@ -0,0 +1,120 @@
+---
+Language:        Cpp
+BasedOnStyle:  LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: true
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlines: Right
+AlignOperands:   true
+AlignTrailingComments: true
+AllowAllArgumentsOnNextLine: false
+AllowAllConstructorInitializersOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: InlineOnly
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: TopLevel
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: MultiLine
+BinPackArguments: false
+BinPackParameters: false
+BraceWrapping:   
+  AfterCaseLabel:  true
+  AfterClass:      true
+  AfterControlStatement: true
+  AfterEnum:       true
+  AfterFunction:   true
+  AfterNamespace:  true
+  AfterObjCDeclaration: true
+  AfterStruct:     true
+  AfterUnion:      true
+  AfterExternBlock: false
+  BeforeCatch:     true
+  BeforeElse:      true
+  IndentBraces:    false
+  SplitEmptyFunction: false
+  SplitEmptyRecord: false
+  SplitEmptyNamespace: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeInheritanceComma: false
+BreakInheritanceList: BeforeColon
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: BeforeColon
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: false
+ColumnLimit:     100
+CommentPragmas:  '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+DisableFormat:   false
+FixNamespaceComments: true
+ForEachMacros:   
+  - foreach
+  - Q_FOREACH
+  - BOOST_FOREACH
+IncludeBlocks:   Preserve
+IncludeCategories: 
+  - Regex:           '^"(llvm|llvm-c|clang|clang-c)/'
+    Priority:        2
+  - Regex:           '^(<|"(gtest|gmock|isl|json)/)'
+    Priority:        3
+  - Regex:           '.*'
+    Priority:        1
+IncludeIsMainRegex: '(Test|_test)?$'
+IndentCaseLabels: false
+IndentPPDirectives: AfterHash
+IndentWidth:     4
+IndentWrappedFunctionNames: false
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 4
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakAssignment: 8
+PenaltyBreakBeforeFirstCallParameter: 8
+PenaltyBreakComment: 1000
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 20
+PointerAlignment: Left
+ReflowComments:  false
+SortIncludes:    true
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: true
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: true
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: NonEmptyParentheses
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles:  false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+SpacesInConditionalStatement: false
+Standard:        Cpp11
+TabWidth:        4
+UseTab:          Never
+...
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644 (file)
index 0000000..01d2f63
--- /dev/null
@@ -0,0 +1,6 @@
+# Disable clang-format in half.cpp
+344334aef268206ed1d46399ea85ab276f3f13e6
+
+# Tune .clang-format to match existing style
+c6014892de1acccca0deada8ab3353cd290e9fbc
+
diff --git a/.github/workflows/analysis_workflow.yml b/.github/workflows/analysis_workflow.yml
new file mode 100644 (file)
index 0000000..3df4951
--- /dev/null
@@ -0,0 +1,143 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (c) Contributors to the OpenEXR Project.
+#
+# GitHub Actions workflow file
+# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions
+
+name: Analysis
+
+on:
+  schedule:
+    # Weekly Sunday build
+    - cron: "0 0 * * 0"
+  workflow_dispatch:
+
+jobs:
+
+  # ---------------------------------------------------------------------------
+  # SonarCloud static analysis
+  # ---------------------------------------------------------------------------
+
+  linux_sonarcloud:
+    name: 'SonarCloud Linux CentOS 7 VFX CY2022 <GCC 9.3.1>'
+    # GH-hosted VM. The build runs in CentOS 7 'container' defined below.
+    runs-on: ubuntu-latest
+    container:
+      # DockerHub: https://hub.docker.com/u/aswf
+      # Source: https://github.com/AcademySoftwareFoundation/aswf-docker
+      image: aswf/ci-openexr:2022
+    env:
+      CXX: g++
+      CC: gcc
+    steps:
+      # TODO: Remove this workaround following resolution of:
+      #       https://github.com/AcademySoftwareFoundation/aswf-docker/issues/43
+      - name: Setup container
+        run: sudo rm -rf /usr/local/lib64/cmake/glew
+      - name: Checkout
+        uses: actions/checkout@v3
+        with:
+          fetch-depth: 50
+      - name: Create build directories
+        run: |
+          mkdir _install
+          mkdir _build
+      - name: Configure
+        run: |
+          cmake .. \
+                -DCMAKE_INSTALL_PREFIX=../_install \
+                -DCMAKE_BUILD_TYPE=Release \
+                -DCMAKE_CXX_STANDARD=14 \
+                -DCMAKE_CXX_FLAGS="-g -O0 -fprofile-arcs -ftest-coverage" \
+                -DCMAKE_CXX_OUTPUT_EXTENSION_REPLACE=ON \
+                -DCMAKE_C_FLAGS="-g -O0 -fprofile-arcs -ftest-coverage" \
+                -DCMAKE_C_OUTPUT_EXTENSION_REPLACE=ON \
+                -DCMAKE_EXE_LINKER_FLAGS="-lgcov" \
+                -DCMAKE_VERBOSE_MAKEFILE:BOOL='OFF' \
+                -DBUILD_SHARED_LIBS='OFF' \
+                -DPYTHON='ON'
+        working-directory: _build
+      - name: Build Imath with build-wrapper
+        shell: bash
+        run: |
+          build-wrapper-linux-x86-64 --out-dir bw_output cmake --build . --target install --config Release
+        working-directory: _build
+      - name: Test
+        run: |
+          ctest -T Test \
+                -C Release \
+                --timeout 7200 \
+                --output-on-failure \
+                -VV
+        working-directory: _build
+      - name: Coverage
+        run: share/ci/scripts/linux/run_gcov.sh
+        shell: bash
+      - name: Sonar-scanner
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+        run: sonar-scanner -X -Dsonar.login=$SONAR_TOKEN
+
+  # ------------------------------------------------------------------------------
+  #  Valgrind memcheck test
+  # ------------------------------------------------------------------------------
+  linux_valgrind:
+    name: 'Valgrind Linux CentOS 7 VFX CY2022 <GCC 9.3.1>'
+    # GH-hosted VM. The build runs in CentOS 7 'container' defined below.
+    runs-on: ubuntu-latest
+    container:
+      # DockerHub: https://hub.docker.com/u/aswf
+      # Source: https://github.com/AcademySoftwareFoundation/aswf-docker
+      image: aswf/ci-openexr:2022
+    env:
+      CXX: g++
+      CC: gcc
+    steps:
+      # TODO: Remove this workaround following resolution of:
+      #       https://github.com/AcademySoftwareFoundation/aswf-docker/issues/43
+      - name: Setup container
+        run: sudo rm -rf /usr/local/lib64/cmake/glew
+      - name: Checkout
+        uses: actions/checkout@v3
+        with:
+          fetch-depth: 50
+      - name: Create build directories
+        run: |
+          mkdir _install
+          mkdir _build
+        shell: bash
+      - name: Install Dependencies
+        run: |
+          share/ci/scripts/linux/install_valgrind.sh 
+        shell: bash
+      - name: Configure
+        run: |
+          cmake .. \
+                -DCMAKE_INSTALL_PREFIX=../_install \
+                -DCMAKE_BUILD_TYPE=Release \
+                -DCMAKE_CXX_STANDARD=14 \
+                -DCMAKE_VERBOSE_MAKEFILE:BOOL='OFF' \
+                -DBUILD_SHARED_LIBS='OFF' \
+                -DPYTHON='ON'
+        working-directory: _build
+      - name: Build
+        run: |
+          cmake --build . \
+                --target install \
+                --config Release
+        working-directory: _build
+      - name: Valgrind memcheck tests
+        run: |
+          ctest -C Release \
+                --timeout 50000 \
+                --force-new-ctest-process \
+                --test-action memcheck \
+                --output-on-failure \
+                -VV
+        working-directory: _build
+      - name: Valgrind memcheck test results
+        run: |
+          share/ci/scripts/linux/log_valgrind.sh _build
+        shell: bash
+
diff --git a/.github/workflows/ci_workflow.yml b/.github/workflows/ci_workflow.yml
new file mode 100644 (file)
index 0000000..18d59eb
--- /dev/null
@@ -0,0 +1,641 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+#
+# GitHub Actions workflow file
+# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions
+
+name: CI
+
+on:
+  push:
+    # Jobs are skipped when ONLY Markdown (*.md) files are changed
+    paths-ignore:
+      - '**.md'
+  pull_request:
+    paths-ignore:
+      - '**.md'
+
+jobs:
+  # Linux jobs run in Docker containers, so the latest OS version is OK. macOS 
+  # and Windows jobs need to be locked to specific virtual environment 
+  # versions to mitigate issues from OS updates, and will require maintenance 
+  # as OS versions are retired.
+  #
+  # GH Actions (Free plan) supports 20 concurrent jobs, with 5 concurrent macOS 
+  # jobs. This workflow tries to utilize (but not exceed) that budget to 
+  # promote timely CI.
+
+  # ---------------------------------------------------------------------------
+  # Linux
+  # ---------------------------------------------------------------------------
+  # TODO: Add ARM build. Add sanitize build.
+
+  linux:
+    name: 'Linux CentOS 7 VFX CY${{ matrix.vfx-cy }} 
+      <${{ matrix.compiler-desc }} ,
+       ${{ matrix.python-desc }},
+       config=${{ matrix.build-type }}, 
+       shared=${{ matrix.build-shared }}, 
+       cxx=${{ matrix.cxx-standard }}>'
+    # GH-hosted VM. The build runs in CentOS 7 'container' defined below.
+    runs-on: ubuntu-latest
+    container:
+      # DockerHub: https://hub.docker.com/u/aswf
+      # Source: https://github.com/AcademySoftwareFoundation/aswf-docker
+      image: aswf/ci-openexr:${{ matrix.vfx-cy }}
+    strategy:
+      matrix:
+        build: [1, 2, 3, 4, 9, 10, 11, 12, 13, 14, 15, 20, 21, 22]
+        include:
+          # -------------------------------------------------------------------
+          # GCC, VFX CY2022
+          # -------------------------------------------------------------------
+          # C++17, Python 3.9
+          - build: 1
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 17
+            cxx-compiler: g++
+            cc-compiler: gcc
+            compiler-desc: gcc9.3.1
+            python: 'ON'
+            python-desc: python3.9.7
+            vfx-cy: 2022
+
+          # C++17, Python 3.9.7, Debug
+          - build: 2
+            build-type: Debug
+            build-shared: 'ON'
+            cxx-standard: 17
+            cxx-compiler: g++
+            cc-compiler: gcc
+            compiler-desc: gcc9.3.1
+            python: 'ON'
+            python-desc: python3.9.7
+            vfx-cy: 2022
+
+          # C++17, Python 3.9.7, Static
+          - build: 3
+            build-type: Release
+            build-shared: 'OFF'
+            cxx-standard: 17
+            cxx-compiler: g++
+            cc-compiler: gcc
+            compiler-desc: gcc9.3.1
+            python: 'ON'
+            python-desc: python3.9.7
+            vfx-cy: 2022
+
+          # C++14, Python 3.9.7, Static
+          - build: 4
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 14
+            cxx-compiler: g++
+            cc-compiler: gcc
+            compiler-desc: gcc9.3.1
+            python: 'ON'
+            python-desc: python3.9.7
+            vfx-cy: 2022
+
+          # C++17, no Python
+            # - build: 5
+            # build-type: Release
+            # build-shared: 'ON'
+            # cxx-standard: 17
+            # cxx-compiler: g++
+            # cc-compiler: gcc
+            # compiler-desc: gcc9.3.1
+            # python: 'OFF'
+            # python-desc: no python
+            # vfx-cy: 2022
+
+          # -------------------------------------------------------------------
+          # GCC, VFX CY2021
+          # -------------------------------------------------------------------
+          # C++17, Python 3.7.9
+          - build: 9
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 17
+            cxx-compiler: g++
+            cc-compiler: gcc
+            compiler-desc: gcc9.3.1
+            python: 'ON'
+            python-desc: python3.7.9
+            vfx-cy: 2021
+
+          # -------------------------------------------------------------------
+          # GCC, VFX CY2020
+          # -------------------------------------------------------------------
+          # C++14, Python 3.7
+          - build: 10
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 14
+            cxx-compiler: g++
+            cc-compiler: gcc
+            compiler-desc: gcc6.3.1
+            python: 'ON'
+            python-desc: python3.7.3
+            vfx-cy: 2020
+
+          # -------------------------------------------------------------------
+          # GCC, VFX CY2019
+          # -------------------------------------------------------------------
+          # C++11, Python 2.7
+          - build: 11
+            build-type: Release
+            build-shared: 'ON'
+            use-python2: 'ON'
+            cxx-standard: 11
+            cxx-compiler: g++
+            cc-compiler: gcc
+            compiler-desc: gcc6.3.1
+            python: 'ON'
+            python-desc: python2.7.15
+            vfx-cy: 2019
+
+          # -------------------------------------------------------------------
+          # Clang, VFX CY2022
+          # -------------------------------------------------------------------
+          # C++17, Python 3.9
+          - build: 12
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 17
+            cxx-compiler: clang++
+            cc-compiler: clang
+            compiler-desc: clang10.4
+            python: 'ON'
+            python-desc: python3.9.7
+            vfx-cy: 2022
+
+          # C++17, Python 3.9.7, Debug
+          - build: 13
+            build-type: Debug
+            build-shared: 'ON'
+            cxx-standard: 17
+            cxx-compiler: clang++
+            cc-compiler: clang
+            compiler-desc: clang10.4
+            python: 'ON'
+            python-desc: python3.9.7
+            vfx-cy: 2022
+
+          # C++17, Python 3.9.7, Static
+          - build: 14
+            build-type: Release
+            build-shared: 'OFF'
+            cxx-standard: 17
+            cxx-compiler: clang++
+            cc-compiler: clang
+            compiler-desc: clang10.4
+            python: 'ON'
+            python-desc: python3.9.7
+            vfx-cy: 2022
+
+          # C++14, Python 3.9.7, Static
+          - build: 15
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 14
+            cxx-compiler: clang++
+            cc-compiler: clang
+            compiler-desc: clang10.4
+            python: 'ON'
+            python-desc: python3.9.7
+            vfx-cy: 2022
+
+          # -------------------------------------------------------------------
+          # Clang, VFX CY2021
+          # -------------------------------------------------------------------
+          # C++17, Python 3.7.9
+          - build: 20
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 17
+            cxx-compiler: clang++
+            cc-compiler: clang
+            compiler-desc: clang10.4
+            python: 'ON'
+            python-desc: python3.7.9
+            vfx-cy: 2021
+
+          # -------------------------------------------------------------------
+          # Clang, VFX CY2020
+          # -------------------------------------------------------------------
+          # C++14, Python 3.7
+          - build: 21
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 14
+            cxx-compiler: clang++
+            cc-compiler: clang
+            compiler-desc: clang7.8
+            python: 'ON'
+            python-desc: python3.7.3
+            vfx-cy: 2020
+
+          # -------------------------------------------------------------------
+          # Clang, VFX CY2019
+          # -------------------------------------------------------------------
+          # C++11, Python 2.7
+          - build: 22
+            build-type: Release
+            build-shared: 'ON'
+            use-python2: 'ON'
+            cxx-standard: 11
+            cxx-compiler: clang++
+            cc-compiler: clang
+            compiler-desc: clang7.8
+            python: 'ON'
+            python-desc: python2.7.15
+            vfx-cy: 2019
+
+    env:
+      CXX: ${{ matrix.cxx-compiler }}
+      CC: ${{ matrix.cc-compiler }}
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+      - name: Create build directories
+        run: |
+          mkdir _install
+          mkdir _build
+          mkdir _examples
+      - name: Configure
+        run: |
+          cmake .. \
+                -DCMAKE_INSTALL_PREFIX=../_install \
+                -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
+                -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \
+                -DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }} \
+                -DCMAKE_VERBOSE_MAKEFILE:BOOL='OFF' \
+                -DBUILD_SHARED_LIBS=${{ matrix.build-shared }} \
+                -DPYTHON=${{ matrix.python }} \
+                -DUSE_PYTHON2=${{ matrix.use-python2 }}
+        working-directory: _build
+      - name: Build
+        run: |
+          cmake --build . \
+                --target install \
+                --config ${{ matrix.build-type }}
+        working-directory: _build
+      - name: Examples
+        run: |
+          # Confirm the python module loads. Query the site-packages directory and substitute ../_install
+          export PYTHONPATH=`python -c "import site; print('../_install%s' % site.USER_SITE[len(site.USER_BASE):])"`          
+          python -c "import imath;print(imath.__version__)"
+          # Make sure we can build the tests when configured as a
+          # standalone application linking against the just-installed
+          # Imath library.
+          cmake ../src/ImathTest \
+                -DCMAKE_PREFIX_PATH=../../_install \
+                -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
+                -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \
+                -DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }}
+          cmake --build . \
+                --config ${{ matrix.build-type }}
+          # Confirm the tests run
+          ./bin/ImathTest
+          # Confirm the examples compile and execute
+          rm -rf bin CMakeCache.txt CMakeFiles cmake_install.cmake Makefile
+          cmake ../docs/examples \
+                -DCMAKE_PREFIX_PATH=../../_install \
+                -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
+                -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \
+                -DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }}
+          cmake --build . \
+                --config ${{ matrix.build-type }}
+          ctest
+        working-directory: _examples 
+      - name: Test
+        run: |
+          ctest -T Test ${{ matrix.exclude-tests }} \
+                -C ${{ matrix.build-type }} \
+                --timeout 7200 \
+                --output-on-failure \
+                -VV
+        working-directory: _build
+
+  # ---------------------------------------------------------------------------
+  # macOS
+  # ---------------------------------------------------------------------------
+  
+  macos_no_python:
+    name: 'macOS VFXP-${{matrix.vfx-cy }} macos-${{ matrix.osver }}
+      <AppleClang 11.0 
+       config=${{ matrix.build-type }}, 
+       shared=${{ matrix.build-shared }}, 
+       cxx=${{ matrix.cxx-standard }}' 
+    runs-on: macos-${{ matrix.osver }}
+    strategy:
+      matrix:
+        build: [1, 2, 3, 4, 5, 6]
+        include:
+          # --------------------------------------------------------------------
+          # VFX CY2023 - MacOS 11.0
+          # --------------------------------------------------------------------
+          # C++11
+          - build: 1
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 17
+            exclude-tests:
+            osver: 11.0
+
+          # Debug
+          - build: 2
+            build-type: Debug
+            build-shared: 'ON'
+            cxx-standard: 17
+            exclude-tests:
+            osver: 11.0
+
+
+          # Static
+          - build: 3
+            build-type: Debug
+            build-shared: 'OFF'
+            cxx-standard: 17
+            exclude-tests:
+            osver: 11.0
+
+
+          # C++14
+          - build: 4
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 14
+            exclude-tests:
+            osver: 11.0
+
+
+          # C++11
+          - build: 5
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 11
+            exclude-tests:
+            osver: 11.0
+              
+          # --------------------------------------------------------------------
+          # VFX CY2022 - MacOS 12
+          # --------------------------------------------------------------------
+          # C++11
+          - build: 6
+            build-type: Release
+            build-shared: 'ON'
+            cxx-standard: 17
+            exclude-tests:
+            osver: 12.0
+
+    steps:
+      ## - name: Setup Python
+      ##   uses: actions/setup-python@v1
+      ##   with:
+      ##     python-version: ${{ matrix.python-version }}
+      - name: Checkout
+        uses: actions/checkout@v2
+      - name: Create build directories
+        run: |
+          mkdir _install
+          mkdir _build
+          mkdir _examples
+      ## - name: Install Dependences
+      ##   run: |
+      ##     share/ci/scripts/macos/install_boost.sh 
+      ##   shell: bash
+      - name: Configure
+        run: |
+          cmake ../. \
+                -DCMAKE_INSTALL_PREFIX=../_install \
+                -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
+                -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \
+                -DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }} \
+                -DCMAKE_VERBOSE_MAKEFILE:BOOL='OFF' \
+                -DBUILD_SHARED_LIBS=${{ matrix.build-shared }}
+        working-directory: _build
+      - name: Build
+        run: |
+          cmake --build . \
+                --target install \
+                --config ${{ matrix.build-type }} \
+                -- -j2
+        working-directory: _build
+      - name: Examples
+        run: |
+          # Make sure we can build the tests when configured as a
+          # standalone application linking against the just-installed
+          # Imath library.
+          cmake ../src/ImathTest \
+                -DCMAKE_PREFIX_PATH=../../_install \
+                -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
+                -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \
+                -DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }}
+          cmake --build . \
+                --config ${{ matrix.build-type }}
+          # Confirm the tests run
+          ./bin/ImathTest
+        working-directory: _examples 
+      - name: Test
+        run: |
+          ctest -T Test ${{matrix.exclude-tests }} \
+                -C ${{matrix.build-type}} \
+                --timeout 7200 \
+                --output-on-failure \
+                -VV
+        working-directory: _build
+
+  # ---------------------------------------------------------------------------
+  # Windows
+  # ---------------------------------------------------------------------------
+  # TODO: Figure out how to get CMake to use Python 3.7.7.
+  #       Boost 1.70.0 will only make boost python for 3.7.
+  #       CMake finds Python 3.8 on the VM when configuring, then does not find 
+  #       a corresponding boost python38 module. 
+  # TODO: Determine why tests hang in Debug job.
+  # TODO: Fix boost script to install from sourceforge.
+
+  windows:
+    name: 'Windows VFXP-${{ matrix.vfx-cy }}
+      <${{ matrix.compiler-desc }},
+       config=${{ matrix.build-type }}, 
+       shared=${{ matrix.build-shared }}, 
+       cxx=${{ matrix.cxx-standard }}, 
+       python=OFF>' 
+    runs-on: windows-${{ matrix.osver }}
+    strategy:
+      matrix:
+        build: [1, 3, 4, 6, 7, 8]
+        include:
+          # -------------------------------------------------------------------
+          # VFX CY2023 - C++17 - Windows 2022 runner - MSVC 2022 (17.5)
+          # -------------------------------------------------------------------
+          # C++17, Release Shared
+          - build: 1
+            build-type: Release
+            build-shared: 'ON'
+            compiler-desc: msvc17.5
+            cxx-standard: 17
+            vfx-cy: 2023
+            exclude-tests:
+            osver: 2022
+
+          # C++17, Debug -
+          ## - build: 2
+          ##   build-type: Debug
+          ##   build-shared: 'ON'
+          ##   cxx-standard: 17
+          ##   exclude-tests:
+
+          # C++17, Release Static
+          - build: 3
+            build-type: Release
+            build-shared: 'OFF'
+            compiler-desc: msvc17.5
+            cxx-standard: 17
+            vfx-cy: 2023
+            exclude-tests:
+            osver: 2022
+
+          # -------------------------------------------------------------------
+          # VFX CY2022 - C++17 - Windows 2019
+          # -------------------------------------------------------------------
+          # C++17, Release Shared
+          - build: 4
+            build-type: Release
+            build-shared: 'ON'
+            compiler-desc: msvc16.11
+            cxx-standard: 17
+            vfx-cy: 2022
+            exclude-tests:
+            osver: 2019
+
+          # C++17, Debug -
+          ## - build: 5
+          ##   build-type: Debug
+          ##   build-shared: 'ON'
+          ##   cxx-standard: 17
+          ##   exclude-tests:
+
+          # C++17, Release Static
+          - build: 6
+            build-type: Release
+            build-shared: 'OFF'
+            compiler-desc: msvc16.11
+            cxx-standard: 17
+            vfx-cy: 2022
+            exclude-tests:
+            osver: 2019
+
+         # -------------------------------------------------------------------
+          # VFX CY2020 - C++14 - Windows 2019
+          # -------------------------------------------------------------------
+          # C++14, Release Shared
+          - build: 7
+            build-type: Release
+            build-shared: 'ON'
+            compiler-desc: msvc16.11
+            cxx-standard: 14
+            vfx-cy: 2020
+            exclude-tests:
+            osver: 2019
+
+          # -------------------------------------------------------------------
+          # VFX CY2019 - C++11 - Windows 2019
+          # -------------------------------------------------------------------
+          # C++11, Release Shared
+          - build: 8
+            build-type: Release
+            build-shared: 'ON'
+            compiler-desc: msvc16.11
+            cxx-standard: 11
+            exclude-tests:
+            osver: 2019
+
+    steps:
+      # - name: Setup Python
+        # uses: actions/setup-python@v1
+        # with:
+          # python-version: ${{ matrix.python-version }}
+      - name: Checkout
+        uses: actions/checkout@v2
+      - name: Create build directories
+        run: |
+          mkdir _install
+          mkdir _build
+        shell: bash
+      # - name: Install Dependences
+        # run: |
+          # share/ci/scripts/windows/install_python.ps1 ${{ matrix.python-version }} $HOME 
+          # share/ci/scripts/windows/install_boost.ps1 ${{ matrix.boost-version }} $HOME 3.8
+          # share/ci/scripts/windows/install_zlib.ps1 ${{ matrix.zlib-version }} $HOME 
+        # shell: powershell
+      - name: Configure
+        run: |
+          cmake ../. \
+                -DCMAKE_INSTALL_PREFIX=../_install \
+                -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
+                -DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \
+                -DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }} \
+                -DCMAKE_VERBOSE_MAKEFILE:BOOL='OFF' \
+                -DBUILD_SHARED_LIBS=${{ matrix.build-shared }}
+                # NB: removed trailing slash from these lines
+                # -DBOOST_ROOT:FILEPATH=$BOOST_ROOT
+                # -DZLIB_ROOT:FILEPATH="$ZLIB_ROOT"
+                # -DZLIB_LIBRARY:FILEPATH="$ZLIB_ROOT/lib/${{ matrix.zlib-lib }}"
+                # -DPYTHON='ON'
+                # -DPython_EXECUTABLE:FILEPATH="$PYTHON_ROOT"
+                # -DPython_INCLUDE_DIR:FILEPATH="$PYTHON_ROOT/include"
+                # -DPython_LIBRARY:"$PYTHON_ROOT\libs"
+        shell: bash
+        working-directory: _build
+      - name: Build
+        run: |
+          cmake --build . \
+                --target install \
+                --config ${{ matrix.build-type }}
+        shell: bash
+        working-directory: _build
+      - name: Test
+        run: |
+          ctest -T Test ${{ matrix.exclude-tests }} \
+                -C ${{ matrix.build-type }} \
+                --timeout 7200 \
+                --output-on-failure \
+                -VV
+        shell: bash
+        working-directory: _build
+
+  Docs:
+
+    # Build the documentation, using a process that mimics the readthedoc build.
+    #
+    # Note that this job does not actually build Imath libraries,
+    # it just runs doxygen and sphinx.
+    
+    name: 'Docs'
+    runs-on: ubuntu-latest
+    
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Create build directory
+        run: mkdir _build
+      - name: Install doxygen 
+        # Need help2man for tool manpages
+        run: sudo apt-get install -y doxygen help2man
+      - name: Install sphinx requirements
+        run: pip3 install -r docs/requirements.txt
+      - name: Configure
+        run: cmake .. -DBUILD_DOCS='ON'
+        working-directory: _build
+      - name: Build
+        run: |
+          cmake --build . \
+                --target docs \
+                --config Release
+        working-directory: _build
+    
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..0f0bab0
--- /dev/null
@@ -0,0 +1,3 @@
+build/
+_build/
+_install/
diff --git a/CHANGES.md b/CHANGES.md
new file mode 100644 (file)
index 0000000..fc47b69
--- /dev/null
@@ -0,0 +1,410 @@
+# Imath Release Notes
+
+* [Version 3.1.9](#version-319-May-31-2023) May 31, 2023
+* [Version 3.1.8](#version-318-May-22-2023) May 22, 2023
+* [Version 3.1.7](#version-317-March-1-2023) March 1, 2023
+* [Version 3.1.6](#version-316-november-7-2022) November 7, 2022
+* [Version 3.1.5](#version-315-march-28-2022) March 28, 2022
+* [Version 3.1.4](#version-314-january-21-2022) January 21, 2022
+* [Version 3.1.3](#version-313-september-2-2021) September 2, 2021
+* [Version 3.1.2](#version-312-july-31-2021) July 31, 2021
+* [Version 3.1.1](#version-311-july-20-2021) July 20, 2021
+* [Version 3.1.0](#version-310-july-13-2021) July 13, 2021
+* [Version 3.0.5](#version-305-june-29-2021) June 29, 2021
+* [Version 3.0.4](#version-304-june-1-2021) June 1, 2021
+* [Version 3.0.2](#version-302-may-16-2021) May 16, 2021
+* [Version 3.0.1](#version-301-april-1-2021) April 1, 2021
+* [Version 3.0.1-beta](#version-301-beta-march-28-2021) March 28, 2021
+* [Version 3.0.0-beta](#version-300-beta-march-15-2021) March 15, 2021
+* [Inherited History from OpenEXR](#inherited-history-from-openexr)
+
+## Version 3.1.9 (May 31, 2023)
+
+Patch release that fixes an correct .so version number introduced in
+v3.1.8. All Imath library functionality is compatible with v3.1.8.
+
+This release also reverts
+[#305](https://github.com/AcademySoftwareFoundation/Imath/pull/305),
+which inadvertently introduced additional python bindings in v3.1.8
+that altered the ABI of ``libPyImath``. ``libPyImath`` is now
+ABI-compatible with v3.1.7 and previous releases.
+
+## Version 3.1.8 (May 22, 2023)
+
+**NOTE: this version has an incorrect .so number and should not be used. Use v3.1.9 instead.**
+
+Patch release that addresses miscellaneous minor compiler/build/doc
+issues and extends test coverage.
+
+### Merged Pull Requests
+
+* \[[#318](https://github.com/AcademySoftwareFoundation/Imath/pull/318)\] Separate CI job for docs 
+* \[[#317](https://github.com/AcademySoftwareFoundation/Imath/pull/317)\] fix the macro switching half-precision floating-point format implementation.
+* \[[#315](https://github.com/AcademySoftwareFoundation/Imath/pull/315)\] Updated Mac and Windows jobs for VFX platform 2023. 
+* \[[#314](https://github.com/AcademySoftwareFoundation/Imath/pull/314)\] Remove duplicate IMATH_HOSTDEVICE 
+* \[[#313](https://github.com/AcademySoftwareFoundation/Imath/pull/313)\] IMATH_EXPORT for Rand32::nextf() 
+* \[[#310](https://github.com/AcademySoftwareFoundation/Imath/pull/310)\] Extend test coverage 
+* \[[#309](https://github.com/AcademySoftwareFoundation/Imath/pull/309)\] Undo #307, restore array-based Matrix constructors 
+* \[[#308](https://github.com/AcademySoftwareFoundation/Imath/pull/308)\] Fix run_gcov.sh to use proper _build/_coverage dirs 
+* \[[#307](https://github.com/AcademySoftwareFoundation/Imath/pull/307)\] Conditionally include Matrix constructors duplicated by interop declarations 
+* \[[#306](https://github.com/AcademySoftwareFoundation/Imath/pull/306)\] Fix coverage analysis for .c files 
+* \[[#305](https://github.com/AcademySoftwareFoundation/Imath/pull/305)\] Extend test code coverage and add missing python bindings 
+* \[[#303](https://github.com/AcademySoftwareFoundation/Imath/pull/303)\] Remove unused variables 
+* \[[#302](https://github.com/AcademySoftwareFoundation/Imath/pull/302)\] In testMatrix(), call fabs() instead of fabsf() for double values 
+* \[[#300](https://github.com/AcademySoftwareFoundation/Imath/pull/300)\] Check return status of extractSHRT in computeRSMatrix 
+
+
+## Version 3.1.7 (March 1, 2023)
+
+**NOTE: this version has an incorrect .so number and should not be used. Use v3.1.9 instead.**
+
+Patch release with miscellaneous bug/doc/build fixes. In particular:
+
+- Support for relative prefix in pkg-config
+- Reorganization of documentation at https://imath.readthedocs.io
+- Add a ``trace()`` method on Matrix types
+
+### Merged Pull Requests
+
+* \[[#296](https://github.com/AcademySoftwareFoundation/Imath/pull/296)\] Move index to bottom of main page; remove top-level link
+* \[[#295](https://github.com/AcademySoftwareFoundation/Imath/pull/295)\] Fix doc typo
+* \[[#294](https://github.com/AcademySoftwareFoundation/Imath/pull/294)\] Fix documentation glitches and symbol visibility table
+* \[[#293](https://github.com/AcademySoftwareFoundation/Imath/pull/293)\] Reorganize repo/readthedocs documentation
+* \[[#292](https://github.com/AcademySoftwareFoundation/Imath/pull/292)\] Add missing licenses/copyrights
+* \[[#291](https://github.com/AcademySoftwareFoundation/Imath/pull/291)\] Support relative prefix in pkg-config
+* \[[#282](https://github.com/AcademySoftwareFoundation/Imath/pull/282)\] Remove MACOSX_RPATH forcing
+* \[[#280](https://github.com/AcademySoftwareFoundation/Imath/pull/280)\] Add trace function for matrix types
+* \[[#279](https://github.com/AcademySoftwareFoundation/Imath/pull/279)\] Define BOOST_BIND_GLOBAL_PLACEHOLDERS to suppress pragma message
+* \[[#278](https://github.com/AcademySoftwareFoundation/Imath/pull/278)\] Use Py_ssize_t in place of size_t where appropriate to avoid warnings
+* \[[#277](https://github.com/AcademySoftwareFoundation/Imath/pull/277)\] Update CONTRIBUTING.md to be consistent with OpenEXR 
+* \[[#275](https://github.com/AcademySoftwareFoundation/Imath/pull/275)\] Remove export attribute from inline half functions
+
+## Version 3.1.6 (November 7, 2022)
+
+Patch release with miscellaneous bug/doc/build fixes.
+
+* \[[#269](https://github.com/AcademySoftwareFoundation/Imath/pull/269)\] fix memory leak in V3fArrayFromBuffer
+* \[[#268](https://github.com/AcademySoftwareFoundation/Imath/pull/268)\] Add <cstdint> for int64_t
+* \[[#263](https://github.com/AcademySoftwareFoundation/Imath/pull/263)\] Initialize x in testRoots.cpp:solve() to suppress compiler warning
+* \[[#262](https://github.com/AcademySoftwareFoundation/Imath/pull/262)\] Fix gcc compiler warning in testFun.cpp
+* \[[#261](https://github.com/AcademySoftwareFoundation/Imath/pull/261)\] Test return value of extractSHRT to avoid uninitialized reference
+* \[[#260](https://github.com/AcademySoftwareFoundation/Imath/pull/260)\] Fix example code so it compiles as is 
+* \[[#259](https://github.com/AcademySoftwareFoundation/Imath/pull/259)\] Cuda safety in several headers
+* \[[#256](https://github.com/AcademySoftwareFoundation/Imath/pull/256)\] Fix markdown and typos in README.md
+* \[[#255](https://github.com/AcademySoftwareFoundation/Imath/pull/255)\] Do not warn if half.h has already being included
+* \[[#250](https://github.com/AcademySoftwareFoundation/Imath/pull/250)\] Fix compiler warnings on windows
+* \[[#249](https://github.com/AcademySoftwareFoundation/Imath/pull/249)\] Remove irrelevant cvs ignore files
+* \[[#248](https://github.com/AcademySoftwareFoundation/Imath/pull/248)\] Update sphinx version
+
+## Version 3.1.5 (March 28, 2022)
+
+Patch release with miscellaneous bug/doc/build fixes.
+
+In particular, this fixes an issue that could lead to incorrect values
+for `numeric_limits<half>`. This also updates the CI workflow matrix
+to VFX-CY2022.
+
+* \[[#246](https://github.com/AcademySoftwareFoundation/Imath/pull/246)\] 
+Update CI workflow matrix for VFX-CY2022
+* \[[#245](https://github.com/AcademySoftwareFoundation/Imath/pull/245)\] 
+Use `_WIN32` instead of `_MSC_VER` to fix mingw build
+* \[[#244](https://github.com/AcademySoftwareFoundation/Imath/pull/244)\] 
+Fix 32-bit x86 build failure with 16c instructions
+* \[[#241](https://github.com/AcademySoftwareFoundation/Imath/pull/241)\] 
+Move `numeric_limits<half>` specializations into half.h
+* \[[#236](https://github.com/AcademySoftwareFoundation/Imath/pull/236)\] 
+Change references to "master" branch to "main"
+
+## Version 3.1.4 (January 21, 2022)
+
+Patch release with miscellaneous bug/doc/build fixes.
+
+* \[[#229](https://github.com/AcademySoftwareFoundation/Imath/pull/229)\] 
+Remove some simple typos in the code
+* \[[#228](https://github.com/AcademySoftwareFoundation/Imath/pull/228)\] 
+Added missing check _M_IX86 or _M_X64 when using __lzcnt.
+* \[[#224](https://github.com/AcademySoftwareFoundation/Imath/pull/224)\] 
+SolveNormalizedCubic fix to return proper real root
+* \[[#223](https://github.com/AcademySoftwareFoundation/Imath/pull/223)\] 
+Add docs target only if not a subproject
+* \[[#222](https://github.com/AcademySoftwareFoundation/Imath/pull/222)\] 
+Fix docs race condition and make installation optional
+* \[[#220](https://github.com/AcademySoftwareFoundation/Imath/pull/220)\] 
+Remove dead PyImath code and references to ilmbase
+* \[[#219](https://github.com/AcademySoftwareFoundation/Imath/pull/219)\] 
+Use equalWithAbsError instead of equal operator for float
+* \[[#218](https://github.com/AcademySoftwareFoundation/Imath/pull/218)\] 
+Fix sphinx warnings and man page filenames
+* \[[#215](https://github.com/AcademySoftwareFoundation/Imath/pull/215)\] 
+Adding missing stdexcept header
+* \[[#214](https://github.com/AcademySoftwareFoundation/Imath/pull/214)\] 
+Use .x instead of operator[] for better SIMD auto-vectorization
+* \[[#213](https://github.com/AcademySoftwareFoundation/Imath/pull/213)\] 
+Remove extra project layer for the pyimath code
+* \[[#209](https://github.com/AcademySoftwareFoundation/Imath/pull/209)\] 
+Successor/predecessor functions use isnan() and isinf()
+* \[[#207](https://github.com/AcademySoftwareFoundation/Imath/pull/207)\] 
+Fix python imath export
+* \[[#202](https://github.com/AcademySoftwareFoundation/Imath/pull/202)\] 
+Cuda safety fixes
+* \[[#185](https://github.com/AcademySoftwareFoundation/Imath/pull/185)\] 
+Sort Imath source files
+* \[[#182](https://github.com/AcademySoftwareFoundation/Imath/pull/182)\] 
+Fix formatting in release notes
+
+## Version 3.1.3 (September 2, 2021)
+
+Patch release with miscellaneous fixes
+
+* \[[#204](https://github.com/AcademySoftwareFoundation/Imath/pull/204)\] 
+Fix undefined access of a vector when empty
+* \[[#203](https://github.com/AcademySoftwareFoundation/Imath/pull/203)\] 
+Require sphinx 4.0.3
+* \[[#201](https://github.com/AcademySoftwareFoundation/Imath/pull/201)\] 
+Build sphinx/doxygen docs with CMake
+* \[[#200](https://github.com/AcademySoftwareFoundation/Imath/pull/200)\] 
+Use PYIMATH_OVERRIDE_PYTHON_INSTALL_DIR to specify destination python modules
+* \[[#199](https://github.com/AcademySoftwareFoundation/Imath/pull/199)\] 
+Guard `__has_attribute` for compilers that don't support it
+* \[[#198](https://github.com/AcademySoftwareFoundation/Imath/pull/198)\] 
+Cuda safety fixes
+* \[[#194](https://github.com/AcademySoftwareFoundation/Imath/pull/194)\] 
+Replace stray Imath:: with IMATH_INTERNAL_NAMESPACE::
+
+## Version 3.1.2 (July 31, 2021)
+
+Patch release that fixes a Windows header issue.
+
+* \[[#190](https://github.com/AcademySoftwareFoundation/Imath/pull/190)\] 
+  Improve handling of ``#include <*intrin.h>``
+
+## Version 3.1.1 (July 20, 2021)
+
+Patch release that fixes a build failure on ARM64 macOS
+
+* \[[#184](https://github.com/AcademySoftwareFoundation/Imath/pull/184)\] Include ``<x86intrin.h>`` only if ``__x86_64__``
+
+## Version 3.1.0 (July 13, 2021)
+
+Minor release with new features:
+
+* Optimized half-to-float and float-to-half conversion, using F16C SSE
+  instruction set if available. Non-SSE conversion eliminates the
+  float-to-half exponent lookup table, and half-to-float conversion
+  provides a compile-time-optional bit shifting that is slower but
+  eliminates the need for the lookup table, for applications where
+  memory is limited.
+
+  Half-to-float and float-to-half conversion is also available as
+  C-language functions ``imath_half_to_float()`` and
+  ``imath_float_to_half()``.
+  
+  All new conversions produced identical results, and new options are
+  off by default to ensure backwards compatibility. See
+  https://imath.readthedocs.io for more info.
+  
+* ``noexcept`` specifier can be eliminated at compile-time via the
+  ``IMATH_USE_NOEXCEPT`` CMake option.
+
+* Python bindings:
+  * FixedArray objects support a "read only" state.
+  * FixedArray objects support python buffer protocol.
+
+* Optimized 4x4 matrix multiplication.
+
+### Merged Pull Requests
+
+* \[[#181](https://github.com/AcademySoftwareFoundation/Imath/pull/181)\] Clean up half lookup-table options and related docs
+* \[[#179](https://github.com/AcademySoftwareFoundation/Imath/pull/179)\] Remove dead code from half
+* \[[#178](https://github.com/AcademySoftwareFoundation/Imath/pull/178)\] Update Imath docs for 3.1
+* \[[#177](https://github.com/AcademySoftwareFoundation/Imath/pull/177)\] v3.1.0 release notes
+* \[[#175](https://github.com/AcademySoftwareFoundation/Imath/pull/175)\] Clean up library VERSION and SOVERSION 
+* \[[#173](https://github.com/AcademySoftwareFoundation/Imath/pull/173)\] Update README.md and INSTALL.md for 3.1 
+* \[[#172](https://github.com/AcademySoftwareFoundation/Imath/pull/172)\] Use CMAKE_INSTALL_FULL_LIBDIR/INCLUDEDIR for pkgconfig 
+* \[[#169](https://github.com/AcademySoftwareFoundation/Imath/pull/169)\] Add testInterop to test list in define_imath_test() 
+* \[[#168](https://github.com/AcademySoftwareFoundation/Imath/pull/168)\] Push/pop Windows warning pragma 
+* \[[#167](https://github.com/AcademySoftwareFoundation/Imath/pull/167)\] Clean up cmake lib symlink message 
+* \[[#166](https://github.com/AcademySoftwareFoundation/Imath/pull/166)\] Fix non-versioned library symlinks in debug build. 
+* \[[#165](https://github.com/AcademySoftwareFoundation/Imath/pull/165)\] Use CMAKE_<CONFIG>_POSTFIX for .pc file lib suffix. 
+* \[[#162](https://github.com/AcademySoftwareFoundation/Imath/pull/162)\] silence a few warnings noticed with -Weverything 
+* \[[#160](https://github.com/AcademySoftwareFoundation/Imath/pull/160)\] Clean up analysis_workflow.yml 
+* \[[#159](https://github.com/AcademySoftwareFoundation/Imath/pull/159)\] Add new macros to Doxyfile PREDEFINED 
+* \[[#158](https://github.com/AcademySoftwareFoundation/Imath/pull/158)\] Improve 4x4 matrix multiplication 
+* \[[#157](https://github.com/AcademySoftwareFoundation/Imath/pull/157)\] IMATH_NOEXCEPT macro to make noexcept a compile-time option 
+* \[[#156](https://github.com/AcademySoftwareFoundation/Imath/pull/156)\] PyImath read-only FixedArray state & python buffer protocol support 
+* \[[#155](https://github.com/AcademySoftwareFoundation/Imath/pull/155)\] Release notes for v3.0.4 
+* \[[#153](https://github.com/AcademySoftwareFoundation/Imath/pull/153)\] Configure ImathTest as optional standalone program 
+* \[[#150](https://github.com/AcademySoftwareFoundation/Imath/pull/150)\] Add __version__ attr to imath and imathnumpy python modules 
+* \[[#141](https://github.com/AcademySoftwareFoundation/Imath/pull/141)\] Enable C and lighter weight half <-> float conversion 
+
+## Version 3.0.5 (June 29, 2021)
+
+Patch release that fixes problems with library symlinks and
+pkg-config. Otherwise, no code changes.
+
+* \[[#172](https://github.com/AcademySoftwareFoundation/Imath/pull/172)\] Use CMAKE_INSTALL_FULL_LIBDIR/INCLUDEDIR for pkgconfig
+* \[[#166](https://github.com/AcademySoftwareFoundation/Imath/pull/166)\] Fix non-versioned library symlinks in debug build.
+* \[[#165](https://github.com/AcademySoftwareFoundation/Imath/pull/165)\] Use CMAKE_<CONFIG>_POSTFIX for .pc file lib suffix.
+
+## Version 3.0.4 (June 1, 2021)
+
+Patch release that corrects a problem with the release version number
+of v3.0.2:
+
+* \[[#147](https://github.com/AcademySoftwareFoundation/Imath/pull/147)\] Add #define for IMATH_VERSION_RELEASE_TYPE
+* \[[#145](https://github.com/AcademySoftwareFoundation/Imath/pull/145)\] Set IMATH_VERSION from Imath_VERSION instead of CMAKE_PROJECT_VERSION
+
+## Version 3.0.2 (May 16, 2021)
+
+Patch release with miscellaneous bug/build fixes:
+
+* \[[#142](https://github.com/AcademySoftwareFoundation/Imath/pull/142)\] Fix order of ${IMATH_SOVERSION}.${IMATH_SOREVISION}.${IMATH_SOAGE}
+* \[[#140](https://github.com/AcademySoftwareFoundation/Imath/pull/140)\] Fix regression in succf()/predf()          
+* \[[#139](https://github.com/AcademySoftwareFoundation/Imath/pull/139)\] Clean up setting of Imath version          
+* \[[#137](https://github.com/AcademySoftwareFoundation/Imath/pull/137)\] Don't impose C++14 on downstream projects  
+* \[[#135](https://github.com/AcademySoftwareFoundation/Imath/pull/135)\] Add section on python bindings             
+* \[[#133](https://github.com/AcademySoftwareFoundation/Imath/pull/133)\] Lib version                                
+
+## Version 3.0.1 (April 1, 2021)
+
+First release of Imath independent of OpenEXR.
+
+See the [porting guide](docs/PortingGuide2-3.md) for details about
+differences from previous releases.
+
+Summary:
+
+* Imath includes the half type, formerly in a separate Half library.
+* Headers are installed in ``Imath/`` subdirectory.
+* All appropriate methods are marked constexpr, noexcept
+* Appropriate declaration include CUDA ``__host__`` and ``__device__``
+  directives.
+* Throwing methods throw std exceptions instead of ``Iex``.
+* New Vec and Matrix interoperability constructors for conversion from
+  other similar type objects.
+* Symbol linkage visibility is limited to specific public symbols.
+* python bindings are off by default, available by setting ``PYTHON=ON``.
+* Deprecated features:
+  - ``std::numeric_limits`` replaces ``Imath::limits``.
+  - ``Int64`` and ``SInt64`` are deprecated in favor of ``uint64_t``
+    and ``int64_t``.
+
+## Version 3.0.1-beta (March 28, 2021)
+
+Beta patch release:
+
+* \[[#131](https://github.com/AcademySoftwareFoundation/Imath/pull/131)\] #if IMATH_FOREIGN_VECTOR_INTEROP around type detectors
+
+* \[[#130](https://github.com/AcademySoftwareFoundation/Imath/pull/130)\] Forward declarations only if header is not included
+
+## Version 3.0.0-beta (March 15, 2021)
+
+First release of Imath independent of OpenEXR.
+
+See the [porting guide](docs/PortingGuide2-3.md) for details about
+differences from previous releases.
+
+Summary and Key Changes:
+
+* Imath includes the half type, formerly in a separate Half library.
+* Headers are installed in ``Imath/`` subdirectory.
+* Header files have been pruned of extraneous ``#include``'s, which may
+  require updates to application source code.
+* All appropriate methods are marked constexpr, noexcept
+* Appropriate declaration include CUDA ``__host__`` and ``__device__``
+  directives.
+* Throwing methods throw std exceptions instead of ``Iex``.
+* New Vec and Matrix interoperability constructors for conversion from
+  other similar type objects.
+* Symbol linkage visibility is limited to specific public symbols.
+* Python bindings are off by default, available by setting ``PYTHON=ON``.
+* Deprecated features:
+  - ``std::numeric_limits`` replaces ``Imath::limits``.
+  - ``Int64`` and ``SInt64`` are deprecated in favor of ``uint64_t``
+    and ``int64_t``.
+
+### Merged Pull Requests
+
+* \[[#119](https://github.com/AcademySoftwareFoundation/Imath/pull/119)\] Enable policy 77 if possible.
+* \[[#117](https://github.com/AcademySoftwareFoundation/Imath/pull/117)\] Add/fix rst source for readthedocs
+* \[[#116](https://github.com/AcademySoftwareFoundation/Imath/pull/116)\] Add/fix doxygen comments
+* \[[#115](https://github.com/AcademySoftwareFoundation/Imath/pull/115)\] Add =delete for the int64_t Vec specializations
+* \[[#114](https://github.com/AcademySoftwareFoundation/Imath/pull/114)\] Disable analysis on PR/push
+* \[[#113](https://github.com/AcademySoftwareFoundation/Imath/pull/113)\] Clean up cmake/config
+* \[[#111](https://github.com/AcademySoftwareFoundation/Imath/pull/111)\] Rename IMATH_IMATH_NAMESPACE option to IMATH_NAMESPACE
+* \[[#110](https://github.com/AcademySoftwareFoundation/Imath/pull/110)\] Remove PyImathConfigInternal
+* \[[#109](https://github.com/AcademySoftwareFoundation/Imath/pull/109)\] build one python binding only
+* \[[#107](https://github.com/AcademySoftwareFoundation/Imath/pull/107)\] Add int64_t specializations of Vec and Box.
+* \[[#106](https://github.com/AcademySoftwareFoundation/Imath/pull/106)\] Replace Int64/SInt64 with uint64_t/int64_t
+* \[[#103](https://github.com/AcademySoftwareFoundation/Imath/pull/103)\] Drop support for exception-handling in PyImath
+* \[[#102](https://github.com/AcademySoftwareFoundation/Imath/pull/102)\] cmake improvements and fixes
+* \[[#100](https://github.com/AcademySoftwareFoundation/Imath/pull/100)\] Replace Iex::OverflowExc with std::invalid_argument
+* \[[#98](https://github.com/AcademySoftwareFoundation/Imath/pull/98)\] constexpr Vec2, Vec3, Vec4 constructors
+* \[[#97](https://github.com/AcademySoftwareFoundation/Imath/pull/97)\] restore original behavior of Matrix33<T>::setScale()
+* \[[#95](https://github.com/AcademySoftwareFoundation/Imath/pull/95)\] Build fixups for Visual Studio 2015
+* \[[#94](https://github.com/AcademySoftwareFoundation/Imath/pull/94)\] Add background and file/class-specific details to porting guide
+* \[[#93](https://github.com/AcademySoftwareFoundation/Imath/pull/93)\] Fix typo in comment in testHalfLimits
+* \[[#92](https://github.com/AcademySoftwareFoundation/Imath/pull/92)\] Replace ILMBASE_HAVE_LARGE_STACK with IMATH_HAVE_LARGE_STACK
+* \[[#91](https://github.com/AcademySoftwareFoundation/Imath/pull/91)\] Interoperability constructors
+* \[[#90](https://github.com/AcademySoftwareFoundation/Imath/pull/90)\] Fix compiler errors from recent changes
+* \[[#89](https://github.com/AcademySoftwareFoundation/Imath/pull/89)\] First stab at Imath 2->3 porting guide
+* \[[#88](https://github.com/AcademySoftwareFoundation/Imath/pull/88)\] PyImath installs headers into Imath subdirectory
+* \[[#87](https://github.com/AcademySoftwareFoundation/Imath/pull/87)\] constexpr as much of half as possible
+* \[[#83](https://github.com/AcademySoftwareFoundation/Imath/pull/83)\] Replace NOTICE with STATUS for CMake messages
+* \[[#82](https://github.com/AcademySoftwareFoundation/Imath/pull/82)\] Clean up Imath::Limits and numeric_limits issues
+* \[[#81](https://github.com/AcademySoftwareFoundation/Imath/pull/81)\] Reformat all Imath header comments to doxygen style
+* \[[#77](https://github.com/AcademySoftwareFoundation/Imath/pull/77)\] Change copyright notices to standard SPDX format
+* \[[#76](https://github.com/AcademySoftwareFoundation/Imath/pull/76)\] Incorrect constexpr in Imath::limits<half>, and missing test.
+* \[[#75](https://github.com/AcademySoftwareFoundation/Imath/pull/75)\] CI: add VFX2021 jobs, enable coverage analysis
+* \[[#74](https://github.com/AcademySoftwareFoundation/Imath/pull/74)\] noexcept all the things
+* \[[#73](https://github.com/AcademySoftwareFoundation/Imath/pull/73)\] Simplify definition of IMATH_RESTRICT for modern supported compilers
+* \[[#72](https://github.com/AcademySoftwareFoundation/Imath/pull/72)\] Eliminate normalize and length methods for Vec<inttype>
+* \[[#70](https://github.com/AcademySoftwareFoundation/Imath/pull/70)\] Adding missing header
+* \[[#69](https://github.com/AcademySoftwareFoundation/Imath/pull/69)\] [#bugfix] Install error on windows #68
+* \[[#67](https://github.com/AcademySoftwareFoundation/Imath/pull/67)\] Fix two typos in m22 tests causing out of bounds references
+* \[[#66](https://github.com/AcademySoftwareFoundation/Imath/pull/66)\] Use likely/unlikely to improve certain vector ops
+* \[[#65](https://github.com/AcademySoftwareFoundation/Imath/pull/65)\] Deprecate Math<T> in favor of std::
+* \[[#60](https://github.com/AcademySoftwareFoundation/Imath/pull/60)\] Make Matrix implementation more SIMD friendly
+* \[[#59](https://github.com/AcademySoftwareFoundation/Imath/pull/59)\] Imath::Vec -- omit exception-throwing methods from Cuda side
+* \[[#58](https://github.com/AcademySoftwareFoundation/Imath/pull/58)\] Make separate test calls for each test
+* \[[#57](https://github.com/AcademySoftwareFoundation/Imath/pull/57)\] Fixes the subproject test
+* \[[#56](https://github.com/AcademySoftwareFoundation/Imath/pull/56)\] Initial support for C wrappers
+* \[[#55](https://github.com/AcademySoftwareFoundation/Imath/pull/55)\] Fix non-linux platform CI
+* \[[#54](https://github.com/AcademySoftwareFoundation/Imath/pull/54)\] Combination of Half/Imath and HalfTest/ImathTest directories.
+* \[[#53](https://github.com/AcademySoftwareFoundation/Imath/pull/53)\] Stoped sonar cloud from running on PR
+* \[[#52](https://github.com/AcademySoftwareFoundation/Imath/pull/52)\] Fix problems with ImathInterval, and add test
+* \[[#51](https://github.com/AcademySoftwareFoundation/Imath/pull/51)\] First pass at sphinx/breathe/doxygen documentation
+* \[[#50](https://github.com/AcademySoftwareFoundation/Imath/pull/50)\] Removed all references to PYIMATH_VERSION, as it is redundant.
+* \[[#48](https://github.com/AcademySoftwareFoundation/Imath/pull/48)\] Set version to 3.0.0 and SOCURRENT to 26
+* \[[#47](https://github.com/AcademySoftwareFoundation/Imath/pull/47)\] Added Exc variants of all methods in frustum that required them.
+* \[[#46](https://github.com/AcademySoftwareFoundation/Imath/pull/46)\] Movement of all source directories into one top level src/ 
+* \[[#44](https://github.com/AcademySoftwareFoundation/Imath/pull/44)\] Fix copy/paste typos in Doxyfile and conf.py
+* \[[#43](https://github.com/AcademySoftwareFoundation/Imath/pull/43)\] Initial Doxygen/sphinx/breathe/readthedocs configuration
+* \[[#42](https://github.com/AcademySoftwareFoundation/Imath/pull/42)\] Made various Imath/ header methods inline
+* \[[#41](https://github.com/AcademySoftwareFoundation/Imath/pull/41)\] __host__ __device__ CUDA macro added to all header functions under Imath/
+* \[[#40](https://github.com/AcademySoftwareFoundation/Imath/pull/40)\] Update INSTALL info on namespaces and cmake options
+* \[[#39](https://github.com/AcademySoftwareFoundation/Imath/pull/39)\] Clean up of repo docs.
+* \[[#38](https://github.com/AcademySoftwareFoundation/Imath/pull/38)\] Added CUDA __host__ __device__ with macro to Vector, Matrix, Limits, \xe2\x80\xa6
+* \[[#37](https://github.com/AcademySoftwareFoundation/Imath/pull/37)\] Add .git-blame-ignore-revs to ignore reformatting
+* \[[#36](https://github.com/AcademySoftwareFoundation/Imath/pull/36)\] Disable clang-format for python bindings
+* \[[#32](https://github.com/AcademySoftwareFoundation/Imath/pull/32)\] Tune .clang-format to match existing style
+* \[[#30](https://github.com/AcademySoftwareFoundation/Imath/pull/30)\] Changed analysis sonarcloud tests, run on pull request.
+* \[[#29](https://github.com/AcademySoftwareFoundation/Imath/pull/29)\] Added CI testing and made necessary changes to pass those tests.
+* \[[#27](https://github.com/AcademySoftwareFoundation/Imath/pull/27)\] Simplest CUDA half type conflict resolution implementation.
+* \[[#25](https://github.com/AcademySoftwareFoundation/Imath/pull/25)\] Used macros to allow compilation with C++11 and constexpr
+* \[[#24](https://github.com/AcademySoftwareFoundation/Imath/pull/24)\] b"removed pragma to disable clang's -Wself-assign-overloaded"
+* \[[#23](https://github.com/AcademySoftwareFoundation/Imath/pull/23)\] changed assert()\] to throw, which is what the original Iex macro ASSERT()\] macro did
+* \[[#21](https://github.com/AcademySoftwareFoundation/Imath/pull/21)\] First pass at adding constexpr where useful
+* \[[#20](https://github.com/AcademySoftwareFoundation/Imath/pull/20)\] Speedtest and Inversion python bindings for Arrays
+* \[[#19](https://github.com/AcademySoftwareFoundation/Imath/pull/19)\] clean up Imath repo docs
+* \[[#18](https://github.com/AcademySoftwareFoundation/Imath/pull/18)\] Transfer of PyImath history and source to Imath
+* \[[#17](https://github.com/AcademySoftwareFoundation/Imath/pull/17)\] fixed typo in README.md
+* \[[#15](https://github.com/AcademySoftwareFoundation/Imath/pull/15)\] further edits of README.md
+* \[[#14](https://github.com/AcademySoftwareFoundation/Imath/pull/14)\] First complete draft of README.md for the Imath project
+
+## Inherited History from OpenEXR
+
+History dated before May 9th, 2020 has been inherited from
+https://github.com/AcademySoftwareFoundation/openexr, omitting commits
+(via [git-filter-repo](https://github.com/newren/git-filter-repo)) not
+pertaining to files now a part of the Imath project.
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1ffdccb
--- /dev/null
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+cmake_minimum_required(VERSION 3.12)
+
+if(POLICY CMP0074)
+  cmake_policy(SET CMP0074 NEW)
+endif()
+
+if(POLICY CMP0077)
+  # enable variables set outside to override options
+  cmake_policy(SET CMP0077 NEW)
+endif()
+
+# Imath version
+
+project(Imath VERSION 3.1.9 LANGUAGES C CXX)
+
+set(IMATH_VERSION_RELEASE_TYPE "" CACHE STRING "Extra version tag string for Imath build, such as -dev, -beta1, etc.")
+
+set(IMATH_VERSION ${Imath_VERSION})
+set(IMATH_VERSION_API "${Imath_VERSION_MAJOR}_${Imath_VERSION_MINOR}")
+
+# Library/shared-object version using libtool versioning policy.
+# See https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+#
+# Library API version (CMake's library VERSION attribute) is of the
+# form CURRENT.REVISION.AGE; the CMake SOVERSION attribute corresonds
+# to just CURRENT. These produce a .so and a symlink symlink, e.g.:
+# libImath-3_1.so.29 -> libImath-3_1.so.29.0.0
+#                 ^                     ^  ^ ^
+#                 |                     |  | |
+#                 CURRENT               |  | AGE
+#                                       |  REVISION 
+#                                       CURRENT
+# When updating:
+#   1. no API change: CURRENT.REVISION+1.AGE
+#   2. API added:     CURRENT+1.0.AGE+1
+#   3. API changed:   CURRENT+1.0.0
+#
+set(IMATH_LIBTOOL_CURRENT 29)
+set(IMATH_LIBTOOL_REVISION 8)
+set(IMATH_LIBTOOL_AGE 0)
+set(IMATH_LIB_VERSION "${IMATH_LIBTOOL_CURRENT}.${IMATH_LIBTOOL_REVISION}.${IMATH_LIBTOOL_AGE}")
+set(IMATH_LIB_SOVERSION ${IMATH_LIBTOOL_CURRENT})
+
+# ImathSetup.cmake declares all the configuration variables visible
+# in cmake-gui or similar and the rest of the global
+# project setup. Check the context to see what is configurable.
+include(config/ImathSetup.cmake)
+
+message(STATUS "Configure ${IMATH_PACKAGE_NAME}, library API version: ${IMATH_LIB_VERSION}")
+
+# Config headers and package config files
+add_subdirectory(config)
+
+# Utility function for the repeated boilerplate of defining the libraries
+include(config/LibraryDefine.cmake)
+
+# Source code is in src/Imath
+add_subdirectory(src/Imath)
+
+# Imath_DIR points to the location of ImathConfig.cmake, which tells
+# downstream projects where to find Imath, via find_package(Imath).
+set(Imath_DIR "${CMAKE_CURRENT_BINARY_DIR}/config" CACHE PATH "" FORCE)
+
+# Add an empty ImathTargets.cmake file for the config to use. It can
+# be empty since we already defined the targets in add_subdirectory().
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/config/ImathTargets.cmake" "# Dummy file")
+
+option(PYTHON "Set ON to compile PyImath bindings")
+if (PYTHON)
+  add_subdirectory(src/python)
+endif()
+
+option(BUILD_DOCS "Set ON to build readthedocs documentation")
+if (BUILD_DOCS AND NOT IMATH_IS_SUBPROJECT)
+  option(INSTALL_DOCS "Set ON to install html documentation" ON)
+  add_subdirectory(docs)
+endif()
+
+# If you want to use ctest to configure, build and
+# upload the results, cmake has builtin support for
+# submitting to CDash, or any server who speaks the
+# same protocol
+# 
+# These settings will need to be set for your environment,
+# and then a script such as the example in
+#
+# cmake/SampleCTestScript.cmake
+#
+# edited and placed into the CI system, then run:
+#
+# cmake -S cmake/SampleCTestScript.cmake
+#
+# [or whatever you name the file you edit]
+# 
+#set(CTEST_PROJECT_NAME "Imath")
+#set(CTEST_NIGHTLY_START_TIME "01:01:01 UTC")
+#set(CTEST_DROP_METHOD "http") # there are others...
+#set(CTEST_DROP_SITE "open.cdash.org")
+#set(CTEST_DROP_LOCATION "/submit.php?project=MyProject")
+#set(CTEST_DROP_SITE_CDASH TRUE)
+include(CTest)
+if(BUILD_TESTING AND NOT IMATH_IS_SUBPROJECT)
+  enable_testing()
+  add_subdirectory(src/ImathTest)
+endif()
+
+# Including this module will add a `clang-format` target to the build
+# if the clang-format executable can be found. Only do this if we are
+# top level.
+if(NOT IMATH_IS_SUBPROJECT)
+  include(cmake/clang-format.cmake)
+endif()
+
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644 (file)
index 0000000..3501232
--- /dev/null
@@ -0,0 +1,52 @@
+# Code of Conduct
+
+Imath is a sub-project of the OpenEXR project, which abides by Linux
+Foundation's code of conduct, which you can read in full
+[here](https://lfprojects.org/policies/code-of-conduct).
+
+Our covenant includes:
+
+* Treat each other with respect, professionalism, fairness, and
+  sensitivity to our many differences and strengths, including in
+  situations of high pressure and urgency.
+
+* Never harass or bully anyone verbally, physically or sexually.
+
+* Never discriminate on the basis of personal characteristics or group
+  membership.
+
+* Communicate constructively and avoid demeaning or insulting behavior
+  or language.
+
+* Seek, accept, and offer objective work criticism, and acknowledge
+  properly the contributions of others.
+
+* Be honest about your own qualifications, and about any circumstances
+  that might lead to conflicts of interest.
+
+* Respect the privacy of others and the confidentiality of data you
+  access.
+
+* With respect to cultural differences, be conservative in what you do
+  and liberal in what you accept from others, but not to the point of
+  accepting disrespectful, unprofessional or unfair or unwelcome
+  behavior or advances.
+
+* Promote the rules of this Code and take action (especially if you
+  are in a leadership position) to bring the discussion back to a more
+  civil level whenever inappropriate behaviors are observed.
+
+* Stay on topic: Make sure that you are posting to the correct channel
+  and avoid off-topic discussions. Remember when you update an issue
+  or respond to an email you are potentially sending to a large number
+  of people.
+
+* Step down considerately: participants in every project come and go,
+  and LF Projects is no different. When you leave or disengage from
+  the project, in whole or in part, we ask that you do so in a way
+  that minimizes disruption to the project. This means you should tell
+  people you are leaving and take the proper steps to ensure that
+  others can pick up where you left off.
+
+To report incidents or to appeal reports of incidents, send email to
+the Manager of LF Projects at manager@lfprojects.org.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644 (file)
index 0000000..fb5bf99
--- /dev/null
@@ -0,0 +1,449 @@
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright (c) Contributors to the OpenEXR Project -->
+
+# Contributing to Imath
+
+Thank you for your interest in contributing to Imath. This document
+explains our contribution process and procedures:
+
+* [Getting Information](#Getting-Information)
+* [Legal Requirements](#Legal-Requirements)
+* [Development Workflow](#Development-Workflow)
+* [Coding Style](#Coding-Style)
+* [Versioning Policy](#Versioning-Policy)
+* [Creating a Release](#Creating-a-Release)
+
+Imath is a sub-project of
+[OpenEXR](https://github.com/AcademySoftwareFoundation/openexr) and
+follows OpenEXR's governance and contribution policies.
+
+For a description of the roles and responsibilities of the various
+members of the OpenEXR community, see [GOVERNANCE](GOVERNANCE.md), and
+for further details, see the OpenEXR project's [Technical
+Charter](ASWF/charter/OpenEXR-Technical-Charter.md). Briefly,
+a "contributor" is anyone who submits content to the project, a
+"committer" reviews and approves such submissions, and the "Technical
+Steering Committee" provides general project oversight and governance.
+
+## Getting Information
+
+There are two primary ways to connect with the Imath project:
+
+* The [openexr-dev](https://lists.aswf.io/g/openexr-dev) mail list:
+  This is a development focused mail list with a deep history of
+  technical conversations and decisions that have shaped the project.
+
+* [GitHub Issues](https://github.com/AcademySoftwareFoundation/Imath/issues): GitHub
+  Issues are used both to track bugs and to discuss feature requests.
+
+### How to Ask for Help
+
+If you have trouble installing, building, or using the library, but
+there's not yet reason to suspect you've encountered a genuine bug,
+start by posting a question to the
+[openexr-dev](http://lists.aswf.io/openexr-dev) mailing list. This is
+the place for question such has "How do I...".
+
+### How to Report a Bug
+
+Imath use GitHub's issue tracking system for bugs and enhancements:
+https://github.com/AcademySoftwareFoundation/Imath/issues
+
+If you are submitting a bug report, please be sure to note which
+version of Imath you are using, on what platform (OS/version, which
+compiler you used, and any special build flags or other unusual
+environmental issues). Please give a specific account of
+
+* what you tried
+* what happened
+* what you expected to happen instead
+
+with enough detail that others can reproduce the problem.
+
+### How to Request a Change
+
+Open a GitHub issue: https://github.com/AcademySoftwareFoundation/Imath/issues.
+
+Describe the situation and the objective in as much detail as
+possible. Feature requests will almost certainly spawn a discussion
+among the project community.
+
+### How to Report a Security Vulnerability
+
+If you think you've found a potential vulnerability in Imath, please
+refer to [SECURITY.md](SECURITY.md) to responsibly disclose it.
+
+### How to Contribute a Bug Fix or Change
+
+To contribute code to the project, first read over the [GOVERNANCE](GOVERNANCE.md) page to understand the roles involved. You'll need:
+
+* A good knowledge of git.
+
+* A fork of the GitHub repo.
+
+* An understanding of the project's development workflow.
+
+* Legal authorization, that is, you need to have signed a contributor
+  License Agreement. See below for details.
+
+## Legal Requirements
+
+Imath is a project of the Academy Software Foundation and follows the
+open source software best practice policies of the Linux Foundation.
+
+### License
+
+Imath is licensed under the [BSD-3-Clause](LICENSE.md)
+license. Contributions to the library should abide by that standard
+license.
+
+### Contributor License Agreements
+
+Developers who wish to contribute code to be considered for inclusion
+in the OpenEXR distribution must first complete a **Contributor
+License Agreement**.
+
+To contribute to Imath or OpenEXR, you must sign a CLA through the
+[EasyCLA](https://contributor.easycla.lfx.linuxfoundation.org/#/cla/project/2e8710cb-e379-4116-a9ba-964f83618cc5/user/564e571e-12d7-4857-abd4-898939accdd7?redirect=https:%2F%2Fgithub.com%2FAcademySoftwareFoundation%2Fopenexr%2Fpull%2F1154)
+system, which is integrated with GitHub as a pull request check.
+
+Sign the form through [this
+link](https://contributor.easycla.lfx.linuxfoundation.org/#/cla/project/2e8710cb-e379-4116-a9ba-964f83618cc5/user/564e571e-12d7-4857-abd4-898939accdd7?redirect=https:%2F%2Fgithub.com%2FAcademySoftwareFoundation%2Fopenexr%2Fpull%2F1154)
+prior to submitting a pull request. If you submit a pull request
+before the form is signed, the "linux-foundation-easycla" check will
+fail and a red "NOT COVERED" button will appear in the PR
+comments. Click that link to sign the form.
+
+* If you are an individual writing the code on your own time and
+  you're **sure** you are the sole owner of any intellectual property you
+  contribute, you can sign the CLA as an **Individual Contributor**.
+
+* If you are writing the code as part of your job, or if your employer
+  retains ownership to intellectual property you create, no matter how
+  small, then your company's legal affairs representatives should sign
+  a **Corporate Contributor Licence Agreement**. If your company already
+  has a signed CCLA on file, ask your local CLA manager to add you
+  (via your GitHub account name/email address) to your company's
+  "approved" list.
+
+The downloadable PDF's on the EasyCLA page are provided for reference
+only. To execute the signature, sign the form online through the
+relevant links.
+
+The OpenEXR CLAs are the standard forms used by Linux Foundation
+projects and [recommended by the ASWF
+TAC](https://github.com/AcademySoftwareFoundation/tac/blob/main/process/contributing.md#contributor-license-agreement-cla).
+
+### Commit Sign-Off
+
+Every commit must be signed off.  That is, every commit log message
+must include a “`Signed-off-by`” line (generated, for example, with
+“`git commit --signoff`”), indicating that the committer wrote the
+code and has the right to release it under the [BSD-3-Clause](LICENSE.md)
+license. See https://github.com/AcademySoftwareFoundation/tac/blob/main/process/contributing.md#contribution-sign-off for more information on this requirement.
+
+## Development Workflow
+
+### Git Basics
+
+Working with Imath requires understanding a significant amount of
+Git and GitHub based terminology. If you’re unfamiliar with these
+tools or their lingo, please look at the [GitHub
+Glossary](https://help.github.com/articles/github-glossary/) or browse
+[GitHub Help](https://help.github.com/).
+
+To contribute, you need a GitHub account. This is needed in order to
+push changes to the upstream repository, via a pull request.
+
+You will also need Git installed on your local development machine. If
+you need setup assistance, please see the official [Git
+Documentation](https://git-scm.com/doc).
+
+### Repository Structure and Commit Policy
+
+The Imath repository uses a simple branching and merging strategy.
+
+All development work is done directly on the ``main`` branch. The ``main``
+branch represents the bleeding-edge of the project and most
+contributions should be done on top of it.
+
+After sufficient work is done on the ``main`` branch and the Imath
+leadership determines that a release is due, we will bump the relevant
+internal versioning and tag a commit with the corresponding version
+number, e.g. v2.0.1. Each minor version also has its own “Release
+Branch”, e.g. RB-1.1. This marks a branch of code dedicated to that
+``major.minor version``, which allows upstream bug fixes to be
+cherry-picked to a given version while still allowing the ``main``
+branch to continue forward onto higher versions. This basic repository
+structure keeps maintenance low, while remaining simple to understand.
+
+To reiterate, the ``main`` branch represents the latest development
+version, so beware that it may include untested features and is not
+generally stable enough for release.  To retrieve a stable version of
+the source code, use one of the release branches.
+
+### The Git Workflow
+
+This development workflow is sometimes referred to as
+[OneFlow](https://www.endoflineblog.com/oneflow-a-git-branching-model-and-workflow). It
+leads to a simple, clean, linear edit history in the repo.
+
+The Imath GitHub repo allows rebase merging and disallows merge
+commits and squash merging. This ensures that the repo edit history
+remains linear, avoiding the "bubbles" characteristic of the
+[GitFlow](https://www.endoflineblog.com/gitflow-considered-harmful)
+workflow.
+
+### Use the Fork, Luke.
+
+In a typical workflow, you should **fork** the Imath repository to
+your account. This creates a copy of the repository under your user
+namespace and serves as the “home base” for your development branches,
+from which you will submit **pull requests** to the upstream
+repository to be merged.
+
+Once your Git environment is operational, the next step is to locally
+**clone** your forked Imath repository, and add a **remote**
+pointing to the upstream Imath repository. These topics are
+covered in the GitHub documentation [Cloning a
+repository](https://help.github.com/articles/cloning-a-repository/)
+and [Configuring a remote for a
+fork](https://help.github.com/articles/configuring-a-remote-for-a-fork/),
+but again, if you need assistance feel free to reach out on the
+openexr-dev@lists.aswf.io mail list.
+
+### Pull Requests
+
+Contributions should be submitted as Github pull requests. See
+[Creating a pull request](https://help.github.com/articles/creating-a-pull-request/)
+if you're unfamiliar with this concept. 
+
+The development cycle for a code change should follow this protocol:
+
+1. Create a topic branch in your local repository, following the naming format
+"feature/<your-feature>" or "bugfix/<your-fix>".
+
+2. Make changes, compile, and test thoroughly. Code style should match existing
+style and conventions, and changes should be focused on the topic the pull
+request will be addressing. Make unrelated changes in a separate topic branch
+with a separate pull request.
+
+3. Push commits to your fork.
+
+4. Create a Github pull request from your topic branch.
+
+5. Pull requests will be reviewed by project committers and contributors,
+who may discuss, offer constructive feedback, request changes, or approve
+the work.
+
+6. Upon receiving the required number of committer approvals (as
+outlined in [Required Approvals](#required-approvals)), a committer
+other than the PR contributor may merge changes into the ``main``
+branch.
+
+### Code Review and Required Approvals
+
+Modifications of the contents of the Imath repository are made on a
+collaborative basis. Anyone with a GitHub account may propose a
+modification via pull request and it will be considered by the project
+committers.
+
+Pull requests must meet a minimum number of committer approvals prior
+to being merged. Rather than having a hard rule for all PRs, the
+requirement is based on the complexity and risk of the proposed
+changes, factoring in the length of time the PR has been open to
+discussion. The following guidelines outline the project's established
+approval rules for merging:
+
+* Core design decisions, large new features, or anything that might be
+perceived as changing the overall direction of the project should be
+discussed at length in the mail list or TSC meetings before any PR is
+submitted, in order to solicit feedback, try to get as much consensus
+as possible, and alert all the stakeholders to be on the lookout for
+the eventual PR when it appears.
+
+* Trivial changes that don't affect functionality (typos, docs, tests)
+can be approved by the committer without review, after waiting at
+least 48 hours.
+
+* Big changes that can alter behavior, add major features, or present
+a high degree of risk should be signed off by TWO committers, ideally
+one of whom should be the "owner" for that section of the codebase (if
+a specific owner has been designated). If the person submitting the PR
+is him/herself the "owner" of that section of the codebase, then only
+one additional committer approval is sufficient. But in either case, a
+48 hour minimum is helpful to give everybody a chance to see it,
+unless it's a critical emergency fix (which would probably put it in
+the previous "small fix" category, rather than a "big feature").
+
+* Escape valve: big changes can nonetheless be merged by a single
+committer if the PR has been open for over two weeks without any
+unaddressed objections from other committers. At some point, we have
+to assume that the people who know and care are monitoring the PRs and
+that an extended period without objections is really assent.
+
+Approval must be from committers who are not authors of the change. If
+one or more committers oppose a proposed change, then the change
+cannot be accepted unless:
+
+* Discussions and/or additional changes result in no committers
+objecting to the change. Previously-objecting committers do not
+necessarily have to sign-off on the change, but they should not be
+opposed to it.
+
+* The change is escalated to the TSC and the TSC votes to approve the
+change.  This should only happen if disagreements between committers
+cannot be resolved through discussion.
+
+Committers may opt to elevate significant or controversial
+modifications to the TSC by assigning the `tsc-review` label to a pull
+request or issue. The TSC should serve as the final arbiter where
+required.
+
+### Test Policy
+
+All functionality in the library must be covered by an automated
+test. Each library has a companion ``Test`` project,
+e.g. ``ImathTest``, ``HalfTest``, ``PyImathTest``.  This test suite is
+collectively expected to validate the behavior of very part of the
+library.
+
+* All new functionality should be accompanied by a test that validates
+  its behavior.
+
+* Any change to existing functionality should have tests added if they
+  don't already exist.
+
+The test should should be run, via:
+
+    make test
+
+before submitting a pull request.
+
+## Coding Style
+
+#### Formatting
+
+The coding style of the library source code is enforced via Clang format, with the configuration defined in [.clang-format](.clang-format).
+
+When modifying existing code, follow the surrounding formatting
+conventions so that new or modified code blends in with the current
+code.
+
+* Indent with spaces, never tabs. Each indent level should be 4 spaces.
+
+* Function return types go on a separate line:
+
+        template <class T>
+        constexpr inline T
+        abs (T a)
+        {
+            return (a > T (0)) ? a : -a;
+        }
+
+* Use a space between function names and the following parentheses unless there are no arguments:
+        V3f v (0.0);
+        v.normalize();
+
+* Place curly braces on their own lines:
+
+#### Naming Conventions
+
+* In general, classes and template type names should start with upper
+  case and capitalize new words: `class CustomerList;`
+
+* In general, local variables should use camelCase. Macros and
+  constants should use `ALL_CAPS`.
+
+* Member fields in a class should start with an underscore. No other
+  variables should begin with underscore.
+
+#### File conventions
+
+C++ implementation should be named `*.cpp`. Headers should be named `.h`.
+
+All headers should contain:
+
+    #pragma once
+
+#### Type Conventions
+
+To clarify the intention, prefer to cast between types using
+``static_cast<>()`` rather than the basic C-style ``()`` notation:
+
+    // good:
+    size_t x = static_cast <size_t> (y);
+
+    // bad:
+    x = (size_t) y;
+    x = size_t (y);
+
+Prefer to use ``std::numeric_limits<>`` instead of preprocessor
+define's such as ``INT_MAX``:
+
+    // good:
+    if (x > std::numeric_limits<int>::max())
+        std::cout << "That's too freakin' high.\n";
+
+    // bad:
+    if (x > INT_MAX)
+
+#### Copyright Notices
+
+All new source files should begin with a copyright and license stating:
+
+    //
+    // SPDX-License-Identifier: BSD-3-Clause
+    // Copyright (c) Contributors to the OpenEXR Project. 
+    //
+    
+#### Third-party libraries
+
+Prefer C++11 `std` over boost where possible.  Use boost classes you
+already see in the code base, but check with the project leadership
+before adding new boost usage.
+
+#### Comments and Doxygen
+
+Comment philosophy: try to be clear, try to help teach the reader
+what's going on in your code.
+
+Prefer C++ comments (starting line with `//`) rather than C comments
+(`/* ... */`).
+
+For public APIs, use Doxygen-style comments (start with `///`), such as:
+
+    /// Explanation of a class.  Note THREE slashes!
+    /// Also, you need at least two lines like this.  If you don't have enough
+    /// for two lines, make one line blank like this:
+    ///
+    class myclass {
+        ....
+        float foo;  ///< Doxygen comments on same line look like this
+    }
+
+## Versioning Policy
+
+Imath uses [semantic versioning](https://semver.org), which labels
+each version with three numbers: ``major.minor.patch``, where:
+
+* ``major`` - indicates incompatible API changes
+* ``minor`` - indicates functionality added in a backwards-compatible manner
+* ``patch`` - indicates backwards-compatible bug fixes 
+
+## Creating a Release
+
+To create a new release from the ``main`` branch:
+
+1. Update the release notes in ``CHANGES.md``.
+
+   Write a high-level summary of the features and
+   improvements. Include the summary in ``CHANGES.md`` and also in the
+   Release comments.
+
+   Include the log of all PR's included beyond the previous release. 
+       
+2. Create a new release on the GitHub Releases page.
+
+3. Tag the release with name beginning with ``v``', e.g. ``v2.3.0``.
+
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
new file mode 100644 (file)
index 0000000..2298bf0
--- /dev/null
@@ -0,0 +1,38 @@
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright (c) Contributors to the OpenEXR Project -->
+
+This is a list of contributors to the Imath project, sorted
+alphabetically by first name.
+
+If you know of missing, please email: info@openexr.com.
+
+* Andrew Kunz 
+* Antonio Rojas 
+* Cary Phillips 
+* Christina Tempelaar-Lietz 
+* Daniel Kaneider 
+* Ed Hanway 
+* Eric Wimmer 
+* Florian Kainz 
+* Gregorio Litenstein 
+* Harry Mallon 
+* Huibean Luo 
+* Jens Lindgren 
+* Ji Hun Yu 
+* Jonathan Stone 
+* Kimball Thurston 
+* Larry Gritz 
+* Liam Fernandez 
+* Mark Sisson 
+* Nicholas Yue 
+* Nick Porcino 
+* Nick Rasmussen 
+* Nicolas Chauvet 
+* Owen Thompson 
+* Peter Hillman 
+* Piotr Stanczyk 
+* Ralph Potter 
+* Simon Boorer 
+* Thanh Ha 
+* Thorsten Kaufmann 
+* Yujie Shu 
diff --git a/GOVERNANCE.md b/GOVERNANCE.md
new file mode 100644 (file)
index 0000000..e286203
--- /dev/null
@@ -0,0 +1,156 @@
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright (c) Contributors to the OpenEXR Project -->
+
+# OpenEXR Project Roles and Responsibilities
+
+Imath is a subproject of OpenEXR and follows OpenEXR's governance and
+contribution policies. OpeneEXR is a project of the Academy Software
+Foundation and in turn relies on the ASWF governance policies,
+supported by the Linux Foundation.
+
+There are three primary project roles: a "contributor" submits code to the
+project; a "committer" approves code to be included into the project; and
+the "Technical Steering Committee" (TSC) provides overall high-level
+project guidance.
+
+* [Contributors](#Contributors)
+* [Committers](#Committers)
+* [Technical Steering Committee](#Technical-Steering-Committee)
+
+## Contributors
+
+The OpenEXR project grows and thrives from assistance from
+contributors.  A contributor is anyone in the community who submits
+code, bug fixes, documentation, or other technical artifacts to the
+project. However, such contributions must be approved by a project
+committer before they become a part of the project.
+
+Anyone can be a contributor. You need no formal approval from the
+project, beyond the legal forms.
+
+### How to Become a Contributor
+
+* Review the coding standards to ensure your contribution is in line
+  with the project's coding and styling guidelines.
+
+* Sign the Individual CLA, or have your organization sign the Corporate CLA.
+
+* Submit your code as a PR with the appropriate DCO sign-off.
+
+## Committers
+
+Project committers have merge access on the Imath GitHub repository
+and are responsible for approving submissions by contributors.
+
+### Committer Responsibilities
+
+Typical activities of a committer include:
+
+* Helping users and novice contributors.
+
+* Ensuring a response to questions posted to the
+  openexr-dev@lists.aswf.io mailing list.
+
+* Contributing code and documentation changes that improve the
+  project.
+
+* Reviewing and commenting on issues and pull requests.
+
+* Ensuring that changes and new code meet acceptable standards and are
+  in the long-term interest of the project.
+
+* Participating in working groups.
+
+* Merging pull requests.
+
+### How to Become a Committer
+
+Any existing committer can nominate an individual making significant
+and valuable contributions to the OpenEXR project to become a new
+committer.  New committers are approved by vote of the TSC.
+
+If you are interested in becoming a committer, contact the TSC at
+info@openexr.com.
+
+## Technical Steering Committee
+
+The Technical Steering Committee (TSC) oversees the overall technical
+direction of OpenEXR, as defined in the project
+[charter](ASWF/charter/OpenEXR-Technical-Charter.md).  This
+charter defines the TSC member terms and succession policies.
+
+The responsibilities of the TSC include:
+
+* Coordinating technical direction of the project.
+
+* Project governance and contribution policy.
+
+* GitHub repository administration.
+
+* Maintaining the list of additional committers.
+
+* Appointing representatives to work with other open source or open
+  standards communities.
+
+* Discussions, seeking consensus, and where necessary, voting on
+  technical matters relating to the code base that affect multiple
+  projects.
+
+* Coordinating any marketing, events, or communications regarding the
+  project.
+
+The TSC elects a Chair person, who acts as the project manager,
+organizing meetings and providing oversight to project
+administration. The Chair is elected by the TSC.  The Chair also
+serves as the OpenEXR representative on the Academy Software
+Foundation (ASWF) Technical Advisory Council (TAC). The chair
+represents the project at ASWF TAC meetings.
+
+### Current TSC Members
+
+* Cary Phillips (chair) - Industrial Light & Magic
+* Rod Bogart - Epic Games
+* Larry Gritz - Sony Pictures ImageWorks
+* Peter Hillman - Weta Digital, Ltd.
+* Kimball Thurston - Weta Digital, Ltd.
+* Nick Porcino - Pixar Animation Studios
+* Christina Tempelaar-Lietz - Industrial Light & Magic
+* Joseph Goldstone - ARRI
+* John Mertic - The Linux Foundation
+
+### TSC Meetings
+
+All meetings of the TSC are open to participation by any member of the
+OpenEXR community. Meeting times are listed in the [ASWF technical
+community calendar](https://lists.aswf.io/g/tac/calendar), currently
+each Thursday at 1:30pm Pacific Time via Zoom video conference.  The
+TSC Chair moderates the meeting, or appoints another TSC member to
+moderate in his or her absence.
+
+Items are added to the TSC agenda which are considered contentious or
+are modifications of governance, contribution policy, TSC membership,
+or release process, in addition to topics involving the high-level
+technical direction of the project.
+
+The intention of the agenda is not to approve or review all
+patches. That should happen continuously on GitHub and be handled by
+the larger group of committers.
+
+Any community member or contributor can ask that something be reviewed
+by the TSC at the meeting by logging a GitHub issue. Any committer,
+TSC member, or the meeting chair can bring the issue to the TSC's
+attention by applying the `TSC` label.
+
+Prior to each TSC meeting, the meeting chair will share the agenda with members
+of the TSC. TSC members can also add items to the agenda at the beginning of
+each meeting. The meeting chair and the TSC cannot veto or remove items.
+
+The TSC may invite additional persons to participate in a non-voting capacity.
+
+The meeting chair is responsible for archiving the minutes, stored at 
+https://wiki.aswf.io/display/OEXR/TSC+Meetings.
+
+Due to the challenges of scheduling a global meeting with participants
+in several time zones, the TSC will seek to resolve as many agenda
+items as possible outside of meetings on the public mailing list.
+
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644 (file)
index 0000000..dacc461
--- /dev/null
@@ -0,0 +1,11 @@
+Copyright Contributors to the OpenEXR Project. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..92b4319
--- /dev/null
+++ b/README.md
@@ -0,0 +1,110 @@
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright (c) Contributors to the OpenEXR Project -->
+
+[![License](https://img.shields.io/github/license/AcademySoftwareFoundation/Imath)](LICENSE.md)
+[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2799/badge)](https://bestpractices.coreinfrastructure.org/projects/2799)
+[![Build Status](https://dev.azure.com/academysoftwarefoundation/Academy%20Software%20Foundation/_apis/build/status/academysoftwarefoundation.Imath)](https://dev.azure.com/academysoftwarefoundation/Academy%20Software%20Foundation/_build?definitionId=4&_a=summary)
+[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=AcademySoftwareFoundation_Imath&metric=alert_status)](https://sonarcloud.io/dashboard?id=AcademySoftwareFoundation_Imath)
+
+# Imath
+
+Imath is a basic, light-weight, and efficient C++ representation of 2D
+and 3D vectors and matrices and other simple but useful mathematical
+objects, functions, and data types common in computer graphics
+applications, including the “half” 16-bit floating-point type.
+
+Imath also includes optional python bindings for all types and
+functions, including optimized implementations of vector and matrix
+arrays.
+
+## Project Mission
+
+The goals of the Imath project are simplicity, ease of use,
+correctness and verifiability, performance, and breadth of
+adoption. Imath is not intended to be a comprehensive linear algebra
+or numerical analysis package.
+
+## Project Governance
+
+OpenEXR is a project of the [Academy Software
+Foundation](https://www.aswf.io). See the project's [governance
+policies](GOVERNANCE.md), [contribution guidelines](CONTRIBzuTING.md), and [code of conduct](CODE_OF_CONDUCT)
+for more information.
+
+The OpenEXR project is dedicated to promoting a harassment-free
+community. Read our [code of conduct](CODE_OF_CONDUCT.md).
+
+## Supported Platforms
+
+Imath builds on Linux, macOS, Microsoft Windows, and is
+cross-compilable on other systems.
+
+## A Note about Versioning
+
+Because Imath was originally distributed as a part of OpenEXR, it has
+already had two major release versions, as a part of OpenEXR v1 and
+v2. To avoid confusion with these original releases, the first
+version of Imath released independently of OpenEXR is Version v3.0. To
+be clear, the versioning and release of Imath is no longer tied to
+OpenEXR.
+
+# Quick Start
+
+Technical documentation for the Imath classes and functions can be found at
+https://imath.readthedocs.io.
+
+See the [Install](https://imath.readthedocs.io) instructions for
+how to download, install, or build Imath from source.
+
+If you encounter problems compiling code or building projects written
+with an earlier release of Imath, the [porting
+guide](https://openexr.readthedocs.io/en/latest/PortingGuide.html)
+explains some of the differences and how to address them.
+
+# Community
+
+* **Ask a question:**
+
+  - Email: openexr-dev@lists.aswf.io
+
+  - Slack: [academysoftwarefdn#openexr](https://academysoftwarefdn.slack.com/archives/CMLRW4N73)
+
+* **Attend a meeting:**
+
+  - Technical Steering Committee meetings are open to the
+    public, fortnightly on Thursdays, 1:30pm Pacific Time.
+
+  - Calendar: https://lists.aswf.io/g/openexr-dev/calendar
+
+* **Report a bug:**
+
+  - Submit an Issue: https://github.com/AcademySoftwareFoundation/Imath/issues
+
+* **Report a security vulnerability:**
+
+  - Email to security@openexr.com
+
+* **Contribute a Fix, Feature, or Improvement:**
+
+  - Read the [Contribution Guidelines](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md)
+
+  - Sign the [Contributor License
+    Agreement](https://contributor.easycla.lfx.linuxfoundation.org/#/cla/project/2e8710cb-e379-4116-a9ba-964f83618cc5/user/564e571e-12d7-4857-abd4-898939accdd7)
+  
+  - Submit a Pull Request: https://github.com/AcademySoftwareFoundation/Imath/pulls
+
+# Resources
+
+- Technical documentation: https://imath.readthedocs.io
+- Porting help: [OpenEXR/Imath Version 2.x to 3.x Porting Guide](https://openexr.readthedocs.io/en/latest/PortingGuide.html)
+- Security policy: [SECURITY.md](SECURITY.md)
+- Release notes: [CHANGES.md](CHANGES.md)
+- Contributors: [CONTRIBUTORS.md](CONTRIBUTORS.md)  
+
+# License
+
+Imath is released under OpenEXR's [BSD-3-Clause](LICENSE.md) license.
+
+---
+
+![aswf](https://github.com/AcademySoftwareFoundation/openexr/blob/main/ASWF/images/aswf.png)
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644 (file)
index 0000000..624c18f
--- /dev/null
@@ -0,0 +1,18 @@
+<!-- SPDX-License-Identifier: BSD-3-Clause -->
+<!-- Copyright (c) Contributors to the OpenEXR Project -->
+
+# Security Policy
+
+## Reporting a Vulnerability
+
+If you think you've found a potential vulnerability in Imath, please
+report it by emailing security@openexr.org. Only OpenEXR Technical
+Steering Committee members and Academy Software Foundation project
+management have access to these messages. Include detailed steps to
+reproduce the issue, and any other information that could aid an
+investigation. Our policy is to respond to vulernability reports
+within 14 days.
+
+Our policy is to address critical security vulnerabilities rapidly and
+post patches as quickly as possible.
+
diff --git a/cmake/FindPythonPackage.cmake b/cmake/FindPythonPackage.cmake
new file mode 100644 (file)
index 0000000..2e1a811
--- /dev/null
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenColorIO Project.
+#
+# Locate a Python package
+#
+# Variables defined by this module:
+#   <package>_FOUND
+#
+# Usage:
+#   find_python_package(Jinja2 2.10.1)
+#
+# If the package is not installed in a standard path, add it to the PYTHONPATH 
+# environment variable before running CMake.
+#
+
+find_package(Python QUIET COMPONENTS Interpreter)
+
+macro(find_python_package package)
+    # Some Python packages have "-" in the PyPi name, but are replaced with "_" 
+    # in the actual package name.
+    string(REPLACE "-" "_" _PKG_IMPORT ${package})
+
+    # Parse options
+    foreach(_ARG ${ARGN})
+        if(_ARG STREQUAL "REQUIRED")
+            set(_PKG_REQUIRED TRUE)
+        endif()
+        if(_PREV_ARG STREQUAL "REQUIRES")
+            set(_PKG_REQUIRES ${_ARG})
+        endif()
+        set(_PREV_ARG ${_ARG})
+    endforeach()
+    
+    if(NOT TARGET ${package})
+        add_custom_target(${package})
+        if(_PKG_REQUIRES)
+            add_dependencies(${package} ${_PKG_REQUIRES})
+            unset(_PKG_REQUIRES)
+        endif()
+        set(_${package}_TARGET_CREATE TRUE)
+    endif()
+
+    set(_PKG_INSTALL TRUE)
+
+    # Try importing Python package
+    execute_process(
+        COMMAND
+            "${Python_EXECUTABLE}" -c "import ${_PKG_IMPORT}"
+        RESULT_VARIABLE
+            _PKG_IMPORT_RESULT
+        OUTPUT_QUIET ERROR_QUIET
+    )
+
+    if(_PKG_IMPORT_RESULT EQUAL 0)
+        set(${package}_FOUND TRUE)
+
+        # Get the package's location
+        execute_process(
+            COMMAND
+                "${Python_EXECUTABLE}" -c 
+                "import ${_PKG_IMPORT}, os; print(os.path.dirname(${_PKG_IMPORT}.__file__))"
+            OUTPUT_VARIABLE
+                _PKG_DIR
+            ERROR_QUIET
+        )
+        string(STRIP "${_PKG_DIR}" _PKG_DIR)
+        message(STATUS "Found ${package}: ${_PKG_DIR}")
+
+    else()
+        set(${package}_FOUND FALSE)
+        set(_FIND_ERR "Could NOT find ${package} (import ${_PKG_IMPORT} failed)")
+
+        if(_PKG_REQUIRED)
+            message(FATAL_ERROR "${_FIND_ERR}")
+        endif()
+        message(STATUS "${_FIND_ERR}")
+    endif()
+
+endmacro()
diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake
new file mode 100644 (file)
index 0000000..9b7a8c0
--- /dev/null
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+#Look for an executable called sphinx-build
+find_program(SPHINX_EXECUTABLE
+             NAMES sphinx-build
+             DOC "Path to sphinx-build executable")
+
+include(FindPackageHandleStandardArgs)
+
+#Handle standard arguments to find_package like REQUIRED and QUIET
+find_package_handle_standard_args(Sphinx
+                                  "Failed to find sphinx-build executable"
+                                  SPHINX_EXECUTABLE)
+                                
diff --git a/cmake/SampleCTestScript.cmake b/cmake/SampleCTestScript.cmake
new file mode 100644 (file)
index 0000000..edef05a
--- /dev/null
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+# This is a sample cmake test script that can be used to integrate into
+# a larger CI setup if you are building your own versions of OpenEXR
+# and also use a cdash (or cdash compliant) results server.
+#
+# There are also settings in the CMakeLists.txt you may wish to
+# just set in there, or replicate here.
+
+# Running ctest -S thisscript.cmake will build into the binary directory
+# and run a few different tests based on what commands are specified
+# (and the steps below). It is best to read the ctest docs to
+# understand all these settings, and how to control it, this is merely
+# provided as a sample
+
+# An edited version (or multiple) are intended to be placed in the CI
+# system, and putting O.S. / configuration specific control to this file
+# instead of having to put it into the make CMakeLists.txt tree
+# somehow.
+
+# this contains the path to the source tree. This may come in as an
+# environment variable from the CI system, but you are free to have
+# any path in here
+set(CTEST_SOURCE_DIRECTORY "$ENV{PATH_TO_OPENEXR_TREE}")
+# Similarly, this is scratch space used to configure, build
+# and run the various tests.
+# For CI builds, it is recommended to make sure this is a
+# unique tree for each build
+set(CTEST_BINARY_DIRECTORY "/tmp/ctest")
+
+# set an override for any compile flags to enable coverage
+# NB: This can make some of the auxiliary binaries such as the
+# dwa lookup table generator quite slow
+#set(ENV{CXXFLAGS} "--coverage")
+
+# If you have alternate build systems, you can control that here
+#set(CTEST_CMAKE_GENERATOR "Ninja")
+set(CTEST_USE_LAUNCHERS 1)
+
+# The various paths to programs to run coverage and memory checks
+set(CTEST_COVERAGE_COMMAND "gcov")
+set(CTEST_MEMORYCHECK_COMMAND "valgrind")
+#set(CTEST_MEMORYCHECK_TYPE "ThreadSanitizer")
+# 
+
+# any of the usual configurations (Debug, Release, etc).
+# We do not attempt to create any alternate configurations
+set(CTEST_CONFIGURATION_TYPE "RelWithDebInfo")
+
+# can be Continuous, Nightly, or Experimental (see the cmake docs)
+ctest_start("Continuous")
+
+# applies the various ctest steps
+ctest_configure()
+ctest_build()
+ctest_test()
+ctest_coverage()
+ctest_memcheck()
+
+# This uploads the results to the server you configured
+ctest_submit()
diff --git a/cmake/Toolchain-Linux-VFX_Platform21.cmake b/cmake/Toolchain-Linux-VFX_Platform21.cmake
new file mode 100644 (file)
index 0000000..b49349e
--- /dev/null
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+# This is only an example of a theoretical toolchain file
+# that might be used for compiling to target a VFX
+# reference platform (https://vfxplatform.com) that is
+# consistent with the CY2021 spec.
+#
+# A toolchain file is loaded early in the cmake configure
+# process to enable compiler checks to use the appropriate
+# compilers.
+#
+# Read the docs to understand more:
+# https://cmake.org/cmake/help/v3.12/manual/cmake-toolchains.7.html
+#
+# Then to run, do something like
+# mkdir vfx_2021
+# cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-Linux-VFX_Platform21.cmake -DCMAKE_INSTALL_PREFIX=/path/to/vfx_2021 ..
+# (plus any other settings you'd like)
+# make
+# make test
+# make install
+
+# by not setting this, it will assume it's a mostly standard linux environment
+#set(CMAKE_SYSTEM_NAME Linux)
+
+set(CMAKE_C_COMPILER gcc-9.3.1)
+set(CMAKE_CXX_COMPILER g++-9.3.1)
+
+set(CMAKE_FIND_ROOT_PATH /my/vfx_2021/libraries)
+
+set(CMAKE_CXX_STANDARD 14)
+
+# read the docs to understand whether this is what you want
+# if you use system libraries for some things, it may not be!!!
+#set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+#set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+#set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
diff --git a/cmake/Toolchain-mingw.cmake b/cmake/Toolchain-mingw.cmake
new file mode 100644 (file)
index 0000000..08e8353
--- /dev/null
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+# This is only an example of cross compiling, but to compile for windows
+# under linux, have the relevant bits installed, and
+# validate the find path below
+#
+# Then to run, do something like
+# mkdir win32_cross
+# cd win32_cross
+# cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw.cmake -DCMAKE_INSTALL_PREFIX=/tmp/win32 ..
+# or for static libs only
+# cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw.cmake -DCMAKE_INSTALL_PREFIX=/tmp/win32 ..
+# make
+#
+
+set(CMAKE_SYSTEM_NAME Windows)
+
+set(CMAKE_CROSSCOMPILING_EMULATOR wine)
+
+set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
+set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
+set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
+
+set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
+set(CMAKE_SHARED_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
+
+set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
+
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/cmake/clang-format.cmake b/cmake/clang-format.cmake
new file mode 100644 (file)
index 0000000..eaa5b84
--- /dev/null
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+#
+# This module was partially adapted from OpenImageIO, also under the
+# same BSD-3-Clause license.
+
+###########################################################################
+# clang-format options
+#
+# clang-format is a source code reformatter that is part of the LLVM tools.
+# It can be used to check adherence to project code formatting rules and
+# correct any deviations. If clang-format is found on the system, a
+# "clang-format" build target will trigger a reformatting.
+#
+set (CLANG_FORMAT_ROOT "" CACHE PATH "clang-format executable's directory (will search if not specified")
+set (CLANG_FORMAT_INCLUDES "*.h" "*.cpp"
+     CACHE STRING "Glob patterns to include for clang-format")
+set (CLANG_FORMAT_EXCLUDES ""
+     CACHE STRING "Glob patterns to exclude for clang-format")
+
+# Look for clang-format. If not in the ordinary execution path, you can
+# hint at it with either CLANG_FORMAT_ROOT or LLVM_ROOT (as a CMake variable
+# or as an environment variable).
+find_program (CLANG_FORMAT_EXE
+              NAMES clang-format bin/clang-format
+              HINTS ${CLANG_FORMAT_ROOT}
+                    ENV CLANG_FORMAT_ROOT
+                    LLVM_ROOT
+                    ENV LLVM_ROOT
+              DOC "Path to clang-format executable")
+
+# If clang-format was found, set up a custom `clang-format` target that will
+# reformat all source code with filenames patterns matching
+# CLANG_FORMAT_INCLUDES and excluding CLANG_FORMAT_EXCLUDES.
+if (CLANG_FORMAT_EXE)
+    message (STATUS "clang-format found: ${CLANG_FORMAT_EXE}")
+    # Start with the list of files to include when formatting...
+    file (GLOB_RECURSE FILES_TO_FORMAT ${CLANG_FORMAT_INCLUDES})
+    # ... then process any list of excludes we are given
+    foreach (_pat ${CLANG_FORMAT_EXCLUDES})
+        file (GLOB_RECURSE _excl ${_pat})
+        list (REMOVE_ITEM FILES_TO_FORMAT ${_excl})
+    endforeach ()
+    #message (STATUS "clang-format file list: ${FILES_TO_FORMAT}")
+    file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/.clang-format
+          DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+    add_custom_target (clang-format
+        COMMAND "${CLANG_FORMAT_EXE}" -i -style=file ${FILES_TO_FORMAT} )
+else ()
+    message (STATUS "clang-format not found.")
+endif ()
diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt
new file mode 100644 (file)
index 0000000..32fb7af
--- /dev/null
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+if (IMATH_ENABLE_LARGE_STACK)
+  set(IMATH_HAVE_LARGE_STACK ON)
+endif()
+if (IMATH_USE_DEFAULT_VISIBILITY)
+  set(IMATH_ENABLE_API_VISIBILITY OFF)
+else()
+  set(IMATH_ENABLE_API_VISIBILITY ON)
+endif()
+
+configure_file(ImathConfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/ImathConfig.h)
+
+add_library(ImathConfig INTERFACE)
+
+target_include_directories(ImathConfig INTERFACE
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
+  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${IMATH_OUTPUT_SUBDIR}>)
+
+install(
+  FILES
+    ${CMAKE_CURRENT_BINARY_DIR}/ImathConfig.h
+  DESTINATION
+    ${CMAKE_INSTALL_INCLUDEDIR}/${IMATH_OUTPUT_SUBDIR}
+)
+
+install(TARGETS ImathConfig EXPORT ${PROJECT_NAME})
+
+add_library(Imath::Config ALIAS ImathConfig)
+
+if(IMATH_INSTALL_PKG_CONFIG)
+
+  # Prepend prefix for includedir only if CMAKE_INSTALL_INCLUDEDIR is relative
+  if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
+      set(PKG_CONFIG_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
+  else()
+      set(PKG_CONFIG_INSTALL_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
+  endif()
+
+  # Prepend exec_prefix for libdir only if CMAKE_INSTALL_LIBDIR is relative
+  if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
+      set(PKG_CONFIG_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
+  else()
+      set(PKG_CONFIG_INSTALL_LIBDIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
+  endif()
+
+  # use a helper function to avoid variable pollution, but pretty simple
+  function(imath_pkg_config_help pcinfile)
+    string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
+    set(LIB_SUFFIX_DASH ${IMATH_LIB_SUFFIX}${CMAKE_${uppercase_CMAKE_BUILD_TYPE}_POSTFIX})
+    string(REPLACE ".in" "" pcout ${pcinfile})
+    configure_file(${pcinfile} ${CMAKE_CURRENT_BINARY_DIR}/${pcout} @ONLY)
+    install(
+        FILES ${CMAKE_CURRENT_BINARY_DIR}/${pcout}
+        DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
+    )
+  endfunction()
+  imath_pkg_config_help(Imath.pc.in)
+else()
+  message(STATUS "pkg-config generation disabled")
+endif()
+
+#
+# The main export of the configuration: this is the cmake equivalent
+# of a pkg-config file and replaces the Find*.cmake of the "old" cmake
+#
+
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file(ImathConfig.cmake.in
+  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
+  INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+)
+
+write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake"
+  VERSION ${IMATH_VERSION}
+  COMPATIBILITY SameMajorVersion
+)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
+              ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+)
+
+install(EXPORT ${PROJECT_NAME}
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+  FILE ${PROJECT_NAME}Targets.cmake
+  NAMESPACE ${PROJECT_NAME}::
+  EXPORT_LINK_INTERFACE_LIBRARIES
+)
diff --git a/config/Imath.pc.in b/config/Imath.pc.in
new file mode 100644 (file)
index 0000000..b37e508
--- /dev/null
@@ -0,0 +1,17 @@
+##
+## SPDX-License-Identifier: BSD-3-Clause
+## Copyright Contributors to the OpenEXR Project.
+##
+
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=@PKG_CONFIG_INSTALL_LIBDIR@
+includedir=@PKG_CONFIG_INSTALL_INCLUDEDIR@
+libsuffix=@LIB_SUFFIX_DASH@
+Name: Imath
+Description: Imath library: vector/matrix and math operations, plus the half type.
+Version: @IMATH_VERSION@
+Requires:
+Conflicts:
+Libs: -L${libdir} -lImath${libsuffix}
+Cflags: -I${includedir} -I${includedir}/Imath
diff --git a/config/ImathConfig.cmake.in b/config/ImathConfig.cmake.in
new file mode 100644 (file)
index 0000000..2f6080e
--- /dev/null
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+check_required_components("@PROJECT_NAME@")
diff --git a/config/ImathConfig.h.in b/config/ImathConfig.h.in
new file mode 100644 (file)
index 0000000..ec29c7f
--- /dev/null
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+
+// This file is auto-generated by the cmake configure step
+
+#ifndef INCLUDED_IMATH_CONFIG_H
+#define INCLUDED_IMATH_CONFIG_H 1
+
+#pragma once
+
+//
+// Options / configuration based on O.S. / compiler
+//
+
+//
+// Define whether the half-to-float conversion should use the lookup
+// table method. Note that this is overriden by F16C compiler
+// flags. It is also overrided by the IMATH_HALF_NO_LOOKUP_TABLE
+// macro, if defined.
+//
+#cmakedefine IMATH_HALF_USE_LOOKUP_TABLE
+
+//
+// Define if the target system has support for large
+// stack sizes.
+//
+#cmakedefine IMATH_HAVE_LARGE_STACK
+
+//////////////////////
+//
+// C++ namespace configuration / options
+
+// Current (internal) library namepace name and corresponding public
+// client namespaces.
+#define IMATH_INTERNAL_NAMESPACE_CUSTOM @IMATH_NAMESPACE_CUSTOM@
+#define IMATH_INTERNAL_NAMESPACE @IMATH_INTERNAL_NAMESPACE@
+
+
+#define IMATH_NAMESPACE_CUSTOM @IMATH_NAMESPACE_CUSTOM@
+#define IMATH_NAMESPACE @IMATH_NAMESPACE@
+
+
+//
+// Version information
+//
+#define IMATH_VERSION_STRING "@IMATH_VERSION@"
+#define IMATH_PACKAGE_STRING "@IMATH_PACKAGE_NAME@"
+
+#define IMATH_VERSION_MAJOR @Imath_VERSION_MAJOR@
+#define IMATH_VERSION_MINOR @Imath_VERSION_MINOR@
+#define IMATH_VERSION_PATCH @Imath_VERSION_PATCH@
+#define IMATH_VERSION_RELEASE_TYPE "@IMATH_VERSION_RELEASE_TYPE@"
+
+#define IMATH_VERSION_HEX ((uint32_t(IMATH_VERSION_MAJOR) << 24) | \
+                             (uint32_t(IMATH_VERSION_MINOR) << 16) | \
+                             (uint32_t(IMATH_VERSION_PATCH) <<  8))
+
+// IMATH_LIB_VERSION is the library API version: SOCURRENT.SOAGE.SOREVISION
+#define IMATH_LIB_VERSION_STRING "@IMATH_LIB_VERSION@"
+
+//
+// Code that depends on the v2 ExcMath mechanism of signal handlers
+// that throw exceptions is incompatible with noexcept, since
+// floating-point overflow and underflow can occur in a wide variety
+// of computations within Imath functions now marked with
+// noexcept. Code that needs to accomodate the exception-handling
+// behavior can build with the IMATH_USE_NOEXCEPT off.
+//
+
+#cmakedefine01 IMATH_USE_NOEXCEPT
+#if IMATH_USE_NOEXCEPT
+#define IMATH_NOEXCEPT noexcept
+#else
+#define IMATH_NOEXCEPT
+#endif
+
+//
+// By default, opt into the interoparability constructors and assignments.
+// If this causes problems, it can be disabled by defining this symbol to
+// be 0 prior to including any Imath headers.
+//
+// If no such definition is found, we enable automatically unless we are
+// using gcc 4.x, which appears to have bugs that prevent the interop
+// templates from compiling correctly.
+//
+#ifndef IMATH_FOREIGN_VECTOR_INTEROP
+#  if defined(__GNUC__) && __GNUC__ == 4 && !defined(__clang__)
+#    define IMATH_FOREIGN_VECTOR_INTEROP 0
+#  else
+#    define IMATH_FOREIGN_VECTOR_INTEROP 1
+#  endif
+#endif
+
+
+//
+// Decorator that makes a function available for both CPU and GPU, when
+// compiling for Cuda.
+//
+#ifdef __CUDACC__
+  #define IMATH_HOSTDEVICE __host__ __device__
+#else
+  #define IMATH_HOSTDEVICE
+#endif
+
+
+//
+// Some compilers define a special intrinsic to use in conditionals that can
+// speed up extremely performance-critical spots if the conditional is
+// usually (or rarely) is true.  You use it by replacing
+//     if (x) ...
+// with
+//     if (IMATH_LIKELY(x)) ...     // if you think x will usually be true
+// or
+//     if (IMATH_UNLIKELY(x)) ...   // if you think x will rarely be true
+//
+// Caveat: Programmers are notoriously bad at guessing this, so it should be
+// used only with thorough benchmarking.
+//
+#if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)
+#    ifdef __cplusplus
+#        define IMATH_LIKELY(x) (__builtin_expect(static_cast<bool>(x), true))
+#        define IMATH_UNLIKELY(x) (__builtin_expect(static_cast<bool>(x), false))
+#    else
+#        define IMATH_LIKELY(x) (__builtin_expect((x), 1))
+#        define IMATH_UNLIKELY(x) (__builtin_expect((x), 0))
+#    endif
+#else
+#    define IMATH_LIKELY(x) (x)
+#    define IMATH_UNLIKELY(x) (x)
+#endif
+
+
+// On modern versions of gcc & clang, __has_attribute can test support for
+// __attribute__((attr)).  Make sure it's safe for other compilers.
+#ifndef __has_attribute
+#    define __has_attribute(x) 0
+#endif
+
+
+//
+// Simple way to mark things as deprecated.
+// When we are sure that C++14 is our true minimum, then we can just
+// directly use [[deprecated(msg)]].
+//
+#if defined(_MSC_VER)
+# define IMATH_DEPRECATED(msg) __declspec(deprecated(msg))
+#elif defined(__cplusplus) && __cplusplus >= 201402L
+# define IMATH_DEPRECATED(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__) || defined(__clang__)
+# define IMATH_DEPRECATED(msg) __attribute__((deprecated(msg)))
+#else
+# define IMATH_DEPRECATED(msg) /* unsupported on this platform */
+#endif
+
+// Whether the user configured the library to have symbol visibility
+// tagged
+#cmakedefine IMATH_ENABLE_API_VISIBILITY
+
+// MSVC does not do the same visibility attributes, and when we are
+// compiling a static library we won't be in DLL mode, but just don't
+// define these and the export headers will work out
+#if ! defined(_MSC_VER) && defined(IMATH_ENABLE_API_VISIBILITY)
+#  define IMATH_PUBLIC_SYMBOL_ATTRIBUTE __attribute__ ((__visibility__ ("default")))
+#  define IMATH_PRIVATE_SYMBOL_ATTRIBUTE __attribute__ ((__visibility__ ("hidden")))
+// clang differs from gcc and has type visibility which is needed for enums and templates
+#  if __has_attribute(__type_visibility__)
+#    define IMATH_PUBLIC_TYPE_VISIBILITY_ATTRIBUTE __attribute__ ((__type_visibility__ ("default")))
+#  endif
+#endif
+
+#endif // INCLUDED_IMATH_CONFIG_H
diff --git a/config/ImathSetup.cmake b/config/ImathSetup.cmake
new file mode 100644 (file)
index 0000000..6cd37ce
--- /dev/null
@@ -0,0 +1,128 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+include(GNUInstallDirs)
+
+# Target configuration
+if(NOT "${CMAKE_PROJECT_NAME}" STREQUAL "${PROJECT_NAME}")
+  set(IMATH_IS_SUBPROJECT ON)
+  message(STATUS "Imath is configuring as a cmake sub project")
+endif()
+
+option(IMATH_HALF_USE_LOOKUP_TABLE "Convert half-to-float using a lookup table (on by default)" ON)
+
+option(IMATH_USE_DEFAULT_VISIBILITY "Makes the compile use default visibility (by default compiles tidy, hidden-by-default)"     OFF)
+
+# This is primarily for the halfFunction code that enables a stack
+# object (if you enable this) that contains a LUT of the function
+option(IMATH_ENABLE_LARGE_STACK "Enables code to take advantage of large stack support"     OFF)
+
+# Option to make it possible to build without the noexcept specifier
+option(IMATH_USE_NOEXCEPT "Compile with noexcept specifier" ON)
+
+# What C++ standard to compile for.  VFX Platform 18 is c++14, so
+# that's the default.
+set(tmp 14)
+if(CMAKE_CXX_STANDARD)
+  set(tmp ${CMAKE_CXX_STANDARD})
+endif()
+set(IMATH_CXX_STANDARD "${tmp}" CACHE STRING "C++ standard to compile against")
+set(tmp)
+
+# Namespace-related settings: allows one to customize the namespace
+# generated, and to version the namespaces.
+set(IMATH_NAMESPACE_CUSTOM "0" CACHE STRING "Whether the namespace has been customized (so external users know)")
+set(IMATH_INTERNAL_NAMESPACE "Imath_${IMATH_VERSION_API}" CACHE STRING "Real namespace for Imath that will end up in compiled symbols")
+set(IMATH_NAMESPACE "Imath" CACHE STRING "Public namespace alias for Imath")
+set(IMATH_PACKAGE_NAME "Imath ${IMATH_VERSION}${IMATH_VERSION_RELEASE_TYPE}" CACHE STRING "Public string / label for displaying package")
+
+# Whether to generate and install a pkg-config file Imath.pc on
+if(WIN32)
+  option(IMATH_INSTALL_PKG_CONFIG "Install Imath.pc file" OFF)
+  option(IMATH_INSTALL_SYM_LINK "Create symbolic links for shared objects" OFF)
+else()
+  option(IMATH_INSTALL_PKG_CONFIG "Install Imath.pc file" ON)
+  option(IMATH_INSTALL_SYM_LINK "Create symbolic links for shared objects" ON)
+endif()
+
+#
+# Build related options
+#
+
+# This variable is for use in install lines. Care must be taken when
+# changing this, as many things assume this is "Imath".
+set(IMATH_OUTPUT_SUBDIR Imath CACHE STRING "Destination sub-folder of the include path for install")
+
+# This does not seem to be available as a per-target property, but is
+# pretty harmless to set globally.
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+# Suffix for debug configuration libraries (if you should choose to
+# install those)
+set(CMAKE_DEBUG_POSTFIX "_d" CACHE STRING "Suffix for debug builds")
+
+# Usual cmake option to build shared libraries or not
+option(BUILD_SHARED_LIBS "Build shared library" ON)
+
+# Suffix to append to root name, this helps with version management
+# but can be turned off if you don't care, or otherwise customized
+set(IMATH_LIB_SUFFIX "-${IMATH_VERSION_API}" CACHE STRING "string added to the end of all the libraries")
+
+# When building static, the additional string to add to the library name such
+# that a static build of Imath is easily distinguishable.
+# To use the static library, you would use
+# -lImath_static (or target_link_libraries(xxx Imath::Imath_static))
+set(IMATH_STATIC_LIB_SUFFIX "_static" CACHE STRING "name to append to static library (in addition to normal suffix)")
+
+# rpath related setup. Make sure we force an rpath to the rpath we're compiling
+set(CMAKE_SKIP_BUILD_RPATH FALSE)
+set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
+
+# Add the automatically determined parts of the rpath which point to
+# directories outside the build tree to the install RPATH
+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+
+# If the user sets an install rpath then just use that, or otherwise
+# set one for them.
+if(NOT CMAKE_INSTALL_RPATH)
+  list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir)
+  if("${isSystemDir}" STREQUAL "-1")
+    if("${CMAKE_SYSTEM}" MATCHES "Linux")
+      get_filename_component(tmpSysPath "${CMAKE_INSTALL_FULL_LIBDIR}" NAME)
+      if(NOT tmpSysPath)
+        set(tmpSysPath "lib")
+      endif()
+      set(CMAKE_INSTALL_RPATH "\\\$ORIGIN/../${tmpSysPath};${CMAKE_INSTALL_FULL_LIBDIR}")
+      set(tmpSysPath)
+       elseif(APPLE)
+      set(CMAKE_INSTALL_RPATH "@loader_path/../lib;@executable_path/../lib;${CMAKE_INSTALL_FULL_LIBDIR}")
+    else()
+      set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}")
+    endif()
+  endif()
+  set(isSystemDir)
+endif()
+
+# Set a default build type if not set
+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+  message(STATUS "Setting build type to 'Release' as none was specified.")
+  set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
+  # Set the possible values of build type for cmake-gui
+  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
+    "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
+endif()
+
+# Code check related features
+option(IMATH_USE_CLANG_TIDY "Check if clang-tidy is available, and enable that" OFF)
+if(IMATH_USE_CLANG_TIDY)
+  find_program(IMATH_CLANG_TIDY_BIN clang-tidy)
+  if(IMATH_CLANG_TIDY_BIN-NOTFOUND)
+    message(FATAL_ERROR "clang-tidy processing requested, but no clang-tidy found")
+  endif()
+  # TODO: Need to define the list of valid checks and add a file with said list
+  set(CMAKE_CXX_CLANG_TIDY
+    ${IMATH_CLANG_TIDY_BIN};
+    -header-filter=.;
+    -checks=*;
+  )
+endif()
diff --git a/config/LibraryDefine.cmake b/config/LibraryDefine.cmake
new file mode 100644 (file)
index 0000000..4868954
--- /dev/null
@@ -0,0 +1,110 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+include(CheckLibraryExists)
+check_library_exists(m sin "" HAVE_LIB_M)
+if (HAVE_LIB_M)
+  set(IMATH_EXTRA_LIBS m)
+endif()
+
+# NB: This function has a number if Imath specific names / variables
+# in it, so be careful copying...
+function(IMATH_DEFINE_LIBRARY libname)
+  set(options)
+  set(oneValueArgs PRIV_EXPORT CURDIR CURBINDIR)
+  set(multiValueArgs SOURCES HEADERS DEPENDENCIES PRIVATE_DEPS)
+  cmake_parse_arguments(IMATH_CURLIB "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+  if (MSVC)
+    set(_imath_extra_flags "/EHsc")
+  endif()
+  set(objlib ${libname})
+  add_library(${objlib}
+    ${IMATH_CURLIB_HEADERS}
+    ${IMATH_CURLIB_SOURCES})
+
+  # Use ${IMATH_CXX_STANDARD} to determine the standard we use to compile
+  # Imath itself. But the headers only require C++11 features, so that's
+  # all we need to pass on as interface reqirements to downstream projects.
+  # For example, it's fine for an Imath built with C++14 to be called from
+  # an app that is compiled with C++11; Imath needn't force the app to
+  # also use C++14.
+  target_compile_features(${objlib}
+                          PRIVATE cxx_std_${IMATH_CXX_STANDARD}
+                          INTERFACE cxx_std_11 )
+
+  if(IMATH_CURLIB_PRIV_EXPORT AND BUILD_SHARED_LIBS)
+    target_compile_definitions(${objlib} PRIVATE ${IMATH_CURLIB_PRIV_EXPORT})
+    if(WIN32)
+      target_compile_definitions(${objlib} PUBLIC IMATH_DLL)
+    endif()
+  endif()
+  if(IMATH_CURLIB_CURDIR)
+    target_include_directories(${objlib} INTERFACE $<BUILD_INTERFACE:${IMATH_CURLIB_CURDIR}>)
+  endif()
+  if(IMATH_CURLIB_CURBINDIR)
+    target_include_directories(${objlib} PRIVATE $<BUILD_INTERFACE:${IMATH_CURLIB_CURBINDIR}>)
+  endif()
+  target_link_libraries(${objlib} PUBLIC ${PROJECT_NAME}::Config ${IMATH_CURLIB_DEPENDENCIES})
+  if(IMATH_CURLIB_PRIVATE_DEPS)
+    target_link_libraries(${objlib} PRIVATE ${IMATH_CURLIB_PRIVATE_DEPS})
+  endif()
+  set_target_properties(${objlib} PROPERTIES
+    CXX_STANDARD_REQUIRED ON
+    CXX_EXTENSIONS OFF
+    POSITION_INDEPENDENT_CODE ON
+    )
+  if (NOT IMATH_USE_DEFAULT_VISIBILITY)
+    set_target_properties(${objlib} PROPERTIES
+      C_VISIBILITY_PRESET hidden
+      CXX_VISIBILITY_PRESET hidden
+      VISIBILITY_INLINES_HIDDEN ON
+      )
+  else()
+      target_compile_definitions(${objlib} PUBLIC IMATH_USE_DEFAULT_VISIBILITY)
+  endif()
+  if (_imath_extra_flags)
+    target_compile_options(${objlib} PUBLIC ${_imath_extra_flags})
+  endif()
+  set_property(TARGET ${objlib} PROPERTY PUBLIC_HEADER ${IMATH_CURLIB_HEADERS})
+
+  if(BUILD_SHARED_LIBS)
+    set_target_properties(${libname} PROPERTIES
+      SOVERSION ${IMATH_LIB_SOVERSION}
+      VERSION ${IMATH_LIB_VERSION}
+    )
+  endif()
+  if(IMATH_EXTRA_LIBS)
+    target_link_libraries(${libname} PUBLIC ${IMATH_EXTRA_LIBS})
+  endif()
+
+  set_target_properties(${libname} PROPERTIES
+      OUTPUT_NAME "${libname}${IMATH_LIB_SUFFIX}"
+      RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+  )
+  add_library(${PROJECT_NAME}::${libname} ALIAS ${libname})
+
+  install(TARGETS ${libname}
+    EXPORT ${PROJECT_NAME}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+    PUBLIC_HEADER
+      DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${IMATH_OUTPUT_SUBDIR}
+  )
+  if(BUILD_SHARED_LIBS AND (NOT "${IMATH_LIB_SUFFIX}" STREQUAL "") AND IMATH_INSTALL_SYM_LINK)
+    string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
+    set(verlibname ${CMAKE_SHARED_LIBRARY_PREFIX}${libname}${IMATH_LIB_SUFFIX}${CMAKE_${uppercase_CMAKE_BUILD_TYPE}_POSTFIX}${CMAKE_SHARED_LIBRARY_SUFFIX})
+    set(baselibname ${CMAKE_SHARED_LIBRARY_PREFIX}${libname}${CMAKE_${uppercase_CMAKE_BUILD_TYPE}_POSTFIX}${CMAKE_SHARED_LIBRARY_SUFFIX})
+    if(WIN32)
+      install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E chdir \"\$ENV\{DESTDIR\}${CMAKE_INSTALL_FULL_BINDIR}\" ${CMAKE_COMMAND} -E create_symlink ${verlibname} ${baselibname})")
+      install(CODE "message(STATUS \"Creating symlink ${CMAKE_INSTALL_FULL_BINDIR}/${baselibname} -> ${verlibname}\")")
+    else()
+      install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E chdir \"\$ENV\{DESTDIR\}${CMAKE_INSTALL_FULL_LIBDIR}\" ${CMAKE_COMMAND} -E create_symlink ${verlibname} ${baselibname})")
+      install(CODE "message(STATUS \"Creating symlink ${CMAKE_INSTALL_FULL_LIBDIR}/${baselibname} -> ${verlibname}\")")
+    endif()
+    set(verlibname)
+    set(baselibname)
+  endif()
+endfunction()
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..799c445
--- /dev/null
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
+
+find_package(Doxygen REQUIRED)
+find_package(Sphinx REQUIRED)
+
+set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/src/Imath)
+set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doxygen)
+set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/html/index.html)
+set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
+set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
+
+set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR})
+set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx)
+set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html)
+
+configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)
+
+file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR})
+
+add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE}
+                   COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
+                   COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/fixmanpages.sh ${DOXYGEN_OUTPUT_DIR}
+                   MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN}
+                   COMMENT "Running doxygen"
+                   VERBATIM)
+
+add_custom_command(OUTPUT ${SPHINX_INDEX_FILE}
+                   COMMAND 
+                     ${SPHINX_EXECUTABLE} -b html
+                     # Tell Breathe where to find the Doxygen output
+                     -Dbreathe_projects.Imath=${DOXYGEN_OUTPUT_DIR}/xml
+                   ${SPHINX_SOURCE} ${SPHINX_BUILD}
+                   WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+                   DEPENDS ${DOXYGEN_INDEX_FILE}
+                   MAIN_DEPENDENCY conf.py
+                   COMMENT "Generating documentation with Sphinx")
+
+add_custom_target(docs ALL DEPENDS ${SPHINX_INDEX_FILE} ${DOXYGEN_INDEX_FILE})
+
+# Add an install target to install the docs
+if(INSTALL_DOCS)
+    include(GNUInstallDirs)
+    install(DIRECTORY ${SPHINX_BUILD}
+    DESTINATION ${CMAKE_INSTALL_DOCDIR})
+endif()
diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in
new file mode 100644 (file)
index 0000000..c6b9f8f
--- /dev/null
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+PROJECT_NAME     = "Imath"
+GENERATE_LATEX   = NO
+GENERATE_MAN     = NO
+GENERATE_RTF     = NO
+CASE_SENSE_NAMES = NO
+INPUT            = "@DOXYGEN_INPUT_DIR@"
+OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIR@"
+RECURSIVE        = YES
+QUIET            = YES
+JAVADOC_AUTOBRIEF    = YES
+GENERATE_HTML        = NO
+GENERATE_XML         = YES
+DISTRIBUTE_GROUP_DOC = YES
+MACRO_EXPANSION      = YES
+ENABLE_PREPROCESSING = YES
+WARN_IF_UNDOCUMENTED = NO
+PREDEFINED = IMATH_CONSTEXPR14=constexpr \
+             IMATH_HOSTDEVICE= \
+             IMATH_INTERNAL_NAMESPACE=Imath \
+             IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER="namespace Imath {" \
+             IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT="}" \
+             IMATH_INTERNAL_NAMESPACE_HEADER_ENTER="namespace Imath {" \
+             IMATH_INTERNAL_NAMESPACE_HEADER_EXIT="}" \
+             IMATH_NOEXCEPT="noexcept" \
+             IMATH_EXPORT="" \
+             IMATH_EXPORT_ENUM= \
+             IMATH_EXPORT_TYPE= \
+             IMATH_EXPORT_TEMPLATE_TYPE= \
+             imath_half_bits_t=half \
+             __cplusplus=1
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644 (file)
index 0000000..9e86a0d
--- /dev/null
@@ -0,0 +1,177 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+       @echo "Please use \`make <target>' where <target> is one of"
+       @echo "  html       to make standalone HTML files"
+       @echo "  dirhtml    to make HTML files named index.html in directories"
+       @echo "  singlehtml to make a single large HTML file"
+       @echo "  pickle     to make pickle files"
+       @echo "  json       to make JSON files"
+       @echo "  htmlhelp   to make HTML files and a HTML help project"
+       @echo "  qthelp     to make HTML files and a qthelp project"
+       @echo "  devhelp    to make HTML files and a Devhelp project"
+       @echo "  epub       to make an epub"
+       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+       @echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+       @echo "  text       to make text files"
+       @echo "  man        to make manual pages"
+       @echo "  texinfo    to make Texinfo files"
+       @echo "  info       to make Texinfo files and run them through makeinfo"
+       @echo "  gettext    to make PO message catalogs"
+       @echo "  changes    to make an overview of all changed/added/deprecated items"
+       @echo "  xml        to make Docutils-native XML files"
+       @echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+       @echo "  linkcheck  to check all external links for integrity"
+       @echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+       rm -rf $(BUILDDIR)/*
+
+html:
+       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+       @echo
+       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+       @echo
+       @echo "Build finished; now you can process the pickle files."
+
+json:
+       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+       @echo
+       @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+       @echo
+       @echo "Build finished; now you can run HTML Help Workshop with the" \
+             ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+       @echo
+       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ReadTheDocs-Breathe.qhcp"
+       @echo "To view the help file:"
+       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ReadTheDocs-Breathe.qhc"
+
+devhelp:
+       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+       @echo
+       @echo "Build finished."
+       @echo "To view the help file:"
+       @echo "# mkdir -p $$HOME/.local/share/devhelp/ReadTheDocs-Breathe"
+       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ReadTheDocs-Breathe"
+       @echo "# devhelp"
+
+epub:
+       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+       @echo
+       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo
+       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+       @echo "Run \`make' in that directory to run these through (pdf)latex" \
+             "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through pdflatex..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+latexpdfja:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through platex and dvipdfmx..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+       @echo
+       @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+       @echo
+       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo
+       @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+       @echo "Run \`make' in that directory to run these through makeinfo" \
+             "(use \`make info' here to do that automatically)."
+
+info:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo "Running Texinfo files through makeinfo..."
+       make -C $(BUILDDIR)/texinfo info
+       @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+       $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+       @echo
+       @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+       @echo
+       @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+       @echo
+       @echo "Link check complete; look for any errors in the above output " \
+             "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+       @echo "Testing of doctests in the sources finished, look at the " \
+             "results in $(BUILDDIR)/doctest/output.txt."
+
+xml:
+       $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+       @echo
+       @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+       $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+       @echo
+       @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/docs/PortingGuide.rst b/docs/PortingGuide.rst
new file mode 100644 (file)
index 0000000..58f3f4a
--- /dev/null
@@ -0,0 +1,607 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+:orphan:
+
+.. _porting:
+
+OpenEXR/Imath 2.x to 3.x Porting Guide
+######################################
+
+This porting guide outlines the several areas where switching from OpenEXR
+2.x to OpenEXR 3.x + Imath 3.x will require source code or build changes of
+downstream software.
+
+In each case, we will often explain both how to change if you are expecting
+3.x only hereafter, or usually a more complex accommodation if you want to
+keep compatibility with both 2.x and 3.x.
+
+OpenEXR and Imath Are Different Packages
+========================================
+
+If your use of OpenEXR was only for the sake of using the math classes and
+utilities, maybe you were unhappy that you needed to download and build the
+full OpenEXR dependency. You are in luck -- now Imath is a separate, very
+lightweight open source package. You can use Imath functionality without
+needing any of OpenEXR, which as of 3.x only includes the parts you need to
+read and write OpenEXR image files.
+
+The parts of "IlmBase" that were ``Imath`` and ``half`` are now repackaged
+as the ``Imath`` library. The ``IlmThread`` and ``Iex`` libraries have been
+folded into the OpenEXR package, since they were were not necessary to
+the rest of Imath.
+
+When building OpenEXR 3.x, note that if Imath 3.x library is not found
+already installed at build time, it will be automatically downloaded and
+built as part of the OpenEXR build.
+
+Background
+==========
+
+Why is this happening? Here is the relevant history.
+
+The OpenEXR project has historically consisted of four separate subprojects:
+
+* ``OpenEXR`` - the Imf image format
+* ``IlmBase`` - supporting utilities (Imath, Half, Iex, IlmThread)
+* ``PyIlmBase`` - python bindings for the IlmBase libraries
+* ``OpenEXR_Viewers`` - code for an example EXR image viewer 
+
+Prior to the 2.4 release in 2019, OpenEXR relied primarily on the Gnu
+autotools build system and was released as four separate tarballs
+(ilmbase, pyilmbase, openexr, openexr_viewers) that were constructed
+via the Gnu tools. This gave direct access to the "IlmBase" libraries
+independent of the OpenEXR format library. The project also included
+CMake files but CMake support was incomplete.
+
+With the adoption of OpenEXR by the Academy Software Foundation in
+2019, the technical steering committee made several key changes:
+
+1. Drop support for autotools in favor of CMake. A significant portion
+   of the OpenEXR user base uses Windows, which the Gnu autotools does
+   not support.  Supporting two build systems is a maintenance burden
+   that the TSC opted to avoid. We now assume that all modern users of
+   OpenEXR can reasonably be expected to rely on CMake.
+
+2. Rely on GitHub's automatic release packaging mechanism. This
+   packages the entire contents of package in a single
+   tarball. Separate tarballs are no longer generated by the Gnu
+   autotools setup.
+
+3. Deprecate the OpenEXR_Viewers code. It was impossibly out of date
+   and of little modern value.
+
+Thus, with the 2.4 release, the "IlmBase" libraries are no longer
+distributed in a form that is readily separable from the rest of
+OpenEXR. The build and installation process for the overall OpenEXR
+project is complicated by the fact it consists of four separate
+projects, which added significant complexity to the CMake setup.
+
+Because Imath is generally useful to the community, the TSC decided to
+simplify the configuration by separating Imath into its own independent
+project, maintained and released independently of OpenEXR, and
+introducing it as a new external dependency of OpenEXR.
+
+To further simplify matters, the new Imath library includes the half
+data type directly, rather than maintaining it in a separate
+library. Also, the community at large has a strong desire for simple
+vector/matrix utilities that are unencumbered by Iex, the IlmBase
+library that provides higher-level exception classes, and even
+further, a clear delineation between functionality that (1) relies on
+exception handlings and (2) is free from exceptions. As a result,
+support for Iex has been removed from Imath, and the Iex library is
+now packaged as a component of OpenEXR.
+
+The Imath python bindings are a part of Imath as a configuration
+option, although support is off by default to simplify the build process
+for most users.
+
+New Library Names and Repository Structures
+===========================================
+
+The new repositories place all source code under the ``src`` top-level
+subdirectory.
+
+Imath:
+------
+
+.. code-block::
+
+    src
+    ├── Imath
+    ├── ImathTest
+    └── python
+        ├── config
+        ├── PyImath
+        ├── PyImathNumpy
+        ├── PyImathTest
+        ├── PyImathNumpyTest
+        └── PyImathSpeedTest
+
+
+OpenEXR:
+--------
+
+The ``IlmImf`` library has been renamed ``OpenEXR``. No header files have
+changed names, only their locations in the repo have changes.
+
+.. code-block::
+
+    src
+    ├── bin
+    │   ├── exr2aces
+    │   ├── exrbuild
+    │   ├── exrcheck
+    │   ├── exrenvmap
+    │   ├── exrheader
+    │   ├── exrmakepreview
+    │   ├── exrmaketiled
+    │   ├── exrmultipart
+    │   ├── exrmultiview
+    │   └── exrstdattr
+    ├── lib
+    │   ├── Iex
+    │   ├── IexMath
+    │   ├── IlmThread
+    │   ├── OpenEXR
+    │   └── OpenEXRUtil
+    ├── examples
+    └── test
+        ├── IexTest
+        ├── OpenEXRTest
+        ├── OpenEXRUtilTest
+        └── OpenEXRFuzzTest
+
+
+Finding and Using OpenEXR and Imath CMake Configs
+=================================================
+
+OpenEXR/Imath 3.x Only
+----------------------
+
+If you are *only* concerned with OpenEXR/Imath 3.x going forward, this is
+the recommended way to find the libraries in a downstream project that uses
+the CMake build system:
+
+.. code-block::
+
+    find_package(Imath CONFIG)
+    find_package(OpenEXR CONFIG)
+
+Note that the second line may be omitted if you only need the Imath
+portions.
+
+And then your project can reference the imported targets like this:
+
+.. code-block::
+
+    target_link_libraries (my_target
+        PRIVATE
+            OpenEXR::OpenEXR
+            Imath::Imath
+            Imath::Half
+        )
+
+You only need the parts you use, so for example, if you only need Half and
+Imath, you can omit the OpenEXR target. Also note that in our example above,
+we have used the ``PRIVATE`` label, but you should specify them as ``PUBLIC`` if
+you are exposing those classes in your own package's public interface.
+
+
+Accommodating OpenEXR/Imath 3.x or OpenEXR 2.x
+----------------------------------------------
+
+On the other hand, to accommodate both 2.x and 3.x, it's admittedly
+inconvenient because the packages and the import targets have changed their
+names.  We have found the following idioms to work:
+
+Finding either/both packages:
+
+.. code-block::
+
+    # First, try to find just the right config files
+    find_package(Imath CONFIG)
+    if (NOT TARGET Imath::Imath)
+        # Couldn't find Imath::Imath, maybe it's older and has IlmBase?
+        find_package(IlmBase CONFIG)
+    endif ()
+    find_package(OpenEXR CONFIG)
+
+To link against them, we use CMake generator expressions so that we can
+reference *both* sets of targets, but it will only use the ones
+corresponding to the package version that was found.
+
+.. code-block::
+
+    target_link_libraries (my_target
+        PRIVATE
+            # For OpenEXR/Imath 3.x:
+              $<$<TARGET_EXISTS:OpenEXR::OpenEXR>:OpenEXR::OpenEXR>
+              $<$<TARGET_EXISTS:Imath::Imath>:Imath::Imath>
+              $<$<TARGET_EXISTS:Imath::Half>:Imath::Half>
+            # For OpenEXR 2.4/2.5:
+              $<$<TARGET_EXISTS:OpenEXR::IlmImf>:OpenEXR::IlmImf>
+              $<$<TARGET_EXISTS:IlmBase::Imath>:IlmBase::Imath>
+              $<$<TARGET_EXISTS:IlmBase::Half>:IlmBase::Half>
+              $<$<TARGET_EXISTS:IlmBase::IlmThread>:IlmBase::IlmThread>
+              $<$<TARGET_EXISTS:IlmBase::Iex>:IlmBase::Iex>
+        )
+
+Again, you can eliminate the references to any of the individual libaries
+that you don't actually need for your application.
+
+Simultaneous Static/Shared Build
+--------------------------------
+
+The OpenEXR 2.x CMake configuration had options to simultaneously
+build both shared and statically linked libraries. This has been
+deprecated. A CMake configuration setting specifies whether to build
+static or shared, but if you want both, you will need to run cmake and
+build twice.
+
+Simultaneous Python 2/3 Build
+-----------------------------
+
+The PyIlmBase 2.x CMake configuration had options to simultaneously
+build both python2 and python3 bindings. This has been deprecated.
+A CMake configuration setting specifies whether to build for
+python 2 or python 3, but if you want both, you will need to run
+cmake and build twice.
+
+Imath Include Files Are in a Different Subdirectory
+===================================================
+
+Imath 3.0 will copy its headers to some ``include/Imath`` subdirectory
+instead of the old ``include/OpenEXR``.
+
+OpenEXR/Imath 3.x Only
+----------------------
+
+If you know that you are only using Imath 3.x, then just change any
+include directions, like this:
+
+.. code-block::
+
+    #include <OpenEXR/ImathVec.h>
+    #include <OpenEXR/half.h>
+
+to the new locations:
+
+.. code-block::
+
+    #include <Imath/ImathVec.h>
+    #include <Imath/half.h>
+
+Accommodating OpenEXR/Imath 3.x or OpenEXR 2.x
+----------------------------------------------
+
+If you want your software to be able to build against either OpenEXR 2.x or
+3.x (depending on which dependency is available at build time), we recommend
+using a more complicated idiom:
+
+.. code-block::
+
+    // The version can reliably be found in this header file from OpenEXR,
+    // for both 2.x and 3.x:
+    #include <OpenEXR/OpenEXRConfig.h>
+    #define COMBINED_OPENEXR_VERSION ((10000*OPENEXR_VERSION_MAJOR) + \
+                                      (100*OPENEXR_VERSION_MINOR) + \
+                                      OPENEXR_VERSION_PATCH)
+
+    // There's just no easy way to have an ``#include`` that works in both
+    // cases, so we use the version to switch which set of include files we
+    // use.
+    #if COMBINED_OPENEXR_VERSION >= 20599 /* 2.5.99: pre-3.0 */
+    #   include <Imath/ImathVec.h>
+    #   include <Imath/half.h>
+    #else
+        // OpenEXR 2.x, use the old locations
+    #   include <OpenEXR/ImathVec.h>
+    #   include <OpenEXR/half.h>
+    #endif
+
+Include Files Include Fewer Other Headers
+=========================================
+
+Extraneous ``#include`` statements have been removed from some header
+files, which can lead to compile failures in application code that
+previously included certain headers indirectly.
+
+For example, the Imath header files no longer include ``float.h``, so
+application code that references symbols such as ``FLT_MAX`` may need
+to add an explicit ``#include <float.h>`` or equivalent.
+
+If your application code reports compile errors due to undefined or
+incompletely-defined Imath or OpenEXR data types, locate the Imath or
+OpenEXR header file that defines the type and include it explicitly.
+
+Symbols Are Hidden by Default
+=============================
+
+To reduce library size and make linkage behavior similar across
+platforms, Imath and OpenEXR now build with directives that make
+symbol visibility hidden by default, with specific externally-visible
+symbols explicitly marked for export. See the :doc:`SymbolVisibility`
+and the appropriate ``*Export.h`` header file for more details.
+
+Imath Now Uses Standard C++ Exceptions and ``noexcept``
+=======================================================
+
+In OpenEXR 2.x, the Imath functions that threw exceptions used to throw
+various Iex varieties.
+
+In Imath 3.x, these functions just throw ``std::exception`` varieties that
+correspond to the failure (e.g., ``std::invalid_argument``,
+``std::domain_error``, etc.). For that reason, all of the Iex exceptions are
+now only part of the OpenEXR library (where they are still used in the same
+manner they were for OpenEXR 2.x).
+
+Imath 3.x has very few functions that throw exceptions. Each is clearly
+marked as such, and each has a version that does not throw exceptions (so
+that it may be used from code where exceptions are avoided). The functions
+that do not throw exceptions are now marked ``noexcept``.
+
+Some Headers and Classes Have Been Removed from Imath 3.x
+=========================================================
+
+* The ``Math<T>`` class (and ``ImathMath.h`` header file) are
+  deprecated. All of the ``Math<T>`` functionality is subsumed by C++11
+  ``std::`` math functions. For example, calls to
+  ``Imath::Math<T>::abs(x)`` should be replaced with ``std::abs(x)``.
+
+* The ``Limits<T>`` class (and the ``ImathLimits.h`` and
+  ``ImathHalfLimits.h`` headers) have been removed entirely. All uses of
+  ``Limits<>`` should be replaced with the appropriate
+  ``std::numeric_limits<>`` method call. The Imath-specific versions
+  predated C++11, and were not only redundant in a C++11 world, but
+  also potentially confusing because some of their functions behaved
+  quite differently than the ``std::numeric_limits`` method with the
+  same name. We are following the precept that if C++11 does something
+  in a standard way, we should not define our own equivalent function
+  (and especially not define it in a way that doesn't match the
+  standard behavior).
+
+* ``Vec<T>::normalize()`` and ``length()`` methods, for integer ``T`` types,
+  have been removed. Also the standalone ``project()`` and
+  ``orthogonal()`` functions are no longer defined for vectors made of
+  integer elements. These all had behavior that was hard to understand
+  and probably useless. They still work as expected for vectors of
+  floating-point types.
+
+* The ``Int64`` and ``SInt64`` types are deprecated in favor of the
+  now-standard ``int64_t`` and ``uint64_t``.
+
+File/Class-specific Changes
+===========================
+
+``half`` in ``half.h``
+----------------------
+
+* The half type is now in the ``Imath`` namespace, but a compile-time
+  option puts it in the global namespace, except when compiling for
+  CUDA, in which case the 'half' type refers to the CUDA type:
+
+.. code-block::
+
+      #ifndef __CUDACC__
+      using half = IMATH_INTERNAL_NAMESPACE::half;
+      #else
+      #include <cuda_fp16.h>
+      #endif
+
+  If you desire to use Imath::half inside a CUDA kernal, you can refer
+  to it via the namespace, or define ``CUDA_NO_HALF`` to avoid the CUDA
+  type altogether.
+
+* ``HALF_MIN`` has changed value. It is now the smallest **normalized**
+   positive value, returned by ``std::numeric_limits<half>::min()``.
+
+* New constructor from a bit pattern:
+
+.. code-block::
+
+      enum FromBitsTag
+      {
+          FromBits
+      };
+
+      constexpr half(FromBitsTag, unsigned short bits) noexcept;
+
+``Imath::Box<T>`` in ``ImathBox.h``
+-----------------------------------
+
+* ``baseTypeMin()`` is replaced with ``baseTypeLowest()``
+
+``Color3<T>``, ``Color4<T>`` in ``ImathColor.h``
+------------------------------------------------
+
+* ``baseTypeMin()`` is replaced with ``baseTypeLowest()``
+
+``Imath::Frustum<T>`` in ``ImathFrustum.h``
+-------------------------------------------
+
+Akin to the ``Vec`` classes, there are now seperate API calls for
+throwing and non-throwing functions:
+
+These functions previously threw exceptions but now do not throw and
+are marked ``noexcept``:
+
+* ``Frustum<T>::projectionMatrix() noexcept``
+
+* ``Frustum<T>::aspect() noexcept``
+
+* ``Frustum<T>::set() noexcept``
+
+* ``Frustum<T>::projectPointToScreen() noexcept``
+
+* ``Frustum<T>::ZToDepth() noexcept``
+
+* ``Frustum<T>::DepthToZ() noexcept``
+
+* ``Frustum<T>::screenRadius() noexcept``
+
+* ``Frustum<T>::localToScreen() noexcept``
+
+These functions throw ``std::domain_error`` exceptions when the
+associated frustum is degenerate:
+
+* ``Frustum<T>::projectionMatrixExc()``
+
+* ``Frustum<T>::aspectExc()``
+
+* ``Frustum<T>::setExc()``
+
+* ``Frustum<T>::projectPointToScreenExc()``
+
+* ``Frustum<T>::ZToDepthExc()``
+
+* ``Frustum<T>::DepthToZExc()``
+
+* ``Frustum<T>::screenRadiusExc()``
+
+* ``Frustum<T>::localToScreenExc()``
+
+``Imath::Interval<T>`` in ``ImathInterval.h``
+---------------------------------------------
+
+New methods/functions: 
+
+* ``Interval<T>::operator !=``
+
+* ``Interval<T>::makeInfinite()``
+
+* ``Interval<T>isInfinite()``
+
+* ``operator<< (std::ostream& s, const Interval<T>&)``
+
+``ImathMatrixAlgo.h``
+---------------------
+
+* ``checkForZeroScaleInRow()`` and ``extractAndRemoveScalingAndShear()``
+   throw ``std::domain_error`` exceptions instead of ``Iex::ZeroScale``
+
+``Matrix22<T>``, ``Matrix33<T>``, ``Matrix44<T>`` in ``ImathMatrix.h``
+----------------------------------------------------------------------
+
+* ``baseTypeMin()`` is replaced with ``baseTypeLowest()``
+
+* ``invert(bool singExc = false)`` is replace by:
+
+  - ``invert() noexcept``
+
+  - ``invert(bool)`` which optionally throws an ``std::invalid_argument``
+    exception.
+
+* ``inverse(bool singExc = false)`` is replace by:
+
+  - ``inverse() noexcept``
+
+  - ``inverse(bool)`` which optionally throws an ``std::invalid_argument``
+    exception.
+
+* ``gjInvert(bool singExc = false)`` is replace by:
+
+  - ``gjInvert()`` noexcept
+
+  - ``gjInvert(bool)`` which optionally throws an
+    ``std::invalid_argument`` exception.
+
+* ``gJinverse(bool singExc = false)`` is replace by:
+
+  - ``gjInverse()`` noexcept
+
+  - ``gjInverse(bool)`` which optionally throws an
+    ``std::invalid_argument`` exception.
+
+New functions:
+
+* ``operator<< (std::ostream& s, const Matrix22<T>&)``
+
+* ``operator<< (std::ostream& s, const Matrix33<T>&)``
+
+* ``operator<< (std::ostream& s, const Matrix44<T>&)``
+
+Other changes:
+
+* Initialization loops unrolled for efficiency
+
+* inline added where appropriate
+
+``ImathRoots.h``
+----------------
+
+* When compiling for CUDA, the ``complex`` type comes from ``thrust``
+  rather than ``std``
+
+``Shear6`` in ``ImathShear.h``
+------------------------------
+
+* ``baseTypeMin()`` is replaced with ``baseTypeLowest()``
+
+``ImathVecAlgo.h``
+------------------
+
+The following functions are no longer defined for integer-based
+vectors, because such behavior is not clearly defined:
+
+* ``project (const Vec& s, const Vec& t)``
+
+* ``orgthogonal (const Vec& s, const Vec& t)``
+
+* ``reflect (const Vec& s, const Vec& t)``
+
+``Vec2<T>``, ``Vec3<T>``, ``Vec4<T>`` in ``ImathVec.h``
+-------------------------------------------------------
+
+* ``baseTypeMin()`` is replaced with ``baseTypeLowest()``
+
+* The following methods are removed (via ``= delete``) for integer-based
+  vectors because the behavior is not clearly defined and thus prone
+  to confusion:
+
+  - ``length()`` - although the length is indeed defined, its proper value
+    is floating point and can thus not be represented by the 'T'
+    return type.
+
+  - ``normalize()``
+
+  - ``normalizeExc()``
+
+  - ``normalizeNonNull()``
+
+  - ``normalized()``
+
+  - ``normalizedExc()``
+
+  - ``normalizedNonNull()``
+* Interoperability Constructors: The Vec and Matrix classes now have
+  constructors that take as an argument any data object of similar
+  size and layout.
+
+Imath Python Changes
+====================
+
+In general, the changes in Imath at the C++ level are reflected in the
+python bindings. In particular:
+
+* The following methods are removed for integer-based
+  vector and matrix objects and arrays:
+
+  - ``length()``
+  - ``normalize()``
+  - ``normalizeExc()``
+  - ``normalizeNonNull()``
+  - ``normalized()``
+  - ``normalizedExc()``
+  - ``normalizedNonNull()``
+
+* ``baseTypeMin()`` is replaced with ``baseTypeLowest()`` for:
+
+   - ``Vec2``, ``Vec3``, ``Vec4``
+   - ``Color3``, ``Color4``
+   - ``Matrix22``, ``Matrix33``, ``Matrix44``
+   - ``Box``
+   - ``Shear6``
+
diff --git a/docs/PortingGuide2-3.md b/docs/PortingGuide2-3.md
new file mode 100644 (file)
index 0000000..851b64c
--- /dev/null
@@ -0,0 +1,547 @@
+# OpenEXR/Imath 2.x to 3.x Porting Guide
+
+This porting guide outlines the several areas where switching from OpenEXR
+2.x to OpenEXR 3.x + Imath 3.x will require source code or build changes of
+downstream software.
+
+In each case, we will often explain both how to change if you are expecting
+3.x only hereafter, or usually a more complex accommodation if you want to
+keep compatibility with both 2.x and 3.x.
+
+## OpenEXR and Imath Are Different Packages
+
+If your use of OpenEXR was only for the sake of using the math classes and
+utilities, maybe you were unhappy that you needed to download and build the
+full OpenEXR dependency. You are in luck -- now Imath is a separate, very
+lightweight open source package. You can use Imath functionality without
+needing any of OpenEXR, which as of 3.x only includes the parts you need to
+read and write OpenEXR image files.
+
+The parts of "IlmBase" that were `Imath` and `half` are now repackaged
+as the `Imath` library. The `IlmThread` and `Iex` libraries have been
+folded into the OpenEXR package, since they were were not necessary to
+the rest of Imath.
+
+When building OpenEXR 3.x, note that if Imath 3.x library is not found
+already installed at build time, it will be automatically downloaded and
+built as part of the OpenEXR build.
+
+## Background
+
+Why is this happening? Here is the relevant history.
+
+The OpenEXR project has historically consisted of four separate subprojects:
+
+* OpenEXR - the Imf image format
+* IlmBase - supporting utilities (Imath, Half, Iex, IlmThread)
+* PyIlmBase - python bindings for the IlmBase libraries
+* OpenEXR_Viewers - code for an example EXR image viewer 
+
+Prior to the 2.4 release in 2019, OpenEXR relied primarily on the Gnu
+autotools build system and was released as four separate tarballs
+(ilmbase, pyilmbase, openexr, openexr_viewers) that were constructed
+via the Gnu tools. This gave direct access to the "IlmBase" libraries
+independent of the OpenEXR format library. The project also included
+CMake files but CMake support was incomplete.
+
+With the adoption of OpenEXR by the Academy Software Foundation in
+2019, the technical steering committee made several key changes:
+
+1. Drop support for autotools in favor of CMake. A significant portion
+   of the OpenEXR user base uses Windows, which the Gnu autotools does
+   not support.  Supporting two build systems is a maintenance burden
+   that the TSC opted to avoid. We now assume that all modern users of
+   OpenEXR can reasonably be expected to rely on CMake.
+
+2. Rely on GitHub's automatic release packaging mechanism. This
+   packages the entire contents of package in a single
+   tarball. Separate tarballs are no longer generated by the Gnu
+   autotools setup.
+
+3. Deprecate the OpenEXR_Viewers code. It was impossibly out of date
+   and of little modern value.
+
+Thus, with the 2.4 release, the "IlmBase" libraries are no longer
+distributed in a form that is readily separable from the rest of
+OpenEXR. The build and installation process for the overall OpenEXR
+project is complicated by the fact it consists of four separate
+projects, which added signifcant complexity to the CMake setup.
+
+Because Imath is generally useful to the community, the TSC decided to
+simplify the configuration by separating Imath into its own independent
+project, maintained and released independently of OpenEXR, and
+introducing it as a new external dependency of OpenEXR.
+
+To further simplify matters, the new Imath library includes the half
+data type directly, rather than maintaining it in a separate
+library. Also, the community at large has a strong desire for simple
+vector/matrix utilities that are unencumbered by Iex, the IlmBase
+library that provides higher-level exception classes, and even
+further, a clear delineation between functionality that (1) relies on
+exception handlings and (2) is free from exceptions. As a result,
+support for Iex has been removed from Imath, and the Iex library is
+now packaged as a component of OpenEXR.
+
+The Imath python bindings are a part of Imath as a configuration
+option, although support is off by default to simplify the build process
+for most users.
+
+## New Library Names and Repository Structures
+
+The new repositories place all source code under the `src` top-level
+subdirectory.
+
+### Imath:
+
+    src
+    ├── Imath
+    ├── ImathTest
+    └── python
+        ├── config
+        ├── PyImath
+        ├── PyImathNumpy
+        ├── PyImathTest
+        ├── PyImathNumpyTest
+        └── PyImathSpeedTest
+
+
+### OpenEXR:
+
+The 'IlmImf' library has been renamed 'OpenEXR'. No header files have
+changed names, only their locations in the repo have changes.
+
+    src
+    ├── bin
+    │   ├── exr2aces
+    │   ├── exrbuild
+    │   ├── exrcheck
+    │   ├── exrenvmap
+    │   ├── exrheader
+    │   ├── exrmakepreview
+    │   ├── exrmaketiled
+    │   ├── exrmultipart
+    │   ├── exrmultiview
+    │   └── exrstdattr
+    ├── lib
+    │   ├── Iex
+    │   ├── IexMath
+    │   ├── IlmThread
+    │   ├── OpenEXR
+    │   └── OpenEXRUtil
+    ├── examples
+    └── test
+        ├── IexTest
+        ├── OpenEXRTest
+        ├── OpenEXRUtilTest
+        └── OpenEXRFuzzTest
+
+
+## Finding and Using OpenEXR and Imath CMake Configs
+
+### OpenEXR/Imath 3.x only
+
+If you are *only* concerned with OpenEXR/Imath 3.x going forward, this is
+the recommended way to find the libraries in a downstream project that uses
+the CMake build system:
+
+    find_package(Imath CONFIG)
+    find_package(OpenEXR CONFIG)
+
+Note that the second line may be omitted if you only need the Imath
+portions.
+
+And then your project can reference the imported targets like this:
+
+    target_link_libraries (my_target
+        PRIVATE
+            OpenEXR::OpenEXR
+            Imath::Imath
+            Imath::Half
+        )
+
+You only need the parts you use, so for example, if you only need Half and
+Imath, you can omit the OpenEXR target. Also note that in our example above,
+we have used the `PRIVATE` label, but you should specify them as `PUBLIC` if
+you are exposing those classes in your own package's public interface.
+
+
+### Accommodating OpenEXR/Imath 3.x or OpenEXR 2.x
+
+On the other hand, to accommodate both 2.x and 3.x, it's admittedly
+inconvenient because the packages and the import targets have changed their
+names.  We have found the following idioms to work:
+
+Finding either/both packages:
+
+    # First, try to find just the right config files
+    find_package(Imath CONFIG)
+    if (NOT TARGET Imath::Imath)
+        # Couldn't find Imath::Imath, maybe it's older and has IlmBase?
+        find_package(IlmBase CONFIG)
+    endif ()
+    find_package(OpenEXR CONFIG)
+
+To link against them, we use CMake generator expressions so that we can
+reference *both* sets of targets, but it will only use the ones
+corresponding to the package version that was found.
+
+    target_link_libraries (my_target
+        PRIVATE
+            # For OpenEXR/Imath 3.x:
+              $<$<TARGET_EXISTS:OpenEXR::OpenEXR>:OpenEXR::OpenEXR>
+              $<$<TARGET_EXISTS:Imath::Imath>:Imath::Imath>
+              $<$<TARGET_EXISTS:Imath::Half>:Imath::Half>
+            # For OpenEXR 2.4/2.5:
+              $<$<TARGET_EXISTS:OpenEXR::IlmImf>:OpenEXR::IlmImf>
+              $<$<TARGET_EXISTS:IlmBase::Imath>:IlmBase::Imath>
+              $<$<TARGET_EXISTS:IlmBase::Half>:IlmBase::Half>
+              $<$<TARGET_EXISTS:IlmBase::IlmThread>:IlmBase::IlmThread>
+              $<$<TARGET_EXISTS:IlmBase::Iex>:IlmBase::Iex>
+        )
+
+Again, you can eliminate the references to any of the individual libaries
+that you don't actually need for your application.
+
+### Simultaneous Static/Shared Build
+
+The OpenEXR 2.x CMake configuration had options to simultaneously
+build both shared and statically linked libraries. This has been
+deprecated. A CMake configuration setting specifies whether to build
+static or shared, but if you want both, you will need to run cmake and
+build twice.
+
+### Simultaneous Python 2/3 Build
+
+The PyIlmBase 2.x CMake configuration had options to simultaneously
+build both python2 and python3 bindings. This has been deprecated.
+A CMake configuration setting specifies whether to build for
+python 2 or python 3, but if you want both, you will need to run
+cmake and build twice.
+
+## Imath Include Files Are in a Different Subdirectory
+
+Imath 3.0 will copy its headers to some `include/Imath` subdirectory
+instead of the old `include/OpenEXR`.
+
+### OpenEXR/Imath 3.x only
+
+If you know that you are only using Imath 3.x, then just change any
+include directions, like this:
+
+    #include <OpenEXR/ImathVec.h>
+    #include <OpenEXR/half.h>
+
+to the new locations:
+
+    #include <Imath/ImathVec.h>
+    #include <Imath/half.h>
+
+### Accommodating OpenEXR/Imath 3.x or OpenEXR 2.x
+
+If you want your software to be able to build against either OpenEXR 2.x or
+3.x (depending on which dependency is available at build time), we recommend
+using a more complicated idiom:
+
+    // The version can reliably be found in this header file from OpenEXR,
+    // for both 2.x and 3.x:
+    #include <OpenEXR/OpenEXRConfig.h>
+    #define COMBINED_OPENEXR_VERSION ((10000*OPENEXR_VERSION_MAJOR) + \
+                                      (100*OPENEXR_VERSION_MINOR) + \
+                                      OPENEXR_VERSION_PATCH)
+
+    // There's just no easy way to have an `#include` that works in both
+    // cases, so we use the version to switch which set of include files we
+    // use.
+    #if COMBINED_OPENEXR_VERSION >= 20599 /* 2.5.99: pre-3.0 */
+    #   include <Imath/ImathVec.h>
+    #   include <Imath/half.h>
+    #else
+        // OpenEXR 2.x, use the old locations
+    #   include <OpenEXR/ImathVec.h>
+    #   include <OpenEXR/half.h>
+    #endif
+
+## Include Files Include Fewer Other Headers
+
+Extraneous ``#include`` statements have been removed from some header
+files, which can lead to compile failures in application code that
+previously included certain headers indirectly.
+
+For example, the Imath header files no longer include ``float.h``, so
+application code that references symbols such as ``FLT_MAX`` may need
+to add an explicit ``#include <float.h>`` or equivalent.
+
+If your application code reports compile errors due to undefined or
+incompletely-defined Imath or OpenEXR data types, locate the Imath or
+OpenEXR header file that defines the type and include it explicitly.
+
+## Symbols Are Hidden by Default
+
+To reduce library size and make linkage behavior similar across
+platforms, Imath and OpenEXR now build with directives that make
+symbol visibility hidden by default, with specific externally-visible
+symbols explicitly marked for export. See the [Symbol
+Visibility](https://github.com/AcademySoftwareFoundation/openexr/blob/main/docs/SymbolVisibility.md)
+doc and the appropriate ``*Export.h`` header file for more details.
+
+## Imath Now Uses Standard C++ Exceptions and `noexcept`
+
+In OpenEXR 2.x, the Imath functions that threw exceptions used to throw
+various Iex varieties.
+
+In Imath 3.x, these functions just throw `std::exception` varieties that
+correspond to the failure (e.g., `std::invalid_argument`,
+`std::domain_error`, etc.). For that reason, all of the Iex exceptions are
+now only part of the OpenEXR library (where they are still used in the same
+manner they were for OpenEXR 2.x).
+
+Imath 3.x has very few functions that throw exceptions. Each is clearly
+marked as such, and each has a version that does not throw exceptions (so
+that it may be used from code where exceptions are avoided). The functions
+that do not throw exceptions are now marked `noexcept`.
+
+## Some Headers and Classes Have Been Removed from Imath 3.x
+
+* The `Math<T>` class (and `ImathMath.h` header file) are
+  deprecated. All of the `Math<T>` functionality is subsumed by C++11
+  `std::` math functions. For example, calls to
+  `Imath::Math<T>::abs(x)` should be replaced with `std::abs(x)`.
+
+* The `Limits<T>` class (and the `ImathLimits.h` and
+  `ImathHalfLimits.h` headers) have been removed entirely. All uses of
+  `Limits<>` should be replaced with the appropriate
+  `std::numeric_limits<>` method call. The Imath-specific versions
+  predated C++11, and were not only redundant in a C++11 world, but
+  also potentially confusing because some of their functions behaved
+  quite differently than the `std::numeric_limits` method with the
+  same name. We are following the precept that if C++11 does something
+  in a standard way, we should not define our own equivalent function
+  (and especially not define it in a way that doesn't match the
+  standard behavior).
+
+* `Vec<T>::normalize()` and `length()` methods, for integer `T` types,
+  have been removed. Also the standalone `project()` and
+  `orthogonal()` functions are no longer defined for vectors made of
+  integer elements. These all had behavior that was hard to understand
+  and probably useless. They still work as expected for vectors of
+  floating-point types.
+
+* The ``Int64`` and ``SInt64`` types are deprecated in favor of the
+  now-standard ``int64_t`` and ``uint64_t``.
+
+## File/Class-specific changes:
+
+### `half` in half.h
+
+* The half type is now in the `Imath` namespace, but a compile-time
+  option puts it in the global namespace, except when compiling for
+  CUDA, in which case the 'half' type refers to the CUDA type:
+
+      #ifndef __CUDACC__
+      using half = IMATH_INTERNAL_NAMESPACE::half;
+      #else
+      #include <cuda_fp16.h>
+      #endif
+
+  If you desire to use Imath::half inside a CUDA kernal, you can refer
+  to it via the namespace, or define `CUDA_NO_HALF` to avoid the CUDA
+  type altogether.
+
+* `HALF_MIN` has changed value. It is now the smallest **normalized**
+   positive value, returned by `std::numeric_limits<half>::min()`.
+
+* New constructor from a bit pattern:
+
+      enum FromBitsTag
+      {
+          FromBits
+      };
+
+      constexpr half(FromBitsTag, unsigned short bits) noexcept;
+
+### `Imath::Box<T>` in ImathBox.h
+
+* `baseTypeMin()` is replaced with `baseTypeLowest()`
+
+### `Color3<T>`, `Color4<T>` in ImathColor.h
+
+* `baseTypeMin()` is replaced with `baseTypeLowest()`
+
+### `Imath::Frustum<T>` in ImathFrustum.h
+
+Akin to the `Vec` classes, there are now seperate API calls for
+throwing and non-throwing functions:
+
+These functions previously threw exceptions but now do not throw and
+are marked `noexcept`:
+
+* `Frustum<T>::projectionMatrix() noexcept`
+
+* `Frustum<T>::aspect() noexcept`
+
+* `Frustum<T>::set() noexcept`
+
+* `Frustum<T>::projectPointToScreen() noexcept`
+
+* `Frustum<T>::ZToDepth() noexcept`
+
+* `Frustum<T>::DepthToZ() noexcept`
+
+* `Frustum<T>::screenRadius() noexcept`
+
+* `Frustum<T>::localToScreen() noexcept`
+
+These functions throw `std::domain_error` exceptions when the
+associated frustum is degenerate:
+
+* `Frustum<T>::projectionMatrixExc()`
+
+* `Frustum<T>::aspectExc()`
+
+* `Frustum<T>::setExc()`
+
+* `Frustum<T>::projectPointToScreenExc()`
+
+* `Frustum<T>::ZToDepthExc()`
+
+* `Frustum<T>::DepthToZExc()`
+
+* `Frustum<T>::screenRadiusExc()`
+
+* `Frustum<T>::localToScreenExc()`
+
+### `Imath::Interval<T>` in ImathInterval.h
+
+New methods/functions: 
+
+* `Interval<T>::operator !=`
+
+* `Interval<T>::makeInfinite()`
+
+* `Interval<T>isInfinite()`
+
+* `operator<< (std::ostream& s, const Interval<T>&)`
+
+### ImathMatrixAlgo.h
+
+* `checkForZeroScaleInRow()` and `extractAndRemoveScalingAndShear()`
+   throw `std::domain_error` exceptions instead of `Iex::ZeroScale`
+
+### `Matrix22<T>`, `Matrix33<T>`, `Matrix44<T>` in ImathMatrix.h
+
+* `baseTypeMin()` is replaced with `baseTypeLowest()`
+
+* `invert(bool singExc = false)` is replace by:
+
+  - `invert() noexcept`
+
+  - `invert(bool)` which optionally throws an `std::invalid_argument`
+    exception.
+
+* `inverse(bool singExc = false)` is replace by:
+
+  - `inverse() noexcept`
+
+  - `inverse(bool)` which optionally throws an `std::invalid_argument`
+    exception.
+
+* `gjInvert(bool singExc = false)` is replace by:
+
+  - `gjInvert()` noexcept
+
+  - `gjInvert(bool)` which optionally throws an
+    `std::invalid_argument` exception.
+
+* `gJinverse(bool singExc = false)` is replace by:
+
+  - `gjInverse()` noexcept
+
+  - `gjInverse(bool)` which optionally throws an
+    `std::invalid_argument` exception.
+
+New functions:
+
+* `operator<< (std::ostream& s, const Matrix22<T>&)`
+
+* `operator<< (std::ostream& s, const Matrix33<T>&)`
+
+* `operator<< (std::ostream& s, const Matrix44<T>&)`
+
+Other changes:
+
+* Initialization loops unrolled for efficiency
+
+* inline added where appropriate
+
+### ImathRoots.h
+
+* When compiling for CUDA, the `complex` type comes from `thrust`
+  rather than `std`
+
+### `Shear6` in ImathShear.h
+
+* `baseTypeMin()` is replaced with `baseTypeLowest()`
+
+### ImathVecAlgo.h
+
+The following functions are no longer defined for integer-based
+vectors, because such behavior is not clearly defined:
+
+* `project (const Vec& s, const Vec& t)`
+
+* `orgthogonal (const Vec& s, const Vec& t)`
+
+* `reflect (const Vec& s, const Vec& t)`
+
+### `Vec2<T>`, `Vec3<T>`, `Vec4<T>` in ImathVec.h
+
+* `baseTypeMin()` is replaced with `baseTypeLowest()`
+
+* The following methods are removed (via `= delete`) for integer-based
+  vectors because the behavior is not clearly defined and thus prone
+  to confusion:
+
+  - `length()` - although the length is indeed defined, its proper value
+    is floating point and can thus not be represented by the 'T'
+    return type.
+
+  - `normalize()`
+
+  - `normalizeExc()`
+
+  - `normalizeNonNull()`
+
+  - `normalized()`
+
+  - `normalizedExc()`
+
+  - `normalizedNonNull()`
+* Interoperability Constructors: The Vec and Matrix classes now have
+  constructors that take as an argument any data object of similar
+  size and layout.
+
+## Python Changes:
+
+In general, the changes at the C++ level are reflected in the python
+bindings. In particular:
+
+* The following methods are removed for integer-based
+  vector and matrix objects and arrays:
+
+  - `length()`
+  - `normalize()`
+  - `normalizeExc()`
+  - `normalizeNonNull()`
+  - `normalized()`
+  - `normalizedExc()`
+  - `normalizedNonNull()`
+
+* `baseTypeMin()` is replaced with `baseTypeLowest()` for:
+
+   - `Vec2`, `Vec3`, `Vec4`
+   - `Color3`, `Color4`
+   - `Matrix22`, `Matrix33`, `Matrix44`
+   - `Box`
+   - `Shear6`
+
diff --git a/docs/SymbolVisibility.rst b/docs/SymbolVisibility.rst
new file mode 100644 (file)
index 0000000..9588749
--- /dev/null
@@ -0,0 +1,156 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+:orphan:
+
+.. _Symbol Visibility in Imath/OpenEXR:
+
+Symbol Visibility in Imath/OpenEXR
+##################################
+
+Managing symbol visibility in a C++ library can reduce library sizes,
+and with the extra information, the optimizer may produce faster
+code. To take advantage of this, OpenEXR 3.0 is switching to
+explicitly manage symbols on all platforms, with a hidden-by-default
+behavior on unix-based platforms. Managing symbols has always been
+required for Windows DLLs, where one must explicitly tag functions for
+import and export as appropriate.
+
+For C, this is trivial: just tag public functions or global variable
+as default visibility and leave everything else defaulting to
+hidden. However, in C++, this is not exactly the same story. Functions
+and globals are of course the same. And class member functions are
+largely the same, and other than the attribute specification
+mechanics, follow the same rules between gcc, clang, and
+msvc. However, types have richer information than they do in C. So,
+unless extra work is done, concepts for RTTI like the typeinfo and the
+vtable for virtual classes will be hidden, and not visible. These are
+referred to as "vague" linkage objects in some discussions. 
+
+It is with the "vague" linkage objects where different properties
+arise. For example, if you have a template, it is happily instantiated
+in multiple compile units. If the typeinfo is hidden for one library,
+then this may cause things like dynamic_cast to fail because then the
+same typeinfo is not used, and even though one might think that
+``ImfAttribute<Imath::Box2i>`` are the same in two places, because they
+are instantiated in separate places, they may be considered different
+types. To compound the issue, there are different rules for this in
+different implementations. For example, a default gcc under linux
+allows one to link against otherwise private "vague" linkage objects
+such that the typeinfo ends up as the same entity. clang, for MacOS
+anyway, follows a stricter approach and keeps those types separate,
+perhaps due to the two level namespace they maintain for symbols.
+
+Unfortunately, this is not clearly discussed as an overview of the
+differences between platforms, hence this document to add
+clarity. Each compiler / platform describes their own behavior, but
+not how that behaves relative to others. `libc++
+<https://libcxx.llvm.org/docs/DesignDocs/VisibilityMacros.html>`_ from
+the llvm project is the closest to providing comparative information,
+where by looking at how they define their macros and the comments
+surrounding, one can infer the behavior among at least windows DLL
+mode, then gcc vs. clang for unixen. Other compilers, for example,
+Intel's icc, tend to adopt the behavior of the predominant compiler
+for that platform (i.e. msvc under windows, gcc under linux), and so
+can generally adopt that behavior and are ignored here. If this is not
+true, the ifdef rules in the various library ``Export.h`` headers
+within OpenEXR may need to be adjusted, and this table updated.
+
+As a summary, below is a table of the attribute or declspec that needs
+to be used for a particular C++ entity to be properly exported. This
+does not address weak symbols, ABI versioning, and only focusing on
+visibility. Under Windows DLL rules, if one exports the entire class,
+it also exports the types for the member types as well, which is not
+desired, so these are marked as N/A even though the compiler does
+allow that to happen.
+
+.. list-table::
+   :header-rows: 1
+   :align: left
+
+   * - C++ vs Compiler
+     - MSVC
+     - mingw
+     - gcc
+     - clang
+   * - function
+     - ``dllexport/dllimport``
+     - ``dllexport/dllimport``
+     - ``visibility("default")``
+     - ``visibility("default")``
+   * - hide a function
+     - N/A
+     - N/A
+     - ``visibility("hidden")``
+     - ``visibility("hidden")``
+   * - ``class(typeinfo)``
+     - N/A
+     - N/A
+     - ``visibility("default")``
+     - ``visibility("default")``
+   * - template class
+     - N/A
+     - N/A
+     - ``visibility("default")``
+     - ``type_visibility("default")``
+   * - template data
+     - N/A
+     - N/A
+     - ``visibility("default")``
+     - ``visibility("default")``
+   * - class template instantiation
+     - ``dllexport/dllimport``
+     - N/A
+     - N/A
+     - ``visibility("default")``
+   * - enum
+     - N/A
+     - N/A
+     - auto unhides (N/A)
+     - ``type_visibility("default")``
+   * - extern template
+     - N/A
+     - ``dllexport/dllimport``
+     - ``visibility("default")``
+     - ``visibility("default")``
+
+With this matrix in mind, we can see the maximal set of macros we need to
+provide throughout the code. *NB*: This does not mean that we need to
+declare all of these, just that they might be needed.
+
+.. list-table::
+   :header-rows: 1
+   :align: left
+
+   * - macro name
+     - purpose
+   * - ``IMATH_EXPORT``
+     - one of export or import for windows, visibility for others
+   * - ``IMATH_EXPORT_TYPE``
+     - for declaring a class / struct as public (for typeinfo / vtable)
+   * - ``IMATH_HIDDEN``
+     - used to explicitly hide, especially members of types
+   * - ``IMATH_EXPORT_TEMPLATE_TYPE``
+     - stating the template type should be visible
+   * - ``IMATH_EXPORT_EXTERN_TEMPLATE``
+     - exporting template types (i.e. extern side of extern template)
+   * - ``IMATH_EXPORT_TEMPLATE_INSTANCE``
+     - exporting specific template instantiations (in cpp code)
+   * - ``IMATH_EXPORT_TEMPLATE_DATA``
+     - exporting templated data blocks
+   * - ``IMATH_EXPORT_ENUM``
+     - exporting enum types
+
+The preference might be to call ``IMATH_EXPORT`` something like
+``IMATH_FUNC``, and rename things such as ``IMATH_EXPORT_TYPE`` to
+``IMATH_TYPE`` for simplicity. However, historically, OpenEXR has used
+the ``_EXPORT`` tag, and so that is preserved for consistency.
+
+---------
+
+* LLVM libc++ visibility macros: https://libcxx.llvm.org/docs/DesignDocs/VisibilityMacros.html
+
+* GCC visibility wiki: https://gcc.gnu.org/wiki/Visibility
+
+* Apple library design docs: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html
diff --git a/docs/about.rst b/docs/about.rst
new file mode 100644 (file)
index 0000000..8bb635c
--- /dev/null
@@ -0,0 +1,71 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _About Imath:
+
+About Imath
+===========
+
+.. toctree::
+   :caption: About
+             
+Imath is maintained by the OpenEXR project, a part of the `Academy
+Software Foundation <https://www.aswf.io>`_.  The library were
+originally developed at Industrial Light & Magic and first released as
+open source in 2003.
+
+Read the origin story of OpenEXR and Imath, and the ``half`` 16-bit
+float type, in particular, on the `ASWF Blog
+<https://www.aswf.io/news/aswf-deep-dive-openexr-origin-story-part-1>`_.
+
+Imath is Version 3 because it was previously distributed as a
+component of OpenEXR v1 and v2.
+
+OpenEXR and Imath is included in the `VFX Reference Platform <https://vfxplatform.com>`_.
+
+New Features in 3.1
+-------------------
+
+The 3.1 release of Imath introduces optimized half-to-float and
+float-to-half conversion using the F16C SSE instruction set extension,
+if available. These single-instruction conversions offer a 5-10x
+speedup for float-to-half and 2x speedup for half-to-float over
+Imath/half's traditional table-based conversion (timings depend on the
+data).
+
+In the absence of the F16C instruction set, the lookup-table-based
+conversion from half to float is still the default, but Imath 3.1 also
+introduces an optimized bit-shift conversion algorithm as a
+compile-time option that does not require lookup tables, for
+architectures where memory is limited. The float-to-half conversion
+also no longer requires an exponent lookup table, further reducing
+memory requirements.
+
+These new conversions generate the same values as the traditional
+methods, which ensures backwards compatibility.  See :doc:`install`
+for more installation and configuration options.
+
+Also, ``half.h`` can now be included in pure C code for a definition
+of the type and for conversions between half and float.
+
+OpenEXR/Imath 2.x to 3.x Porting Guide
+--------------------------------------
+
+See the :doc:`PortingGuide` for help in restructing old code to work
+with recent releases of OpenEXR and Imath.
+
+Credits
+-------
+
+The ILM Imath library and the ``half`` data type were originally
+designed and implemented at Industrial Light & Magic by Florian Kainz,
+Wojciech Jarosz, Rod Bogart, and others. Drew Hess packaged and
+adapted ILM's internal source code for public release.
+
+For a complete list of contributors see `CONTRIBUTORS.md
+<https://github.com/AcademySoftwareFoundation/Imath/blob/main/CONTRIBUTORS.md>`_.
+
+
+
+
diff --git a/docs/classes.rst b/docs/classes.rst
new file mode 100644 (file)
index 0000000..b258cd7
--- /dev/null
@@ -0,0 +1,34 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _Imath Classes:
+
+Imath Classes
+#############
+
+.. toctree::
+   :caption: Classes
+   :maxdepth: 2
+
+   classes/half
+   classes/Box
+   classes/Color3
+   classes/Color4
+   classes/Euler
+   classes/Frustum
+   classes/Interval
+   classes/Line3
+   classes/Matrix22
+   classes/Matrix33
+   classes/Matrix44
+   classes/Plane3
+   classes/Quat
+   classes/Rand32
+   classes/Rand48
+   classes/Shear6
+   classes/Sphere3
+   classes/Vec2
+   classes/Vec3
+   classes/Vec4
+
diff --git a/docs/classes/Box.rst b/docs/classes/Box.rst
new file mode 100644 (file)
index 0000000..04ed143
--- /dev/null
@@ -0,0 +1,59 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Box
+###
+
+.. code-block::
+
+   #include <Imath/ImathBox.h>
+   
+The ``Box`` class template represents 2D and 3D axis-aligned bounding
+boxes, with predefined typedefs for boxes of type ``short``, ``int``,
+``int64_t``, ``float``, and ``double``.
+
+The box is defined by minimum and maximum values along each axis,
+represented by ``Vec2<T>`` for the ``Box2`` types and by ``Vec3<T>``
+for ``Box3`` types.
+
+There are also various utility functions that operate on bounding
+boxes defined in ``ImathBoxAlgo.h`` and described in :ref:`Box
+Functions <box-functions>`.
+
+Example:
+
+.. literalinclude:: ../examples/Box.cpp
+   :language: c++
+
+.. doxygentypedef:: Box2s
+
+.. doxygentypedef:: Box2i
+
+.. doxygentypedef:: Box2i64
+
+.. doxygentypedef:: Box2f
+
+.. doxygentypedef:: Box2d
+      
+.. doxygentypedef:: Box3s
+
+.. doxygentypedef:: Box3i
+
+.. doxygentypedef:: Box3i64
+
+.. doxygentypedef:: Box3f
+
+.. doxygentypedef:: Box3d
+
+.. doxygenclass:: Imath::Box
+   :undoc-members:
+   :members:
+
+.. doxygenclass:: Imath::Box< Vec2< T > >
+   :undoc-members:
+   :members:
+      
+.. doxygenclass:: Imath::Box< Vec3< T > >
+   :undoc-members:
+   :members:
diff --git a/docs/classes/Color3.rst b/docs/classes/Color3.rst
new file mode 100644 (file)
index 0000000..e6068a1
--- /dev/null
@@ -0,0 +1,42 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Color3
+######
+
+.. code-block::
+
+   #include <Imath/ImathColor.h>
+
+The ``Color3`` class template represents a 3-component color, with
+pre-defined typedefs of ``unsigned char``, ``half``, and ``float``.
+
+The ``Color3`` class inherits from ``Vec3`` and thus has
+fields named ``x``, ``y``, and ``z``. The class itself implies no
+specific interpretation of the values.
+
+There are also various utility functions that operate on colors
+defined in ``ImathColorAlgo.h`` and described in :ref:`Color Functions
+<color-functions>`.
+
+Example:
+
+.. literalinclude:: ../examples/Color3.cpp
+   :language: c++
+
+.. doxygentypedef:: Color3c
+
+.. doxygentypedef:: Color3h
+
+.. doxygentypedef:: Color3f
+
+.. doxygentypedef:: C3c
+
+.. doxygentypedef:: C3h
+
+.. doxygentypedef:: C3f
+                    
+.. doxygenclass:: Imath::Color3
+   :undoc-members:
+   :members:
diff --git a/docs/classes/Color4.rst b/docs/classes/Color4.rst
new file mode 100644 (file)
index 0000000..6b5ea09
--- /dev/null
@@ -0,0 +1,46 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Color4
+######
+
+.. code-block::
+
+   #include <Imath/ImathColor.h>
+   
+The ``Color4`` class template represents a 4-component color (red,
+green, blue, and alpha), with pre-defined typedefs of ``unsigned
+char``, ``half``, and ``float``.
+
+The ``Color4`` class is *not* derived from ``Vec4``. Its fields are
+named ``r``, ``g``, ``b``, and ``a``. The class itself implies no
+specific interpretation of the values.
+
+There are also various utility functions that operate on colors
+defined in ``ImathColorAlgo.h`` and described in :ref:`Color Functions
+<color-functions>`.
+
+Example:
+
+.. literalinclude:: ../examples/Color4.cpp
+   :language: c++
+
+.. doxygentypedef:: Color4c
+
+.. doxygentypedef:: Color4h
+
+.. doxygentypedef:: Color4f
+
+.. doxygentypedef:: C4c
+
+.. doxygentypedef:: C4h
+
+.. doxygentypedef:: C4f
+                    
+.. doxygenclass:: Imath::Color4
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Color4<T>& v)
+      
diff --git a/docs/classes/Euler.rst b/docs/classes/Euler.rst
new file mode 100644 (file)
index 0000000..6c8bf7d
--- /dev/null
@@ -0,0 +1,35 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Euler
+#####
+
+.. code-block::
+
+   #include <Imath/ImathEuler.h>
+   
+The ``Euler`` class template represents an euler angle rotation/orientation,
+with predefined typedefs of type ``float`` and ``double``.
+
+The ``Euler`` class is derived from ``Imath::Vec3`` and thus has
+fields named ``x``, ``y``, and ``z``, which correspond to the first,
+second, and third rotation angles in a specified order, which,
+depending on the order, may not correspond directly to x, y, or z
+rotations.
+
+Example:
+
+.. literalinclude:: ../examples/Euler.cpp
+   :language: c++
+
+.. doxygentypedef:: Eulerf
+
+.. doxygentypedef:: Eulerd
+
+.. doxygenclass:: Imath::Euler
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& o, const Euler<T>& euler)
+      
diff --git a/docs/classes/Frustum.rst b/docs/classes/Frustum.rst
new file mode 100644 (file)
index 0000000..547234d
--- /dev/null
@@ -0,0 +1,26 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Frustum
+#######
+
+.. code-block::
+
+   #include <Imath/ImathFrustum.h>
+   
+The ``Frustum`` class template represents a 3D viewing frustum, with
+predefined typedefs of type ``float`` and ``double``.
+
+Example:
+
+.. literalinclude:: ../examples/Frustum.cpp
+   :language: c++                 
+
+.. doxygentypedef:: Frustumf
+
+.. doxygentypedef:: Frustumd
+                    
+.. doxygenclass:: Imath::Frustum
+   :undoc-members:
+   :members:
diff --git a/docs/classes/Interval.rst b/docs/classes/Interval.rst
new file mode 100644 (file)
index 0000000..17d605e
--- /dev/null
@@ -0,0 +1,36 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Interval
+########
+
+.. code-block::
+
+   #include <Imath/ImathInterval.h>
+   
+The ``Interval`` class template represents a scalar interval, with
+predefined typedefs for ``short``, ``int``, ``float``, and ``double``.
+
+An ``Interval`` is essentially a ``Box<T>`` that allows ``T`` to be a
+scalar.
+
+Example:
+
+.. literalinclude:: ../examples/Interval.cpp
+   :language: c++                 
+
+.. doxygentypedef:: Intervals
+
+.. doxygentypedef:: Intervali
+
+.. doxygentypedef:: Intervalf
+
+.. doxygentypedef:: Intervald
+
+.. doxygenclass:: Imath::Interval
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Interval<T>& v)
+      
diff --git a/docs/classes/Line3.rst b/docs/classes/Line3.rst
new file mode 100644 (file)
index 0000000..f70718b
--- /dev/null
@@ -0,0 +1,33 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Line3
+#####
+
+.. code-block::
+
+   #include <Imath/ImathLine.h>
+   
+The ``Line3`` class template represents a line in 3D space, with
+predefined typedefs for lines of type ``float`` and ``double``.
+
+There are also various utility functions that operate on ``Line3``
+objects defined in ``ImathLineAlgo.h`` and described in :ref:`Line
+Functions <line-functions>`.
+
+Example:
+
+.. literalinclude:: ../examples/Line3.cpp
+   :language: c++                 
+
+.. doxygentypedef:: Line3f
+
+.. doxygentypedef:: Line3d
+   
+.. doxygenclass:: Imath::Line3
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Line3<T>& line)
+      
diff --git a/docs/classes/Matrix22.rst b/docs/classes/Matrix22.rst
new file mode 100644 (file)
index 0000000..d520335
--- /dev/null
@@ -0,0 +1,42 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Matrix22
+########
+
+.. code-block::
+
+   #include <Imath/ImathMatrix.h>
+   
+The ``Matrix22`` class template represents a 2x2 matrix, with
+predefined typedefs for ``float`` and ``double``.
+
+There are also various utility functions that operate on matrices
+defined in ``ImathMatrixAlgo.h`` and described in :ref:`Matrix
+Functions <matrix-functions>`.
+
+Individual components of a matrix ``M`` may be referenced as either
+``M[j][i]`` or ``M.x[j][i]``. While the latter is a little awkward, it has an
+advantage when used in loops that may be auto-vectorized or explicitly
+vectorized by ``#pragma omp simd`` or other such hints, because the function
+call and pointer casting of ``operator[]`` can confuse the compiler just
+enough to prevent vectorization of the loop, whereas directly addressing the
+real underlying array (``M.x[j][i]``) does not.
+
+Example:
+
+.. literalinclude:: ../examples/Matrix22.cpp
+   :language: c++                 
+
+.. doxygentypedef:: M22f
+
+.. doxygentypedef:: M22d
+
+.. doxygenclass:: Imath::Matrix22
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Matrix22<T>& m)
+
+      
diff --git a/docs/classes/Matrix33.rst b/docs/classes/Matrix33.rst
new file mode 100644 (file)
index 0000000..37a22fc
--- /dev/null
@@ -0,0 +1,41 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Matrix33
+########
+
+.. code-block::
+
+   #include <Imath/ImathMatrix.h>
+   
+The ``Matrix33`` class template represents a 3x3 matrix, with
+predefined typedefs for ``float`` and ``double``.
+
+There are also various utility functions that operate on matrices
+defined in ``ImathMatrixAlgo.h`` and described in :ref:`Matrix
+Functions <matrix-functions>`.
+
+Individual components of a matrix ``M`` may be referenced as either
+``M[j][i]`` or ``M.x[j][i]``. While the latter is a little awkward, it has an
+advantage when used in loops that may be auto-vectorized or explicitly
+vectorized by ``#pragma omp simd`` or other such hints, because the function
+call and pointer casting of ``operator[]`` can confuse the compiler just
+enough to prevent vectorization of the loop, whereas directly addressing the
+real underlying array (``M.x[j][i]``) does not.
+
+Example:
+
+.. literalinclude:: ../examples/Matrix33.cpp
+   :language: c++                 
+
+.. doxygentypedef:: M33f
+
+.. doxygentypedef:: M33d
+
+.. doxygenclass:: Imath::Matrix33
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Matrix33<T>& m)
+
diff --git a/docs/classes/Matrix44.rst b/docs/classes/Matrix44.rst
new file mode 100644 (file)
index 0000000..e183da4
--- /dev/null
@@ -0,0 +1,41 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Matrix44
+########
+
+.. code-block::
+
+   #include <Imath/ImathMatrix.h>
+   
+The ``Matrix44`` class template represents a 4x4 matrix, with
+predefined typedefs for ``float`` and ``double``.
+
+There are also various utility functions that operate on matrices
+defined in ``ImathMatrixAlgo.h`` and described in :ref:`Matrix
+Functions <matrix-functions>`.
+
+Individual components of a matrix ``M`` may be referenced as either
+``M[j][i]`` or ``M.x[j][i]``. While the latter is a little awkward, it has an
+advantage when used in loops that may be auto-vectorized or explicitly
+vectorized by ``#pragma omp simd`` or other such hints, because the function
+call and pointer casting of ``operator[]`` can confuse the compiler just
+enough to prevent vectorization of the loop, whereas directly addressing the
+real underlying array (``M.x[j][i]``) does not.
+
+Example:
+
+.. literalinclude:: ../examples/Matrix44.cpp
+   :language: c++
+               
+.. doxygentypedef:: M44f
+
+.. doxygentypedef:: M44d
+
+.. doxygenclass:: Imath::Matrix44
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Matrix44<T>& m)
+      
diff --git a/docs/classes/Plane3.rst b/docs/classes/Plane3.rst
new file mode 100644 (file)
index 0000000..24f947a
--- /dev/null
@@ -0,0 +1,29 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Plane3
+######
+
+.. code-block::
+
+   #include <Imath/ImathPlane.h>
+   
+The ``Plane3`` class template represents a plane in 3D space, with
+predefined typedefs for planes of type ``float`` and ``double``.
+
+Example:
+
+.. literalinclude:: ../examples/Plane3.cpp
+   :language: c++
+               
+.. doxygentypedef:: Plane3f
+
+.. doxygentypedef:: Plane3d
+
+.. doxygenclass:: Imath::Plane3
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Plane3<T>& plane)
+      
diff --git a/docs/classes/Quat.rst b/docs/classes/Quat.rst
new file mode 100644 (file)
index 0000000..0ced3ca
--- /dev/null
@@ -0,0 +1,28 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Quat
+####
+
+.. code-block::
+
+   #include <Imath/ImathQuat.h>
+   
+The ``Quat`` class template represents a quaterion
+rotation/orientation, with predefined typedefs for ``float`` and
+``double``.
+
+Example:
+
+.. literalinclude:: ../examples/Quat.cpp
+   :language: c++
+              
+.. doxygentypedef:: Quatf
+
+.. doxygenclass:: Imath::Quat
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Quat<T>& q)
+      
diff --git a/docs/classes/Rand32.rst b/docs/classes/Rand32.rst
new file mode 100644 (file)
index 0000000..29df667
--- /dev/null
@@ -0,0 +1,18 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Rand32
+######
+
+.. code-block::
+
+   #include <Imath/ImathRandom.h>
+   
+The ``Rand32`` class is a fast pseudo-random number generator that
+generates a uniformly distributed sequence with a period length of
+:math:`2^32`.
+
+.. doxygenclass:: Imath::Rand32
+   :undoc-members:
+   :members:
diff --git a/docs/classes/Rand48.rst b/docs/classes/Rand48.rst
new file mode 100644 (file)
index 0000000..42f45ec
--- /dev/null
@@ -0,0 +1,18 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Rand48
+######
+
+.. code-block::
+
+   #include <Imath/ImathRandom.h>   
+
+The ``Rand48`` class is a fast pseudo-random number generator based on
+the C Standard Library functions erand48(), nrand48() & company. It
+generates a uniformly distributed sequence.
+
+.. doxygenclass:: Imath::Rand48
+   :undoc-members:
+   :members:
diff --git a/docs/classes/Shear6.rst b/docs/classes/Shear6.rst
new file mode 100644 (file)
index 0000000..2326c91
--- /dev/null
@@ -0,0 +1,27 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Shear6
+######
+
+.. code-block::
+
+   #include <Imath/ImathShear.h>   
+
+The ``Shear6`` class template represent a 3D shear transformation,
+with predefined typedefs for ``float`` and ``double``.
+
+Example:
+
+.. literalinclude:: ../examples/Shear6.cpp
+   :language: c++
+              
+.. doxygentypedef:: Shear6f
+
+.. doxygenclass:: Imath::Shear6
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Shear6<T>& h)
+      
diff --git a/docs/classes/Sphere3.rst b/docs/classes/Sphere3.rst
new file mode 100644 (file)
index 0000000..92e11a5
--- /dev/null
@@ -0,0 +1,24 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Sphere3
+#######
+
+.. code-block::
+
+   #include <Imath/ImathSphere.h>
+   
+The ``Sphere3`` class template represents a sphere in 3D space, with
+predefined typedefs for lines of type ``float`` and ``double``.
+
+Example:
+
+.. literalinclude:: ../examples/Sphere3.cpp
+   :language: c++
+              
+.. doxygentypedef:: Sphere3f
+
+.. doxygenclass:: Imath::Sphere3
+   :undoc-members:
+   :members:
diff --git a/docs/classes/Vec2.rst b/docs/classes/Vec2.rst
new file mode 100644 (file)
index 0000000..b9135ad
--- /dev/null
@@ -0,0 +1,58 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Vec2
+####
+
+.. code-block::
+
+   #include <Imath/ImathVec.h>
+   
+The ``Vec2`` class template represents a 2D vector, with predefined
+typedefs for vectors of type ``short``, ``int``, ``int64_t``, ``float``, and
+``double``.
+
+Note that the integer specializations of ``Vec2`` lack the
+``length()`` and ``normalize()`` methods that are present in the
+``float`` and ``double`` versions, because the results don't fit into
+integer quantities.
+
+There are also various utility functions that operate on vectors
+defined in ``ImathVecAlgo.h`` and described in :ref:`Vector Functions
+<vector-functions>`.
+
+Individual components of a vector ``V`` may be referenced as either ``V[i]``
+or ``V.x``, ``V.y``. Obviously, the ``[]`` notation is more
+suited to looping over components, or in cases where a variable determines
+which coordinate is needed. However, when the coordinate is known, it can be
+more efficient to directly address the components, such as ``V.y`` rather than
+``V[1]``. While both appear to do the same thing (and indeed do generate the
+same machine operations for ordinary scalar code), when used inside loops that
+you hope to parallelize (either through compiler auto-vectorization or
+explicit hints such as ``#pragma omp simd``), the function call and
+pointer casting of ``operator[]`` can confuse the compiler just enough to
+prevent vectorization of the loop.
+
+Example:
+
+.. literalinclude:: ../examples/Vec2.cpp
+   :language: c++
+              
+.. doxygentypedef:: V2s
+
+.. doxygentypedef:: V2i
+                    
+.. doxygentypedef:: V2i64
+                    
+.. doxygentypedef:: V2f
+                    
+.. doxygentypedef:: V2d
+                    
+.. doxygenclass:: Imath::Vec2
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Vec2<T>& v)
+
+      
diff --git a/docs/classes/Vec3.rst b/docs/classes/Vec3.rst
new file mode 100644 (file)
index 0000000..7131ca1
--- /dev/null
@@ -0,0 +1,58 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Vec3
+####
+
+.. code-block::
+
+   #include <Imath/ImathVec.h>
+   
+The ``Vec3`` class template represents a 3D vector, with predefined
+typedefs for vectors of type ``short``, ``int``, ``int64_t``,
+``float``, and ``double``.
+
+Note that the integer specializations of ``Vec3`` lack the
+``length()`` and ``normalize()`` methods that are present in the
+``float`` and ``double`` versions, because the results don't fit into
+integer quantities.
+
+There are also various utility functions that operate on vectors
+defined in ``ImathVecAlgo.h`` and described in :ref:`Vector Functions
+<vector-functions>`.
+
+Individual components of a vector ``V`` may be referenced as either ``V[i]``
+or ``V.x``, ``V.y``, ``V.z``. Obviously, the ``[]`` notation is more
+suited to looping over components, or in cases where a variable determines
+which coordinate is needed. However, when the coordinate is known, it can be
+more efficient to directly address the components, such as ``V.y`` rather than
+``V[1]``. While both appear to do the same thing (and indeed do generate the
+same machine operations for ordinary scalar code), when used inside loops that
+you hope to parallelize (either through compiler auto-vectorization or
+explicit hints such as ``#pragma omp simd``), the function call and
+pointer casting of ``operator[]`` can confuse the compiler just enough to
+prevent vectorization of the loop.
+
+Example:
+
+.. literalinclude:: ../examples/Vec3.cpp
+   :language: c++
+              
+.. doxygentypedef:: V3s
+
+.. doxygentypedef:: V3i
+                    
+.. doxygentypedef:: V3i64
+                    
+.. doxygentypedef:: V3f
+                    
+.. doxygentypedef:: V3d
+                    
+.. doxygenclass:: Imath::Vec3
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Vec3<T>& v)
+
+      
diff --git a/docs/classes/Vec4.rst b/docs/classes/Vec4.rst
new file mode 100644 (file)
index 0000000..1e3f8e6
--- /dev/null
@@ -0,0 +1,57 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Vec4
+####
+
+.. code-block::
+
+   #include <Imath/ImathVec.h>
+   
+The ``Vec4`` class template represents a 4D vector, with predefined
+typedefs for vectors of type ``short``, ``int``, ``int64_t``,
+``float``, and ``double``.
+
+Note that the integer specializations of ``Vec4`` lack the
+``length()`` and ``normalize()`` methods that are present in the
+``float`` and ``double`` versions, because the results don't fit into
+integer quantities.
+
+There are also various utility functions that operate on vectors
+defined in ``ImathVecAlgo.h`` and described in :ref:`Vector Functions
+<vector-functions>`.
+
+Individual components of a vector ``V`` may be referenced as either ``V[i]``
+or ``V.x``, ``V.y``, ``V.z``, ``V.w``. Obviously, the ``[]`` notation is more
+suited to looping over components, or in cases where a variable determines
+which coordinate is needed. However, when the coordinate is known, it can be
+more efficient to directly address the components, such as ``V.y`` rather than
+``V[1]``. While both appear to do the same thing (and indeed do generate the
+same machine operations for ordinary scalar code), when used inside loops that
+you hope to parallelize (either through compiler auto-vectorization or
+explicit hints such as ``#pragma omp simd``), the function call and
+pointer casting of ``operator[]`` can confuse the compiler just enough to
+prevent vectorization of the loop.
+
+Example:
+
+.. literalinclude:: ../examples/Vec4.cpp
+   :language: c++
+              
+.. doxygentypedef:: V4s
+
+.. doxygentypedef:: V4i
+                    
+.. doxygentypedef:: V4i64
+                    
+.. doxygentypedef:: V4f
+                    
+.. doxygentypedef:: V4d
+                    
+.. doxygenclass:: Imath::Vec4
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& s, const Vec4<T>& v)
+      
diff --git a/docs/classes/float.rst b/docs/classes/float.rst
new file mode 100644 (file)
index 0000000..b9c9566
--- /dev/null
@@ -0,0 +1,183 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+Floating Point Representation
+#############################
+
+The half type is a 16-bit floating number, compatible with the
+IEEE 754-2008 binary16 type.
+
+Representation of a 32-bit float
+--------------------------------
+
+We assume that a float, ``f``, is an IEEE 754 single-precision
+floating point number, whose bits are arranged as follows:
+
+.. code-block::
+
+    31 (msb)
+    |
+    | 30     23
+    | |      |
+    | |      | 22                    0 (lsb)
+    | |      | |                     |
+    X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
+
+    s e        m
+
+``s`` is the sign-bit, ``e`` is the exponent and ``m`` is the significand.
+
+If ``e`` is between 1 and 254, ``f`` is a normalized number:
+
+.. math::    {\tt f} = (-1)^{\tt s} \times 2^{\tt e-127} \times {\tt 1.m}
+
+If ``e`` is 0, and ``m`` is not zero, ``f`` is a denormalized number:
+
+.. math::    {\tt f} = (-1)^{\tt s} \times 2^{\tt e-126} \times {\tt 0.m}
+    
+If ``e`` and ``m`` are both zero, ``f`` is zero:
+
+.. math::    {\tt f} = 0.0
+
+If ``e`` is 255, ``f`` is an "infinity" or "not a number" (NAN),
+depending on whether ``m`` is zero or not.
+
+Examples:
+
+.. code-block::
+
+    0 00000000 00000000000000000000000 = 0.0
+    0 01111110 00000000000000000000000 = 0.5
+    0 01111111 00000000000000000000000 = 1.0
+    0 10000000 00000000000000000000000 = 2.0
+    0 10000000 10000000000000000000000 = 3.0
+    1 10000101 11110000010000000000000 = -124.0625
+    0 11111111 00000000000000000000000 = +infinity
+    1 11111111 00000000000000000000000 = -infinity
+    0 11111111 10000000000000000000000 = NAN
+    1 11111111 11111111111111111111111 = NAN
+
+Representation of a 16-bit half
+-------------------------------
+
+Here is the bit-layout for a half number, ``h``:
+
+.. code-block::
+
+    15 (msb)
+    |
+    | 14  10
+    | |   |
+    | |   | 9        0 (lsb)
+    | |   | |        |
+    X XXXXX XXXXXXXXXX
+
+    s e     m
+
+``s`` is the sign-bit, ``e`` is the exponent and ``m`` is the significand.
+
+If ``e`` is between 1 and 30, ``h`` is a normalized number:
+
+.. math::    {\tt h} = (-1)^{\tt s} \times 2^{\tt e-15} \times {\tt 1.m}
+    
+If ``e`` is 0, and ``m`` is not zero, ``h`` is a denormalized number:
+
+.. math::    {\tt h} = (-1)^{\tt s} \times 2^{\tt -14} \times {\tt 0.m}
+
+If ``e`` and ``m`` are both zero, ``h`` is zero:
+
+.. math::    {\tt h} = 0.0
+
+If ``e`` is 31, ``h`` is an "infinity" or "not a number" (NAN),
+depending on whether ``m`` is zero or not.
+
+Examples:
+
+.. code-block::
+
+    0 00000 0000000000 = 0.0
+    0 01110 0000000000 = 0.5
+    0 01111 0000000000 = 1.0
+    0 10000 0000000000 = 2.0
+    0 10000 1000000000 = 3.0
+    1 10101 1111000001 = -124.0625
+    0 11111 0000000000 = +infinity
+    1 11111 0000000000 = -infinity
+    0 11111 1000000000 = NAN
+    1 11111 1111111111 = NAN
+
+Conversion via Lookup Table
+---------------------------
+
+Converting from half to float is performed by default using a
+lookup table. There are only 65,536 different half numbers; each
+of these numbers has been converted and stored in a table pointed
+to by the ``imath_half_to_float_table`` pointer.
+
+Prior to Imath v3.1, conversion from float to half was
+accomplished with the help of an exponent look table, but this is
+now replaced with explicit bit shifting.
+
+Conversion via Hardware
+-----------------------
+
+For Imath v3.1, the conversion routines have been extended to use
+F16C SSE instructions whenever present and enabled by compiler
+flags.
+
+Conversion via Bit-Shifting
+---------------------------
+
+If F16C SSE instructions are not available, conversion can be
+accomplished by a bit-shifting algorithm. For half-to-float
+conversion, this is generally slower than the lookup table, but it
+may be preferable when memory limits preclude storing of the
+65,536-entry lookup table.
+
+The lookup table symbol is included in the compilation even if
+``IMATH_HALF_USE_LOOKUP_TABLE`` is false, because application code
+using the exported ``half.h`` may choose to enable the use of the table.
+
+An implementation can eliminate the table from compilation by
+defining the ``IMATH_HALF_NO_LOOKUP_TABLE`` preprocessor symbol.
+Simply add:
+
+.. code-block::
+
+    #define IMATH_HALF_NO_LOOKUP_TABLE
+
+before including ``half.h``, or define the symbol on the compile
+command line.
+
+Furthermore, an implementation wishing to receive ``FE_OVERFLOW``
+and ``FE_UNDERFLOW`` floating point exceptions when converting
+float to half by the bit-shift algorithm can define the
+preprocessor symbol ``IMATH_HALF_ENABLE_FP_EXCEPTIONS`` prior to
+including ``half.h``:
+
+.. code-block::
+
+    #define IMATH_HALF_ENABLE_FP_EXCEPTIONS
+
+Conversion Performance Comparison
+---------------------------------
+
+Testing on a Core i9, the timings are approximately:
+
+- half to float:
+
+  * table: 0.71 ns / call
+  * no table: 1.06 ns / call
+  * f16c: 0.45 ns / call
+
+- float-to-half:
+
+  * original: 5.2 ns / call
+  * no exp table + opt: 1.27 ns / call
+  * f16c: 0.45 ns / call
+
+**Note:** the timing above depends on the distribution of the
+floats in question.
+
+
diff --git a/docs/classes/half.rst b/docs/classes/half.rst
new file mode 100644 (file)
index 0000000..016f14c
--- /dev/null
@@ -0,0 +1,36 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _half:
+
+half
+####
+
+.. code-block::
+
+   #include <Imath/half.h>
+
+``half`` is a 16-bit floating point number. See :doc:`float` for an
+explanation of the representation.
+
+See :doc:`half_c` for C-language functions for conversion
+between ``half`` and ``float``. Also, see :doc:`half_conversion`
+for information about building Imath with support for the F16C SSE
+instruction set.
+
+Example:
+
+.. literalinclude:: ../examples/half.cpp
+   :language: c++
+              
+.. toctree::
+   :caption: half
+   :maxdepth: 1
+
+   half_class
+   half_limits
+   half_c
+   half_conversion
+   float
+              
diff --git a/docs/classes/half_c.rst b/docs/classes/half_c.rst
new file mode 100644 (file)
index 0000000..7ad0911
--- /dev/null
@@ -0,0 +1,21 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+C-language half-float Conversion
+################################
+
+The ``half.h`` header can be included in pure C code:
+
+.. literalinclude:: ../examples/half.c
+   :language: c
+
+The only C-language operations supported for the ``half`` type are
+conversion to and from ``float``. No arithmetic operations are
+currently implemented in the C interface.
+
+.. doxygenfunction:: imath_half_to_float
+
+.. doxygenfunction:: imath_float_to_half
+
+
diff --git a/docs/classes/half_class.rst b/docs/classes/half_class.rst
new file mode 100644 (file)
index 0000000..061b20c
--- /dev/null
@@ -0,0 +1,16 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+The half Class
+##############
+
+.. doxygenclass:: Imath::half
+   :undoc-members:
+   :members:
+
+.. doxygenfunction:: operator<<(std::ostream& os, Imath::half h)
+
+.. doxygenfunction:: operator>>(std::istream&, Imath::half&)
+
+                     
diff --git a/docs/classes/half_conversion.rst b/docs/classes/half_conversion.rst
new file mode 100644 (file)
index 0000000..6c64e60
--- /dev/null
@@ -0,0 +1,75 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _half-float-conversion-configuration-options:
+
+Build-time half-float Conversion Configuration Options
+######################################################
+
+The Imath library supports three options for conversion between 16-bit
+half and 32-bit float:
+
+1. Conversion from half to float via a 16-bit lookup table. Prior to
+   Imath v3.1, this was the only method supported.
+
+2. F16C SSE instructions: single-instruction conversion for machine
+   architectures that support it. When available, this is the fastest
+   option, by far.
+
+3. Bit-shift conversion algorithm.
+
+To use the F16C SSE instruction set on an architecture that supports
+it, simply provide the appropriate compiler flags when building an
+application that includes ``half.h``. For g++ and clang,
+for example:
+::
+
+    $ cmake -DCMAKE_CXX_FLAGS="-m16fc" <source directory> 
+    
+When code including ``half.h`` is compiled with F16C enabled, it will
+automatically perform conversions using the instruction set. F16C
+compiler flags take precedence over other lookup-table-related Imath
+CMake settings.
+
+On architectures that do not support F16C, you may choose at
+compile-time between the bit-shift conversion and lookup table
+conversion via the ``IMATH_HALF_USE_LOOKUP_TABLE`` CMake option:
+::
+
+    $ cmake -DIMATH_HALF_USE_LOOKUP_TABLE=OFF <source directory>
+
+Note that when building and installing the Imath library itself, the
+65,536-entry lookup table symbol will be compiled into the library
+even if the ``IMATH_HALF_USE_LOOKUP_TABLE`` setting is false. This
+allows applications using that installed Imath library downstream to
+choose at compile time which conversion method to use.
+
+Applications with memory limitations that cannot accomodate the
+conversion lookup table can eliminate it from the library by building
+Imath with the C preprocessor define ``IMATH_HALF_NO_LOOKUP_TABLE``
+defined. Note that this is a compile-time option, not a CMake setting
+(making it possible for application code to choose the desired
+behavior). Simply add:
+::
+
+    #define IMATH_HALF_NO_LOOKUP_TABLE
+
+before including ``half.h``, or define the symbol on the compile
+command line.
+
+Furthermore, an implementation wishing to receive ``FE_OVERFLOW`` and
+``FE_UNDERFLOW`` floating point exceptions when converting float to
+half by the bit-shift algorithm can define the preprocessor symbol
+``IMATH_HALF_ENABLE_FP_EXCEPTIONS`` prior to including ``half.h``:
+::
+   
+    #define IMATH_HALF_ENABLE_FP_EXCEPTIONS
+
+By default, no exceptions are raised on overflow and underflow.
+
+
+
+
+
+
diff --git a/docs/classes/half_limits.rst b/docs/classes/half_limits.rst
new file mode 100644 (file)
index 0000000..72b6392
--- /dev/null
@@ -0,0 +1,117 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+half Limits
+###########
+
+Constants
+---------
+
+``HALF_DENORM_MIN``
+  Smallest positive denormalized half.
+
+``HALF_NRM_MIN``
+  Smallest positive normalized half.
+
+``HALF_MIN``
+  Smallest positive normalized half.
+
+``HALF_MAX``
+  Largest positive half.
+
+``HALF_EPSILON``
+  Smallest positive e for which half(1.0 + e) != half(1.0)
+
+``HALF_MANT_DIG``
+  Number of digits in mantissa (significand + hidden leading 1)
+
+``HALF_DIG``
+  Number of base 10 digits that can be represented without change:
+
+    floor( (``HALF_MANT_DIG`` - 1) * log10(2) ) => 3.01... -> 3
+
+``HALF_DECIMAL_DIG``
+  Number of base-10 digits that are necessary to uniquely represent
+  all distinct values:
+
+    ceil(``HALF_MANT_DIG`` * log10(2) + 1) => 4.31... -> 5
+
+``HALF_RADIX``
+  Base of the exponent.
+
+``HALF_DENORM_MIN_EXP``
+  Minimum negative integer such that ``HALF_RADIX`` raised to the
+  power of one less than that integer is a normalized half.
+
+``HALF_MAX_EXP``
+  Maximum positive integer such that ``HALF_RADIX`` raised to the
+  power of one less than that integer is a normalized half.
+
+``HALF_DENORM_MIN_10_EXP``
+  Minimum positive integer such that 10 raised to that power is a
+  normalized half.
+
+``HALF_MAX_10_EXP``
+  Maximum positive integer such that 10 raised to that power is a
+  normalized half.
+
+``std::numeric_limits<half>``
+-----------------------------
+
+The ``half`` type provides specializations for
+``std::numeric_limits<half>``:
+
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::min() <https://en.cppreference.com/w/cpp/types/numeric_limits/min>`_                           | ``HALF_MIN``               |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::max() <https://en.cppreference.com/w/cpp/types/numeric_limits/max>`_                           | ``HALF_MAX``               |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::lowest() <https://en.cppreference.com/w/cpp/types/numeric_limits/lowest>`_                     | ``-HALF_MAX``              |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::digits <https://en.cppreference.com/w/cpp/types/numeric_limits/digits>`_                       | ``HALF_MANT_DIG``          |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::digits10 <https://en.cppreference.com/w/cpp/types/numeric_limits/digits10>`_                   | ``HALF_DIG``               |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::max_digits10 <https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10>`_           | ``HALF_DECIMAL_DIG``       |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::is_signed <https://en.cppreference.com/w/cpp/types/numeric_limits/is_signed>`_                 | ``true``                   |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::is_integer <https://en.cppreference.com/w/cpp/types/numeric_limits/is_integer>`_               | ``false``                  |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::is_exact <https://en.cppreference.com/w/cpp/types/numeric_limits/is_exact>`_                   | ``false``                  |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::radix <https://en.cppreference.com/w/cpp/types/numeric_limits/radix>`_                         | ``HALF_RADIX``             |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::epsilon() <https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon>`_                   | ``HALF_EPSILON``           |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::round_error() <https://en.cppreference.com/w/cpp/types/numeric_limits/round_error()>`_         | ``0.5``                    |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::min_exponent <https://en.cppreference.com/w/cpp/types/numeric_limits/min_exponent>`_           | ``HALF_DENORM_MIN_EXP``    |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::min_exponent10 <https://en.cppreference.com/w/cpp/types/numeric_limits/min_exponent10>`_       | ``HALF_DENORM_MIN_10_EXP`` |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::max_exponent <https://en.cppreference.com/w/cpp/types/numeric_limits/max_exponent>`_           | ``HALF_MAX_EXP``           |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::max_exponent10 <https://en.cppreference.com/w/cpp/types/numeric_limits/max_exponent10>`_       | ``HALF_MAX_10_EXP``        |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::has_infinity <https://en.cppreference.com/w/cpp/types/numeric_limits/has_infinity>`_           | ``true``                   |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::has_quiet_NaN <https://en.cppreference.com/w/cpp/types/numeric_limits/has_quiet_NaN>`_         | ``true``                   |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::has_signaling_NaN <https://en.cppreference.com/w/cpp/types/numeric_limits/has_signaling_NaN>`_ | ``true``                   |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::has_denorm <https://en.cppreference.com/w/cpp/types/numeric_limits/denorm_style>`_             | ``std::denorm_present``    |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::has_denorm_loss <https://en.cppreference.com/w/cpp/types/numeric_limits/has_denorm_loss>`_     | ``false``                  |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::infinity() <https://en.cppreference.com/w/cpp/types/numeric_limits/infinity()>`_               | ``half::posInf()``         |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::quiet_NaN() <https://en.cppreference.com/w/cpp/types/numeric_limits/quiet_NaN()>`_             | ``half::qNan()``           |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::signaling_NaN() <https://en.cppreference.com/w/cpp/types/numeric_limits/signaling_NaN()>`_     | ``half::sNan()``           |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+| `std::numeric_limits<half>::denorm_min() <https://en.cppreference.com/w/cpp/types/numeric_limits/denorm_min()>`_           | ``HALF_DENORM_MIN``        |
++----------------------------------------------------------------------------------------------------------------------------+----------------------------+
+
+  
diff --git a/docs/concepts.rst b/docs/concepts.rst
new file mode 100644 (file)
index 0000000..46405c3
--- /dev/null
@@ -0,0 +1,143 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _Concepts:
+
+Concepts
+########
+
+.. toctree::
+   :caption: Concepts
+   :maxdepth: 0
+              
+The Imath library emphasizes simplicity, ease of use, correctness and
+verifiability, performance, and breadth of adoption. Imath is not
+intended to be a comprehensive linear algebra or numerical analysis
+package.
+
+Imath is not a substitute for `Eigen <https://eigen.tuxfamily.org>`_!
+It's not a full-featured linear algebra package, and it doesn't
+represent vectors and matrices of arbitrary dimension. Its greatest
+utility is as a geometric data representation, primarily for 2D images
+and 3D scenes and coordinate transformations, along with an
+accompanying set of utility methods and functions.
+
+Example
+=======
+
+A basic program:
+
+.. literalinclude:: examples/intro.cpp
+
+Matrices Are Row-Major
+======================
+
+Imath stores matrices in row-major layout, originally inspired by
+compatibility with OpenGL matrices. 
+
+A matrix described as:
+
+.. math::
+  \begin{bmatrix}
+  m_{00} & m_{01} & m_{02} & m_{03} \\
+  m_{10} & m_{11} & m_{12} & m_{13} \\
+  m_{20} & m_{21} & m_{22} & m_{23} \\
+  m_{30} & m_{31} & m_{32} & m_{33} \\
+  \end{bmatrix}
+
+is laid out in memory as:
+
+.. list-table::
+   :widths: 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+   :header-rows: 1
+
+   * - 0
+     - 1
+     - 2
+     - 3
+     - 4
+     - 5
+     - 6
+     - 7
+     - 8
+     - 9
+     - 10
+     - 11
+     - 12
+     - 13
+     - 14
+     - 15
+   * - :math:`m_{00}`
+     - :math:`m_{01}`
+     - :math:`m_{02}`
+     - :math:`m_{03}`
+     - :math:`m_{10}`
+     - :math:`m_{11}`
+     - :math:`m_{12}`
+     - :math:`m_{13}`
+     - :math:`m_{20}`
+     - :math:`m_{21}`
+     - :math:`m_{22}`
+     - :math:`m_{23}`
+     - :math:`m_{30}`
+     - :math:`m_{31}`
+     - :math:`m_{32}`
+     - :math:`m_{33}`
+
+A matrix representing a homogeneous transform has a right-hand column
+of :math:`\begin{bmatrix} 0 & 0 & 0 & 1\end{bmatrix}` and the
+translation component across the bottom row.
+
+As a result, it is best to think of Imath vectors as row-vectors, and
+vector-matrix multiplication with the vector on the left and matrix on
+the right:
+
+.. math::
+  \begin{bmatrix} v_{0}' & v_{1}' & v_{2}' & 1' \end{bmatrix}
+  =
+  \begin{bmatrix} v_{0} & v_{1} & v_{2} & 1 \end{bmatrix}
+  \begin{bmatrix} m_{00} & m_{01} & m_{02} & 0 \\
+  m_{10} & m_{11} & m_{12} & 0 \\
+  m_{20} & m_{21} & m_{22} & 0 \\
+  m_{30} & m_{31} & m_{32} & 1
+  \end{bmatrix}
+
+This further implies that you should interpret local transformations
+as pre-multiplication:
+
+.. code-block::
+
+   M44f M;
+   M.translate (tx, ty, tz);
+   m.rotate (r, 0, 0);
+   m.scale (s);
+
+.. math::
+  \begin{bmatrix}
+  m_{00} & m_{01} & m_{02} & m_{03} \\
+  m_{10} & m_{11} & m_{12} & m_{13} \\
+  m_{20} & m_{21} & m_{22} & m_{23} \\
+  m_{30} & m_{31} & m_{32} & m_{33} \\
+  \end{bmatrix}
+  = 
+  \begin{bmatrix}
+  s & 0 & 0 & 0 \\
+  0 & s & 0 & 0 \\
+  0 & 0 & s & 0 \\
+  0 & 0 & 0 & 1 \\
+  \end{bmatrix}
+  \begin{bmatrix}
+  1 & 0 & 0 & 0 \\
+  0 & \cos(r) & \sin(r) & 0 \\
+  0 & -\sin(r) & \cos(r) & 0 \\
+  0 & 0 & 0 & 1 \\
+  \end{bmatrix}
+  \begin{bmatrix}
+  1 & 0 & 0 & 0 \\
+  0 & 1 & 0 & 0 \\
+  0 & 0 & 1 & 0 \\
+  tx & ty & tz & 1 \\
+  \end{bmatrix}
+
+
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644 (file)
index 0000000..b8c2166
--- /dev/null
@@ -0,0 +1,309 @@
+#!/usr/bin/env python3
+
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+# -*- coding: utf-8 -*-
+#
+# ReadTheDocs-Breathe documentation build configuration file, created by
+# sphinx-quickstart on Mon Feb 10 20:03:57 2014.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# hack for readthedocs to cause it to run doxygen first
+# https://github.com/rtfd/readthedocs.org/issues/388
+
+on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
+if on_rtd:
+
+  with open("Doxyfile.in", "r") as file:
+    filedata = file.read()
+
+  doxygen_output_dir = "_build"
+  filedata = filedata.replace('@DOXYGEN_INPUT_DIR@', "../src/Imath")
+  filedata = filedata.replace('@DOXYGEN_OUTPUT_DIR@', "doxygen")
+
+  with open("Doxyfile", "w") as file:
+    file.write(filedata)
+
+  from subprocess import call 
+  call('doxygen')
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+    'sphinx.ext.autodoc',
+    'sphinx.ext.todo',
+    'sphinx.ext.viewcode',
+    'breathe',
+]
+
+# Breathe extension variables
+breathe_projects = { "Imath": "doxygen/xml" }
+breathe_default_project = "Imath"
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# General information about the project.
+project = 'Imath'
+copyright = '2021, Contributors to the OpenEXR Project'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+project_Imath_VERSION = "project(Imath VERSION "
+release = None
+for l in open ("../CMakeLists.txt"):
+  if l.startswith (project_Imath_VERSION):
+    release = l.split (' ')[2]
+    break
+if release == None:
+  print ("Error in conf.py: can't find Imath VERSION in ../CMakeList.txt")
+  exit(-1)
+
+v = release.split('.')
+# The short X.Y version.
+version = "%s.%s" % (v[0], v[1])
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#html_theme = 'agogo'
+#html_theme = 'default' # good
+#html_theme = 'nature' # too green
+#html_theme = 'bizstyle' # OK
+#html_theme = 'sphinxdoc'
+
+html_theme = "press"
+html_theme_options = {
+  "external_links": [
+      ("Github", "https://github.com/AcademySoftwareFoundation/Imath"),
+  ]
+}
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+html_title = "Imath Documentation"
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+html_short_title = "Imath"
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = "images/imath-logo-blue.png"
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+html_favicon = "images/imath-fav.ico"
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+#html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Imath'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+#latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+#}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+#latex_documents = [
+#  ('index', 'Imath.tex', 'Imath Documentation',
+#   'Contributors to the OpenEXR Project', 'manual'),
+#]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'imath', 'Imath Documentation',
+     ['Contributors to the OpenEXR Project'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('index', 'Imath', 'Imath Documentation',
+   'Contributors to the OpenEXR Project', 'Imath',
+   '2D and 3D vectors and matrices, half 16-bit floating-point type',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
diff --git a/docs/examples/Box.cpp b/docs/examples/Box.cpp
new file mode 100644 (file)
index 0000000..8d2fa28
--- /dev/null
@@ -0,0 +1,25 @@
+#include <Imath/ImathBox.h>
+        
+void
+box_example()
+{
+    Imath::V3f   a (0, 0, 0);
+    Imath::V3f   b (1, 1, 1);
+    Imath::V3f   c (2, 9, 2);
+
+    Imath::Box3f box (a);
+
+    assert (box.isEmpty());
+    assert (!box.isInfinite());
+    assert (!box.hasVolume());
+    
+    box.extendBy (c);
+
+    assert (box.size() == (c-a));
+    assert (box.intersects (b));
+    assert (box.max[0] > box.min[0]);
+    assert (box.max[1] > box.min[1]);
+    assert (box.max[2] > box.min[2]);
+    assert (box.hasVolume());
+    assert (box.majorAxis() == 1);
+}
diff --git a/docs/examples/CMakeLists.txt b/docs/examples/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4a6a817
--- /dev/null
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+cmake_minimum_required(VERSION 3.10)
+
+project(imath-examples)
+
+find_package(Imath)
+
+# The introductory example on the main docs page
+add_executable(imath-intro intro.cpp)
+
+# A main() that executes all the example code snippets
+add_executable(imath-examples
+  main.cpp
+  Color3.cpp
+  Color4.cpp
+  Euler.cpp
+  Frustum.cpp
+  Interval.cpp
+  Line3.cpp
+  Matrix22.cpp
+  Matrix33.cpp
+  Matrix44.cpp
+  Plane3.cpp
+  Quat.cpp
+  Shear6.cpp
+  Sphere3.cpp
+  Vec2.cpp
+  Vec3.cpp
+  Vec4.cpp
+  half.cpp
+)
+
+target_link_libraries(imath-intro Imath::Imath)
+target_link_libraries(imath-examples Imath::Imath)
+
+set_target_properties(imath-examples PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+)
+set_target_properties(imath-intro PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+)
+
+add_test(NAME Imath.imath-intro COMMAND $<TARGET_FILE:imath-intro>)
+add_test(NAME Imath.imath-examples COMMAND $<TARGET_FILE:imath-examples>)
+
+enable_testing()
diff --git a/docs/examples/Color3.cpp b/docs/examples/Color3.cpp
new file mode 100644 (file)
index 0000000..d2edcd1
--- /dev/null
@@ -0,0 +1,16 @@
+#include <Imath/ImathColor.h>
+#include <cassert>
+
+void
+color3_example()
+{
+    Imath::C3c   r (255, 0, 0);
+    Imath::C3c   g (0, 255, 0);
+    Imath::C3c   b (0, 0, 255);
+    
+    Imath::C3c   c = r + g + b;
+
+    assert (c.x == 255);
+    assert (c.x == 255);
+    assert (c.x == 255);
+}
diff --git a/docs/examples/Color4.cpp b/docs/examples/Color4.cpp
new file mode 100644 (file)
index 0000000..582aacd
--- /dev/null
@@ -0,0 +1,17 @@
+#include <Imath/ImathColor.h>
+#include <cassert>
+
+void
+color4_example()
+{
+    Imath::C4f   r (1.0f, 0.0f, 0.0f, 1.0f);
+    Imath::C4f   g (0.0f, 1.0f, 0.0f, 1.0f);
+    Imath::C4f   b (0.0f, 0.0f, 1.0f, 1.0f);
+    
+    Imath::C4f   w = r + g + b;
+
+    assert (w.r == 1.0f);
+    assert (w.g == 1.0f);
+    assert (w.b == 1.0f);
+    assert (w.a == 3.0f);
+}
diff --git a/docs/examples/Euler.cpp b/docs/examples/Euler.cpp
new file mode 100644 (file)
index 0000000..705a458
--- /dev/null
@@ -0,0 +1,25 @@
+#include <Imath/ImathEuler.h>
+#include <Imath/ImathMatrixAlgo.h>
+#include <cassert>
+
+void
+euler_example()
+{
+    int i, j, k;
+    
+    Imath::Eulerf xyz (Imath::Eulerf::XYZ);
+    xyz.angleOrder (i, j, k);
+    assert (i == 0 && j == 1 && k == 2);
+
+    Imath::Eulerf xzy (Imath::Eulerf::XZY);
+    xzy.angleOrder (i, j, k);
+    assert (i == 0 && j == 2 && k == 1);
+
+    Imath::Eulerf e1 (0.0f, 0.0f, 0.1f + 2 * M_PI);
+    Imath::Eulerf e2 (0.0f, 0.0f, 0.1f);
+
+    e1.makeNear (e2);
+    Imath::V3f v = e2.toXYZVector();
+    assert (v.equalWithAbsError (Imath::V3f (0.0f, 0.0f, 0.1f), 0.00001f));
+}
+  
diff --git a/docs/examples/Frustum.cpp b/docs/examples/Frustum.cpp
new file mode 100644 (file)
index 0000000..eb3f750
--- /dev/null
@@ -0,0 +1,22 @@
+#include <Imath/ImathFrustum.h>
+#include <cassert>
+
+void
+frustum_example()
+{
+    float near = 1.7f;
+    float far = 567.0f;
+    float left = -3.5f;
+    float right = 2.0f;
+    float top = 0.9f;
+    float bottom = -1.3f;
+
+    Imath::Frustumf frustum (near, far, left, right, top, bottom, false);
+
+    Imath::M44f m = frustum.projectionMatrix();
+
+    Imath::V3f p (1.0f, 1.0f, 1.0f);
+    Imath::V2f s = frustum.projectPointToScreen (p);
+
+    assert (s.equalWithAbsError (Imath::V2f (-0.345455f, -1.36364f), 0.0001f));
+}
diff --git a/docs/examples/Interval.cpp b/docs/examples/Interval.cpp
new file mode 100644 (file)
index 0000000..afaab79
--- /dev/null
@@ -0,0 +1,19 @@
+#include <Imath/ImathInterval.h>
+#include <cassert>
+
+void
+interval_example()
+{
+    Imath::Intervalf v;
+
+    assert (v.isEmpty());
+    assert (!v.hasVolume());
+    assert (!v.isInfinite());
+
+    v.extendBy (1.0f);
+    assert (!v.isEmpty());
+    
+    v.extendBy (2.0f);
+    assert (v.hasVolume());
+    assert (v.intersects (1.5f));
+}
diff --git a/docs/examples/Line3.cpp b/docs/examples/Line3.cpp
new file mode 100644 (file)
index 0000000..f622c26
--- /dev/null
@@ -0,0 +1,23 @@
+#include <Imath/ImathLine.h>
+#include <cassert>
+
+void
+line3_example()
+{
+    Imath::V3f   a (0.0f, 0.0f, 0.0f);
+    Imath::V3f   b (1.0f, 1.0f, 1.0f);
+
+    Imath::Line3f line (a, b);
+  
+    assert (line.pos == a);
+    assert (line.dir == (b-a).normalized());
+    
+    Imath::V3f   c (0.5f, 0.5f, 0.5f);
+
+    float f = line.distanceTo (c);
+    assert (Imath::equalWithAbsError (f, 0.0f, 0.0001f));
+
+    Imath::V3f p = line (0.5f); // midpoint, i.e. 0.5 units from a along (b-a)
+
+    assert (p.equalWithAbsError (Imath::V3f (0.288675f, 0.288675f, 0.288675f), 0.0001f));
+}
diff --git a/docs/examples/Matrix22.cpp b/docs/examples/Matrix22.cpp
new file mode 100644 (file)
index 0000000..cdf3c6c
--- /dev/null
@@ -0,0 +1,27 @@
+#include <Imath/ImathMatrix.h>
+#include <Imath/ImathMatrixAlgo.h>
+#include <cassert>
+
+void
+matrix22_example()
+{
+    Imath::M22f M (Imath::UNINITIALIZED); // uninitialized
+
+    M.makeIdentity();
+    assert (M[0][0] == 1.0f);
+    assert (M[0][1] == 0.0f);
+
+    Imath::M22f Minv = M.inverse();
+
+    Imath::M22f R;
+    assert (R == Imath::identity22f);
+
+    R.rotate (M_PI/4);
+    
+    M = R * M;
+
+    Imath::V2f v2 (1.0f, 0.0f);
+    Imath::V2f r2 = v2 * M;
+
+    assert (r2.equalWithAbsError (Imath::V2f (0.707107f, 0.707107f), 1e-6f));
+}
diff --git a/docs/examples/Matrix33.cpp b/docs/examples/Matrix33.cpp
new file mode 100644 (file)
index 0000000..6ed42da
--- /dev/null
@@ -0,0 +1,27 @@
+#include <Imath/ImathMatrix.h>
+#include <Imath/ImathMatrixAlgo.h>
+#include <cassert>
+
+void
+matrix33_example()
+{
+    Imath::M33f M (Imath::UNINITIALIZED); // uninitialized
+
+    M.makeIdentity();
+    assert (M[0][0] == 1.0f);
+    assert (M[0][1] == 0.0f);
+
+    Imath::M33f Minv = M.inverse();
+
+    Imath::M33f R;
+    assert (R == Imath::identity33f);
+
+    R.rotate (M_PI/4);
+    
+    M = R * M;
+
+    Imath::V3f v3 (1.0f, 0.0f, 0.0f);
+    Imath::V3f r3 = v3 * M;
+
+    assert (r3.equalWithAbsError (Imath::V3f (0.707107f, 0.7071070f, 0.0f), 1e-6f));
+}
diff --git a/docs/examples/Matrix44.cpp b/docs/examples/Matrix44.cpp
new file mode 100644 (file)
index 0000000..8b6c2a3
--- /dev/null
@@ -0,0 +1,31 @@
+#include <Imath/ImathMatrix.h>
+#include <Imath/ImathMatrixAlgo.h>
+#include <cassert>
+
+void
+matrix44_example()
+{
+    Imath::M44f M (Imath::UNINITIALIZED); // uninitialized
+
+    M.makeIdentity();
+    assert (M[0][0] == 1.0f);
+    assert (M[0][1] == 0.0f);
+
+    Imath::M44f Minv = M.inverse();
+
+    Imath::M44f R;
+    assert (R == Imath::identity44f);
+
+    R.rotate (Imath::V3f (0.02f, M_PI/4, 0.0f));
+    
+    M = R * M;
+
+    Imath::V3f v3 (1.0f, 0.0f, 0.0f);
+    Imath::V4f v4 (1.0f, 0.0f, 0.0f, 1.0f);
+
+    Imath::V3f r3 = v3 * M;
+    assert (r3.equalWithAbsError (Imath::V3f (0.707107f, 0.0f, -0.7071070f), 1e-6f));
+
+    Imath::V4f r4 = v4 * M;
+    assert (r4.equalWithAbsError (Imath::V4f (0.707107f, 0.0f, -0.7071070f, 1.0f), 1e-6f));
+}
diff --git a/docs/examples/Plane3.cpp b/docs/examples/Plane3.cpp
new file mode 100644 (file)
index 0000000..e75cb0f
--- /dev/null
@@ -0,0 +1,21 @@
+#include <Imath/ImathPlane.h>
+#include <cassert>
+
+void
+plane3_example()
+{
+    Imath::V3f a (1.0f, 0.0f, 0.0f);
+    Imath::V3f b (0.0f, 1.0f, 0.0f);
+    Imath::V3f c (0.0f, 0.0f, 1.0f);
+
+    Imath::Plane3f p (a, b, c);
+
+    Imath::V3f n (1.0f,  1.0f,  1.0f);
+    n.normalize();
+
+    assert (p.normal == n);
+
+    Imath::V3f o (0.0f, 0.0f, 0.0f);
+    float d = p.distanceTo (o);
+    assert (Imath::equalWithAbsError (d, -0.57735f, 1e-6f));
+}
diff --git a/docs/examples/Quat.cpp b/docs/examples/Quat.cpp
new file mode 100644 (file)
index 0000000..c824afa
--- /dev/null
@@ -0,0 +1,12 @@
+#include <Imath/ImathQuat.h>
+#include <cassert>
+
+void
+quat_example()
+{
+    Imath::Quatf q (2.0f, 3.0f, 4.0f, 5.0f);
+    assert (q.r == 2.0f && q.v == Imath::V3f (3.0f, 4.0f, 5.0f));
+
+    Imath::Quatf r (1.0f, 0.0f, 0.0f, 1.0f);
+    assert (r.inverse() == Imath::Quatf (0.5f, 0.0f, 0.0f, -0.5f));
+}
diff --git a/docs/examples/Shear6.cpp b/docs/examples/Shear6.cpp
new file mode 100644 (file)
index 0000000..ba97bd2
--- /dev/null
@@ -0,0 +1,11 @@
+#include <Imath/ImathShear.h>
+#include <Imath/ImathMatrix.h>
+
+void
+shear6_example()
+{
+    Imath::Shear6f s (0.330f, 0.710f, 0.010f, 0.999f, -0.531f, -0.012f);
+
+    Imath::M44f M;
+    M.setShear (s);
+}
diff --git a/docs/examples/Sphere3.cpp b/docs/examples/Sphere3.cpp
new file mode 100644 (file)
index 0000000..f0f1bea
--- /dev/null
@@ -0,0 +1,21 @@
+#include <Imath/ImathSphere.h>
+#include <cassert>
+
+void
+sphere3_example()
+{
+    Imath::V3f center (1.0f, 1.0f, 1.0f); 
+    float radius = 2.0f;
+    Imath::Sphere3f s (center, radius);
+
+    assert (s.center == center);
+    assert (s.radius == radius);
+    
+    Imath::Line3f line (Imath::V3f (0.0f, 0.0f, 0.0f),
+                        Imath::V3f (1.0f, 1.0f, 1.0f));
+
+    Imath::V3f v;
+    assert (s.intersect (line, v));
+
+    assert (v.equalWithAbsError (Imath::V3f(2.1547f, 2.1547f, 2.1547f), 1e-6f));    
+}
diff --git a/docs/examples/Vec2.cpp b/docs/examples/Vec2.cpp
new file mode 100644 (file)
index 0000000..551f487
--- /dev/null
@@ -0,0 +1,19 @@
+#include <Imath/ImathVec.h>
+#include <cassert>
+
+void
+vec2_example()
+{
+    Imath::V2f   a (1.0f, 2.0f);
+    Imath::V2f   b; // b is uninitialized
+
+    b.x = a[0];
+    b.y = a[1];
+
+    assert (a == b);
+
+    assert (a.length() == sqrt (a ^ a));
+
+    a.normalize();
+    assert (Imath::equalWithAbsError (a.length(), 1.0f, 1e-6f));
+}
diff --git a/docs/examples/Vec3.cpp b/docs/examples/Vec3.cpp
new file mode 100644 (file)
index 0000000..51f91ff
--- /dev/null
@@ -0,0 +1,20 @@
+#include <Imath/ImathVec.h>
+#include <cassert>
+
+void
+vec3_example()
+{
+    Imath::V3f   a (1.0f, 2.0f, 3.0f);
+    Imath::V3f   b; // b is uninitialized
+
+    b.x = a[0];
+    b.y = a[1];
+    b.z = a[2];
+
+    assert (a == b);
+
+    assert (a.length() == sqrt (a ^ a));
+
+    a.normalize();
+    assert (Imath::equalWithAbsError (a.length(), 1.0f, 1e-6f));
+}
diff --git a/docs/examples/Vec4.cpp b/docs/examples/Vec4.cpp
new file mode 100644 (file)
index 0000000..c63c9b9
--- /dev/null
@@ -0,0 +1,21 @@
+#include <Imath/ImathVec.h>
+#include <cassert>
+
+void
+vec4_example()
+{
+    Imath::V4f   a (1.0f, 2.0f, 3.0f, 4.0f);
+    Imath::V4f   b; // b is uninitialized
+
+    b.x = a[0];
+    b.y = a[1];
+    b.z = a[2];
+    b.w = a[3];
+
+    assert (a == b);
+
+    assert (a.length() == sqrt (a ^ a));
+
+    a.normalize();
+    assert (Imath::equalWithAbsError (a.length(), 1.0f, 1e-6f));
+}
diff --git a/docs/examples/gl.cpp b/docs/examples/gl.cpp
new file mode 100644 (file)
index 0000000..ce0150d
--- /dev/null
@@ -0,0 +1,12 @@
+#include <Imath/ImathGL.h>
+
+void
+gl_example()
+{
+    Imath::M44f M;
+    glPushMatrix (M);
+
+    Imath::V3f v (0.0f, 1.0f, 2.0f);
+    glVertex (v);
+}
+
diff --git a/docs/examples/half.c b/docs/examples/half.c
new file mode 100644 (file)
index 0000000..b7a65b0
--- /dev/null
@@ -0,0 +1,12 @@
+#include <Imath/half.h>
+
+void
+half_example()
+{
+    float f = 3.5f;
+  
+    half h = imath_float_to_half (f)
+
+    float hh = imath_half_to_float (h)
+}
+
diff --git a/docs/examples/half.cpp b/docs/examples/half.cpp
new file mode 100644 (file)
index 0000000..266a868
--- /dev/null
@@ -0,0 +1,13 @@
+#include <Imath/half.h>
+#include <math.h>
+
+void
+half_example()
+{
+    half a (3.5);
+    float b (a + sqrt (a));
+    a += b;
+    b += a;
+    b = a + 7;
+}
+
diff --git a/docs/examples/intro.cpp b/docs/examples/intro.cpp
new file mode 100644 (file)
index 0000000..eaa2425
--- /dev/null
@@ -0,0 +1,24 @@
+#include <Imath/ImathMatrix.h>
+#include <Imath/ImathVec.h>
+#include <iostream>
+#include <cassert>
+
+int
+main()
+{
+    const Imath::V3f v (3.0f, 4.0f, 5.0f);
+   
+    Imath::M44f M;
+    const Imath::V3f t(1.0f, 2.0f, 3.0f);
+    M.translate (t);
+
+    Imath::V3f p;
+    M.multVecMatrix(v, p);
+
+    std::cout << "What's your vector, Victor? " << p << std::endl;
+
+    Imath::V3f vt = v + t;
+    assert (p.equalWithAbsError(vt, 1e-6f));
+
+    return 0;
+}
diff --git a/docs/examples/main.cpp b/docs/examples/main.cpp
new file mode 100644 (file)
index 0000000..0578441
--- /dev/null
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+
+#include <iostream>
+
+void color3_example();
+void color4_example();
+void euler_example();
+void frustum_example();
+void interval_example();
+void line3_example();
+void matrix22_example();
+void matrix33_example();
+void matrix44_example();
+void plane3_example();
+void quat_example();
+void shear6_example();
+void sphere3_example();
+void vec2_example();
+void vec3_example();
+void vec4_example();
+void half_example();
+
+int
+main (int argc, char* argv[])
+{
+    std::cout << "imath examples..." << std::endl;
+
+    color3_example();
+    color4_example();
+    euler_example();
+    frustum_example();
+    interval_example();
+    line3_example();
+    matrix22_example();
+    matrix33_example();
+    matrix44_example();
+    plane3_example();
+    quat_example();
+    shear6_example();
+    sphere3_example();
+    vec2_example();
+    vec3_example();
+    vec4_example();
+    half_example();
+    
+    std::cout << "done." << std::endl;
+    
+    return 0;
+}
diff --git a/docs/fixmanpages.sh b/docs/fixmanpages.sh
new file mode 100755 (executable)
index 0000000..0036179
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# Fix the names of doxygen-generated man page files:
+# * Strip "_ Vec" and "_ T _ _" from "Imath_Box_ Vec2_ T _ _.3"
+# * and rename "Imath_*" to "Imath::*"
+
+if [ -d $1/man/man3 ]; then
+
+  cd $1/man/man3
+  echo cd $1/man/man3
+  shopt -s nullglob
+  for file in Imath_*.3;
+  do
+    new=`echo $file | sed -e 's/_ T _ _//g' -e 's/_ Vec//g' -e s/_/::/g`
+    echo /bin/mv "$file" $new
+    /bin/mv "$file" $new
+  done
+fi
+   
+
+
diff --git a/docs/functions.rst b/docs/functions.rst
new file mode 100644 (file)
index 0000000..82f7691
--- /dev/null
@@ -0,0 +1,24 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _Imath Functions:
+   
+Imath Functions
+###############
+
+.. toctree::
+   :caption: Functions
+   :maxdepth: 3
+
+   functions/box
+   functions/color
+   functions/frame
+   functions/gl
+   functions/glu
+   functions/line
+   functions/matrix
+   functions/random
+   functions/roots
+   functions/vec
+   
diff --git a/docs/functions/box.rst b/docs/functions/box.rst
new file mode 100644 (file)
index 0000000..1cf82d7
--- /dev/null
@@ -0,0 +1,26 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _box-functions:
+
+Box Functions
+#############
+
+Functions that operate on bounding boxes.
+
+.. code-block::
+
+   #include <Imath/ImathBoxAlgo.h>
+
+.. doxygenfunction:: clip
+                     
+.. doxygenfunction:: closestPointInBox
+                     
+.. doxygenfunction:: transform(const Box<Vec3<S>>& box, const Matrix44<T>& m) noexcept
+
+.. doxygenfunction:: affineTransform(const Box<Vec3<S>>& box, const Matrix44<T>& m) noexcept
+
+.. doxygenfunction:: findEntryAndExitPoints
+
+.. doxygenfunction:: intersects(const Box<Vec3<T>>& b, const Line3<T>& r, Vec3<T>& ip) noexcept
diff --git a/docs/functions/color.rst b/docs/functions/color.rst
new file mode 100644 (file)
index 0000000..9a9c881
--- /dev/null
@@ -0,0 +1,32 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _color-functions:
+
+Color Functions
+###############
+
+Functions that operate on colors.
+
+.. code-block::
+
+   #include <Imath/ImathColorAlgo.h>
+
+.. doxygenfunction:: hsv2rgb(const Vec3<T>& hsv) noexcept
+
+.. doxygenfunction:: hsv2rgb(const Color4<T>& hsv) noexcept
+                     
+.. doxygenfunction:: rgb2hsv(const Color4<T> &rgb) noexcept
+                     
+.. doxygenfunction:: rgb2hsv(const Vec3<T> &rgb) noexcept
+
+.. doxygenfunction:: rgb2packed(const Color4<T> &c) noexcept
+
+.. doxygenfunction:: rgb2packed(const Vec3<T> &c) noexcept
+
+.. doxygenfunction:: packed2rgb(PackedColor packed, Color4<T> &out) noexcept
+
+.. doxygenfunction:: packed2rgb(PackedColor packed, Vec3<T> &out) noexcept
+
+                     
diff --git a/docs/functions/frame.rst b/docs/functions/frame.rst
new file mode 100644 (file)
index 0000000..c3d5236
--- /dev/null
@@ -0,0 +1,20 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _frame-functions:
+
+Frame Functions
+###############
+
+Functions to compute coordinate frames.
+
+.. code-block::
+
+   #include <Imath/ImathFrame.h>
+
+.. doxygenfunction:: firstFrame
+                     
+.. doxygenfunction:: nextFrame
+                     
+.. doxygenfunction:: lastFrame
diff --git a/docs/functions/gl.rst b/docs/functions/gl.rst
new file mode 100644 (file)
index 0000000..288db8d
--- /dev/null
@@ -0,0 +1,53 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _gl-functions:
+
+GL Functions
+############
+
+Functions that wrap OpenGL calls to accept Imath vectors and matrices.
+
+.. code-block::
+
+   #include <Imath/ImathGL.h>
+
+Example:
+
+.. literalinclude:: ../examples/gl.cpp
+   :language: c++
+              
+.. doxygenfunction:: glVertex(const Imath::V2f &v)
+
+.. doxygenfunction:: glVertex(const Imath::V3f &v)
+                     
+.. doxygenfunction:: glNormal(const Imath::V3f &v)
+                     
+.. doxygenfunction:: glColor(const Imath::V3f &v)
+                     
+.. doxygenfunction:: glTranslate                     
+
+.. doxygenfunction:: glTexCoord
+
+.. doxygenfunction:: throwBadMatrix
+                     
+.. doxygenfunction:: glMultMatrix( const Imath::M44f &m )
+                     
+.. doxygenfunction:: glMultMatrix( const Imath::M44f *m )
+                     
+.. doxygenfunction:: glLoadMatrix(const Imath::M44f &m)
+
+.. doxygenfunction:: glLoadMatrix(const Imath::M44f *m)
+
+.. doxygenclass:: Imath::GLPushMatrix
+   :members:
+   :undoc-members:
+                     
+.. doxygenclass:: Imath::GLPushAttrib
+   :members:
+   :undoc-members:
+                     
+.. doxygenclass:: Imath::GLBegin
+   :members:
+   :undoc-members:
diff --git a/docs/functions/glu.rst b/docs/functions/glu.rst
new file mode 100644 (file)
index 0000000..ad15c3b
--- /dev/null
@@ -0,0 +1,16 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _glu-functions:
+
+GLU Functions
+#############
+
+Functions that wrap GLU calls to accept Imath vectors.
+
+.. code-block::
+
+   #include <Imath/ImathGLU.h>
+
+.. doxygenfunction:: gluLookAt(const Imath::V3f& pos, const Imath::V3f& interest, const Imath::V3f& up)
diff --git a/docs/functions/line.rst b/docs/functions/line.rst
new file mode 100644 (file)
index 0000000..f8e1279
--- /dev/null
@@ -0,0 +1,22 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _line-functions:
+
+Line3 Functions
+###############
+
+.. code-block::
+
+   #include <Imath/ImathLineAlgo.h>   
+
+Functions that operate on the ``Line3`` object.
+
+.. doxygenfunction:: closestPoints
+                     
+.. doxygenfunction:: intersect(const Line3<T>& line, const Vec3<T>&v0, const Vec3<T>& v1, const Vec3<T>& v2, Vec3<T>& pt, Vec3<T>& barycentric, bool& front) noexcept
+                     
+.. doxygenfunction:: closestVertex(const Vec3<T>& v0, const Vec3<T>& v1, const Vec3<T>& v2, const Line3<T>& l) noexcept
+
+.. doxygenfunction:: rotatePoint
diff --git a/docs/functions/matrix.rst b/docs/functions/matrix.rst
new file mode 100644 (file)
index 0000000..2bc9b78
--- /dev/null
@@ -0,0 +1,104 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _matrix-functions:
+
+Matrix Functions
+################
+
+.. code-block::
+
+   #include <Imath/ImathMatrixAlgo.h>   
+
+Functions that operate on matrices
+
+.. doxygenfunction:: extractScaling(const Matrix44<T>& mat, Vec3<T>& scl, bool exc)
+                     
+.. doxygenfunction:: sansScaling(const Matrix44<T>& mat, bool exc)
+
+.. doxygenfunction:: removeScaling(Matrix44<T>& mat, bool exc)
+
+.. doxygenfunction:: extractScalingAndShear(const Matrix44<T>& mat, Vec3<T>& scl, Vec3<T>& shr, bool exc)
+
+.. doxygenfunction:: sansScalingAndShear(const Matrix44<T>& mat, bool exc)
+
+.. doxygenfunction:: sansScalingAndShear(Matrix44<T>& result, const Matrix44<T>& mat, bool exc)
+
+.. doxygenfunction:: removeScalingAndShear(Matrix44<T>& mat, bool exc)
+
+.. doxygenfunction:: extractAndRemoveScalingAndShear(Matrix44<T>& mat, Vec3<T>& scl, Vec3<T>& shr, bool exc)
+
+.. doxygenfunction:: extractEulerXYZ(const Matrix44<T>& mat, Vec3<T>& rot)
+
+.. doxygenfunction:: extractEulerZYX(const Matrix44<T>& mat, Vec3<T>& rot)
+
+.. doxygenfunction:: extractQuat(const Matrix44<T>& mat)
+
+.. doxygenfunction:: extractSHRT(const Matrix44<T>& mat, Vec3<T>& s, Vec3<T>& h, Vec3<T>& r, Vec3<T>& t, bool exc, typename Euler<T>::Order rOrder)
+
+.. doxygenfunction:: extractSHRT(const Matrix44<T>& mat, Vec3<T>& s, Vec3<T>& h, Vec3<T>& r, Vec3<T>& t, bool exc)
+
+.. doxygenfunction:: extractSHRT(const Matrix44<T>& mat, Vec3<T>& s, Vec3<T>& h, Euler<T>& r, Vec3<T>& t, bool exc)
+
+.. doxygenfunction:: checkForZeroScaleInRow(const T& scl, const Vec3<T>& row, bool exc)
+
+.. doxygenfunction:: outerProduct(const Vec4<T>& a, const Vec4<T>& b)
+
+.. doxygenfunction:: rotationMatrix(const Vec3<T>& fromDirection, const Vec3<T>& toDirection)                     
+
+.. doxygenfunction:: rotationMatrixWithUpDir(const Vec3<T>& fromDir, const Vec3<T>& toDir, const Vec3<T>& upDir)
+
+.. doxygenfunction:: alignZAxisWithTargetDir(Matrix44<T>& result, Vec3<T> targetDir, Vec3<T> upDir)
+
+.. doxygenfunction:: computeLocalFrame(const Vec3<T>& p, const Vec3<T>& xDir, const Vec3<T>& normal)
+
+.. doxygenfunction:: addOffset(const Matrix44<T>& inMat, const Vec3<T>& tOffset, const Vec3<T>& rOffset, const Vec3<T>& sOffset, const Vec3<T>& ref)
+
+.. doxygenfunction:: computeRSMatrix(bool keepRotateA, bool keepScaleA, const Matrix44<T>& A, const Matrix44<T>& B)
+
+.. doxygenfunction:: extractScaling(const Matrix33<T>& mat, Vec2<T>& scl, bool exc)
+
+.. doxygenfunction:: sansScaling(const Matrix33<T>& mat, bool exc)
+
+.. doxygenfunction:: removeScaling(Matrix33<T>& mat, bool exc)
+
+.. doxygenfunction:: extractScalingAndShear(const Matrix33<T>& mat, Vec2<T>& scl, T& shr, bool exc)
+
+.. doxygenfunction:: sansScalingAndShear(const Matrix33<T>& mat, bool exc)
+
+.. doxygenfunction:: removeScalingAndShear(Matrix33<T>& mat, bool exc)
+
+.. doxygenfunction:: extractAndRemoveScalingAndShear(Matrix33<T>& mat, Vec2<T>& scl, T& shr, bool exc)
+
+.. doxygenfunction:: extractEuler(const Matrix22<T>& mat, T& rot)
+
+.. doxygenfunction:: extractEuler(const Matrix33<T>& mat, T& rot)
+
+.. doxygenfunction:: extractSHRT(const Matrix33<T>& mat, Vec2<T>& s, T& h, T& r, Vec2<T>& t, bool exc)
+
+.. doxygenfunction:: checkForZeroScaleInRow(const T& scl, const Vec2<T>& row, bool exc)
+
+.. doxygenfunction:: outerProduct(const Vec3<T>& a, const Vec3<T>& b)
+
+.. doxygenfunction:: procrustesRotationAndTranslation(const Vec3<T>* A, const Vec3<T>* B, const T* weights, const size_t numPoints, const bool doScaling)
+
+.. doxygenfunction:: procrustesRotationAndTranslation(const Vec3<T>* A, const Vec3<T>* B, const size_t numPoints, const bool doScaling)
+
+.. doxygenfunction:: jacobiSVD(const Matrix33<T>& A, Matrix33<T>& U, Vec3<T>& S, Matrix33<T>& V, const T tol, const bool forcePositiveDeterminant)
+
+.. doxygenfunction:: jacobiSVD(const Matrix44<T>& A, Matrix44<T>& U, Vec4<T>& S, Matrix44<T>& V, const T tol, const bool forcePositiveDeterminant)
+
+.. doxygenfunction:: jacobiEigenSolver(Matrix33<T>& A, Vec3<T>& S, Matrix33<T>& V, const T tol)
+
+.. doxygenfunction:: jacobiEigenSolver(Matrix33<T>& A, Vec3<T>& S, Matrix33<T>& V)
+
+.. doxygenfunction:: jacobiEigenSolver(Matrix44<T>& A, Vec4<T>& S, Matrix44<T>& V, const T tol)
+
+.. doxygenfunction:: jacobiEigenSolver(Matrix44<T>& A, Vec4<T>& S, Matrix44<T>& V)
+
+.. doxygenfunction:: maxEigenVector(TM& A, TV& S)
+
+.. doxygenfunction:: minEigenVector(TM& A, TV& S)
+
+
diff --git a/docs/functions/random.rst b/docs/functions/random.rst
new file mode 100644 (file)
index 0000000..ef66ace
--- /dev/null
@@ -0,0 +1,33 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _random-number-functions:
+
+Random Numbers
+##############
+
+Functions to compute pseudo-random numbers.
+
+.. code-block::
+
+   #include <Imath/ImathRandom.h>
+
+.. doxygenfunction:: solidSphereRand
+
+.. doxygenfunction:: hollowSphereRand
+
+.. doxygenfunction:: gaussSphereRand
+                     
+.. doxygenfunction:: gaussRand
+                     
+.. doxygenfunction:: erand48
+                     
+.. doxygenfunction:: drand48
+                     
+.. doxygenfunction:: nrand48
+                     
+.. doxygenfunction:: lrand48
+                     
+.. doxygenfunction:: srand48
+                     
diff --git a/docs/functions/roots.rst b/docs/functions/roots.rst
new file mode 100644 (file)
index 0000000..4783721
--- /dev/null
@@ -0,0 +1,22 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _roots:
+
+Roots
+#####
+
+Functions to compute roots of simple equations.
+
+.. code-block::
+
+   #include <Imath/ImathRoots.h>
+
+.. doxygenfunction:: solveLinear
+                     
+.. doxygenfunction:: solveQuadratic
+
+.. doxygenfunction:: solveNormalizedCubic
+                     
+.. doxygenfunction:: solveCubic
diff --git a/docs/functions/vec.rst b/docs/functions/vec.rst
new file mode 100644 (file)
index 0000000..1ae9f5a
--- /dev/null
@@ -0,0 +1,19 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _vector-functions:
+
+Vector Functions
+################
+
+.. code-block::
+
+   #include <Imath/ImathVecAlgo.h>   
+
+Functions that operate on vectors.
+
+.. doxygenfunction:: closestVertex(const Vec& v0, const Vec& v1, const Vec& v2, const Vec& p) noexcept
+
+
+                     
diff --git a/docs/images/imath-fav.ico b/docs/images/imath-fav.ico
new file mode 100644 (file)
index 0000000..4795fc5
Binary files /dev/null and b/docs/images/imath-fav.ico differ
diff --git a/docs/images/imath-logo-black.png b/docs/images/imath-logo-black.png
new file mode 100644 (file)
index 0000000..6fafb08
Binary files /dev/null and b/docs/images/imath-logo-black.png differ
diff --git a/docs/images/imath-logo-blue.png b/docs/images/imath-logo-blue.png
new file mode 100644 (file)
index 0000000..9539835
Binary files /dev/null and b/docs/images/imath-logo-blue.png differ
diff --git a/docs/images/imath-logo-white.png b/docs/images/imath-logo-white.png
new file mode 100644 (file)
index 0000000..161b7d6
Binary files /dev/null and b/docs/images/imath-logo-white.png differ
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644 (file)
index 0000000..7eaf494
--- /dev/null
@@ -0,0 +1,77 @@
+..\r
+  SPDX-License-Identifier: BSD-3-Clause\r
+  Copyright Contributors to the OpenEXR Project.\r
+\r
+.. _Overview:\r
+\r
+Imath\r
+#####\r
+\r
+.. toctree::\r
+   :caption: Imath\r
+   :maxdepth: 1\r
+\r
+Imath is a basic, light-weight, and efficient C++ representation of 2D\r
+and 3D vectors, 2x2, 3x3, and 4x4 matrices, and other simple but useful\r
+mathematical objects, functions, and data types common in computer\r
+graphics applications, including the :doc:`classes/half` 16-bit floating-point\r
+type.\r
+\r
+Imath also includes optional python bindings for all types and\r
+functions, including optimized implementations of vector and matrix\r
+arrays.\r
+\r
+Imath is maintained by the `OpenEXR project <https://openexr.com>`_, a part of the `Academy\r
+Software Foundation <https://www.aswf.io>`_.\r
+\r
+Community\r
+=========\r
+\r
+* **Ask a question:**\r
+\r
+  - Email: `openexr-dev@lists.aswf.io <https://lists.aswf.io/g/openexr-dev>`_\r
+\r
+  - Slack: `academysoftwarefdn#openexr <https://academysoftwarefdn.slack.com/archives/CMLRW4N73>`_\r
+\r
+* **Attend a meeting:**\r
+\r
+  - Technical Steering Committee meetings are open to the\r
+    public, fortnightly on Thursdays, 1:30pm Pacific Time.\r
+\r
+  - Calendar: https://lists.aswf.io/g/openexr-dev/calendar\r
+\r
+* **Report a bug:**\r
+\r
+  - Submit an Issue: https://github.com/AcademySoftwareFoundation/Imath/issues\r
+\r
+* **Report a security vulnerability:**\r
+\r
+  - Email security@openexr.com\r
+\r
+* **Contribute a Fix, Feature, or Improvement:**\r
+\r
+  - Read the `Contribution Guidelines\r
+    <https://github.com/AcademySoftwareFoundation/openexr/blob/main/CONTRIBUTING.md>`_\r
+    and `Code of Conduct <https://github.com/AcademySoftwareFoundation/openexr/blob/main/CODE_OF_CONDUCT.md>`_\r
+\r
+  - Sign the `Contributor License Agreement\r
+    <https://contributor.easycla.lfx.linuxfoundation.org/#/cla/project/2e8710cb-e379-4116-a9ba-964f83618cc5/user/564e571e-12d7-4857-abd4-898939accdd7>`_\r
+  \r
+  - Submit a Pull Request: https://github.com/AcademySoftwareFoundation/Imath/pulls\r
+\r
+Resources\r
+=========\r
+\r
+- Security policy: `SECURITY.md <https://github.com/AcademySoftwareFoundation/Imath/blob/main/SECURITY.md>`_\r
+- Release notes: `CHANGES.md\r
+  <https://github.com/AcademySoftwareFoundation/Imath/blob/main/CHANGES.md>`_\r
+- Contributors: `CONTRIBUTORS.md <https://github.com/AcademySoftwareFoundation/Imath/blob/main/CONTRIBUTORS.md>`_\r
+- Porting Guide: :doc:`PortingGuide`\r
+\r
+Index\r
+=====\r
+\r
+:ref:`genindex`\r
+\r
+.. include:: toc_redirect.rst\r
+\r
diff --git a/docs/install.rst b/docs/install.rst
new file mode 100644 (file)
index 0000000..120153c
--- /dev/null
@@ -0,0 +1,310 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _Install:
+
+Install
+========
+
+.. toctree::
+   :caption: Install
+             
+The Imath library is available for download and installation in
+binary form via package managers on many Linux distributions. See
+`https://pkgs.org/download/Imath
+<https://pkgs.org/download/Imath>`_ for a complete list. The common
+ones that generally provide current releases include:
+
+* `Fedora <https://packages.fedoraproject.org/pkgs/`download/Imath/>`_
+* `Gentoo <https://packages.gentoo.org/packages/media-libs/Imath>`_ 
+* `Ubuntu <https://packages.ubuntu.com/source/kinetic/Imath>`_
+
+Beware that some distributions are out of date and only provide
+distributions of outdated releases OpenEXR. We recommend against using
+OpenEXR v2, and we *strongly* recommend against using OpenEXR v1.
+
+On macOS, we do not recommend installation via HomeBrew because the
+distribution is outdated.
+
+Please note that ``pip install openexr`` installs the `openexrpython
+<https://github.com/jamesbowman/openexrpython>`_ module, which is not
+affiliated with the OpenEXR project or the ASWF. Please direct
+questions there.
+
+Build from Source
+-----------------
+
+Imath builds on Linux, macOS, Microsoft Windows via CMake, and is
+cross-compilable on other systems.
+
+Download the source from the `GitHub releases page
+<https://github.com/AcademySoftwareFoundation/Imath/releases>`_
+page, or clone the `repo <https://github.com/AcademySoftwareFoundation/Imath>`_.
+
+The ``release`` branch of the repo always points to the most advanced
+release.
+
+
+Prerequisites
+~~~~~~~~~~~~~
+
+Make sure these are installed on your system before building Imath:
+
+* Imath requires CMake version 3.12 or newer
+* C++ compiler that supports C++11
+
+The instructions that follow describe building Imath with CMake.
+
+Linux/macOS
+~~~~~~~~~~~
+
+To build via CMake, you need to first identify three directories:
+
+1. The source directory, i.e. the top-level directory of the
+   downloaded source archive or cloned repo, referred to below as ``$srcdir``
+2. A temporary directory to hold the build artifacts, referred to below as
+   ``$builddir``
+3. A destination directory into which to install the
+   libraries and headers, referred to below as ``$installdir``.  
+
+To build:
+.. code-block::
+
+    $ cd $builddir
+    $ cmake $srcdir --install-prefix $installdir
+    $ cmake --build $builddir --target install --config Release
+
+Note that the CMake configuration prefers to apply an out-of-tree
+build process, since there may be multiple build configurations
+(i.e. debug and release), one per folder, all pointing at once source
+tree, hence the ``$builddir`` noted above, referred to in CMake
+parlance as the *build directory*. You can place this directory
+wherever you like.
+
+See the CMake Configuration Options section below for the most common
+configuration options especially the install directory. Note that with
+no arguments, as above, ``make install`` installs the header files in
+``/usr/local/include``, the object libraries in ``/usr/local/lib``, and the
+executable programs in ``/usr/local/bin``.
+
+Windows
+~~~~~~~
+
+Under Windows, if you are using a command line-based setup, such as
+cygwin, you can of course follow the above. For Visual Studio, cmake
+generators are "multiple configuration", so you don't even have to set
+the build type, although you will most likely need to specify the
+install location.  Install Directory By default, ``make install``
+installs the headers, libraries, and programs into ``/usr/local``, but you
+can specify a local install directory to cmake via the
+``CMAKE_INSTALL_PREFIX`` variable:
+
+.. code-block::
+
+    $ cmake .. -DCMAKE_INSTALL_PREFIX=$Imath_install_directory
+
+Library Names
+-------------
+
+By default the installed libraries follow a pattern for how they are
+named. This is done to enable multiple versions of the library to be
+installed and targeted by different builds depending on the needs of
+the project. A simple example of this would be to have different
+versions of the library installed to allow for applications targeting
+different VFX Platform years to co-exist.
+
+If you are building dynamic libraries, once you have configured, built,
+and installed the libraries, you should see the following pattern of
+symlinks and files in the install lib folder:
+
+.. code-block::
+
+    libImath.so -> libImath-3_1.so
+    libImath-3_1.so -> libImath-3_1.so.30
+    libImath-3_1.so.30 -> libImath-3_1.so.30.3.0
+    libImath-3_1.so.30.3.0 (the shared object file)
+    
+The ``-3_1`` suffix encodes the major and minor version, which can be
+configured via the ``IMATH_LIB_SUFFIX`` CMake setting. The ``30``
+corresponds to the so version, or in ``libtool`` terminology the
+``current`` shared object version; the `3` denotes the ``libtool``
+``revision``, and the ``0`` denotes the ``libtool`` ``age``. See the
+`libtool
+<https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info>`_
+documentation for more details.
+
+Porting Applications from OpenEXR v2 to v3
+------------------------------------------
+
+See the :doc:`PortingGuide` for details about differences from previous
+releases and how to address them. Also refer to the porting guide for
+details about changes to Imath.
+
+Building the Documentation
+--------------------------
+
+The Imath technical documentation at `https://imath.readthedocs.io
+<https://imath.readthedocs.io>`_ is generated via `Sphinx
+<https://www.sphinx-doc.org>`_ with the `Breathe
+<https://breathe.readthedocs.io>`_ extension using information
+extracted from header comments by `Doxygen <https://www.doxygen.nl>`_.
+
+To build the documentation locally from the source headers and
+``.rst`` files, set the CMake option ``BUILD_DOCS=ON``. This adds
+``Doxygen`` and ``Sphinx`` CMake targets and enables building the docs
+by default.  generation is off by default.
+
+Building the documentation requires that ``sphinx``, ``breathe``, and
+``doxygen`` are installed. It further requires the `sphinx-press-theme
+<https://pypi.org/project/sphinx-press-theme>`_, as indicated in the
+`requirements.txt
+<https://github.com/AcademySoftwareFoundation/imath/blob/main/docs/requirements.txt>`_
+file.
+
+CMake Build-time Configuration Options
+--------------------------------------
+
+The default CMake configuration options are stored in
+``cmake/ImathSetup.cmake``. To see a complete set of option
+variables, run:
+
+.. code-block::
+
+    $ cmake -LAH $imath_source_directory
+
+You can customize these options three ways:
+
+1. Modify the ``.cmake`` files in place.
+2. Use the UI ``cmake-gui`` or ``ccmake``.
+3. Specify them as command-line arguments when you invoke cmake.
+
+Library Naming Options
+~~~~~~~~~~~~~~~~~~~~~~
+
+* ``IMATH_LIB_SUFFIX``
+
+  Append the given string to the end of all the Imath
+  libraries. Default is ``-<major>_<minor>`` version string. Please
+  see the section on library names
+
+Imath Dependency
+~~~~~~~~~~~~~~~~
+
+* ``CMAKE_PREFIX_PATH``
+
+  The standard CMake path in which to
+  search for dependencies, Imath in particular.  A comma-separated
+  path. Add the root directory where Imath is installed.
+
+Namespace Options
+~~~~~~~~~~~~~~~~~
+
+* ``IMATH_NAMESPACE``
+
+  Public namespace alias for Imath. Default is ``Imath``.
+
+* ``IMATH_INTERNAL_NAMESPACE``
+
+  Real namespace for Imath that will end up in compiled
+  symbols. Default is ``Imath_<major>_<minor>``.
+
+* ``IMATH_NAMESPACE_CUSTOM``
+
+  Whether the namespace has been customized (so external users know)
+
+Component Options
+~~~~~~~~~~~~~~~~~
+
+* ``BUILD_TESTING``
+
+  Build the testing tree. Default is ``ON``.  Note that
+  this causes the test suite to be compiled, but it is not
+  executed. To execute the suite, run "make test".
+
+Additional CMake Options
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+See the CMake documentation for more information (https://cmake.org/cmake/help/v3.12/).
+
+* ``CMAKE_BUILD_TYPE``
+
+  For builds when not using a multi-configuration generator. Available
+  values: ``Debug``, ``Release``, ``RelWithDebInfo``, ``MinSizeRel``
+
+* ``BUILD_SHARED_LIBS``
+
+  This is the primary control whether to build static libraries or
+  shared libraries / dlls (side note: technically a convention, hence
+  not an official ``CMAKE_`` variable, it is defined within cmake and
+  used everywhere to control this static / shared behavior)
+
+* ``IMATH_CXX_STANDARD``
+
+  C++ standard to compile against. This obeys the global
+  ``CMAKE_CXX_STANDARD`` but doesn’t force the global setting to
+  enable sub-project inclusion. Default is ``14``.
+
+* ``CMAKE_CXX_COMPILER``
+
+  The C++ compiler.        
+
+* ``CMAKE_C_COMPILER``
+
+  The C compiler.
+  
+* ``CMAKE_INSTALL_RPATH``
+
+  For non-standard install locations where you don’t want to have to
+  set ``LD_LIBRARY_PATH`` to use them
+
+* ``CMAKE_EXPORT_COMPILE_COMMANDS``
+
+  Enable/Disable output of compile commands during generation. Default
+  is ``OFF``.
+
+* ``CMAKE_VERBOSE_MAKEFILE``
+
+  Echo all compile commands during make. Default is ``OFF``.
+
+Cross Compiling / Specifying Specific Compilers
+-----------------------------------------------
+
+When trying to either cross-compile for a different platform, or for
+tasks such as specifying a compiler set to match the `VFX reference
+platform <https://vfxplatform.com>`_, cmake provides the idea of a
+toolchain which may be useful instead of having to remember a chain of
+configuration options. It also means that platform-specific compiler
+names and options are out of the main cmake file, providing better
+isolation.
+
+A toolchain file is simply just a cmake script that sets all the
+compiler and related flags and is run very early in the configuration
+step to be able to set all the compiler options and such for the
+discovery that cmake performs automatically. These options can be set
+on the command line still if that is clearer, but a theoretical
+toolchain file for compiling for VFX Platform 2015 is provided in the
+source tree at ``cmake/Toolchain-Linux-VFX_Platform15.cmake`` which
+will hopefully provide a guide how this might work.
+
+For cross-compiling for additional platforms, there is also an
+included sample script in ``cmake/Toolchain-mingw.cmake`` which shows
+how cross compiling from Linux for Windows may work. The compiler
+names and paths may need to be changed for your environment.
+
+More documentation:
+
+* Toolchains: https://cmake.org/cmake/help/v3.12/manual/cmake-toolchains.7.html
+* Cross compiling: https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/
+
+Ninja
+-----
+
+If you have `Ninja <https://ninja-build.org>`_ installed, it is faster
+than make. You can generate ninja files using cmake when doing the
+initial generation:
+
+.. code-block::
+
+    $ cmake -G “Ninja” ..
+
diff --git a/docs/license.rst b/docs/license.rst
new file mode 100644 (file)
index 0000000..0675bf7
--- /dev/null
@@ -0,0 +1,33 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. _License:
+
+License
+=======
+
+.. toctree::
+   :caption: License
+
+Imath is licensed under the BSD-3-Clause license. Contributions to the 
+library should abide by that license unless otherwised approved by the OpenEXR
+TSC and ASWF Governing Board.
+
+See `LICENSE.md 
+<https://github.com/AcademySoftwareFoundation/Imath/blob/main/LICENSE.md>`__ 
+on GitHub.
+
+Copyright (c) Contributors to the OpenEXR Project. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.
+
+  
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644 (file)
index 0000000..d030b3b
--- /dev/null
@@ -0,0 +1,3 @@
+sphinx == 4.4.0
+breathe
+sphinx-press-theme
diff --git a/docs/toc_redirect.rst b/docs/toc_redirect.rst
new file mode 100644 (file)
index 0000000..4406e7b
--- /dev/null
@@ -0,0 +1,38 @@
+..
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright Contributors to the OpenEXR Project.
+
+.. toctree::
+   :hidden:
+
+   concepts
+
+.. toctree::
+   :hidden:
+
+   classes
+
+.. toctree::
+   :hidden:
+
+   functions
+
+.. toctree::
+   :hidden:
+
+   install
+   
+.. toctree::
+   :hidden:
+
+   license
+
+.. toctree::
+   :hidden:
+
+   about
+
+      
+   
+
+   
diff --git a/share/ci/scripts/linux/install_boost.sh b/share/ci/scripts/linux/install_boost.sh
new file mode 100755 (executable)
index 0000000..471ecff
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+set -ex
+
+BOOST_VERSION="$1"
+BOOST_MAJOR_MINOR=$(echo "${BOOST_VERSION}" | cut -d. -f-2)
+BOOST_MAJOR=$(echo "${BOOST_VERSION}" | cut -d. -f-1)
+BOOST_MINOR=$(echo "${BOOST_MAJOR_MINOR}" | cut -d. -f2-)
+BOOST_PATCH=$(echo "${BOOST_VERSION}" | cut -d. -f3-)
+BOOST_VERSION_U="${BOOST_MAJOR}_${BOOST_MINOR}_${BOOST_PATCH}"
+
+mkdir _boost
+cd _boost
+
+wget -q https://sourceforge.net/projects/boost/files/boost/${BOOST_VERSION}/boost_${BOOST_VERSION_U}.tar.gz
+tar -xzf boost_${BOOST_VERSION_U}.tar.gz
+
+cd boost_${BOOST_VERSION_U}
+sh bootstrap.sh
+./b2 install -j4 variant=release toolset=gcc \
+    --with-system \
+    --with-regex \
+    --with-filesystem \
+    --with-thread \
+    --with-python \
+    --prefix=/usr/local
+
+cd ../..
+rm -rf _boost
diff --git a/share/ci/scripts/linux/install_cmake.sh b/share/ci/scripts/linux/install_cmake.sh
new file mode 100755 (executable)
index 0000000..7f194ed
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+set -ex
+
+echo "Updating to newer cmake to enable python-3"
+
+CMAKE_VERSION="$1"
+
+curl --location "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.sh" -o /tmp/cmake.sh
+cd /tmp && sh cmake.sh --skip-license --prefix=/usr/local --exclude-subdir
+rm /tmp/cmake.sh
+
+echo $(ls /usr/local/bin)
+echo $(which cmake)
diff --git a/share/ci/scripts/linux/install_gdb.sh b/share/ci/scripts/linux/install_gdb.sh
new file mode 100755 (executable)
index 0000000..484b023
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+set -ex
+
+GDB_VERSION="8.3"
+
+echo "Installing gdb-${GDB_VERSION}" 
+
+wget -q https://ftp.gnu.org/gnu/gdb/gdb-${GDB_VERSION}.tar.xz
+tar -xvf gdb-${GDB_VERSION}.tar.xz
+
+cd gdb-${GDB_VERSION}
+
+# Build gdb
+./configure --prefix=/usr \
+            --with-system-readline \
+            --with-python=/usr/bin/python3 &&
+make
+sudo make -C gdb install
+
+cd ..
diff --git a/share/ci/scripts/linux/install_six.sh b/share/ci/scripts/linux/install_six.sh
new file mode 100755 (executable)
index 0000000..7d87ed3
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+set -ex
+
+SIX_VERSION="1.12.0"
+
+echo "Installing six-${SIX_VERSION}" 
+
+wget -q  https://files.pythonhosted.org/packages/source/s/six/six-${SIX_VERSION}.tar.gz
+tar -xvf six-${SIX_VERSION}.tar.gz
+
+cd six-${SIX_VERSION}
+
+# Install six
+python3 setup.py build
+sudo python3 setup.py install --optimize=1
+
+cd ..
+
diff --git a/share/ci/scripts/linux/install_sonar.sh b/share/ci/scripts/linux/install_sonar.sh
new file mode 100755 (executable)
index 0000000..8ed0861
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+set -ex
+
+SONAR_VERSION="$1"
+
+mkdir _sonar
+cd _sonar
+
+wget https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip
+unzip build-wrapper-linux-x86.zip
+mv build-wrapper-linux-x86 /var/opt/.
+ln -s /var/opt/build-wrapper-linux-x86/build-wrapper-linux-x86-64 /usr/bin/build-wrapper-linux-x86-64
+echo $(build-wrapper-linux-x86-64 --help)
+
+wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_VERSION}-linux.zip
+unzip sonar-scanner-cli-${SONAR_VERSION}-linux.zip
+mv sonar-scanner-${SONAR_VERSION}-linux /var/opt/.
+ln -s /var/opt/sonar-scanner-${SONAR_VERSION}-linux/bin/sonar-scanner /usr/bin/sonar-scanner
+echo $(sonar-scanner --help)
+
+cd ..
+rm -rf _sonar
diff --git a/share/ci/scripts/linux/install_valgrind.sh b/share/ci/scripts/linux/install_valgrind.sh
new file mode 100755 (executable)
index 0000000..d6135fd
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+set -ex
+
+VALGRIND_VERSION="3.15.0"
+
+echo "Updating to Valgrind ${VALGRIND_VERSION}" 
+
+wget -q https://sourceware.org/ftp/valgrind/valgrind-${VALGRIND_VERSION}.tar.bz2 
+tar -xjf valgrind-${VALGRIND_VERSION}.tar.bz2
+
+cd valgrind-${VALGRIND_VERSION}
+
+# Build valgrind 
+sed -i 's|/doc/valgrind||' docs/Makefile.in &&
+./configure --prefix=/usr \
+            --datadir=/usr/share/doc/valgrind-${VALGRIND_VERSION} &&
+make
+
+# Test the build - disabled
+# NOTE: if enabled, must install prerequisites gedb-8.3 and six-1.12.0
+# make regtest
+
+# Install valgrind 
+sudo make install
+
+echo $(which valgrind)
+
+cd ..
diff --git a/share/ci/scripts/linux/log_valgrind.sh b/share/ci/scripts/linux/log_valgrind.sh
new file mode 100755 (executable)
index 0000000..39183ba
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+set -ex
+
+LOGDIR="$1"
+
+if [[ -d ${LOGDIR}/Testing/Temporary ]]; then 
+       for log in ${LOGDIR}/Testing/Temporary/MemoryChecker.*.log; do 
+               echo "========================== " ${log##*/} " ==========================" 
+               cat $log 
+               echo 
+       done 
+else 
+       echo "Memcheck log files not found." 
+fi
diff --git a/share/ci/scripts/linux/run_gcov.sh b/share/ci/scripts/linux/run_gcov.sh
new file mode 100755 (executable)
index 0000000..35ce32f
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (c) Contributors to the OpenEXR Project.
+
+set -ex
+
+if [ $# -gt 0 ]
+then
+   build=$1  # use explicity-provided build directory
+   coverage="$build/_coverage"
+else
+   build='../_build'  # from with CI, use the _build subdirectory
+   coverage="_coverage"
+fi
+   
+mkdir -p $coverage
+cd $coverage
+
+for gcno in $(find $build -name "*.gcno" -type f); do
+
+    # Identify the original source file (.cpp or .c) from the .gcno
+    # file by examining the .o.d make dependency file. The source
+    # file should be the second line in the .o.d file.
+    
+    # gcno = $build/src/bin/exrheader/CMakeFiles/exrheader.dir/main.gcno
+    # object_directory = $build/src/bin/exrheader/CMakeFiles/exrheader.dir
+    # source_base = $build/src/bin/exrheader/CMakeFiles/exrheader.dir/main
+    # dependenty_file = $build/src/bin/exrheader/CMakeFiles/exrheader.dir/main.o.d
+
+    object_directory=$(dirname "$gcno")
+    source_base=$(basename "$gcno" ".gcno")
+    dependency_file=$object_directory/$source_base.o.d
+
+    if [ -f "$dependency_file" ]; then
+
+        source_file=$(head -2 $dependency_file | tail -1 | sed -e 's/ //' -e 's/ \\//') 
+        gcov -l -p -o $object_directory $source_file 
+    fi
+done
+
+
+
diff --git a/share/ci/scripts/macos/install_boost.sh b/share/ci/scripts/macos/install_boost.sh
new file mode 100755 (executable)
index 0000000..89d2458
--- /dev/null
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+set -ex
+
+brew update
+brew install boost
+brew install boost-python
+brew install boost-python3
diff --git a/share/ci/scripts/macos/install_python.sh b/share/ci/scripts/macos/install_python.sh
new file mode 100755 (executable)
index 0000000..ab2b709
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+set -ex
+
+PYTHON_VERSION="$1"
+PYTHON_MAJOR="$(echo ${PYTHON_VERSION} | cut -f 1 -d .)"
+
+MACOS_MAJOR="$(sw_vers -productVersion | cut -f 1 -d .)"
+MACOS_MINOR="$(sw_vers -productVersion | cut -f 2 -d .)"
+
+echo "Installing Python ${PYTHON_VERSION} Major ${PYTHON_MAJOR}"
+
+# This workaround is needed for building Python on macOS >= 10.14:
+#   https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
+
+if [[ "$MACOS_MAJOR" -gt 9 && "$MACOS_MINOR" -gt 13 ]]; then
+    sudo installer \
+        -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_${MACOS_MAJOR}.${MACOS_MINOR}.pkg \
+        -target /
+fi
+
+unset CFLAGS
+
+brew update
+brew install pyenv openssl 
+
+CFLAGS="-I/usr/local/Cellar/openssl/1.0.2s/include"
+LDFLAGS="-L/usr/local/Cellar/openssl/1.0.2s/lib"
+
+echo 'eval "$(pyenv init -)"' >> .bash_profile
+source .bash_profile
+env PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install -v ${PYTHON_VERSION}
+pyenv global ${PYTHON_VERSION}
+
+sudo pip install --upgrade pip
+if [[ $PYTHON_MAJOR -eq 2 ]]; then
+    sudo pip install numpy
+else
+    sudo pip3 install numpy
+fi
diff --git a/share/ci/scripts/windows/install_boost.ps1 b/share/ci/scripts/windows/install_boost.ps1
new file mode 100755 (executable)
index 0000000..087c06f
--- /dev/null
@@ -0,0 +1,70 @@
+#\r
+# TODO: fix this script to work with sourceforge archive!\r
+#\r
+$homeDir = (pwd)\r
+\r
+$boostVersion = $Args[0]\r
+$boostWorkingDir = $Args[1]\r
+$pythonVersion = $Args[2]\r
+\r
+$boostRoot = "${boostWorkingDir}\_boost"\r
+\r
+$boostMajorMinor = [io.path]::GetFileNameWithoutExtension("$boostVersion")\r
+$boostVersionConcise = $boostVersion -replace '[.]',''\r
+$boostArray = $boostVersion -split "\."\r
+$boostMajor = $boostArray[0]\r
+$boostMinor = $boostArray[1]\r
+$boostPatch = $boostArray[2];\r
+$boostVersionU = "boost_${boostMajor}_${boostMinor}_${boostPatch}"\r
+$boostArchive = "https://sourceforge.net/projects/boost/files/boost-binaries/1.70.0/boost_1_70_0-msvc-14.1-64.exe"\r
+$boostBuildPath = "${boostRoot}\boost-${boostVersion}\${boostVersionU}"\r
+\r
+$pythonMajor = ($pythonVersion -split '\.')[0]\r
+$pythonMinor = ($pythonVersion -split '\.')[1]\r
+$pythonMajorMinor = "${pythonMajor}.${pythonMinor}"\r
+\r
+Write-Host "boostRoot ${boostRoot}"\r
+Write-Host "boostBuildPath ${boostBuildPath}"\r
+Write-Host "pythonMajorMinor ${pythonMajorMinor}"\r
+\r
+if (-NOT (Test-Path $boostRoot))\r
+{\r
+       New-Item -ItemType Directory $boostRoot\r
+}\r
+\r
+cd $boostRoot\r
+\r
+# Retrieve/expand archive \r
+Write-Host "Retrieving ${boostArchive}"\r
+Invoke-WebRequest $boostArchive -OutFile "boost-${boostVersion}.zip"\r
+Write-Host "Expanding archive boost-${boostVersion}.zip"\r
+Expand-Archive "boost-${boostVersion}.zip" \r
+\r
+cd "${boostBuildPath}\tools\build"\r
+\r
+# Configure and install boost \r
+echo "Configuring boost..."\r
+& .\bootstrap.bat --with-python-version=$pythonMajorMinor\r
+& .\b2 install -j4 variant=release toolset=msvc `\r
+      --prefix=$boostBuildPath `\r
+      --address-model=64\r
+\r
+$env:Path = "${boostBuildPath}\bin;${boostBuildPath};$env:Path"\r
+\r
+cd $boostBuildPath\r
+\r
+# Build boost-python2 libs \r
+echo "Building boost python..."\r
+& b2 --with-python `\r
+        --address-model=64 `\r
+        --prefix=$boostBuildPath `\r
+        toolset=msvc\r
+\r
+cd $homeDir\r
+\r
+$env:BOOST_ROOT = $boostBuildPath\r
+echo "BOOST_ROOT = ${env:BOOST_ROOT}"\r
+\r
+echo "::set-env name=BOOST_ROOT::$boostBuildPath"\r
+echo "::add-path::$boostBuildPath"\r
+\r
diff --git a/share/ci/scripts/windows/install_cmake.ps1 b/share/ci/scripts/windows/install_cmake.ps1
new file mode 100755 (executable)
index 0000000..92cb6d6
--- /dev/null
@@ -0,0 +1,7 @@
+$cmakeVersion = $Args[0]
+$cmakeMajorMinor = [io.path]::GetFileNameWithoutExtension("$cmakeVersion")
+
+Invoke-WebRequest "https://cmake.org/files/v${cmakeMajorMinor}/cmake-${cmakeVersion}-win64-x64.zip" -OutFile "C:\cmake-${cmakeVersion}-win64-x64.zip"
+Expand-Archive "C:\cmake-${cmakeVersion}-win64-x64.zip" -DestinationPath C:\
+Rename-Item -Path "C:\cmake-${cmakeVersion}-win64-x64" -NewName C:\_cmake
+Write-Host "##vso[task.prependpath]C:\_cmake\bin"
diff --git a/share/ci/scripts/windows/install_python.ps1 b/share/ci/scripts/windows/install_python.ps1
new file mode 100755 (executable)
index 0000000..24cb0e9
--- /dev/null
@@ -0,0 +1,34 @@
+$homeDir = (pwd)
+
+$pythonVersion = $Args[0]
+$pythonWorkingDir = $Args[1]
+
+$pythonMajor = ($pythonVersion -split '\.')[0]
+$pythonMinor = ($pythonVersion -split '\.')[1]
+$pythonRoot = "${pythonWorkingDir}\_python${pythonMajor}${pythonMinor}"
+
+Write-Host "Installing python version ${pythonVersion} ${pythonRoot}"
+
+if (-NOT (Test-Path $pythonRoot))
+{
+       New-Item -ItemType Directory $pythonRoot
+}
+
+cd $pythonRoot
+
+if ($pythonMajor -eq "3")
+{
+    Invoke-WebRequest "https://www.python.org/ftp/python/${pythonVersion}/python-${pythonVersion}.exe" -OutFile "python-${pythonVersion}-amd64.exe"
+    Invoke-Expression "./python-${pythonVersion}-amd64.exe /quiet /l* _python.log TargetDir=${pythonRoot} PrependPath=1"
+}
+else
+{
+    Invoke-WebRequest "https://www.python.org/ftp/python/${pythonVersion}/python-${pythonVersion}.amd64.msi" -OutFile "python-${pythonVersion}-amd64.msi"
+    msiexec /i "python-${pythonVersion}-amd64.msi" /quiet /l* _python.log TARGETDIR="${pythonRoot}" PrependPath=1
+}
+
+cd $homeDir
+
+echo "::set-env name=PYTHON_ROOT::$pythonRoot"
+echo "::add-path::$pythonRoot"
+echo "::add-path::$pythonRoot/Scripts"
\ No newline at end of file
diff --git a/share/ci/scripts/windows/install_zlib.ps1 b/share/ci/scripts/windows/install_zlib.ps1
new file mode 100755 (executable)
index 0000000..4c3bea2
--- /dev/null
@@ -0,0 +1,36 @@
+$homeDir = (pwd)\r
+\r
+$zlibVersion = $Args[0]\r
+$zlibWorkingDir = $Args[1]\r
+\r
+$zlibMajorMinor = [io.path]::GetFileNameWithoutExtension("$zlibVersion")\r
+$zlibVersionConcise = $zlibVersion -replace '[.]',''\r
+$zlibArchive = "https://www.zlib.net/zlib${zlibVersionConcise}.zip"\r
+\r
+$zlibRoot = "${zlibWorkingDir}\_zlib"\r
+$zlibBuildPath = "${zlibWorkingDir}\zlib-${zlibVersion}"\r
+$zlibDllPath = "${zlibRoot}\bin"\r
+$msbuild = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe"\r
+\r
+Write-Host "Retrieving ${zlibArchive}"\r
+Invoke-WebRequest "${zlibArchive}" -OutFile "${zlibBuildPath}.zip"\r
+Write-Host "Expanding archive ${zlibBuildPath}.zip"\r
+Expand-Archive "${zlibBuildPath}.zip" -DestinationPath "${zlibWorkingDir}"\r
+\r
+if (-NOT (Test-Path $zlibRoot))\r
+{\r
+       New-Item -ItemType Directory $zlibRoot\r
+}\r
+\r
+cd $zlibBuildPath\r
+mkdir _build\r
+cd _build\r
+cmake .. -G"Visual Studio 16 2019" -DCMAKE_INSTALL_PREFIX="${zlibRoot}"\r
+\r
+Write-Host "Building ${zlibBuildPath}\_build\INSTALL.vcxproj" -foregroundcolor green \r
+& "${msbuild}" "${zlibBuildPath}\_build\INSTALL.vcxproj" /P:Configuration=Release\r
+\r
+cd $homeDir\r
+\r
+echo "::set-env name=ZLIB_ROOT::$zlibRoot"\r
+echo "::add-path::$zlibDllPath"\r
diff --git a/sonar-project.properties b/sonar-project.properties
new file mode 100644 (file)
index 0000000..c8d8977
--- /dev/null
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+#
+# SonarCloud analysis configuration file
+# https://sonarcloud.io/documentation/analysis/analysis-parameters
+
+sonar.host.url=https://sonarcloud.io
+
+# Required metadata
+sonar.organization=academysoftwarefoundation
+sonar.projectKey=AcademySoftwareFoundation_Imath
+sonar.projectName=Imath
+sonar.projectVersion=3.0
+
+# Project links
+sonar.links.homepage=http://openexr.com
+sonar.links.ci=https://github.com/AcademySoftwareFoundation/imath/actions
+sonar.links.scm=https://github.com/AcademySoftwareFoundation/imath
+sonar.links.issue=https://github.com/AcademySoftwareFoundation/imath/issues
+
+# Source properties
+sonar.exclusions=src/bindings/java/**,*.java
+
+# C/C++ analyzer properties
+sonar.cfamily.build-wrapper-output=_build/bw_output
+sonar.cfamily.gcov.reportsPath=_coverage
+
diff --git a/src/Imath/CMakeLists.txt b/src/Imath/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7990bde
--- /dev/null
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+imath_define_library(Imath
+  PRIV_EXPORT IMATH_EXPORTS
+  CURDIR ${CMAKE_CURRENT_SOURCE_DIR}
+  SOURCES
+    half.cpp
+    ImathColorAlgo.cpp
+    ImathFun.cpp
+    ImathMatrixAlgo.cpp
+    ImathRandom.cpp
+    toFloat.h
+  HEADERS
+    half.h
+    halfFunction.h
+    halfLimits.h
+    ImathBox.h
+    ImathBoxAlgo.h
+    ImathColor.h
+    ImathColorAlgo.h
+    ImathEuler.h
+    ImathExport.h
+    ImathForward.h
+    ImathFrame.h
+    ImathFrustum.h
+    ImathFrustumTest.h
+    ImathFun.h
+    ImathGL.h
+    ImathGLU.h
+    ImathInt64.h
+    ImathInterval.h
+    ImathLine.h
+    ImathLineAlgo.h
+    ImathMath.h
+    ImathMatrix.h
+    ImathMatrixAlgo.h
+    ImathNamespace.h
+    ImathPlane.h
+    ImathPlatform.h
+    ImathQuat.h
+    ImathRandom.h
+    ImathRoots.h
+    ImathShear.h
+    ImathSphere.h
+    ImathTypeTraits.h
+    ImathVec.h
+    ImathVecAlgo.h
+  )
diff --git a/src/Imath/ImathBox.h b/src/Imath/ImathBox.h
new file mode 100644 (file)
index 0000000..7391dd7
--- /dev/null
@@ -0,0 +1,899 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Axis-aligned bounding box
+//
+
+#ifndef INCLUDED_IMATHBOX_H
+#define INCLUDED_IMATHBOX_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include "ImathVec.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// The `Box<V>` template represents an axis-aligned bounding box defined by
+/// minimum and maximum values of type `V`. The `min` and `max` members are
+/// public.
+///
+/// The type `V` is typically an Imath vector (i.e. `V2i`, `V3f`, etc) and must
+/// implement an index `operator[]` that returns a type (typically as scalar)
+/// that supports assignment, comparison, and arithmetic operators.
+///
+/// `V` must also provide a constructor that takes a float and/or double for
+/// use in initializing the box.
+///
+/// `V` must also provide a function `V::dimensions()` which returns the
+/// number of dimensions in the class (since its assumed its a vector) --
+/// preferably, this returns a constant expression, typically 2 or 3.
+///
+
+template <class V> class IMATH_EXPORT_TEMPLATE_TYPE Box
+{
+  public:
+
+    /// @{
+    /// @name Direct access to bounds
+    
+    /// The minimum value of the box.
+    V min;
+
+    /// The maximum value of the box.
+    V max;
+
+    /// @}
+
+    /// @{
+    ///        @name Constructors
+
+    /// Construct an empty bounding box. This initializes the mimimum to
+    /// std::numeric_limits<V::baseType>::max() and the maximum to
+    /// std::numeric_limits<V::baseType>::lowest().
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Box() IMATH_NOEXCEPT;
+
+    /// Construct a bounding box that contains a single point.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Box (const V& point) IMATH_NOEXCEPT;
+
+    /// Construct a bounding box with the given minimum and maximum values.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Box (const V& minV, const V& maxV) IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Comparison
+    
+    /// Equality
+    IMATH_HOSTDEVICE constexpr bool operator== (const Box<V>& src) const IMATH_NOEXCEPT;
+
+    /// Inequality
+    IMATH_HOSTDEVICE constexpr bool operator!= (const Box<V>& src) const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Manipulation
+
+    /// Set the box to be empty. A box is empty if the mimimum is greater
+    /// than the maximum. makeEmpty() sets the mimimum to `V::baseTypeMax()`
+    /// and the maximum to `V::baseTypeLowest()`.
+    IMATH_HOSTDEVICE void makeEmpty() IMATH_NOEXCEPT;
+
+    /// Extend the box to include the given point.
+    IMATH_HOSTDEVICE void extendBy (const V& point) IMATH_NOEXCEPT;
+
+    /// Extend the box to include the given box.
+    IMATH_HOSTDEVICE void extendBy (const Box<V>& box) IMATH_NOEXCEPT;
+
+    /// Make the box include the entire range of `V`.
+    IMATH_HOSTDEVICE void makeInfinite() IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Query
+    
+    /// Return the size of the box. The size is of type `V`, defined
+    /// as `(max-min)`. An empty box has a size of `V(0)`, i.e. 0 in
+    /// each dimension.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 V size() const IMATH_NOEXCEPT;
+
+    /// Return the center of the box. The center is defined as
+    /// `(max+min)/2`. The center of an empty box is undefined.
+    IMATH_HOSTDEVICE constexpr V center() const IMATH_NOEXCEPT;
+
+    /// Return true if the given point is inside the box, false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersects (const V& point) const IMATH_NOEXCEPT;
+
+    /// Return true if the given box is inside the box, false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersects (const Box<V>& box) const IMATH_NOEXCEPT;
+
+    /// Return the major axis of the box. The major axis is the dimension with
+    /// the greatest difference between maximum and minimum.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 unsigned int majorAxis() const IMATH_NOEXCEPT;
+
+    /// Return true if the box is empty, false otherwise. An empty box's
+    /// minimum is greater than its maximum.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool isEmpty() const IMATH_NOEXCEPT;
+
+    /// Return true if the box is larger than a single point, false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool hasVolume() const IMATH_NOEXCEPT;
+
+    /// Return true if the box contains all points, false otherwise.
+    /// An infinite box has a mimimum of`V::baseTypeLowest()`
+    /// and a maximum of `V::baseTypeMax()`.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool isInfinite() const IMATH_NOEXCEPT;
+
+    /// @}
+};
+
+//--------------------
+// Convenient typedefs
+//--------------------
+
+/// 2D box of base type `short`.
+typedef Box<V2s> Box2s;
+
+/// 2D box of base type `int`.
+typedef Box<V2i> Box2i;
+
+/// 2D box of base type `int64_t`.
+typedef Box<V2i64> Box2i64;
+
+/// 2D box of base type `float`.
+typedef Box<V2f> Box2f;
+
+/// 2D box of base type `double`.
+typedef Box<V2d> Box2d;
+
+/// 3D box of base type `short`.
+typedef Box<V3s> Box3s;
+
+/// 3D box of base type `int`.
+typedef Box<V3i> Box3i;
+
+/// 3D box of base type `int64_t`.
+typedef Box<V3i64> Box3i64;
+
+/// 3D box of base type `float`.
+typedef Box<V3f> Box3f;
+
+/// 3D box of base type `double`.
+typedef Box<V3d> Box3d;
+
+template <class V>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Box<V>::Box() IMATH_NOEXCEPT
+{
+    makeEmpty();
+}
+
+template <class V>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Box<V>::Box (const V& point) IMATH_NOEXCEPT
+{
+    min = point;
+    max = point;
+}
+
+template <class V>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Box<V>::Box (const V& minV, const V& maxV) IMATH_NOEXCEPT
+{
+    min = minV;
+    max = maxV;
+}
+
+template <class V>
+IMATH_HOSTDEVICE constexpr inline bool
+Box<V>::operator== (const Box<V>& src) const IMATH_NOEXCEPT
+{
+    return (min == src.min && max == src.max);
+}
+
+template <class V>
+IMATH_HOSTDEVICE constexpr inline bool
+Box<V>::operator!= (const Box<V>& src) const IMATH_NOEXCEPT
+{
+    return (min != src.min || max != src.max);
+}
+
+template <class V>
+IMATH_HOSTDEVICE inline void
+Box<V>::makeEmpty() IMATH_NOEXCEPT
+{
+    min = V (V::baseTypeMax());
+    max = V (V::baseTypeLowest());
+}
+
+template <class V>
+IMATH_HOSTDEVICE inline void
+Box<V>::makeInfinite() IMATH_NOEXCEPT
+{
+    min = V (V::baseTypeLowest());
+    max = V (V::baseTypeMax());
+}
+
+template <class V>
+IMATH_HOSTDEVICE inline void
+Box<V>::extendBy (const V& point) IMATH_NOEXCEPT
+{
+    for (unsigned int i = 0; i < min.dimensions(); i++)
+    {
+        if (point[i] < min[i])
+            min[i] = point[i];
+
+        if (point[i] > max[i])
+            max[i] = point[i];
+    }
+}
+
+template <class V>
+IMATH_HOSTDEVICE inline void
+Box<V>::extendBy (const Box<V>& box) IMATH_NOEXCEPT
+{
+    for (unsigned int i = 0; i < min.dimensions(); i++)
+    {
+        if (box.min[i] < min[i])
+            min[i] = box.min[i];
+
+        if (box.max[i] > max[i])
+            max[i] = box.max[i];
+    }
+}
+
+template <class V>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<V>::intersects (const V& point) const IMATH_NOEXCEPT
+{
+    for (unsigned int i = 0; i < min.dimensions(); i++)
+    {
+        if (point[i] < min[i] || point[i] > max[i])
+            return false;
+    }
+
+    return true;
+}
+
+template <class V>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<V>::intersects (const Box<V>& box) const IMATH_NOEXCEPT
+{
+    for (unsigned int i = 0; i < min.dimensions(); i++)
+    {
+        if (box.max[i] < min[i] || box.min[i] > max[i])
+            return false;
+    }
+
+    return true;
+}
+
+template <class V>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline V
+Box<V>::size() const IMATH_NOEXCEPT
+{
+    if (isEmpty())
+        return V (0);
+
+    return max - min;
+}
+
+template <class V>
+IMATH_HOSTDEVICE constexpr inline V
+Box<V>::center() const IMATH_NOEXCEPT
+{
+    return (max + min) / 2;
+}
+
+template <class V>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<V>::isEmpty() const IMATH_NOEXCEPT
+{
+    for (unsigned int i = 0; i < min.dimensions(); i++)
+    {
+        if (max[i] < min[i])
+            return true;
+    }
+
+    return false;
+}
+
+template <class V>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<V>::isInfinite() const IMATH_NOEXCEPT
+{
+    for (unsigned int i = 0; i < min.dimensions(); i++)
+    {
+        if (min[i] != V::baseTypeLowest() || max[i] != V::baseTypeMax())
+            return false;
+    }
+
+    return true;
+}
+
+template <class V>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<V>::hasVolume() const IMATH_NOEXCEPT
+{
+    for (unsigned int i = 0; i < min.dimensions(); i++)
+    {
+        if (max[i] <= min[i])
+            return false;
+    }
+
+    return true;
+}
+
+template <class V>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline unsigned int
+Box<V>::majorAxis() const IMATH_NOEXCEPT
+{
+    unsigned int major = 0;
+    V s                = size();
+
+    for (unsigned int i = 1; i < min.dimensions(); i++)
+    {
+        if (s[i] > s[major])
+            major = i;
+    }
+
+    return major;
+}
+
+//-------------------------------------------------------------------
+//
+//  Partial class specializations for Imath::Vec2<T> and Imath::Vec3<T>
+//
+//-------------------------------------------------------------------
+
+template <typename V> class Box;
+
+///
+/// The Box<Vec2<T>> template represents a 2D bounding box defined by
+/// minimum and maximum values of type Vec2<T>. The min and max members are
+/// public.
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Box<Vec2<T>>
+{
+  public:
+
+    /// @{
+    /// @name Direct access to bounds
+    
+    /// The minimum value of the box.
+    Vec2<T> min;
+
+    /// The maximum value of the box.
+    Vec2<T> max;
+
+    /// @}
+    
+    /// @{
+    /// @name Constructors and Assignment
+
+    /// Empty by default
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Box() IMATH_NOEXCEPT;
+
+    /// Construct a bounding box that contains a single point.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Box (const Vec2<T>& point) IMATH_NOEXCEPT;
+
+    /// Construct a bounding box with the given minimum and maximum points
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Box (const Vec2<T>& minT, const Vec2<T>& maxT) IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Comparison
+    
+    /// Equality
+    IMATH_HOSTDEVICE constexpr bool operator== (const Box<Vec2<T>>& src) const IMATH_NOEXCEPT;
+
+    /// Inequality
+    IMATH_HOSTDEVICE constexpr bool operator!= (const Box<Vec2<T>>& src) const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Manipulation
+
+    /// Set the Box to be empty. A Box is empty if the mimimum is
+    /// greater than the maximum. makeEmpty() sets the mimimum to
+    /// std::numeric_limits<T>::max() and the maximum to
+    /// std::numeric_limits<T>::lowest().
+    IMATH_HOSTDEVICE void makeEmpty() IMATH_NOEXCEPT;
+
+    /// Extend the Box to include the given point.
+    IMATH_HOSTDEVICE void extendBy (const Vec2<T>& point) IMATH_NOEXCEPT;
+
+    /// Extend the Box to include the given box.
+    IMATH_HOSTDEVICE void extendBy (const Box<Vec2<T>>& box) IMATH_NOEXCEPT;
+
+    /// Make the box include the entire range of T.
+    IMATH_HOSTDEVICE void makeInfinite() IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Query
+    
+    /// Return the size of the box. The size is of type `V`, defined as
+    /// `(max-min)`. An empty box has a size of `V(0)`, i.e. 0 in each dimension.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec2<T> size() const IMATH_NOEXCEPT;
+
+    /// Return the center of the box. The center is defined as
+    /// `(max+min)/2`. The center of an empty box is undefined.
+    IMATH_HOSTDEVICE constexpr Vec2<T> center() const IMATH_NOEXCEPT;
+
+    /// Return true if the given point is inside the box, false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersects (const Vec2<T>& point) const IMATH_NOEXCEPT;
+
+    /// Return true if the given box is inside the box, false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersects (const Box<Vec2<T>>& box) const IMATH_NOEXCEPT;
+
+    /// Return the major axis of the box. The major axis is the dimension with
+    /// the greatest difference between maximum and minimum.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 unsigned int majorAxis() const IMATH_NOEXCEPT;
+
+    /// Return true if the box is empty, false otherwise. An empty box's
+    /// minimum is greater than its maximum.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool isEmpty() const IMATH_NOEXCEPT;
+
+    /// Return true if the box is larger than a single point, false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool hasVolume() const IMATH_NOEXCEPT;
+
+    /// Return true if the box contains all points, false otherwise.
+    /// An infinite box has a mimimum of `V::baseTypeMin()`
+    /// and a maximum of `V::baseTypeMax()`.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool isInfinite() const IMATH_NOEXCEPT;
+
+    /// @}
+};
+
+//----------------
+//  Implementation
+//----------------
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Box<Vec2<T>>::Box() IMATH_NOEXCEPT
+{
+    makeEmpty();
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Box<Vec2<T>>::Box (const Vec2<T>& point) IMATH_NOEXCEPT
+{
+    min = point;
+    max = point;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Box<Vec2<T>>::Box (const Vec2<T>& minT, const Vec2<T>& maxT) IMATH_NOEXCEPT
+{
+    min = minT;
+    max = maxT;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Box<Vec2<T>>::operator== (const Box<Vec2<T>>& src) const IMATH_NOEXCEPT
+{
+    return (min == src.min && max == src.max);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Box<Vec2<T>>::operator!= (const Box<Vec2<T>>& src) const IMATH_NOEXCEPT
+{
+    return (min != src.min || max != src.max);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Box<Vec2<T>>::makeEmpty() IMATH_NOEXCEPT
+{
+    min = Vec2<T> (Vec2<T>::baseTypeMax());
+    max = Vec2<T> (Vec2<T>::baseTypeLowest());
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Box<Vec2<T>>::makeInfinite() IMATH_NOEXCEPT
+{
+    min = Vec2<T> (Vec2<T>::baseTypeLowest());
+    max = Vec2<T> (Vec2<T>::baseTypeMax());
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Box<Vec2<T>>::extendBy (const Vec2<T>& point) IMATH_NOEXCEPT
+{
+    if (point[0] < min[0])
+        min[0] = point[0];
+
+    if (point[0] > max[0])
+        max[0] = point[0];
+
+    if (point[1] < min[1])
+        min[1] = point[1];
+
+    if (point[1] > max[1])
+        max[1] = point[1];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Box<Vec2<T>>::extendBy (const Box<Vec2<T>>& box) IMATH_NOEXCEPT
+{
+    if (box.min[0] < min[0])
+        min[0] = box.min[0];
+
+    if (box.max[0] > max[0])
+        max[0] = box.max[0];
+
+    if (box.min[1] < min[1])
+        min[1] = box.min[1];
+
+    if (box.max[1] > max[1])
+        max[1] = box.max[1];
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<Vec2<T>>::intersects (const Vec2<T>& point) const IMATH_NOEXCEPT
+{
+    if (point[0] < min[0] || point[0] > max[0] || point[1] < min[1] || point[1] > max[1])
+        return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<Vec2<T>>::intersects (const Box<Vec2<T>>& box) const IMATH_NOEXCEPT
+{
+    if (box.max[0] < min[0] || box.min[0] > max[0] || box.max[1] < min[1] || box.min[1] > max[1])
+        return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Vec2<T>
+Box<Vec2<T>>::size() const IMATH_NOEXCEPT
+{
+    if (isEmpty())
+        return Vec2<T> (0);
+
+    return max - min;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec2<T>
+Box<Vec2<T>>::center() const IMATH_NOEXCEPT
+{
+    return (max + min) / 2;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<Vec2<T>>::isEmpty() const IMATH_NOEXCEPT
+{
+    if (max[0] < min[0] || max[1] < min[1])
+        return true;
+
+    return false;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<Vec2<T>>::isInfinite() const IMATH_NOEXCEPT
+{
+    if (min[0] != std::numeric_limits<T>::lowest() ||
+        max[0] != std::numeric_limits<T>::max() ||
+        min[1] != std::numeric_limits<T>::lowest() ||
+        max[1] != std::numeric_limits<T>::max())
+        return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<Vec2<T>>::hasVolume() const IMATH_NOEXCEPT
+{
+    if (max[0] <= min[0] || max[1] <= min[1])
+        return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline unsigned int
+Box<Vec2<T>>::majorAxis() const IMATH_NOEXCEPT
+{
+    unsigned int major = 0;
+    Vec2<T> s          = size();
+
+    if (s[1] > s[major])
+        major = 1;
+
+    return major;
+}
+
+///
+/// The Box<Vec3> template represents a 3D bounding box defined by
+/// minimum and maximum values of type Vec3. 
+///
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Box<Vec3<T>>
+{
+  public:
+
+    /// @{
+    /// @name Direct access to bounds
+    
+    /// The minimum value of the box.
+    Vec3<T> min;
+
+    /// The maximum value of the box.
+    Vec3<T> max;
+
+    /// @}
+
+    /// @{
+    /// @name Constructors
+
+    /// Empty by default
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Box() IMATH_NOEXCEPT;
+
+    /// Construct a bounding box that contains a single point.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Box (const Vec3<T>& point) IMATH_NOEXCEPT;
+
+    /// Construct a bounding box with the given minimum and maximum points
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Box (const Vec3<T>& minT, const Vec3<T>& maxT) IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// Equality
+    IMATH_HOSTDEVICE constexpr bool operator== (const Box<Vec3<T>>& src) const IMATH_NOEXCEPT;
+
+    /// Inequality
+    IMATH_HOSTDEVICE constexpr bool operator!= (const Box<Vec3<T>>& src) const IMATH_NOEXCEPT;
+
+    /// Set the Box to be empty. A Box is empty if the mimimum is
+    /// greater than the maximum. makeEmpty() sets the mimimum to
+    /// std::numeric_limits<T>::max() and the maximum to
+    /// std::numeric_limits<T>::lowest().
+    IMATH_HOSTDEVICE void makeEmpty() IMATH_NOEXCEPT;
+
+    /// Extend the Box to include the given point.
+    IMATH_HOSTDEVICE void extendBy (const Vec3<T>& point) IMATH_NOEXCEPT;
+    /// Extend the Box to include the given box.
+
+    IMATH_HOSTDEVICE void extendBy (const Box<Vec3<T>>& box) IMATH_NOEXCEPT;
+
+    /// Make the box include the entire range of T.
+    IMATH_HOSTDEVICE void makeInfinite() IMATH_NOEXCEPT;
+
+    /// Return the size of the box. The size is of type `V`, defined as
+    /// (max-min). An empty box has a size of V(0), i.e. 0 in each dimension.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3<T> size() const IMATH_NOEXCEPT;
+
+    /// Return the center of the box. The center is defined as
+    /// (max+min)/2. The center of an empty box is undefined.
+    IMATH_HOSTDEVICE constexpr Vec3<T> center() const IMATH_NOEXCEPT;
+
+    /// Return true if the given point is inside the box, false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersects (const Vec3<T>& point) const IMATH_NOEXCEPT;
+
+    /// Return true if the given box is inside the box, false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersects (const Box<Vec3<T>>& box) const IMATH_NOEXCEPT;
+
+    /// Return the major axis of the box. The major axis is the dimension with
+    /// the greatest difference between maximum and minimum.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 unsigned int majorAxis() const IMATH_NOEXCEPT;
+
+    /// Return true if the box is empty, false otherwise. An empty box's
+    /// minimum is greater than its maximum.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool isEmpty() const IMATH_NOEXCEPT;
+
+    /// Return true if the box is larger than a single point, false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool hasVolume() const IMATH_NOEXCEPT;
+
+    /// Return true if the box contains all points, false otherwise.
+    /// An infinite box has a mimimum of`V::baseTypeMin()`
+    /// and a maximum of `V::baseTypeMax()`.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool isInfinite() const IMATH_NOEXCEPT;
+};
+
+//----------------
+//  Implementation
+//----------------
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Box<Vec3<T>>::Box() IMATH_NOEXCEPT
+{
+    makeEmpty();
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Box<Vec3<T>>::Box (const Vec3<T>& point) IMATH_NOEXCEPT
+{
+    min = point;
+    max = point;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Box<Vec3<T>>::Box (const Vec3<T>& minT, const Vec3<T>& maxT) IMATH_NOEXCEPT
+{
+    min = minT;
+    max = maxT;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Box<Vec3<T>>::operator== (const Box<Vec3<T>>& src) const IMATH_NOEXCEPT
+{
+    return (min == src.min && max == src.max);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Box<Vec3<T>>::operator!= (const Box<Vec3<T>>& src) const IMATH_NOEXCEPT
+{
+    return (min != src.min || max != src.max);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Box<Vec3<T>>::makeEmpty() IMATH_NOEXCEPT
+{
+    min = Vec3<T> (Vec3<T>::baseTypeMax());
+    max = Vec3<T> (Vec3<T>::baseTypeLowest());
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Box<Vec3<T>>::makeInfinite() IMATH_NOEXCEPT
+{
+    min = Vec3<T> (Vec3<T>::baseTypeLowest());
+    max = Vec3<T> (Vec3<T>::baseTypeMax());
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Box<Vec3<T>>::extendBy (const Vec3<T>& point) IMATH_NOEXCEPT
+{
+    if (point[0] < min[0])
+        min[0] = point[0];
+
+    if (point[0] > max[0])
+        max[0] = point[0];
+
+    if (point[1] < min[1])
+        min[1] = point[1];
+
+    if (point[1] > max[1])
+        max[1] = point[1];
+
+    if (point[2] < min[2])
+        min[2] = point[2];
+
+    if (point[2] > max[2])
+        max[2] = point[2];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Box<Vec3<T>>::extendBy (const Box<Vec3<T>>& box) IMATH_NOEXCEPT
+{
+    if (box.min[0] < min[0])
+        min[0] = box.min[0];
+
+    if (box.max[0] > max[0])
+        max[0] = box.max[0];
+
+    if (box.min[1] < min[1])
+        min[1] = box.min[1];
+
+    if (box.max[1] > max[1])
+        max[1] = box.max[1];
+
+    if (box.min[2] < min[2])
+        min[2] = box.min[2];
+
+    if (box.max[2] > max[2])
+        max[2] = box.max[2];
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<Vec3<T>>::intersects (const Vec3<T>& point) const IMATH_NOEXCEPT
+{
+    if (point[0] < min[0] || point[0] > max[0] || point[1] < min[1] || point[1] > max[1] ||
+        point[2] < min[2] || point[2] > max[2])
+        return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<Vec3<T>>::intersects (const Box<Vec3<T>>& box) const IMATH_NOEXCEPT
+{
+    if (box.max[0] < min[0] || box.min[0] > max[0] || box.max[1] < min[1] || box.min[1] > max[1] ||
+        box.max[2] < min[2] || box.min[2] > max[2])
+        return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Vec3<T>
+Box<Vec3<T>>::size() const IMATH_NOEXCEPT
+{
+    if (isEmpty())
+        return Vec3<T> (0);
+
+    return max - min;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Box<Vec3<T>>::center() const IMATH_NOEXCEPT
+{
+    return (max + min) / 2;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<Vec3<T>>::isEmpty() const IMATH_NOEXCEPT
+{
+    if (max[0] < min[0] || max[1] < min[1] || max[2] < min[2])
+        return true;
+
+    return false;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<Vec3<T>>::isInfinite() const IMATH_NOEXCEPT
+{
+    if (min[0] != std::numeric_limits<T>::lowest() ||
+        max[0] != std::numeric_limits<T>::max() ||
+        min[1] != std::numeric_limits<T>::lowest() ||
+        max[1] != std::numeric_limits<T>::max() ||
+        min[2] != std::numeric_limits<T>::lowest() ||
+        max[2] != std::numeric_limits<T>::max())
+        return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Box<Vec3<T>>::hasVolume() const IMATH_NOEXCEPT
+{
+    if (max[0] <= min[0] || max[1] <= min[1] || max[2] <= min[2])
+        return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline unsigned int
+Box<Vec3<T>>::majorAxis() const IMATH_NOEXCEPT
+{
+    unsigned int major = 0;
+    Vec3<T> s          = size();
+
+    if (s[1] > s[major])
+        major = 1;
+
+    if (s[2] > s[major])
+        major = 2;
+
+    return major;
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHBOX_H
diff --git a/src/Imath/ImathBoxAlgo.h b/src/Imath/ImathBoxAlgo.h
new file mode 100644 (file)
index 0000000..97e6edb
--- /dev/null
@@ -0,0 +1,908 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Axis-aligned bounding box utility functions
+//
+
+#ifndef INCLUDED_IMATHBOXALGO_H
+#define INCLUDED_IMATHBOXALGO_H
+
+#include "ImathNamespace.h"
+
+#include "ImathBox.h"
+#include "ImathLineAlgo.h"
+#include "ImathMatrix.h"
+#include "ImathPlane.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// Clip the coordinates of a point, `p`, against a `Box<T>`, `box`.
+/// Return the closest point to `p` that is inside the box.
+///
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+clip (const T& p, const Box<T>& box) IMATH_NOEXCEPT
+{
+    T q;
+
+    for (int i = 0; i < int (box.min.dimensions()); i++)
+    {
+        if (p[i] < box.min[i])
+            q[i] = box.min[i];
+        else if (p[i] > box.max[i])
+            q[i] = box.max[i];
+        else
+            q[i] = p[i];
+    }
+
+    return q;
+}
+
+///
+/// Return the point in or on the `Box<T>`, `box`, that is closesest to
+/// the point, `p`.
+///
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+closestPointInBox (const T& p, const Box<T>& box) IMATH_NOEXCEPT
+{
+    return clip (p, box);
+}
+
+///
+/// Return the point on the surface of the `Box<T>`, `box`, that is
+/// closest to point `p`.
+///
+/// If the box is empty, return `p`.
+///
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3<T>
+closestPointOnBox (const Vec3<T>& p, const Box<Vec3<T>>& box) IMATH_NOEXCEPT
+{
+    if (box.isEmpty())
+        return p;
+
+    Vec3<T> q = closestPointInBox (p, box);
+
+    if (q == p)
+    {
+        Vec3<T> d1 = p - box.min;
+        Vec3<T> d2 = box.max - p;
+
+        Vec3<T> d ((d1.x < d2.x) ? d1.x : d2.x,
+                   (d1.y < d2.y) ? d1.y : d2.y,
+                   (d1.z < d2.z) ? d1.z : d2.z);
+
+        if (d.x < d.y && d.x < d.z)
+        {
+            q.x = (d1.x < d2.x) ? box.min.x : box.max.x;
+        }
+        else if (d.y < d.z)
+        {
+            q.y = (d1.y < d2.y) ? box.min.y : box.max.y;
+        }
+        else
+        {
+            q.z = (d1.z < d2.z) ? box.min.z : box.max.z;
+        }
+    }
+
+    return q;
+}
+
+///
+/// Transform a 3D box by a matrix, and compute a new box that
+/// tightly encloses the transformed box. Return the transformed box.
+///
+/// If `m` is an affine transform, then we use James Arvo's fast
+/// method as described in "Graphics Gems", Academic Press, 1990,
+/// pp. 548-550.
+///
+/// A transformed empty box is still empty, and a transformed infinite box
+/// is still infinite.
+///
+
+template <class S, class T>
+IMATH_HOSTDEVICE Box<Vec3<S>>
+transform (const Box<Vec3<S>>& box, const Matrix44<T>& m) IMATH_NOEXCEPT
+{
+    if (box.isEmpty() || box.isInfinite())
+        return box;
+
+    //
+    // If the last column of m is (0 0 0 1) then m is an affine
+    // transform, and we use the fast Graphics Gems trick.
+    //
+
+    if (m[0][3] == 0 && m[1][3] == 0 && m[2][3] == 0 && m[3][3] == 1)
+    {
+        Box<Vec3<S>> newBox;
+
+        for (int i = 0; i < 3; i++)
+        {
+            newBox.min[i] = newBox.max[i] = (S) m[3][i];
+
+            for (int j = 0; j < 3; j++)
+            {
+                S a, b;
+
+                a = (S) m[j][i] * box.min[j];
+                b = (S) m[j][i] * box.max[j];
+
+                if (a < b)
+                {
+                    newBox.min[i] += a;
+                    newBox.max[i] += b;
+                }
+                else
+                {
+                    newBox.min[i] += b;
+                    newBox.max[i] += a;
+                }
+            }
+        }
+
+        return newBox;
+    }
+
+    //
+    // M is a projection matrix.  Do things the naive way:
+    // Transform the eight corners of the box, and find an
+    // axis-parallel box that encloses the transformed corners.
+    //
+
+    Vec3<S> points[8];
+
+    points[0][0] = points[1][0] = points[2][0] = points[3][0] = box.min[0];
+    points[4][0] = points[5][0] = points[6][0] = points[7][0] = box.max[0];
+
+    points[0][1] = points[1][1] = points[4][1] = points[5][1] = box.min[1];
+    points[2][1] = points[3][1] = points[6][1] = points[7][1] = box.max[1];
+
+    points[0][2] = points[2][2] = points[4][2] = points[6][2] = box.min[2];
+    points[1][2] = points[3][2] = points[5][2] = points[7][2] = box.max[2];
+
+    Box<Vec3<S>> newBox;
+
+    for (int i = 0; i < 8; i++)
+        newBox.extendBy (points[i] * m);
+
+    return newBox;
+}
+
+///
+/// Transform a 3D box by a matrix, and compute a new box that
+/// tightly encloses the transformed box. The transformed box is
+/// returned in the `result` argument.
+///
+/// If m is an affine transform, then we use James Arvo's fast
+/// method as described in "Graphics Gems", Academic Press, 1990,
+/// pp. 548-550.
+///
+/// A transformed empty box is still empty, and a transformed infinite
+/// box is still infinite
+///
+
+template <class S, class T>
+IMATH_HOSTDEVICE void
+transform (const Box<Vec3<S>>& box, const Matrix44<T>& m, Box<Vec3<S>>& result) IMATH_NOEXCEPT
+{
+    if (box.isEmpty() || box.isInfinite())
+    {
+        return;
+    }
+
+    //
+    // If the last column of m is (0 0 0 1) then m is an affine
+    // transform, and we use the fast Graphics Gems trick.
+    //
+
+    if (m[0][3] == 0 && m[1][3] == 0 && m[2][3] == 0 && m[3][3] == 1)
+    {
+        for (int i = 0; i < 3; i++)
+        {
+            result.min[i] = result.max[i] = (S) m[3][i];
+
+            for (int j = 0; j < 3; j++)
+            {
+                S a, b;
+
+                a = (S) m[j][i] * box.min[j];
+                b = (S) m[j][i] * box.max[j];
+
+                if (a < b)
+                {
+                    result.min[i] += a;
+                    result.max[i] += b;
+                }
+                else
+                {
+                    result.min[i] += b;
+                    result.max[i] += a;
+                }
+            }
+        }
+
+        return;
+    }
+
+    //
+    // M is a projection matrix.  Do things the naive way:
+    // Transform the eight corners of the box, and find an
+    // axis-parallel box that encloses the transformed corners.
+    //
+
+    Vec3<S> points[8];
+
+    points[0][0] = points[1][0] = points[2][0] = points[3][0] = box.min[0];
+    points[4][0] = points[5][0] = points[6][0] = points[7][0] = box.max[0];
+
+    points[0][1] = points[1][1] = points[4][1] = points[5][1] = box.min[1];
+    points[2][1] = points[3][1] = points[6][1] = points[7][1] = box.max[1];
+
+    points[0][2] = points[2][2] = points[4][2] = points[6][2] = box.min[2];
+    points[1][2] = points[3][2] = points[5][2] = points[7][2] = box.max[2];
+
+    for (int i = 0; i < 8; i++)
+        result.extendBy (points[i] * m);
+}
+
+///
+/// Transform a 3D box by a matrix whose rightmost column `(0 0 0 1)`,
+/// and compute a new box that tightly encloses the transformed
+/// box. Return the transformed box.
+///
+/// As in the transform() function, use James Arvo's fast method if
+/// possible.
+///
+/// A transformed empty or infinite box is still empty or infinite.
+///
+
+template <class S, class T>
+IMATH_HOSTDEVICE Box<Vec3<S>>
+affineTransform (const Box<Vec3<S>>& box, const Matrix44<T>& m) IMATH_NOEXCEPT
+{
+    if (box.isEmpty() || box.isInfinite())
+        return box;
+
+    Box<Vec3<S>> newBox;
+
+    for (int i = 0; i < 3; i++)
+    {
+        newBox.min[i] = newBox.max[i] = (S) m[3][i];
+
+        for (int j = 0; j < 3; j++)
+        {
+            S a, b;
+
+            a = (S) m[j][i] * box.min[j];
+            b = (S) m[j][i] * box.max[j];
+
+            if (a < b)
+            {
+                newBox.min[i] += a;
+                newBox.max[i] += b;
+            }
+            else
+            {
+                newBox.min[i] += b;
+                newBox.max[i] += a;
+            }
+        }
+    }
+
+    return newBox;
+}
+
+///
+/// Transform a 3D box by a matrix whose rightmost column is
+/// `(0 0 0 1)`, and compute a new box that tightly encloses 
+/// the transformed box. Return the transformed box in the `result`
+/// argument.
+///
+/// As in the transform() function, use James Arvo's fast method if
+/// possible.
+///
+/// A transformed empty or infinite box is still empty or infinite.
+///
+
+template <class S, class T>
+IMATH_HOSTDEVICE void
+affineTransform (const Box<Vec3<S>>& box, const Matrix44<T>& m, Box<Vec3<S>>& result) IMATH_NOEXCEPT
+{
+    if (box.isEmpty())
+    {
+        result.makeEmpty();
+        return;
+    }
+
+    if (box.isInfinite())
+    {
+        result.makeInfinite();
+        return;
+    }
+
+    for (int i = 0; i < 3; i++)
+    {
+        result.min[i] = result.max[i] = (S) m[3][i];
+
+        for (int j = 0; j < 3; j++)
+        {
+            S a, b;
+
+            a = (S) m[j][i] * box.min[j];
+            b = (S) m[j][i] * box.max[j];
+
+            if (a < b)
+            {
+                result.min[i] += a;
+                result.max[i] += b;
+            }
+            else
+            {
+                result.min[i] += b;
+                result.max[i] += a;
+            }
+        }
+    }
+}
+
+///
+/// Compute the points where a ray, `r`, enters and exits a 3D box, `b`:
+///
+/// Return true if the ray starts inside the box or if the ray starts
+/// outside and intersects the box, or return false otherwise (that
+/// is, if the ray does not intersect the box).
+///
+/// The entry and exit points are the points on two of the faces of
+/// the box when the function returns true (the entry end exit points
+/// may be on either side of the ray's origin), or undefined if the
+/// the function returns false.
+///
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool
+findEntryAndExitPoints (const Line3<T>& r, const Box<Vec3<T>>& b, Vec3<T>& entry, Vec3<T>& exit) IMATH_NOEXCEPT
+{
+    if (b.isEmpty())
+    {
+        //
+        // No ray intersects an empty box
+        //
+
+        return false;
+    }
+
+    //
+    // The following description assumes that the ray's origin is outside
+    // the box, but the code below works even if the origin is inside the
+    // box:
+    //
+    // Between one and three "frontfacing" sides of the box are oriented
+    // towards the ray's origin, and between one and three "backfacing"
+    // sides are oriented away from the ray's origin.
+    // We intersect the ray with the planes that contain the sides of the
+    // box, and compare the distances between the ray's origin and the
+    // ray-plane intersections.  The ray intersects the box if the most
+    // distant frontfacing intersection is nearer than the nearest
+    // backfacing intersection.  If the ray does intersect the box, then
+    // the most distant frontfacing ray-plane intersection is the entry
+    // point and the nearest backfacing ray-plane intersection is the
+    // exit point.
+    //
+
+    const T TMAX = std::numeric_limits<T>::max();
+
+    T tFrontMax = -TMAX;
+    T tBackMin  = TMAX;
+
+    //
+    // Minimum and maximum X sides.
+    //
+
+    if (r.dir.x >= 0)
+    {
+        T d1 = b.max.x - r.pos.x;
+        T d2 = b.min.x - r.pos.x;
+
+        if (r.dir.x > 1 || (abs (d1) < TMAX * r.dir.x && abs (d2) < TMAX * r.dir.x))
+        {
+            T t1 = d1 / r.dir.x;
+            T t2 = d2 / r.dir.x;
+
+            if (tBackMin > t1)
+            {
+                tBackMin = t1;
+
+                exit.x = b.max.x;
+                exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
+                exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
+            }
+
+            if (tFrontMax < t2)
+            {
+                tFrontMax = t2;
+
+                entry.x = b.min.x;
+                entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
+                entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
+            }
+        }
+        else if (r.pos.x < b.min.x || r.pos.x > b.max.x)
+        {
+            return false;
+        }
+    }
+    else // r.dir.x < 0
+    {
+        T d1 = b.min.x - r.pos.x;
+        T d2 = b.max.x - r.pos.x;
+
+        if (r.dir.x < -1 || (abs (d1) < -TMAX * r.dir.x && abs (d2) < -TMAX * r.dir.x))
+        {
+            T t1 = d1 / r.dir.x;
+            T t2 = d2 / r.dir.x;
+
+            if (tBackMin > t1)
+            {
+                tBackMin = t1;
+
+                exit.x = b.min.x;
+                exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
+                exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
+            }
+
+            if (tFrontMax < t2)
+            {
+                tFrontMax = t2;
+
+                entry.x = b.max.x;
+                entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
+                entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
+            }
+        }
+        else if (r.pos.x < b.min.x || r.pos.x > b.max.x)
+        {
+            return false;
+        }
+    }
+
+    //
+    // Minimum and maximum Y sides.
+    //
+
+    if (r.dir.y >= 0)
+    {
+        T d1 = b.max.y - r.pos.y;
+        T d2 = b.min.y - r.pos.y;
+
+        if (r.dir.y > 1 || (abs (d1) < TMAX * r.dir.y && abs (d2) < TMAX * r.dir.y))
+        {
+            T t1 = d1 / r.dir.y;
+            T t2 = d2 / r.dir.y;
+
+            if (tBackMin > t1)
+            {
+                tBackMin = t1;
+
+                exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
+                exit.y = b.max.y;
+                exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
+            }
+
+            if (tFrontMax < t2)
+            {
+                tFrontMax = t2;
+
+                entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
+                entry.y = b.min.y;
+                entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
+            }
+        }
+        else if (r.pos.y < b.min.y || r.pos.y > b.max.y)
+        {
+            return false;
+        }
+    }
+    else // r.dir.y < 0
+    {
+        T d1 = b.min.y - r.pos.y;
+        T d2 = b.max.y - r.pos.y;
+
+        if (r.dir.y < -1 || (abs (d1) < -TMAX * r.dir.y && abs (d2) < -TMAX * r.dir.y))
+        {
+            T t1 = d1 / r.dir.y;
+            T t2 = d2 / r.dir.y;
+
+            if (tBackMin > t1)
+            {
+                tBackMin = t1;
+
+                exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
+                exit.y = b.min.y;
+                exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
+            }
+
+            if (tFrontMax < t2)
+            {
+                tFrontMax = t2;
+
+                entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
+                entry.y = b.max.y;
+                entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
+            }
+        }
+        else if (r.pos.y < b.min.y || r.pos.y > b.max.y)
+        {
+            return false;
+        }
+    }
+
+    //
+    // Minimum and maximum Z sides.
+    //
+
+    if (r.dir.z >= 0)
+    {
+        T d1 = b.max.z - r.pos.z;
+        T d2 = b.min.z - r.pos.z;
+
+        if (r.dir.z > 1 || (abs (d1) < TMAX * r.dir.z && abs (d2) < TMAX * r.dir.z))
+        {
+            T t1 = d1 / r.dir.z;
+            T t2 = d2 / r.dir.z;
+
+            if (tBackMin > t1)
+            {
+                tBackMin = t1;
+
+                exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
+                exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
+                exit.z = b.max.z;
+            }
+
+            if (tFrontMax < t2)
+            {
+                tFrontMax = t2;
+
+                entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
+                entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
+                entry.z = b.min.z;
+            }
+        }
+        else if (r.pos.z < b.min.z || r.pos.z > b.max.z)
+        {
+            return false;
+        }
+    }
+    else // r.dir.z < 0
+    {
+        T d1 = b.min.z - r.pos.z;
+        T d2 = b.max.z - r.pos.z;
+
+        if (r.dir.z < -1 || (abs (d1) < -TMAX * r.dir.z && abs (d2) < -TMAX * r.dir.z))
+        {
+            T t1 = d1 / r.dir.z;
+            T t2 = d2 / r.dir.z;
+
+            if (tBackMin > t1)
+            {
+                tBackMin = t1;
+
+                exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
+                exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
+                exit.z = b.min.z;
+            }
+
+            if (tFrontMax < t2)
+            {
+                tFrontMax = t2;
+
+                entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
+                entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
+                entry.z = b.max.z;
+            }
+        }
+        else if (r.pos.z < b.min.z || r.pos.z > b.max.z)
+        {
+            return false;
+        }
+    }
+
+    return tFrontMax <= tBackMin;
+}
+
+///
+/// Intersect a ray, `r`, with a 3D box, `b, and compute the intersection
+/// point, returned in `ip`.
+///
+/// The intersection point is
+/// - the ray's origin if the ray starts inside the box
+/// - a point on one of the faces of the box if the ray
+///   starts outside the box
+/// - undefined when intersect() returns false
+///
+/// @return
+/// - true if the ray starts inside the box or if the
+///   ray starts outside and intersects the box
+/// - false if the ray starts outside the box and intersects it,
+///   but the intersection is behind the ray's origin.
+/// - false if the ray starts outside and does not intersect it
+///
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool
+intersects (const Box<Vec3<T>>& b, const Line3<T>& r, Vec3<T>& ip) IMATH_NOEXCEPT
+{
+    if (b.isEmpty())
+    {
+        //
+        // No ray intersects an empty box
+        //
+
+        return false;
+    }
+
+    if (b.intersects (r.pos))
+    {
+        //
+        // The ray starts inside the box
+        //
+
+        ip = r.pos;
+        return true;
+    }
+
+    //
+    // The ray starts outside the box.  Between one and three "frontfacing"
+    // sides of the box are oriented towards the ray, and between one and
+    // three "backfacing" sides are oriented away from the ray.
+    // We intersect the ray with the planes that contain the sides of the
+    // box, and compare the distances between ray's origin and the ray-plane
+    // intersections.
+    // The ray intersects the box if the most distant frontfacing intersection
+    // is nearer than the nearest backfacing intersection.  If the ray does
+    // intersect the box, then the most distant frontfacing ray-plane
+    // intersection is the ray-box intersection.
+    //
+
+    const T TMAX = std::numeric_limits<T>::max();
+
+    T tFrontMax = -1;
+    T tBackMin  = TMAX;
+
+    //
+    // Minimum and maximum X sides.
+    //
+
+    if (r.dir.x > 0)
+    {
+        if (r.pos.x > b.max.x)
+            return false;
+
+        T d = b.max.x - r.pos.x;
+
+        if (r.dir.x > 1 || d < TMAX * r.dir.x)
+        {
+            T t = d / r.dir.x;
+
+            if (tBackMin > t)
+                tBackMin = t;
+        }
+
+        if (r.pos.x <= b.min.x)
+        {
+            T d = b.min.x - r.pos.x;
+            T t = (r.dir.x > 1 || d < TMAX * r.dir.x) ? d / r.dir.x : TMAX;
+
+            if (tFrontMax < t)
+            {
+                tFrontMax = t;
+
+                ip.x = b.min.x;
+                ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
+                ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
+            }
+        }
+    }
+    else if (r.dir.x < 0)
+    {
+        if (r.pos.x < b.min.x)
+            return false;
+
+        T d = b.min.x - r.pos.x;
+
+        if (r.dir.x < -1 || d > TMAX * r.dir.x)
+        {
+            T t = d / r.dir.x;
+
+            if (tBackMin > t)
+                tBackMin = t;
+        }
+
+        if (r.pos.x >= b.max.x)
+        {
+            T d = b.max.x - r.pos.x;
+            T t = (r.dir.x < -1 || d > TMAX * r.dir.x) ? d / r.dir.x : TMAX;
+
+            if (tFrontMax < t)
+            {
+                tFrontMax = t;
+
+                ip.x = b.max.x;
+                ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
+                ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
+            }
+        }
+    }
+    else // r.dir.x == 0
+    {
+        if (r.pos.x < b.min.x || r.pos.x > b.max.x)
+            return false;
+    }
+
+    //
+    // Minimum and maximum Y sides.
+    //
+
+    if (r.dir.y > 0)
+    {
+        if (r.pos.y > b.max.y)
+            return false;
+
+        T d = b.max.y - r.pos.y;
+
+        if (r.dir.y > 1 || d < TMAX * r.dir.y)
+        {
+            T t = d / r.dir.y;
+
+            if (tBackMin > t)
+                tBackMin = t;
+        }
+
+        if (r.pos.y <= b.min.y)
+        {
+            T d = b.min.y - r.pos.y;
+            T t = (r.dir.y > 1 || d < TMAX * r.dir.y) ? d / r.dir.y : TMAX;
+
+            if (tFrontMax < t)
+            {
+                tFrontMax = t;
+
+                ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
+                ip.y = b.min.y;
+                ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
+            }
+        }
+    }
+    else if (r.dir.y < 0)
+    {
+        if (r.pos.y < b.min.y)
+            return false;
+
+        T d = b.min.y - r.pos.y;
+
+        if (r.dir.y < -1 || d > TMAX * r.dir.y)
+        {
+            T t = d / r.dir.y;
+
+            if (tBackMin > t)
+                tBackMin = t;
+        }
+
+        if (r.pos.y >= b.max.y)
+        {
+            T d = b.max.y - r.pos.y;
+            T t = (r.dir.y < -1 || d > TMAX * r.dir.y) ? d / r.dir.y : TMAX;
+
+            if (tFrontMax < t)
+            {
+                tFrontMax = t;
+
+                ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
+                ip.y = b.max.y;
+                ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
+            }
+        }
+    }
+    else // r.dir.y == 0
+    {
+        if (r.pos.y < b.min.y || r.pos.y > b.max.y)
+            return false;
+    }
+
+    //
+    // Minimum and maximum Z sides.
+    //
+
+    if (r.dir.z > 0)
+    {
+        if (r.pos.z > b.max.z)
+            return false;
+
+        T d = b.max.z - r.pos.z;
+
+        if (r.dir.z > 1 || d < TMAX * r.dir.z)
+        {
+            T t = d / r.dir.z;
+
+            if (tBackMin > t)
+                tBackMin = t;
+        }
+
+        if (r.pos.z <= b.min.z)
+        {
+            T d = b.min.z - r.pos.z;
+            T t = (r.dir.z > 1 || d < TMAX * r.dir.z) ? d / r.dir.z : TMAX;
+
+            if (tFrontMax < t)
+            {
+                tFrontMax = t;
+
+                ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
+                ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
+                ip.z = b.min.z;
+            }
+        }
+    }
+    else if (r.dir.z < 0)
+    {
+        if (r.pos.z < b.min.z)
+            return false;
+
+        T d = b.min.z - r.pos.z;
+
+        if (r.dir.z < -1 || d > TMAX * r.dir.z)
+        {
+            T t = d / r.dir.z;
+
+            if (tBackMin > t)
+                tBackMin = t;
+        }
+
+        if (r.pos.z >= b.max.z)
+        {
+            T d = b.max.z - r.pos.z;
+            T t = (r.dir.z < -1 || d > TMAX * r.dir.z) ? d / r.dir.z : TMAX;
+
+            if (tFrontMax < t)
+            {
+                tFrontMax = t;
+
+                ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
+                ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
+                ip.z = b.max.z;
+            }
+        }
+    }
+    else // r.dir.z == 0
+    {
+        if (r.pos.z < b.min.z || r.pos.z > b.max.z)
+            return false;
+    }
+
+    return tFrontMax <= tBackMin;
+}
+
+///
+/// Return whether the the ray `ray` interects the 3D box `box`.
+///
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool
+intersects (const Box<Vec3<T>>& box, const Line3<T>& ray) IMATH_NOEXCEPT
+{
+    Vec3<T> ignored;
+    return intersects (box, ray, ignored);
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHBOXALGO_H
diff --git a/src/Imath/ImathColor.h b/src/Imath/ImathColor.h
new file mode 100644 (file)
index 0000000..9059942
--- /dev/null
@@ -0,0 +1,739 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// 3-channel and 4-channel color representations
+//
+
+#ifndef INCLUDED_IMATHCOLOR_H
+#define INCLUDED_IMATHCOLOR_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include "ImathVec.h"
+#include "half.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// 3-channel color class that inherits from Vec3.
+///
+/// This class does not impose interpretation on the channels, which
+/// can represent either rgb or hsv color values.
+///
+/// Note: because Color3 inherits from Vec3, its member fields are
+/// called `x`, `y`, and `z`.
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Color3 : public Vec3<T>
+{
+  public:
+
+    /// @{
+    /// @name Constructors and Assignemt
+
+    /// No initialization by default
+    IMATH_HOSTDEVICE Color3() IMATH_NOEXCEPT;                         
+
+    /// Initialize to (a a a)
+    IMATH_HOSTDEVICE constexpr explicit Color3 (T a) IMATH_NOEXCEPT;  
+
+    /// Initialize to (a b c)
+    IMATH_HOSTDEVICE constexpr Color3 (T a, T b, T c) IMATH_NOEXCEPT; 
+
+    /// Construct from Color3
+    IMATH_HOSTDEVICE constexpr Color3 (const Color3& c) IMATH_NOEXCEPT; 
+
+    /// Construct from Vec3
+    template <class S> IMATH_HOSTDEVICE constexpr Color3 (const Vec3<S>& v) IMATH_NOEXCEPT; 
+
+    /// Destructor
+    ~Color3() = default;
+
+    /// Component-wise assignment
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color3& operator= (const Color3& c) IMATH_NOEXCEPT; 
+
+    /// @}
+    
+    /// @{
+    /// @name Arithmetic
+    
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color3& operator+= (const Color3& c) IMATH_NOEXCEPT; 
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE constexpr Color3 operator+ (const Color3& c) const IMATH_NOEXCEPT;  
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color3& operator-= (const Color3& c) IMATH_NOEXCEPT; 
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE constexpr Color3 operator- (const Color3& c) const IMATH_NOEXCEPT; 
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE constexpr Color3 operator-() const IMATH_NOEXCEPT; 
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color3& negate() IMATH_NOEXCEPT; 
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color3& operator*= (const Color3& c) IMATH_NOEXCEPT; 
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color3& operator*= (T a) IMATH_NOEXCEPT;  
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Color3 operator* (const Color3& c) const IMATH_NOEXCEPT;  
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Color3 operator* (T a) const IMATH_NOEXCEPT;  
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color3& operator/= (const Color3& c) IMATH_NOEXCEPT; 
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color3& operator/= (T a) IMATH_NOEXCEPT; 
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Color3 operator/ (const Color3& c) const IMATH_NOEXCEPT;  
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Color3 operator/ (T a) const IMATH_NOEXCEPT;  
+
+    /// @}
+};
+
+///
+/// A 4-channel color class: 3 channels plus alpha. 
+///
+/// For convenience, the fields are named `r`, `g`, and `b`, although
+/// this class does not impose interpretation on the channels, which
+/// can represent either rgb or hsv color values.
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Color4
+{
+  public:
+
+    /// @{
+    /// @name Direct access to elements
+
+    T r, g, b, a;
+
+    /// @}
+
+    /// @{
+    /// @name Constructors and Assignment
+
+    /// No initialization by default
+    IMATH_HOSTDEVICE Color4() IMATH_NOEXCEPT;                                      
+
+    /// Initialize to `(a a a a)`
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 explicit Color4 (T a) IMATH_NOEXCEPT;       
+
+    /// Initialize to `(a b c d)`
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Color4 (T a, T b, T c, T d) IMATH_NOEXCEPT; 
+
+    /// Construct from Color4
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Color4 (const Color4& v) IMATH_NOEXCEPT; 
+
+    /// Construct from Color4
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Color4 (const Color4<S>& v) IMATH_NOEXCEPT; 
+
+    /// Destructor
+    ~Color4() = default;
+
+    /// Assignment
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color4& operator= (const Color4& v) IMATH_NOEXCEPT; 
+
+    /// Component-wise value
+    IMATH_HOSTDEVICE T& operator[] (int i) IMATH_NOEXCEPT; 
+
+    /// Component-wise value
+    IMATH_HOSTDEVICE const T& operator[] (int i) const IMATH_NOEXCEPT; 
+
+    /// @}
+    
+    /// @{
+    /// @name Arithmetic and Comparison
+    
+    /// Equality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator== (const Color4<S>& v) const IMATH_NOEXCEPT; 
+
+    /// Inequality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator!= (const Color4<S>& v) const IMATH_NOEXCEPT; 
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color4& operator+= (const Color4& v) IMATH_NOEXCEPT; 
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE constexpr Color4 operator+ (const Color4& v) const IMATH_NOEXCEPT; 
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color4& operator-= (const Color4& v) IMATH_NOEXCEPT; 
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE constexpr Color4 operator- (const Color4& v) const IMATH_NOEXCEPT; 
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE constexpr Color4 operator-() const IMATH_NOEXCEPT; 
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color4& negate() IMATH_NOEXCEPT; 
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color4& operator*= (const Color4& v) IMATH_NOEXCEPT; 
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color4& operator*= (T a) IMATH_NOEXCEPT; 
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Color4 operator* (const Color4& v) const IMATH_NOEXCEPT; 
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Color4 operator* (T a) const IMATH_NOEXCEPT; 
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color4& operator/= (const Color4& v) IMATH_NOEXCEPT; 
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Color4& operator/= (T a) IMATH_NOEXCEPT; 
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Color4 operator/ (const Color4& v) const IMATH_NOEXCEPT; 
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Color4 operator/ (T a) const IMATH_NOEXCEPT; 
+
+    /// @}
+
+    /// @{
+    /// @name Numeric Limits
+    
+    /// Number of dimensions (channels), i.e. 4 for a Color4
+    IMATH_HOSTDEVICE constexpr static unsigned int dimensions() IMATH_NOEXCEPT { return 4; }
+
+    /// Largest possible negative value
+    IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
+
+    /// Largest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
+
+    /// Smallest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
+
+    /// Smallest possible e for which 1+e != 1
+    IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
+
+    /// @}
+    
+    /// The base type: In templates that accept a parameter `V` (could
+    /// be a Color4), you can refer to `T` as `V::BaseType`
+    typedef T BaseType;
+
+    /// @{
+    /// @name Compatibilty with Sb
+
+    /// Set the value
+    template <class S> IMATH_HOSTDEVICE void setValue (S a, S b, S c, S d) IMATH_NOEXCEPT; 
+
+    /// Set the value
+    template <class S> IMATH_HOSTDEVICE void setValue (const Color4<S>& v) IMATH_NOEXCEPT; 
+
+    /// Return the value
+    template <class S> IMATH_HOSTDEVICE void getValue (S& a, S& b, S& c, S& d) const IMATH_NOEXCEPT; 
+
+    /// Return the value
+    template <class S> IMATH_HOSTDEVICE void getValue (Color4<S>& v) const IMATH_NOEXCEPT; 
+
+    /// Return raw pointer to the value
+    IMATH_HOSTDEVICE T* getValue() IMATH_NOEXCEPT; 
+
+    /// Return raw pointer to the value
+    IMATH_HOSTDEVICE const T* getValue() const IMATH_NOEXCEPT; 
+
+    /// @}
+};
+
+/// Stream output, as "(r g b a)"
+template <class T> std::ostream& operator<< (std::ostream& s, const Color4<T>& v);
+
+/// Reverse multiplication: S * Color4
+template <class S, class T>
+IMATH_HOSTDEVICE constexpr Color4<T> operator* (S a, const Color4<T>& v) IMATH_NOEXCEPT;
+
+/// 3 float channels
+typedef Color3<float> Color3f;
+
+/// 3 half channels
+typedef Color3<half> Color3h;
+
+/// 3 8-bit integer channels
+typedef Color3<unsigned char> Color3c;
+
+/// 3 half channels
+typedef Color3<half> C3h;
+
+/// 3 float channels
+typedef Color3<float> C3f;
+
+/// 3 8-bit integer channels
+typedef Color3<unsigned char> C3c;
+
+/// 4 float channels
+typedef Color4<float> Color4f;
+
+/// 4 half channels
+typedef Color4<half> Color4h;
+
+/// 4 8-bit integer channels
+typedef Color4<unsigned char> Color4c;
+
+/// 4 float channels
+typedef Color4<float> C4f;
+
+/// 4 half channels
+typedef Color4<half> C4h;
+
+/// 4 8-bit integer channels
+typedef Color4<unsigned char> C4c;
+
+/// Packed 32-bit integer
+typedef unsigned int PackedColor;
+
+//
+// Implementation of Color3
+//
+
+template <class T> IMATH_HOSTDEVICE inline Color3<T>::Color3() IMATH_NOEXCEPT : Vec3<T>()
+{
+    // empty
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Color3<T>::Color3 (T a) IMATH_NOEXCEPT : Vec3<T> (a)
+{
+    // empty
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Color3<T>::Color3 (T a, T b, T c) IMATH_NOEXCEPT : Vec3<T> (a, b, c)
+{
+    // empty
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Color3<T>::Color3 (const Color3& c) IMATH_NOEXCEPT : Vec3<T> (c)
+{
+    // empty
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline Color3<T>::Color3 (const Vec3<S>& v) IMATH_NOEXCEPT : Vec3<T> (v)
+{
+    //empty
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color3<T>&
+Color3<T>::operator= (const Color3& c) IMATH_NOEXCEPT
+{
+    *((Vec3<T>*) this) = c;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color3<T>&
+Color3<T>::operator+= (const Color3& c) IMATH_NOEXCEPT
+{
+    *((Vec3<T>*) this) += c;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color3<T>
+Color3<T>::operator+ (const Color3& c) const IMATH_NOEXCEPT
+{
+    return Color3 (*(Vec3<T>*) this + (const Vec3<T>&) c);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color3<T>&
+Color3<T>::operator-= (const Color3& c) IMATH_NOEXCEPT
+{
+    *((Vec3<T>*) this) -= c;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color3<T>
+Color3<T>::operator- (const Color3& c) const IMATH_NOEXCEPT
+{
+    return Color3 (*(Vec3<T>*) this - (const Vec3<T>&) c);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color3<T>
+Color3<T>::operator-() const IMATH_NOEXCEPT
+{
+    return Color3 (-(*(Vec3<T>*) this));
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color3<T>&
+Color3<T>::negate() IMATH_NOEXCEPT
+{
+    ((Vec3<T>*) this)->negate();
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color3<T>&
+Color3<T>::operator*= (const Color3& c) IMATH_NOEXCEPT
+{
+    *((Vec3<T>*) this) *= c;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color3<T>&
+Color3<T>::operator*= (T a) IMATH_NOEXCEPT
+{
+    *((Vec3<T>*) this) *= a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color3<T>
+Color3<T>::operator* (const Color3& c) const IMATH_NOEXCEPT
+{
+    return Color3 (*(Vec3<T>*) this * (const Vec3<T>&) c);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color3<T>
+Color3<T>::operator* (T a) const IMATH_NOEXCEPT
+{
+    return Color3 (*(Vec3<T>*) this * a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color3<T>&
+Color3<T>::operator/= (const Color3& c) IMATH_NOEXCEPT
+{
+    *((Vec3<T>*) this) /= c;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color3<T>&
+Color3<T>::operator/= (T a) IMATH_NOEXCEPT
+{
+    *((Vec3<T>*) this) /= a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color3<T>
+Color3<T>::operator/ (const Color3& c) const IMATH_NOEXCEPT
+{
+    return Color3 (*(Vec3<T>*) this / (const Vec3<T>&) c);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color3<T>
+Color3<T>::operator/ (T a) const IMATH_NOEXCEPT
+{
+    return Color3 (*(Vec3<T>*) this / a);
+}
+
+//
+// Implementation of Color4
+//
+
+template <class T>
+IMATH_HOSTDEVICE inline T&
+Color4<T>::operator[] (int i) IMATH_NOEXCEPT
+{
+    return (&r)[i];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const T&
+Color4<T>::operator[] (int i) const IMATH_NOEXCEPT
+{
+    return (&r)[i];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Color4<T>::Color4() IMATH_NOEXCEPT
+{
+    // empty
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Color4<T>::Color4 (T x) IMATH_NOEXCEPT
+{
+    r = g = b = a = x;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Color4<T>::Color4 (T x, T y, T z, T w) IMATH_NOEXCEPT
+{
+    r = x;
+    g = y;
+    b = z;
+    a = w;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Color4<T>::Color4 (const Color4& v) IMATH_NOEXCEPT
+{
+    r = v.r;
+    g = v.g;
+    b = v.b;
+    a = v.a;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Color4<T>::Color4 (const Color4<S>& v) IMATH_NOEXCEPT
+{
+    r = T (v.r);
+    g = T (v.g);
+    b = T (v.b);
+    a = T (v.a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color4<T>&
+Color4<T>::operator= (const Color4& v) IMATH_NOEXCEPT
+{
+    r = v.r;
+    g = v.g;
+    b = v.b;
+    a = v.a;
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Color4<T>::setValue (S x, S y, S z, S w) IMATH_NOEXCEPT
+{
+    r = T (x);
+    g = T (y);
+    b = T (z);
+    a = T (w);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Color4<T>::setValue (const Color4<S>& v) IMATH_NOEXCEPT
+{
+    r = T (v.r);
+    g = T (v.g);
+    b = T (v.b);
+    a = T (v.a);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Color4<T>::getValue (S& x, S& y, S& z, S& w) const IMATH_NOEXCEPT
+{
+    x = S (r);
+    y = S (g);
+    z = S (b);
+    w = S (a);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Color4<T>::getValue (Color4<S>& v) const IMATH_NOEXCEPT
+{
+    v.r = S (r);
+    v.g = S (g);
+    v.b = S (b);
+    v.a = S (a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline T*
+Color4<T>::getValue() IMATH_NOEXCEPT
+{
+    return (T*) &r;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const T*
+Color4<T>::getValue() const IMATH_NOEXCEPT
+{
+    return (const T*) &r;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Color4<T>::operator== (const Color4<S>& v) const IMATH_NOEXCEPT
+{
+    return r == v.r && g == v.g && b == v.b && a == v.a;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Color4<T>::operator!= (const Color4<S>& v) const IMATH_NOEXCEPT
+{
+    return r != v.r || g != v.g || b != v.b || a != v.a;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color4<T>&
+Color4<T>::operator+= (const Color4& v) IMATH_NOEXCEPT
+{
+    r += v.r;
+    g += v.g;
+    b += v.b;
+    a += v.a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color4<T>
+Color4<T>::operator+ (const Color4& v) const IMATH_NOEXCEPT
+{
+    return Color4 (r + v.r, g + v.g, b + v.b, a + v.a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color4<T>&
+Color4<T>::operator-= (const Color4& v) IMATH_NOEXCEPT
+{
+    r -= v.r;
+    g -= v.g;
+    b -= v.b;
+    a -= v.a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color4<T>
+Color4<T>::operator- (const Color4& v) const IMATH_NOEXCEPT
+{
+    return Color4 (r - v.r, g - v.g, b - v.b, a - v.a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color4<T>
+Color4<T>::operator-() const IMATH_NOEXCEPT
+{
+    return Color4 (-r, -g, -b, -a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color4<T>&
+Color4<T>::negate() IMATH_NOEXCEPT
+{
+    r = -r;
+    g = -g;
+    b = -b;
+    a = -a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color4<T>&
+Color4<T>::operator*= (const Color4& v) IMATH_NOEXCEPT
+{
+    r *= v.r;
+    g *= v.g;
+    b *= v.b;
+    a *= v.a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color4<T>&
+Color4<T>::operator*= (T x) IMATH_NOEXCEPT
+{
+    r *= x;
+    g *= x;
+    b *= x;
+    a *= x;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color4<T>
+Color4<T>::operator* (const Color4& v) const IMATH_NOEXCEPT
+{
+    return Color4 (r * v.r, g * v.g, b * v.b, a * v.a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color4<T>
+Color4<T>::operator* (T x) const IMATH_NOEXCEPT
+{
+    return Color4 (r * x, g * x, b * x, a * x);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color4<T>&
+Color4<T>::operator/= (const Color4& v) IMATH_NOEXCEPT
+{
+    r /= v.r;
+    g /= v.g;
+    b /= v.b;
+    a /= v.a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Color4<T>&
+Color4<T>::operator/= (T x) IMATH_NOEXCEPT
+{
+    r /= x;
+    g /= x;
+    b /= x;
+    a /= x;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color4<T>
+Color4<T>::operator/ (const Color4& v) const IMATH_NOEXCEPT
+{
+    return Color4 (r / v.r, g / v.g, b / v.b, a / v.a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Color4<T>
+Color4<T>::operator/ (T x) const IMATH_NOEXCEPT
+{
+    return Color4 (r / x, g / x, b / x, a / x);
+}
+
+template <class T>
+std::ostream&
+operator<< (std::ostream& s, const Color4<T>& v)
+{
+    return s << '(' << v.r << ' ' << v.g << ' ' << v.b << ' ' << v.a << ')';
+}
+
+//
+// Implementation of reverse multiplication
+//
+
+template <class S, class T>
+IMATH_HOSTDEVICE constexpr inline Color4<T>
+operator* (S x, const Color4<T>& v) IMATH_NOEXCEPT
+{
+    return Color4<T> (x * v.r, x * v.g, x * v.b, x * v.a);
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHCOLOR_H
diff --git a/src/Imath/ImathColorAlgo.cpp b/src/Imath/ImathColorAlgo.cpp
new file mode 100644 (file)
index 0000000..ddc26ef
--- /dev/null
@@ -0,0 +1,202 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+///
+/// @file  ImathColorAlgo.cpp
+///
+/// @brief Implementation of non-template items declared in ImathColorAlgo.h
+///
+
+#include "ImathColorAlgo.h"
+
+IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+Vec3<double>
+hsv2rgb_d (const Vec3<double>& hsv) IMATH_NOEXCEPT
+{
+    double hue = hsv.x;
+    double sat = hsv.y;
+    double val = hsv.z;
+
+    double x = 0.0, y = 0.0, z = 0.0;
+
+    if (hue == 1)
+        hue = 0;
+    else
+        hue *= 6;
+
+    int i    = int (std::floor (hue));
+    double f = hue - i;
+    double p = val * (1 - sat);
+    double q = val * (1 - (sat * f));
+    double t = val * (1 - (sat * (1 - f)));
+
+    switch (i)
+    {
+    case 0:
+        x = val;
+        y = t;
+        z = p;
+        break;
+    case 1:
+        x = q;
+        y = val;
+        z = p;
+        break;
+    case 2:
+        x = p;
+        y = val;
+        z = t;
+        break;
+    case 3:
+        x = p;
+        y = q;
+        z = val;
+        break;
+    case 4:
+        x = t;
+        y = p;
+        z = val;
+        break;
+    case 5:
+        x = val;
+        y = p;
+        z = q;
+        break;
+    }
+
+    return Vec3<double> (x, y, z);
+}
+
+Color4<double>
+hsv2rgb_d (const Color4<double>& hsv) IMATH_NOEXCEPT
+{
+    double hue = hsv.r;
+    double sat = hsv.g;
+    double val = hsv.b;
+
+    double r = 0.0, g = 0.0, b = 0.0;
+
+    if (hue == 1)
+        hue = 0;
+    else
+        hue *= 6;
+
+    int i    = int (std::floor (hue));
+    double f = hue - i;
+    double p = val * (1 - sat);
+    double q = val * (1 - (sat * f));
+    double t = val * (1 - (sat * (1 - f)));
+
+    switch (i)
+    {
+    case 0:
+        r = val;
+        g = t;
+        b = p;
+        break;
+    case 1:
+        r = q;
+        g = val;
+        b = p;
+        break;
+    case 2:
+        r = p;
+        g = val;
+        b = t;
+        break;
+    case 3:
+        r = p;
+        g = q;
+        b = val;
+        break;
+    case 4:
+        r = t;
+        g = p;
+        b = val;
+        break;
+    case 5:
+        r = val;
+        g = p;
+        b = q;
+        break;
+    }
+
+    return Color4<double> (r, g, b, hsv.a);
+}
+
+Vec3<double>
+rgb2hsv_d (const Vec3<double>& c) IMATH_NOEXCEPT
+{
+    const double& x = c.x;
+    const double& y = c.y;
+    const double& z = c.z;
+
+    double max   = (x > y) ? ((x > z) ? x : z) : ((y > z) ? y : z);
+    double min   = (x < y) ? ((x < z) ? x : z) : ((y < z) ? y : z);
+    double range = max - min;
+    double val   = max;
+    double sat   = 0;
+    double hue   = 0;
+
+    if (max != 0)
+        sat = range / max;
+
+    if (sat != 0)
+    {
+        double h;
+
+        if (x == max)
+            h = (y - z) / range;
+        else if (y == max)
+            h = 2 + (z - x) / range;
+        else
+            h = 4 + (x - y) / range;
+
+        hue = h / 6.;
+
+        if (hue < 0.)
+            hue += 1.0;
+    }
+    return Vec3<double> (hue, sat, val);
+}
+
+Color4<double>
+rgb2hsv_d (const Color4<double>& c) IMATH_NOEXCEPT
+{
+    const double& r = c.r;
+    const double& g = c.g;
+    const double& b = c.b;
+
+    double max   = (r > g) ? ((r > b) ? r : b) : ((g > b) ? g : b);
+    double min   = (r < g) ? ((r < b) ? r : b) : ((g < b) ? g : b);
+    double range = max - min;
+    double val   = max;
+    double sat   = 0;
+    double hue   = 0;
+
+    if (max != 0)
+        sat = range / max;
+
+    if (sat != 0)
+    {
+        double h;
+
+        if (r == max)
+            h = (g - b) / range;
+        else if (g == max)
+            h = 2 + (b - r) / range;
+        else
+            h = 4 + (r - g) / range;
+
+        hue = h / 6.;
+
+        if (hue < 0.)
+            hue += 1.0;
+    }
+    return Color4<double> (hue, sat, val, c.a);
+}
+
+IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT
diff --git a/src/Imath/ImathColorAlgo.h b/src/Imath/ImathColorAlgo.h
new file mode 100644 (file)
index 0000000..cfb08c5
--- /dev/null
@@ -0,0 +1,256 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Color conversion functions and general color algorithms
+//
+
+#ifndef INCLUDED_IMATHCOLORALGO_H
+#define INCLUDED_IMATHCOLORALGO_H
+
+#include "ImathNamespace.h"
+#include "ImathExport.h"
+
+#include "ImathColor.h"
+#include "ImathMath.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//
+// Non-templated helper routines for color conversion.
+// These routines eliminate type warnings under g++.
+//
+
+///
+/// Convert 3-channel hsv to rgb. Non-templated helper routine.
+IMATH_EXPORT Vec3<double> hsv2rgb_d (const Vec3<double>& hsv) IMATH_NOEXCEPT;
+
+///
+/// Convert 4-channel hsv to rgb (with alpha). Non-templated helper routine.
+IMATH_EXPORT Color4<double> hsv2rgb_d (const Color4<double>& hsv) IMATH_NOEXCEPT;
+
+///
+/// Convert 3-channel rgb to hsv. Non-templated helper routine.
+IMATH_EXPORT Vec3<double> rgb2hsv_d (const Vec3<double>& rgb) IMATH_NOEXCEPT;
+
+///
+/// Convert 4-channel rgb to hsv. Non-templated helper routine.
+IMATH_EXPORT Color4<double> rgb2hsv_d (const Color4<double>& rgb) IMATH_NOEXCEPT;
+
+///
+/// Convert 3-channel hsv to rgb.
+///
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3<T>
+hsv2rgb (const Vec3<T>& hsv) IMATH_NOEXCEPT
+{
+    if (std::numeric_limits<T>::is_integer)
+    {
+        Vec3<double> v = Vec3<double> (hsv.x / double (std::numeric_limits<T>::max()),
+                                       hsv.y / double (std::numeric_limits<T>::max()),
+                                       hsv.z / double (std::numeric_limits<T>::max()));
+        Vec3<double> c = hsv2rgb_d (v);
+        return Vec3<T> ((T) (c.x * std::numeric_limits<T>::max()),
+                        (T) (c.y * std::numeric_limits<T>::max()),
+                        (T) (c.z * std::numeric_limits<T>::max()));
+    }
+    else
+    {
+        Vec3<double> v = Vec3<double> (hsv.x, hsv.y, hsv.z);
+        Vec3<double> c = hsv2rgb_d (v);
+        return Vec3<T> ((T) c.x, (T) c.y, (T) c.z);
+    }
+}
+
+///
+/// Convert 4-channel hsv to rgb (with alpha).
+///
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Color4<T>
+hsv2rgb (const Color4<T>& hsv) IMATH_NOEXCEPT
+{
+    if (std::numeric_limits<T>::is_integer)
+    {
+        Color4<double> v = Color4<double> (hsv.r / float (std::numeric_limits<T>::max()),
+                                           hsv.g / float (std::numeric_limits<T>::max()),
+                                           hsv.b / float (std::numeric_limits<T>::max()),
+                                           hsv.a / float (std::numeric_limits<T>::max()));
+        Color4<double> c = hsv2rgb_d (v);
+        return Color4<T> ((T) (c.r * std::numeric_limits<T>::max()),
+                          (T) (c.g * std::numeric_limits<T>::max()),
+                          (T) (c.b * std::numeric_limits<T>::max()),
+                          (T) (c.a * std::numeric_limits<T>::max()));
+    }
+    else
+    {
+        Color4<double> v = Color4<double> (hsv.r, hsv.g, hsv.b, hsv.a);
+        Color4<double> c = hsv2rgb_d (v);
+        return Color4<T> ((T) c.r, (T) c.g, (T) c.b, (T) c.a);
+    }
+}
+
+///
+/// Convert 3-channel rgb to hsv.
+///
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3<T>
+rgb2hsv (const Vec3<T>& rgb) IMATH_NOEXCEPT
+{
+    if (std::numeric_limits<T>::is_integer)
+    {
+        Vec3<double> v = Vec3<double> (rgb.x / double (std::numeric_limits<T>::max()),
+                                       rgb.y / double (std::numeric_limits<T>::max()),
+                                       rgb.z / double (std::numeric_limits<T>::max()));
+        Vec3<double> c = rgb2hsv_d (v);
+        return Vec3<T> ((T) (c.x * std::numeric_limits<T>::max()),
+                        (T) (c.y * std::numeric_limits<T>::max()),
+                        (T) (c.z * std::numeric_limits<T>::max()));
+    }
+    else
+    {
+        Vec3<double> v = Vec3<double> (rgb.x, rgb.y, rgb.z);
+        Vec3<double> c = rgb2hsv_d (v);
+        return Vec3<T> ((T) c.x, (T) c.y, (T) c.z);
+    }
+}
+
+///
+/// Convert 4-channel rgb to hsv (with alpha).
+///
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Color4<T>
+rgb2hsv (const Color4<T>& rgb) IMATH_NOEXCEPT
+{
+    if (std::numeric_limits<T>::is_integer)
+    {
+        Color4<double> v = Color4<double> (rgb.r / float (std::numeric_limits<T>::max()),
+                                           rgb.g / float (std::numeric_limits<T>::max()),
+                                           rgb.b / float (std::numeric_limits<T>::max()),
+                                           rgb.a / float (std::numeric_limits<T>::max()));
+        Color4<double> c = rgb2hsv_d (v);
+        return Color4<T> ((T) (c.r * std::numeric_limits<T>::max()),
+                          (T) (c.g * std::numeric_limits<T>::max()),
+                          (T) (c.b * std::numeric_limits<T>::max()),
+                          (T) (c.a * std::numeric_limits<T>::max()));
+    }
+    else
+    {
+        Color4<double> v = Color4<double> (rgb.r, rgb.g, rgb.b, rgb.a);
+        Color4<double> c = rgb2hsv_d (v);
+        return Color4<T> ((T) c.r, (T) c.g, (T) c.b, (T) c.a);
+    }
+}
+
+///
+/// Convert 3-channel rgb to PackedColor
+///
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 PackedColor
+rgb2packed (const Vec3<T>& c) IMATH_NOEXCEPT
+{
+    if (std::numeric_limits<T>::is_integer)
+    {
+        float x = c.x / float (std::numeric_limits<T>::max());
+        float y = c.y / float (std::numeric_limits<T>::max());
+        float z = c.z / float (std::numeric_limits<T>::max());
+        return rgb2packed (V3f (x, y, z));
+    }
+    else
+    {
+        // clang-format off
+       return (  (PackedColor) (c.x * 255)             |
+               (((PackedColor) (c.y * 255)) << 8)      |
+               (((PackedColor) (c.z * 255)) << 16)     | 0xFF000000 );
+        // clang-format on
+    }
+}
+
+///
+/// Convert 4-channel rgb to PackedColor (with alpha)
+///
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 PackedColor
+rgb2packed (const Color4<T>& c) IMATH_NOEXCEPT
+{
+    if (std::numeric_limits<T>::is_integer)
+    {
+        float r = c.r / float (std::numeric_limits<T>::max());
+        float g = c.g / float (std::numeric_limits<T>::max());
+        float b = c.b / float (std::numeric_limits<T>::max());
+        float a = c.a / float (std::numeric_limits<T>::max());
+        return rgb2packed (C4f (r, g, b, a));
+    }
+    else
+    {
+        // clang-format off
+       return (  (PackedColor) (c.r * 255)             |
+               (((PackedColor) (c.g * 255)) << 8)      |
+               (((PackedColor) (c.b * 255)) << 16)     |
+               (((PackedColor) (c.a * 255)) << 24));
+        // clang-format on
+    }
+}
+
+///
+/// Convert PackedColor to 3-channel rgb. Return the result in the
+/// `out` parameter.
+///
+
+template <class T>
+IMATH_HOSTDEVICE void
+packed2rgb (PackedColor packed, Vec3<T>& out) IMATH_NOEXCEPT
+{
+    if (std::numeric_limits<T>::is_integer)
+    {
+        T f   = std::numeric_limits<T>::max() / ((PackedColor) 0xFF);
+        out.x = (packed & 0xFF) * f;
+        out.y = ((packed & 0xFF00) >> 8) * f;
+        out.z = ((packed & 0xFF0000) >> 16) * f;
+    }
+    else
+    {
+        T f   = T (1) / T (255);
+        out.x = (packed & 0xFF) * f;
+        out.y = ((packed & 0xFF00) >> 8) * f;
+        out.z = ((packed & 0xFF0000) >> 16) * f;
+    }
+}
+
+///
+/// Convert PackedColor to 4-channel rgb (with alpha). Return the
+/// result in the `out` parameter.
+///
+
+template <class T>
+IMATH_HOSTDEVICE void
+packed2rgb (PackedColor packed, Color4<T>& out) IMATH_NOEXCEPT
+{
+    if (std::numeric_limits<T>::is_integer)
+    {
+        T f   = std::numeric_limits<T>::max() / ((PackedColor) 0xFF);
+        out.r = (packed & 0xFF) * f;
+        out.g = ((packed & 0xFF00) >> 8) * f;
+        out.b = ((packed & 0xFF0000) >> 16) * f;
+        out.a = ((packed & 0xFF000000) >> 24) * f;
+    }
+    else
+    {
+        T f   = T (1) / T (255);
+        out.r = (packed & 0xFF) * f;
+        out.g = ((packed & 0xFF00) >> 8) * f;
+        out.b = ((packed & 0xFF0000) >> 16) * f;
+        out.a = ((packed & 0xFF000000) >> 24) * f;
+    }
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHCOLORALGO_H
diff --git a/src/Imath/ImathEuler.h b/src/Imath/ImathEuler.h
new file mode 100644 (file)
index 0000000..985cce3
--- /dev/null
@@ -0,0 +1,1037 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Euler angle representation of rotation/orientation
+//
+
+#ifndef INCLUDED_IMATHEULER_H
+#define INCLUDED_IMATHEULER_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include "ImathMath.h"
+#include "ImathMatrix.h"
+#include "ImathQuat.h"
+#include "ImathVec.h"
+
+#include <iostream>
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
+// Disable MS VC++ warnings about conversion from double to float
+#    pragma warning(push)
+#    pragma warning(disable : 4244)
+#endif
+
+///
+/// Template class `Euler<T>`
+///
+/// The Euler class represents euler angle orientations. The class
+/// inherits from Vec3 to it can be freely cast. The additional
+/// information is the euler priorities rep. This class is
+/// essentially a rip off of Ken Shoemake's GemsIV code. It has
+/// been modified minimally to make it more understandable, but
+/// hardly enough to make it easy to grok completely.
+///
+/// There are 24 possible combonations of Euler angle
+/// representations of which 12 are common in CG and you will
+/// probably only use 6 of these which in this scheme are the
+/// non-relative-non-repeating types.
+///
+/// The representations can be partitioned according to two
+/// criteria:
+///
+///    1) Are the angles measured relative to a set of fixed axis
+///       or relative to each other (the latter being what happens
+///       when rotation matrices are multiplied together and is
+///       almost ubiquitous in the cg community)
+///
+///    2) Is one of the rotations repeated (ala XYX rotation)
+///
+/// When you construct a given representation from scratch you
+/// must order the angles according to their priorities. So, the
+/// easiest is a softimage or aerospace (yaw/pitch/roll) ordering
+/// of ZYX.
+///
+///     float x_rot = 1;
+///     float y_rot = 2;
+///     float z_rot = 3;
+///
+///     Eulerf angles(z_rot, y_rot, x_rot, Eulerf::ZYX);
+///
+/// or:
+///
+///     Eulerf angles( V3f(z_rot,y_rot,z_rot), Eulerf::ZYX );
+///
+///
+/// If instead, the order was YXZ for instance you would have to
+/// do this:
+///
+///     float x_rot = 1;
+///     float y_rot = 2;
+///     float z_rot = 3;
+///
+///     Eulerf angles(y_rot, x_rot, z_rot, Eulerf::YXZ);
+///
+/// or:
+///
+///
+///     Eulerf angles( V3f(y_rot,x_rot,z_rot), Eulerf::YXZ );
+///
+/// Notice how the order you put the angles into the three slots
+/// should correspond to the enum (YXZ) ordering. The input angle
+/// vector is called the "ijk" vector -- not an "xyz" vector. The
+/// ijk vector order is the same as the enum. If you treat the
+/// Euler as a Vec3 (which it inherts from) you will find the
+/// angles are ordered in the same way, i.e.:
+///
+///     V3f v = angles;
+///     v.x == y_rot, v.y == x_rot, v.z == z_rot
+///
+/// If you just want the x, y, and z angles stored in a vector in
+/// that order, you can do this:
+///
+///     V3f v = angles.toXYZVector()
+///     v.x == x_rot, v.y == y_rot, v.z == z_rot
+///
+/// If you want to set the Euler with an XYZVector use the
+/// optional layout argument:
+///
+///     Eulerf angles(x_rot, y_rot, z_rot, Eulerf::YXZ, Eulerf::XYZLayout);
+///
+/// This is the same as:
+///
+///     Eulerf angles(y_rot, x_rot, z_rot, Eulerf::YXZ);
+///
+/// Note that this won't do anything intelligent if you have a
+/// repeated axis in the euler angles (e.g. XYX)
+///
+/// If you need to use the "relative" versions of these, you will
+/// need to use the "r" enums.
+///
+/// The units of the rotation angles are assumed to be radians.
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Euler : public Vec3<T>
+{
+  public:
+    using Vec3<T>::x;
+    using Vec3<T>::y;
+    using Vec3<T>::z;
+
+    
+    ///
+    ///  All 24 possible orderings
+    ///
+    enum IMATH_EXPORT_ENUM Order
+    {
+        XYZ = 0x0101, // "usual" orderings
+        XZY = 0x0001,
+        YZX = 0x1101,
+        YXZ = 0x1001,
+        ZXY = 0x2101,
+        ZYX = 0x2001,
+
+        XZX = 0x0011, // first axis repeated
+        XYX = 0x0111,
+        YXY = 0x1011,
+        YZY = 0x1111,
+        ZYZ = 0x2011,
+        ZXZ = 0x2111,
+
+        XYZr = 0x2000, // relative orderings -- not common
+        XZYr = 0x2100,
+        YZXr = 0x1000,
+        YXZr = 0x1100,
+        ZXYr = 0x0000,
+        ZYXr = 0x0100,
+
+        XZXr = 0x2110, // relative first axis repeated
+        XYXr = 0x2010,
+        YXYr = 0x1110,
+        YZYr = 0x1010,
+        ZYZr = 0x0110,
+        ZXZr = 0x0010,
+        //       ||||
+        //       VVVV
+        //       ABCD
+        // Legend: 
+        //  A -> Initial Axis (0==x, 1==y, 2==z)
+        //  B -> Parity Even (1==true)
+        //  C -> Initial Repeated (1==true)
+        //  D -> Frame Static (1==true)
+        //
+
+        Legal = XYZ | XZY | YZX | YXZ | ZXY | ZYX | XZX | XYX | YXY | YZY | ZYZ | ZXZ | XYZr |
+                XZYr | YZXr | YXZr | ZXYr | ZYXr | XZXr | XYXr | YXYr | YZYr | ZYZr | ZXZr,
+
+        Min     = 0x0000,
+        Max     = 0x2111,
+        Default = XYZ
+    };
+
+    ///
+    /// Axes
+    ///
+    enum IMATH_EXPORT_ENUM Axis
+    {
+        X = 0,
+        Y = 1,
+        Z = 2
+    };
+
+    ///
+    /// Layout
+    ///
+    
+    enum IMATH_EXPORT_ENUM InputLayout
+    {
+        XYZLayout,
+        IJKLayout
+    };
+
+    /// @{
+    /// @name Constructors
+    ///
+    /// All default to `ZYX` non-relative (ala Softimage 3D/Maya),
+    /// where there is no argument to specify it.
+    ///
+    /// The Euler-from-matrix constructors assume that the matrix does
+    /// not include shear or non-uniform scaling, but the constructors
+    /// do not examine the matrix to verify this assumption.  If necessary,
+    /// you can adjust the matrix by calling the removeScalingAndShear()
+    /// function, defined in ImathMatrixAlgo.h.
+
+    /// No initialization by default
+    IMATH_HOSTDEVICE constexpr Euler() IMATH_NOEXCEPT;
+
+    /// Copy constructor
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Euler (const Euler&) IMATH_NOEXCEPT;
+
+    /// Construct from given Order
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Euler (Order p) IMATH_NOEXCEPT;
+
+    /// Construct from vector, order, layout
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Euler (const Vec3<T>& v,
+                                              Order o       = Default,
+                                              InputLayout l = IJKLayout) IMATH_NOEXCEPT;
+    /// Construct from explicit axes, order, layout
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14
+    Euler (T i, T j, T k, Order o = Default, InputLayout l = IJKLayout) IMATH_NOEXCEPT;
+
+    /// Copy constructor with new Order
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Euler (const Euler<T>& euler, Order newp) IMATH_NOEXCEPT;
+
+    /// Construct from Matrix33
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Euler (const Matrix33<T>&, Order o = Default) IMATH_NOEXCEPT;
+
+    /// Construct from Matrix44
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Euler (const Matrix44<T>&, Order o = Default) IMATH_NOEXCEPT;
+
+    /// Destructor
+    ~Euler () = default;
+
+    /// @}
+    
+    /// @{
+    /// @name Query
+    
+    /// Return whether the given value is a legal Order
+    IMATH_HOSTDEVICE constexpr static bool legal (Order) IMATH_NOEXCEPT;
+
+    /// Return the order
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Order order() const IMATH_NOEXCEPT;
+
+    /// Return frameStatic
+    IMATH_HOSTDEVICE constexpr bool frameStatic() const { return _frameStatic; }
+
+    /// Return intialRepeated
+    IMATH_HOSTDEVICE constexpr bool initialRepeated() const { return _initialRepeated; }
+
+    /// Return partityEven
+    IMATH_HOSTDEVICE constexpr bool parityEven() const { return _parityEven; }
+
+    /// Return initialAxis 
+    IMATH_HOSTDEVICE constexpr Axis initialAxis() const { return _initialAxis; }
+
+    /// Unpack angles from ijk form
+    IMATH_HOSTDEVICE void angleOrder (int& i, int& j, int& k) const IMATH_NOEXCEPT;
+
+    /// Determine mapping from xyz to ijk (reshuffle the xyz to match the order)
+    IMATH_HOSTDEVICE void angleMapping (int& i, int& j, int& k) const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Set Value
+    
+    /// Set the order. This does NOT convert the angles, but it
+    /// does reorder the input vector.
+    IMATH_HOSTDEVICE void setOrder (Order) IMATH_NOEXCEPT;
+
+    /// Set the euler value: set the first angle to `v[0]`, the second to
+    /// `v[1]`, the third to `v[2]`.
+    IMATH_HOSTDEVICE void setXYZVector (const Vec3<T>&) IMATH_NOEXCEPT;
+
+    /// Set the value.
+    IMATH_HOSTDEVICE void set (Axis initial, bool relative, bool parityEven, bool firstRepeats) IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Assignments and Conversions
+    ///
+
+    /// Assignment
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Euler<T>& operator= (const Euler<T>&) IMATH_NOEXCEPT;
+
+    /// Assignment
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Euler<T>& operator= (const Vec3<T>&) IMATH_NOEXCEPT;
+
+    /// Assign from Matrix33, assumed to be affine
+    IMATH_HOSTDEVICE void extract (const Matrix33<T>&) IMATH_NOEXCEPT;
+
+    /// Assign from Matrix44, assumed to be affine
+    IMATH_HOSTDEVICE void extract (const Matrix44<T>&) IMATH_NOEXCEPT;
+
+    /// Assign from Quaternion
+    IMATH_HOSTDEVICE void extract (const Quat<T>&) IMATH_NOEXCEPT;
+
+    /// Convert to Matrix33
+    IMATH_HOSTDEVICE Matrix33<T> toMatrix33() const IMATH_NOEXCEPT;
+
+    /// Convert to Matrix44
+    IMATH_HOSTDEVICE Matrix44<T> toMatrix44() const IMATH_NOEXCEPT;
+
+    /// Convert to Quat
+    IMATH_HOSTDEVICE Quat<T> toQuat() const IMATH_NOEXCEPT;
+
+    /// Reorder the angles so that the X rotation comes first,
+    ///  followed by the Y and Z in cases like XYX ordering, the
+    ///  repeated angle will be in the "z" component
+    IMATH_HOSTDEVICE Vec3<T> toXYZVector() const IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Utility Methods
+    ///
+    ///  Utility methods for getting continuous rotations. None of these
+    ///  methods change the orientation given by its inputs (or at least
+    ///  that is the intent).
+
+    /// Convert an angle to its equivalent in [-PI, PI]
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 static float angleMod (T angle) IMATH_NOEXCEPT;
+
+    /// Adjust xyzRot so that its components differ from targetXyzRot by no more than +/-PI
+    IMATH_HOSTDEVICE static void simpleXYZRotation (Vec3<T>& xyzRot, const Vec3<T>& targetXyzRot) IMATH_NOEXCEPT;
+
+    /// Adjust xyzRot so that its components differ from targetXyzRot by as little as possible.
+    /// Note that xyz here really means ijk, because the order must be provided.
+    IMATH_HOSTDEVICE static void
+    nearestRotation (Vec3<T>& xyzRot, const Vec3<T>& targetXyzRot, Order order = XYZ) IMATH_NOEXCEPT;
+
+    /// Adjusts "this" Euler so that its components differ from target
+    /// by as little as possible. This method might not make sense for
+    /// Eulers with different order and it probably doesn't work for
+    /// repeated axis and relative orderings (TODO).
+    IMATH_HOSTDEVICE void makeNear (const Euler<T>& target) IMATH_NOEXCEPT;
+
+    /// @}
+
+  protected:
+
+    /// relative or static rotations
+    bool _frameStatic : 1;     
+
+    /// init axis repeated as last
+    bool _initialRepeated : 1; 
+
+    /// "parity of axis permutation"
+    bool _parityEven : 1;      
+
+#if defined _WIN32 || defined _WIN64
+    /// First axis of rotation
+    Axis _initialAxis; 
+#else
+    /// First axis of rotation
+    Axis _initialAxis : 2; 
+#endif
+};
+
+//
+// Convenient typedefs
+//
+
+/// Euler of type float
+typedef Euler<float> Eulerf;
+/// Euler of type double
+typedef Euler<double> Eulerd;
+
+//
+// Implementation
+//
+
+/// @cond Doxygen_Suppress
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Euler<T>::angleOrder (int& i, int& j, int& k) const IMATH_NOEXCEPT
+{
+    i = _initialAxis;
+    j = _parityEven ? (i + 1) % 3 : (i > 0 ? i - 1 : 2);
+    k = _parityEven ? (i > 0 ? i - 1 : 2) : (i + 1) % 3;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Euler<T>::angleMapping (int& i, int& j, int& k) const IMATH_NOEXCEPT
+{
+    int m[3];
+
+    m[_initialAxis]           = 0;
+    m[(_initialAxis + 1) % 3] = _parityEven ? 1 : 2;
+    m[(_initialAxis + 2) % 3] = _parityEven ? 2 : 1;
+    i                         = m[0];
+    j                         = m[1];
+    k                         = m[2];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Euler<T>::setXYZVector (const Vec3<T>& v) IMATH_NOEXCEPT
+{
+    int i, j, k;
+    angleMapping (i, j, k);
+    (*this)[i] = v.x;
+    (*this)[j] = v.y;
+    (*this)[k] = v.z;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Vec3<T>
+Euler<T>::toXYZVector() const IMATH_NOEXCEPT
+{
+    int i, j, k;
+    angleMapping (i, j, k);
+    return Vec3<T> ((*this)[i], (*this)[j], (*this)[k]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Euler<T>::Euler() IMATH_NOEXCEPT
+    : Vec3<T> (0, 0, 0),
+      _frameStatic (true),
+      _initialRepeated (false),
+      _parityEven (true),
+      _initialAxis (X)
+{}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Euler<T>::Euler (typename Euler<T>::Order p) IMATH_NOEXCEPT
+    : Vec3<T> (0, 0, 0),
+      _frameStatic (true),
+      _initialRepeated (false),
+      _parityEven (true),
+      _initialAxis (X)
+{
+    setOrder (p);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Euler<T>::Euler (const Vec3<T>& v,
+                                          typename Euler<T>::Order p,
+                                          typename Euler<T>::InputLayout l) IMATH_NOEXCEPT
+{
+    setOrder (p);
+    if (l == XYZLayout)
+        setXYZVector (v);
+    else
+    {
+        x = v.x;
+        y = v.y;
+        z = v.z;
+    }
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Euler<T>::Euler (const Euler<T>& euler) IMATH_NOEXCEPT
+{
+    operator= (euler);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Euler<T>::Euler (const Euler<T>& euler, Order p) IMATH_NOEXCEPT
+{
+    setOrder (p);
+    Matrix33<T> M = euler.toMatrix33();
+    extract (M);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline
+Euler<T>::Euler (T xi, T yi, T zi, typename Euler<T>::Order p,
+                 typename Euler<T>::InputLayout l) IMATH_NOEXCEPT
+{
+    setOrder (p);
+    if (l == XYZLayout)
+        setXYZVector (Vec3<T> (xi, yi, zi));
+    else
+    {
+        x = xi;
+        y = yi;
+        z = zi;
+    }
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Euler<T>::Euler (const Matrix33<T>& M, typename Euler::Order p) IMATH_NOEXCEPT
+{
+    setOrder (p);
+    extract (M);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Euler<T>::Euler (const Matrix44<T>& M, typename Euler::Order p) IMATH_NOEXCEPT
+{
+    setOrder (p);
+    extract (M);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Euler<T>::extract (const Quat<T>& q) IMATH_NOEXCEPT
+{
+    extract (q.toMatrix33());
+}
+
+template <class T>
+IMATH_HOSTDEVICE void
+Euler<T>::extract (const Matrix33<T>& M) IMATH_NOEXCEPT
+{
+    int i, j, k;
+    angleOrder (i, j, k);
+
+    if (_initialRepeated)
+    {
+        //
+        // Extract the first angle, x.
+        //
+
+        x = std::atan2 (M[j][i], M[k][i]);
+
+        //
+        // Remove the x rotation from M, so that the remaining
+        // rotation, N, is only around two axes, and gimbal lock
+        // cannot occur.
+        //
+
+        Vec3<T> r (0, 0, 0);
+        r[i] = (_parityEven ? -x : x);
+
+        Matrix44<T> N;
+        N.rotate (r);
+
+        N = N * Matrix44<T> (M[0][0],
+                             M[0][1],
+                             M[0][2],
+                             0,
+                             M[1][0],
+                             M[1][1],
+                             M[1][2],
+                             0,
+                             M[2][0],
+                             M[2][1],
+                             M[2][2],
+                             0,
+                             0,
+                             0,
+                             0,
+                             1);
+        //
+        // Extract the other two angles, y and z, from N.
+        //
+
+        T sy = std::sqrt (N[j][i] * N[j][i] + N[k][i] * N[k][i]);
+        y    = std::atan2 (sy, N[i][i]);
+        z    = std::atan2 (N[j][k], N[j][j]);
+    }
+    else
+    {
+        //
+        // Extract the first angle, x.
+        //
+
+        x = std::atan2 (M[j][k], M[k][k]);
+
+        //
+        // Remove the x rotation from M, so that the remaining
+        // rotation, N, is only around two axes, and gimbal lock
+        // cannot occur.
+        //
+
+        Vec3<T> r (0, 0, 0);
+        r[i] = (_parityEven ? -x : x);
+
+        Matrix44<T> N;
+        N.rotate (r);
+
+        N = N * Matrix44<T> (M[0][0],
+                             M[0][1],
+                             M[0][2],
+                             0,
+                             M[1][0],
+                             M[1][1],
+                             M[1][2],
+                             0,
+                             M[2][0],
+                             M[2][1],
+                             M[2][2],
+                             0,
+                             0,
+                             0,
+                             0,
+                             1);
+        //
+        // Extract the other two angles, y and z, from N.
+        //
+
+        T cy = std::sqrt (N[i][i] * N[i][i] + N[i][j] * N[i][j]);
+        y    = std::atan2 (-N[i][k], cy);
+        z    = std::atan2 (-N[j][i], N[j][j]);
+    }
+
+    if (!_parityEven)
+        *this *= -1;
+
+    if (!_frameStatic)
+    {
+        T t = x;
+        x   = z;
+        z   = t;
+    }
+}
+
+template <class T>
+IMATH_HOSTDEVICE void
+Euler<T>::extract (const Matrix44<T>& M) IMATH_NOEXCEPT
+{
+    int i, j, k;
+    angleOrder (i, j, k);
+
+    if (_initialRepeated)
+    {
+        //
+        // Extract the first angle, x.
+        //
+
+        x = std::atan2 (M[j][i], M[k][i]);
+
+        //
+        // Remove the x rotation from M, so that the remaining
+        // rotation, N, is only around two axes, and gimbal lock
+        // cannot occur.
+        //
+
+        Vec3<T> r (0, 0, 0);
+        r[i] = (_parityEven ? -x : x);
+
+        Matrix44<T> N;
+        N.rotate (r);
+        N = N * M;
+
+        //
+        // Extract the other two angles, y and z, from N.
+        //
+
+        T sy = std::sqrt (N[j][i] * N[j][i] + N[k][i] * N[k][i]);
+        y    = std::atan2 (sy, N[i][i]);
+        z    = std::atan2 (N[j][k], N[j][j]);
+    }
+    else
+    {
+        //
+        // Extract the first angle, x.
+        //
+
+        x = std::atan2 (M[j][k], M[k][k]);
+
+        //
+        // Remove the x rotation from M, so that the remaining
+        // rotation, N, is only around two axes, and gimbal lock
+        // cannot occur.
+        //
+
+        Vec3<T> r (0, 0, 0);
+        r[i] = (_parityEven ? -x : x);
+
+        Matrix44<T> N;
+        N.rotate (r);
+        N = N * M;
+
+        //
+        // Extract the other two angles, y and z, from N.
+        //
+
+        T cy = std::sqrt (N[i][i] * N[i][i] + N[i][j] * N[i][j]);
+        y    = std::atan2 (-N[i][k], cy);
+        z    = std::atan2 (-N[j][i], N[j][j]);
+    }
+
+    if (!_parityEven)
+        *this *= -1;
+
+    if (!_frameStatic)
+    {
+        T t = x;
+        x   = z;
+        z   = t;
+    }
+}
+
+template <class T>
+IMATH_HOSTDEVICE Matrix33<T>
+Euler<T>::toMatrix33() const IMATH_NOEXCEPT
+{
+    int i, j, k;
+    angleOrder (i, j, k);
+
+    Vec3<T> angles;
+
+    if (_frameStatic)
+        angles = (*this);
+    else
+        angles = Vec3<T> (z, y, x);
+
+    if (!_parityEven)
+        angles *= -1.0;
+
+    T ci = std::cos (angles.x);
+    T cj = std::cos (angles.y);
+    T ch = std::cos (angles.z);
+    T si = std::sin (angles.x);
+    T sj = std::sin (angles.y);
+    T sh = std::sin (angles.z);
+
+    T cc = ci * ch;
+    T cs = ci * sh;
+    T sc = si * ch;
+    T ss = si * sh;
+
+    Matrix33<T> M;
+
+    if (_initialRepeated)
+    {
+        M[i][i] = cj;
+        M[j][i] = sj * si;
+        M[k][i] = sj * ci;
+        M[i][j] = sj * sh;
+        M[j][j] = -cj * ss + cc;
+        M[k][j] = -cj * cs - sc;
+        M[i][k] = -sj * ch;
+        M[j][k] = cj * sc + cs;
+        M[k][k] = cj * cc - ss;
+    }
+    else
+    {
+        M[i][i] = cj * ch;
+        M[j][i] = sj * sc - cs;
+        M[k][i] = sj * cc + ss;
+        M[i][j] = cj * sh;
+        M[j][j] = sj * ss + cc;
+        M[k][j] = sj * cs - sc;
+        M[i][k] = -sj;
+        M[j][k] = cj * si;
+        M[k][k] = cj * ci;
+    }
+
+    return M;
+}
+
+template <class T>
+IMATH_HOSTDEVICE Matrix44<T>
+Euler<T>::toMatrix44() const IMATH_NOEXCEPT
+{
+    int i, j, k;
+    angleOrder (i, j, k);
+
+    Vec3<T> angles;
+
+    if (_frameStatic)
+        angles = (*this);
+    else
+        angles = Vec3<T> (z, y, x);
+
+    if (!_parityEven)
+        angles *= -1.0;
+
+    T ci = std::cos (angles.x);
+    T cj = std::cos (angles.y);
+    T ch = std::cos (angles.z);
+    T si = std::sin (angles.x);
+    T sj = std::sin (angles.y);
+    T sh = std::sin (angles.z);
+
+    T cc = ci * ch;
+    T cs = ci * sh;
+    T sc = si * ch;
+    T ss = si * sh;
+
+    Matrix44<T> M;
+
+    if (_initialRepeated)
+    {
+        M[i][i] = cj;
+        M[j][i] = sj * si;
+        M[k][i] = sj * ci;
+        M[i][j] = sj * sh;
+        M[j][j] = -cj * ss + cc;
+        M[k][j] = -cj * cs - sc;
+        M[i][k] = -sj * ch;
+        M[j][k] = cj * sc + cs;
+        M[k][k] = cj * cc - ss;
+    }
+    else
+    {
+        M[i][i] = cj * ch;
+        M[j][i] = sj * sc - cs;
+        M[k][i] = sj * cc + ss;
+        M[i][j] = cj * sh;
+        M[j][j] = sj * ss + cc;
+        M[k][j] = sj * cs - sc;
+        M[i][k] = -sj;
+        M[j][k] = cj * si;
+        M[k][k] = cj * ci;
+    }
+
+    return M;
+}
+
+template <class T>
+IMATH_HOSTDEVICE Quat<T>
+Euler<T>::toQuat() const IMATH_NOEXCEPT
+{
+    Vec3<T> angles;
+    int i, j, k;
+    angleOrder (i, j, k);
+
+    if (_frameStatic)
+        angles = (*this);
+    else
+        angles = Vec3<T> (z, y, x);
+
+    if (!_parityEven)
+        angles.y = -angles.y;
+
+    T ti = angles.x * 0.5;
+    T tj = angles.y * 0.5;
+    T th = angles.z * 0.5;
+    T ci = std::cos (ti);
+    T cj = std::cos (tj);
+    T ch = std::cos (th);
+    T si = std::sin (ti);
+    T sj = std::sin (tj);
+    T sh = std::sin (th);
+    T cc = ci * ch;
+    T cs = ci * sh;
+    T sc = si * ch;
+    T ss = si * sh;
+
+    T parity = _parityEven ? 1.0 : -1.0;
+
+    Quat<T> q;
+    Vec3<T> a;
+
+    if (_initialRepeated)
+    {
+        a[i]     = cj * (cs + sc);
+        a[j]     = sj * (cc + ss) * parity, // NOSONAR - suppress SonarCloud bug report.
+            a[k] = sj * (cs - sc);
+        q.r      = cj * (cc - ss);
+    }
+    else
+    {
+        a[i]     = cj * sc - sj * cs,
+        a[j]     = (cj * ss + sj * cc) * parity, // NOSONAR - suppress SonarCloud bug report.
+            a[k] = cj * cs - sj * sc;
+        q.r      = cj * cc + sj * ss;
+    }
+
+    q.v = a;
+
+    return q;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Euler<T>::legal (typename Euler<T>::Order order) IMATH_NOEXCEPT
+{
+    return (order & ~Legal) ? false : true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 typename Euler<T>::Order
+Euler<T>::order() const IMATH_NOEXCEPT
+{
+    int foo = (_initialAxis == Z ? 0x2000 : (_initialAxis == Y ? 0x1000 : 0));
+
+    if (_parityEven)
+        foo |= 0x0100;
+    if (_initialRepeated)
+        foo |= 0x0010;
+    if (_frameStatic)
+        foo++;
+
+    return (Order) foo;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Euler<T>::setOrder (typename Euler<T>::Order p) IMATH_NOEXCEPT
+{
+    set (p & 0x2000 ? Z : (p & 0x1000 ? Y : X), // initial axis
+         !(p & 0x1),                            // static?
+         !!(p & 0x100),                         // permutation even?
+         !!(p & 0x10));                         // initial repeats?
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Euler<T>::set (typename Euler<T>::Axis axis, bool relative, bool parityEven, bool firstRepeats) IMATH_NOEXCEPT
+{
+    _initialAxis     = axis;
+    _frameStatic     = !relative;
+    _parityEven      = parityEven;
+    _initialRepeated = firstRepeats;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Euler<T>&
+Euler<T>::operator= (const Euler<T>& euler) IMATH_NOEXCEPT
+{
+    x                = euler.x;
+    y                = euler.y;
+    z                = euler.z;
+    _initialAxis     = euler._initialAxis;
+    _frameStatic     = euler._frameStatic;
+    _parityEven      = euler._parityEven;
+    _initialRepeated = euler._initialRepeated;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Euler<T>&
+Euler<T>::operator= (const Vec3<T>& v) IMATH_NOEXCEPT
+{
+    x = v.x;
+    y = v.y;
+    z = v.z;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline float
+Euler<T>::angleMod (T angle) IMATH_NOEXCEPT
+{
+    const T pi = static_cast<T> (M_PI);
+    angle      = fmod (T (angle), T (2 * pi));
+
+    if (angle < -pi)
+        angle += 2 * pi;
+    if (angle > +pi)
+        angle -= 2 * pi;
+
+    return angle;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Euler<T>::simpleXYZRotation (Vec3<T>& xyzRot, const Vec3<T>& targetXyzRot) IMATH_NOEXCEPT
+{
+    Vec3<T> d = xyzRot - targetXyzRot;
+    xyzRot[0] = targetXyzRot[0] + angleMod (d[0]);
+    xyzRot[1] = targetXyzRot[1] + angleMod (d[1]);
+    xyzRot[2] = targetXyzRot[2] + angleMod (d[2]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE void
+Euler<T>::nearestRotation (Vec3<T>& xyzRot, const Vec3<T>& targetXyzRot, Order order) IMATH_NOEXCEPT
+{
+    int i, j, k;
+    Euler<T> e (0, 0, 0, order);
+    e.angleOrder (i, j, k);
+
+    simpleXYZRotation (xyzRot, targetXyzRot);
+
+    Vec3<T> otherXyzRot;
+    otherXyzRot[i] = M_PI + xyzRot[i];
+    otherXyzRot[j] = M_PI - xyzRot[j];
+    otherXyzRot[k] = M_PI + xyzRot[k];
+
+    simpleXYZRotation (otherXyzRot, targetXyzRot);
+
+    Vec3<T> d  = xyzRot - targetXyzRot;
+    Vec3<T> od = otherXyzRot - targetXyzRot;
+    T dMag     = d.dot (d);
+    T odMag    = od.dot (od);
+
+    if (odMag < dMag)
+    {
+        xyzRot = otherXyzRot;
+    }
+}
+
+template <class T>
+IMATH_HOSTDEVICE void
+Euler<T>::makeNear (const Euler<T>& target) IMATH_NOEXCEPT
+{
+    Vec3<T> xyzRot = toXYZVector();
+    Vec3<T> targetXyz;
+    if (order() != target.order())
+    {
+        Euler<T> targetSameOrder = Euler<T> (target, order());
+        targetXyz                = targetSameOrder.toXYZVector();
+    }
+    else
+    {
+        targetXyz = target.toXYZVector();
+    }
+
+    nearestRotation (xyzRot, targetXyz, order());
+
+    setXYZVector (xyzRot);
+}
+
+/// @endcond
+
+/// Stream ouput, as "(x y z i j k)"
+template <class T>
+std::ostream&
+operator<< (std::ostream& o, const Euler<T>& euler)
+{
+    char a[3] = { 'X', 'Y', 'Z' };
+
+    const char* r = euler.frameStatic() ? "" : "r";
+    int i, j, k;
+    euler.angleOrder (i, j, k);
+
+    if (euler.initialRepeated())
+        k = i;
+
+    return o << "(" << euler.x << " " << euler.y << " " << euler.z << " " << a[i] << a[j] << a[k]
+             << r << ")";
+}
+
+#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
+#    pragma warning(pop)
+#endif
+
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHEULER_H
diff --git a/src/Imath/ImathExport.h b/src/Imath/ImathExport.h
new file mode 100644 (file)
index 0000000..8e7bb6a
--- /dev/null
@@ -0,0 +1,68 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifndef INCLUDED_IMATHEXPORT_H
+#define INCLUDED_IMATHEXPORT_H
+
+#include "ImathConfig.h"
+
+/// \defgroup ExportMacros Macros to manage symbol visibility
+///
+/// There is more information about the motivation for these macros
+/// documented in the OpenEXR source tree
+/// (https://github.com/AcademySoftwareFoundation/openexr) under
+/// docs/SymbolVisibility.md
+///
+/// Imath only needs a couple of the possible macros outlined in the
+/// above document, and due to it largely being inline only, does not
+/// have much to do.
+/// 
+/// @{
+#if defined(IMATH_DLL)
+
+// when building Imath as a DLL for Windows, we have to control the
+// typical DLL export / import things. Luckily, the typeinfo is all
+// automatic there, so only have to deal with symbols, except Windows
+// has some weirdness with DLLs and extern const, so we have to
+// provide a macro to handle that.
+
+#  if defined(IMATH_EXPORTS)
+#    define IMATH_EXPORT __declspec(dllexport)
+#    define IMATH_EXPORT_CONST extern __declspec(dllexport)
+#  else
+#    define IMATH_EXPORT __declspec(dllimport)
+#    define IMATH_EXPORT_CONST extern __declspec(dllimport)
+#  endif
+
+// DLLs don't support these types of visibility controls, just leave them as empty
+#  define IMATH_EXPORT_TYPE
+#  define IMATH_EXPORT_ENUM
+#  define IMATH_EXPORT_TEMPLATE_TYPE
+
+#else
+
+#  ifdef IMATH_PUBLIC_SYMBOL_ATTRIBUTE
+#    define IMATH_EXPORT IMATH_PUBLIC_SYMBOL_ATTRIBUTE
+#    define IMATH_EXPORT_CONST extern const IMATH_PUBLIC_SYMBOL_ATTRIBUTE
+#  else
+#    define IMATH_EXPORT
+#    define IMATH_EXPORT_CONST extern const
+#  endif
+
+#  ifdef IMATH_PUBLIC_TYPE_VISIBILITY_ATTRIBUTE
+#    define IMATH_EXPORT_ENUM IMATH_PUBLIC_TYPE_VISIBILITY_ATTRIBUTE
+#    define IMATH_EXPORT_TEMPLATE_TYPE IMATH_PUBLIC_TYPE_VISIBILITY_ATTRIBUTE
+#    define IMATH_EXPORT_TYPE IMATH_PUBLIC_TYPE_VISIBILITY_ATTRIBUTE
+#  else
+#    define IMATH_EXPORT_ENUM
+#    define IMATH_EXPORT_TEMPLATE_TYPE IMATH_EXPORT
+#    define IMATH_EXPORT_TYPE IMATH_EXPORT
+#  endif
+
+#endif // IMATH_DLL
+
+/// @}
+
+#endif // INCLUDED_IMATHEXPORT_H
diff --git a/src/Imath/ImathForward.h b/src/Imath/ImathForward.h
new file mode 100644 (file)
index 0000000..8741652
--- /dev/null
@@ -0,0 +1,80 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifndef INCLUDED_IMATHFORWARD_H
+#define INCLUDED_IMATHFORWARD_H
+
+#include "ImathNamespace.h"
+#include "ImathExport.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+/// @cond Doxygen_Suppress
+
+//
+// Basic template type declarations.
+//
+
+//
+// Note: declarations with attributes generate warnings with
+// -Wattributes or -Wall if the type is already defined, i.e. the
+// header is already included. To avoid the warning, only make the
+// forward declaration if the header has not yet been included.
+//
+
+#ifndef INCLUDED_IMATHBOX_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Box;
+#endif
+#ifndef INCLUDED_IMATHCOLOR_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Color3;
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Color4;
+#endif
+#ifndef INCLUDED_IMATHEULER_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Euler;
+#endif
+#ifndef INCLUDED_IMATHFRUSTUM_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Frustum;
+#endif
+#ifndef INCLUDED_IMATHFRUSTUMTEST_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE FrustumTest;
+#endif
+#ifndef INCLUDED_IMATHINTERVAL_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Interval;
+#endif
+#ifndef INCLUDED_IMATHLINE_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Line3;
+#endif
+#ifndef INCLUDED_IMATHMATRIX_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Matrix33;
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Matrix44;
+#endif
+#ifndef INCLUDED_IMATHPLANE_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Plane3;
+#endif
+#ifndef INCLUDED_IMATHQUAT_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Quat;
+#endif
+#ifndef INCLUDED_IMATHSHEAR_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Shear6;
+#endif
+#ifndef INCLUDED_IMATHSPHERE_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Sphere3;
+#endif
+#ifndef INCLUDED_IMATHVEC_H
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Vec2;
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Vec3;
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Vec4;
+#endif
+
+#ifndef INCLUDED_IMATHRANDOM_H
+class IMATH_EXPORT_TYPE Rand32;
+class IMATH_EXPORT_TYPE Rand48;
+#endif
+
+/// @endcond
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHFORWARD_H
diff --git a/src/Imath/ImathFrame.h b/src/Imath/ImathFrame.h
new file mode 100644 (file)
index 0000000..4d547fc
--- /dev/null
@@ -0,0 +1,216 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Functions for computing reference frames.
+//
+
+#ifndef INCLUDED_IMATHFRAME_H
+#define INCLUDED_IMATHFRAME_H
+
+#include "ImathNamespace.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+/// @cond Doxygen_Suppress
+template <class T> class Vec3;
+template <class T> class Matrix44;
+/// @endcond
+
+///
+/// @{
+/// @name Functions for computing reference frames
+///
+/// These methods compute a set of reference frames, defined by their
+/// transformation matrix, along a curve. It is designed so that the
+/// array of points and the array of matrices used to fetch these
+/// routines don't need to be ordered as the curve.
+///
+/// A typical usage would be :
+///
+///      m[0] = IMATH_INTERNAL_NAMESPACE::firstFrame( p[0], p[1], p[2] );
+///      for( int i = 1; i < n - 1; i++ )
+///      {
+///          m[i] = IMATH_INTERNAL_NAMESPACE::nextFrame( m[i-1], p[i-1], p[i], t[i-1], t[i] );
+///      }
+///      m[n-1] = IMATH_INTERNAL_NAMESPACE::lastFrame( m[n-2], p[n-2], p[n-1] );
+///
+///  See Graphics Gems I for the underlying algorithm.
+
+
+template <class T>
+Matrix44<T> constexpr firstFrame (const Vec3<T>&,  // First point
+                                  const Vec3<T>&,  // Second point
+                                  const Vec3<T>&) IMATH_NOEXCEPT; // Third point
+
+template <class T>
+Matrix44<T> constexpr nextFrame (const Matrix44<T>&, // Previous matrix
+                                 const Vec3<T>&,     // Previous point
+                                 const Vec3<T>&,     // Current point
+                                 Vec3<T>&,           // Previous tangent
+                                 Vec3<T>&) IMATH_NOEXCEPT;          // Current tangent
+
+template <class T>
+Matrix44<T> constexpr lastFrame (const Matrix44<T>&, // Previous matrix
+                                 const Vec3<T>&,     // Previous point
+                                 const Vec3<T>&) IMATH_NOEXCEPT;    // Last point
+
+///
+/// Compute the first reference frame along a curve.
+///
+/// This function returns the transformation matrix to the reference
+/// frame defined by the three points `pi`, `pj` and `pk`. Note that
+/// if the two vectors <`pi`,`pj`> and <`pi`,`pk`> are colinears, an
+/// arbitrary twist value will be choosen.
+///
+/// Throw `std::domain_error` if `pi` and `pj` are equal.
+///
+/// @param pi
+///      First point
+/// @param pj
+///      Second point
+/// @param pk
+///      Third point
+/// 
+template <class T>
+Matrix44<T> constexpr firstFrame (const Vec3<T>& pi, // first point
+                                  const Vec3<T>& pj, // secont point
+                                  const Vec3<T>& pk) IMATH_NOEXCEPT // third point
+{
+    Vec3<T> t = pj - pi;
+    t.normalizeExc();
+
+    Vec3<T> n = t.cross (pk - pi);
+    n.normalize();
+    if (n.length() == 0.0f)
+    {
+        int i = fabs (t[0]) < fabs (t[1]) ? 0 : 1;
+        if (fabs (t[2]) < fabs (t[i]))
+            i = 2;
+
+        Vec3<T> v (0.0, 0.0, 0.0);
+        v[i] = 1.0;
+        n    = t.cross (v);
+        n.normalize();
+    }
+
+    Vec3<T> b = t.cross (n);
+
+    Matrix44<T> M;
+
+    M[0][0] = t[0];
+    M[0][1] = t[1];
+    M[0][2] = t[2];
+    M[0][3] = 0.0, M[1][0] = n[0];
+    M[1][1] = n[1];
+    M[1][2] = n[2];
+    M[1][3] = 0.0, M[2][0] = b[0];
+    M[2][1] = b[1];
+    M[2][2] = b[2];
+    M[2][3] = 0.0, M[3][0] = pi[0];
+    M[3][1] = pi[1];
+    M[3][2] = pi[2];
+    M[3][3] = 1.0;
+
+    return M;
+}
+
+///
+/// Compute the next reference frame along a curve.
+///
+/// This function returns the transformation matrix to the next reference
+/// frame defined by the previously computed transformation matrix and the
+/// new point and tangent vector along the curve.
+///
+/// @param Mi
+///      The previous matrix
+/// @param pi
+///      The previous point
+/// @param pj
+///      The current point
+/// @param ti
+///      The previous tangent vector
+/// @param tj
+///      The current tangent vector
+
+template <class T>
+Matrix44<T> constexpr nextFrame (const Matrix44<T>& Mi, // Previous matrix
+                                 const Vec3<T>& pi,     // Previous point
+                                 const Vec3<T>& pj,     // Current point
+                                 Vec3<T>& ti,           // Previous tangent vector
+                                 Vec3<T>& tj) IMATH_NOEXCEPT  // Current tangent vector
+{
+    Vec3<T> a (0.0, 0.0, 0.0); /// Rotation axis.
+    T r = 0.0;                 // Rotation angle.
+
+    if (ti.length() != 0.0 && tj.length() != 0.0)
+    {
+        ti.normalize();
+        tj.normalize();
+        T dot = ti.dot (tj);
+
+        //
+        //  This is *really* necessary :
+        //
+
+        if (dot > 1.0)
+            dot = 1.0;
+        else if (dot < -1.0)
+            dot = -1.0;
+
+        r = acosf (dot);
+        a = ti.cross (tj);
+    }
+
+    if (a.length() != 0.0 && r != 0.0)
+    {
+        Matrix44<T> R;
+        R.setAxisAngle (a, r);
+        Matrix44<T> Tj;
+        Tj.translate (pj);
+        Matrix44<T> Ti;
+        Ti.translate (-pi);
+
+        return Mi * Ti * R * Tj;
+    }
+    else
+    {
+        Matrix44<T> Tr;
+        Tr.translate (pj - pi);
+
+        return Mi * Tr;
+    }
+}
+
+///
+/// Compute the last reference frame along a curve.
+///
+/// This function returns the transformation matrix to the last reference
+/// frame defined by the previously computed transformation matrix and the
+/// last point along the curve.
+///
+/// @param Mi
+///      The previous matrix
+/// @param pi
+///      The previous point
+/// @param pj
+///      The last point
+
+template <class T>
+Matrix44<T> constexpr lastFrame (const Matrix44<T>& Mi, // Previous matrix
+                                 const Vec3<T>& pi,     // Previous point
+                                 const Vec3<T>& pj) IMATH_NOEXCEPT // Last point
+{
+    Matrix44<T> Tr;
+    Tr.translate (pj - pi);
+
+    return Mi * Tr;
+}
+
+/// @}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHFRAME_H
diff --git a/src/Imath/ImathFrustum.h b/src/Imath/ImathFrustum.h
new file mode 100644 (file)
index 0000000..a5daf0e
--- /dev/null
@@ -0,0 +1,975 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// A viewing frustum class
+//
+
+#ifndef INCLUDED_IMATHFRUSTUM_H
+#define INCLUDED_IMATHFRUSTUM_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include "ImathFun.h"
+#include "ImathLine.h"
+#include "ImathMatrix.h"
+#include "ImathPlane.h"
+#include "ImathVec.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// Template class `Frustum<T>`
+///
+/// The frustum is always located with the eye point at the origin
+/// facing down -Z. This makes the Frustum class compatable with
+/// OpenGL (or anything that assumes a camera looks down -Z, hence
+/// with a right-handed coordinate system) but not with RenderMan
+/// which assumes the camera looks down +Z. Additional functions are
+/// provided for conversion from and from various camera coordinate
+/// spaces.
+///
+/// nearPlane/farPlane: near/far are keywords used by Microsoft's
+/// compiler, so we use nearPlane/farPlane instead to avoid
+/// issues.
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Frustum
+{
+  public:
+
+    /// @{
+    /// @name Constructors and Assignment
+    ///
+
+    /// Initialize with default values:
+    ///  near=0.1, far=1000.0, left=-1.0, right=1.0, top=1.0, bottom=-1.0, ortho=false
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Frustum() IMATH_NOEXCEPT;
+
+    /// Copy constructor
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Frustum (const Frustum&) IMATH_NOEXCEPT;
+
+    /// Initialize to specific values
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14
+    Frustum (T nearPlane, T farPlane, T left, T right, T top, T bottom, bool ortho = false) IMATH_NOEXCEPT;
+
+    /// Initialize with fov and aspect 
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Frustum (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT;
+
+    /// Destructor
+    virtual ~Frustum() IMATH_NOEXCEPT;
+
+    /// Component-wise assignment
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Frustum& operator= (const Frustum&) IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Comparison
+
+    /// Equality
+    IMATH_HOSTDEVICE constexpr bool operator== (const Frustum<T>& src) const IMATH_NOEXCEPT;
+
+    /// Inequality
+    IMATH_HOSTDEVICE constexpr bool operator!= (const Frustum<T>& src) const IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Query
+    
+    /// Return true if the frustum is orthographic, false if perspective
+    IMATH_HOSTDEVICE constexpr bool orthographic() const IMATH_NOEXCEPT { return _orthographic; }
+
+    /// Return the near clipping plane
+    IMATH_HOSTDEVICE constexpr T nearPlane() const IMATH_NOEXCEPT { return _nearPlane; }
+
+    /// Return the near clipping plane
+    IMATH_HOSTDEVICE constexpr T hither() const IMATH_NOEXCEPT { return _nearPlane; }
+
+    /// Return the far clipping plane
+    IMATH_HOSTDEVICE constexpr T farPlane() const IMATH_NOEXCEPT { return _farPlane; }
+
+    /// Return the far clipping plane
+    IMATH_HOSTDEVICE constexpr T yon() const IMATH_NOEXCEPT { return _farPlane; }
+
+    /// Return the left of the frustum
+    IMATH_HOSTDEVICE constexpr T left() const IMATH_NOEXCEPT { return _left; }
+
+    /// Return the right of the frustum
+    IMATH_HOSTDEVICE constexpr T right() const IMATH_NOEXCEPT { return _right; }
+
+    /// Return the bottom of the frustum
+    IMATH_HOSTDEVICE constexpr T bottom() const IMATH_NOEXCEPT { return _bottom; }
+
+    /// Return the top of the frustum
+    IMATH_HOSTDEVICE constexpr T top() const IMATH_NOEXCEPT { return _top; }
+
+    /// Return the field of view in X
+    IMATH_HOSTDEVICE constexpr T fovx() const IMATH_NOEXCEPT;
+
+    /// Return the field of view in Y
+    IMATH_HOSTDEVICE constexpr T fovy() const IMATH_NOEXCEPT;
+
+    /// Return the aspect ratio
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T aspect() const IMATH_NOEXCEPT;
+
+    /// Return the aspect ratio. Throw an exception if the aspect
+    /// ratio is undefined.
+    IMATH_CONSTEXPR14 T aspectExc() const;
+
+    /// Return the project matrix that the frustum defines
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44<T> projectionMatrix() const IMATH_NOEXCEPT;
+
+    /// Return the project matrix that the frustum defines. Throw an
+    /// exception if the frustum is degenerate.
+    IMATH_CONSTEXPR14 Matrix44<T> projectionMatrixExc() const;
+
+    /// Return true if the frustum is degenerate.
+    IMATH_HOSTDEVICE constexpr bool degenerate() const IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Set Value
+    
+    /// Set functions change the entire state of the Frustum
+    IMATH_HOSTDEVICE void
+    set (T nearPlane, T farPlane, T left, T right, T top, T bottom, bool ortho = false) IMATH_NOEXCEPT;
+
+    /// Set functions change the entire state of the Frustum using
+    /// field of view and aspect ratio
+    IMATH_HOSTDEVICE void set (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT;
+
+    /// Set functions change the entire state of the Frustum using
+    /// field of view and aspect ratio. Throw an exception if `fovx`
+    /// and/or `fovy` are invalid.
+    void setExc (T nearPlane, T farPlane, T fovx, T fovy, T aspect);
+
+    /// Set the near and far clipping planes
+    IMATH_HOSTDEVICE void modifyNearAndFar (T nearPlane, T farPlane) IMATH_NOEXCEPT;
+
+    /// Set the ortographic state
+    IMATH_HOSTDEVICE void setOrthographic (bool) IMATH_NOEXCEPT;
+
+    /// Set the planes in p to be the six bounding planes of the frustum, in
+    /// the following order: top, right, bottom, left, near, far.
+    /// Note that the planes have normals that point out of the frustum.
+    IMATH_HOSTDEVICE void planes (Plane3<T> p[6]) const IMATH_NOEXCEPT;
+
+    /// Set the planes in p to be the six bounding planes of the
+    /// frustum, in the following order: top, right, bottom, left,
+    /// near, far.  Note that the planes have normals that point out
+    /// of the frustum.  Apply the given matrix to transform the
+    /// frustum before setting the planes.
+    IMATH_HOSTDEVICE void planes (Plane3<T> p[6], const Matrix44<T>& M) const IMATH_NOEXCEPT;
+
+    /// Takes a rectangle in the screen space (i.e., -1 <= left <= right <= 1
+    /// and -1 <= bottom <= top <= 1) of this Frustum, and returns a new
+    /// Frustum whose near clipping-plane window is that rectangle in local
+    /// space.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 IMATH_HOSTDEVICE Frustum<T>
+    window (T left, T right, T top, T bottom) const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Utility Methods
+    
+    /// Project a point in screen spaced to 3d ray
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Line3<T> projectScreenToRay (const Vec2<T>&) const IMATH_NOEXCEPT;
+
+    /// Project a 3D point into screen coordinates
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec2<T> projectPointToScreen (const Vec3<T>&) const IMATH_NOEXCEPT;
+
+    /// Project a 3D point into screen coordinates. Throw an
+    /// exception if the point cannot be projected.
+    IMATH_CONSTEXPR14 Vec2<T> projectPointToScreenExc (const Vec3<T>&) const;
+
+    /// Map a z value to its depth in the frustum.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T ZToDepth (long zval,
+                                                   long min,
+                                                   long max) const IMATH_NOEXCEPT;
+    /// Map a z value to its depth in the frustum.
+    IMATH_CONSTEXPR14 T ZToDepthExc (long zval, long min, long max) const;
+
+    /// Map a normalized z value to its depth in the frustum.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T normalizedZToDepth (T zval) const IMATH_NOEXCEPT;
+
+    /// Map a normalized z value to its depth in the frustum. Throw an
+    /// exception on error.
+    IMATH_CONSTEXPR14 T normalizedZToDepthExc (T zval) const;
+
+    /// Map depth to z value.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 long
+    DepthToZ (T depth, long zmin, long zmax) const IMATH_NOEXCEPT;
+
+    /// Map depth to z value. Throw an exception on error.
+    IMATH_CONSTEXPR14 long DepthToZExc (T depth, long zmin, long zmax) const;
+
+    /// Compute worldRadius
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T worldRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT;
+
+    /// Compute worldRadius. Throw an exception on error.
+    IMATH_CONSTEXPR14 T worldRadiusExc (const Vec3<T>& p, T radius) const;
+
+    /// Compute screen radius
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T screenRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT;
+
+    /// Compute screen radius. Throw an exception on error.
+    IMATH_CONSTEXPR14 T screenRadiusExc (const Vec3<T>& p, T radius) const;
+
+    /// @}
+    
+  protected:
+
+    /// Map point from screen space to local space
+    IMATH_HOSTDEVICE constexpr Vec2<T> screenToLocal (const Vec2<T>&) const IMATH_NOEXCEPT;
+
+    /// Map point from local space to screen space
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec2<T>
+    localToScreen (const Vec2<T>&) const IMATH_NOEXCEPT;
+
+    /// Map point from local space to screen space. Throw an exception
+    /// on error.
+    IMATH_CONSTEXPR14 Vec2<T> localToScreenExc (const Vec2<T>&) const;
+
+  protected:
+
+    /// @cond Doxygen_Suppress
+
+    T _nearPlane;
+    T _farPlane;
+    T _left;
+    T _right;
+    T _top;
+    T _bottom;
+    bool _orthographic;
+
+    /// @endcond
+};
+
+template <class T> IMATH_CONSTEXPR14 inline Frustum<T>::Frustum() IMATH_NOEXCEPT
+{
+    set (T (0.1), T (1000.0), T (-1.0), T (1.0), T (1.0), T (-1.0), false);
+}
+
+template <class T> IMATH_CONSTEXPR14 inline Frustum<T>::Frustum (const Frustum& f) IMATH_NOEXCEPT
+{
+    *this = f;
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline Frustum<T>::Frustum (T n, T f, T l, T r, T t, T b, bool o) IMATH_NOEXCEPT
+{
+    set (n, f, l, r, t, b, o);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline Frustum<T>::Frustum (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT
+{
+    set (nearPlane, farPlane, fovx, fovy, aspect);
+}
+
+template <class T> Frustum<T>::~Frustum() IMATH_NOEXCEPT
+{}
+
+template <class T>
+IMATH_CONSTEXPR14 inline const Frustum<T>&
+Frustum<T>::operator= (const Frustum& f) IMATH_NOEXCEPT
+{
+    _nearPlane    = f._nearPlane;
+    _farPlane     = f._farPlane;
+    _left         = f._left;
+    _right        = f._right;
+    _top          = f._top;
+    _bottom       = f._bottom;
+    _orthographic = f._orthographic;
+
+    return *this;
+}
+
+template <class T>
+constexpr inline bool
+Frustum<T>::operator== (const Frustum<T>& src) const IMATH_NOEXCEPT
+{
+    return _nearPlane == src._nearPlane && _farPlane == src._farPlane && _left == src._left &&
+           _right == src._right && _top == src._top && _bottom == src._bottom &&
+           _orthographic == src._orthographic;
+}
+
+template <class T>
+constexpr inline bool
+Frustum<T>::operator!= (const Frustum<T>& src) const IMATH_NOEXCEPT
+{
+    return !operator== (src);
+}
+
+template <class T>
+inline void
+Frustum<T>::set (T n, T f, T l, T r, T t, T b, bool o) IMATH_NOEXCEPT
+{
+    _nearPlane    = n;
+    _farPlane     = f;
+    _left         = l;
+    _right        = r;
+    _bottom       = b;
+    _top          = t;
+    _orthographic = o;
+}
+
+template <class T>
+inline void
+Frustum<T>::modifyNearAndFar (T n, T f) IMATH_NOEXCEPT
+{
+    if (_orthographic)
+    {
+        _nearPlane = n;
+    }
+    else
+    {
+        Line3<T> lowerLeft (Vec3<T> (0, 0, 0), Vec3<T> (_left, _bottom, -_nearPlane));
+        Line3<T> upperRight (Vec3<T> (0, 0, 0), Vec3<T> (_right, _top, -_nearPlane));
+        Plane3<T> nearPlane (Vec3<T> (0, 0, -1), n);
+
+        Vec3<T> ll = Vec3<T> (0, 0, 0);
+        Vec3<T> ur = Vec3<T> (0, 0, 0);
+        nearPlane.intersect (lowerLeft, ll);
+        nearPlane.intersect (upperRight, ur);
+
+        _left      = ll.x;
+        _right     = ur.x;
+        _top       = ur.y;
+        _bottom    = ll.y;
+        _nearPlane = n;
+        _farPlane  = f;
+    }
+
+    _farPlane = f;
+}
+
+template <class T>
+inline void
+Frustum<T>::setOrthographic (bool ortho) IMATH_NOEXCEPT
+{
+    _orthographic = ortho;
+}
+
+template <class T>
+inline void
+Frustum<T>::setExc (T nearPlane, T farPlane, T fovx, T fovy, T aspect)
+{
+    if (fovx != T (0) && fovy != T (0))
+        throw std::domain_error ("fovx and fovy cannot both be non-zero.");
+
+    const T two = static_cast<T> (2);
+
+    if (fovx != T (0))
+    {
+        _right  = nearPlane * std::tan (fovx / two);
+        _left   = -_right;
+        _top    = ((_right - _left) / aspect) / two;
+        _bottom = -_top;
+    }
+    else
+    {
+        _top    = nearPlane * std::tan (fovy / two);
+        _bottom = -_top;
+        _right  = (_top - _bottom) * aspect / two;
+        _left   = -_right;
+    }
+    _nearPlane    = nearPlane;
+    _farPlane     = farPlane;
+    _orthographic = false;
+}
+
+template <class T>
+inline void
+Frustum<T>::set (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT
+{
+    const T two = static_cast<T> (2);
+
+    if (fovx != T (0))
+    {
+        _right  = nearPlane * std::tan (fovx / two);
+        _left   = -_right;
+        _top    = ((_right - _left) / aspect) / two;
+        _bottom = -_top;
+    }
+    else
+    {
+        _top    = nearPlane * std::tan (fovy / two);
+        _bottom = -_top;
+        _right  = (_top - _bottom) * aspect / two;
+        _left   = -_right;
+    }
+    _nearPlane    = nearPlane;
+    _farPlane     = farPlane;
+    _orthographic = false;
+}
+
+template <class T>
+constexpr inline T
+Frustum<T>::fovx() const IMATH_NOEXCEPT
+{
+    return std::atan2 (_right, _nearPlane) - std::atan2 (_left, _nearPlane);
+}
+
+template <class T>
+constexpr inline T
+Frustum<T>::fovy() const IMATH_NOEXCEPT
+{
+    return std::atan2 (_top, _nearPlane) - std::atan2 (_bottom, _nearPlane);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline T
+Frustum<T>::aspectExc() const
+{
+    T rightMinusLeft = _right - _left;
+    T topMinusBottom = _top - _bottom;
+
+    if (abs (topMinusBottom) < T (1) && abs (rightMinusLeft) > std::numeric_limits<T>::max() * abs (topMinusBottom))
+    {
+        throw std::domain_error ("Bad viewing frustum: "
+                                 "aspect ratio cannot be computed.");
+    }
+
+    return rightMinusLeft / topMinusBottom;
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline T
+Frustum<T>::aspect() const IMATH_NOEXCEPT
+{
+    T rightMinusLeft = _right - _left;
+    T topMinusBottom = _top - _bottom;
+    return rightMinusLeft / topMinusBottom;
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline Matrix44<T>
+Frustum<T>::projectionMatrixExc() const
+{
+    T rightPlusLeft  = _right + _left;
+    T rightMinusLeft = _right - _left;
+
+    T topPlusBottom  = _top + _bottom;
+    T topMinusBottom = _top - _bottom;
+
+    T farPlusNear  = _farPlane + _nearPlane;
+    T farMinusNear = _farPlane - _nearPlane;
+
+    if ((abs (rightMinusLeft) < T (1) &&
+         abs (rightPlusLeft) > std::numeric_limits<T>::max() * abs (rightMinusLeft)) ||
+        (abs (topMinusBottom) < T (1) &&
+         abs (topPlusBottom) > std::numeric_limits<T>::max() * abs (topMinusBottom)) ||
+        (abs (farMinusNear) < 1 && abs (farPlusNear) > std::numeric_limits<T>::max() * abs (farMinusNear)))
+    {
+        throw std::domain_error ("Bad viewing frustum: "
+                                 "projection matrix cannot be computed.");
+    }
+
+    if (_orthographic)
+    {
+        T tx = -rightPlusLeft / rightMinusLeft;
+        T ty = -topPlusBottom / topMinusBottom;
+        T tz = -farPlusNear / farMinusNear;
+
+        if ((abs (rightMinusLeft) < T (1) && T (2) > std::numeric_limits<T>::max() * abs (rightMinusLeft)) ||
+            (abs (topMinusBottom) < T (1) && T (2) > std::numeric_limits<T>::max() * abs (topMinusBottom)) ||
+            (abs (farMinusNear) < T (1) && T (2) > std::numeric_limits<T>::max() * abs (farMinusNear)))
+        {
+            throw std::domain_error ("Bad viewing frustum: "
+                                     "projection matrix cannot be computed.");
+        }
+
+        T A = T (2) / rightMinusLeft;
+        T B = T (2) / topMinusBottom;
+        T C = T (-2) / farMinusNear;
+
+        return Matrix44<T> (A, 0, 0, 0, 0, B, 0, 0, 0, 0, C, 0, tx, ty, tz, 1.f);
+    }
+    else
+    {
+        T A = rightPlusLeft / rightMinusLeft;
+        T B = topPlusBottom / topMinusBottom;
+        T C = -farPlusNear / farMinusNear;
+
+        T farTimesNear = T (-2) * _farPlane * _nearPlane;
+        if (abs (farMinusNear) < T (1) && abs (farTimesNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
+        {
+            throw std::domain_error ("Bad viewing frustum: "
+                                     "projection matrix cannot be computed.");
+        }
+
+        T D = farTimesNear / farMinusNear;
+
+        T twoTimesNear = T (2) * _nearPlane;
+
+        if ((abs (rightMinusLeft) < T (1) &&
+             abs (twoTimesNear) > std::numeric_limits<T>::max() * abs (rightMinusLeft)) ||
+            (abs (topMinusBottom) < T (1) &&
+             abs (twoTimesNear) > std::numeric_limits<T>::max() * abs (topMinusBottom)))
+        {
+            throw std::domain_error ("Bad viewing frustum: "
+                                     "projection matrix cannot be computed.");
+        }
+
+        T E = twoTimesNear / rightMinusLeft;
+        T F = twoTimesNear / topMinusBottom;
+
+        return Matrix44<T> (E, 0, 0, 0, 0, F, 0, 0, A, B, C, -1, 0, 0, D, 0);
+    }
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline Matrix44<T>
+Frustum<T>::projectionMatrix() const IMATH_NOEXCEPT
+{
+    T rightPlusLeft  = _right + _left;
+    T rightMinusLeft = _right - _left;
+
+    T topPlusBottom  = _top + _bottom;
+    T topMinusBottom = _top - _bottom;
+
+    T farPlusNear  = _farPlane + _nearPlane;
+    T farMinusNear = _farPlane - _nearPlane;
+
+    if (_orthographic)
+    {
+        T tx = -rightPlusLeft / rightMinusLeft;
+        T ty = -topPlusBottom / topMinusBottom;
+        T tz = -farPlusNear / farMinusNear;
+
+        T A = T (2) / rightMinusLeft;
+        T B = T (2) / topMinusBottom;
+        T C = T (-2) / farMinusNear;
+
+        return Matrix44<T> (A, 0, 0, 0, 0, B, 0, 0, 0, 0, C, 0, tx, ty, tz, 1.f);
+    }
+    else
+    {
+        T A = rightPlusLeft / rightMinusLeft;
+        T B = topPlusBottom / topMinusBottom;
+        T C = -farPlusNear / farMinusNear;
+
+        T farTimesNear = T (-2) * _farPlane * _nearPlane;
+
+        T D = farTimesNear / farMinusNear;
+
+        T twoTimesNear = T (2) * _nearPlane;
+
+        T E = twoTimesNear / rightMinusLeft;
+        T F = twoTimesNear / topMinusBottom;
+
+        return Matrix44<T> (E, 0, 0, 0, 0, F, 0, 0, A, B, C, -1, 0, 0, D, 0);
+    }
+}
+
+template <class T>
+constexpr inline bool
+Frustum<T>::degenerate() const IMATH_NOEXCEPT
+{
+    return (_nearPlane == _farPlane) || (_left == _right) || (_top == _bottom);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline Frustum<T>
+Frustum<T>::window (T l, T r, T t, T b) const IMATH_NOEXCEPT
+{
+    // move it to 0->1 space
+
+    Vec2<T> bl = screenToLocal (Vec2<T> (l, b));
+    Vec2<T> tr = screenToLocal (Vec2<T> (r, t));
+
+    return Frustum<T> (_nearPlane, _farPlane, bl.x, tr.x, tr.y, bl.y, _orthographic);
+}
+
+template <class T>
+constexpr inline Vec2<T>
+Frustum<T>::screenToLocal (const Vec2<T>& s) const IMATH_NOEXCEPT
+{
+    return Vec2<T> (_left + (_right - _left) * (1.f + s.x) / 2.f,
+                    _bottom + (_top - _bottom) * (1.f + s.y) / 2.f);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline Vec2<T>
+Frustum<T>::localToScreenExc (const Vec2<T>& p) const
+{
+    T leftPlusRight  = _left - T (2) * p.x + _right;
+    T leftMinusRight = _left - _right;
+    T bottomPlusTop  = _bottom - T (2) * p.y + _top;
+    T bottomMinusTop = _bottom - _top;
+
+    if ((abs (leftMinusRight) < T (1) &&
+         abs (leftPlusRight) > std::numeric_limits<T>::max() * abs (leftMinusRight)) ||
+        (abs (bottomMinusTop) < T (1) &&
+         abs (bottomPlusTop) > std::numeric_limits<T>::max() * abs (bottomMinusTop)))
+    {
+        throw std::domain_error ("Bad viewing frustum: "
+                                 "local-to-screen transformation cannot be computed");
+    }
+
+    return Vec2<T> (leftPlusRight / leftMinusRight, bottomPlusTop / bottomMinusTop);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline Vec2<T>
+Frustum<T>::localToScreen (const Vec2<T>& p) const IMATH_NOEXCEPT
+{
+    T leftPlusRight  = _left - T (2) * p.x + _right;
+    T leftMinusRight = _left - _right;
+    T bottomPlusTop  = _bottom - T (2) * p.y + _top;
+    T bottomMinusTop = _bottom - _top;
+
+    return Vec2<T> (leftPlusRight / leftMinusRight, bottomPlusTop / bottomMinusTop);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline Line3<T>
+Frustum<T>::projectScreenToRay (const Vec2<T>& p) const IMATH_NOEXCEPT
+{
+    Vec2<T> point = screenToLocal (p);
+    if (orthographic())
+        return Line3<T> (Vec3<T> (point.x, point.y, 0.0), Vec3<T> (point.x, point.y, -1.0));
+    else
+        return Line3<T> (Vec3<T> (0, 0, 0), Vec3<T> (point.x, point.y, -_nearPlane));
+}
+
+template <class T>
+IMATH_CONSTEXPR14 Vec2<T>
+Frustum<T>::projectPointToScreenExc (const Vec3<T>& point) const
+{
+    if (orthographic() || point.z == T (0))
+        return localToScreenExc (Vec2<T> (point.x, point.y));
+    else
+        return localToScreenExc (
+            Vec2<T> (point.x * _nearPlane / -point.z, point.y * _nearPlane / -point.z));
+}
+
+template <class T>
+IMATH_CONSTEXPR14 Vec2<T>
+Frustum<T>::projectPointToScreen (const Vec3<T>& point) const IMATH_NOEXCEPT
+{
+    if (orthographic() || point.z == T (0))
+        return localToScreen (Vec2<T> (point.x, point.y));
+    else
+        return localToScreen (
+            Vec2<T> (point.x * _nearPlane / -point.z, point.y * _nearPlane / -point.z));
+}
+
+template <class T>
+IMATH_CONSTEXPR14 T
+Frustum<T>::ZToDepthExc (long zval, long zmin, long zmax) const
+{
+    int zdiff = zmax - zmin;
+
+    if (zdiff == 0)
+    {
+        throw std::domain_error ("Bad call to Frustum::ZToDepth: zmax == zmin");
+    }
+
+    if (zval > zmax + 1)
+        zval -= zdiff;
+
+    T fzval = (T (zval) - T (zmin)) / T (zdiff);
+    return normalizedZToDepthExc (fzval);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 T
+Frustum<T>::ZToDepth (long zval, long zmin, long zmax) const IMATH_NOEXCEPT
+{
+    int zdiff = zmax - zmin;
+
+    if (zval > zmax + 1)
+        zval -= zdiff;
+
+    T fzval = (T (zval) - T (zmin)) / T (zdiff);
+    return normalizedZToDepth (fzval);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 T
+Frustum<T>::normalizedZToDepthExc (T zval) const
+{
+    T Zp = zval * T (2) - T (1);
+
+    if (_orthographic)
+    {
+        return -(Zp * (_farPlane - _nearPlane) + (_farPlane + _nearPlane)) / T (2);
+    }
+    else
+    {
+        T farTimesNear = 2 * _farPlane * _nearPlane;
+        T farMinusNear = Zp * (_farPlane - _nearPlane) - _farPlane - _nearPlane;
+
+        if (abs (farMinusNear) < 1 && abs (farTimesNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
+        {
+            throw std::domain_error ("Frustum::normalizedZToDepth cannot be computed: "
+                                     "near and far clipping planes of the viewing frustum "
+                                     "may be too close to each other");
+        }
+
+        return farTimesNear / farMinusNear;
+    }
+}
+
+template <class T>
+IMATH_CONSTEXPR14 T
+Frustum<T>::normalizedZToDepth (T zval) const IMATH_NOEXCEPT
+{
+    T Zp = zval * T (2) - T (1);
+
+    if (_orthographic)
+    {
+        return -(Zp * (_farPlane - _nearPlane) + (_farPlane + _nearPlane)) / T (2);
+    }
+    else
+    {
+        T farTimesNear = 2 * _farPlane * _nearPlane;
+        T farMinusNear = Zp * (_farPlane - _nearPlane) - _farPlane - _nearPlane;
+
+        return farTimesNear / farMinusNear;
+    }
+}
+
+template <class T>
+IMATH_CONSTEXPR14 long
+Frustum<T>::DepthToZExc (T depth, long zmin, long zmax) const
+{
+    long zdiff     = zmax - zmin;
+    T farMinusNear = _farPlane - _nearPlane;
+
+    if (_orthographic)
+    {
+        T farPlusNear = T (2) * depth + _farPlane + _nearPlane;
+
+        if (abs (farMinusNear) < T (1) && abs (farPlusNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
+        {
+            throw std::domain_error ("Bad viewing frustum: "
+                                     "near and far clipping planes "
+                                     "are too close to each other");
+        }
+
+        T Zp = -farPlusNear / farMinusNear;
+        return long (0.5 * (Zp + 1) * zdiff) + zmin;
+    }
+    else
+    {
+        // Perspective
+
+        T farTimesNear = T (2) * _farPlane * _nearPlane;
+        if (abs (depth) < T (1) && abs (farTimesNear) > std::numeric_limits<T>::max() * abs (depth))
+        {
+            throw std::domain_error ("Bad call to DepthToZ function: "
+                                     "value of `depth' is too small");
+        }
+
+        T farPlusNear = farTimesNear / depth + _farPlane + _nearPlane;
+        if (abs (farMinusNear) < T (1) && abs (farPlusNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
+        {
+            throw std::domain_error ("Bad viewing frustum: "
+                                     "near and far clipping planes "
+                                     "are too close to each other");
+        }
+
+        T Zp = farPlusNear / farMinusNear;
+        return long (0.5 * (Zp + 1) * zdiff) + zmin;
+    }
+}
+
+template <class T>
+IMATH_CONSTEXPR14 long
+Frustum<T>::DepthToZ (T depth, long zmin, long zmax) const IMATH_NOEXCEPT
+{
+    long zdiff     = zmax - zmin;
+    T farMinusNear = _farPlane - _nearPlane;
+
+    if (_orthographic)
+    {
+        T farPlusNear = T (2) * depth + _farPlane + _nearPlane;
+
+        T Zp = -farPlusNear / farMinusNear;
+        return long (0.5 * (Zp + 1) * zdiff) + zmin;
+    }
+    else
+    {
+        // Perspective
+
+        T farTimesNear = T (2) * _farPlane * _nearPlane;
+
+        T farPlusNear = farTimesNear / depth + _farPlane + _nearPlane;
+
+        T Zp = farPlusNear / farMinusNear;
+        return long (0.5 * (Zp + 1) * zdiff) + zmin;
+    }
+}
+
+template <class T>
+IMATH_CONSTEXPR14 T
+Frustum<T>::screenRadiusExc (const Vec3<T>& p, T radius) const
+{
+    // Derivation:
+    // Consider X-Z plane.
+    // X coord of projection of p = xp = p.x * (-_nearPlane / p.z)
+    // Let q be p + (radius, 0, 0).
+    // X coord of projection of q = xq = (p.x - radius)  * (-_nearPlane / p.z)
+    // X coord of projection of segment from p to q = r = xp - xq
+    //         = radius * (-_nearPlane / p.z)
+    // A similar analysis holds in the Y-Z plane.
+    // So r is the quantity we want to return.
+
+    if (abs (p.z) > T (1) || abs (-_nearPlane) < std::numeric_limits<T>::max() * abs (p.z))
+    {
+        return radius * (-_nearPlane / p.z);
+    }
+    else
+    {
+        throw std::domain_error ("Bad call to Frustum::screenRadius: "
+                                 "magnitude of `p' is too small");
+    }
+
+    return radius * (-_nearPlane / p.z);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 T
+Frustum<T>::screenRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT
+{
+    // Derivation:
+    // Consider X-Z plane.
+    // X coord of projection of p = xp = p.x * (-_nearPlane / p.z)
+    // Let q be p + (radius, 0, 0).
+    // X coord of projection of q = xq = (p.x - radius)  * (-_nearPlane / p.z)
+    // X coord of projection of segment from p to q = r = xp - xq
+    //         = radius * (-_nearPlane / p.z)
+    // A similar analysis holds in the Y-Z plane.
+    // So r is the quantity we want to return.
+
+    return radius * (-_nearPlane / p.z);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 T
+Frustum<T>::worldRadiusExc (const Vec3<T>& p, T radius) const
+{
+    if (abs (-_nearPlane) > T (1) || abs (p.z) < std::numeric_limits<T>::max() * abs (-_nearPlane))
+    {
+        return radius * (p.z / -_nearPlane);
+    }
+    else
+    {
+        throw std::domain_error ("Bad viewing frustum: "
+                                 "near clipping plane is too close to zero");
+    }
+}
+
+template <class T>
+IMATH_CONSTEXPR14 T
+Frustum<T>::worldRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT
+{
+    return radius * (p.z / -_nearPlane);
+}
+
+template <class T>
+void
+Frustum<T>::planes (Plane3<T> p[6]) const IMATH_NOEXCEPT
+{
+    //
+    //        Plane order: Top, Right, Bottom, Left, Near, Far.
+    //  Normals point outwards.
+    //
+
+    if (!_orthographic)
+    {
+        Vec3<T> a (_left, _bottom, -_nearPlane);
+        Vec3<T> b (_left, _top, -_nearPlane);
+        Vec3<T> c (_right, _top, -_nearPlane);
+        Vec3<T> d (_right, _bottom, -_nearPlane);
+        Vec3<T> o (0, 0, 0);
+
+        p[0].set (o, c, b);
+        p[1].set (o, d, c);
+        p[2].set (o, a, d);
+        p[3].set (o, b, a);
+    }
+    else
+    {
+        p[0].set (Vec3<T> (0, 1, 0), _top);
+        p[1].set (Vec3<T> (1, 0, 0), _right);
+        p[2].set (Vec3<T> (0, -1, 0), -_bottom);
+        p[3].set (Vec3<T> (-1, 0, 0), -_left);
+    }
+    p[4].set (Vec3<T> (0, 0, 1), -_nearPlane);
+    p[5].set (Vec3<T> (0, 0, -1), _farPlane);
+}
+
+template <class T>
+void
+Frustum<T>::planes (Plane3<T> p[6], const Matrix44<T>& M) const IMATH_NOEXCEPT
+{
+    //
+    //  Plane order: Top, Right, Bottom, Left, Near, Far.
+    //  Normals point outwards.
+    //
+
+    Vec3<T> a = Vec3<T> (_left, _bottom, -_nearPlane) * M;
+    Vec3<T> b = Vec3<T> (_left, _top, -_nearPlane) * M;
+    Vec3<T> c = Vec3<T> (_right, _top, -_nearPlane) * M;
+    Vec3<T> d = Vec3<T> (_right, _bottom, -_nearPlane) * M;
+    if (!_orthographic)
+    {
+        double s    = _farPlane / double (_nearPlane);
+        T farLeft   = (T) (s * _left);
+        T farRight  = (T) (s * _right);
+        T farTop    = (T) (s * _top);
+        T farBottom = (T) (s * _bottom);
+        Vec3<T> e   = Vec3<T> (farLeft, farBottom, -_farPlane) * M;
+        Vec3<T> f   = Vec3<T> (farLeft, farTop, -_farPlane) * M;
+        Vec3<T> g   = Vec3<T> (farRight, farTop, -_farPlane) * M;
+        Vec3<T> o   = Vec3<T> (0, 0, 0) * M;
+        p[0].set (o, c, b);
+        p[1].set (o, d, c);
+        p[2].set (o, a, d);
+        p[3].set (o, b, a);
+        p[4].set (a, d, c);
+        p[5].set (e, f, g);
+    }
+    else
+    {
+        Vec3<T> e = Vec3<T> (_left, _bottom, -_farPlane) * M;
+        Vec3<T> f = Vec3<T> (_left, _top, -_farPlane) * M;
+        Vec3<T> g = Vec3<T> (_right, _top, -_farPlane) * M;
+        Vec3<T> h = Vec3<T> (_right, _bottom, -_farPlane) * M;
+        p[0].set (c, g, f);
+        p[1].set (d, h, g);
+        p[2].set (a, e, h);
+        p[3].set (b, f, e);
+        p[4].set (a, d, c);
+        p[5].set (e, f, g);
+    }
+}
+
+/// Frustum of type float
+typedef Frustum<float> Frustumf;
+
+/// Frustum of type double
+typedef Frustum<double> Frustumd;
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#if defined _WIN32 || defined _WIN64
+#    ifdef _redef_near
+#        define near
+#    endif
+#    ifdef _redef_far
+#        define far
+#    endif
+#endif
+
+#endif // INCLUDED_IMATHFRUSTUM_H
diff --git a/src/Imath/ImathFrustumTest.h b/src/Imath/ImathFrustumTest.h
new file mode 100644 (file)
index 0000000..3995ddb
--- /dev/null
@@ -0,0 +1,344 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// A viewing frustum class
+//
+// This file contains algorithms applied to or in conjunction with
+// Frustum visibility testing (Imath::Frustum).
+//
+// Methods for frustum-based rejection of primitives are contained here.
+//
+
+#ifndef INCLUDED_IMATHFRUSTUMTEST_H
+#define INCLUDED_IMATHFRUSTUMTEST_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include "ImathBox.h"
+#include "ImathFrustum.h"
+#include "ImathMatrix.h"
+#include "ImathSphere.h"
+#include "ImathVec.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// template class FrustumTest<T>
+///
+/// This is a helper class, designed to accelerate the case
+/// where many tests are made against the same frustum.
+/// That's a really common case.
+///
+/// The acceleration is achieved by pre-computing the planes of
+/// the frustum, along with the ablsolute values of the plane normals.
+///
+/// How to use this
+///
+/// Given that you already have:
+///    Imath::Frustum   myFrustum
+///    Imath::Matrix44  myCameraWorldMatrix
+///
+/// First, make a frustum test object:
+///    FrustumTest myFrustumTest(myFrustum, myCameraWorldMatrix)
+///
+/// Whenever the camera or frustum changes, call:
+///    myFrustumTest.setFrustum(myFrustum, myCameraWorldMatrix)
+///
+/// For each object you want to test for visibility, call:
+///    myFrustumTest.isVisible(myBox)
+///    myFrustumTest.isVisible(mySphere)
+///    myFrustumTest.isVisible(myVec3)
+///    myFrustumTest.completelyContains(myBox)
+///    myFrustumTest.completelyContains(mySphere)
+///
+/// Explanation of how it works
+///
+/// We store six world-space Frustum planes (nx, ny, nz, offset)
+///
+/// Points: To test a Vec3 for visibility, test it against each plane
+///         using the normal (v dot n - offset) method. (the result is exact)
+///
+/// BBoxes: To test an axis-aligned bbox, test the center against each plane
+///         using the normal (v dot n - offset) method, but offset by the
+///         box extents dot the abs of the plane normal. (the result is NOT
+///         exact, but will not return false-negatives.)
+///
+/// Spheres: To test a sphere, test the center against each plane
+///         using the normal (v dot n - offset) method, but offset by the
+///         sphere's radius. (the result is NOT exact, but will not return
+///         false-negatives.)
+///
+///
+/// SPECIAL NOTE: "Where are the dot products?"
+///     Actual dot products are currently slow for most SIMD architectures.
+///     In order to keep this code optimization-ready, the dot products
+///     are all performed using vector adds and multipies.
+///
+///     In order to do this, the plane equations are stored in "transpose"
+///     form, with the X components grouped into an X vector, etc.
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE FrustumTest
+{
+  public:
+    /// @{
+    /// @name Constructors
+
+    /// Initialize camera matrix to identity
+    FrustumTest() IMATH_NOEXCEPT
+    {
+        Frustum<T> frust;
+        Matrix44<T> cameraMat;
+        cameraMat.makeIdentity();
+        setFrustum (frust, cameraMat);
+    }
+
+    /// Initialize to a given frustum and camera matrix.
+    FrustumTest (const Frustum<T>& frustum, const Matrix44<T>& cameraMat) IMATH_NOEXCEPT
+    {
+        setFrustum (frustum, cameraMat);
+    }
+
+    /// @}
+
+    /// @{
+    /// @name Set Value
+    
+    /// Update the frustum test with a new frustum and matrix.
+    /// This should usually be called just once per frame, or however
+    /// often the camera moves.
+    void setFrustum (const Frustum<T>& frustum, const Matrix44<T>& cameraMat) IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Query
+    
+    /// Return true if any part of the sphere is inside the frustum.
+    /// The result MAY return close false-positives, but not false-negatives.
+    bool isVisible (const Sphere3<T>& sphere) const IMATH_NOEXCEPT;
+
+    /// Return true if any part of the box is inside the frustum.
+    /// The result MAY return close false-positives, but not false-negatives.
+    bool isVisible (const Box<Vec3<T>>& box) const IMATH_NOEXCEPT;
+
+    /// Return true if the point is inside the frustum.
+    bool isVisible (const Vec3<T>& vec) const IMATH_NOEXCEPT;
+
+    /// Return true if every part of the sphere is inside the frustum.
+    /// The result MAY return close false-negatives, but not false-positives.
+    bool completelyContains (const Sphere3<T>& sphere) const IMATH_NOEXCEPT;
+
+    /// Return true if every part of the box is inside the frustum.
+    /// The result MAY return close false-negatives, but not false-positives.
+    bool completelyContains (const Box<Vec3<T>>& box) const IMATH_NOEXCEPT;
+
+    /// Return the camera matrix (primarily for debugging)
+    IMATH_INTERNAL_NAMESPACE::Matrix44<T> cameraMat() const IMATH_NOEXCEPT { return cameraMatrix; }
+
+    /// Return the viewing frustum (primarily for debugging)
+    IMATH_INTERNAL_NAMESPACE::Frustum<T> currentFrustum() const IMATH_NOEXCEPT { return currFrustum; }
+
+    /// @}
+    
+  protected:
+
+    // To understand why the planes are stored this way, see
+    // the SPECIAL NOTE above.
+
+    /// @cond Doxygen_Suppress
+
+    Vec3<T> planeNormX[2]; // The X components from 6 plane equations
+    Vec3<T> planeNormY[2]; // The Y components from 6 plane equations
+    Vec3<T> planeNormZ[2]; // The Z components from 6 plane equations
+
+    Vec3<T> planeOffsetVec[2]; // The distance offsets from 6 plane equations
+
+    // The absolute values are stored to assist with bounding box tests.
+    Vec3<T> planeNormAbsX[2]; // The abs(X) components from 6 plane equations
+    Vec3<T> planeNormAbsY[2]; // The abs(X) components from 6 plane equations
+    Vec3<T> planeNormAbsZ[2]; // The abs(X) components from 6 plane equations
+
+    // These are kept primarily for debugging tools.
+    Frustum<T> currFrustum;
+    Matrix44<T> cameraMatrix;
+
+    /// @endcond
+};
+
+template <class T>
+void
+FrustumTest<T>::setFrustum (const Frustum<T>& frustum, const Matrix44<T>& cameraMat) IMATH_NOEXCEPT
+{
+    Plane3<T> frustumPlanes[6];
+    frustum.planes (frustumPlanes, cameraMat);
+
+    // Here's where we effectively transpose the plane equations.
+    // We stuff all six X's into the two planeNormX vectors, etc.
+    for (int i = 0; i < 2; ++i)
+    {
+        int index = i * 3;
+
+        planeNormX[i] = Vec3<T> (frustumPlanes[index + 0].normal.x,
+                                 frustumPlanes[index + 1].normal.x,
+                                 frustumPlanes[index + 2].normal.x);
+        planeNormY[i] = Vec3<T> (frustumPlanes[index + 0].normal.y,
+                                 frustumPlanes[index + 1].normal.y,
+                                 frustumPlanes[index + 2].normal.y);
+        planeNormZ[i] = Vec3<T> (frustumPlanes[index + 0].normal.z,
+                                 frustumPlanes[index + 1].normal.z,
+                                 frustumPlanes[index + 2].normal.z);
+
+        planeNormAbsX[i] = Vec3<T> (std::abs (planeNormX[i].x),
+                                    std::abs (planeNormX[i].y),
+                                    std::abs (planeNormX[i].z));
+        planeNormAbsY[i] = Vec3<T> (std::abs (planeNormY[i].x),
+                                    std::abs (planeNormY[i].y),
+                                    std::abs (planeNormY[i].z));
+        planeNormAbsZ[i] = Vec3<T> (std::abs (planeNormZ[i].x),
+                                    std::abs (planeNormZ[i].y),
+                                    std::abs (planeNormZ[i].z));
+
+        planeOffsetVec[i] = Vec3<T> (frustumPlanes[index + 0].distance,
+                                     frustumPlanes[index + 1].distance,
+                                     frustumPlanes[index + 2].distance);
+    }
+    currFrustum  = frustum;
+    cameraMatrix = cameraMat;
+}
+
+template <typename T>
+bool
+FrustumTest<T>::isVisible (const Sphere3<T>& sphere) const IMATH_NOEXCEPT
+{
+    Vec3<T> center    = sphere.center;
+    Vec3<T> radiusVec = Vec3<T> (sphere.radius, sphere.radius, sphere.radius);
+
+    // This is a vertical dot-product on three vectors at once.
+    Vec3<T> d0 = planeNormX[0] * center.x + planeNormY[0] * center.y + planeNormZ[0] * center.z -
+                 radiusVec - planeOffsetVec[0];
+
+    if (d0.x >= 0 || d0.y >= 0 || d0.z >= 0)
+        return false;
+
+    Vec3<T> d1 = planeNormX[1] * center.x + planeNormY[1] * center.y + planeNormZ[1] * center.z -
+                 radiusVec - planeOffsetVec[1];
+
+    if (d1.x >= 0 || d1.y >= 0 || d1.z >= 0)
+        return false;
+
+    return true;
+}
+
+template <typename T>
+bool
+FrustumTest<T>::completelyContains (const Sphere3<T>& sphere) const IMATH_NOEXCEPT
+{
+    Vec3<T> center    = sphere.center;
+    Vec3<T> radiusVec = Vec3<T> (sphere.radius, sphere.radius, sphere.radius);
+
+    // This is a vertical dot-product on three vectors at once.
+    Vec3<T> d0 = planeNormX[0] * center.x + planeNormY[0] * center.y + planeNormZ[0] * center.z +
+                 radiusVec - planeOffsetVec[0];
+
+    if (d0.x >= 0 || d0.y >= 0 || d0.z >= 0)
+        return false;
+
+    Vec3<T> d1 = planeNormX[1] * center.x + planeNormY[1] * center.y + planeNormZ[1] * center.z +
+                 radiusVec - planeOffsetVec[1];
+
+    if (d1.x >= 0 || d1.y >= 0 || d1.z >= 0)
+        return false;
+
+    return true;
+}
+
+template <typename T>
+bool
+FrustumTest<T>::isVisible (const Box<Vec3<T>>& box) const IMATH_NOEXCEPT
+{
+    if (box.isEmpty())
+        return false;
+
+    Vec3<T> center = (box.min + box.max) / 2;
+    Vec3<T> extent = (box.max - center);
+
+    // This is a vertical dot-product on three vectors at once.
+    Vec3<T> d0 = planeNormX[0] * center.x + planeNormY[0] * center.y + planeNormZ[0] * center.z -
+                 planeNormAbsX[0] * extent.x - planeNormAbsY[0] * extent.y -
+                 planeNormAbsZ[0] * extent.z - planeOffsetVec[0];
+
+    if (d0.x >= 0 || d0.y >= 0 || d0.z >= 0)
+        return false;
+
+    Vec3<T> d1 = planeNormX[1] * center.x + planeNormY[1] * center.y + planeNormZ[1] * center.z -
+                 planeNormAbsX[1] * extent.x - planeNormAbsY[1] * extent.y -
+                 planeNormAbsZ[1] * extent.z - planeOffsetVec[1];
+
+    if (d1.x >= 0 || d1.y >= 0 || d1.z >= 0)
+        return false;
+
+    return true;
+}
+
+template <typename T>
+bool
+FrustumTest<T>::completelyContains (const Box<Vec3<T>>& box) const IMATH_NOEXCEPT
+{
+    if (box.isEmpty())
+        return false;
+
+    Vec3<T> center = (box.min + box.max) / 2;
+    Vec3<T> extent = (box.max - center);
+
+    // This is a vertical dot-product on three vectors at once.
+    Vec3<T> d0 = planeNormX[0] * center.x + planeNormY[0] * center.y + planeNormZ[0] * center.z +
+                 planeNormAbsX[0] * extent.x + planeNormAbsY[0] * extent.y +
+                 planeNormAbsZ[0] * extent.z - planeOffsetVec[0];
+
+    if (d0.x >= 0 || d0.y >= 0 || d0.z >= 0)
+        return false;
+
+    Vec3<T> d1 = planeNormX[1] * center.x + planeNormY[1] * center.y + planeNormZ[1] * center.z +
+                 planeNormAbsX[1] * extent.x + planeNormAbsY[1] * extent.y +
+                 planeNormAbsZ[1] * extent.z - planeOffsetVec[1];
+
+    if (d1.x >= 0 || d1.y >= 0 || d1.z >= 0)
+        return false;
+
+    return true;
+}
+
+template <typename T>
+bool
+FrustumTest<T>::isVisible (const Vec3<T>& vec) const IMATH_NOEXCEPT
+{
+    // This is a vertical dot-product on three vectors at once.
+    Vec3<T> d0 = (planeNormX[0] * vec.x) + (planeNormY[0] * vec.y) + (planeNormZ[0] * vec.z) -
+                 planeOffsetVec[0];
+
+    if (d0.x >= 0 || d0.y >= 0 || d0.z >= 0)
+        return false;
+
+    Vec3<T> d1 = (planeNormX[1] * vec.x) + (planeNormY[1] * vec.y) + (planeNormZ[1] * vec.z) -
+                 planeOffsetVec[1];
+
+    if (d1.x >= 0 || d1.y >= 0 || d1.z >= 0)
+        return false;
+
+    return true;
+}
+
+/// FrustymTest of type float
+typedef FrustumTest<float> FrustumTestf;
+
+/// FrustymTest of type double
+typedef FrustumTest<double> FrustumTestd;
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHFRUSTUMTEST_H
diff --git a/src/Imath/ImathFun.cpp b/src/Imath/ImathFun.cpp
new file mode 100644 (file)
index 0000000..7479936
--- /dev/null
@@ -0,0 +1,162 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#include "ImathFun.h"
+
+IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+float
+succf (float f) IMATH_NOEXCEPT
+{
+    union
+    {
+        float f;
+        uint32_t i;
+    } u;
+    u.f = f;
+
+    if (isinf(f) || isnan (f))
+    {
+        // Nan or infinity; don't change value.
+    }
+    else if (u.i == 0x00000000 || u.i == 0x80000000)
+    {
+        // Plus or minus zero.
+
+        u.i = 0x00000001;
+    }
+    else if (u.f > 0)
+    {
+        // Positive float, normalized or denormalized.
+        // Incrementing the largest positive float
+        // produces +infinity.
+
+        ++u.i;
+    }
+    else
+    {
+        // Negative normalized or denormalized float.
+
+        --u.i;
+    }
+
+    return u.f;
+}
+
+float
+predf (float f) IMATH_NOEXCEPT
+{
+    union
+    {
+        float f;
+        uint32_t i;
+    } u;
+    u.f = f;
+
+    if (isinf(f) || isnan (f))
+    {
+        // Nan or infinity; don't change value.
+    }
+    else if (u.i == 0x00000000 || u.i == 0x80000000)
+    {
+        // Plus or minus zero.
+
+        u.i = 0x80000001;
+    }
+    else if (u.f > 0)
+    {
+        // Positive float, normalized or denormalized.
+
+        --u.i;
+    }
+    else
+    {
+        // Negative normalized or denormalized float.
+        // Decrementing the largest negative float
+        // produces -infinity.
+
+        ++u.i;
+    }
+
+    return u.f;
+}
+
+double
+succd (double d) IMATH_NOEXCEPT
+{
+    union
+    {
+        double d;
+        uint64_t i;
+    } u;
+    u.d = d;
+
+    if (isinf(d) || isnan (d))
+    {
+        // Nan or infinity; don't change value.
+    }
+    else if (u.i == 0x0000000000000000LL || u.i == 0x8000000000000000LL)
+    {
+        // Plus or minus zero.
+
+        u.i = 0x0000000000000001LL;
+    }
+    else if (u.d > 0)
+    {
+        // Positive double, normalized or denormalized.
+        // Incrementing the largest positive double
+        // produces +infinity.
+
+        ++u.i;
+    }
+    else
+    {
+        // Negative normalized or denormalized double.
+
+        --u.i;
+    }
+
+    return u.d;
+}
+
+double
+predd (double d) IMATH_NOEXCEPT
+{
+    union
+    {
+        double d;
+        uint64_t i;
+    } u;
+    u.d = d;
+
+    if ((u.i & 0x7ff0000000000000LL) == 0x7ff0000000000000LL)
+    {
+        // Nan or infinity; don't change value.
+    }
+    else if (u.i == 0x0000000000000000LL || u.i == 0x8000000000000000LL)
+    {
+        // Plus or minus zero.
+
+        u.i = 0x8000000000000001LL;
+    }
+    else if (u.d > 0)
+    {
+        // Positive double, normalized or denormalized.
+
+        --u.i;
+    }
+    else
+    {
+        // Negative normalized or denormalized double.
+        // Decrementing the largest negative double
+        // produces -infinity.
+
+        ++u.i;
+    }
+
+    return u.d;
+}
+
+IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT
diff --git a/src/Imath/ImathFun.h b/src/Imath/ImathFun.h
new file mode 100644 (file)
index 0000000..938d0cf
--- /dev/null
@@ -0,0 +1,231 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifndef INCLUDED_IMATHFUN_H
+#define INCLUDED_IMATHFUN_H
+
+//-----------------------------------------------------------------------------
+//
+//     Miscellaneous utility functions
+//
+//-----------------------------------------------------------------------------
+
+#include <limits>
+#include <cstdint>
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+#include "ImathPlatform.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+abs (T a) IMATH_NOEXCEPT
+{
+    return (a > T (0)) ? a : -a;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline int
+sign (T a) IMATH_NOEXCEPT
+{
+    return (a > T (0)) ? 1 : ((a < T (0)) ? -1 : 0);
+}
+
+template <class T, class Q>
+IMATH_HOSTDEVICE constexpr inline T
+lerp (T a, T b, Q t) IMATH_NOEXCEPT
+{
+    return (T) (a * (1 - t) + b * t);
+}
+
+template <class T, class Q>
+IMATH_HOSTDEVICE constexpr inline T
+ulerp (T a, T b, Q t) IMATH_NOEXCEPT
+{
+    return (T) ((a > b) ? (a - (a - b) * t) : (a + (b - a) * t));
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+lerpfactor (T m, T a, T b) IMATH_NOEXCEPT
+{
+    //
+    // Return how far m is between a and b, that is return t such that
+    // if:
+    //     t = lerpfactor(m, a, b);
+    // then:
+    //     m = lerp(a, b, t);
+    //
+    // If a==b, return 0.
+    //
+
+    T d = b - a;
+    T n = m - a;
+
+    if (abs (d) > T (1) || abs (n) < std::numeric_limits<T>::max() * abs (d))
+        return n / d;
+
+    return T (0);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+clamp (T a, T l, T h) IMATH_NOEXCEPT
+{
+    return (a < l) ? l : ((a > h) ? h : a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline int
+cmp (T a, T b) IMATH_NOEXCEPT
+{
+    return IMATH_INTERNAL_NAMESPACE::sign (a - b);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline int
+cmpt (T a, T b, T t) IMATH_NOEXCEPT
+{
+    return (IMATH_INTERNAL_NAMESPACE::abs (a - b) <= t) ? 0 : cmp (a, b);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+iszero (T a, T t) IMATH_NOEXCEPT
+{
+    return (IMATH_INTERNAL_NAMESPACE::abs (a) <= t) ? 1 : 0;
+}
+
+template <class T1, class T2, class T3>
+IMATH_HOSTDEVICE constexpr inline bool
+equal (T1 a, T2 b, T3 t) IMATH_NOEXCEPT
+{
+    return IMATH_INTERNAL_NAMESPACE::abs (a - b) <= t;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline int
+floor (T x) IMATH_NOEXCEPT
+{
+    return (x >= 0) ? int (x) : -(int (-x) + (-x > int (-x)));
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline int
+ceil (T x) IMATH_NOEXCEPT
+{
+    return -floor (-x);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline int
+trunc (T x) IMATH_NOEXCEPT
+{
+    return (x >= 0) ? int (x) : -int (-x);
+}
+
+//
+// Integer division and remainder where the
+// remainder of x/y has the same sign as x:
+//
+//     divs(x,y) == (abs(x) / abs(y)) * (sign(x) * sign(y))
+//     mods(x,y) == x - y * divs(x,y)
+//
+
+IMATH_HOSTDEVICE constexpr inline int
+divs (int x, int y) IMATH_NOEXCEPT
+{
+    return (x >= 0) ? ((y >= 0) ? (x / y) : -(x / -y)) : ((y >= 0) ? -(-x / y) : (-x / -y));
+}
+
+IMATH_HOSTDEVICE constexpr inline int
+mods (int x, int y) IMATH_NOEXCEPT
+{
+    return (x >= 0) ? ((y >= 0) ? (x % y) : (x % -y)) : ((y >= 0) ? -(-x % y) : -(-x % -y));
+}
+
+//
+// Integer division and remainder where the
+// remainder of x/y is always positive:
+//
+//     divp(x,y) == floor (double(x) / double (y))
+//     modp(x,y) == x - y * divp(x,y)
+//
+
+IMATH_HOSTDEVICE constexpr inline int
+divp (int x, int y) IMATH_NOEXCEPT
+{
+    return (x >= 0) ? ((y >= 0) ? (x / y) : -(x / -y))
+                    : ((y >= 0) ? -((y - 1 - x) / y) : ((-y - 1 - x) / -y));
+}
+
+IMATH_HOSTDEVICE constexpr inline int
+modp (int x, int y) IMATH_NOEXCEPT
+{
+    return x - y * divp (x, y);
+}
+
+//----------------------------------------------------------
+// Successor and predecessor for floating-point numbers:
+//
+// succf(f)     returns float(f+e), where e is the smallest
+//              positive number such that float(f+e) != f.
+//
+// predf(f)     returns float(f-e), where e is the smallest
+//              positive number such that float(f-e) != f.
+//
+// succd(d)     returns double(d+e), where e is the smallest
+//              positive number such that double(d+e) != d.
+//
+// predd(d)     returns double(d-e), where e is the smallest
+//              positive number such that double(d-e) != d.
+//
+// Exceptions:  If the input value is an infinity or a nan,
+//              succf(), predf(), succd(), and predd() all
+//              return the input value without changing it.
+//
+//----------------------------------------------------------
+
+IMATH_EXPORT float succf (float f) IMATH_NOEXCEPT;
+IMATH_EXPORT float predf (float f) IMATH_NOEXCEPT;
+
+IMATH_EXPORT double succd (double d) IMATH_NOEXCEPT;
+IMATH_EXPORT double predd (double d) IMATH_NOEXCEPT;
+
+//
+// Return true if the number is not a NaN or Infinity.
+//
+
+IMATH_HOSTDEVICE inline bool
+finitef (float f) IMATH_NOEXCEPT
+{
+    union
+    {
+        float f;
+        int i;
+    } u;
+    u.f = f;
+
+    return (u.i & 0x7f800000) != 0x7f800000;
+}
+
+IMATH_HOSTDEVICE inline bool
+finited (double d) IMATH_NOEXCEPT
+{
+    union
+    {
+        double d;
+        uint64_t i;
+    } u;
+    u.d = d;
+
+    return (u.i & 0x7ff0000000000000LL) != 0x7ff0000000000000LL;
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHFUN_H
diff --git a/src/Imath/ImathGL.h b/src/Imath/ImathGL.h
new file mode 100644 (file)
index 0000000..e38fe65
--- /dev/null
@@ -0,0 +1,176 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Convenience functions that call GL with Imath types
+//
+
+#ifndef INCLUDED_IMATHGL_H
+#define INCLUDED_IMATHGL_H
+
+#include <GL/gl.h>
+
+#include "ImathFun.h"
+#include "ImathMatrix.h"
+#include "ImathNamespace.h"
+#include "ImathVec.h"
+
+/// Call glVertex3f
+inline void
+glVertex (const IMATH_INTERNAL_NAMESPACE::V3f& v)
+{
+    glVertex3f (v.x, v.y, v.z);
+}
+
+/// Call glVertex2f
+inline void
+glVertex (const IMATH_INTERNAL_NAMESPACE::V2f& v)
+{
+    glVertex2f (v.x, v.y);
+}
+
+/// Call glNormal3f
+inline void
+glNormal (const IMATH_INTERNAL_NAMESPACE::V3f& n)
+{
+    glNormal3f (n.x, n.y, n.z);
+}
+
+/// Call glColor3f
+inline void
+glColor (const IMATH_INTERNAL_NAMESPACE::V3f& c)
+{
+    glColor3f (c.x, c.y, c.z);
+}
+
+/// Call glTranslatef
+inline void
+glTranslate (const IMATH_INTERNAL_NAMESPACE::V3f& t)
+{
+    glTranslatef (t.x, t.y, t.z);
+}
+
+/// Call glTexCoord2f
+inline void
+glTexCoord (const IMATH_INTERNAL_NAMESPACE::V2f& t)
+{
+    glTexCoord2f (t.x, t.y);
+}
+
+/// Disable GL textures
+inline void
+glDisableTexture()
+{
+    glActiveTexture (GL_TEXTURE1);
+    glBindTexture (GL_TEXTURE_2D, 0);
+    glDisable (GL_TEXTURE_2D);
+
+    glActiveTexture (GL_TEXTURE0);
+}
+
+namespace
+{
+
+const float GL_FLOAT_MAX = 1.8e+19; // sqrt (FLT_MAX)
+
+inline bool
+badFloat (float f)
+{
+    return !IMATH_INTERNAL_NAMESPACE::finitef (f) || f < -GL_FLOAT_MAX || f > GL_FLOAT_MAX;
+}
+
+} // namespace
+
+/// Throw an exception if m is not a valid matrix for GL
+inline void
+throwBadMatrix (const IMATH_INTERNAL_NAMESPACE::M44f& m)
+{
+    if (badFloat (m[0][0]) || badFloat (m[0][1]) || badFloat (m[0][2]) || badFloat (m[0][3]) ||
+        badFloat (m[1][0]) || badFloat (m[1][1]) || badFloat (m[1][2]) || badFloat (m[1][3]) ||
+        badFloat (m[2][0]) || badFloat (m[2][1]) || badFloat (m[2][2]) || badFloat (m[2][3]) ||
+        badFloat (m[3][0]) || badFloat (m[3][1]) || badFloat (m[3][2]) || badFloat (m[3][3]))
+        throw std::invalid_argument ("GL matrix overflow");
+}
+
+/// Call glMultmatrixf. Throw an exception if m is not a valid matrix for GL.
+inline void
+glMultMatrix (const IMATH_INTERNAL_NAMESPACE::M44f& m)
+{
+    throwBadMatrix (m);
+    glMultMatrixf ((GLfloat*) m[0]);
+}
+
+/// Call glMultmatrixf. Throw an exception if m is not a valid matrix for GL.
+inline void
+glMultMatrix (const IMATH_INTERNAL_NAMESPACE::M44f* m)
+{
+    throwBadMatrix (*m);
+    glMultMatrixf ((GLfloat*) (*m)[0]);
+}
+
+/// Call glLoadmatrixf. Throw an exception if m is not a valid matrix for GL.
+inline void
+glLoadMatrix (const IMATH_INTERNAL_NAMESPACE::M44f& m)
+{
+    throwBadMatrix (m);
+    glLoadMatrixf ((GLfloat*) m[0]);
+}
+
+/// Call glLoadmatrixf. Throw an exception if m is not a valid matrix for GL.
+inline void
+glLoadMatrix (const IMATH_INTERNAL_NAMESPACE::M44f* m)
+{
+    throwBadMatrix (*m);
+    glLoadMatrixf ((GLfloat*) (*m)[0]);
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// A class object that pushes/pops the GL matrix. This object assists with
+/// proper cleanup of the state when exceptions are thrown.
+///
+
+class GLPushMatrix
+{
+  public:
+    GLPushMatrix() { glPushMatrix(); }
+    ~GLPushMatrix() { glPopMatrix(); }
+};
+
+///
+/// A class object that pushes/pops the current GL attribute state. This object assists with
+/// proper cleanup of the state when exceptions are thrown.
+///
+
+class GLPushAttrib
+{
+  public:
+    /// call glPushAttrib()
+    GLPushAttrib (GLbitfield mask) { glPushAttrib (mask); }
+
+    /// call glPopAttrib()
+    ~GLPushAttrib() { glPopAttrib(); }
+};
+
+///
+/// A class object that wraps glBegin/glEnd. The constructor calls
+/// glBegin(). The destructor calls glEnd().
+///
+
+class GLBegin
+{
+  public:
+
+    /// Call glBegin()
+    GLBegin (GLenum mode) { glBegin (mode); }
+
+    /// Call glEnd()
+    ~GLBegin() { glEnd(); }
+};
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
diff --git a/src/Imath/ImathGLU.h b/src/Imath/ImathGLU.h
new file mode 100644 (file)
index 0000000..231da83
--- /dev/null
@@ -0,0 +1,27 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Convenience functions that call GLU with Imath types
+//
+
+#ifndef INCLUDED_IMATHGLU_H
+#define INCLUDED_IMATHGLU_H
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+#include "ImathVec.h"
+
+/// Call gluLookAt with the given position, interest, and up-vector.
+inline void
+gluLookAt (const IMATH_INTERNAL_NAMESPACE::V3f& pos,
+           const IMATH_INTERNAL_NAMESPACE::V3f& interest,
+           const IMATH_INTERNAL_NAMESPACE::V3f& up)
+{
+    gluLookAt (pos.x, pos.y, pos.z, interest.x, interest.y, interest.z, up.x, up.y, up.z);
+}
+
+#endif
diff --git a/src/Imath/ImathInt64.h b/src/Imath/ImathInt64.h
new file mode 100644 (file)
index 0000000..258b147
--- /dev/null
@@ -0,0 +1,45 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// 64-bit integer types
+//
+// Deprecated, use int64_t/uint64_t instead.
+//
+
+#ifndef INCLUDED_IMATH_INT64_H
+#define INCLUDED_IMATH_INT64_H
+
+#include "ImathNamespace.h"
+#include <limits.h>
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+#if (defined _WIN32 || defined _WIN64) && _MSC_VER >= 1300
+/// Int64 - unsigned 64-bit integer
+IMATH_DEPRECATED("use uint64_t")
+typedef unsigned __int64 Int64;
+/// SInt64 - signed 64-bit integer
+IMATH_DEPRECATED("use sint64_t")
+typedef __int64 SInt64;
+#elif ULONG_MAX == 18446744073709551615LU
+/// Int64 - unsigned 64-bit integer
+IMATH_DEPRECATED("use uint64_t")
+typedef long unsigned int Int64;
+/// SInt64 - signed 64-bit integer
+IMATH_DEPRECATED("use sint64_t")
+typedef long int SInt64;
+#else
+/// Int64 - unsigned 64-bit integer
+IMATH_DEPRECATED("use uint64_t")
+typedef long long unsigned int Int64;
+/// SInt64 - signed 64-bit integer
+IMATH_DEPRECATED("use sint64_t")
+typedef long long int SInt64;
+#endif
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATH_INT64_H
diff --git a/src/Imath/ImathInterval.h b/src/Imath/ImathInterval.h
new file mode 100644 (file)
index 0000000..ae483a4
--- /dev/null
@@ -0,0 +1,267 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// An interval class
+//
+
+#ifndef INCLUDED_IMATHINTERVAL_H
+#define INCLUDED_IMATHINTERVAL_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include "ImathVec.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// An Interval has a min and a max and some miscellaneous
+/// functions. It is basically a Box<T> that allows T to be a scalar.
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Interval
+{
+  public:
+
+    /// @{
+    /// @name Direct access to bounds
+    
+    /// The minimum value of the interval
+    T min;
+
+    /// The minimum value of the interval
+    T max;
+
+    /// @}
+    
+    /// @{
+    /// @name Constructors
+
+    /// Initialize to the empty interval
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Interval() IMATH_NOEXCEPT;
+
+    /// Intitialize to a single point
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Interval (const T& point) IMATH_NOEXCEPT;
+
+    /// Intitialize to a given (min,max)
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Interval (const T& minT, const T& maxT) IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Comparison
+
+    /// Equality
+    IMATH_HOSTDEVICE constexpr bool operator== (const Interval<T>& src) const IMATH_NOEXCEPT;
+    /// Inequality
+    IMATH_HOSTDEVICE constexpr bool operator!= (const Interval<T>& src) const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Manipulation
+
+    /// Set the interval to be empty. An interval is empty if the
+    /// minimum is greater than the maximum.
+    IMATH_HOSTDEVICE void makeEmpty() IMATH_NOEXCEPT;
+
+    /// Extend the interval to include the given point.
+    IMATH_HOSTDEVICE void extendBy (const T& point) IMATH_NOEXCEPT;
+
+    /// Extend the interval to include the given interval
+    IMATH_HOSTDEVICE void extendBy (const Interval<T>& interval) IMATH_NOEXCEPT;
+
+    /// Make the interval include the entire range of the base type.
+    IMATH_HOSTDEVICE void makeInfinite() IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    ///        @name Query
+
+    /// Return the size of the interval. The size is (max-min). An empty box has a size of 0.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T size() const IMATH_NOEXCEPT;
+
+    /// Return the center of the interval. The center is defined as
+    /// (max+min)/2. The center of an empty interval is undefined.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T center() const IMATH_NOEXCEPT;
+
+    /// Return true if the given point is inside the interval, false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersects (const T& point) const IMATH_NOEXCEPT;
+
+    /// Return true if the given interval is inside the interval, false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersects (const Interval<T>& interval) const IMATH_NOEXCEPT;
+
+    /// Return true if the interval is empty, false otherwise. An
+    /// empty interval's minimum is greater than its maximum.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool isEmpty() const IMATH_NOEXCEPT;
+
+    /// Return true if the interval is larger than a single point,
+    /// false otherwise.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool hasVolume() const IMATH_NOEXCEPT;
+
+    /// Return true if the interval contains all points, false
+    /// otherwise.  An infinite box has a mimimum of std::numeric_limits<T>::lowest()
+    /// and a maximum of std::numeric_limits<T>::max()
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool isInfinite() const IMATH_NOEXCEPT;
+
+    /// @}
+};
+
+/// Stream output, as "(min max)"
+template <class T> std::ostream& operator<< (std::ostream& s, const Interval<T>& v);
+
+/// Interval of type float
+typedef Interval<float> Intervalf;
+
+/// Interval of type double
+typedef Interval<double> Intervald;
+
+/// Interval of type short
+typedef Interval<short> Intervals;
+
+/// Interval of type integer
+typedef Interval<int> Intervali;
+
+template <class T>
+IMATH_HOSTDEVICE inline IMATH_CONSTEXPR14 Interval<T>::Interval() IMATH_NOEXCEPT
+{
+    makeEmpty();
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Interval<T>::Interval (const T& point) IMATH_NOEXCEPT
+{
+    min = point;
+    max = point;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Interval<T>::Interval (const T& minV, const T& maxV) IMATH_NOEXCEPT
+{
+    min = minV;
+    max = maxV;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Interval<T>::operator== (const Interval<T>& src) const IMATH_NOEXCEPT
+{
+    return (min == src.min && max == src.max);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Interval<T>::operator!= (const Interval<T>& src) const IMATH_NOEXCEPT
+{
+    return (min != src.min || max != src.max);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Interval<T>::makeEmpty() IMATH_NOEXCEPT
+{
+    min = std::numeric_limits<T>::max();
+    max = std::numeric_limits<T>::lowest();
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Interval<T>::makeInfinite() IMATH_NOEXCEPT
+{
+    min = std::numeric_limits<T>::lowest();
+    max = std::numeric_limits<T>::max();
+}
+
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Interval<T>::extendBy (const T& point) IMATH_NOEXCEPT
+{
+    if (point < min)
+        min = point;
+
+    if (point > max)
+        max = point;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Interval<T>::extendBy (const Interval<T>& interval) IMATH_NOEXCEPT
+{
+    if (interval.min < min)
+        min = interval.min;
+
+    if (interval.max > max)
+        max = interval.max;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Interval<T>::intersects (const T& point) const IMATH_NOEXCEPT
+{
+    return point >= min && point <= max;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Interval<T>::intersects (const Interval<T>& interval) const IMATH_NOEXCEPT
+{
+    return interval.max >= min && interval.min <= max;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+Interval<T>::size() const IMATH_NOEXCEPT
+{
+    if (isEmpty())
+        return T(0);
+    
+    return max - min;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+Interval<T>::center() const IMATH_NOEXCEPT
+{
+    return (max + min) / 2;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Interval<T>::isEmpty() const IMATH_NOEXCEPT
+{
+    return max < min;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Interval<T>::hasVolume() const IMATH_NOEXCEPT
+{
+    return max > min;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Interval<T>::isInfinite() const IMATH_NOEXCEPT
+{
+    if (min != std::numeric_limits<T>::lowest() || max != std::numeric_limits<T>::max())
+        return false;
+
+    return true;
+}
+
+/// Stream output
+template <class T>
+std::ostream&
+operator<< (std::ostream& s, const Interval<T>& v)
+{
+    return s << '(' << v.min << ' ' << v.max << ')';
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHINTERVAL_H
diff --git a/src/Imath/ImathLine.h b/src/Imath/ImathLine.h
new file mode 100644 (file)
index 0000000..499d75b
--- /dev/null
@@ -0,0 +1,176 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// A 3D line class template
+//
+
+#ifndef INCLUDED_IMATHLINE_H
+#define INCLUDED_IMATHLINE_H
+
+#include "ImathMatrix.h"
+#include "ImathNamespace.h"
+#include "ImathVec.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// The `Line3` class represents a 3D line, defined by a point and a
+/// direction vector.
+///
+
+template <class T> class Line3
+{
+  public:
+
+    /// @{
+    /// @name Direct access to member fields
+    
+    /// A point on the line
+    Vec3<T> pos;
+
+    /// The direction of the line
+    Vec3<T> dir;
+
+    /// @}
+
+    /// @{
+    ///        @name Constructors
+
+    /// Uninitialized by default
+    IMATH_HOSTDEVICE constexpr Line3() IMATH_NOEXCEPT {}
+
+    /// Initialize with two points. The direction is the difference
+    /// between the points.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Line3 (const Vec3<T>& point1, const Vec3<T>& point2) IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Manipulation
+    
+    /// Set the line defined by two points. The direction is the difference
+    /// between the points.
+    IMATH_HOSTDEVICE void set (const Vec3<T>& point1, const Vec3<T>& point2) IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Utility Methods
+    
+    /// Return the point on the line at the given parameter value,
+    ///        e.g. L(t)
+    IMATH_HOSTDEVICE constexpr Vec3<T> operator() (T parameter) const IMATH_NOEXCEPT;
+
+    /// Return the distance to the given point
+    IMATH_HOSTDEVICE constexpr T distanceTo (const Vec3<T>& point) const IMATH_NOEXCEPT;
+    /// Return the distance to the given line
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T distanceTo (const Line3<T>& line) const IMATH_NOEXCEPT;
+
+    /// Return the point on the line closest to the given point
+    IMATH_HOSTDEVICE constexpr Vec3<T> closestPointTo (const Vec3<T>& point) const IMATH_NOEXCEPT;
+
+    /// Return the point on the line closest to the given line
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3<T> closestPointTo (const Line3<T>& line) const IMATH_NOEXCEPT;
+
+    /// @}
+};
+
+/// Line of type float
+typedef Line3<float> Line3f;
+
+/// Line of type double
+typedef Line3<double> Line3d;
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Line3<T>::Line3 (const Vec3<T>& p0, const Vec3<T>& p1) IMATH_NOEXCEPT
+{
+    set (p0, p1);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Line3<T>::set (const Vec3<T>& p0, const Vec3<T>& p1) IMATH_NOEXCEPT
+{
+    pos = p0;
+    dir = p1 - p0;
+    dir.normalize();
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Line3<T>::operator() (T parameter) const IMATH_NOEXCEPT
+{
+    return pos + dir * parameter;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Line3<T>::distanceTo (const Vec3<T>& point) const IMATH_NOEXCEPT
+{
+    return (closestPointTo (point) - point).length();
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Line3<T>::closestPointTo (const Vec3<T>& point) const IMATH_NOEXCEPT
+{
+    return ((point - pos) ^ dir) * dir + pos;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+Line3<T>::distanceTo (const Line3<T>& line) const IMATH_NOEXCEPT
+{
+    T d = (dir % line.dir) ^ (line.pos - pos);
+    return (d >= 0) ? d : -d;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Vec3<T>
+Line3<T>::closestPointTo (const Line3<T>& line) const IMATH_NOEXCEPT
+{
+    // Assumes the lines are normalized
+
+    Vec3<T> posLpos = pos - line.pos;
+    T c             = dir ^ posLpos;
+    T a             = line.dir ^ dir;
+    T f             = line.dir ^ posLpos;
+    T num           = c - a * f;
+
+    T denom = a * a - 1;
+
+    T absDenom = ((denom >= 0) ? denom : -denom);
+
+    if (absDenom < 1)
+    {
+        T absNum = ((num >= 0) ? num : -num);
+
+        if (absNum >= absDenom * std::numeric_limits<T>::max())
+            return pos;
+    }
+
+    return pos + dir * (num / denom);
+}
+
+/// Stream output, as "(pos dir)"
+template <class T>
+std::ostream&
+operator<< (std::ostream& o, const Line3<T>& line)
+{
+    return o << "(" << line.pos << ", " << line.dir << ")";
+}
+
+/// Transform a line by a matrix
+template <class S, class T>
+IMATH_HOSTDEVICE constexpr inline Line3<S>
+operator* (const Line3<S>& line, const Matrix44<T>& M) IMATH_NOEXCEPT
+{
+    return Line3<S> (line.pos * M, (line.pos + line.dir) * M);
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHLINE_H
diff --git a/src/Imath/ImathLineAlgo.h b/src/Imath/ImathLineAlgo.h
new file mode 100644 (file)
index 0000000..89d3a77
--- /dev/null
@@ -0,0 +1,217 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Algorithms applied to or in conjunction with Imath::Line class
+//
+
+#ifndef INCLUDED_IMATHLINEALGO_H
+#define INCLUDED_IMATHLINEALGO_H
+
+#include "ImathFun.h"
+#include "ImathLine.h"
+#include "ImathNamespace.h"
+#include "ImathVecAlgo.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// Compute point1 and point2 such that point1 is on line1, point2
+/// is on line2 and the distance between point1 and point2 is minimal.
+///
+/// This function returns true if point1 and point2 can be computed,
+/// or false if line1 and line2 are parallel or nearly parallel.
+/// This function assumes that line1.dir and line2.dir are normalized.
+///
+
+template <class T>
+IMATH_CONSTEXPR14 bool
+closestPoints (const Line3<T>& line1, const Line3<T>& line2, Vec3<T>& point1, Vec3<T>& point2) IMATH_NOEXCEPT
+{
+    Vec3<T> w = line1.pos - line2.pos;
+    T d1w     = line1.dir ^ w;
+    T d2w     = line2.dir ^ w;
+    T d1d2    = line1.dir ^ line2.dir;
+    T n1      = d1d2 * d2w - d1w;
+    T n2      = d2w - d1d2 * d1w;
+    T d       = 1 - d1d2 * d1d2;
+    T absD    = abs (d);
+
+    if ((absD > 1) || (abs (n1) < std::numeric_limits<T>::max() * absD && abs (n2) < std::numeric_limits<T>::max() * absD))
+    {
+        point1 = line1 (n1 / d);
+        point2 = line2 (n2 / d);
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+///
+/// Given a line and a triangle (v0, v1, v2), the intersect() function
+/// finds the intersection of the line and the plane that contains the
+/// triangle.
+///
+/// If the intersection point cannot be computed, either because the
+/// line and the triangle's plane are nearly parallel or because the
+/// triangle's area is very small, intersect() returns false.
+///
+/// If the intersection point is outside the triangle, intersect
+/// returns false.
+///
+/// If the intersection point, pt, is inside the triangle, intersect()
+/// computes a front-facing flag and the barycentric coordinates of
+/// the intersection point, and returns true.
+///
+/// The front-facing flag is true if the dot product of the triangle's
+/// normal, (v2-v1)%(v1-v0), and the line's direction is negative.
+///
+/// The barycentric coordinates have the following property:
+///
+///     pt = v0 * barycentric.x + v1 * barycentric.y + v2 * barycentric.z
+///
+
+template <class T>
+IMATH_CONSTEXPR14 bool
+intersect (const Line3<T>& line,
+           const Vec3<T>& v0,
+           const Vec3<T>& v1,
+           const Vec3<T>& v2,
+           Vec3<T>& pt,
+           Vec3<T>& barycentric,
+           bool& front) IMATH_NOEXCEPT
+{
+    Vec3<T> edge0  = v1 - v0;
+    Vec3<T> edge1  = v2 - v1;
+    Vec3<T> normal = edge1 % edge0;
+
+    T l = normal.length();
+
+    if (l != 0)
+        normal /= l;
+    else
+        return false; // zero-area triangle
+
+    //
+    // d is the distance of line.pos from the plane that contains the triangle.
+    // The intersection point is at line.pos + (d/nd) * line.dir.
+    //
+
+    T d  = normal ^ (v0 - line.pos);
+    T nd = normal ^ line.dir;
+
+    if (abs (nd) > 1 || abs (d) < std::numeric_limits<T>::max() * abs (nd))
+        pt = line (d / nd);
+    else
+        return false; // line and plane are nearly parallel
+
+    //
+    // Compute the barycentric coordinates of the intersection point.
+    // The intersection is inside the triangle if all three barycentric
+    // coordinates are between zero and one.
+    //
+
+    {
+        Vec3<T> en = edge0.normalized();
+        Vec3<T> a  = pt - v0;
+        Vec3<T> b  = v2 - v0;
+        Vec3<T> c  = (a - en * (en ^ a));
+        Vec3<T> d  = (b - en * (en ^ b));
+        T e        = c ^ d;
+        T f        = d ^ d;
+
+        if (e >= 0 && e <= f)
+            barycentric.z = e / f;
+        else
+            return false; // outside
+    }
+
+    {
+        Vec3<T> en = edge1.normalized();
+        Vec3<T> a  = pt - v1;
+        Vec3<T> b  = v0 - v1;
+        Vec3<T> c  = (a - en * (en ^ a));
+        Vec3<T> d  = (b - en * (en ^ b));
+        T e        = c ^ d;
+        T f        = d ^ d;
+
+        if (e >= 0 && e <= f)
+            barycentric.x = e / f;
+        else
+            return false; // outside
+    }
+
+    barycentric.y = 1 - barycentric.x - barycentric.z;
+
+    if (barycentric.y < 0)
+        return false; // outside
+
+    front = ((line.dir ^ normal) < 0);
+    return true;
+}
+
+///
+/// Return the vertex that is closest to the given line. The returned
+/// point is either v0, v1, or v2.
+///
+
+template <class T>
+IMATH_CONSTEXPR14 Vec3<T>
+closestVertex (const Vec3<T>& v0, const Vec3<T>& v1, const Vec3<T>& v2, const Line3<T>& l) IMATH_NOEXCEPT
+{
+    Vec3<T> nearest = v0;
+    T neardot       = (v0 - l.closestPointTo (v0)).length2();
+
+    T tmp = (v1 - l.closestPointTo (v1)).length2();
+
+    if (tmp < neardot)
+    {
+        neardot = tmp;
+        nearest = v1;
+    }
+
+    tmp = (v2 - l.closestPointTo (v2)).length2();
+    if (tmp < neardot)
+    {
+        neardot = tmp;
+        nearest = v2;
+    }
+
+    return nearest;
+}
+
+///
+/// Rotate the point p around the line l by the given angle.
+///
+
+template <class T>
+IMATH_CONSTEXPR14 Vec3<T>
+rotatePoint (const Vec3<T> p, Line3<T> l, T angle) IMATH_NOEXCEPT
+{
+    //
+    // Form a coordinate frame with <x,y,a>. The rotation is the in xy
+    // plane.
+    //
+
+    Vec3<T> q = l.closestPointTo (p);
+    Vec3<T> x = p - q;
+    T radius  = x.length();
+
+    x.normalize();
+    Vec3<T> y = (x % l.dir).normalize();
+
+    T cosangle = std::cos (angle);
+    T sinangle = std::sin (angle);
+
+    Vec3<T> r = q + x * radius * cosangle + y * radius * sinangle;
+
+    return r;
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHLINEALGO_H
diff --git a/src/Imath/ImathMath.h b/src/Imath/ImathMath.h
new file mode 100644 (file)
index 0000000..d6551b9
--- /dev/null
@@ -0,0 +1,172 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Obsolete functions provided for compatibility, deprecated in favor
+// of std:: functions.
+//
+
+#ifndef INCLUDED_IMATHMATH_H
+#define INCLUDED_IMATHMATH_H
+
+#include "ImathNamespace.h"
+#include "ImathPlatform.h"
+#include <cmath>
+#include <limits>
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//----------------------------------------------------------------------------
+//
+// The deprecated Math<T> methods were intended to allow templated access to
+// math functions so that they would automatically choose either the double
+// (e.g. sin()) or float (e.g., sinf()) version.
+//
+// Beginning wth C++11, this is unnecessary, as std:: versions of all these
+// functions are available and are templated by type.
+//
+// We keep these old definitions for backward compatibility but encourage
+// users to prefer the std:: versions. Some day we may remove these
+// deprecated versions.
+//
+//----------------------------------------------------------------------------
+
+/// @cond Doxygen_Suppress
+template <class T> struct Math
+{
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T acos (T x) { return std::acos (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T asin (T x) { return std::asin (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T atan (T x) { return std::atan (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T atan2 (T x, T y) { return std::atan2 (x, y); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T cos (T x) { return std::cos (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T sin (T x) { return std::sin (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T tan (T x) { return std::tan (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T cosh (T x) { return std::cosh (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T sinh (T x) { return std::sinh (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T tanh (T x) { return std::tanh (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T exp (T x) { return std::exp (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T log (T x) { return std::log (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T log10 (T x) { return std::log10 (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T modf (T x, T* iptr)
+    {
+        T ival;
+        T rval (std::modf (T (x), &ival));
+        *iptr = ival;
+        return rval;
+    }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T pow (T x, T y) { return std::pow (x, y); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T sqrt (T x) { return std::sqrt (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T ceil (T x) { return std::ceil (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T fabs (T x) { return std::fabs (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T floor (T x) { return std::floor (x); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T fmod (T x, T y) { return std::fmod (x, y); }
+
+    IMATH_DEPRECATED("use std::math functions")
+    IMATH_HOSTDEVICE
+    static T hypot (T x, T y) { return std::hypot (x, y); }
+};
+/// @endcond
+
+
+/// Don Hatch's version of sin(x)/x, which is accurate for very small x.
+/// Returns 1 for x == 0.
+template <class T>
+IMATH_HOSTDEVICE inline T
+sinx_over_x (T x)
+{
+    if (x * x < std::numeric_limits<T>::epsilon())
+        return T (1);
+    else
+        return std::sin (x) / x;
+}
+
+/// Compare two numbers and test if they are "approximately equal":
+///
+/// @return Ttrue if x1 is the same as x2 with an absolute error of
+/// no more than e:
+///
+///    abs (x1 - x2) <= e
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+equalWithAbsError (T x1, T x2, T e) IMATH_NOEXCEPT
+{
+    return ((x1 > x2) ? x1 - x2 : x2 - x1) <= e;
+}
+
+/// Compare two numbers and test if they are "approximately equal":
+///
+/// @return True if x1 is the same as x2 with an relative error of
+/// no more than e,
+///
+/// abs (x1 - x2) <= e * x1
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+equalWithRelError (T x1, T x2, T e) IMATH_NOEXCEPT
+{
+    return ((x1 > x2) ? x1 - x2 : x2 - x1) <= e * ((x1 > 0) ? x1 : -x1);
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHMATH_H
diff --git a/src/Imath/ImathMatrix.h b/src/Imath/ImathMatrix.h
new file mode 100644 (file)
index 0000000..63e1447
--- /dev/null
@@ -0,0 +1,4826 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// 2x2, 3x3, and 4x4 transformation matrix templates
+//
+
+#ifndef INCLUDED_IMATHMATRIX_H
+#define INCLUDED_IMATHMATRIX_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include "ImathFun.h"
+#include "ImathPlatform.h"
+#include "ImathShear.h"
+#include "ImathVec.h"
+
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+#include <limits>
+#include <string.h>
+
+#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
+// suppress exception specification warnings
+#    pragma warning(disable : 4290)
+#endif
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+/// Enum used to indicate uninitialized construction of Matrix22,
+/// Matrix33, Matrix44
+enum IMATH_EXPORT_ENUM Uninitialized
+{
+    UNINITIALIZED
+};
+
+///
+/// 2x2 transformation matrix
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Matrix22
+{
+  public:
+
+    /// @{
+    /// @name Direct access to elements
+    
+    /// Matrix elements
+    T x[2][2];
+
+    /// @}
+    
+    /// Row access
+    IMATH_HOSTDEVICE T* operator[] (int i) IMATH_NOEXCEPT;
+
+    /// Row access
+    IMATH_HOSTDEVICE const T* operator[] (int i) const IMATH_NOEXCEPT;
+
+    /// @{
+    ///        @name Constructors and Assignment
+
+    /// Uninitialized
+    IMATH_HOSTDEVICE Matrix22 (Uninitialized) IMATH_NOEXCEPT {}
+
+    /// Default constructor: initialize to identity
+    ///
+    ///     1 0
+    ///     0 1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix22() IMATH_NOEXCEPT;
+
+    /// Initialize to scalar constant:
+    ///
+    ///     a a
+    ///     a a
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix22 (T a) IMATH_NOEXCEPT;
+
+    /// Construct from 2x2 array:
+    ///
+    ///     a[0][0] a[0][1]
+    ///     a[1][0] a[1][1]
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix22 (const T a[2][2]) IMATH_NOEXCEPT;
+    /// Construct from given scalar values:
+    ///
+    ///     a b
+    ///     c d
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix22 (T a, T b, T c, T d) IMATH_NOEXCEPT;
+
+    /// Copy constructor
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix22 (const Matrix22& v) IMATH_NOEXCEPT;
+
+    /// Construct from Matrix22 of another base type
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 explicit Matrix22 (const Matrix22<S>& v) IMATH_NOEXCEPT;
+
+    /// Assignment
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& operator= (const Matrix22& v) IMATH_NOEXCEPT;
+
+    /// Assignment from scalar
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& operator= (T a) IMATH_NOEXCEPT;
+
+    /// Destructor
+    ~Matrix22() IMATH_NOEXCEPT = default;
+
+    /// @}
+
+#if IMATH_FOREIGN_VECTOR_INTEROP
+    /// @{
+    /// @name Interoperability with other matrix types
+    ///
+    /// Construction and assignment are allowed from other classes that
+    /// appear to be equivalent matrix types, provided that they support
+    /// double-subscript (i.e., `m[j][i]`) giving the same type as the
+    /// elements of this matrix, and their total size appears to be the
+    /// right number of matrix elements.
+    ///
+    /// This functionality is disabled for gcc 4.x, which seems to have a
+    /// compiler bug that results in spurious errors. It can also be
+    /// disabled by defining IMATH_FOREIGN_VECTOR_INTEROP to be 0 prior to
+    /// including any Imath header files.
+    ///
+    template<typename M, IMATH_ENABLE_IF(has_double_subscript<M,T,2,2>::value)>
+    IMATH_HOSTDEVICE explicit Matrix22 (const M& m)
+        : Matrix22(T(m[0][0]), T(m[0][1]), T(m[1][0]), T(m[1][1]))
+    { }
+
+    template<typename M, IMATH_ENABLE_IF(has_double_subscript<M,T,2,2>::value)>
+    IMATH_HOSTDEVICE const Matrix22& operator= (const M& m)
+    {
+        *this = Matrix22(T(m[0][0]), T(m[0][1]), T(m[1][0]), T(m[1][1]));
+        return *this;
+    }
+    /// @}
+#endif
+
+    /// @{
+    /// @name Compatibility with Sb
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE T* getValue() IMATH_NOEXCEPT;
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE const T* getValue() const IMATH_NOEXCEPT;
+
+    /// Return the value in `v`
+    template <class S> IMATH_HOSTDEVICE void getValue (Matrix22<S>& v) const IMATH_NOEXCEPT;
+
+    /// Set the value
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix22& setValue (const Matrix22<S>& v) IMATH_NOEXCEPT;
+
+    /// Set the value
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix22& setTheMatrix (const Matrix22<S>& v) IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Arithmetic and Comparison
+    
+    /// Equality
+    IMATH_HOSTDEVICE constexpr bool operator== (const Matrix22& v) const IMATH_NOEXCEPT;
+
+    /// Inequality
+    IMATH_HOSTDEVICE constexpr bool operator!= (const Matrix22& v) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and `m` are the same
+    /// with an absolute error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i][j] - m[i][j]) <= e
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithAbsError (const Matrix22<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and m are the same with
+    /// a relative error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i] - v[i][j]) <= e * abs (this[i][j])
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithRelError (const Matrix22<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& operator+= (const Matrix22& v) IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& operator+= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE constexpr Matrix22 operator+ (const Matrix22& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& operator-= (const Matrix22& v) IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& operator-= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE constexpr Matrix22 operator- (const Matrix22& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE constexpr Matrix22 operator-() const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& negate() IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& operator*= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Matrix22 operator* (T a) const IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& operator/= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Matrix22 operator/ (T a) const IMATH_NOEXCEPT;
+
+    /// Matrix-matrix multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& operator*= (const Matrix22& v) IMATH_NOEXCEPT;
+
+    /// Matrix-matrix multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix22 operator* (const Matrix22& v) const IMATH_NOEXCEPT;
+
+    /// Vector * matrix multiplication
+    /// @param[in] src Input vector
+    /// @param[out] dst transformed vector
+    template <class S> IMATH_HOSTDEVICE void multDirMatrix (const Vec2<S>& src, Vec2<S>& dst) const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Maniplation
+
+    /// Set to the identity
+    IMATH_HOSTDEVICE void makeIdentity() IMATH_NOEXCEPT;
+
+    /// Transpose
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& transpose() IMATH_NOEXCEPT;
+
+    /// Return the transpose
+    IMATH_HOSTDEVICE constexpr Matrix22 transposed() const IMATH_NOEXCEPT;
+
+    /// Invert in place
+    /// @param singExc If true, throw an exception if the matrix cannot be inverted.
+    /// @return const reference to this
+    IMATH_CONSTEXPR14 const Matrix22& invert (bool singExc);
+
+    /// Invert in place
+    /// @return const reference to this
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& invert() IMATH_NOEXCEPT;
+
+    /// Return the inverse, leaving this unmodified.
+    /// @param singExc If true, throw an exception if the matrix cannot be inverted.
+    IMATH_CONSTEXPR14 Matrix22<T> inverse (bool singExc) const;
+
+    /// Return the inverse, leaving this unmodified.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix22<T> inverse() const IMATH_NOEXCEPT;
+
+    /// Determinant
+    IMATH_HOSTDEVICE constexpr T determinant() const IMATH_NOEXCEPT;
+
+    /// Trace
+    IMATH_HOSTDEVICE constexpr T trace() const IMATH_NOEXCEPT;
+
+    /// Set matrix to rotation by r (in radians)
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE const Matrix22& setRotation (S r) IMATH_NOEXCEPT;
+
+    /// Rotate the given matrix by r (in radians)
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& rotate (S r) IMATH_NOEXCEPT;
+
+    /// Set matrix to scale by given uniform factor
+    /// @return const referenced to this
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& setScale (T s) IMATH_NOEXCEPT;
+
+    /// Set matrix to scale by given vector
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& setScale (const Vec2<S>& s) IMATH_NOEXCEPT;
+
+    // Scale the matrix by s
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix22& scale (const Vec2<S>& s) IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Numeric Limits
+    
+    /// Largest possible negative value
+    IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
+
+    /// Largest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
+
+    /// Smallest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
+
+    /// Smallest possible e for which 1+e != 1
+    IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
+
+    /// @}
+    
+    /// Return the number of the row and column dimensions, i.e. 2.
+    IMATH_HOSTDEVICE constexpr static unsigned int dimensions() IMATH_NOEXCEPT { return 2; }
+
+    /// The base type: In templates that accept a parameter `V`, you
+    /// can refer to `T` as `V::BaseType`
+    typedef T BaseType;
+
+    /// The base vector type
+    typedef Vec2<T> BaseVecType;
+};
+
+///
+/// 3x3 transformation matrix
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Matrix33
+{
+  public:
+
+    /// @{
+    /// @name Direct access to elements
+    
+    /// Matrix elements
+    T x[3][3];
+
+    /// @}
+    
+    /// Row access
+    IMATH_HOSTDEVICE T* operator[] (int i) IMATH_NOEXCEPT;
+
+    /// Row access
+    IMATH_HOSTDEVICE const T* operator[] (int i) const IMATH_NOEXCEPT;
+
+    /// @{
+    ///        @name Constructors and Assignment
+
+    /// Uninitialized
+    IMATH_HOSTDEVICE Matrix33 (Uninitialized) IMATH_NOEXCEPT {}
+
+    /// Default constructor: initialize to identity
+    ///     1 0 0
+    ///     0 1 0
+    ///     0 0 1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix33() IMATH_NOEXCEPT;
+
+    /// Initialize to scalar constant
+    ///     a a a
+    ///     a a a
+    ///     a a a
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix33 (T a) IMATH_NOEXCEPT;
+
+    /// Construct from 3x3 array 
+    ///     a[0][0] a[0][1] a[0][2]
+    ///     a[1][0] a[1][1] a[1][2]
+    ///     a[2][0] a[2][1] a[2][2]
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix33 (const T a[3][3]) IMATH_NOEXCEPT;
+    /// Construct from given scalar values
+    ///     a b c
+    ///     d e f
+    ///     g h i
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix33 (T a, T b, T c, T d, T e, T f, T g, T h, T i) IMATH_NOEXCEPT;
+
+    /// Copy constructor
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix33 (const Matrix33& v) IMATH_NOEXCEPT;
+
+    /// Construct from Matrix33 of another base type
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 explicit Matrix33 (const Matrix33<S>& v) IMATH_NOEXCEPT;
+
+    /// Assignment operator
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& operator= (const Matrix33& v) IMATH_NOEXCEPT;
+
+    /// Assignment from scalar
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& operator= (T a) IMATH_NOEXCEPT;
+
+    /// Destructor
+    ~Matrix33() IMATH_NOEXCEPT = default;
+
+    /// @}
+
+#if IMATH_FOREIGN_VECTOR_INTEROP
+    /// @{
+    /// @name Interoperability with other matrix types
+    ///
+    /// Construction and assignment are allowed from other classes that
+    /// appear to be equivalent matrix types, provided that they support
+    /// double-subscript (i.e., `m[j][i]`) giving the same type as the
+    /// elements of this matrix, and their total size appears to be the
+    /// right number of matrix elements.
+    ///
+    /// This functionality is disabled for gcc 4.x, which seems to have a
+    /// compiler bug that results in spurious errors. It can also be
+    /// disabled by defining IMATH_FOREIGN_VECTOR_INTEROP to be 0 prior to
+    /// including any Imath header files.
+    ///
+    template<typename M, IMATH_ENABLE_IF(has_double_subscript<M,T,3,3>::value)>
+    IMATH_HOSTDEVICE explicit Matrix33 (const M& m)
+        : Matrix33(T(m[0][0]), T(m[0][1]), T(m[0][2]),
+                   T(m[1][0]), T(m[1][1]), T(m[1][2]),
+                   T(m[2][0]), T(m[2][1]), T(m[2][2]))
+    { }
+
+    /// Interoperability assignment from another type that behaves as if it
+    /// were an equivalent matrix.
+    template<typename M, IMATH_ENABLE_IF(has_double_subscript<M,T,3,3>::value)>
+    IMATH_HOSTDEVICE const Matrix33& operator= (const M& m)
+    {
+        *this = Matrix33(T(m[0][0]), T(m[0][1]), T(m[0][2]),
+                         T(m[1][0]), T(m[1][1]), T(m[1][2]),
+                         T(m[2][0]), T(m[2][1]), T(m[2][2]));
+        return *this;
+    }
+    /// @}
+#endif
+
+    /// @{
+    /// @name Compatibility with Sb
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE T* getValue() IMATH_NOEXCEPT;
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE const T* getValue() const IMATH_NOEXCEPT;
+
+    /// Return the value in `v`
+    template <class S> IMATH_HOSTDEVICE void getValue (Matrix33<S>& v) const IMATH_NOEXCEPT;
+
+    /// Set the value
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix33& setValue (const Matrix33<S>& v) IMATH_NOEXCEPT;
+
+    /// Set the value
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix33& setTheMatrix (const Matrix33<S>& v) IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Arithmetic and Comparison
+    
+    /// Equality
+    IMATH_HOSTDEVICE constexpr bool operator== (const Matrix33& v) const IMATH_NOEXCEPT;
+
+    /// Inequality
+    IMATH_HOSTDEVICE constexpr bool operator!= (const Matrix33& v) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and `m` are the same
+    /// with an absolute error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i][j] - m[i][j]) <= e
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithAbsError (const Matrix33<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and m are the same with
+    /// a relative error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i] - v[i][j]) <= e * abs (this[i][j])
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithRelError (const Matrix33<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& operator+= (const Matrix33& v) IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& operator+= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE constexpr Matrix33 operator+ (const Matrix33& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& operator-= (const Matrix33& v) IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& operator-= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE constexpr Matrix33 operator- (const Matrix33& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE constexpr Matrix33 operator-() const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& negate() IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& operator*= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Matrix33 operator* (T a) const IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& operator/= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Matrix33 operator/ (T a) const IMATH_NOEXCEPT;
+
+    /// Matrix-matrix multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& operator*= (const Matrix33& v) IMATH_NOEXCEPT;
+
+    /// Matrix-matrix multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix33 operator* (const Matrix33& v) const IMATH_NOEXCEPT;
+
+    /// Vector-matrix multiplication: a homogeneous transformation
+    /// by computing Vec3 (src.x, src.y, 1) * m and dividing by the
+    /// result's third element.
+    /// @param[in] src The input vector
+    /// @param[out] dst The output vector
+    template <class S> IMATH_HOSTDEVICE void multVecMatrix (const Vec2<S>& src, Vec2<S>& dst) const IMATH_NOEXCEPT;
+
+    /// Vector-matrix multiplication: multiply `src` by the upper left 2x2
+    /// submatrix, ignoring the rest of matrix.
+    /// @param[in] src The input vector
+    /// @param[out] dst The output vector
+    template <class S> IMATH_HOSTDEVICE void multDirMatrix (const Vec2<S>& src, Vec2<S>& dst) const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Maniplation
+
+    /// Set to the identity matrix
+    IMATH_HOSTDEVICE void makeIdentity() IMATH_NOEXCEPT;
+
+    /// Transpose
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& transpose() IMATH_NOEXCEPT;
+
+    /// Return the transpose
+    IMATH_HOSTDEVICE constexpr Matrix33 transposed() const IMATH_NOEXCEPT;
+
+    /// Invert in place using the determinant.
+    /// @param singExc If true, throw an exception if the matrix cannot be inverted.
+    /// @return const reference to this
+    IMATH_CONSTEXPR14 const Matrix33& invert (bool singExc);
+
+    /// Invert in place using the determinant.
+    /// @return const reference to this
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& invert() IMATH_NOEXCEPT;
+
+    /// Return the inverse using the determinant, leaving this unmodified.
+    /// @param singExc If true, throw an exception if the matrix cannot be inverted.
+    IMATH_CONSTEXPR14 Matrix33<T> inverse (bool singExc) const;
+
+    /// Return the inverse using the determinant, leaving this unmodified.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix33<T> inverse() const IMATH_NOEXCEPT;
+
+    /// Invert in place using the Gauss-Jordan method. Significantly slower
+    /// but more accurate than invert().
+    /// @param singExc If true, throw an exception if the matrix cannot be inverted.
+    /// @return const reference to this
+    const Matrix33& gjInvert (bool singExc);
+    
+    /// Invert in place using the Gauss-Jordan method. Significantly slower
+    /// but more accurate than invert().
+    /// @return const reference to this
+    IMATH_HOSTDEVICE const Matrix33& gjInvert() IMATH_NOEXCEPT;
+
+    /// Return the inverse using the Gauss-Jordan method, leaving this
+    /// unmodified. Significantly slower but more accurate than inverse().
+    Matrix33<T> gjInverse (bool singExc) const;
+
+    /// Return the inverse using the Gauss-Jordan method. Significantly slower,
+    /// leaving this unmodified. Slower but more accurate than inverse().
+    IMATH_HOSTDEVICE Matrix33<T> gjInverse() const IMATH_NOEXCEPT;
+
+    /// Calculate the matrix minor of the (r,c) element
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T minorOf (const int r, const int c) const IMATH_NOEXCEPT;
+
+    /// Build a minor using the specified rows and columns
+    IMATH_HOSTDEVICE
+    constexpr T fastMinor (const int r0, const int r1, const int c0, const int c1) const IMATH_NOEXCEPT;
+
+    /// Determinant
+    IMATH_HOSTDEVICE constexpr T determinant() const IMATH_NOEXCEPT;
+
+    /// Trace
+    IMATH_HOSTDEVICE constexpr T trace() const IMATH_NOEXCEPT;
+
+    /// Set matrix to rotation by r (in radians)
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE const Matrix33& setRotation (S r) IMATH_NOEXCEPT;
+
+    // Rotate the given matrix by r (in radians)
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& rotate (S r) IMATH_NOEXCEPT;
+
+    /// Set matrix to scale by given uniform factor
+    /// @return const referenced to this
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& setScale (T s) IMATH_NOEXCEPT;
+
+    /// Set matrix to scale by given vector
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& setScale (const Vec2<S>& s) IMATH_NOEXCEPT;
+
+    /// Scale the matrix by s
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& scale (const Vec2<S>& s) IMATH_NOEXCEPT;
+
+    /// Set matrix to translation by given vector
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& setTranslation (const Vec2<S>& t) IMATH_NOEXCEPT;
+
+    /// Return the translation component
+    IMATH_HOSTDEVICE constexpr Vec2<T> translation() const IMATH_NOEXCEPT;
+
+    /// Translate the matrix by t
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& translate (const Vec2<S>& t) IMATH_NOEXCEPT;
+
+    /// Set matrix to shear x for each y coord. by given factor xy
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& setShear (const S& h) IMATH_NOEXCEPT;
+
+    /// Set matrix to shear x for each y coord. by given factor h.x
+    /// and to shear y for each x coord. by given factor h.y
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& setShear (const Vec2<S>& h) IMATH_NOEXCEPT;
+
+    /// Shear the matrix in x for each y coord. by given factor xy
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& shear (const S& xy) IMATH_NOEXCEPT;
+
+    /// Shear the matrix in x for each y coord. by given factor xy
+    /// and shear y for each x coord. by given factor yx
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix33& shear (const Vec2<S>& h) IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Numeric Limits
+    
+    /// Largest possible negative value
+    IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
+
+    /// Largest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
+
+    /// Smallest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
+
+    /// Smallest possible e for which 1+e != 1
+    IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
+
+    /// @}
+    
+    /// Return the number of the row and column dimensions, i.e. 3.
+    IMATH_HOSTDEVICE constexpr static unsigned int dimensions() IMATH_NOEXCEPT { return 3; }
+
+    /// The base type: In templates that accept a parameter `V` (could be a Color4), you can refer to `T` as `V::BaseType`
+    typedef T BaseType;
+
+    /// The base vector type
+    typedef Vec3<T> BaseVecType;
+};
+
+///
+/// 4x4 transformation matrix
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Matrix44
+{
+  public:
+
+    /// @{
+    /// @name Direct access to elements
+    
+    /// Matrix elements
+    T x[4][4];
+
+    /// @}
+    
+    /// Row access
+    IMATH_HOSTDEVICE T* operator[] (int i) IMATH_NOEXCEPT;
+
+    /// Row access
+    IMATH_HOSTDEVICE const T* operator[] (int i) const IMATH_NOEXCEPT;
+
+    /// @{
+    ///        @name Constructors and Assignment
+
+    /// Uninitialized
+    IMATH_HOSTDEVICE constexpr Matrix44 (Uninitialized) IMATH_NOEXCEPT {}
+
+    /// Default constructor: initialize to identity
+    ///     1 0 0 0
+    ///     0 1 0 0
+    ///     0 0 1 0
+    ///     0 0 0 1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44() IMATH_NOEXCEPT;
+
+    /// Initialize to scalar constant
+    ///     a a a a
+    ///     a a a a
+    ///     a a a a
+    ///     a a a a
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44 (T a) IMATH_NOEXCEPT;
+
+    /// Construct from 4x4 array 
+    ///     a[0][0] a[0][1] a[0][2] a[0][3]
+    ///     a[1][0] a[1][1] a[1][2] a[1][3]
+    ///     a[2][0] a[2][1] a[2][2] a[2][3]
+    ///     a[3][0] a[3][1] a[3][2] a[3][3]
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44 (const T a[4][4]) IMATH_NOEXCEPT;
+    /// Construct from given scalar values
+    ///     a b c d
+    ///     e f g h
+    ///     i j k l
+    ///     m n o p
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14
+    Matrix44 (T a, T b, T c, T d, T e, T f, T g, T h, T i, T j, T k, T l, T m, T n, T o, T p) IMATH_NOEXCEPT;
+
+
+    /// Construct from a 3x3 rotation matrix and a translation vector
+    ///     r r r 0
+    ///     r r r 0
+    ///     r r r 0
+    ///     t t t 1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44 (Matrix33<T> r, Vec3<T> t) IMATH_NOEXCEPT;
+
+    /// Copy constructor
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44 (const Matrix44& v) IMATH_NOEXCEPT;
+
+    /// Construct from Matrix44 of another base type
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 explicit Matrix44 (const Matrix44<S>& v) IMATH_NOEXCEPT;
+
+    /// Assignment operator
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& operator= (const Matrix44& v) IMATH_NOEXCEPT;
+
+    /// Assignment from scalar
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& operator= (T a) IMATH_NOEXCEPT;
+
+    /// Destructor
+    ~Matrix44() IMATH_NOEXCEPT = default;
+
+    /// @}
+
+#if IMATH_FOREIGN_VECTOR_INTEROP
+    /// @{
+    /// @name Interoperability with other matrix types
+    ///
+    /// Construction and assignment are allowed from other classes that
+    /// appear to be equivalent matrix types, provided that they support
+    /// double-subscript (i.e., `m[j][i]`) giving the same type as the
+    /// elements of this matrix, and their total size appears to be the
+    /// right number of matrix elements.
+    ///
+    /// This functionality is disabled for gcc 4.x, which seems to have a
+    /// compiler bug that results in spurious errors. It can also be
+    /// disabled by defining IMATH_FOREIGN_VECTOR_INTEROP to be 0 prior to
+    /// including any Imath header files.
+    ///
+    template<typename M, IMATH_ENABLE_IF(has_double_subscript<M,T,4,4>::value)>
+    IMATH_HOSTDEVICE explicit Matrix44 (const M& m)
+        : Matrix44(T(m[0][0]), T(m[0][1]), T(m[0][2]), T(m[0][3]),
+                   T(m[1][0]), T(m[1][1]), T(m[1][2]), T(m[1][3]),
+                   T(m[2][0]), T(m[2][1]), T(m[2][2]), T(m[2][3]),
+                   T(m[3][0]), T(m[3][1]), T(m[3][2]), T(m[3][3]))
+    { }
+
+    /// Interoperability assignment from another type that behaves as if it
+    /// were an equivalent matrix.
+    template<typename M, IMATH_ENABLE_IF(has_double_subscript<M,T,4,4>::value)>
+    IMATH_HOSTDEVICE const Matrix44& operator= (const M& m)
+    {
+        *this = Matrix44(T(m[0][0]), T(m[0][1]), T(m[0][2]), T(m[0][3]),
+                         T(m[1][0]), T(m[1][1]), T(m[1][2]), T(m[1][3]),
+                         T(m[2][0]), T(m[2][1]), T(m[2][2]), T(m[2][3]),
+                         T(m[3][0]), T(m[3][1]), T(m[3][2]), T(m[3][3]));
+        return *this;
+    }
+    /// @}
+#endif
+
+    /// @{
+    /// @name Compatibility with Sb
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE T* getValue() IMATH_NOEXCEPT;
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE const T* getValue() const IMATH_NOEXCEPT;
+
+    /// Return the value in `v`
+    template <class S> IMATH_HOSTDEVICE void getValue (Matrix44<S>& v) const IMATH_NOEXCEPT;
+
+    /// Set the value
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44& setValue (const Matrix44<S>& v) IMATH_NOEXCEPT;
+
+    /// Set the value
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44& setTheMatrix (const Matrix44<S>& v) IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Arithmetic and Comparison
+    
+    /// Equality
+    IMATH_HOSTDEVICE constexpr bool operator== (const Matrix44& v) const IMATH_NOEXCEPT;
+
+    /// Inequality
+    IMATH_HOSTDEVICE constexpr bool operator!= (const Matrix44& v) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and `m` are the same
+    /// with an absolute error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i][j] - m[i][j]) <= e
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithAbsError (const Matrix44<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and m are the same with
+    /// a relative error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i] - v[i][j]) <= e * abs (this[i][j])
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithRelError (const Matrix44<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& operator+= (const Matrix44& v) IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& operator+= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE constexpr Matrix44 operator+ (const Matrix44& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& operator-= (const Matrix44& v) IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& operator-= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE constexpr Matrix44 operator- (const Matrix44& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE constexpr Matrix44 operator-() const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& negate() IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& operator*= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Matrix44 operator* (T a) const IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& operator/= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Matrix44 operator/ (T a) const IMATH_NOEXCEPT;
+
+    /// Matrix-matrix multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& operator*= (const Matrix44& v) IMATH_NOEXCEPT;
+
+    /// Matrix-matrix multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44 operator* (const Matrix44& v) const IMATH_NOEXCEPT;
+
+    /// Matrix-matrix multiplication: compute c = a * b
+    IMATH_HOSTDEVICE
+    static void multiply (const Matrix44& a,     // assumes that
+                          const Matrix44& b,     // &a != &c and
+                          Matrix44& c) IMATH_NOEXCEPT; // &b != &c.
+
+    /// Matrix-matrix multiplication returning a result.
+    IMATH_HOSTDEVICE
+    static IMATH_CONSTEXPR14 Matrix44 multiply (const Matrix44& a, const Matrix44& b) IMATH_NOEXCEPT;
+
+    /// Vector-matrix multiplication: a homogeneous transformation
+    /// by computing Vec3 (src.x, src.y, src.z, 1) * m and dividing by the
+    /// result's third element.
+    /// @param[in] src The input vector
+    /// @param[out] dst The output vector
+    template <class S> IMATH_HOSTDEVICE void multVecMatrix (const Vec3<S>& src, Vec3<S>& dst) const IMATH_NOEXCEPT;
+
+    /// Vector-matrix multiplication: multiply `src` by the upper left 2x2
+    /// submatrix, ignoring the rest of matrix.
+    /// @param[in] src The input vector
+    /// @param[out] dst The output vector
+    template <class S> IMATH_HOSTDEVICE void multDirMatrix (const Vec3<S>& src, Vec3<S>& dst) const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Maniplation
+
+    /// Set to the identity matrix
+    IMATH_HOSTDEVICE void makeIdentity() IMATH_NOEXCEPT;
+
+    /// Transpose
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& transpose() IMATH_NOEXCEPT;
+
+    /// Return the transpose
+    IMATH_HOSTDEVICE constexpr Matrix44 transposed() const IMATH_NOEXCEPT;
+
+    /// Invert in place using the determinant.
+    /// @param singExc If true, throw an exception if the matrix cannot be inverted.
+    /// @return const reference to this
+    IMATH_CONSTEXPR14 const Matrix44& invert (bool singExc);
+
+    /// Invert in place using the determinant.
+    /// @return const reference to this
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& invert() IMATH_NOEXCEPT;
+
+    /// Return the inverse using the determinant, leaving this unmodified.
+    /// @param singExc If true, throw an exception if the matrix cannot be inverted.
+    IMATH_CONSTEXPR14 Matrix44<T> inverse (bool singExc) const;
+
+    /// Return the inverse using the determinant, leaving this unmodified.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44<T> inverse() const IMATH_NOEXCEPT;
+
+    /// Invert in place using the Gauss-Jordan method. Significantly slower
+    /// but more accurate than invert().
+    /// @param singExc If true, throw an exception if the matrix cannot be inverted.
+    /// @return const reference to this
+    IMATH_CONSTEXPR14 const Matrix44& gjInvert (bool singExc);
+
+    /// Invert in place using the Gauss-Jordan method. Significantly slower
+    /// but more accurate than invert().
+    /// @return const reference to this
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& gjInvert() IMATH_NOEXCEPT;
+
+    /// Return the inverse using the Gauss-Jordan method, leaving this
+    /// unmodified. Significantly slower but more accurate than inverse().
+    Matrix44<T> gjInverse (bool singExc) const;
+
+    /// Return the inverse using the Gauss-Jordan method, leaving this
+    /// unmodified Significantly slower but more accurate than inverse().
+    IMATH_HOSTDEVICE Matrix44<T> gjInverse() const IMATH_NOEXCEPT;
+
+    /// Calculate the matrix minor of the (r,c) element
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T minorOf (const int r, const int c) const IMATH_NOEXCEPT;
+
+    /// Build a minor using the specified rows and columns
+    IMATH_HOSTDEVICE
+    constexpr T fastMinor (const int r0,
+                           const int r1,
+                           const int r2,
+                           const int c0,
+                           const int c1,
+                           const int c2) const IMATH_NOEXCEPT;
+
+    /// Determinant
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T determinant() const IMATH_NOEXCEPT;
+
+    /// Trace
+    IMATH_HOSTDEVICE constexpr T trace() const IMATH_NOEXCEPT;
+
+    /// Set matrix to rotation by XYZ euler angles (in radians)
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE const Matrix44& setEulerAngles (const Vec3<S>& r) IMATH_NOEXCEPT;
+
+    /// Set matrix to rotation around given axis by given angle (in radians)
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& setAxisAngle (const Vec3<S>& ax, S ang) IMATH_NOEXCEPT;
+
+    /// Rotate the matrix by XYZ euler angles in r (in radians)
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE const Matrix44& rotate (const Vec3<S>& r) IMATH_NOEXCEPT;
+
+    /// Set matrix to scale by given uniform factor
+    /// @return const referenced to this
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& setScale (T s) IMATH_NOEXCEPT;
+
+    /// Set matrix to scale by given vector
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& setScale (const Vec3<S>& s) IMATH_NOEXCEPT;
+
+    /// Scale the matrix by s
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& scale (const Vec3<S>& s) IMATH_NOEXCEPT;
+
+    /// Set matrix to translation by given vector
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& setTranslation (const Vec3<S>& t) IMATH_NOEXCEPT;
+
+    /// Return translation component
+    IMATH_HOSTDEVICE constexpr const Vec3<T> translation() const IMATH_NOEXCEPT;
+
+    /// Translate the matrix by t
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& translate (const Vec3<S>& t) IMATH_NOEXCEPT;
+
+    /// Set matrix to shear by given vector h.  The resulting matrix
+    /// - will shear x for each y coord. by a factor of h[0] ;
+    /// - will shear x for each z coord. by a factor of h[1] ;
+    /// - will shear y for each z coord. by a factor of h[2] .
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& setShear (const Vec3<S>& h) IMATH_NOEXCEPT;
+
+    /// Set matrix to shear by given factors.  The resulting matrix
+    /// - will shear x for each y coord. by a factor of h.xy ;
+    /// - will shear x for each z coord. by a factor of h.xz ;
+    /// - will shear y for each z coord. by a factor of h.yz ;
+    /// - will shear y for each x coord. by a factor of h.yx ;
+    /// - will shear z for each x coord. by a factor of h.zx ;
+    /// - will shear z for each y coord. by a factor of h.zy .
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& setShear (const Shear6<S>& h) IMATH_NOEXCEPT;
+
+    /// Shear the matrix by given vector.  The composed matrix
+    /// will be `shear` * `this`, where the shear matrix ...
+    /// - will shear x for each y coord. by a factor of h[0] ;
+    /// - will shear x for each z coord. by a factor of h[1] ;
+    /// - will shear y for each z coord. by a factor of h[2] .
+    /// @return const referenced to this
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& shear (const Vec3<S>& h) IMATH_NOEXCEPT;
+
+    /// Shear the matrix by the given factors.  The composed matrix
+    /// will be `shear` * `this`, where the shear matrix ...
+    /// - will shear x for each y coord. by a factor of h.xy ;
+    /// - will shear x for each z coord. by a factor of h.xz ;
+    /// - will shear y for each z coord. by a factor of h.yz ;
+    /// - will shear y for each x coord. by a factor of h.yx ;
+    /// - will shear z for each x coord. by a factor of h.zx ;
+    /// - will shear z for each y coord. by a factor of h.zy .
+    /// @return const referenced to this
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Matrix44& shear (const Shear6<S>& h) IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Numeric Limits
+    
+    /// Largest possible negative value
+    IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
+
+    /// Largest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
+
+    /// Smallest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
+
+    /// Smallest possible e for which 1+e != 1
+    IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
+
+    /// @}
+    
+    /// Return the number of the row and column dimensions, i.e. 4
+    IMATH_HOSTDEVICE constexpr static unsigned int dimensions() IMATH_NOEXCEPT { return 4; }
+
+    /// The base type: In templates that accept a parameter `V` (could be a Color4), you can refer to `T` as `V::BaseType`
+    typedef T BaseType;
+
+    /// The base vector type
+    typedef Vec4<T> BaseVecType;
+};
+
+/// Stream output, as:
+///     (m00 m01
+///      m10 m11)
+template <class T> std::ostream& operator<< (std::ostream& s, const Matrix22<T>& m);
+
+/// Stream output, as:
+///     (m00 m01 m02
+///      m10 m11 m12
+///      m20 m21 m22)
+template <class T> std::ostream& operator<< (std::ostream& s, const Matrix33<T>& m);
+
+/// Stream output, as:
+///
+///     (m00 m01 m02 m03
+///      m10 m11 m12 m13
+///      m20 m21 m22 m23
+///      m30 m31 m32 m33)
+template <class T> std::ostream& operator<< (std::ostream& s, const Matrix44<T>& m);
+
+//---------------------------------------------
+// Vector-times-matrix multiplication operators
+//---------------------------------------------
+
+/// Vector-matrix multiplication: v *= m
+template <class S, class T>
+IMATH_HOSTDEVICE inline const Vec2<S>& operator*= (Vec2<S>& v, const Matrix22<T>& m) IMATH_NOEXCEPT;
+
+/// Vector-matrix multiplication: r = v * m
+template <class S, class T>
+IMATH_HOSTDEVICE inline Vec2<S> operator* (const Vec2<S>& v, const Matrix22<T>& m) IMATH_NOEXCEPT;
+
+/// Vector-matrix multiplication: v *= m
+template <class S, class T>
+IMATH_HOSTDEVICE inline const Vec2<S>& operator*= (Vec2<S>& v, const Matrix33<T>& m) IMATH_NOEXCEPT;
+
+/// Vector-matrix multiplication: r = v * m
+template <class S, class T>
+IMATH_HOSTDEVICE inline Vec2<S> operator* (const Vec2<S>& v, const Matrix33<T>& m) IMATH_NOEXCEPT;
+
+/// Vector-matrix multiplication: v *= m
+template <class S, class T>
+IMATH_HOSTDEVICE inline const Vec3<S>& operator*= (Vec3<S>& v, const Matrix33<T>& m) IMATH_NOEXCEPT;
+
+/// Vector-matrix multiplication: r = v * m
+template <class S, class T>
+IMATH_HOSTDEVICE inline Vec3<S> operator* (const Vec3<S>& v, const Matrix33<T>& m) IMATH_NOEXCEPT;
+
+/// Vector-matrix multiplication: v *= m
+template <class S, class T>
+IMATH_HOSTDEVICE inline const Vec3<S>& operator*= (Vec3<S>& v, const Matrix44<T>& m) IMATH_NOEXCEPT;
+
+/// Vector-matrix multiplication: r = v * m
+template <class S, class T>
+IMATH_HOSTDEVICE inline Vec3<S> operator* (const Vec3<S>& v, const Matrix44<T>& m) IMATH_NOEXCEPT;
+
+/// Vector-matrix multiplication: v *= m
+template <class S, class T>
+IMATH_HOSTDEVICE inline const Vec4<S>& operator*= (Vec4<S>& v, const Matrix44<T>& m) IMATH_NOEXCEPT;
+
+/// Vector-matrix multiplication: r = v * m
+template <class S, class T>
+IMATH_HOSTDEVICE inline Vec4<S> operator* (const Vec4<S>& v, const Matrix44<T>& m) IMATH_NOEXCEPT;
+
+//-------------------------
+// Typedefs for convenience
+//-------------------------
+
+/// 2x2 matrix of float
+typedef Matrix22<float> M22f;
+
+/// 2x2 matrix of double
+typedef Matrix22<double> M22d;
+
+/// 3x3 matrix of float
+typedef Matrix33<float> M33f;
+
+/// 3x3 matrix of double
+typedef Matrix33<double> M33d;
+
+/// 4x4 matrix of float
+typedef Matrix44<float> M44f;
+
+/// 4x4 matrix of double
+typedef Matrix44<double> M44d;
+
+//---------------------------
+// Implementation of Matrix22
+//---------------------------
+
+template <class T>
+IMATH_HOSTDEVICE inline T*
+Matrix22<T>::operator[] (int i) IMATH_NOEXCEPT
+{
+    return x[i];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const T*
+Matrix22<T>::operator[] (int i) const IMATH_NOEXCEPT
+{
+    return x[i];
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix22<T>::Matrix22() IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = 0;
+    x[1][0] = 0;
+    x[1][1] = 1;
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix22<T>::Matrix22 (T a) IMATH_NOEXCEPT
+{
+    x[0][0] = a;
+    x[0][1] = a;
+    x[1][0] = a;
+    x[1][1] = a;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix22<T>::Matrix22 (
+    const T a[2][2]) IMATH_NOEXCEPT
+{
+    // Function calls and aliasing issues can inhibit vectorization versus
+    // straight assignment of data members, so instead of this:
+    //     memcpy (x, a, sizeof (x));
+    // we do this:
+    x[0][0] = a[0][0];
+    x[0][1] = a[0][1];
+    x[1][0] = a[1][0];
+    x[1][1] = a[1][1];
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix22<T>::Matrix22 (
+    T a, T b, T c, T d) IMATH_NOEXCEPT
+{
+    x[0][0] = a;
+    x[0][1] = b;
+    x[1][0] = c;
+    x[1][1] = d;
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix22<T>::Matrix22 (const Matrix22& v) IMATH_NOEXCEPT
+{
+    // Function calls and aliasing issues can inhibit vectorization versus
+    // straight assignment of data members, so we don't do this:
+    //     memcpy (x, v.x, sizeof (x));
+    // we do this:
+    x[0][0] = v.x[0][0];
+    x[0][1] = v.x[0][1];
+    x[1][0] = v.x[1][0];
+    x[1][1] = v.x[1][1];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix22<T>::Matrix22 (const Matrix22<S>& v) IMATH_NOEXCEPT
+{
+    x[0][0] = T (v.x[0][0]);
+    x[0][1] = T (v.x[0][1]);
+    x[1][0] = T (v.x[1][0]);
+    x[1][1] = T (v.x[1][1]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::operator= (const Matrix22& v) IMATH_NOEXCEPT
+{
+    // Function calls and aliasing issues can inhibit vectorization versus
+    // straight assignment of data members, so we don't do this:
+    //     memcpy (x, v.x, sizeof (x));
+    // we do this:
+    x[0][0] = v.x[0][0];
+    x[0][1] = v.x[0][1];
+    x[1][0] = v.x[1][0];
+    x[1][1] = v.x[1][1];
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::operator= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] = a;
+    x[0][1] = a;
+    x[1][0] = a;
+    x[1][1] = a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline T*
+Matrix22<T>::getValue () IMATH_NOEXCEPT
+{
+    return (T*) &x[0][0];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const T*
+Matrix22<T>::getValue() const IMATH_NOEXCEPT
+{
+    return (const T*) &x[0][0];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Matrix22<T>::getValue (Matrix22<S>& v) const IMATH_NOEXCEPT
+{
+    v.x[0][0] = x[0][0];
+    v.x[0][1] = x[0][1];
+    v.x[1][0] = x[1][0];
+    v.x[1][1] = x[1][1];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix22<T>&
+Matrix22<T>::setValue (const Matrix22<S>& v) IMATH_NOEXCEPT
+{
+    x[0][0] = v.x[0][0];
+    x[0][1] = v.x[0][1];
+    x[1][0] = v.x[1][0];
+    x[1][1] = v.x[1][1];
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix22<T>&
+Matrix22<T>::setTheMatrix (const Matrix22<S>& v) IMATH_NOEXCEPT
+{
+    x[0][0] = v.x[0][0];
+    x[0][1] = v.x[0][1];
+    x[1][0] = v.x[1][0];
+    x[1][1] = v.x[1][1];
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Matrix22<T>::makeIdentity() IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = 0;
+    x[1][0] = 0;
+    x[1][1] = 1;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Matrix22<T>::operator== (const Matrix22& v) const IMATH_NOEXCEPT
+{
+    return x[0][0] == v.x[0][0] && x[0][1] == v.x[0][1] && x[1][0] == v.x[1][0] &&
+           x[1][1] == v.x[1][1];
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Matrix22<T>::operator!= (const Matrix22& v) const IMATH_NOEXCEPT
+{
+    return x[0][0] != v.x[0][0] || x[0][1] != v.x[0][1] || x[1][0] != v.x[1][0] ||
+           x[1][1] != v.x[1][1];
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Matrix22<T>::equalWithAbsError (const Matrix22<T>& m, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 2; i++)
+        for (int j = 0; j < 2; j++)
+            if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this).x[i][j], m.x[i][j], e))
+                return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Matrix22<T>::equalWithRelError (const Matrix22<T>& m, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 2; i++)
+        for (int j = 0; j < 2; j++)
+            if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this).x[i][j], m.x[i][j], e))
+                return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::operator+= (const Matrix22<T>& v) IMATH_NOEXCEPT
+{
+    x[0][0] += v.x[0][0];
+    x[0][1] += v.x[0][1];
+    x[1][0] += v.x[1][0];
+    x[1][1] += v.x[1][1];
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::operator+= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] += a;
+    x[0][1] += a;
+    x[1][0] += a;
+    x[1][1] += a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix22<T>
+Matrix22<T>::operator+ (const Matrix22<T>& v) const IMATH_NOEXCEPT
+{
+    return Matrix22 (x[0][0] + v.x[0][0],
+                     x[0][1] + v.x[0][1],
+                     x[1][0] + v.x[1][0],
+                     x[1][1] + v.x[1][1]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::operator-= (const Matrix22<T>& v) IMATH_NOEXCEPT
+{
+    x[0][0] -= v.x[0][0];
+    x[0][1] -= v.x[0][1];
+    x[1][0] -= v.x[1][0];
+    x[1][1] -= v.x[1][1];
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::operator-= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] -= a;
+    x[0][1] -= a;
+    x[1][0] -= a;
+    x[1][1] -= a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix22<T>
+Matrix22<T>::operator- (const Matrix22<T>& v) const IMATH_NOEXCEPT
+{
+    return Matrix22 (x[0][0] - v.x[0][0],
+                     x[0][1] - v.x[0][1],
+                     x[1][0] - v.x[1][0],
+                     x[1][1] - v.x[1][1]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix22<T>
+Matrix22<T>::operator-() const IMATH_NOEXCEPT
+{
+    return Matrix22 (-x[0][0], -x[0][1], -x[1][0], -x[1][1]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::negate() IMATH_NOEXCEPT
+{
+    x[0][0] = -x[0][0];
+    x[0][1] = -x[0][1];
+    x[1][0] = -x[1][0];
+    x[1][1] = -x[1][1];
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::operator*= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] *= a;
+    x[0][1] *= a;
+    x[1][0] *= a;
+    x[1][1] *= a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix22<T>
+Matrix22<T>::operator* (T a) const IMATH_NOEXCEPT
+{
+    return Matrix22 (x[0][0] * a, x[0][1] * a, x[1][0] * a, x[1][1] * a);
+}
+
+/// Matrix-scalar multiplication
+template <class T>
+IMATH_HOSTDEVICE inline Matrix22<T>
+operator* (T a, const Matrix22<T>& v) IMATH_NOEXCEPT
+{
+    return v * a;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::operator*= (const Matrix22<T>& v) IMATH_NOEXCEPT
+{
+    Matrix22 tmp (T (0));
+
+    for (int i = 0; i < 2; i++)
+        for (int j = 0; j < 2; j++)
+            for (int k = 0; k < 2; k++)
+                tmp.x[i][j] += x[i][k] * v.x[k][j];
+
+    *this = tmp;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix22<T>
+Matrix22<T>::operator* (const Matrix22<T>& v) const IMATH_NOEXCEPT
+{
+    Matrix22 tmp (T (0));
+
+    for (int i = 0; i < 2; i++)
+        for (int j = 0; j < 2; j++)
+            for (int k = 0; k < 2; k++)
+                tmp.x[i][j] += x[i][k] * v.x[k][j];
+
+    return tmp;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Matrix22<T>::multDirMatrix (const Vec2<S>& src, Vec2<S>& dst) const IMATH_NOEXCEPT
+{
+    S a, b;
+
+    a = src.x * x[0][0] + src.y * x[1][0];
+    b = src.x * x[0][1] + src.y * x[1][1];
+
+    dst.x = a;
+    dst.y = b;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::operator/= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] /= a;
+    x[0][1] /= a;
+    x[1][0] /= a;
+    x[1][1] /= a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix22<T>
+Matrix22<T>::operator/ (T a) const IMATH_NOEXCEPT
+{
+    return Matrix22 (x[0][0] / a, x[0][1] / a, x[1][0] / a, x[1][1] / a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::transpose() IMATH_NOEXCEPT
+{
+    Matrix22 tmp (x[0][0], x[1][0], x[0][1], x[1][1]);
+    *this = tmp;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix22<T>
+Matrix22<T>::transposed() const IMATH_NOEXCEPT
+{
+    return Matrix22 (x[0][0], x[1][0], x[0][1], x[1][1]);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::invert (bool singExc)
+{
+    *this = inverse (singExc);
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::invert() IMATH_NOEXCEPT
+{
+    *this = inverse();
+    return *this;
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline Matrix22<T>
+Matrix22<T>::inverse (bool singExc) const
+{
+    Matrix22 s (x[1][1], -x[0][1], -x[1][0], x[0][0]);
+
+    T r = x[0][0] * x[1][1] - x[1][0] * x[0][1];
+
+    if (IMATH_INTERNAL_NAMESPACE::abs (r) >= 1)
+    {
+        for (int i = 0; i < 2; ++i)
+        {
+            for (int j = 0; j < 2; ++j)
+            {
+                s[i][j] /= r;
+            }
+        }
+    }
+    else
+    {
+        T mr = IMATH_INTERNAL_NAMESPACE::abs (r) / std::numeric_limits<T>::min();
+
+        for (int i = 0; i < 2; ++i)
+        {
+            for (int j = 0; j < 2; ++j)
+            {
+                if (mr > IMATH_INTERNAL_NAMESPACE::abs (s[i][j]))
+                {
+                    s[i][j] /= r;
+                }
+                else
+                {
+                    if (singExc)
+                        throw std::invalid_argument ("Cannot invert "
+                                                     "singular matrix.");
+                    return Matrix22();
+                }
+            }
+        }
+    }
+    return s;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix22<T>
+Matrix22<T>::inverse() const IMATH_NOEXCEPT
+{
+    Matrix22 s (x[1][1], -x[0][1], -x[1][0], x[0][0]);
+
+    T r = x[0][0] * x[1][1] - x[1][0] * x[0][1];
+
+    if (IMATH_INTERNAL_NAMESPACE::abs (r) >= 1)
+    {
+        for (int i = 0; i < 2; ++i)
+        {
+            for (int j = 0; j < 2; ++j)
+            {
+                s[i][j] /= r;
+            }
+        }
+    }
+    else
+    {
+        T mr = IMATH_INTERNAL_NAMESPACE::abs (r) / std::numeric_limits<T>::min();
+
+        for (int i = 0; i < 2; ++i)
+        {
+            for (int j = 0; j < 2; ++j)
+            {
+                if (mr > IMATH_INTERNAL_NAMESPACE::abs (s[i][j]))
+                {
+                    s[i][j] /= r;
+                }
+                else
+                {
+                    return Matrix22();
+                }
+            }
+        }
+    }
+    return s;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Matrix22<T>::determinant() const IMATH_NOEXCEPT
+{
+    return x[0][0] * x[1][1] - x[1][0] * x[0][1];
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Matrix22<T>::trace () const IMATH_NOEXCEPT
+{
+    return x[0][0] + x[1][1];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline const Matrix22<T>&
+Matrix22<T>::setRotation (S r) IMATH_NOEXCEPT
+{
+    S cos_r, sin_r;
+
+    cos_r = cos ((T) r);
+    sin_r = sin ((T) r);
+
+    x[0][0] = cos_r;
+    x[0][1] = sin_r;
+
+    x[1][0] = -sin_r;
+    x[1][1] = cos_r;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::rotate (S r) IMATH_NOEXCEPT
+{
+    *this *= Matrix22<T>().setRotation (r);
+    return *this;
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::setScale (T s) IMATH_NOEXCEPT
+{
+    //
+    // Set the matrix to:
+    //  | s 0 |
+    //  | 0 s |
+    //
+
+    x[0][0] = s;
+    x[0][1] = static_cast<T> (0);
+    x[1][0] = static_cast<T> (0);
+    x[1][1] = s;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::setScale (const Vec2<S>& s) IMATH_NOEXCEPT
+{
+    //
+    // Set the matrix to:
+    //  | s.x  0  |
+    //  |  0  s.y |
+    //
+
+    x[0][0] = s.x;
+    x[0][1] = static_cast<T> (0);
+    x[1][0] = static_cast<T> (0);
+    x[1][1] = s.y;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix22<T>&
+Matrix22<T>::scale (const Vec2<S>& s) IMATH_NOEXCEPT
+{
+    x[0][0] *= s.x;
+    x[0][1] *= s.x;
+
+    x[1][0] *= s.y;
+    x[1][1] *= s.y;
+
+    return *this;
+}
+
+//---------------------------
+// Implementation of Matrix33
+//---------------------------
+
+template <class T>
+IMATH_HOSTDEVICE inline T*
+Matrix33<T>::operator[] (int i) IMATH_NOEXCEPT
+{
+    return x[i];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const T*
+Matrix33<T>::operator[] (int i) const IMATH_NOEXCEPT
+{
+    return x[i];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline IMATH_CONSTEXPR14
+Matrix33<T>::Matrix33() IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = 0;
+    x[0][2] = 0;
+    x[1][0] = 0;
+    x[1][1] = 1;
+    x[1][2] = 0;
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = 1;
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix33<T>::Matrix33 (T a) IMATH_NOEXCEPT
+{
+    x[0][0] = a;
+    x[0][1] = a;
+    x[0][2] = a;
+    x[1][0] = a;
+    x[1][1] = a;
+    x[1][2] = a;
+    x[2][0] = a;
+    x[2][1] = a;
+    x[2][2] = a;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix33<T>::Matrix33 (
+    const T a[3][3]) IMATH_NOEXCEPT
+{
+    // Function calls and aliasing issues can inhibit vectorization versus
+    // straight assignment of data members, so instead of this:
+    //     memcpy (x, a, sizeof (x));
+    // we do this:
+    x[0][0] = a[0][0];
+    x[0][1] = a[0][1];
+    x[0][2] = a[0][2];
+    x[1][0] = a[1][0];
+    x[1][1] = a[1][1];
+    x[1][2] = a[1][2];
+    x[2][0] = a[2][0];
+    x[2][1] = a[2][1];
+    x[2][2] = a[2][2];
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix33<T>::Matrix33 (T a, T b, T c, T d, T e, T f, T g, T h, T i) IMATH_NOEXCEPT
+{
+    x[0][0] = a;
+    x[0][1] = b;
+    x[0][2] = c;
+    x[1][0] = d;
+    x[1][1] = e;
+    x[1][2] = f;
+    x[2][0] = g;
+    x[2][1] = h;
+    x[2][2] = i;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix33<T>::Matrix33 (const Matrix33& v) IMATH_NOEXCEPT
+{
+    // Function calls and aliasing issues can inhibit vectorization versus
+    // straight assignment of data members, so instead of this:
+    //     memcpy (x, v.x, sizeof (x));
+    // we do this:
+    x[0][0] = v.x[0][0];
+    x[0][1] = v.x[0][1];
+    x[0][2] = v.x[0][2];
+    x[1][0] = v.x[1][0];
+    x[1][1] = v.x[1][1];
+    x[1][2] = v.x[1][2];
+    x[2][0] = v.x[2][0];
+    x[2][1] = v.x[2][1];
+    x[2][2] = v.x[2][2];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix33<T>::Matrix33 (const Matrix33<S>& v) IMATH_NOEXCEPT
+{
+    x[0][0] = T (v.x[0][0]);
+    x[0][1] = T (v.x[0][1]);
+    x[0][2] = T (v.x[0][2]);
+    x[1][0] = T (v.x[1][0]);
+    x[1][1] = T (v.x[1][1]);
+    x[1][2] = T (v.x[1][2]);
+    x[2][0] = T (v.x[2][0]);
+    x[2][1] = T (v.x[2][1]);
+    x[2][2] = T (v.x[2][2]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::operator= (const Matrix33& v) IMATH_NOEXCEPT
+{
+    // Function calls and aliasing issues can inhibit vectorization versus
+    // straight assignment of data members, so instead of this:
+    //     memcpy (x, v.x, sizeof (x));
+    // we do this:
+    x[0][0] = v.x[0][0];
+    x[0][1] = v.x[0][1];
+    x[0][2] = v.x[0][2];
+    x[1][0] = v.x[1][0];
+    x[1][1] = v.x[1][1];
+    x[1][2] = v.x[1][2];
+    x[2][0] = v.x[2][0];
+    x[2][1] = v.x[2][1];
+    x[2][2] = v.x[2][2];
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::operator= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] = a;
+    x[0][1] = a;
+    x[0][2] = a;
+    x[1][0] = a;
+    x[1][1] = a;
+    x[1][2] = a;
+    x[2][0] = a;
+    x[2][1] = a;
+    x[2][2] = a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline T*
+Matrix33<T>::getValue () IMATH_NOEXCEPT
+{
+    return (T*) &x[0][0];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const T*
+Matrix33<T>::getValue() const IMATH_NOEXCEPT
+{
+    return (const T*) &x[0][0];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Matrix33<T>::getValue (Matrix33<S>& v) const IMATH_NOEXCEPT
+{
+    v.x[0][0] = x[0][0];
+    v.x[0][1] = x[0][1];
+    v.x[0][2] = x[0][2];
+    v.x[1][0] = x[1][0];
+    v.x[1][1] = x[1][1];
+    v.x[1][2] = x[1][2];
+    v.x[2][0] = x[2][0];
+    v.x[2][1] = x[2][1];
+    v.x[2][2] = x[2][2];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix33<T>&
+Matrix33<T>::setValue (const Matrix33<S>& v) IMATH_NOEXCEPT
+{
+    x[0][0] = v.x[0][0];
+    x[0][1] = v.x[0][1];
+    x[0][2] = v.x[0][2];
+    x[1][0] = v.x[1][0];
+    x[1][1] = v.x[1][1];
+    x[1][2] = v.x[1][2];
+    x[2][0] = v.x[2][0];
+    x[2][1] = v.x[2][1];
+    x[2][2] = v.x[2][2];
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix33<T>&
+Matrix33<T>::setTheMatrix (const Matrix33<S>& v) IMATH_NOEXCEPT
+{
+    x[0][0] = v.x[0][0];
+    x[0][1] = v.x[0][1];
+    x[0][2] = v.x[0][2];
+    x[1][0] = v.x[1][0];
+    x[1][1] = v.x[1][1];
+    x[1][2] = v.x[1][2];
+    x[2][0] = v.x[2][0];
+    x[2][1] = v.x[2][1];
+    x[2][2] = v.x[2][2];
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Matrix33<T>::makeIdentity() IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = 0;
+    x[0][2] = 0;
+    x[1][0] = 0;
+    x[1][1] = 1;
+    x[1][2] = 0;
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = 1;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Matrix33<T>::operator== (const Matrix33& v) const IMATH_NOEXCEPT
+{
+    return x[0][0] == v.x[0][0] && x[0][1] == v.x[0][1] && x[0][2] == v.x[0][2] &&
+           x[1][0] == v.x[1][0] && x[1][1] == v.x[1][1] && x[1][2] == v.x[1][2] &&
+           x[2][0] == v.x[2][0] && x[2][1] == v.x[2][1] && x[2][2] == v.x[2][2];
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Matrix33<T>::operator!= (const Matrix33& v) const IMATH_NOEXCEPT
+{
+    return x[0][0] != v.x[0][0] || x[0][1] != v.x[0][1] || x[0][2] != v.x[0][2] ||
+           x[1][0] != v.x[1][0] || x[1][1] != v.x[1][1] || x[1][2] != v.x[1][2] ||
+           x[2][0] != v.x[2][0] || x[2][1] != v.x[2][1] || x[2][2] != v.x[2][2];
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Matrix33<T>::equalWithAbsError (const Matrix33<T>& m, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 3; i++)
+        for (int j = 0; j < 3; j++)
+            if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i][j], m[i][j], e))
+                return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Matrix33<T>::equalWithRelError (const Matrix33<T>& m, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 3; i++)
+        for (int j = 0; j < 3; j++)
+            if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i][j], m[i][j], e))
+                return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::operator+= (const Matrix33<T>& v) IMATH_NOEXCEPT
+{
+    x[0][0] += v.x[0][0];
+    x[0][1] += v.x[0][1];
+    x[0][2] += v.x[0][2];
+    x[1][0] += v.x[1][0];
+    x[1][1] += v.x[1][1];
+    x[1][2] += v.x[1][2];
+    x[2][0] += v.x[2][0];
+    x[2][1] += v.x[2][1];
+    x[2][2] += v.x[2][2];
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::operator+= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] += a;
+    x[0][1] += a;
+    x[0][2] += a;
+    x[1][0] += a;
+    x[1][1] += a;
+    x[1][2] += a;
+    x[2][0] += a;
+    x[2][1] += a;
+    x[2][2] += a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix33<T>
+Matrix33<T>::operator+ (const Matrix33<T>& v) const IMATH_NOEXCEPT
+{
+    return Matrix33 (x[0][0] + v.x[0][0],
+                     x[0][1] + v.x[0][1],
+                     x[0][2] + v.x[0][2],
+                     x[1][0] + v.x[1][0],
+                     x[1][1] + v.x[1][1],
+                     x[1][2] + v.x[1][2],
+                     x[2][0] + v.x[2][0],
+                     x[2][1] + v.x[2][1],
+                     x[2][2] + v.x[2][2]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::operator-= (const Matrix33<T>& v) IMATH_NOEXCEPT
+{
+    x[0][0] -= v.x[0][0];
+    x[0][1] -= v.x[0][1];
+    x[0][2] -= v.x[0][2];
+    x[1][0] -= v.x[1][0];
+    x[1][1] -= v.x[1][1];
+    x[1][2] -= v.x[1][2];
+    x[2][0] -= v.x[2][0];
+    x[2][1] -= v.x[2][1];
+    x[2][2] -= v.x[2][2];
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::operator-= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] -= a;
+    x[0][1] -= a;
+    x[0][2] -= a;
+    x[1][0] -= a;
+    x[1][1] -= a;
+    x[1][2] -= a;
+    x[2][0] -= a;
+    x[2][1] -= a;
+    x[2][2] -= a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix33<T>
+Matrix33<T>::operator- (const Matrix33<T>& v) const IMATH_NOEXCEPT
+{
+    return Matrix33 (x[0][0] - v.x[0][0],
+                     x[0][1] - v.x[0][1],
+                     x[0][2] - v.x[0][2],
+                     x[1][0] - v.x[1][0],
+                     x[1][1] - v.x[1][1],
+                     x[1][2] - v.x[1][2],
+                     x[2][0] - v.x[2][0],
+                     x[2][1] - v.x[2][1],
+                     x[2][2] - v.x[2][2]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix33<T>
+Matrix33<T>::operator-() const IMATH_NOEXCEPT
+{
+    return Matrix33 (-x[0][0],
+                     -x[0][1],
+                     -x[0][2],
+                     -x[1][0],
+                     -x[1][1],
+                     -x[1][2],
+                     -x[2][0],
+                     -x[2][1],
+                     -x[2][2]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::negate() IMATH_NOEXCEPT
+{
+    x[0][0] = -x[0][0];
+    x[0][1] = -x[0][1];
+    x[0][2] = -x[0][2];
+    x[1][0] = -x[1][0];
+    x[1][1] = -x[1][1];
+    x[1][2] = -x[1][2];
+    x[2][0] = -x[2][0];
+    x[2][1] = -x[2][1];
+    x[2][2] = -x[2][2];
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::operator*= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] *= a;
+    x[0][1] *= a;
+    x[0][2] *= a;
+    x[1][0] *= a;
+    x[1][1] *= a;
+    x[1][2] *= a;
+    x[2][0] *= a;
+    x[2][1] *= a;
+    x[2][2] *= a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix33<T>
+Matrix33<T>::operator* (T a) const IMATH_NOEXCEPT
+{
+    return Matrix33 (x[0][0] * a,
+                     x[0][1] * a,
+                     x[0][2] * a,
+                     x[1][0] * a,
+                     x[1][1] * a,
+                     x[1][2] * a,
+                     x[2][0] * a,
+                     x[2][1] * a,
+                     x[2][2] * a);
+}
+
+/// Matrix-scalar multiplication
+template <class T>
+IMATH_HOSTDEVICE inline Matrix33<T> constexpr
+operator* (T a, const Matrix33<T>& v) IMATH_NOEXCEPT
+{
+    return v * a;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::operator*= (const Matrix33<T>& v) IMATH_NOEXCEPT
+{
+    // Avoid initializing with 0 values before immediately overwriting them,
+    // and unroll all loops for the best autovectorization.
+    Matrix33 tmp(IMATH_INTERNAL_NAMESPACE::UNINITIALIZED);
+
+    tmp.x[0][0] = x[0][0] * v.x[0][0] + x[0][1] * v.x[1][0] + x[0][2] * v.x[2][0];
+    tmp.x[0][1] = x[0][0] * v.x[0][1] + x[0][1] * v.x[1][1] + x[0][2] * v.x[2][1];
+    tmp.x[0][2] = x[0][0] * v.x[0][2] + x[0][1] * v.x[1][2] + x[0][2] * v.x[2][2];
+
+    tmp.x[1][0] = x[1][0] * v.x[0][0] + x[1][1] * v.x[1][0] + x[1][2] * v.x[2][0];
+    tmp.x[1][1] = x[1][0] * v.x[0][1] + x[1][1] * v.x[1][1] + x[1][2] * v.x[2][1];
+    tmp.x[1][2] = x[1][0] * v.x[0][2] + x[1][1] * v.x[1][2] + x[1][2] * v.x[2][2];
+
+    tmp.x[2][0] = x[2][0] * v.x[0][0] + x[2][1] * v.x[1][0] + x[2][2] * v.x[2][0];
+    tmp.x[2][1] = x[2][0] * v.x[0][1] + x[2][1] * v.x[1][1] + x[2][2] * v.x[2][1];
+    tmp.x[2][2] = x[2][0] * v.x[0][2] + x[2][1] * v.x[1][2] + x[2][2] * v.x[2][2];
+
+    *this = tmp;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix33<T>
+Matrix33<T>::operator* (const Matrix33<T>& v) const IMATH_NOEXCEPT
+{
+    // Avoid initializing with 0 values before immediately overwriting them,
+    // and unroll all loops for the best autovectorization.
+    Matrix33 tmp(IMATH_INTERNAL_NAMESPACE::UNINITIALIZED);
+
+    tmp.x[0][0] = x[0][0] * v.x[0][0] + x[0][1] * v.x[1][0] + x[0][2] * v.x[2][0];
+    tmp.x[0][1] = x[0][0] * v.x[0][1] + x[0][1] * v.x[1][1] + x[0][2] * v.x[2][1];
+    tmp.x[0][2] = x[0][0] * v.x[0][2] + x[0][1] * v.x[1][2] + x[0][2] * v.x[2][2];
+
+    tmp.x[1][0] = x[1][0] * v.x[0][0] + x[1][1] * v.x[1][0] + x[1][2] * v.x[2][0];
+    tmp.x[1][1] = x[1][0] * v.x[0][1] + x[1][1] * v.x[1][1] + x[1][2] * v.x[2][1];
+    tmp.x[1][2] = x[1][0] * v.x[0][2] + x[1][1] * v.x[1][2] + x[1][2] * v.x[2][2];
+
+    tmp.x[2][0] = x[2][0] * v.x[0][0] + x[2][1] * v.x[1][0] + x[2][2] * v.x[2][0];
+    tmp.x[2][1] = x[2][0] * v.x[0][1] + x[2][1] * v.x[1][1] + x[2][2] * v.x[2][1];
+    tmp.x[2][2] = x[2][0] * v.x[0][2] + x[2][1] * v.x[1][2] + x[2][2] * v.x[2][2];
+
+    return tmp;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Matrix33<T>::multVecMatrix (const Vec2<S>& src, Vec2<S>& dst) const IMATH_NOEXCEPT
+{
+    S a, b, w;
+
+    a = src.x * x[0][0] + src.y * x[1][0] + x[2][0];
+    b = src.x * x[0][1] + src.y * x[1][1] + x[2][1];
+    w = src.x * x[0][2] + src.y * x[1][2] + x[2][2];
+
+    dst.x = a / w;
+    dst.y = b / w;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Matrix33<T>::multDirMatrix (const Vec2<S>& src, Vec2<S>& dst) const IMATH_NOEXCEPT
+{
+    S a, b;
+
+    a = src.x * x[0][0] + src.y * x[1][0];
+    b = src.x * x[0][1] + src.y * x[1][1];
+
+    dst.x = a;
+    dst.y = b;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::operator/= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] /= a;
+    x[0][1] /= a;
+    x[0][2] /= a;
+    x[1][0] /= a;
+    x[1][1] /= a;
+    x[1][2] /= a;
+    x[2][0] /= a;
+    x[2][1] /= a;
+    x[2][2] /= a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix33<T>
+Matrix33<T>::operator/ (T a) const IMATH_NOEXCEPT
+{
+    return Matrix33 (x[0][0] / a,
+                     x[0][1] / a,
+                     x[0][2] / a,
+                     x[1][0] / a,
+                     x[1][1] / a,
+                     x[1][2] / a,
+                     x[2][0] / a,
+                     x[2][1] / a,
+                     x[2][2] / a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::transpose() IMATH_NOEXCEPT
+{
+    Matrix33 tmp (x[0][0], x[1][0], x[2][0], x[0][1], x[1][1], x[2][1], x[0][2], x[1][2], x[2][2]);
+    *this = tmp;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix33<T>
+Matrix33<T>::transposed() const IMATH_NOEXCEPT
+{
+    return Matrix33 (x[0][0],
+                     x[1][0],
+                     x[2][0],
+                     x[0][1],
+                     x[1][1],
+                     x[2][1],
+                     x[0][2],
+                     x[1][2],
+                     x[2][2]);
+}
+
+template <class T>
+const inline Matrix33<T>&
+Matrix33<T>::gjInvert (bool singExc)
+{
+    *this = gjInverse (singExc);
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE const inline Matrix33<T>&
+Matrix33<T>::gjInvert() IMATH_NOEXCEPT
+{
+    *this = gjInverse();
+    return *this;
+}
+
+template <class T>
+inline Matrix33<T>
+Matrix33<T>::gjInverse (bool singExc) const
+{
+    int i, j, k;
+    Matrix33 s;
+    Matrix33 t (*this);
+
+    // Forward elimination
+
+    for (i = 0; i < 2; i++)
+    {
+        int pivot = i;
+
+        T pivotsize = t.x[i][i];
+
+        if (pivotsize < 0)
+            pivotsize = -pivotsize;
+
+        for (j = i + 1; j < 3; j++)
+        {
+            T tmp = t.x[j][i];
+
+            if (tmp < 0)
+                tmp = -tmp;
+
+            if (tmp > pivotsize)
+            {
+                pivot     = j;
+                pivotsize = tmp;
+            }
+        }
+
+        if (pivotsize == 0)
+        {
+            if (singExc)
+                throw std::invalid_argument ("Cannot invert singular matrix.");
+
+            return Matrix33();
+        }
+
+        if (pivot != i)
+        {
+            for (j = 0; j < 3; j++)
+            {
+                T tmp;
+
+                tmp           = t.x[i][j];
+                t.x[i][j]     = t.x[pivot][j];
+                t.x[pivot][j] = tmp;
+
+                tmp           = s.x[i][j];
+                s.x[i][j]     = s.x[pivot][j];
+                s.x[pivot][j] = tmp;
+            }
+        }
+
+        for (j = i + 1; j < 3; j++)
+        {
+            T f = t.x[j][i] / t.x[i][i];
+
+            for (k = 0; k < 3; k++)
+            {
+                t.x[j][k] -= f * t.x[i][k];
+                s.x[j][k] -= f * s.x[i][k];
+            }
+        }
+    }
+
+    // Backward substitution
+
+    for (i = 2; i >= 0; --i)
+    {
+        T f;
+
+        if ((f = t[i][i]) == 0)
+        {
+            if (singExc)
+                throw std::invalid_argument ("Cannot invert singular matrix.");
+
+            return Matrix33();
+        }
+
+        for (j = 0; j < 3; j++)
+        {
+            t.x[i][j] /= f;
+            s.x[i][j] /= f;
+        }
+
+        for (j = 0; j < i; j++)
+        {
+            f = t.x[j][i];
+
+            for (k = 0; k < 3; k++)
+            {
+                t.x[j][k] -= f * t.x[i][k];
+                s.x[j][k] -= f * s.x[i][k];
+            }
+        }
+    }
+
+    return s;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Matrix33<T>
+Matrix33<T>::gjInverse() const IMATH_NOEXCEPT
+{
+    int i, j, k;
+    Matrix33 s;
+    Matrix33 t (*this);
+
+    // Forward elimination
+
+    for (i = 0; i < 2; i++)
+    {
+        int pivot = i;
+
+        T pivotsize = t.x[i][i];
+
+        if (pivotsize < 0)
+            pivotsize = -pivotsize;
+
+        for (j = i + 1; j < 3; j++)
+        {
+            T tmp = t.x[j][i];
+
+            if (tmp < 0)
+                tmp = -tmp;
+
+            if (tmp > pivotsize)
+            {
+                pivot     = j;
+                pivotsize = tmp;
+            }
+        }
+
+        if (pivotsize == 0)
+        {
+            return Matrix33();
+        }
+
+        if (pivot != i)
+        {
+            for (j = 0; j < 3; j++)
+            {
+                T tmp;
+
+                tmp           = t.x[i][j];
+                t.x[i][j]     = t.x[pivot][j];
+                t.x[pivot][j] = tmp;
+
+                tmp           = s.x[i][j];
+                s.x[i][j]     = s.x[pivot][j];
+                s.x[pivot][j] = tmp;
+            }
+        }
+
+        for (j = i + 1; j < 3; j++)
+        {
+            T f = t.x[j][i] / t.x[i][i];
+
+            for (k = 0; k < 3; k++)
+            {
+                t.x[j][k] -= f * t.x[i][k];
+                s.x[j][k] -= f * s.x[i][k];
+            }
+        }
+    }
+
+    // Backward substitution
+
+    for (i = 2; i >= 0; --i)
+    {
+        T f;
+
+        if ((f = t.x[i][i]) == 0)
+        {
+            return Matrix33();
+        }
+
+        for (j = 0; j < 3; j++)
+        {
+            t.x[i][j] /= f;
+            s.x[i][j] /= f;
+        }
+
+        for (j = 0; j < i; j++)
+        {
+            f = t.x[j][i];
+
+            for (k = 0; k < 3; k++)
+            {
+                t.x[j][k] -= f * t.x[i][k];
+                s.x[j][k] -= f * s.x[i][k];
+            }
+        }
+    }
+
+    return s;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::invert (bool singExc)
+{
+    *this = inverse (singExc);
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::invert() IMATH_NOEXCEPT
+{
+    *this = inverse();
+    return *this;
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline Matrix33<T>
+Matrix33<T>::inverse (bool singExc) const
+{
+    if (x[0][2] != 0 || x[1][2] != 0 || x[2][2] != 1)
+    {
+        Matrix33 s (x[1][1] * x[2][2] - x[2][1] * x[1][2],
+                    x[2][1] * x[0][2] - x[0][1] * x[2][2],
+                    x[0][1] * x[1][2] - x[1][1] * x[0][2],
+
+                    x[2][0] * x[1][2] - x[1][0] * x[2][2],
+                    x[0][0] * x[2][2] - x[2][0] * x[0][2],
+                    x[1][0] * x[0][2] - x[0][0] * x[1][2],
+
+                    x[1][0] * x[2][1] - x[2][0] * x[1][1],
+                    x[2][0] * x[0][1] - x[0][0] * x[2][1],
+                    x[0][0] * x[1][1] - x[1][0] * x[0][1]);
+
+        T r = x[0][0] * s[0][0] + x[0][1] * s[1][0] + x[0][2] * s[2][0];
+
+        if (IMATH_INTERNAL_NAMESPACE::abs (r) >= 1)
+        {
+            for (int i = 0; i < 3; ++i)
+            {
+                for (int j = 0; j < 3; ++j)
+                {
+                    s.x[i][j] /= r;
+                }
+            }
+        }
+        else
+        {
+            T mr = IMATH_INTERNAL_NAMESPACE::abs (r) / std::numeric_limits<T>::min();
+
+            for (int i = 0; i < 3; ++i)
+            {
+                for (int j = 0; j < 3; ++j)
+                {
+                    if (mr > IMATH_INTERNAL_NAMESPACE::abs (s.x[i][j]))
+                    {
+                        s.x[i][j] /= r;
+                    }
+                    else
+                    {
+                        if (singExc)
+                            throw std::invalid_argument ("Cannot invert "
+                                                         "singular matrix.");
+                        return Matrix33();
+                    }
+                }
+            }
+        }
+
+        return s;
+    }
+    else
+    {
+        Matrix33 s (x[1][1],
+                    -x[0][1],
+                    0,
+
+                    -x[1][0],
+                    x[0][0],
+                    0,
+
+                    0,
+                    0,
+                    1);
+
+        T r = x[0][0] * x[1][1] - x[1][0] * x[0][1];
+
+        if (IMATH_INTERNAL_NAMESPACE::abs (r) >= 1)
+        {
+            for (int i = 0; i < 2; ++i)
+            {
+                for (int j = 0; j < 2; ++j)
+                {
+                    s.x[i][j] /= r;
+                }
+            }
+        }
+        else
+        {
+            T mr = IMATH_INTERNAL_NAMESPACE::abs (r) / std::numeric_limits<T>::min();
+
+            for (int i = 0; i < 2; ++i)
+            {
+                for (int j = 0; j < 2; ++j)
+                {
+                    if (mr > IMATH_INTERNAL_NAMESPACE::abs (s.x[i][j]))
+                    {
+                        s.x[i][j] /= r;
+                    }
+                    else
+                    {
+                        if (singExc)
+                            throw std::invalid_argument ("Cannot invert "
+                                                         "singular matrix.");
+                        return Matrix33();
+                    }
+                }
+            }
+        }
+
+        s.x[2][0] = -x[2][0] * s.x[0][0] - x[2][1] * s.x[1][0];
+        s.x[2][1] = -x[2][0] * s.x[0][1] - x[2][1] * s.x[1][1];
+
+        return s;
+    }
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix33<T>
+Matrix33<T>::inverse () const IMATH_NOEXCEPT
+{
+    if (x[0][2] != 0 || x[1][2] != 0 || x[2][2] != 1)
+    {
+        Matrix33 s (x[1][1] * x[2][2] - x[2][1] * x[1][2],
+                    x[2][1] * x[0][2] - x[0][1] * x[2][2],
+                    x[0][1] * x[1][2] - x[1][1] * x[0][2],
+
+                    x[2][0] * x[1][2] - x[1][0] * x[2][2],
+                    x[0][0] * x[2][2] - x[2][0] * x[0][2],
+                    x[1][0] * x[0][2] - x[0][0] * x[1][2],
+
+                    x[1][0] * x[2][1] - x[2][0] * x[1][1],
+                    x[2][0] * x[0][1] - x[0][0] * x[2][1],
+                    x[0][0] * x[1][1] - x[1][0] * x[0][1]);
+
+        T r = x[0][0] * s.x[0][0] + x[0][1] * s.x[1][0] + x[0][2] * s.x[2][0];
+
+        if (IMATH_INTERNAL_NAMESPACE::abs (r) >= 1)
+        {
+            for (int i = 0; i < 3; ++i)
+            {
+                for (int j = 0; j < 3; ++j)
+                {
+                    s.x[i][j] /= r;
+                }
+            }
+        }
+        else
+        {
+            T mr = IMATH_INTERNAL_NAMESPACE::abs (r) / std::numeric_limits<T>::min();
+
+            for (int i = 0; i < 3; ++i)
+            {
+                for (int j = 0; j < 3; ++j)
+                {
+                    if (mr > IMATH_INTERNAL_NAMESPACE::abs (s.x[i][j]))
+                    {
+                        s.x[i][j] /= r;
+                    }
+                    else
+                    {
+                        return Matrix33();
+                    }
+                }
+            }
+        }
+
+        return s;
+    }
+    else
+    {
+        Matrix33 s (x[1][1],
+                    -x[0][1],
+                    0,
+
+                    -x[1][0],
+                    x[0][0],
+                    0,
+
+                    0,
+                    0,
+                    1);
+
+        T r = x[0][0] * x[1][1] - x[1][0] * x[0][1];
+
+        if (IMATH_INTERNAL_NAMESPACE::abs (r) >= 1)
+        {
+            for (int i = 0; i < 2; ++i)
+            {
+                for (int j = 0; j < 2; ++j)
+                {
+                    s.x[i][j] /= r;
+                }
+            }
+        }
+        else
+        {
+            T mr = IMATH_INTERNAL_NAMESPACE::abs (r) / std::numeric_limits<T>::min();
+
+            for (int i = 0; i < 2; ++i)
+            {
+                for (int j = 0; j < 2; ++j)
+                {
+                    if (mr > IMATH_INTERNAL_NAMESPACE::abs (s.x[i][j]))
+                    {
+                        s.x[i][j] /= r;
+                    }
+                    else
+                    {
+                        return Matrix33();
+                    }
+                }
+            }
+        }
+
+        s.x[2][0] = -x[2][0] * s.x[0][0] - x[2][1] * s.x[1][0];
+        s.x[2][1] = -x[2][0] * s.x[0][1] - x[2][1] * s.x[1][1];
+
+        return s;
+    }
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+Matrix33<T>::minorOf (const int r, const int c) const IMATH_NOEXCEPT
+{
+    int r0 = 0 + (r < 1 ? 1 : 0);
+    int r1 = 1 + (r < 2 ? 1 : 0);
+    int c0 = 0 + (c < 1 ? 1 : 0);
+    int c1 = 1 + (c < 2 ? 1 : 0);
+
+    return x[r0][c0] * x[r1][c1] - x[r1][c0] * x[r0][c1];
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Matrix33<T>::fastMinor (const int r0, const int r1, const int c0, const int c1) const IMATH_NOEXCEPT
+{
+    return x[r0][c0] * x[r1][c1] - x[r0][c1] * x[r1][c0];
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Matrix33<T>::determinant() const IMATH_NOEXCEPT
+{
+    return x[0][0] * (x[1][1] * x[2][2] - x[1][2] * x[2][1]) +
+           x[0][1] * (x[1][2] * x[2][0] - x[1][0] * x[2][2]) +
+           x[0][2] * (x[1][0] * x[2][1] - x[1][1] * x[2][0]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Matrix33<T>::trace () const IMATH_NOEXCEPT
+{
+    return x[0][0] + x[1][1] + x[2][2];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline const Matrix33<T>&
+Matrix33<T>::setRotation (S r) IMATH_NOEXCEPT
+{
+    S cos_r, sin_r;
+
+    cos_r = cos ((T) r);
+    sin_r = sin ((T) r);
+
+    x[0][0] = cos_r;
+    x[0][1] = sin_r;
+    x[0][2] = 0;
+
+    x[1][0] = -sin_r;
+    x[1][1] = cos_r;
+    x[1][2] = 0;
+
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = 1;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::rotate (S r) IMATH_NOEXCEPT
+{
+    *this *= Matrix33<T>().setRotation (r);
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::setScale (T s) IMATH_NOEXCEPT
+{
+    //
+    // Set the matrix to a 2D homogeneous transform scale:
+    //  | s 0 0 |
+    //  | 0 s 0 |
+    //  | 0 0 1 |
+    //
+
+    x[0][0] = s;
+    x[0][1] = 0;
+    x[0][2] = 0;
+    x[1][0] = 0;
+    x[1][1] = s;
+    x[1][2] = 0;
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = 1;
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::setScale (const Vec2<S>& s) IMATH_NOEXCEPT
+{
+    //
+    // Set the matrix to a 2D homogeneous transform scale:
+    //  | s.x  0   0 |
+    //  |  0  s.y  0 |
+    //  |  0   0   1 |
+    //
+
+    x[0][0] = s.x;
+    x[0][1] = 0;
+    x[0][2] = 0;
+    x[1][0] = 0;
+    x[1][1] = s.y;
+    x[1][2] = 0;
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = 1;
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::scale (const Vec2<S>& s) IMATH_NOEXCEPT
+{
+    x[0][0] *= s.x;
+    x[0][1] *= s.x;
+    x[0][2] *= s.x;
+
+    x[1][0] *= s.y;
+    x[1][1] *= s.y;
+    x[1][2] *= s.y;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::setTranslation (const Vec2<S>& t) IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = 0;
+    x[0][2] = 0;
+
+    x[1][0] = 0;
+    x[1][1] = 1;
+    x[1][2] = 0;
+
+    x[2][0] = t.x;
+    x[2][1] = t.y;
+    x[2][2] = 1;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec2<T>
+Matrix33<T>::translation() const IMATH_NOEXCEPT
+{
+    return Vec2<T> (x[2][0], x[2][1]);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::translate (const Vec2<S>& t) IMATH_NOEXCEPT
+{
+    x[2][0] += t.x * x[0][0] + t.y * x[1][0];
+    x[2][1] += t.x * x[0][1] + t.y * x[1][1];
+    x[2][2] += t.x * x[0][2] + t.y * x[1][2];
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::setShear (const S& xy) IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = 0;
+    x[0][2] = 0;
+
+    x[1][0] = xy;
+    x[1][1] = 1;
+    x[1][2] = 0;
+
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = 1;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::setShear (const Vec2<S>& h) IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = h.y;
+    x[0][2] = 0;
+
+    x[1][0] = h.x;
+    x[1][1] = 1;
+    x[1][2] = 0;
+
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = 1;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::shear (const S& xy) IMATH_NOEXCEPT
+{
+    //
+    // In this case, we don't need a temp. copy of the matrix
+    // because we never use a value on the RHS after we've
+    // changed it on the LHS.
+    //
+
+    x[1][0] += xy * x[0][0];
+    x[1][1] += xy * x[0][1];
+    x[1][2] += xy * x[0][2];
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix33<T>&
+Matrix33<T>::shear (const Vec2<S>& h) IMATH_NOEXCEPT
+{
+    Matrix33<T> P (*this);
+
+    x[0][0] = P.x[0][0] + h.y * P.x[1][0];
+    x[0][1] = P.x[0][1] + h.y * P.x[1][1];
+    x[0][2] = P.x[0][2] + h.y * P.x[1][2];
+
+    x[1][0] = P.x[1][0] + h.x * P.x[0][0];
+    x[1][1] = P.x[1][1] + h.x * P.x[0][1];
+    x[1][2] = P.x[1][2] + h.x * P.x[0][2];
+
+    return *this;
+}
+
+//---------------------------
+// Implementation of Matrix44
+//---------------------------
+
+template <class T>
+IMATH_HOSTDEVICE inline T*
+Matrix44<T>::operator[] (int i) IMATH_NOEXCEPT
+{
+    return x[i];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const T*
+Matrix44<T>::operator[] (int i) const IMATH_NOEXCEPT
+{
+    return x[i];
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix44<T>::Matrix44() IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = 0;
+    x[0][2] = 0;
+    x[0][3] = 0;
+    x[1][0] = 0;
+    x[1][1] = 1;
+    x[1][2] = 0;
+    x[1][3] = 0;
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = 1;
+    x[2][3] = 0;
+    x[3][0] = 0;
+    x[3][1] = 0;
+    x[3][2] = 0;
+    x[3][3] = 1;
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix44<T>::Matrix44 (T a) IMATH_NOEXCEPT
+{
+    x[0][0] = a;
+    x[0][1] = a;
+    x[0][2] = a;
+    x[0][3] = a;
+    x[1][0] = a;
+    x[1][1] = a;
+    x[1][2] = a;
+    x[1][3] = a;
+    x[2][0] = a;
+    x[2][1] = a;
+    x[2][2] = a;
+    x[2][3] = a;
+    x[3][0] = a;
+    x[3][1] = a;
+    x[3][2] = a;
+    x[3][3] = a;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix44<T>::Matrix44 (
+    const T a[4][4]) IMATH_NOEXCEPT
+{
+    x[0][0] = a[0][0];
+    x[0][1] = a[0][1];
+    x[0][2] = a[0][2];
+    x[0][3] = a[0][3];
+    x[1][0] = a[1][0];
+    x[1][1] = a[1][1];
+    x[1][2] = a[1][2];
+    x[1][3] = a[1][3];
+    x[2][0] = a[2][0];
+    x[2][1] = a[2][1];
+    x[2][2] = a[2][2];
+    x[2][3] = a[2][3];
+    x[3][0] = a[3][0];
+    x[3][1] = a[3][1];
+    x[3][2] = a[3][2];
+    x[3][3] = a[3][3];
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix44<
+    T>::Matrix44 (T a, T b, T c, T d, T e, T f, T g, T h, T i, T j, T k, T l, T m, T n, T o, T p) IMATH_NOEXCEPT
+{
+    x[0][0] = a;
+    x[0][1] = b;
+    x[0][2] = c;
+    x[0][3] = d;
+    x[1][0] = e;
+    x[1][1] = f;
+    x[1][2] = g;
+    x[1][3] = h;
+    x[2][0] = i;
+    x[2][1] = j;
+    x[2][2] = k;
+    x[2][3] = l;
+    x[3][0] = m;
+    x[3][1] = n;
+    x[3][2] = o;
+    x[3][3] = p;
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix44<T>::Matrix44 (Matrix33<T> r, Vec3<T> t) IMATH_NOEXCEPT
+{
+    x[0][0] = r.x[0][0];
+    x[0][1] = r.x[0][1];
+    x[0][2] = r.x[0][2];
+    x[0][3] = 0;
+    x[1][0] = r.x[1][0];
+    x[1][1] = r.x[1][1];
+    x[1][2] = r.x[1][2];
+    x[1][3] = 0;
+    x[2][0] = r.x[2][0];
+    x[2][1] = r.x[2][1];
+    x[2][2] = r.x[2][2];
+    x[2][3] = 0;
+    x[3][0] = t.x;
+    x[3][1] = t.y;
+    x[3][2] = t.z;
+    x[3][3] = 1;
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix44<T>::Matrix44 (const Matrix44& v) IMATH_NOEXCEPT
+{
+    x[0][0] = v.x[0][0];
+    x[0][1] = v.x[0][1];
+    x[0][2] = v.x[0][2];
+    x[0][3] = v.x[0][3];
+    x[1][0] = v.x[1][0];
+    x[1][1] = v.x[1][1];
+    x[1][2] = v.x[1][2];
+    x[1][3] = v.x[1][3];
+    x[2][0] = v.x[2][0];
+    x[2][1] = v.x[2][1];
+    x[2][2] = v.x[2][2];
+    x[2][3] = v.x[2][3];
+    x[3][0] = v.x[3][0];
+    x[3][1] = v.x[3][1];
+    x[3][2] = v.x[3][2];
+    x[3][3] = v.x[3][3];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix44<T>::Matrix44 (const Matrix44<S>& v) IMATH_NOEXCEPT
+{
+    x[0][0] = T (v.x[0][0]);
+    x[0][1] = T (v.x[0][1]);
+    x[0][2] = T (v.x[0][2]);
+    x[0][3] = T (v.x[0][3]);
+    x[1][0] = T (v.x[1][0]);
+    x[1][1] = T (v.x[1][1]);
+    x[1][2] = T (v.x[1][2]);
+    x[1][3] = T (v.x[1][3]);
+    x[2][0] = T (v.x[2][0]);
+    x[2][1] = T (v.x[2][1]);
+    x[2][2] = T (v.x[2][2]);
+    x[2][3] = T (v.x[2][3]);
+    x[3][0] = T (v.x[3][0]);
+    x[3][1] = T (v.x[3][1]);
+    x[3][2] = T (v.x[3][2]);
+    x[3][3] = T (v.x[3][3]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::operator= (const Matrix44& v) IMATH_NOEXCEPT
+{
+    x[0][0] = v.x[0][0];
+    x[0][1] = v.x[0][1];
+    x[0][2] = v.x[0][2];
+    x[0][3] = v.x[0][3];
+    x[1][0] = v.x[1][0];
+    x[1][1] = v.x[1][1];
+    x[1][2] = v.x[1][2];
+    x[1][3] = v.x[1][3];
+    x[2][0] = v.x[2][0];
+    x[2][1] = v.x[2][1];
+    x[2][2] = v.x[2][2];
+    x[2][3] = v.x[2][3];
+    x[3][0] = v.x[3][0];
+    x[3][1] = v.x[3][1];
+    x[3][2] = v.x[3][2];
+    x[3][3] = v.x[3][3];
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::operator= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] = a;
+    x[0][1] = a;
+    x[0][2] = a;
+    x[0][3] = a;
+    x[1][0] = a;
+    x[1][1] = a;
+    x[1][2] = a;
+    x[1][3] = a;
+    x[2][0] = a;
+    x[2][1] = a;
+    x[2][2] = a;
+    x[2][3] = a;
+    x[3][0] = a;
+    x[3][1] = a;
+    x[3][2] = a;
+    x[3][3] = a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline T*
+Matrix44<T>::getValue () IMATH_NOEXCEPT
+{
+    return (T*) &x[0][0];
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const T*
+Matrix44<T>::getValue() const IMATH_NOEXCEPT
+{
+    return (const T*) &x[0][0];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Matrix44<T>::getValue (Matrix44<S>& v) const IMATH_NOEXCEPT
+{
+    v.x[0][0] = x[0][0];
+    v.x[0][1] = x[0][1];
+    v.x[0][2] = x[0][2];
+    v.x[0][3] = x[0][3];
+    v.x[1][0] = x[1][0];
+    v.x[1][1] = x[1][1];
+    v.x[1][2] = x[1][2];
+    v.x[1][3] = x[1][3];
+    v.x[2][0] = x[2][0];
+    v.x[2][1] = x[2][1];
+    v.x[2][2] = x[2][2];
+    v.x[2][3] = x[2][3];
+    v.x[3][0] = x[3][0];
+    v.x[3][1] = x[3][1];
+    v.x[3][2] = x[3][2];
+    v.x[3][3] = x[3][3];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix44<T>&
+Matrix44<T>::setValue (const Matrix44<S>& v) IMATH_NOEXCEPT
+{
+    x[0][0] = T(v.x[0][0]);
+    x[0][1] = T(v.x[0][1]);
+    x[0][2] = T(v.x[0][2]);
+    x[0][3] = T(v.x[0][3]);
+    x[1][0] = T(v.x[1][0]);
+    x[1][1] = T(v.x[1][1]);
+    x[1][2] = T(v.x[1][2]);
+    x[1][3] = T(v.x[1][3]);
+    x[2][0] = T(v.x[2][0]);
+    x[2][1] = T(v.x[2][1]);
+    x[2][2] = T(v.x[2][2]);
+    x[2][3] = T(v.x[2][3]);
+    x[3][0] = T(v.x[3][0]);
+    x[3][1] = T(v.x[3][1]);
+    x[3][2] = T(v.x[3][2]);
+    x[3][3] = T(v.x[3][3]);
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix44<T>&
+Matrix44<T>::setTheMatrix (const Matrix44<S>& v) IMATH_NOEXCEPT
+{
+    x[0][0] = v.x[0][0];
+    x[0][1] = v.x[0][1];
+    x[0][2] = v.x[0][2];
+    x[0][3] = v.x[0][3];
+    x[1][0] = v.x[1][0];
+    x[1][1] = v.x[1][1];
+    x[1][2] = v.x[1][2];
+    x[1][3] = v.x[1][3];
+    x[2][0] = v.x[2][0];
+    x[2][1] = v.x[2][1];
+    x[2][2] = v.x[2][2];
+    x[2][3] = v.x[2][3];
+    x[3][0] = v.x[3][0];
+    x[3][1] = v.x[3][1];
+    x[3][2] = v.x[3][2];
+    x[3][3] = v.x[3][3];
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Matrix44<T>::makeIdentity() IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = 0;
+    x[0][2] = 0;
+    x[0][3] = 0;
+    x[1][0] = 0;
+    x[1][1] = 1;
+    x[1][2] = 0;
+    x[1][3] = 0;
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = 1;
+    x[2][3] = 0;
+    x[3][0] = 0;
+    x[3][1] = 0;
+    x[3][2] = 0;
+    x[3][3] = 1;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Matrix44<T>::operator== (const Matrix44& v) const IMATH_NOEXCEPT
+{
+    return x[0][0] == v.x[0][0] && x[0][1] == v.x[0][1] && x[0][2] == v.x[0][2] &&
+           x[0][3] == v.x[0][3] && x[1][0] == v.x[1][0] && x[1][1] == v.x[1][1] &&
+           x[1][2] == v.x[1][2] && x[1][3] == v.x[1][3] && x[2][0] == v.x[2][0] &&
+           x[2][1] == v.x[2][1] && x[2][2] == v.x[2][2] && x[2][3] == v.x[2][3] &&
+           x[3][0] == v.x[3][0] && x[3][1] == v.x[3][1] && x[3][2] == v.x[3][2] &&
+           x[3][3] == v.x[3][3];
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline bool
+Matrix44<T>::operator!= (const Matrix44& v) const IMATH_NOEXCEPT
+{
+    return x[0][0] != v.x[0][0] || x[0][1] != v.x[0][1] || x[0][2] != v.x[0][2] ||
+           x[0][3] != v.x[0][3] || x[1][0] != v.x[1][0] || x[1][1] != v.x[1][1] ||
+           x[1][2] != v.x[1][2] || x[1][3] != v.x[1][3] || x[2][0] != v.x[2][0] ||
+           x[2][1] != v.x[2][1] || x[2][2] != v.x[2][2] || x[2][3] != v.x[2][3] ||
+           x[3][0] != v.x[3][0] || x[3][1] != v.x[3][1] || x[3][2] != v.x[3][2] ||
+           x[3][3] != v.x[3][3];
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Matrix44<T>::equalWithAbsError (const Matrix44<T>& m, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 4; i++)
+        for (int j = 0; j < 4; j++)
+            if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this).x[i][j], m.x[i][j], e))
+                return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Matrix44<T>::equalWithRelError (const Matrix44<T>& m, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 4; i++)
+        for (int j = 0; j < 4; j++)
+            if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this).x[i][j], m.x[i][j], e))
+                return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::operator+= (const Matrix44<T>& v) IMATH_NOEXCEPT
+{
+    x[0][0] += v.x[0][0];
+    x[0][1] += v.x[0][1];
+    x[0][2] += v.x[0][2];
+    x[0][3] += v.x[0][3];
+    x[1][0] += v.x[1][0];
+    x[1][1] += v.x[1][1];
+    x[1][2] += v.x[1][2];
+    x[1][3] += v.x[1][3];
+    x[2][0] += v.x[2][0];
+    x[2][1] += v.x[2][1];
+    x[2][2] += v.x[2][2];
+    x[2][3] += v.x[2][3];
+    x[3][0] += v.x[3][0];
+    x[3][1] += v.x[3][1];
+    x[3][2] += v.x[3][2];
+    x[3][3] += v.x[3][3];
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::operator+= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] += a;
+    x[0][1] += a;
+    x[0][2] += a;
+    x[0][3] += a;
+    x[1][0] += a;
+    x[1][1] += a;
+    x[1][2] += a;
+    x[1][3] += a;
+    x[2][0] += a;
+    x[2][1] += a;
+    x[2][2] += a;
+    x[2][3] += a;
+    x[3][0] += a;
+    x[3][1] += a;
+    x[3][2] += a;
+    x[3][3] += a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix44<T>
+Matrix44<T>::operator+ (const Matrix44<T>& v) const IMATH_NOEXCEPT
+{
+    return Matrix44 (x[0][0] + v.x[0][0],
+                     x[0][1] + v.x[0][1],
+                     x[0][2] + v.x[0][2],
+                     x[0][3] + v.x[0][3],
+                     x[1][0] + v.x[1][0],
+                     x[1][1] + v.x[1][1],
+                     x[1][2] + v.x[1][2],
+                     x[1][3] + v.x[1][3],
+                     x[2][0] + v.x[2][0],
+                     x[2][1] + v.x[2][1],
+                     x[2][2] + v.x[2][2],
+                     x[2][3] + v.x[2][3],
+                     x[3][0] + v.x[3][0],
+                     x[3][1] + v.x[3][1],
+                     x[3][2] + v.x[3][2],
+                     x[3][3] + v.x[3][3]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::operator-= (const Matrix44<T>& v) IMATH_NOEXCEPT
+{
+    x[0][0] -= v.x[0][0];
+    x[0][1] -= v.x[0][1];
+    x[0][2] -= v.x[0][2];
+    x[0][3] -= v.x[0][3];
+    x[1][0] -= v.x[1][0];
+    x[1][1] -= v.x[1][1];
+    x[1][2] -= v.x[1][2];
+    x[1][3] -= v.x[1][3];
+    x[2][0] -= v.x[2][0];
+    x[2][1] -= v.x[2][1];
+    x[2][2] -= v.x[2][2];
+    x[2][3] -= v.x[2][3];
+    x[3][0] -= v.x[3][0];
+    x[3][1] -= v.x[3][1];
+    x[3][2] -= v.x[3][2];
+    x[3][3] -= v.x[3][3];
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::operator-= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] -= a;
+    x[0][1] -= a;
+    x[0][2] -= a;
+    x[0][3] -= a;
+    x[1][0] -= a;
+    x[1][1] -= a;
+    x[1][2] -= a;
+    x[1][3] -= a;
+    x[2][0] -= a;
+    x[2][1] -= a;
+    x[2][2] -= a;
+    x[2][3] -= a;
+    x[3][0] -= a;
+    x[3][1] -= a;
+    x[3][2] -= a;
+    x[3][3] -= a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix44<T>
+Matrix44<T>::operator- (const Matrix44<T>& v) const IMATH_NOEXCEPT
+{
+    return Matrix44 (x[0][0] - v.x[0][0],
+                     x[0][1] - v.x[0][1],
+                     x[0][2] - v.x[0][2],
+                     x[0][3] - v.x[0][3],
+                     x[1][0] - v.x[1][0],
+                     x[1][1] - v.x[1][1],
+                     x[1][2] - v.x[1][2],
+                     x[1][3] - v.x[1][3],
+                     x[2][0] - v.x[2][0],
+                     x[2][1] - v.x[2][1],
+                     x[2][2] - v.x[2][2],
+                     x[2][3] - v.x[2][3],
+                     x[3][0] - v.x[3][0],
+                     x[3][1] - v.x[3][1],
+                     x[3][2] - v.x[3][2],
+                     x[3][3] - v.x[3][3]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix44<T>
+Matrix44<T>::operator-() const IMATH_NOEXCEPT
+{
+    return Matrix44 (-x[0][0],
+                     -x[0][1],
+                     -x[0][2],
+                     -x[0][3],
+                     -x[1][0],
+                     -x[1][1],
+                     -x[1][2],
+                     -x[1][3],
+                     -x[2][0],
+                     -x[2][1],
+                     -x[2][2],
+                     -x[2][3],
+                     -x[3][0],
+                     -x[3][1],
+                     -x[3][2],
+                     -x[3][3]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::negate() IMATH_NOEXCEPT
+{
+    x[0][0] = -x[0][0];
+    x[0][1] = -x[0][1];
+    x[0][2] = -x[0][2];
+    x[0][3] = -x[0][3];
+    x[1][0] = -x[1][0];
+    x[1][1] = -x[1][1];
+    x[1][2] = -x[1][2];
+    x[1][3] = -x[1][3];
+    x[2][0] = -x[2][0];
+    x[2][1] = -x[2][1];
+    x[2][2] = -x[2][2];
+    x[2][3] = -x[2][3];
+    x[3][0] = -x[3][0];
+    x[3][1] = -x[3][1];
+    x[3][2] = -x[3][2];
+    x[3][3] = -x[3][3];
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::operator*= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] *= a;
+    x[0][1] *= a;
+    x[0][2] *= a;
+    x[0][3] *= a;
+    x[1][0] *= a;
+    x[1][1] *= a;
+    x[1][2] *= a;
+    x[1][3] *= a;
+    x[2][0] *= a;
+    x[2][1] *= a;
+    x[2][2] *= a;
+    x[2][3] *= a;
+    x[3][0] *= a;
+    x[3][1] *= a;
+    x[3][2] *= a;
+    x[3][3] *= a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix44<T>
+Matrix44<T>::operator* (T a) const IMATH_NOEXCEPT
+{
+    return Matrix44 (x[0][0] * a,
+                     x[0][1] * a,
+                     x[0][2] * a,
+                     x[0][3] * a,
+                     x[1][0] * a,
+                     x[1][1] * a,
+                     x[1][2] * a,
+                     x[1][3] * a,
+                     x[2][0] * a,
+                     x[2][1] * a,
+                     x[2][2] * a,
+                     x[2][3] * a,
+                     x[3][0] * a,
+                     x[3][1] * a,
+                     x[3][2] * a,
+                     x[3][3] * a);
+}
+
+/// Matrix-scalar multiplication
+template <class T>
+IMATH_HOSTDEVICE inline Matrix44<T>
+operator* (T a, const Matrix44<T>& v) IMATH_NOEXCEPT
+{
+    return v * a;
+}
+
+
+template <class T>
+IMATH_HOSTDEVICE inline IMATH_CONSTEXPR14 Matrix44<T>
+Matrix44<T>::multiply (const Matrix44 &a, const Matrix44 &b) IMATH_NOEXCEPT
+{
+    const auto a00 = a.x[0][0];
+    const auto a01 = a.x[0][1];
+    const auto a02 = a.x[0][2];
+    const auto a03 = a.x[0][3];
+
+    const auto c00  = a00 * b.x[0][0] + a01 * b.x[1][0] + a02 * b.x[2][0] + a03 * b.x[3][0];
+    const auto c01  = a00 * b.x[0][1] + a01 * b.x[1][1] + a02 * b.x[2][1] + a03 * b.x[3][1];
+    const auto c02  = a00 * b.x[0][2] + a01 * b.x[1][2] + a02 * b.x[2][2] + a03 * b.x[3][2];
+    const auto c03  = a00 * b.x[0][3] + a01 * b.x[1][3] + a02 * b.x[2][3] + a03 * b.x[3][3];
+
+    const auto a10 = a.x[1][0];
+    const auto a11 = a.x[1][1];
+    const auto a12 = a.x[1][2];
+    const auto a13 = a.x[1][3];
+
+    const auto c10  = a10 * b.x[0][0] + a11 * b.x[1][0] + a12 * b.x[2][0] + a13 * b.x[3][0];
+    const auto c11  = a10 * b.x[0][1] + a11 * b.x[1][1] + a12 * b.x[2][1] + a13 * b.x[3][1];
+    const auto c12  = a10 * b.x[0][2] + a11 * b.x[1][2] + a12 * b.x[2][2] + a13 * b.x[3][2];
+    const auto c13  = a10 * b.x[0][3] + a11 * b.x[1][3] + a12 * b.x[2][3] + a13 * b.x[3][3];
+
+    const auto a20 = a.x[2][0];
+    const auto a21 = a.x[2][1];
+    const auto a22 = a.x[2][2];
+    const auto a23 = a.x[2][3];
+
+    const auto c20 = a20 * b.x[0][0] + a21 * b.x[1][0] + a22 * b.x[2][0] + a23 * b.x[3][0];
+    const auto c21 = a20 * b.x[0][1] + a21 * b.x[1][1] + a22 * b.x[2][1] + a23 * b.x[3][1];
+    const auto c22 = a20 * b.x[0][2] + a21 * b.x[1][2] + a22 * b.x[2][2] + a23 * b.x[3][2];
+    const auto c23 = a20 * b.x[0][3] + a21 * b.x[1][3] + a22 * b.x[2][3] + a23 * b.x[3][3];
+
+    const auto a30 = a.x[3][0];
+    const auto a31 = a.x[3][1];
+    const auto a32 = a.x[3][2];
+    const auto a33 = a.x[3][3];
+
+    const auto c30 = a30 * b.x[0][0] + a31 * b.x[1][0] + a32 * b.x[2][0] + a33 * b.x[3][0];
+    const auto c31 = a30 * b.x[0][1] + a31 * b.x[1][1] + a32 * b.x[2][1] + a33 * b.x[3][1];
+    const auto c32 = a30 * b.x[0][2] + a31 * b.x[1][2] + a32 * b.x[2][2] + a33 * b.x[3][2];
+    const auto c33 = a30 * b.x[0][3] + a31 * b.x[1][3] + a32 * b.x[2][3] + a33 * b.x[3][3];
+    return Matrix44(c00, c01, c02, c03,
+                    c10, c11, c12, c13,
+                    c20, c21, c22, c23,
+                    c30, c31, c32, c33);
+}
+
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::operator*= (const Matrix44<T>& v) IMATH_NOEXCEPT
+{
+    *this = multiply(*this, v);
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix44<T>
+Matrix44<T>::operator* (const Matrix44<T>& v) const IMATH_NOEXCEPT
+{
+    return multiply(*this, v);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Matrix44<T>::multiply (const Matrix44<T>& a, const Matrix44<T>& b, Matrix44<T>& c) IMATH_NOEXCEPT
+{
+    c = multiply(a, b);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Matrix44<T>::multVecMatrix (const Vec3<S>& src, Vec3<S>& dst) const IMATH_NOEXCEPT
+{
+    S a, b, c, w;
+
+    a = src.x * x[0][0] + src.y * x[1][0] + src.z * x[2][0] + x[3][0];
+    b = src.x * x[0][1] + src.y * x[1][1] + src.z * x[2][1] + x[3][1];
+    c = src.x * x[0][2] + src.y * x[1][2] + src.z * x[2][2] + x[3][2];
+    w = src.x * x[0][3] + src.y * x[1][3] + src.z * x[2][3] + x[3][3];
+
+    dst.x = a / w;
+    dst.y = b / w;
+    dst.z = c / w;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Matrix44<T>::multDirMatrix (const Vec3<S>& src, Vec3<S>& dst) const IMATH_NOEXCEPT
+{
+    S a, b, c;
+
+    a = src.x * x[0][0] + src.y * x[1][0] + src.z * x[2][0];
+    b = src.x * x[0][1] + src.y * x[1][1] + src.z * x[2][1];
+    c = src.x * x[0][2] + src.y * x[1][2] + src.z * x[2][2];
+
+    dst.x = a;
+    dst.y = b;
+    dst.z = c;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::operator/= (T a) IMATH_NOEXCEPT
+{
+    x[0][0] /= a;
+    x[0][1] /= a;
+    x[0][2] /= a;
+    x[0][3] /= a;
+    x[1][0] /= a;
+    x[1][1] /= a;
+    x[1][2] /= a;
+    x[1][3] /= a;
+    x[2][0] /= a;
+    x[2][1] /= a;
+    x[2][2] /= a;
+    x[2][3] /= a;
+    x[3][0] /= a;
+    x[3][1] /= a;
+    x[3][2] /= a;
+    x[3][3] /= a;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix44<T>
+Matrix44<T>::operator/ (T a) const IMATH_NOEXCEPT
+{
+    return Matrix44 (x[0][0] / a,
+                     x[0][1] / a,
+                     x[0][2] / a,
+                     x[0][3] / a,
+                     x[1][0] / a,
+                     x[1][1] / a,
+                     x[1][2] / a,
+                     x[1][3] / a,
+                     x[2][0] / a,
+                     x[2][1] / a,
+                     x[2][2] / a,
+                     x[2][3] / a,
+                     x[3][0] / a,
+                     x[3][1] / a,
+                     x[3][2] / a,
+                     x[3][3] / a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::transpose() IMATH_NOEXCEPT
+{
+    Matrix44 tmp (x[0][0],
+                  x[1][0],
+                  x[2][0],
+                  x[3][0],
+                  x[0][1],
+                  x[1][1],
+                  x[2][1],
+                  x[3][1],
+                  x[0][2],
+                  x[1][2],
+                  x[2][2],
+                  x[3][2],
+                  x[0][3],
+                  x[1][3],
+                  x[2][3],
+                  x[3][3]);
+    *this = tmp;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix44<T>
+Matrix44<T>::transposed() const IMATH_NOEXCEPT
+{
+    return Matrix44 (x[0][0],
+                     x[1][0],
+                     x[2][0],
+                     x[3][0],
+                     x[0][1],
+                     x[1][1],
+                     x[2][1],
+                     x[3][1],
+                     x[0][2],
+                     x[1][2],
+                     x[2][2],
+                     x[3][2],
+                     x[0][3],
+                     x[1][3],
+                     x[2][3],
+                     x[3][3]);
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::gjInvert (bool singExc)
+{
+    *this = gjInverse (singExc);
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::gjInvert() IMATH_NOEXCEPT
+{
+    *this = gjInverse();
+    return *this;
+}
+
+template <class T>
+inline Matrix44<T>
+Matrix44<T>::gjInverse (bool singExc) const
+{
+    int i, j, k;
+    Matrix44 s;
+    Matrix44 t (*this);
+
+    // Forward elimination
+
+    for (i = 0; i < 3; i++)
+    {
+        int pivot = i;
+
+        T pivotsize = t.x[i][i];
+
+        if (pivotsize < 0)
+            pivotsize = -pivotsize;
+
+        for (j = i + 1; j < 4; j++)
+        {
+            T tmp = t.x[j][i];
+
+            if (tmp < 0)
+                tmp = -tmp;
+
+            if (tmp > pivotsize)
+            {
+                pivot     = j;
+                pivotsize = tmp;
+            }
+        }
+
+        if (pivotsize == 0)
+        {
+            if (singExc)
+                throw std::invalid_argument ("Cannot invert singular matrix.");
+
+            return Matrix44();
+        }
+
+        if (pivot != i)
+        {
+            for (j = 0; j < 4; j++)
+            {
+                T tmp;
+
+                tmp           = t.x[i][j];
+                t.x[i][j]     = t.x[pivot][j];
+                t.x[pivot][j] = tmp;
+
+                tmp           = s.x[i][j];
+                s.x[i][j]     = s.x[pivot][j];
+                s.x[pivot][j] = tmp;
+            }
+        }
+
+        for (j = i + 1; j < 4; j++)
+        {
+            T f = t.x[j][i] / t.x[i][i];
+
+            for (k = 0; k < 4; k++)
+            {
+                t.x[j][k] -= f * t.x[i][k];
+                s.x[j][k] -= f * s.x[i][k];
+            }
+        }
+    }
+
+    // Backward substitution
+
+    for (i = 3; i >= 0; --i)
+    {
+        T f;
+
+        if ((f = t.x[i][i]) == 0)
+        {
+            if (singExc)
+                throw std::invalid_argument ("Cannot invert singular matrix.");
+
+            return Matrix44();
+        }
+
+        for (j = 0; j < 4; j++)
+        {
+            t.x[i][j] /= f;
+            s.x[i][j] /= f;
+        }
+
+        for (j = 0; j < i; j++)
+        {
+            f = t.x[j][i];
+
+            for (k = 0; k < 4; k++)
+            {
+                t.x[j][k] -= f * t.x[i][k];
+                s.x[j][k] -= f * s.x[i][k];
+            }
+        }
+    }
+
+    return s;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Matrix44<T>
+Matrix44<T>::gjInverse() const IMATH_NOEXCEPT
+{
+    int i, j, k;
+    Matrix44 s;
+    Matrix44 t (*this);
+
+    // Forward elimination
+
+    for (i = 0; i < 3; i++)
+    {
+        int pivot = i;
+
+        T pivotsize = t.x[i][i];
+
+        if (pivotsize < 0)
+            pivotsize = -pivotsize;
+
+        for (j = i + 1; j < 4; j++)
+        {
+            T tmp = t.x[j][i];
+
+            if (tmp < 0)
+                tmp = -tmp;
+
+            if (tmp > pivotsize)
+            {
+                pivot     = j;
+                pivotsize = tmp;
+            }
+        }
+
+        if (pivotsize == 0)
+        {
+            return Matrix44();
+        }
+
+        if (pivot != i)
+        {
+            for (j = 0; j < 4; j++)
+            {
+                T tmp;
+
+                tmp           = t.x[i][j];
+                t.x[i][j]     = t.x[pivot][j];
+                t.x[pivot][j] = tmp;
+
+                tmp           = s.x[i][j];
+                s.x[i][j]     = s.x[pivot][j];
+                s.x[pivot][j] = tmp;
+            }
+        }
+
+        for (j = i + 1; j < 4; j++)
+        {
+            T f = t.x[j][i] / t.x[i][i];
+
+            for (k = 0; k < 4; k++)
+            {
+                t.x[j][k] -= f * t.x[i][k];
+                s.x[j][k] -= f * s.x[i][k];
+            }
+        }
+    }
+
+    // Backward substitution
+
+    for (i = 3; i >= 0; --i)
+    {
+        T f;
+
+        if ((f = t.x[i][i]) == 0)
+        {
+            return Matrix44();
+        }
+
+        for (j = 0; j < 4; j++)
+        {
+            t.x[i][j] /= f;
+            s.x[i][j] /= f;
+        }
+
+        for (j = 0; j < i; j++)
+        {
+            f = t.x[j][i];
+
+            for (k = 0; k < 4; k++)
+            {
+                t.x[j][k] -= f * t.x[i][k];
+                s.x[j][k] -= f * s.x[i][k];
+            }
+        }
+    }
+
+    return s;
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::invert (bool singExc)
+{
+    *this = inverse (singExc);
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::invert() IMATH_NOEXCEPT
+{
+    *this = inverse();
+    return *this;
+}
+
+template <class T>
+IMATH_CONSTEXPR14 inline Matrix44<T>
+Matrix44<T>::inverse (bool singExc) const
+{
+    if (x[0][3] != 0 || x[1][3] != 0 || x[2][3] != 0 || x[3][3] != 1)
+        return gjInverse (singExc);
+
+    Matrix44 s (x[1][1] * x[2][2] - x[2][1] * x[1][2],
+                x[2][1] * x[0][2] - x[0][1] * x[2][2],
+                x[0][1] * x[1][2] - x[1][1] * x[0][2],
+                0,
+
+                x[2][0] * x[1][2] - x[1][0] * x[2][2],
+                x[0][0] * x[2][2] - x[2][0] * x[0][2],
+                x[1][0] * x[0][2] - x[0][0] * x[1][2],
+                0,
+
+                x[1][0] * x[2][1] - x[2][0] * x[1][1],
+                x[2][0] * x[0][1] - x[0][0] * x[2][1],
+                x[0][0] * x[1][1] - x[1][0] * x[0][1],
+                0,
+
+                0,
+                0,
+                0,
+                1);
+
+    T r = x[0][0] * s.x[0][0] + x[0][1] * s.x[1][0] + x[0][2] * s.x[2][0];
+
+    if (IMATH_INTERNAL_NAMESPACE::abs (r) >= 1)
+    {
+        for (int i = 0; i < 3; ++i)
+        {
+            for (int j = 0; j < 3; ++j)
+            {
+                s.x[i][j] /= r;
+            }
+        }
+    }
+    else
+    {
+        T mr = IMATH_INTERNAL_NAMESPACE::abs (r) / std::numeric_limits<T>::min();
+
+        for (int i = 0; i < 3; ++i)
+        {
+            for (int j = 0; j < 3; ++j)
+            {
+                if (mr > IMATH_INTERNAL_NAMESPACE::abs (s.x[i][j]))
+                {
+                    s.x[i][j] /= r;
+                }
+                else
+                {
+                    if (singExc)
+                        throw std::invalid_argument ("Cannot invert singular matrix.");
+
+                    return Matrix44();
+                }
+            }
+        }
+    }
+
+    s.x[3][0] = -x[3][0] * s.x[0][0] - x[3][1] * s.x[1][0] - x[3][2] * s.x[2][0];
+    s.x[3][1] = -x[3][0] * s.x[0][1] - x[3][1] * s.x[1][1] - x[3][2] * s.x[2][1];
+    s.x[3][2] = -x[3][0] * s.x[0][2] - x[3][1] * s.x[1][2] - x[3][2] * s.x[2][2];
+
+    return s;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Matrix44<T>
+Matrix44<T>::inverse() const IMATH_NOEXCEPT
+{
+    if (x[0][3] != 0 || x[1][3] != 0 || x[2][3] != 0 || x[3][3] != 1)
+        return gjInverse();
+
+    Matrix44 s (x[1][1] * x[2][2] - x[2][1] * x[1][2],
+                x[2][1] * x[0][2] - x[0][1] * x[2][2],
+                x[0][1] * x[1][2] - x[1][1] * x[0][2],
+                0,
+
+                x[2][0] * x[1][2] - x[1][0] * x[2][2],
+                x[0][0] * x[2][2] - x[2][0] * x[0][2],
+                x[1][0] * x[0][2] - x[0][0] * x[1][2],
+                0,
+
+                x[1][0] * x[2][1] - x[2][0] * x[1][1],
+                x[2][0] * x[0][1] - x[0][0] * x[2][1],
+                x[0][0] * x[1][1] - x[1][0] * x[0][1],
+                0,
+
+                0,
+                0,
+                0,
+                1);
+
+    T r = x[0][0] * s.x[0][0] + x[0][1] * s.x[1][0] + x[0][2] * s.x[2][0];
+
+    if (IMATH_INTERNAL_NAMESPACE::abs (r) >= 1)
+    {
+        for (int i = 0; i < 3; ++i)
+        {
+            for (int j = 0; j < 3; ++j)
+            {
+                s.x[i][j] /= r;
+            }
+        }
+    }
+    else
+    {
+        T mr = IMATH_INTERNAL_NAMESPACE::abs (r) / std::numeric_limits<T>::min();
+
+        for (int i = 0; i < 3; ++i)
+        {
+            for (int j = 0; j < 3; ++j)
+            {
+                if (mr > IMATH_INTERNAL_NAMESPACE::abs (s.x[i][j]))
+                {
+                    s.x[i][j] /= r;
+                }
+                else
+                {
+                    return Matrix44();
+                }
+            }
+        }
+    }
+
+    s.x[3][0] = -x[3][0] * s.x[0][0] - x[3][1] * s.x[1][0] - x[3][2] * s.x[2][0];
+    s.x[3][1] = -x[3][0] * s.x[0][1] - x[3][1] * s.x[1][1] - x[3][2] * s.x[2][1];
+    s.x[3][2] = -x[3][0] * s.x[0][2] - x[3][1] * s.x[1][2] - x[3][2] * s.x[2][2];
+
+    return s;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Matrix44<T>::fastMinor (const int r0,
+                        const int r1,
+                        const int r2,
+                        const int c0,
+                        const int c1,
+                        const int c2) const IMATH_NOEXCEPT
+{
+    return x[r0][c0] * (x[r1][c1] * x[r2][c2] - x[r1][c2] * x[r2][c1]) +
+           x[r0][c1] * (x[r1][c2] * x[r2][c0] - x[r1][c0] * x[r2][c2]) +
+           x[r0][c2] * (x[r1][c0] * x[r2][c1] - x[r1][c1] * x[r2][c0]);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+Matrix44<T>::minorOf (const int r, const int c) const IMATH_NOEXCEPT
+{
+    int r0 = 0 + (r < 1 ? 1 : 0);
+    int r1 = 1 + (r < 2 ? 1 : 0);
+    int r2 = 2 + (r < 3 ? 1 : 0);
+    int c0 = 0 + (c < 1 ? 1 : 0);
+    int c1 = 1 + (c < 2 ? 1 : 0);
+    int c2 = 2 + (c < 3 ? 1 : 0);
+
+    Matrix33<T> working (x[r0][c0],
+                         x[r1][c0],
+                         x[r2][c0],
+                         x[r0][c1],
+                         x[r1][c1],
+                         x[r2][c1],
+                         x[r0][c2],
+                         x[r1][c2],
+                         x[r2][c2]);
+
+    return working.determinant();
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+Matrix44<T>::determinant() const IMATH_NOEXCEPT
+{
+    T sum = (T) 0;
+
+    if (x[0][3] != 0.)
+        sum -= x[0][3] * fastMinor (1, 2, 3, 0, 1, 2);
+    if (x[1][3] != 0.)
+        sum += x[1][3] * fastMinor (0, 2, 3, 0, 1, 2);
+    if (x[2][3] != 0.)
+        sum -= x[2][3] * fastMinor (0, 1, 3, 0, 1, 2);
+    if (x[3][3] != 0.)
+        sum += x[3][3] * fastMinor (0, 1, 2, 0, 1, 2);
+
+    return sum;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Matrix44<T>::trace () const IMATH_NOEXCEPT
+{
+    return x[0][0] + x[1][1] + x[2][2] + x[3][3];
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline const Matrix44<T>&
+Matrix44<T>::setEulerAngles (const Vec3<S>& r) IMATH_NOEXCEPT
+{
+    S cos_rz, sin_rz, cos_ry, sin_ry, cos_rx, sin_rx;
+
+    cos_rz = cos ((T) r.z);
+    cos_ry = cos ((T) r.y);
+    cos_rx = cos ((T) r.x);
+
+    sin_rz = sin ((T) r.z);
+    sin_ry = sin ((T) r.y);
+    sin_rx = sin ((T) r.x);
+
+    x[0][0] = cos_rz * cos_ry;
+    x[0][1] = sin_rz * cos_ry;
+    x[0][2] = -sin_ry;
+    x[0][3] = 0;
+
+    x[1][0] = -sin_rz * cos_rx + cos_rz * sin_ry * sin_rx;
+    x[1][1] = cos_rz * cos_rx + sin_rz * sin_ry * sin_rx;
+    x[1][2] = cos_ry * sin_rx;
+    x[1][3] = 0;
+
+    x[2][0] = sin_rz * sin_rx + cos_rz * sin_ry * cos_rx;
+    x[2][1] = -cos_rz * sin_rx + sin_rz * sin_ry * cos_rx;
+    x[2][2] = cos_ry * cos_rx;
+    x[2][3] = 0;
+
+    x[3][0] = 0;
+    x[3][1] = 0;
+    x[3][2] = 0;
+    x[3][3] = 1;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::setAxisAngle (const Vec3<S>& axis, S angle) IMATH_NOEXCEPT
+{
+    Vec3<S> unit (axis.normalized());
+    S sine   = std::sin (angle);
+    S cosine = std::cos (angle);
+
+    x[0][0] = unit.x * unit.x * (1 - cosine) + cosine;
+    x[0][1] = unit.x * unit.y * (1 - cosine) + unit.z * sine;
+    x[0][2] = unit.x * unit.z * (1 - cosine) - unit.y * sine;
+    x[0][3] = 0;
+
+    x[1][0] = unit.x * unit.y * (1 - cosine) - unit.z * sine;
+    x[1][1] = unit.y * unit.y * (1 - cosine) + cosine;
+    x[1][2] = unit.y * unit.z * (1 - cosine) + unit.x * sine;
+    x[1][3] = 0;
+
+    x[2][0] = unit.x * unit.z * (1 - cosine) + unit.y * sine;
+    x[2][1] = unit.y * unit.z * (1 - cosine) - unit.x * sine;
+    x[2][2] = unit.z * unit.z * (1 - cosine) + cosine;
+    x[2][3] = 0;
+
+    x[3][0] = 0;
+    x[3][1] = 0;
+    x[3][2] = 0;
+    x[3][3] = 1;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline const Matrix44<T>&
+Matrix44<T>::rotate (const Vec3<S>& r) IMATH_NOEXCEPT
+{
+    S cos_rz, sin_rz, cos_ry, sin_ry, cos_rx, sin_rx;
+    S m00, m01, m02;
+    S m10, m11, m12;
+    S m20, m21, m22;
+
+    cos_rz = cos ((S) r.z);
+    cos_ry = cos ((S) r.y);
+    cos_rx = cos ((S) r.x);
+
+    sin_rz = sin ((S) r.z);
+    sin_ry = sin ((S) r.y);
+    sin_rx = sin ((S) r.x);
+
+    m00 = cos_rz * cos_ry;
+    m01 = sin_rz * cos_ry;
+    m02 = -sin_ry;
+    m10 = -sin_rz * cos_rx + cos_rz * sin_ry * sin_rx;
+    m11 = cos_rz * cos_rx + sin_rz * sin_ry * sin_rx;
+    m12 = cos_ry * sin_rx;
+    m20 = -sin_rz * -sin_rx + cos_rz * sin_ry * cos_rx;
+    m21 = cos_rz * -sin_rx + sin_rz * sin_ry * cos_rx;
+    m22 = cos_ry * cos_rx;
+
+    Matrix44<T> P (*this);
+
+    x[0][0] = P.x[0][0] * m00 + P.x[1][0] * m01 + P.x[2][0] * m02;
+    x[0][1] = P.x[0][1] * m00 + P.x[1][1] * m01 + P.x[2][1] * m02;
+    x[0][2] = P.x[0][2] * m00 + P.x[1][2] * m01 + P.x[2][2] * m02;
+    x[0][3] = P.x[0][3] * m00 + P.x[1][3] * m01 + P.x[2][3] * m02;
+
+    x[1][0] = P.x[0][0] * m10 + P.x[1][0] * m11 + P.x[2][0] * m12;
+    x[1][1] = P.x[0][1] * m10 + P.x[1][1] * m11 + P.x[2][1] * m12;
+    x[1][2] = P.x[0][2] * m10 + P.x[1][2] * m11 + P.x[2][2] * m12;
+    x[1][3] = P.x[0][3] * m10 + P.x[1][3] * m11 + P.x[2][3] * m12;
+
+    x[2][0] = P.x[0][0] * m20 + P.x[1][0] * m21 + P.x[2][0] * m22;
+    x[2][1] = P.x[0][1] * m20 + P.x[1][1] * m21 + P.x[2][1] * m22;
+    x[2][2] = P.x[0][2] * m20 + P.x[1][2] * m21 + P.x[2][2] * m22;
+    x[2][3] = P.x[0][3] * m20 + P.x[1][3] * m21 + P.x[2][3] * m22;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::setScale (T s) IMATH_NOEXCEPT
+{
+    //
+    // Set the matrix to a 3D homogeneous transform scale:
+    //  | s 0 0 0 |
+    //  | 0 s 0 0 |
+    //  | 0 0 s 0 |
+    //  | 0 0 0 1 |
+    //
+
+    x[0][0] = s;
+    x[0][1] = 0;
+    x[0][2] = 0;
+    x[0][3] = 0;
+    x[1][0] = 0;
+    x[1][1] = s;
+    x[1][2] = 0;
+    x[1][3] = 0;
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = s;
+    x[2][3] = 0;
+    x[3][0] = 0;
+    x[3][1] = 0;
+    x[3][2] = 0;
+    x[3][3] = 1;
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::setScale (const Vec3<S>& s) IMATH_NOEXCEPT
+{
+    //
+    // Set the matrix to a 3D homogeneous transform scale:
+    //  | s.x  0   0   0 |
+    //  |  0  s.y  0   0 |
+    //  |  0   0  s.z  0 |
+    //  |  0   0   0   1 |
+    //
+
+    x[0][0] = s.x;
+    x[0][1] = 0;
+    x[0][2] = 0;
+    x[0][3] = 0;
+    x[1][0] = 0;
+    x[1][1] = s.y;
+    x[1][2] = 0;
+    x[1][3] = 0;
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = s.z;
+    x[2][3] = 0;
+    x[3][0] = 0;
+    x[3][1] = 0;
+    x[3][2] = 0;
+    x[3][3] = 1;
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::scale (const Vec3<S>& s) IMATH_NOEXCEPT
+{
+    x[0][0] *= s.x;
+    x[0][1] *= s.x;
+    x[0][2] *= s.x;
+    x[0][3] *= s.x;
+
+    x[1][0] *= s.y;
+    x[1][1] *= s.y;
+    x[1][2] *= s.y;
+    x[1][3] *= s.y;
+
+    x[2][0] *= s.z;
+    x[2][1] *= s.z;
+    x[2][2] *= s.z;
+    x[2][3] *= s.z;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::setTranslation (const Vec3<S>& t) IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = 0;
+    x[0][2] = 0;
+    x[0][3] = 0;
+
+    x[1][0] = 0;
+    x[1][1] = 1;
+    x[1][2] = 0;
+    x[1][3] = 0;
+
+    x[2][0] = 0;
+    x[2][1] = 0;
+    x[2][2] = 1;
+    x[2][3] = 0;
+
+    x[3][0] = t.x;
+    x[3][1] = t.y;
+    x[3][2] = t.z;
+    x[3][3] = 1;
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline const Vec3<T>
+Matrix44<T>::translation() const IMATH_NOEXCEPT
+{
+    return Vec3<T> (x[3][0], x[3][1], x[3][2]);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::translate (const Vec3<S>& t) IMATH_NOEXCEPT
+{
+    x[3][0] += t.x * x[0][0] + t.y * x[1][0] + t.z * x[2][0];
+    x[3][1] += t.x * x[0][1] + t.y * x[1][1] + t.z * x[2][1];
+    x[3][2] += t.x * x[0][2] + t.y * x[1][2] + t.z * x[2][2];
+    x[3][3] += t.x * x[0][3] + t.y * x[1][3] + t.z * x[2][3];
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::setShear (const Vec3<S>& h) IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = 0;
+    x[0][2] = 0;
+    x[0][3] = 0;
+
+    x[1][0] = h.x;
+    x[1][1] = 1;
+    x[1][2] = 0;
+    x[1][3] = 0;
+
+    x[2][0] = h.y;
+    x[2][1] = h.z;
+    x[2][2] = 1;
+    x[2][3] = 0;
+
+    x[3][0] = 0;
+    x[3][1] = 0;
+    x[3][2] = 0;
+    x[3][3] = 1;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::setShear (const Shear6<S>& h) IMATH_NOEXCEPT
+{
+    x[0][0] = 1;
+    x[0][1] = h.yx;
+    x[0][2] = h.zx;
+    x[0][3] = 0;
+
+    x[1][0] = h.xy;
+    x[1][1] = 1;
+    x[1][2] = h.zy;
+    x[1][3] = 0;
+
+    x[2][0] = h.xz;
+    x[2][1] = h.yz;
+    x[2][2] = 1;
+    x[2][3] = 0;
+
+    x[3][0] = 0;
+    x[3][1] = 0;
+    x[3][2] = 0;
+    x[3][3] = 1;
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::shear (const Vec3<S>& h) IMATH_NOEXCEPT
+{
+    //
+    // In this case, we don't need a temp. copy of the matrix
+    // because we never use a value on the RHS after we've
+    // changed it on the LHS.
+    //
+
+    for (int i = 0; i < 4; i++)
+    {
+        x[2][i] += h.y * x[0][i] + h.z * x[1][i];
+        x[1][i] += h.x * x[0][i];
+    }
+
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Matrix44<T>&
+Matrix44<T>::shear (const Shear6<S>& h) IMATH_NOEXCEPT
+{
+    Matrix44<T> P (*this);
+
+    for (int i = 0; i < 4; i++)
+    {
+        x[0][i] = P.x[0][i] + h.yx * P.x[1][i] + h.zx * P.x[2][i];
+        x[1][i] = h.xy * P.x[0][i] + P.x[1][i] + h.zy * P.x[2][i];
+        x[2][i] = h.xz * P.x[0][i] + h.yz * P.x[1][i] + P.x[2][i];
+    }
+
+    return *this;
+}
+
+//--------------------------------
+// Implementation of stream output
+//--------------------------------
+
+template <class T>
+std::ostream&
+operator<< (std::ostream& s, const Matrix22<T>& m)
+{
+    std::ios_base::fmtflags oldFlags = s.flags();
+    int width;
+
+    if (s.flags() & std::ios_base::fixed)
+    {
+        s.setf (std::ios_base::showpoint);
+        width = static_cast<int> (s.precision()) + 5;
+    }
+    else
+    {
+        s.setf (std::ios_base::scientific);
+        s.setf (std::ios_base::showpoint);
+        width = static_cast<int> (s.precision()) + 8;
+    }
+
+    s << "(" << std::setw (width) << m[0][0] << " " << std::setw (width) << m[0][1] << "\n"
+      <<
+
+        " " << std::setw (width) << m[1][0] << " " << std::setw (width) << m[1][1] << ")\n";
+
+    s.flags (oldFlags);
+    return s;
+}
+
+template <class T>
+std::ostream&
+operator<< (std::ostream& s, const Matrix33<T>& m)
+{
+    std::ios_base::fmtflags oldFlags = s.flags();
+    int width;
+
+    if (s.flags() & std::ios_base::fixed)
+    {
+        s.setf (std::ios_base::showpoint);
+        width = static_cast<int> (s.precision()) + 5;
+    }
+    else
+    {
+        s.setf (std::ios_base::scientific);
+        s.setf (std::ios_base::showpoint);
+        width = static_cast<int> (s.precision()) + 8;
+    }
+
+    s << "(" << std::setw (width) << m[0][0] << " " << std::setw (width) << m[0][1] << " "
+      << std::setw (width) << m[0][2] << "\n"
+      <<
+
+        " " << std::setw (width) << m[1][0] << " " << std::setw (width) << m[1][1] << " "
+      << std::setw (width) << m[1][2] << "\n"
+      <<
+
+        " " << std::setw (width) << m[2][0] << " " << std::setw (width) << m[2][1] << " "
+      << std::setw (width) << m[2][2] << ")\n";
+
+    s.flags (oldFlags);
+    return s;
+}
+
+template <class T>
+std::ostream&
+operator<< (std::ostream& s, const Matrix44<T>& m)
+{
+    std::ios_base::fmtflags oldFlags = s.flags();
+    int width;
+
+    if (s.flags() & std::ios_base::fixed)
+    {
+        s.setf (std::ios_base::showpoint);
+        width = static_cast<int> (s.precision()) + 5;
+    }
+    else
+    {
+        s.setf (std::ios_base::scientific);
+        s.setf (std::ios_base::showpoint);
+        width = static_cast<int> (s.precision()) + 8;
+    }
+
+    s << "(" << std::setw (width) << m[0][0] << " " << std::setw (width) << m[0][1] << " "
+      << std::setw (width) << m[0][2] << " " << std::setw (width) << m[0][3] << "\n"
+      <<
+
+        " " << std::setw (width) << m[1][0] << " " << std::setw (width) << m[1][1] << " "
+      << std::setw (width) << m[1][2] << " " << std::setw (width) << m[1][3] << "\n"
+      <<
+
+        " " << std::setw (width) << m[2][0] << " " << std::setw (width) << m[2][1] << " "
+      << std::setw (width) << m[2][2] << " " << std::setw (width) << m[2][3] << "\n"
+      <<
+
+        " " << std::setw (width) << m[3][0] << " " << std::setw (width) << m[3][1] << " "
+      << std::setw (width) << m[3][2] << " " << std::setw (width) << m[3][3] << ")\n";
+
+    s.flags (oldFlags);
+    return s;
+}
+
+//---------------------------------------------------------------
+// Implementation of vector-times-matrix multiplication operators
+//---------------------------------------------------------------
+
+template <class S, class T>
+IMATH_HOSTDEVICE inline const Vec2<S>&
+operator*= (Vec2<S>& v, const Matrix22<T>& m) IMATH_NOEXCEPT
+{
+    S x = S (v.x * m.x[0][0] + v.y * m.x[1][0]);
+    S y = S (v.x * m.x[0][1] + v.y * m.x[1][1]);
+
+    v.x = x;
+    v.y = y;
+
+    return v;
+}
+
+template <class S, class T>
+IMATH_HOSTDEVICE inline Vec2<S>
+operator* (const Vec2<S>& v, const Matrix22<T>& m) IMATH_NOEXCEPT
+{
+    S x = S (v.x * m.x[0][0] + v.y * m.x[1][0]);
+    S y = S (v.x * m.x[0][1] + v.y * m.x[1][1]);
+
+    return Vec2<S> (x, y);
+}
+
+template <class S, class T>
+IMATH_HOSTDEVICE inline const Vec2<S>&
+operator*= (Vec2<S>& v, const Matrix33<T>& m) IMATH_NOEXCEPT
+{
+    S x = S (v.x * m.x[0][0] + v.y * m.x[1][0] + m.x[2][0]);
+    S y = S (v.x * m.x[0][1] + v.y * m.x[1][1] + m.x[2][1]);
+    S w = S (v.x * m.x[0][2] + v.y * m.x[1][2] + m.x[2][2]);
+
+    v.x = x / w;
+    v.y = y / w;
+
+    return v;
+}
+
+template <class S, class T>
+IMATH_HOSTDEVICE inline Vec2<S>
+operator* (const Vec2<S>& v, const Matrix33<T>& m) IMATH_NOEXCEPT
+{
+    S x = S (v.x * m.x[0][0] + v.y * m.x[1][0] + m.x[2][0]);
+    S y = S (v.x * m.x[0][1] + v.y * m.x[1][1] + m.x[2][1]);
+    S w = S (v.x * m.x[0][2] + v.y * m.x[1][2] + m.x[2][2]);
+
+    return Vec2<S> (x / w, y / w);
+}
+
+template <class S, class T>
+IMATH_HOSTDEVICE inline const Vec3<S>&
+operator*= (Vec3<S>& v, const Matrix33<T>& m) IMATH_NOEXCEPT
+{
+    S x = S (v.x * m.x[0][0] + v.y * m.x[1][0] + v.z * m.x[2][0]);
+    S y = S (v.x * m.x[0][1] + v.y * m.x[1][1] + v.z * m.x[2][1]);
+    S z = S (v.x * m.x[0][2] + v.y * m.x[1][2] + v.z * m.x[2][2]);
+
+    v.x = x;
+    v.y = y;
+    v.z = z;
+
+    return v;
+}
+
+template <class S, class T>
+IMATH_HOSTDEVICE inline Vec3<S>
+operator* (const Vec3<S>& v, const Matrix33<T>& m) IMATH_NOEXCEPT
+{
+    S x = S (v.x * m.x[0][0] + v.y * m.x[1][0] + v.z * m.x[2][0]);
+    S y = S (v.x * m.x[0][1] + v.y * m.x[1][1] + v.z * m.x[2][1]);
+    S z = S (v.x * m.x[0][2] + v.y * m.x[1][2] + v.z * m.x[2][2]);
+
+    return Vec3<S> (x, y, z);
+}
+
+template <class S, class T>
+IMATH_HOSTDEVICE inline const Vec3<S>&
+operator*= (Vec3<S>& v, const Matrix44<T>& m) IMATH_NOEXCEPT
+{
+    S x = S (v.x * m.x[0][0] + v.y * m.x[1][0] + v.z * m.x[2][0] + m.x[3][0]);
+    S y = S (v.x * m.x[0][1] + v.y * m.x[1][1] + v.z * m.x[2][1] + m.x[3][1]);
+    S z = S (v.x * m.x[0][2] + v.y * m.x[1][2] + v.z * m.x[2][2] + m.x[3][2]);
+    S w = S (v.x * m.x[0][3] + v.y * m.x[1][3] + v.z * m.x[2][3] + m.x[3][3]);
+
+    v.x = x / w;
+    v.y = y / w;
+    v.z = z / w;
+
+    return v;
+}
+
+template <class S, class T>
+IMATH_HOSTDEVICE inline Vec3<S>
+IMATH_HOSTDEVICE operator* (const Vec3<S>& v, const Matrix44<T>& m) IMATH_NOEXCEPT
+{
+    S x = S (v.x * m.x[0][0] + v.y * m.x[1][0] + v.z * m.x[2][0] + m.x[3][0]);
+    S y = S (v.x * m.x[0][1] + v.y * m.x[1][1] + v.z * m.x[2][1] + m.x[3][1]);
+    S z = S (v.x * m.x[0][2] + v.y * m.x[1][2] + v.z * m.x[2][2] + m.x[3][2]);
+    S w = S (v.x * m.x[0][3] + v.y * m.x[1][3] + v.z * m.x[2][3] + m.x[3][3]);
+
+    return Vec3<S> (x / w, y / w, z / w);
+}
+
+template <class S, class T>
+IMATH_HOSTDEVICE inline const Vec4<S>&
+IMATH_HOSTDEVICE operator*= (Vec4<S>& v, const Matrix44<T>& m) IMATH_NOEXCEPT
+{
+    S x = S (v.x * m.x[0][0] + v.y * m.x[1][0] + v.z * m.x[2][0] + v.w * m.x[3][0]);
+    S y = S (v.x * m.x[0][1] + v.y * m.x[1][1] + v.z * m.x[2][1] + v.w * m.x[3][1]);
+    S z = S (v.x * m.x[0][2] + v.y * m.x[1][2] + v.z * m.x[2][2] + v.w * m.x[3][2]);
+    S w = S (v.x * m.x[0][3] + v.y * m.x[1][3] + v.z * m.x[2][3] + v.w * m.x[3][3]);
+
+    v.x = x;
+    v.y = y;
+    v.z = z;
+    v.w = w;
+
+    return v;
+}
+
+template <class S, class T>
+IMATH_HOSTDEVICE inline Vec4<S>
+IMATH_HOSTDEVICE operator* (const Vec4<S>& v, const Matrix44<T>& m) IMATH_NOEXCEPT
+{
+    S x = S (v.x * m.x[0][0] + v.y * m.x[1][0] + v.z * m.x[2][0] + v.w * m.x[3][0]);
+    S y = S (v.x * m.x[0][1] + v.y * m.x[1][1] + v.z * m.x[2][1] + v.w * m.x[3][1]);
+    S z = S (v.x * m.x[0][2] + v.y * m.x[1][2] + v.z * m.x[2][2] + v.w * m.x[3][2]);
+    S w = S (v.x * m.x[0][3] + v.y * m.x[1][3] + v.z * m.x[2][3] + v.w * m.x[3][3]);
+
+    return Vec4<S> (x, y, z, w);
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHMATRIX_H
diff --git a/src/Imath/ImathMatrixAlgo.cpp b/src/Imath/ImathMatrixAlgo.cpp
new file mode 100644 (file)
index 0000000..746751f
--- /dev/null
@@ -0,0 +1,1246 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+///
+/// @file  ImathMatrixAlgo.cpp
+///
+/// @brief Functions operating on Matrix22, Matrix33, and Matrix44 types.
+///
+
+// clang-format off
+/// @cond Doxygen_Suppress
+
+#include "ImathMatrixAlgo.h"
+#include <algorithm>
+#include <cmath>
+
+#if defined(IMATH_DLL)
+#    define EXPORT_CONST __declspec(dllexport)
+#else
+#    define EXPORT_CONST const
+#endif
+
+IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+EXPORT_CONST M22f identity22f ( 1, 0,
+                               0, 1);
+EXPORT_CONST M22d identity22d ( 1, 0,
+                               0, 1);
+EXPORT_CONST M33f identity33f ( 1, 0, 0,
+                               0, 1, 0,
+                               0, 0, 1);
+EXPORT_CONST M33d identity33d ( 1, 0, 0,
+                               0, 1, 0,
+                               0, 0, 1);
+EXPORT_CONST M44f identity44f ( 1, 0, 0, 0,
+                               0, 1, 0, 0,
+                               0, 0, 1, 0,
+                               0, 0, 0, 1);
+EXPORT_CONST M44d identity44d ( 1, 0, 0, 0,
+                               0, 1, 0, 0,
+                               0, 0, 1, 0,
+                               0, 0, 0, 1);
+
+// clang-format on
+
+namespace
+{
+
+class KahanSum
+{
+  public:
+    KahanSum() : _total (0), _correction (0) {}
+
+    void operator+= (const double val)
+    {
+        const double y = val - _correction;
+        const double t = _total + y;
+        _correction    = (t - _total) - y;
+        _total         = t;
+    }
+
+    double get() const { return _total; }
+
+  private:
+    double _total;
+    double _correction;
+};
+
+} // namespace
+
+template <typename T>
+M44d
+procrustesRotationAndTranslation (const Vec3<T>* A,
+                                  const Vec3<T>* B,
+                                  const T* weights,
+                                  const size_t numPoints,
+                                  const bool doScale)
+{
+    if (numPoints == 0)
+        return M44d();
+
+    // Always do the accumulation in double precision:
+    V3d Acenter (0.0);
+    V3d Bcenter (0.0);
+    double weightsSum = 0.0;
+
+    if (weights == 0)
+    {
+        for (size_t i = 0; i < numPoints; ++i)
+        {
+            Acenter += (V3d) A[i];
+            Bcenter += (V3d) B[i];
+        }
+        weightsSum = (double) numPoints;
+    }
+    else
+    {
+        for (size_t i = 0; i < numPoints; ++i)
+        {
+            const double w = weights[i];
+            weightsSum += w;
+
+            Acenter += w * (V3d) A[i];
+            Bcenter += w * (V3d) B[i];
+        }
+    }
+
+    if (weightsSum == 0)
+        return M44d();
+
+    Acenter /= weightsSum;
+    Bcenter /= weightsSum;
+
+    //
+    // Find Q such that |Q*A - B|  (actually A-Acenter and B-Bcenter, weighted)
+    // is minimized in the least squares sense.
+    // From Golub/Van Loan, p.601
+    //
+    // A,B are 3xn
+    // Let C = B A^T   (where A is 3xn and B^T is nx3, so C is 3x3)
+    // Compute the SVD: C = U D V^T  (U,V rotations, D diagonal).
+    // Throw away the D part, and return Q = U V^T
+    M33d C (0.0);
+    if (weights == 0)
+    {
+        for (size_t i = 0; i < numPoints; ++i)
+            C += outerProduct ((V3d) B[i] - Bcenter, (V3d) A[i] - Acenter);
+    }
+    else
+    {
+        for (size_t i = 0; i < numPoints; ++i)
+        {
+            const double w = weights[i];
+            C += outerProduct (w * ((V3d) B[i] - Bcenter), (V3d) A[i] - Acenter);
+        }
+    }
+
+    M33d U, V;
+    V3d S;
+    jacobiSVD (C, U, S, V, std::numeric_limits<double>::epsilon(), true);
+
+    // We want Q.transposed() here since we are going to be using it in the
+    // Imath style (multiplying vectors on the right, v' = v*A^T):
+    const M33d Qt = V * U.transposed();
+
+    double s = 1.0;
+    if (doScale && numPoints > 1)
+    {
+        // Finding a uniform scale: let us assume the Q is completely fixed
+        // at this point (solving for both simultaneously seems much harder).
+        // We are trying to compute (again, per Golub and van Loan)
+        //    min || s*A*Q - B ||_F
+        // Notice that we've jammed a uniform scale in front of the Q.
+        // Now, the Frobenius norm (the least squares norm over matrices)
+        // has the neat property that it is equivalent to minimizing the trace
+        // of M^T*M (see your friendly neighborhood linear algebra text for a
+        // derivation).  Thus, we can expand this out as
+        //   min tr (s*A*Q - B)^T*(s*A*Q - B)
+        // = min tr(Q^T*A^T*s*s*A*Q) + tr(B^T*B) - 2*tr(Q^T*A^T*s*B)  by linearity of the trace
+        // = min s^2 tr(A^T*A) + tr(B^T*B) - 2*s*tr(Q^T*A^T*B)        using the fact that the trace is invariant
+        //                                                            under similarity transforms Q*M*Q^T
+        // If we differentiate w.r.t. s and set this to 0, we get
+        // 0 = 2*s*tr(A^T*A) - 2*tr(Q^T*A^T*B)
+        // so
+        // 2*s*tr(A^T*A) = 2*s*tr(Q^T*A^T*B)
+        // s = tr(Q^T*A^T*B) / tr(A^T*A)
+
+        KahanSum traceATA;
+        if (weights == 0)
+        {
+            for (size_t i = 0; i < numPoints; ++i)
+                traceATA += ((V3d) A[i] - Acenter).length2();
+        }
+        else
+        {
+            for (size_t i = 0; i < numPoints; ++i)
+                traceATA += ((double) weights[i]) * ((V3d) A[i] - Acenter).length2();
+        }
+
+        KahanSum traceBATQ;
+        for (int i = 0; i < 3; ++i)
+            for (int j = 0; j < 3; ++j)
+                traceBATQ += Qt[j][i] * C[i][j];
+
+        s = traceBATQ.get() / traceATA.get();
+    }
+
+    // Q is the rotation part of what we want to return.
+    // The entire transform is:
+    //    (translate origin to Bcenter) * Q * (translate Acenter to origin)
+    //                last                                first
+    // The effect of this on a point is:
+    //    (translate origin to Bcenter) * Q * (translate Acenter to origin) * point
+    //  = (translate origin to Bcenter) * Q * (-Acenter + point)
+    //  = (translate origin to Bcenter) * (-Q*Acenter + Q*point)
+    //  = (translate origin to Bcenter) * (translate Q*Acenter to origin) * Q*point
+    //  = (translate Q*Acenter to Bcenter) * Q*point
+    // So what we want to return is:
+    //    (translate Q*Acenter to Bcenter) * Q
+    //
+    // In block form, this is:
+    //   [ 1 0 0  | ] [       0 ] [ 1 0 0  |  ]   [ 1 0 0  | ] [           |   ]   [                 ]
+    //   [ 0 1 0 tb ] [  s*Q  0 ] [ 0 1 0 -ta ] = [ 0 1 0 tb ] [  s*Q  -s*Q*ta ] = [   Q   tb-s*Q*ta ]
+    //   [ 0 0 1  | ] [       0 ] [ 0 0 1  |  ]   [ 0 0 1  | ] [           |   ]   [                 ]
+    //   [ 0 0 0  1 ] [ 0 0 0 1 ] [ 0 0 0  1  ]   [ 0 0 0  1 ] [ 0 0 0     1   ]   [ 0 0 0    1      ]
+    // (ofc the whole thing is transposed for Imath).
+    const V3d translate = Bcenter - s * Acenter * Qt;
+
+    return M44d (s * Qt.x[0][0],
+                 s * Qt.x[0][1],
+                 s * Qt.x[0][2],
+                 T (0),
+                 s * Qt.x[1][0],
+                 s * Qt.x[1][1],
+                 s * Qt.x[1][2],
+                 T (0),
+                 s * Qt.x[2][0],
+                 s * Qt.x[2][1],
+                 s * Qt.x[2][2],
+                 T (0),
+                 translate.x,
+                 translate.y,
+                 translate.z,
+                 T (1));
+} // procrustesRotationAndTranslation
+
+///
+/// Return the procrustes transformation of a set of points: the
+/// rotation, translation, and optionally the scale that comes closest
+/// in a least squares sense to transforming the `A` points into
+/// `B`.
+///
+
+template <typename T>
+M44d
+procrustesRotationAndTranslation (const Vec3<T>* A,
+                                  const Vec3<T>* B,
+                                  const size_t numPoints,
+                                  const bool doScale)
+{
+    return procrustesRotationAndTranslation (A, B, (const T*) 0, numPoints, doScale);
+} // procrustesRotationAndTranslation
+
+/// TODO
+template IMATH_EXPORT M44d procrustesRotationAndTranslation (const V3d* from,
+                                                             const V3d* to,
+                                                             const size_t numPoints,
+                                                             const bool doScale);
+/// TODO
+template IMATH_EXPORT M44d procrustesRotationAndTranslation (const V3f* from,
+                                                             const V3f* to,
+                                                             const size_t numPoints,
+                                                             const bool doScale);
+/// TODO
+template IMATH_EXPORT M44d procrustesRotationAndTranslation (const V3d* from,
+                                                             const V3d* to,
+                                                             const double* weights,
+                                                             const size_t numPoints,
+                                                             const bool doScale);
+/// TODO
+template IMATH_EXPORT M44d procrustesRotationAndTranslation (const V3f* from,
+                                                             const V3f* to,
+                                                             const float* weights,
+                                                             const size_t numPoints,
+                                                             const bool doScale);
+
+namespace
+{
+
+// Applies the 2x2 Jacobi rotation
+//   [  c s 0 ]    [ 1  0 0 ]    [  c 0 s ]
+//   [ -s c 0 ] or [ 0  c s ] or [  0 1 0 ]
+//   [  0 0 1 ]    [ 0 -s c ]    [ -s 0 c ]
+// from the right; that is, computes
+//   J * A
+// for the Jacobi rotation J and the matrix A.  This is efficient because we
+// only need to touch exactly the 2 columns that are affected, so we never
+// need to explicitly construct the J matrix.
+template <typename T, int j, int k>
+void
+jacobiRotateRight (IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A, const T c, const T s)
+{
+    for (int i = 0; i < 3; ++i)
+    {
+        const T tau1 = A[i][j];
+        const T tau2 = A[i][k];
+        A[i][j]      = c * tau1 - s * tau2;
+        A[i][k]      = s * tau1 + c * tau2;
+    }
+}
+
+template <typename T>
+void
+jacobiRotateRight (IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A,
+                   const int j,
+                   const int k,
+                   const T c,
+                   const T s)
+{
+    for (int i = 0; i < 4; ++i)
+    {
+        const T tau1 = A[i][j];
+        const T tau2 = A[i][k];
+        A[i][j]      = c * tau1 - s * tau2;
+        A[i][k]      = s * tau1 + c * tau2;
+    }
+}
+
+// This routine solves the 2x2 SVD:
+//     [  c1   s1 ] [ w   x ] [  c2  s2 ]   [ d1    0 ]
+//     [          ] [       ] [         ] = [         ]
+//     [ -s1   c1 ] [ y   z ] [ -s2  c2 ]   [  0   d2 ]
+// where
+//      [ w   x ]
+//  A = [       ]
+//      [ y   z ]
+// is the subset of A consisting of the [j,k] entries, A([j k], [j k]) in
+// Matlab parlance.  The method is the 'USVD' algorithm described in the
+// following paper:
+//    'Computation of the Singular Value Decomposition using Mesh-Connected Processors'
+//    by Richard P. Brent, Franklin T. Luk, and Charles Van Loan
+// It breaks the computation into two steps: the first symmetrizes the matrix,
+// and the second diagonalizes the symmetric matrix.
+template <typename T, int j, int k, int l>
+bool
+twoSidedJacobiRotation (IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A,
+                        IMATH_INTERNAL_NAMESPACE::Matrix33<T>& U,
+                        IMATH_INTERNAL_NAMESPACE::Matrix33<T>& V,
+                        const T tol)
+{
+    // Load everything into local variables to make things easier on the
+    // optimizer:
+    const T w = A[j][j];
+    const T x = A[j][k];
+    const T y = A[k][j];
+    const T z = A[k][k];
+
+    // We will keep track of whether we're actually performing any rotations,
+    // since if the matrix is already diagonal we'll end up with the identity
+    // as our Jacobi rotation and we can short-circuit.
+    bool changed = false;
+
+    // The first step is to symmetrize the 2x2 matrix,
+    //   [ c  s ]^T [ w x ] = [ p q ]
+    //   [ -s c ]   [ y z ]   [ q r ]
+    T mu_1 = w + z;
+    T mu_2 = x - y;
+
+    T c, s;
+    if (std::abs (mu_2) <= tol * std::abs (mu_1)) // Already symmetric (to tolerance)
+    {                                             // Note that the <= is important here
+        c = T (1);                                // because we want to bypass the computation
+        s = T (0);                                // of rho if mu_1 = mu_2 = 0.
+
+        const T p = w;
+        const T r = z;
+        mu_1      = r - p;
+        mu_2      = x + y;
+    }
+    else
+    {
+        // TODO is there a native inverse square root function?
+        const T rho = mu_1 / mu_2;
+
+        s = T (1) / std::sqrt (T (1) + rho * rho);
+        if (rho < 0)
+            s = -s;
+        c = s * rho;
+
+        mu_1 = s * (x + y) + c * (z - w); // = r - p
+        mu_2 = T (2) * (c * x - s * z);   // = 2*q
+
+        changed = true;
+    }
+
+    // The second stage diagonalizes,
+    //   [ c2   s2 ]^T [ p q ] [ c2  s2 ]  = [ d1   0 ]
+    //   [ -s2  c2 ]   [ q r ] [ -s2 c2 ]    [  0  d2 ]
+    T c_2, s_2;
+    if (std::abs (mu_2) <= tol * std::abs (mu_1))
+    {
+        c_2 = T (1);
+        s_2 = T (0);
+    }
+    else
+    {
+        const T rho_2 = mu_1 / mu_2;
+        T t_2         = T (1) / (std::abs (rho_2) + std::sqrt (1 + rho_2 * rho_2));
+        if (rho_2 < 0)
+            t_2 = -t_2;
+        c_2 = T (1) / std::sqrt (T (1) + t_2 * t_2);
+        s_2 = c_2 * t_2;
+
+        changed = true;
+    }
+
+    const T c_1 = c_2 * c - s_2 * s;
+    const T s_1 = s_2 * c + c_2 * s;
+
+    if (!changed)
+    {
+        // We've decided that the off-diagonal entries are already small
+        // enough, so we'll set them to zero.  This actually appears to result
+        // in smaller errors than leaving them be, possibly because it prevents
+        // us from trying to do extra rotations later that we don't need.
+        A[k][j] = 0;
+        A[j][k] = 0;
+        return false;
+    }
+
+    const T d_1 = c_1 * (w * c_2 - x * s_2) - s_1 * (y * c_2 - z * s_2);
+    const T d_2 = s_1 * (w * s_2 + x * c_2) + c_1 * (y * s_2 + z * c_2);
+
+    // For the entries we just zeroed out, we'll just set them to 0, since
+    // they should be 0 up to machine precision.
+    A[j][j] = d_1;
+    A[k][k] = d_2;
+    A[k][j] = 0;
+    A[j][k] = 0;
+
+    // Rotate the entries that _weren't_ involved in the 2x2 SVD:
+    {
+        // Rotate on the left by
+        //    [  c1 s1 0 ]^T      [  c1 0 s1 ]^T      [ 1   0  0 ]^T
+        //    [ -s1 c1 0 ]    or  [   0 1  0 ]    or  [ 0  c1 s1 ]
+        //    [   0  0 1 ]        [ -s1 0 c1 ]        [ 0 -s1 c1 ]
+        // This has the effect of adding the (weighted) ith and jth _rows_ to
+        // each other.
+        const T tau1 = A[j][l];
+        const T tau2 = A[k][l];
+        A[j][l]      = c_1 * tau1 - s_1 * tau2;
+        A[k][l]      = s_1 * tau1 + c_1 * tau2;
+    }
+
+    {
+        // Rotate on the right by
+        //    [  c2 s2 0 ]      [  c2 0 s2 ]      [ 1   0  0 ]
+        //    [ -s2 c2 0 ]  or  [   0 1  0 ]  or  [ 0  c2 s2 ]
+        //    [   0  0 1 ]      [ -s2 0 c2 ]      [ 0 -s2 c2 ]
+        // This has the effect of adding the (weighted) ith and jth _columns_ to
+        // each other.
+        const T tau1 = A[l][j];
+        const T tau2 = A[l][k];
+        A[l][j]      = c_2 * tau1 - s_2 * tau2;
+        A[l][k]      = s_2 * tau1 + c_2 * tau2;
+    }
+
+    // Now apply the rotations to U and V:
+    // Remember that we have
+    //    R1^T * A * R2 = D
+    // This is in the 2x2 case, but after doing a bunch of these
+    // we will get something like this for the 3x3 case:
+    //   ... R1b^T * R1a^T * A * R2a * R2b * ... = D
+    //   -----------------       ---------------
+    //        = U^T                    = V
+    // So,
+    //   U = R1a * R1b * ...
+    //   V = R2a * R2b * ...
+    jacobiRotateRight<T, j, k> (U, c_1, s_1);
+    jacobiRotateRight<T, j, k> (V, c_2, s_2);
+
+    return true;
+}
+
+template <typename T>
+bool
+twoSidedJacobiRotation (IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A,
+                        int j,
+                        int k,
+                        IMATH_INTERNAL_NAMESPACE::Matrix44<T>& U,
+                        IMATH_INTERNAL_NAMESPACE::Matrix44<T>& V,
+                        const T tol)
+{
+    // Load everything into local variables to make things easier on the
+    // optimizer:
+    const T w = A[j][j];
+    const T x = A[j][k];
+    const T y = A[k][j];
+    const T z = A[k][k];
+
+    // We will keep track of whether we're actually performing any rotations,
+    // since if the matrix is already diagonal we'll end up with the identity
+    // as our Jacobi rotation and we can short-circuit.
+    bool changed = false;
+
+    // The first step is to symmetrize the 2x2 matrix,
+    //   [ c  s ]^T [ w x ] = [ p q ]
+    //   [ -s c ]   [ y z ]   [ q r ]
+    T mu_1 = w + z;
+    T mu_2 = x - y;
+
+    T c, s;
+    if (std::abs (mu_2) <= tol * std::abs (mu_1)) // Already symmetric (to tolerance)
+    {                                             // Note that the <= is important here
+        c = T (1);                                // because we want to bypass the computation
+        s = T (0);                                // of rho if mu_1 = mu_2 = 0.
+
+        const T p = w;
+        const T r = z;
+        mu_1      = r - p;
+        mu_2      = x + y;
+    }
+    else
+    {
+        // TODO is there a native inverse square root function?
+        const T rho = mu_1 / mu_2;
+
+        s = T (1) / std::sqrt (T (1) + rho * rho);
+        if (rho < 0)
+            s = -s;
+        c = s * rho;
+
+        mu_1 = s * (x + y) + c * (z - w); // = r - p
+        mu_2 = T (2) * (c * x - s * z);   // = 2*q
+
+        changed = true;
+    }
+
+    // The second stage diagonalizes,
+    //   [ c2   s2 ]^T [ p q ] [ c2  s2 ]  = [ d1   0 ]
+    //   [ -s2  c2 ]   [ q r ] [ -s2 c2 ]    [  0  d2 ]
+    T c_2, s_2;
+    if (std::abs (mu_2) <= tol * std::abs (mu_1))
+    {
+        c_2 = T (1);
+        s_2 = T (0);
+    }
+    else
+    {
+        const T rho_2 = mu_1 / mu_2;
+        T t_2         = T (1) / (std::abs (rho_2) + std::sqrt (1 + rho_2 * rho_2));
+        if (rho_2 < 0)
+            t_2 = -t_2;
+        c_2 = T (1) / std::sqrt (T (1) + t_2 * t_2);
+        s_2 = c_2 * t_2;
+
+        changed = true;
+    }
+
+    const T c_1 = c_2 * c - s_2 * s;
+    const T s_1 = s_2 * c + c_2 * s;
+
+    if (!changed)
+    {
+        // We've decided that the off-diagonal entries are already small
+        // enough, so we'll set them to zero.  This actually appears to result
+        // in smaller errors than leaving them be, possibly because it prevents
+        // us from trying to do extra rotations later that we don't need.
+        A[k][j] = 0;
+        A[j][k] = 0;
+        return false;
+    }
+
+    const T d_1 = c_1 * (w * c_2 - x * s_2) - s_1 * (y * c_2 - z * s_2);
+    const T d_2 = s_1 * (w * s_2 + x * c_2) + c_1 * (y * s_2 + z * c_2);
+
+    // For the entries we just zeroed out, we'll just set them to 0, since
+    // they should be 0 up to machine precision.
+    A[j][j] = d_1;
+    A[k][k] = d_2;
+    A[k][j] = 0;
+    A[j][k] = 0;
+
+    // Rotate the entries that _weren't_ involved in the 2x2 SVD:
+    for (int l = 0; l < 4; ++l)
+    {
+        if (l == j || l == k)
+            continue;
+
+        // Rotate on the left by
+        //    [ 1               ]
+        //    [   .             ]
+        //    [     c2   s2     ]  j
+        //    [        1        ]
+        //    [    -s2   c2     ]  k
+        //    [             .   ]
+        //    [               1 ]
+        //          j    k
+        //
+        // This has the effect of adding the (weighted) ith and jth _rows_ to
+        // each other.
+        const T tau1 = A[j][l];
+        const T tau2 = A[k][l];
+        A[j][l]      = c_1 * tau1 - s_1 * tau2;
+        A[k][l]      = s_1 * tau1 + c_1 * tau2;
+    }
+
+    for (int l = 0; l < 4; ++l)
+    {
+        // We set the A[j/k][j/k] entries already
+        if (l == j || l == k)
+            continue;
+
+        // Rotate on the right by
+        //    [ 1               ]
+        //    [   .             ]
+        //    [     c2   s2     ]  j
+        //    [        1        ]
+        //    [    -s2   c2     ]  k
+        //    [             .   ]
+        //    [               1 ]
+        //          j    k
+        //
+        // This has the effect of adding the (weighted) ith and jth _columns_ to
+        // each other.
+        const T tau1 = A[l][j];
+        const T tau2 = A[l][k];
+        A[l][j]      = c_2 * tau1 - s_2 * tau2;
+        A[l][k]      = s_2 * tau1 + c_2 * tau2;
+    }
+
+    // Now apply the rotations to U and V:
+    // Remember that we have
+    //    R1^T * A * R2 = D
+    // This is in the 2x2 case, but after doing a bunch of these
+    // we will get something like this for the 3x3 case:
+    //   ... R1b^T * R1a^T * A * R2a * R2b * ... = D
+    //   -----------------       ---------------
+    //        = U^T                    = V
+    // So,
+    //   U = R1a * R1b * ...
+    //   V = R2a * R2b * ...
+    jacobiRotateRight (U, j, k, c_1, s_1);
+    jacobiRotateRight (V, j, k, c_2, s_2);
+
+    return true;
+}
+
+template <typename T>
+void
+swapColumns (IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A, int j, int k)
+{
+    for (int i = 0; i < 3; ++i)
+        std::swap (A[i][j], A[i][k]);
+}
+
+template <typename T>
+IMATH_CONSTEXPR14 T
+maxOffDiag (const IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A)
+{
+    T result = 0;
+    result   = std::max (result, std::abs (A[0][1]));
+    result   = std::max (result, std::abs (A[0][2]));
+    result   = std::max (result, std::abs (A[1][0]));
+    result   = std::max (result, std::abs (A[1][2]));
+    result   = std::max (result, std::abs (A[2][0]));
+    result   = std::max (result, std::abs (A[2][1]));
+    return result;
+}
+
+template <typename T>
+IMATH_CONSTEXPR14 T
+maxOffDiag (const IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A)
+{
+    T result = 0;
+    for (int i = 0; i < 4; ++i)
+    {
+        for (int j = 0; j < 4; ++j)
+        {
+            if (i != j)
+                result = std::max (result, std::abs (A[i][j]));
+        }
+    }
+
+    return result;
+}
+
+template <typename T>
+void
+twoSidedJacobiSVD (IMATH_INTERNAL_NAMESPACE::Matrix33<T> A,
+                   IMATH_INTERNAL_NAMESPACE::Matrix33<T>& U,
+                   IMATH_INTERNAL_NAMESPACE::Vec3<T>& S,
+                   IMATH_INTERNAL_NAMESPACE::Matrix33<T>& V,
+                   const T tol,
+                   const bool forcePositiveDeterminant)
+{
+    // The two-sided Jacobi SVD works by repeatedly zeroing out
+    // off-diagonal entries of the matrix, 2 at a time.  Basically,
+    // we can take our 3x3 matrix,
+    //    [* * *]
+    //    [* * *]
+    //    [* * *]
+    // and use a pair of orthogonal transforms to zero out, say, the
+    // pair of entries (0, 1) and (1, 0):
+    //  [ c1 s1  ] [* * *] [ c2 s2  ]   [*   *]
+    //  [-s1 c1  ] [* * *] [-s2 c2  ] = [  * *]
+    //  [       1] [* * *] [       1]   [* * *]
+    // When we go to zero out the next pair of entries (say, (0, 2) and (2, 0))
+    // then we don't expect those entries to stay 0:
+    //  [ c1 s1  ] [*   *] [ c2 s2  ]   [* *  ]
+    //  [-s1 c1  ] [  * *] [-s2 c2  ] = [* * *]
+    //  [       1] [* * *] [       1]   [  * *]
+    // However, if we keep doing this, we'll find that the off-diagonal entries
+    // converge to 0 fairly quickly (convergence should be roughly cubic).  The
+    // result is a diagonal A matrix and a bunch of orthogonal transforms:
+    //               [* * *]                [*    ]
+    //  L1 L2 ... Ln [* * *] Rn ... R2 R1 = [  *  ]
+    //               [* * *]                [    *]
+    //  ------------ ------- ------------   -------
+    //      U^T         A         V            S
+    // This turns out to be highly accurate because (1) orthogonal transforms
+    // are extremely stable to compute and apply (this is why QR factorization
+    // works so well, FWIW) and because (2) by applying everything to the original
+    // matrix A instead of computing (A^T * A) we avoid any precision loss that
+    // would result from that.
+    U.makeIdentity();
+    V.makeIdentity();
+
+    const int maxIter = 20; // In case we get really unlucky, prevents infinite loops
+    const T absTol    = tol * maxOffDiag (A); // Tolerance is in terms of the maximum
+    if (absTol != 0)                          // _off-diagonal_ entry.
+    {
+        int numIter = 0;
+        do
+        {
+            ++numIter;
+            bool changed = twoSidedJacobiRotation<T, 0, 1, 2> (A, U, V, tol);
+            changed      = twoSidedJacobiRotation<T, 0, 2, 1> (A, U, V, tol) || changed;
+            changed      = twoSidedJacobiRotation<T, 1, 2, 0> (A, U, V, tol) || changed;
+            if (!changed)
+                break;
+        } while (maxOffDiag (A) > absTol && numIter < maxIter);
+    }
+
+    // The off-diagonal entries are (effectively) 0, so whatever's left on the
+    // diagonal are the singular values:
+    S.x = A[0][0];
+    S.y = A[1][1];
+    S.z = A[2][2];
+
+    // Nothing thus far has guaranteed that the singular values are positive,
+    // so let's go back through and flip them if not (since by contract we are
+    // supposed to return all positive SVs):
+    for (int i = 0; i < 3; ++i)
+    {
+        if (S[i] < 0)
+        {
+            // If we flip S[i], we need to flip the corresponding column of U
+            // (we could also pick V if we wanted; it doesn't really matter):
+            S[i] = -S[i];
+            for (int j = 0; j < 3; ++j)
+                U[j][i] = -U[j][i];
+        }
+    }
+
+    // Order the singular values from largest to smallest; this requires
+    // exactly two passes through the data using bubble sort:
+    for (int i = 0; i < 2; ++i)
+    {
+        for (int j = 0; j < (2 - i); ++j)
+        {
+            // No absolute values necessary since we already ensured that
+            // they're positive:
+            if (S[j] < S[j + 1])
+            {
+                // If we swap singular values we also have to swap
+                // corresponding columns in U and V:
+                std::swap (S[j], S[j + 1]);
+                swapColumns (U, j, j + 1);
+                swapColumns (V, j, j + 1);
+            }
+        }
+    }
+
+    if (forcePositiveDeterminant)
+    {
+        // We want to guarantee that the returned matrices always have positive
+        // determinant.  We can do this by adding the appropriate number of
+        // matrices of the form:
+        //       [ 1       ]
+        //  L =  [    1    ]
+        //       [      -1 ]
+        // Note that L' = L and L*L = Identity.  Thus we can add:
+        //   U*L*L*S*V = (U*L)*(L*S)*V
+        // if U has a negative determinant, and
+        //   U*S*L*L*V = U*(S*L)*(L*V)
+        // if V has a neg. determinant.
+        if (U.determinant() < 0)
+        {
+            for (int i = 0; i < 3; ++i)
+                U[i][2] = -U[i][2];
+            S.z = -S.z;
+        }
+
+        if (V.determinant() < 0)
+        {
+            for (int i = 0; i < 3; ++i)
+                V[i][2] = -V[i][2];
+            S.z = -S.z;
+        }
+    }
+}
+
+template <typename T>
+void
+twoSidedJacobiSVD (IMATH_INTERNAL_NAMESPACE::Matrix44<T> A,
+                   IMATH_INTERNAL_NAMESPACE::Matrix44<T>& U,
+                   IMATH_INTERNAL_NAMESPACE::Vec4<T>& S,
+                   IMATH_INTERNAL_NAMESPACE::Matrix44<T>& V,
+                   const T tol,
+                   const bool forcePositiveDeterminant)
+{
+    // Please see the Matrix33 version for a detailed description of the algorithm.
+    U.makeIdentity();
+    V.makeIdentity();
+
+    const int maxIter = 20; // In case we get really unlucky, prevents infinite loops
+    const T absTol    = tol * maxOffDiag (A); // Tolerance is in terms of the maximum
+    if (absTol != 0)                          // _off-diagonal_ entry.
+    {
+        int numIter = 0;
+        do
+        {
+            ++numIter;
+            bool changed = twoSidedJacobiRotation (A, 0, 1, U, V, tol);
+            changed      = twoSidedJacobiRotation (A, 0, 2, U, V, tol) || changed;
+            changed      = twoSidedJacobiRotation (A, 0, 3, U, V, tol) || changed;
+            changed      = twoSidedJacobiRotation (A, 1, 2, U, V, tol) || changed;
+            changed      = twoSidedJacobiRotation (A, 1, 3, U, V, tol) || changed;
+            changed      = twoSidedJacobiRotation (A, 2, 3, U, V, tol) || changed;
+            if (!changed)
+                break;
+        } while (maxOffDiag (A) > absTol && numIter < maxIter);
+    }
+
+    // The off-diagonal entries are (effectively) 0, so whatever's left on the
+    // diagonal are the singular values:
+    S[0] = A[0][0];
+    S[1] = A[1][1];
+    S[2] = A[2][2];
+    S[3] = A[3][3];
+
+    // Nothing thus far has guaranteed that the singular values are positive,
+    // so let's go back through and flip them if not (since by contract we are
+    // supposed to return all positive SVs):
+    for (int i = 0; i < 4; ++i)
+    {
+        if (S[i] < 0)
+        {
+            // If we flip S[i], we need to flip the corresponding column of U
+            // (we could also pick V if we wanted; it doesn't really matter):
+            S[i] = -S[i];
+            for (int j = 0; j < 4; ++j)
+                U[j][i] = -U[j][i];
+        }
+    }
+
+    // Order the singular values from largest to smallest using insertion sort:
+    for (int i = 1; i < 4; ++i)
+    {
+        const IMATH_INTERNAL_NAMESPACE::Vec4<T> uCol (U[0][i], U[1][i], U[2][i], U[3][i]);
+        const IMATH_INTERNAL_NAMESPACE::Vec4<T> vCol (V[0][i], V[1][i], V[2][i], V[3][i]);
+        const T sVal = S[i];
+
+        int j = i - 1;
+        while (std::abs (S[j]) < std::abs (sVal))
+        {
+            for (int k = 0; k < 4; ++k)
+                U[k][j + 1] = U[k][j];
+            for (int k = 0; k < 4; ++k)
+                V[k][j + 1] = V[k][j];
+            S[j + 1] = S[j];
+
+            --j;
+            if (j < 0)
+                break;
+        }
+
+        for (int k = 0; k < 4; ++k)
+            U[k][j + 1] = uCol[k];
+        for (int k = 0; k < 4; ++k)
+            V[k][j + 1] = vCol[k];
+        S[j + 1] = sVal;
+    }
+
+    if (forcePositiveDeterminant)
+    {
+        // We want to guarantee that the returned matrices always have positive
+        // determinant.  We can do this by adding the appropriate number of
+        // matrices of the form:
+        //       [ 1          ]
+        //  L =  [    1       ]
+        //       [       1    ]
+        //       [         -1 ]
+        // Note that L' = L and L*L = Identity.  Thus we can add:
+        //   U*L*L*S*V = (U*L)*(L*S)*V
+        // if U has a negative determinant, and
+        //   U*S*L*L*V = U*(S*L)*(L*V)
+        // if V has a neg. determinant.
+        if (U.determinant() < 0)
+        {
+            for (int i = 0; i < 4; ++i)
+                U[i][3] = -U[i][3];
+            S[3] = -S[3];
+        }
+
+        if (V.determinant() < 0)
+        {
+            for (int i = 0; i < 4; ++i)
+                V[i][3] = -V[i][3];
+            S[3] = -S[3];
+        }
+    }
+}
+
+} // namespace
+
+/// TODO
+template <typename T>
+void
+jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A,
+           IMATH_INTERNAL_NAMESPACE::Matrix33<T>& U,
+           IMATH_INTERNAL_NAMESPACE::Vec3<T>& S,
+           IMATH_INTERNAL_NAMESPACE::Matrix33<T>& V,
+           const T tol,
+           const bool forcePositiveDeterminant)
+{
+    twoSidedJacobiSVD (A, U, S, V, tol, forcePositiveDeterminant);
+}
+
+/// TODO
+template <typename T>
+void
+jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A,
+           IMATH_INTERNAL_NAMESPACE::Matrix44<T>& U,
+           IMATH_INTERNAL_NAMESPACE::Vec4<T>& S,
+           IMATH_INTERNAL_NAMESPACE::Matrix44<T>& V,
+           const T tol,
+           const bool forcePositiveDeterminant)
+{
+    twoSidedJacobiSVD (A, U, S, V, tol, forcePositiveDeterminant);
+}
+
+/// TODO
+template IMATH_EXPORT void jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix33<float>& A,
+                                      IMATH_INTERNAL_NAMESPACE::Matrix33<float>& U,
+                                      IMATH_INTERNAL_NAMESPACE::Vec3<float>& S,
+                                      IMATH_INTERNAL_NAMESPACE::Matrix33<float>& V,
+                                      const float tol,
+                                      const bool forcePositiveDeterminant);
+/// TODO
+template IMATH_EXPORT void jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix33<double>& A,
+                                      IMATH_INTERNAL_NAMESPACE::Matrix33<double>& U,
+                                      IMATH_INTERNAL_NAMESPACE::Vec3<double>& S,
+                                      IMATH_INTERNAL_NAMESPACE::Matrix33<double>& V,
+                                      const double tol,
+                                      const bool forcePositiveDeterminant);
+/// TODO
+template IMATH_EXPORT void jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix44<float>& A,
+                                      IMATH_INTERNAL_NAMESPACE::Matrix44<float>& U,
+                                      IMATH_INTERNAL_NAMESPACE::Vec4<float>& S,
+                                      IMATH_INTERNAL_NAMESPACE::Matrix44<float>& V,
+                                      const float tol,
+                                      const bool forcePositiveDeterminant);
+/// TODO
+template IMATH_EXPORT void jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix44<double>& A,
+                                      IMATH_INTERNAL_NAMESPACE::Matrix44<double>& U,
+                                      IMATH_INTERNAL_NAMESPACE::Vec4<double>& S,
+                                      IMATH_INTERNAL_NAMESPACE::Matrix44<double>& V,
+                                      const double tol,
+                                      const bool forcePositiveDeterminant);
+
+namespace
+{
+
+template <int j, int k, typename TM>
+inline void
+jacobiRotateRight (TM& A, const typename TM::BaseType s, const typename TM::BaseType tau)
+{
+    typedef typename TM::BaseType T;
+
+    for (unsigned int i = 0; i < TM::dimensions(); ++i)
+    {
+        const T nu1 = A[i][j];
+        const T nu2 = A[i][k];
+        A[i][j] -= s * (nu2 + tau * nu1);
+        A[i][k] += s * (nu1 - tau * nu2);
+    }
+}
+
+template <int j, int k, int l, typename T>
+bool
+jacobiRotation (Matrix33<T>& A, Matrix33<T>& V, Vec3<T>& Z, const T tol)
+{
+    // Load everything into local variables to make things easier on the
+    // optimizer:
+    const T x = A[j][j];
+    const T y = A[j][k];
+    const T z = A[k][k];
+
+    // The first stage diagonalizes,
+    //   [ c  s ]^T [ x y ] [ c -s ]  = [ d1   0 ]
+    //   [ -s c ]   [ y z ] [ s  c ]    [  0  d2 ]
+    const T mu1 = z - x;
+    const T mu2 = 2 * y;
+
+    if (std::abs (mu2) <= tol * std::abs (mu1))
+    {
+        // We've decided that the off-diagonal entries are already small
+        // enough, so we'll set them to zero.  This actually appears to result
+        // in smaller errors than leaving them be, possibly because it prevents
+        // us from trying to do extra rotations later that we don't need.
+        A[j][k] = 0;
+        return false;
+    }
+    const T rho = mu1 / mu2;
+    const T t   = (rho < 0 ? T (-1) : T (1)) / (std::abs (rho) + std::sqrt (1 + rho * rho));
+    const T c   = T (1) / std::sqrt (T (1) + t * t);
+    const T s   = t * c;
+    const T tau = s / (T (1) + c);
+    const T h   = t * y;
+
+    // Update diagonal elements.
+    Z[j] -= h;
+    Z[k] += h;
+    A[j][j] -= h;
+    A[k][k] += h;
+
+    // For the entries we just zeroed out, we'll just set them to 0, since
+    // they should be 0 up to machine precision.
+    A[j][k] = 0;
+
+    // We only update upper triagnular elements of A, since
+    // A is supposed to be symmetric.
+    T& offd1    = l < j ? A[l][j] : A[j][l];
+    T& offd2    = l < k ? A[l][k] : A[k][l];
+    const T nu1 = offd1;
+    const T nu2 = offd2;
+    offd1       = nu1 - s * (nu2 + tau * nu1);
+    offd2       = nu2 + s * (nu1 - tau * nu2);
+
+    // Apply rotation to V
+    jacobiRotateRight<j, k> (V, s, tau);
+
+    return true;
+}
+
+template <int j, int k, int l1, int l2, typename T>
+bool
+jacobiRotation (Matrix44<T>& A, Matrix44<T>& V, Vec4<T>& Z, const T tol)
+{
+    const T x = A[j][j];
+    const T y = A[j][k];
+    const T z = A[k][k];
+
+    const T mu1 = z - x;
+    const T mu2 = T (2) * y;
+
+    // Let's see if rho^(-1) = mu2 / mu1 is less than tol
+    // This test also checks if rho^2 will overflow
+    // when tol^(-1) < sqrt(std::numeric_limits<T>::max()).
+    if (std::abs (mu2) <= tol * std::abs (mu1))
+    {
+        A[j][k] = 0;
+        return true;
+    }
+
+    const T rho = mu1 / mu2;
+    const T t   = (rho < 0 ? T (-1) : T (1)) / (std::abs (rho) + std::sqrt (1 + rho * rho));
+    const T c   = T (1) / std::sqrt (T (1) + t * t);
+    const T s   = c * t;
+    const T tau = s / (T (1) + c);
+    const T h   = t * y;
+
+    Z[j] -= h;
+    Z[k] += h;
+    A[j][j] -= h;
+    A[k][k] += h;
+    A[j][k] = 0;
+
+    {
+        T& offd1    = l1 < j ? A[l1][j] : A[j][l1];
+        T& offd2    = l1 < k ? A[l1][k] : A[k][l1];
+        const T nu1 = offd1;
+        const T nu2 = offd2;
+        offd1 -= s * (nu2 + tau * nu1);
+        offd2 += s * (nu1 - tau * nu2);
+    }
+
+    {
+        T& offd1    = l2 < j ? A[l2][j] : A[j][l2];
+        T& offd2    = l2 < k ? A[l2][k] : A[k][l2];
+        const T nu1 = offd1;
+        const T nu2 = offd2;
+        offd1 -= s * (nu2 + tau * nu1);
+        offd2 += s * (nu1 - tau * nu2);
+    }
+
+    jacobiRotateRight<j, k> (V, s, tau);
+
+    return true;
+}
+
+template <typename TM>
+IMATH_CONSTEXPR14 inline typename TM::BaseType
+maxOffDiagSymm (const TM& A)
+{
+    typedef typename TM::BaseType T;
+    T result = 0;
+    for (unsigned int i = 0; i < TM::dimensions(); ++i)
+        for (unsigned int j = i + 1; j < TM::dimensions(); ++j)
+            result = std::max (result, std::abs (A[i][j]));
+
+    return result;
+}
+
+} // namespace
+
+template <typename T>
+void
+jacobiEigenSolver (Matrix33<T>& A, Vec3<T>& S, Matrix33<T>& V, const T tol)
+{
+    V.makeIdentity();
+    for (int i = 0; i < 3; ++i)
+    {
+        S[i] = A[i][i];
+    }
+
+    const int maxIter = 20; // In case we get really unlucky, prevents infinite loops
+    const T absTol    = tol * maxOffDiagSymm (A); // Tolerance is in terms of the maximum
+    if (absTol != 0)                              // _off-diagonal_ entry.
+    {
+        int numIter = 0;
+        do
+        {
+            // Z is for accumulating small changes (h) to diagonal entries
+            // of A for one sweep. Adding h's directly to A might cause
+            // a cancellation effect when h is relatively very small to
+            // the corresponding diagonal entry of A and
+            // this will increase numerical errors
+            Vec3<T> Z (0, 0, 0);
+            ++numIter;
+            bool changed = jacobiRotation<0, 1, 2> (A, V, Z, tol);
+            changed      = jacobiRotation<0, 2, 1> (A, V, Z, tol) || changed;
+            changed      = jacobiRotation<1, 2, 0> (A, V, Z, tol) || changed;
+            // One sweep passed. Add accumulated changes (Z) to singular values (S)
+            // Update diagonal elements of A for better accuracy as well.
+            for (int i = 0; i < 3; ++i)
+            {
+                A[i][i] = S[i] += Z[i];
+            }
+            if (!changed)
+                break;
+        } while (maxOffDiagSymm (A) > absTol && numIter < maxIter);
+    }
+}
+
+template <typename T>
+void
+jacobiEigenSolver (Matrix44<T>& A, Vec4<T>& S, Matrix44<T>& V, const T tol)
+{
+    V.makeIdentity();
+
+    for (int i = 0; i < 4; ++i)
+    {
+        S[i] = A[i][i];
+    }
+
+    const int maxIter = 20; // In case we get really unlucky, prevents infinite loops
+    const T absTol    = tol * maxOffDiagSymm (A); // Tolerance is in terms of the maximum
+    if (absTol != 0)                              // _off-diagonal_ entry.
+    {
+        int numIter = 0;
+        do
+        {
+            ++numIter;
+            Vec4<T> Z (0, 0, 0, 0);
+            bool changed = jacobiRotation<0, 1, 2, 3> (A, V, Z, tol);
+            changed      = jacobiRotation<0, 2, 1, 3> (A, V, Z, tol) || changed;
+            changed      = jacobiRotation<0, 3, 1, 2> (A, V, Z, tol) || changed;
+            changed      = jacobiRotation<1, 2, 0, 3> (A, V, Z, tol) || changed;
+            changed      = jacobiRotation<1, 3, 0, 2> (A, V, Z, tol) || changed;
+            changed      = jacobiRotation<2, 3, 0, 1> (A, V, Z, tol) || changed;
+            for (int i = 0; i < 4; ++i)
+            {
+                A[i][i] = S[i] += Z[i];
+            }
+            if (!changed)
+                break;
+        } while (maxOffDiagSymm (A) > absTol && numIter < maxIter);
+    }
+}
+
+template <typename TM, typename TV>
+void
+maxEigenVector (TM& A, TV& V)
+{
+    TV S;
+    TM MV;
+    jacobiEigenSolver (A, S, MV);
+
+    int maxIdx (0);
+    for (unsigned int i = 1; i < TV::dimensions(); ++i)
+    {
+        if (std::abs (S[i]) > std::abs (S[maxIdx]))
+            maxIdx = i;
+    }
+
+    for (unsigned int i = 0; i < TV::dimensions(); ++i)
+        V[i] = MV[i][maxIdx];
+}
+
+template <typename TM, typename TV>
+void
+minEigenVector (TM& A, TV& V)
+{
+    TV S;
+    TM MV;
+    jacobiEigenSolver (A, S, MV);
+
+    int minIdx (0);
+    for (unsigned int i = 1; i < TV::dimensions(); ++i)
+    {
+        if (std::abs (S[i]) < std::abs (S[minIdx]))
+            minIdx = i;
+    }
+
+    for (unsigned int i = 0; i < TV::dimensions(); ++i)
+        V[i] = MV[i][minIdx];
+}
+
+template IMATH_EXPORT void
+jacobiEigenSolver (Matrix33<float>& A, Vec3<float>& S, Matrix33<float>& V, const float tol);
+template IMATH_EXPORT void
+jacobiEigenSolver (Matrix33<double>& A, Vec3<double>& S, Matrix33<double>& V, const double tol);
+template IMATH_EXPORT void
+jacobiEigenSolver (Matrix44<float>& A, Vec4<float>& S, Matrix44<float>& V, const float tol);
+template IMATH_EXPORT void
+jacobiEigenSolver (Matrix44<double>& A, Vec4<double>& S, Matrix44<double>& V, const double tol);
+
+template IMATH_EXPORT void maxEigenVector (Matrix33<float>& A, Vec3<float>& S);
+template IMATH_EXPORT void maxEigenVector (Matrix44<float>& A, Vec4<float>& S);
+template IMATH_EXPORT void maxEigenVector (Matrix33<double>& A, Vec3<double>& S);
+template IMATH_EXPORT void maxEigenVector (Matrix44<double>& A, Vec4<double>& S);
+
+template IMATH_EXPORT void minEigenVector (Matrix33<float>& A, Vec3<float>& S);
+template IMATH_EXPORT void minEigenVector (Matrix44<float>& A, Vec4<float>& S);
+template IMATH_EXPORT void minEigenVector (Matrix33<double>& A, Vec3<double>& S);
+template IMATH_EXPORT void minEigenVector (Matrix44<double>& A, Vec4<double>& S);
+
+
+IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT
+
+/// @endcond
diff --git a/src/Imath/ImathMatrixAlgo.h b/src/Imath/ImathMatrixAlgo.h
new file mode 100644 (file)
index 0000000..ddc85f8
--- /dev/null
@@ -0,0 +1,1517 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+//
+// Functions operating on Matrix22, Matrix33, and Matrix44 types
+//
+// This file also defines a few predefined constant matrices.
+//
+
+#ifndef INCLUDED_IMATHMATRIXALGO_H
+#define INCLUDED_IMATHMATRIXALGO_H
+
+#include "ImathEuler.h"
+#include "ImathExport.h"
+#include "ImathMatrix.h"
+#include "ImathNamespace.h"
+#include "ImathQuat.h"
+#include "ImathVec.h"
+#include <math.h>
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//------------------
+// Identity matrices
+//------------------
+
+/// M22f identity matrix
+IMATH_EXPORT_CONST M22f identity22f;
+/// M33f identity matrix
+IMATH_EXPORT_CONST M33f identity33f;
+/// M44f identity matrix
+IMATH_EXPORT_CONST M44f identity44f;
+/// M22d identity matrix
+IMATH_EXPORT_CONST M22d identity22d;
+/// M33d identity matrix
+IMATH_EXPORT_CONST M33d identity33d;
+/// M44d identity matrix
+IMATH_EXPORT_CONST M44d identity44d;
+
+//----------------------------------------------------------------------
+// Extract scale, shear, rotation, and translation values from a matrix:
+//
+// Notes:
+//
+// This implementation follows the technique described in the paper by
+// Spencer W. Thomas in the Graphics Gems II article: "Decomposing a
+// Matrix into Simple Transformations", p. 320.
+//
+// - Some of the functions below have an optional exc parameter
+//   that determines the functions' behavior when the matrix'
+//   scaling is very close to zero:
+//
+//   If exc is true, the functions throw a std::domain_error exception.
+//
+//   If exc is false:
+//
+//      extractScaling (m, s)            returns false, s is invalid
+//     sansScaling (m)                  returns m
+//     removeScaling (m)                returns false, m is unchanged
+//      sansScalingAndShear (m)          returns m
+//      removeScalingAndShear (m)        returns false, m is unchanged
+//      extractAndRemoveScalingAndShear (m, s, h)
+//                                       returns false, m is unchanged,
+//                                                      (sh) are invalid
+//      checkForZeroScaleInRow ()        returns false
+//     extractSHRT (m, s, h, r, t)      returns false, (shrt) are invalid
+//
+// - Functions extractEuler(), extractEulerXYZ() and extractEulerZYX()
+//   assume that the matrix does not include shear or non-uniform scaling,
+//   but they do not examine the matrix to verify this assumption.
+//   Matrices with shear or non-uniform scaling are likely to produce
+//   meaningless results.  Therefore, you should use the
+//   removeScalingAndShear() routine, if necessary, prior to calling
+//   extractEuler...() .
+//
+// - All functions assume that the matrix does not include perspective
+//   transformation(s), but they do not examine the matrix to verify
+//   this assumption.  Matrices with perspective transformations are
+//   likely to produce meaningless results.
+//
+//----------------------------------------------------------------------
+
+//
+// Declarations for 4x4 matrix.
+//
+
+/// Extract the scaling component of the given 4x4 matrix. 
+///
+/// @param[in] mat The input matrix
+/// @param[out] scl The extracted scale, i.e. the output value
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the scale could be extracted, false if the matrix is degenerate.
+template <class T> bool extractScaling (const Matrix44<T>& mat, Vec3<T>& scl, bool exc = true);
+
+/// Return the given 4x4 matrix with scaling removed.
+///
+/// @param[in] mat The input matrix
+/// @param[in] exc If true, throw an exception if the scaling in `mat`
+template <class T> Matrix44<T> sansScaling (const Matrix44<T>& mat, bool exc = true);
+
+/// Remove scaling from the given 4x4 matrix in place.  Return true if the
+/// scale could be successfully extracted, false if the matrix is
+/// degenerate.
+//
+/// @param[in] mat The matrix to operate on
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the scale could be extracted, false if the matrix is degenerate.
+template <class T> bool removeScaling (Matrix44<T>& mat, bool exc = true);
+
+/// Extract the scaling and shear components of the given 4x4 matrix.
+/// Return true if the scale could be successfully extracted, false if
+/// the matrix is degenerate.
+///
+/// @param[in] mat The input matrix
+/// @param[out] scl The extracted scale
+/// @param[out] shr The extracted shear
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the scale could be extracted, false if the matrix is degenerate.
+template <class T> bool extractScalingAndShear (const Matrix44<T>& mat, Vec3<T>& scl, Vec3<T>& shr, bool exc = true);
+
+/// Return the given 4x4 matrix with scaling and shear removed.
+///
+/// @param[in] mat The input matrix
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+template <class T> Matrix44<T> sansScalingAndShear (const Matrix44<T>& mat, bool exc = true);
+
+/// Extract scaling and shear from the given 4x4 matrix in-place.
+///
+/// @param[in,out] result The output matrix
+/// @param[in] mat The return value if `result` is degenerate
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+template <class T>
+void sansScalingAndShear (Matrix44<T>& result, const Matrix44<T>& mat, bool exc = true);
+
+/// Remove scaling and shear from the given 4x4 matrix in place.
+//
+/// @param[in,out] mat The matrix to operate on
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the scale could be extracted, false if the matrix is degenerate.
+template <class T> bool removeScalingAndShear (Matrix44<T>& mat, bool exc = true);
+
+/// Remove scaling and shear from the given 4x4 matrix in place, returning
+/// the extracted values.
+//
+/// @param[in,out] mat The matrix to operate on
+/// @param[out] scl The extracted scale
+/// @param[out] shr The extracted shear
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the scale could be extracted, false if the matrix is degenerate.
+template <class T>
+bool
+extractAndRemoveScalingAndShear (Matrix44<T>& mat, Vec3<T>& scl, Vec3<T>& shr, bool exc = true);
+
+/// Extract the rotation from the given 4x4 matrix in the form of XYZ
+/// euler angles.
+///
+/// @param[in] mat The input matrix
+/// @param[out] rot The extracted XYZ euler angle vector
+template <class T> void extractEulerXYZ (const Matrix44<T>& mat, Vec3<T>& rot);
+
+/// Extract the rotation from the given 4x4 matrix in the form of ZYX
+/// euler angles.
+///
+/// @param[in] mat The input matrix
+/// @param[out] rot The extracted ZYX euler angle vector
+template <class T> void extractEulerZYX (const Matrix44<T>& mat, Vec3<T>& rot);
+
+/// Extract the rotation from the given 4x4 matrix in the form of a quaternion.
+///
+/// @param[in] mat The input matrix
+/// @return The extracted quaternion
+template <class T> Quat<T> extractQuat (const Matrix44<T>& mat);
+
+/// Extract the scaling, shear, rotation, and translation components
+/// of the given 4x4 matrix. The values are such that:
+///
+///     M = S * H * R * T
+///
+/// @param[in] mat The input matrix
+/// @param[out] s The extracted scale
+/// @param[out] h The extracted shear
+/// @param[out] r The extracted rotation
+/// @param[out] t The extracted translation
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @param[in] rOrder The order with which to extract the rotation 
+/// @return True if the values could be extracted, false if the matrix is degenerate.
+template <class T>
+bool extractSHRT (const Matrix44<T>& mat,
+                  Vec3<T>& s,
+                  Vec3<T>& h,
+                  Vec3<T>& r,
+                  Vec3<T>& t,
+                  bool exc /*= true*/,
+                  typename Euler<T>::Order rOrder);
+
+/// Extract the scaling, shear, rotation, and translation components
+/// of the given 4x4 matrix.
+///
+/// @param[in] mat The input matrix
+/// @param[out] s The extracted scale
+/// @param[out] h The extracted shear
+/// @param[out] r The extracted rotation, in XYZ euler angles
+/// @param[out] t The extracted translation
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the values could be extracted, false if the matrix is degenerate.
+template <class T>
+bool extractSHRT (const Matrix44<T>& mat,
+                  Vec3<T>& s,
+                  Vec3<T>& h,
+                  Vec3<T>& r,
+                  Vec3<T>& t,
+                  bool exc = true);
+
+/// Extract the scaling, shear, rotation, and translation components
+/// of the given 4x4 matrix.
+///
+/// @param[in] mat The input matrix
+/// @param[out] s The extracted scale
+/// @param[out] h The extracted shear
+/// @param[out] r The extracted rotation, in Euler angles
+/// @param[out] t The extracted translation
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the values could be extracted, false if the matrix is degenerate.
+template <class T>
+bool extractSHRT (const Matrix44<T>& mat,
+                  Vec3<T>& s,
+                  Vec3<T>& h,
+                  Euler<T>& r,
+                  Vec3<T>& t,
+                  bool exc = true);
+
+/// Return true if the given scale can be removed from the given row
+/// matrix, false if `scl` is small enough that the operation would
+/// overflow. If `exc` is true, throw an exception on overflow.
+template <class T> bool checkForZeroScaleInRow (const T& scl, const Vec3<T>& row, bool exc = true);
+
+/// Return the 4x4 outer product two 4-vectors
+template <class T> Matrix44<T> outerProduct (const Vec4<T>& a, const Vec4<T>& b);
+
+///
+/// Return a 4x4 matrix that rotates the vector `fromDirection` to `toDirection`
+///
+template <class T>
+Matrix44<T> rotationMatrix (const Vec3<T>& fromDirection, const Vec3<T>& toDirection);
+
+///
+/// Return a 4x4 matrix that rotates the `fromDir` vector
+/// so that it points towards `toDir1.  You may also
+/// specify that you want the up vector to be pointing
+/// in a certain direction 1upDir`.
+template <class T>
+Matrix44<T>
+rotationMatrixWithUpDir (const Vec3<T>& fromDir, const Vec3<T>& toDir, const Vec3<T>& upDir);
+
+///
+/// Construct a 4x4 matrix that rotates the z-axis so that it points
+/// towards `targetDir`.  You must also specify that you want the up
+/// vector to be pointing in a certain direction `upDir`.
+///
+/// Notes: The following degenerate cases are handled:
+/// (a) when the directions given by `toDir` and `upDir`
+/// are parallel or opposite (the direction vectors must have a non-zero cross product);
+/// (b) when any of the given direction vectors have zero length
+///
+/// @param[out] result The output matrix
+/// @param[in] targetDir The target direction vector
+/// @param[in] upDir The up direction vector
+template <class T>
+void alignZAxisWithTargetDir (Matrix44<T>& result, Vec3<T> targetDir, Vec3<T> upDir);
+
+/// Compute an orthonormal direct 4x4 frame from a position, an x axis
+/// direction and a normal to the y axis. If the x axis and normal are
+/// perpendicular, then the normal will have the same direction as the
+/// z axis.
+///
+/// @param[in] p The position of the frame
+/// @param[in] xDir The x axis direction of the frame
+/// @param[in] normal A normal to the y axis of the frame
+/// @return The orthonormal frame
+template <class T>
+Matrix44<T> computeLocalFrame (const Vec3<T>& p, const Vec3<T>& xDir, const Vec3<T>& normal);
+
+/// Add a translate/rotate/scale offset to a 4x4 input frame
+/// and put it in another frame of reference
+/// 
+/// @param[in] inMat Input frame
+/// @param[in] tOffset Translation offset
+/// @param[in] rOffset Rotation offset in degrees
+/// @param[in] sOffset Scale offset
+/// @param[in] ref Frame of reference
+/// @return The offsetted frame
+template <class T>
+Matrix44<T> addOffset (const Matrix44<T>& inMat,
+                       const Vec3<T>& tOffset,
+                       const Vec3<T>& rOffset,
+                       const Vec3<T>& sOffset,
+                       const Vec3<T>& ref);
+
+/// Compute 4x4 translate/rotate/scale matrix from `A` with the
+/// rotate/scale of `B`.
+/// 
+/// @param[in] keepRotateA If true, keep rotate from matrix `A`, use `B` otherwise
+/// @param[in] keepScaleA If true, keep scale  from matrix `A`, use `B` otherwise
+/// @param[in] A Matrix A
+/// @param[in] B Matrix B
+/// @return Matrix `A` with tweaked rotation/scale
+template <class T>
+Matrix44<T>
+computeRSMatrix (bool keepRotateA, bool keepScaleA, const Matrix44<T>& A, const Matrix44<T>& B);
+
+//
+// Declarations for 3x3 matrix.
+//
+
+/// Extract the scaling component of the given 3x3 matrix. 
+///
+/// @param[in] mat The input matrix
+/// @param[out] scl The extracted scale, i.e. the output value
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the scale could be extracted, false if the matrix is degenerate.
+template <class T> bool extractScaling (const Matrix33<T>& mat, Vec2<T>& scl, bool exc = true);
+
+/// Return the given 3x3 matrix with scaling removed.
+///
+/// @param[in] mat The input matrix
+/// @param[in] exc If true, throw an exception if the scaling in `mat`
+template <class T> Matrix33<T> sansScaling (const Matrix33<T>& mat, bool exc = true);
+
+/// Remove scaling from the given 3x3 matrix in place.  Return true if the
+/// scale could be successfully extracted, false if the matrix is
+/// degenerate.
+//
+/// @param[in] mat The matrix to operate on
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the scale could be extracted, false if the matrix is degenerate.
+template <class T> bool removeScaling (Matrix33<T>& mat, bool exc = true);
+
+/// Extract the scaling and shear components of the given 3x3 matrix.
+/// Return true if the scale could be successfully extracted, false if
+/// the matrix is degenerate.
+///
+/// @param[in] mat The input matrix
+/// @param[out] scl The extracted scale
+/// @param[out] shr The extracted shear
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the scale could be extracted, false if the matrix is degenerate.
+template <class T>
+bool extractScalingAndShear (const Matrix33<T>& mat, Vec2<T>& scl, T& shr, bool exc = true);
+
+/// Return the given 3x3 matrix with scaling and shear removed.
+///
+/// @param[in] mat The input matrix
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+template <class T> Matrix33<T> sansScalingAndShear (const Matrix33<T>& mat, bool exc = true);
+
+
+/// Remove scaling and shear from the given 3x3e matrix in place.
+//
+/// @param[in,out] mat The matrix to operate on
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the scale could be extracted, false if the matrix is degenerate.
+template <class T> bool removeScalingAndShear (Matrix33<T>& mat, bool exc = true);
+
+/// Remove scaling and shear from the given 3x3 matrix in place, returning
+/// the extracted values.
+//
+/// @param[in,out] mat The matrix to operate on
+/// @param[out] scl The extracted scale
+/// @param[out] shr The extracted shear
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the scale could be extracted, false if the matrix is degenerate.
+template <class T>
+bool extractAndRemoveScalingAndShear (Matrix33<T>& mat, Vec2<T>& scl, T& shr, bool exc = true);
+
+/// Extract the rotation from the given 2x2 matrix
+///
+/// @param[in] mat The input matrix
+/// @param[out] rot The extracted rotation value
+template <class T> void extractEuler (const Matrix22<T>& mat, T& rot);
+
+/// Extract the rotation from the given 3x3 matrix
+///
+/// @param[in] mat The input matrix
+/// @param[out] rot The extracted rotation value
+template <class T> void extractEuler (const Matrix33<T>& mat, T& rot);
+
+/// Extract the scaling, shear, rotation, and translation components
+/// of the given 3x3 matrix. The values are such that:
+///
+///     M = S * H * R * T
+///
+/// @param[in] mat The input matrix
+/// @param[out] s The extracted scale
+/// @param[out] h The extracted shear
+/// @param[out] r The extracted rotation
+/// @param[out] t The extracted translation
+/// @param[in] exc If true, throw an exception if the scaling in `mat` is very close to zero.
+/// @return True if the values could be extracted, false if the matrix is degenerate.
+template <class T>
+bool extractSHRT (const Matrix33<T>& mat, Vec2<T>& s, T& h, T& r, Vec2<T>& t, bool exc = true);
+
+/// Return true if the given scale can be removed from the given row
+/// matrix, false if `scl` is small enough that the operation would
+/// overflow. If `exc` is true, throw an exception on overflow.
+template <class T> bool checkForZeroScaleInRow (const T& scl, const Vec2<T>& row, bool exc = true);
+
+/// Return the 3xe outer product two 3-vectors
+template <class T> Matrix33<T> outerProduct (const Vec3<T>& a, const Vec3<T>& b);
+
+//------------------------------
+// Implementation for 4x4 Matrix
+//------------------------------
+
+template <class T>
+bool
+extractScaling (const Matrix44<T>& mat, Vec3<T>& scl, bool exc)
+{
+    Vec3<T> shr;
+    Matrix44<T> M (mat);
+
+    if (!extractAndRemoveScalingAndShear (M, scl, shr, exc))
+        return false;
+
+    return true;
+}
+
+template <class T>
+Matrix44<T>
+sansScaling (const Matrix44<T>& mat, bool exc)
+{
+    Vec3<T> scl;
+    Vec3<T> shr;
+    Vec3<T> rot;
+    Vec3<T> tran;
+
+    if (!extractSHRT (mat, scl, shr, rot, tran, exc))
+        return mat;
+
+    Matrix44<T> M;
+
+    M.translate (tran);
+    M.rotate (rot);
+    M.shear (shr);
+
+    return M;
+}
+
+template <class T>
+bool
+removeScaling (Matrix44<T>& mat, bool exc)
+{
+    Vec3<T> scl;
+    Vec3<T> shr;
+    Vec3<T> rot;
+    Vec3<T> tran;
+
+    if (!extractSHRT (mat, scl, shr, rot, tran, exc))
+        return false;
+
+    mat.makeIdentity();
+    mat.translate (tran);
+    mat.rotate (rot);
+    mat.shear (shr);
+
+    return true;
+}
+
+template <class T>
+bool
+extractScalingAndShear (const Matrix44<T>& mat, Vec3<T>& scl, Vec3<T>& shr, bool exc)
+{
+    Matrix44<T> M (mat);
+
+    if (!extractAndRemoveScalingAndShear (M, scl, shr, exc))
+        return false;
+
+    return true;
+}
+
+template <class T>
+Matrix44<T>
+sansScalingAndShear (const Matrix44<T>& mat, bool exc)
+{
+    Vec3<T> scl;
+    Vec3<T> shr;
+    Matrix44<T> M (mat);
+
+    if (!extractAndRemoveScalingAndShear (M, scl, shr, exc))
+        return mat;
+
+    return M;
+}
+
+template <class T>
+void
+sansScalingAndShear (Matrix44<T>& result, const Matrix44<T>& mat, bool exc)
+{
+    Vec3<T> scl;
+    Vec3<T> shr;
+
+    if (!extractAndRemoveScalingAndShear (result, scl, shr, exc))
+        result = mat;
+}
+
+template <class T>
+bool
+removeScalingAndShear (Matrix44<T>& mat, bool exc)
+{
+    Vec3<T> scl;
+    Vec3<T> shr;
+
+    if (!extractAndRemoveScalingAndShear (mat, scl, shr, exc))
+        return false;
+
+    return true;
+}
+
+template <class T>
+bool
+extractAndRemoveScalingAndShear (Matrix44<T>& mat, Vec3<T>& scl, Vec3<T>& shr, bool exc)
+{
+    //
+    // This implementation follows the technique described in the paper by
+    // Spencer W. Thomas in the Graphics Gems II article: "Decomposing a
+    // Matrix into Simple Transformations", p. 320.
+    //
+
+    Vec3<T> row[3];
+
+    row[0] = Vec3<T> (mat[0][0], mat[0][1], mat[0][2]);
+    row[1] = Vec3<T> (mat[1][0], mat[1][1], mat[1][2]);
+    row[2] = Vec3<T> (mat[2][0], mat[2][1], mat[2][2]);
+
+    T maxVal = 0;
+    for (int i = 0; i < 3; i++)
+        for (int j = 0; j < 3; j++)
+            if (IMATH_INTERNAL_NAMESPACE::abs (row[i][j]) > maxVal)
+                maxVal = IMATH_INTERNAL_NAMESPACE::abs (row[i][j]);
+
+    //
+    // We normalize the 3x3 matrix here.
+    // It was noticed that this can improve numerical stability significantly,
+    // especially when many of the upper 3x3 matrix's coefficients are very
+    // close to zero; we correct for this step at the end by multiplying the
+    // scaling factors by maxVal at the end (shear and rotation are not
+    // affected by the normalization).
+
+    if (maxVal != 0)
+    {
+        for (int i = 0; i < 3; i++)
+            if (!checkForZeroScaleInRow (maxVal, row[i], exc))
+                return false;
+            else
+                row[i] /= maxVal;
+    }
+
+    // Compute X scale factor.
+    scl.x = row[0].length();
+    if (!checkForZeroScaleInRow (scl.x, row[0], exc))
+        return false;
+
+    // Normalize first row.
+    row[0] /= scl.x;
+
+    // An XY shear factor will shear the X coord. as the Y coord. changes.
+    // There are 6 combinations (XY, XZ, YZ, YX, ZX, ZY), although we only
+    // extract the first 3 because we can effect the last 3 by shearing in
+    // XY, XZ, YZ combined rotations and scales.
+    //
+    // shear matrix <   1,  YX,  ZX,  0,
+    //                 XY,   1,  ZY,  0,
+    //                 XZ,  YZ,   1,  0,
+    //                  0,   0,   0,  1 >
+
+    // Compute XY shear factor and make 2nd row orthogonal to 1st.
+    shr[0] = row[0].dot (row[1]);
+    row[1] -= shr[0] * row[0];
+
+    // Now, compute Y scale.
+    scl.y = row[1].length();
+    if (!checkForZeroScaleInRow (scl.y, row[1], exc))
+        return false;
+
+    // Normalize 2nd row and correct the XY shear factor for Y scaling.
+    row[1] /= scl.y;
+    shr[0] /= scl.y;
+
+    // Compute XZ and YZ shears, orthogonalize 3rd row.
+    shr[1] = row[0].dot (row[2]);
+    row[2] -= shr[1] * row[0];
+    shr[2] = row[1].dot (row[2]);
+    row[2] -= shr[2] * row[1];
+
+    // Next, get Z scale.
+    scl.z = row[2].length();
+    if (!checkForZeroScaleInRow (scl.z, row[2], exc))
+        return false;
+
+    // Normalize 3rd row and correct the XZ and YZ shear factors for Z scaling.
+    row[2] /= scl.z;
+    shr[1] /= scl.z;
+    shr[2] /= scl.z;
+
+    // At this point, the upper 3x3 matrix in mat is orthonormal.
+    // Check for a coordinate system flip. If the determinant
+    // is less than zero, then negate the matrix and the scaling factors.
+    if (row[0].dot (row[1].cross (row[2])) < 0)
+        for (int i = 0; i < 3; i++)
+        {
+            scl[i] *= -1;
+            row[i] *= -1;
+        }
+
+    // Copy over the orthonormal rows into the returned matrix.
+    // The upper 3x3 matrix in mat is now a rotation matrix.
+    for (int i = 0; i < 3; i++)
+    {
+        mat[i][0] = row[i][0];
+        mat[i][1] = row[i][1];
+        mat[i][2] = row[i][2];
+    }
+
+    // Correct the scaling factors for the normalization step that we
+    // performed above; shear and rotation are not affected by the
+    // normalization.
+    scl *= maxVal;
+
+    return true;
+}
+
+template <class T>
+void
+extractEulerXYZ (const Matrix44<T>& mat, Vec3<T>& rot)
+{
+    //
+    // Normalize the local x, y and z axes to remove scaling.
+    //
+
+    Vec3<T> i (mat[0][0], mat[0][1], mat[0][2]);
+    Vec3<T> j (mat[1][0], mat[1][1], mat[1][2]);
+    Vec3<T> k (mat[2][0], mat[2][1], mat[2][2]);
+
+    i.normalize();
+    j.normalize();
+    k.normalize();
+
+    Matrix44<T> M (i[0], i[1], i[2], 0, j[0], j[1], j[2], 0, k[0], k[1], k[2], 0, 0, 0, 0, 1);
+
+    //
+    // Extract the first angle, rot.x.
+    //
+
+    rot.x = std::atan2 (M[1][2], M[2][2]);
+
+    //
+    // Remove the rot.x rotation from M, so that the remaining
+    // rotation, N, is only around two axes, and gimbal lock
+    // cannot occur.
+    //
+
+    Matrix44<T> N;
+    N.rotate (Vec3<T> (-rot.x, 0, 0));
+    N = N * M;
+
+    //
+    // Extract the other two angles, rot.y and rot.z, from N.
+    //
+
+    T cy  = std::sqrt (N[0][0] * N[0][0] + N[0][1] * N[0][1]);
+    rot.y = std::atan2 (-N[0][2], cy);
+    rot.z = std::atan2 (-N[1][0], N[1][1]);
+}
+
+template <class T>
+void
+extractEulerZYX (const Matrix44<T>& mat, Vec3<T>& rot)
+{
+    //
+    // Normalize the local x, y and z axes to remove scaling.
+    //
+
+    Vec3<T> i (mat[0][0], mat[0][1], mat[0][2]);
+    Vec3<T> j (mat[1][0], mat[1][1], mat[1][2]);
+    Vec3<T> k (mat[2][0], mat[2][1], mat[2][2]);
+
+    i.normalize();
+    j.normalize();
+    k.normalize();
+
+    Matrix44<T> M (i[0], i[1], i[2], 0, j[0], j[1], j[2], 0, k[0], k[1], k[2], 0, 0, 0, 0, 1);
+
+    //
+    // Extract the first angle, rot.x.
+    //
+
+    rot.x = -std::atan2 (M[1][0], M[0][0]);
+
+    //
+    // Remove the x rotation from M, so that the remaining
+    // rotation, N, is only around two axes, and gimbal lock
+    // cannot occur.
+    //
+
+    Matrix44<T> N;
+    N.rotate (Vec3<T> (0, 0, -rot.x));
+    N = N * M;
+
+    //
+    // Extract the other two angles, rot.y and rot.z, from N.
+    //
+
+    T cy  = std::sqrt (N[2][2] * N[2][2] + N[2][1] * N[2][1]);
+    rot.y = -std::atan2 (-N[2][0], cy);
+    rot.z = -std::atan2 (-N[1][2], N[1][1]);
+}
+
+template <class T>
+Quat<T>
+extractQuat (const Matrix44<T>& mat)
+{
+    T       tr, s;
+    T       q[4];
+    int     i, j, k;
+
+    Quat<T> quat;
+
+    int nxt[3] = { 1, 2, 0 };
+    tr         = mat[0][0] + mat[1][1] + mat[2][2];
+
+    // check the diagonal
+    if (tr > 0.0)
+    {
+        s      = std::sqrt (tr + T (1.0));
+        quat.r = s / T (2.0);
+        s      = T (0.5) / s;
+
+        quat.v.x = (mat[1][2] - mat[2][1]) * s;
+        quat.v.y = (mat[2][0] - mat[0][2]) * s;
+        quat.v.z = (mat[0][1] - mat[1][0]) * s;
+    }
+    else
+    {
+        // diagonal is negative
+        i = 0;
+        if (mat[1][1] > mat[0][0])
+            i = 1;
+        if (mat[2][2] > mat[i][i])
+            i = 2;
+
+        j = nxt[i];
+        k = nxt[j];
+        s = std::sqrt ((mat[i][i] - (mat[j][j] + mat[k][k])) + T (1.0));
+
+        q[i] = s * T (0.5);
+        if (s != T (0.0))
+            s = T (0.5) / s;
+
+        q[3] = (mat[j][k] - mat[k][j]) * s;
+        q[j] = (mat[i][j] + mat[j][i]) * s;
+        q[k] = (mat[i][k] + mat[k][i]) * s;
+
+        quat.v.x = q[0];
+        quat.v.y = q[1];
+        quat.v.z = q[2];
+        quat.r   = q[3];
+    }
+
+    return quat;
+}
+
+template <class T>
+bool
+extractSHRT (const Matrix44<T>& mat,
+             Vec3<T>& s,
+             Vec3<T>& h,
+             Vec3<T>& r,
+             Vec3<T>& t,
+             bool exc /* = true */,
+             typename Euler<T>::Order rOrder /* = Euler<T>::XYZ */)
+{
+    Matrix44<T> rot;
+
+    rot = mat;
+    if (!extractAndRemoveScalingAndShear (rot, s, h, exc))
+        return false;
+
+    extractEulerXYZ (rot, r);
+
+    t.x = mat[3][0];
+    t.y = mat[3][1];
+    t.z = mat[3][2];
+
+    if (rOrder != Euler<T>::XYZ)
+    {
+        Euler<T> eXYZ (r, Euler<T>::XYZ);
+        Euler<T> e (eXYZ, rOrder);
+        r = e.toXYZVector();
+    }
+
+    return true;
+}
+
+template <class T>
+bool
+extractSHRT (const Matrix44<T>& mat, Vec3<T>& s, Vec3<T>& h, Vec3<T>& r, Vec3<T>& t, bool exc)
+{
+    return extractSHRT (mat, s, h, r, t, exc, Euler<T>::XYZ);
+}
+
+template <class T>
+bool
+extractSHRT (const Matrix44<T>& mat,
+             Vec3<T>& s,
+             Vec3<T>& h,
+             Euler<T>& r,
+             Vec3<T>& t,
+             bool exc /* = true */)
+{
+    return extractSHRT (mat, s, h, r, t, exc, r.order());
+}
+
+template <class T>
+bool
+checkForZeroScaleInRow (const T& scl, const Vec3<T>& row, bool exc /* = true */)
+{
+    for (int i = 0; i < 3; i++)
+    {
+        if ((abs (scl) < 1 && abs (row[i]) >= std::numeric_limits<T>::max() * abs (scl)))
+        {
+            if (exc)
+                throw std::domain_error ("Cannot remove zero scaling "
+                                         "from matrix.");
+            else
+                return false;
+        }
+    }
+
+    return true;
+}
+
+template <class T>
+Matrix44<T>
+outerProduct (const Vec4<T>& a, const Vec4<T>& b)
+{
+    return Matrix44<T> (a.x * b.x,
+                        a.x * b.y,
+                        a.x * b.z,
+                        a.x * b.w,
+                        a.y * b.x,
+                        a.y * b.y,
+                        a.y * b.z,
+                        a.x * b.w,
+                        a.z * b.x,
+                        a.z * b.y,
+                        a.z * b.z,
+                        a.x * b.w,
+                        a.w * b.x,
+                        a.w * b.y,
+                        a.w * b.z,
+                        a.w * b.w);
+}
+
+template <class T>
+Matrix44<T>
+rotationMatrix (const Vec3<T>& from, const Vec3<T>& to)
+{
+    Quat<T> q;
+    q.setRotation (from, to);
+    return q.toMatrix44();
+}
+
+template <class T>
+Matrix44<T>
+rotationMatrixWithUpDir (const Vec3<T>& fromDir, const Vec3<T>& toDir, const Vec3<T>& upDir)
+{
+    //
+    // The goal is to obtain a rotation matrix that takes
+    // "fromDir" to "toDir".  We do this in two steps and
+    // compose the resulting rotation matrices;
+    //    (a) rotate "fromDir" into the z-axis
+    //    (b) rotate the z-axis into "toDir"
+    //
+
+    // The from direction must be non-zero; but we allow zero to and up dirs.
+    if (fromDir.length() == 0)
+        return Matrix44<T>();
+
+    else
+    {
+        Matrix44<T> zAxis2FromDir (UNINITIALIZED);
+        alignZAxisWithTargetDir (zAxis2FromDir, fromDir, Vec3<T> (0, 1, 0));
+
+        Matrix44<T> fromDir2zAxis = zAxis2FromDir.transposed();
+
+        Matrix44<T> zAxis2ToDir (UNINITIALIZED);
+        alignZAxisWithTargetDir (zAxis2ToDir, toDir, upDir);
+
+        return fromDir2zAxis * zAxis2ToDir;
+    }
+}
+
+template <class T>
+void
+alignZAxisWithTargetDir (Matrix44<T>& result, Vec3<T> targetDir, Vec3<T> upDir)
+{
+    //
+    // Ensure that the target direction is non-zero.
+    //
+
+    if (targetDir.length() == 0)
+        targetDir = Vec3<T> (0, 0, 1);
+
+    //
+    // Ensure that the up direction is non-zero.
+    //
+
+    if (upDir.length() == 0)
+        upDir = Vec3<T> (0, 1, 0);
+
+    //
+    // Check for degeneracies.  If the upDir and targetDir are parallel
+    // or opposite, then compute a new, arbitrary up direction that is
+    // not parallel or opposite to the targetDir.
+    //
+
+    if (upDir.cross (targetDir).length() == 0)
+    {
+        upDir = targetDir.cross (Vec3<T> (1, 0, 0));
+        if (upDir.length() == 0)
+            upDir = targetDir.cross (Vec3<T> (0, 0, 1));
+    }
+
+    //
+    // Compute the x-, y-, and z-axis vectors of the new coordinate system.
+    //
+
+    Vec3<T> targetPerpDir = upDir.cross (targetDir);
+    Vec3<T> targetUpDir   = targetDir.cross (targetPerpDir);
+
+    //
+    // Rotate the x-axis into targetPerpDir (row 0),
+    // rotate the y-axis into targetUpDir   (row 1),
+    // rotate the z-axis into targetDir     (row 2).
+    //
+
+    Vec3<T> row[3];
+    row[0] = targetPerpDir.normalized();
+    row[1] = targetUpDir.normalized();
+    row[2] = targetDir.normalized();
+
+    result.x[0][0] = row[0][0];
+    result.x[0][1] = row[0][1];
+    result.x[0][2] = row[0][2];
+    result.x[0][3] = (T) 0;
+
+    result.x[1][0] = row[1][0];
+    result.x[1][1] = row[1][1];
+    result.x[1][2] = row[1][2];
+    result.x[1][3] = (T) 0;
+
+    result.x[2][0] = row[2][0];
+    result.x[2][1] = row[2][1];
+    result.x[2][2] = row[2][2];
+    result.x[2][3] = (T) 0;
+
+    result.x[3][0] = (T) 0;
+    result.x[3][1] = (T) 0;
+    result.x[3][2] = (T) 0;
+    result.x[3][3] = (T) 1;
+}
+
+// Compute an orthonormal direct frame from : a position, an x axis direction and a normal to the y axis
+// If the x axis and normal are perpendicular, then the normal will have the same direction as the z axis.
+// Inputs are :
+//     -the position of the frame
+//     -the x axis direction of the frame
+//     -a normal to the y axis of the frame
+// Return is the orthonormal frame
+template <class T>
+Matrix44<T>
+computeLocalFrame (const Vec3<T>& p, const Vec3<T>& xDir, const Vec3<T>& normal)
+{
+    Vec3<T> _xDir (xDir);
+    Vec3<T> x = _xDir.normalize();
+    Vec3<T> y = (normal % x).normalize();
+    Vec3<T> z = (x % y).normalize();
+
+    Matrix44<T> L;
+    L[0][0] = x[0];
+    L[0][1] = x[1];
+    L[0][2] = x[2];
+    L[0][3] = 0.0;
+
+    L[1][0] = y[0];
+    L[1][1] = y[1];
+    L[1][2] = y[2];
+    L[1][3] = 0.0;
+
+    L[2][0] = z[0];
+    L[2][1] = z[1];
+    L[2][2] = z[2];
+    L[2][3] = 0.0;
+
+    L[3][0] = p[0];
+    L[3][1] = p[1];
+    L[3][2] = p[2];
+    L[3][3] = 1.0;
+
+    return L;
+}
+
+/// Add a translate/rotate/scale offset to an input frame and put it
+/// in another frame of reference.
+///
+/// @param inMat input frame
+/// @param tOffset translate offset
+/// @param rOffset rotate offset in degrees
+/// @param sOffset scale offset
+/// @param ref Frame of reference
+/// @return The offsetted frame
+template <class T>
+Matrix44<T>
+addOffset (const Matrix44<T>& inMat,
+           const Vec3<T>& tOffset,
+           const Vec3<T>& rOffset,
+           const Vec3<T>& sOffset,
+           const Matrix44<T>& ref)
+{
+    Matrix44<T> O;
+
+    Vec3<T> _rOffset (rOffset);
+    _rOffset *= T(M_PI / 180.0);
+    O.rotate (_rOffset);
+
+    O[3][0] = tOffset[0];
+    O[3][1] = tOffset[1];
+    O[3][2] = tOffset[2];
+
+    Matrix44<T> S;
+    S.scale (sOffset);
+
+    Matrix44<T> X = S * O * inMat * ref;
+
+    return X;
+}
+
+// Compute Translate/Rotate/Scale matrix from matrix A with the Rotate/Scale of Matrix B
+// Inputs are :
+//      -keepRotateA : if true keep rotate from matrix A, use B otherwise
+//      -keepScaleA  : if true keep scale  from matrix A, use B otherwise
+//      -Matrix A
+//      -Matrix B
+// Return Matrix A with tweaked rotation/scale
+template <class T>
+Matrix44<T>
+computeRSMatrix (bool keepRotateA, bool keepScaleA, const Matrix44<T>& A, const Matrix44<T>& B)
+{
+    Vec3<T> as, ah, ar, at;
+    if (!extractSHRT (A, as, ah, ar, at))
+        throw std::domain_error ("degenerate A matrix in computeRSMatrix");
+
+    Vec3<T> bs, bh, br, bt;
+    if (!extractSHRT (B, bs, bh, br, bt))
+        throw std::domain_error ("degenerate B matrix in computeRSMatrix");
+
+    if (!keepRotateA)
+        ar = br;
+
+    if (!keepScaleA)
+        as = bs;
+
+    Matrix44<T> mat;
+    mat.makeIdentity();
+    mat.translate (at);
+    mat.rotate (ar);
+    mat.scale (as);
+
+    return mat;
+}
+
+//-----------------------------------------------------------------------------
+// Implementation for 3x3 Matrix
+//------------------------------
+
+template <class T>
+bool
+extractScaling (const Matrix33<T>& mat, Vec2<T>& scl, bool exc)
+{
+    T shr;
+    Matrix33<T> M (mat);
+
+    if (!extractAndRemoveScalingAndShear (M, scl, shr, exc))
+        return false;
+
+    return true;
+}
+
+template <class T>
+Matrix33<T>
+sansScaling (const Matrix33<T>& mat, bool exc)
+{
+    Vec2<T> scl;
+    T shr;
+    T rot;
+    Vec2<T> tran;
+
+    if (!extractSHRT (mat, scl, shr, rot, tran, exc))
+        return mat;
+
+    Matrix33<T> M;
+
+    M.translate (tran);
+    M.rotate (rot);
+    M.shear (shr);
+
+    return M;
+}
+
+template <class T>
+bool
+removeScaling (Matrix33<T>& mat, bool exc)
+{
+    Vec2<T> scl;
+    T shr;
+    T rot;
+    Vec2<T> tran;
+
+    if (!extractSHRT (mat, scl, shr, rot, tran, exc))
+        return false;
+
+    mat.makeIdentity();
+    mat.translate (tran);
+    mat.rotate (rot);
+    mat.shear (shr);
+
+    return true;
+}
+
+template <class T>
+bool
+extractScalingAndShear (const Matrix33<T>& mat, Vec2<T>& scl, T& shr, bool exc)
+{
+    Matrix33<T> M (mat);
+
+    if (!extractAndRemoveScalingAndShear (M, scl, shr, exc))
+        return false;
+
+    return true;
+}
+
+template <class T>
+Matrix33<T>
+sansScalingAndShear (const Matrix33<T>& mat, bool exc)
+{
+    Vec2<T> scl;
+    T shr;
+    Matrix33<T> M (mat);
+
+    if (!extractAndRemoveScalingAndShear (M, scl, shr, exc))
+        return mat;
+
+    return M;
+}
+
+template <class T>
+bool
+removeScalingAndShear (Matrix33<T>& mat, bool exc)
+{
+    Vec2<T> scl;
+    T shr;
+
+    if (!extractAndRemoveScalingAndShear (mat, scl, shr, exc))
+        return false;
+
+    return true;
+}
+
+template <class T>
+bool
+extractAndRemoveScalingAndShear (Matrix33<T>& mat, Vec2<T>& scl, T& shr, bool exc)
+{
+    Vec2<T> row[2];
+
+    row[0] = Vec2<T> (mat[0][0], mat[0][1]);
+    row[1] = Vec2<T> (mat[1][0], mat[1][1]);
+
+    T maxVal = 0;
+    for (int i = 0; i < 2; i++)
+        for (int j = 0; j < 2; j++)
+            if (IMATH_INTERNAL_NAMESPACE::abs (row[i][j]) > maxVal)
+                maxVal = IMATH_INTERNAL_NAMESPACE::abs (row[i][j]);
+
+    //
+    // We normalize the 2x2 matrix here.
+    // It was noticed that this can improve numerical stability significantly,
+    // especially when many of the upper 2x2 matrix's coefficients are very
+    // close to zero; we correct for this step at the end by multiplying the
+    // scaling factors by maxVal at the end (shear and rotation are not
+    // affected by the normalization).
+
+    if (maxVal != 0)
+    {
+        for (int i = 0; i < 2; i++)
+            if (!checkForZeroScaleInRow (maxVal, row[i], exc))
+                return false;
+            else
+                row[i] /= maxVal;
+    }
+
+    // Compute X scale factor.
+    scl.x = row[0].length();
+    if (!checkForZeroScaleInRow (scl.x, row[0], exc))
+        return false;
+
+    // Normalize first row.
+    row[0] /= scl.x;
+
+    // An XY shear factor will shear the X coord. as the Y coord. changes.
+    // There are 2 combinations (XY, YX), although we only extract the XY
+    // shear factor because we can effect the an YX shear factor by
+    // shearing in XY combined with rotations and scales.
+    //
+    // shear matrix <   1,  YX,  0,
+    //                 XY,   1,  0,
+    //                  0,   0,  1 >
+
+    // Compute XY shear factor and make 2nd row orthogonal to 1st.
+    shr = row[0].dot (row[1]);
+    row[1] -= shr * row[0];
+
+    // Now, compute Y scale.
+    scl.y = row[1].length();
+    if (!checkForZeroScaleInRow (scl.y, row[1], exc))
+        return false;
+
+    // Normalize 2nd row and correct the XY shear factor for Y scaling.
+    row[1] /= scl.y;
+    shr /= scl.y;
+
+    // At this point, the upper 2x2 matrix in mat is orthonormal.
+    // Check for a coordinate system flip. If the determinant
+    // is -1, then flip the rotation matrix and adjust the scale(Y)
+    // and shear(XY) factors to compensate.
+    if (row[0][0] * row[1][1] - row[0][1] * row[1][0] < 0)
+    {
+        row[1][0] *= -1;
+        row[1][1] *= -1;
+        scl[1] *= -1;
+        shr *= -1;
+    }
+
+    // Copy over the orthonormal rows into the returned matrix.
+    // The upper 2x2 matrix in mat is now a rotation matrix.
+    for (int i = 0; i < 2; i++)
+    {
+        mat[i][0] = row[i][0];
+        mat[i][1] = row[i][1];
+    }
+
+    scl *= maxVal;
+
+    return true;
+}
+
+template <class T>
+void
+extractEuler (const Matrix22<T>& mat, T& rot)
+{
+    //
+    // Normalize the local x and y axes to remove scaling.
+    //
+
+    Vec2<T> i (mat[0][0], mat[0][1]);
+    Vec2<T> j (mat[1][0], mat[1][1]);
+
+    i.normalize();
+    j.normalize();
+
+    //
+    // Extract the angle, rot.
+    //
+
+    rot = -std::atan2 (j[0], i[0]);
+}
+
+template <class T>
+void
+extractEuler (const Matrix33<T>& mat, T& rot)
+{
+    //
+    // Normalize the local x and y axes to remove scaling.
+    //
+
+    Vec2<T> i (mat[0][0], mat[0][1]);
+    Vec2<T> j (mat[1][0], mat[1][1]);
+
+    i.normalize();
+    j.normalize();
+
+    //
+    // Extract the angle, rot.
+    //
+
+    rot = -std::atan2 (j[0], i[0]);
+}
+
+template <class T>
+bool
+extractSHRT (const Matrix33<T>& mat, Vec2<T>& s, T& h, T& r, Vec2<T>& t, bool exc)
+{
+    Matrix33<T> rot;
+
+    rot = mat;
+    if (!extractAndRemoveScalingAndShear (rot, s, h, exc))
+        return false;
+
+    extractEuler (rot, r);
+
+    t.x = mat[2][0];
+    t.y = mat[2][1];
+
+    return true;
+}
+
+/// @cond Doxygen_Suppress
+template <class T>
+bool
+checkForZeroScaleInRow (const T& scl, const Vec2<T>& row, bool exc /* = true */)
+{
+    for (int i = 0; i < 2; i++)
+    {
+        if ((abs (scl) < 1 && abs (row[i]) >= std::numeric_limits<T>::max() * abs (scl)))
+        {
+            if (exc)
+                throw std::domain_error ("Cannot remove zero scaling from matrix.");
+            else
+                return false;
+        }
+    }
+
+    return true;
+}
+/// @endcond
+
+template <class T>
+Matrix33<T>
+outerProduct (const Vec3<T>& a, const Vec3<T>& b)
+{
+    return Matrix33<T> (a.x * b.x,
+                        a.x * b.y,
+                        a.x * b.z,
+                        a.y * b.x,
+                        a.y * b.y,
+                        a.y * b.z,
+                        a.z * b.x,
+                        a.z * b.y,
+                        a.z * b.z);
+}
+
+/// Computes the translation and rotation that brings the 'from' points
+/// as close as possible to the 'to' points under the Frobenius norm.
+/// To be more specific, let x be the matrix of 'from' points and y be
+/// the matrix of 'to' points, we want to find the matrix A of the form
+///    [ R t ]
+///    [ 0 1 ]
+/// that minimizes
+///     || (A*x - y)^T * W * (A*x - y) ||_F
+/// If doScaling is true, then a uniform scale is allowed also.
+/// @param A From points
+/// @param B To points
+/// @param weights Per-point weights
+/// @param numPoints The number of points in `A`, `B`, and `weights` (must be equal)
+/// @param doScaling If true, include a scaling transformation
+/// @return The procrustes transformation
+template <typename T>
+M44d
+procrustesRotationAndTranslation (const Vec3<T>* A,
+                                  const Vec3<T>* B,
+                                  const T* weights,
+                                  const size_t numPoints,
+                                  const bool doScaling = false);
+
+/// Computes the translation and rotation that brings the 'from' points
+/// as close as possible to the 'to' points under the Frobenius norm.
+/// To be more specific, let x be the matrix of 'from' points and y be
+/// the matrix of 'to' points, we want to find the matrix A of the form
+///    [ R t ]
+///    [ 0 1 ]
+/// that minimizes
+///     || (A*x - y)^T * W * (A*x - y) ||_F
+/// If doScaling is true, then a uniform scale is allowed also.
+/// @param A From points
+/// @param B To points
+/// @param numPoints The number of points in `A` and `B` (must be equal)
+/// @param doScaling If true, include a scaling transformation
+/// @return The procrustes transformation
+template <typename T>
+M44d
+procrustesRotationAndTranslation (const Vec3<T>* A,
+                                  const Vec3<T>* B,
+                                  const size_t numPoints,
+                                  const bool doScaling = false);
+
+/// Compute the SVD of a 3x3 matrix using Jacobi transformations.  This method
+/// should be quite accurate (competitive with LAPACK) even for poorly
+/// conditioned matrices, and because it has been written specifically for the
+/// 3x3/4x4 case it is much faster than calling out to LAPACK.
+///
+/// The SVD of a 3x3/4x4 matrix A is defined as follows:
+///     A = U * S * V^T
+/// where S is the diagonal matrix of singular values and both U and V are
+/// orthonormal.  By convention, the entries S are all positive and sorted from
+/// the largest to the smallest.  However, some uses of this function may
+/// require that the matrix U*V^T have positive determinant; in this case, we
+/// may make the smallest singular value negative to ensure that this is
+/// satisfied.
+///
+/// Currently only available for single- and double-precision matrices.
+template <typename T>
+void jacobiSVD (const Matrix33<T>& A,
+                Matrix33<T>& U,
+                Vec3<T>& S,
+                Matrix33<T>& V,
+                const T tol = std::numeric_limits<T>::epsilon(),
+                const bool forcePositiveDeterminant = false);
+
+/// Compute the SVD of a 3x3 matrix using Jacobi transformations.  This method
+/// should be quite accurate (competitive with LAPACK) even for poorly
+/// conditioned matrices, and because it has been written specifically for the
+/// 3x3/4x4 case it is much faster than calling out to LAPACK.
+///
+/// The SVD of a 3x3/4x4 matrix A is defined as follows:
+///     A = U * S * V^T
+/// where S is the diagonal matrix of singular values and both U and V are
+/// orthonormal.  By convention, the entries S are all positive and sorted from
+/// the largest to the smallest.  However, some uses of this function may
+/// require that the matrix U*V^T have positive determinant; in this case, we
+/// may make the smallest singular value negative to ensure that this is
+/// satisfied.
+///
+/// Currently only available for single- and double-precision matrices.
+template <typename T>
+void jacobiSVD (const Matrix44<T>& A,
+                Matrix44<T>& U,
+                Vec4<T>& S,
+                Matrix44<T>& V,
+                const T tol = std::numeric_limits<T>::epsilon(),
+                const bool forcePositiveDeterminant = false);
+
+/// Compute the eigenvalues (S) and the eigenvectors (V) of a real
+/// symmetric matrix using Jacobi transformation, using a given
+/// tolerance `tol`.
+///
+/// Jacobi transformation of a 3x3/4x4 matrix A outputs S and V:
+///    A = V * S * V^T
+/// where V is orthonormal and S is the diagonal matrix of eigenvalues.
+/// Input matrix A must be symmetric. A is also modified during
+/// the computation so that upper diagonal entries of A become zero.
+template <typename T>
+void jacobiEigenSolver (Matrix33<T>& A, Vec3<T>& S, Matrix33<T>& V, const T tol);
+
+/// Compute the eigenvalues (S) and the eigenvectors (V) of
+/// a real symmetric matrix using Jacobi transformation.
+///
+/// Jacobi transformation of a 3x3/4x4 matrix A outputs S and V:
+///    A = V * S * V^T
+/// where V is orthonormal and S is the diagonal matrix of eigenvalues.
+/// Input matrix A must be symmetric. A is also modified during
+/// the computation so that upper diagonal entries of A become zero.
+template <typename T>
+inline void
+jacobiEigenSolver (Matrix33<T>& A, Vec3<T>& S, Matrix33<T>& V)
+{
+    jacobiEigenSolver (A, S, V, std::numeric_limits<T>::epsilon());
+}
+
+/// Compute the eigenvalues (S) and the eigenvectors (V) of a real
+/// symmetric matrix using Jacobi transformation, using a given
+/// tolerance `tol`.
+///
+/// Jacobi transformation of a 3x3/4x4 matrix A outputs S and V:
+///    A = V * S * V^T
+/// where V is orthonormal and S is the diagonal matrix of eigenvalues.
+/// Input matrix A must be symmetric. A is also modified during
+/// the computation so that upper diagonal entries of A become zero.
+template <typename T>
+void jacobiEigenSolver (Matrix44<T>& A, Vec4<T>& S, Matrix44<T>& V, const T tol);
+
+/// Compute the eigenvalues (S) and the eigenvectors (V) of
+/// a real symmetric matrix using Jacobi transformation.
+///
+/// Jacobi transformation of a 3x3/4x4 matrix A outputs S and V:
+///    A = V * S * V^T
+/// where V is orthonormal and S is the diagonal matrix of eigenvalues.
+/// Input matrix A must be symmetric. A is also modified during
+/// the computation so that upper diagonal entries of A become zero.
+template <typename T>
+inline void
+jacobiEigenSolver (Matrix44<T>& A, Vec4<T>& S, Matrix44<T>& V)
+{
+    jacobiEigenSolver (A, S, V, std::numeric_limits<T>::epsilon());
+}
+
+/// Compute a eigenvector corresponding to the abs max eigenvalue
+/// of a real symmetric matrix using Jacobi transformation.
+template <typename TM, typename TV> void maxEigenVector (TM& A, TV& S);
+
+/// Compute a eigenvector corresponding to the abs min eigenvalue
+/// of a real symmetric matrix using Jacobi transformation.
+template <typename TM, typename TV> void minEigenVector (TM& A, TV& S);
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHMATRIXALGO_H
diff --git a/src/Imath/ImathNamespace.h b/src/Imath/ImathNamespace.h
new file mode 100644 (file)
index 0000000..913241c
--- /dev/null
@@ -0,0 +1,96 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// The Imath library namespace
+//
+// The purpose of this file is to make it possible to specify an
+// IMATH_INTERNAL_NAMESPACE as a preprocessor definition and have all of the
+// Imath symbols defined within that namespace rather than the standard
+// Imath namespace.  Those symbols are made available to client code through
+// the IMATH_NAMESPACE in addition to the IMATH_INTERNAL_NAMESPACE.
+//
+// To ensure source code compatibility, the IMATH_NAMESPACE defaults to Imath
+// and then "using namespace IMATH_INTERNAL_NAMESPACE;" brings all of the
+// declarations from the IMATH_INTERNAL_NAMESPACE into the IMATH_NAMESPACE.
+// This means that client code can continue to use syntax like Imath::V3f,
+// but at link time it will resolve to a mangled symbol based on the
+// IMATH_INTERNAL_NAMESPACE.
+//
+// As an example, if one needed to build against a newer version of Imath and
+// have it run alongside an older version in the same application, it is now
+// possible to use an internal namespace to prevent collisions between the
+// older versions of Imath symbols and the newer ones.  To do this, the
+// following could be defined at build time:
+//
+// IMATH_INTERNAL_NAMESPACE = Imath_v2
+//
+// This means that declarations inside Imath headers look like this (after
+// the preprocessor has done its work):
+//
+// namespace Imath_v2 {
+//     ...
+//     class declarations
+//     ...
+// }
+//
+// namespace Imath {
+//     using namespace Imath_v2;
+// }
+//
+
+#ifndef INCLUDED_IMATHNAMESPACE_H
+#define INCLUDED_IMATHNAMESPACE_H
+
+/// @cond Doxygen_Suppress
+
+#include "ImathConfig.h"
+
+#ifndef IMATH_NAMESPACE
+#    define IMATH_NAMESPACE Imath
+#endif
+
+#ifndef IMATH_INTERNAL_NAMESPACE
+#    define IMATH_INTERNAL_NAMESPACE IMATH_NAMESPACE
+#endif
+
+#ifdef __cplusplus
+
+//
+// We need to be sure that we import the internal namespace into the public one.
+// To do this, we use the small bit of code below which initially defines
+// IMATH_INTERNAL_NAMESPACE (so it can be referenced) and then defines
+// IMATH_NAMESPACE and pulls the internal symbols into the public
+// namespace.
+//
+
+namespace IMATH_INTERNAL_NAMESPACE
+{}
+namespace IMATH_NAMESPACE
+{
+using namespace IMATH_INTERNAL_NAMESPACE;
+}
+
+//
+// There are identical pairs of HEADER/SOURCE ENTER/EXIT macros so that
+// future extension to the namespace mechanism is possible without changing
+// project source code.
+//
+
+#define IMATH_INTERNAL_NAMESPACE_HEADER_ENTER                                                      \
+    namespace IMATH_INTERNAL_NAMESPACE                                                             \
+    {
+#define IMATH_INTERNAL_NAMESPACE_HEADER_EXIT }
+
+#define IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER                                                      \
+    namespace IMATH_INTERNAL_NAMESPACE                                                             \
+    {
+#define IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT }
+
+#endif // __cplusplus
+
+/// @endcond
+
+#endif /* INCLUDED_IMATHNAMESPACE_H */
diff --git a/src/Imath/ImathPlane.h b/src/Imath/ImathPlane.h
new file mode 100644 (file)
index 0000000..9ec1e83
--- /dev/null
@@ -0,0 +1,260 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// A 3D plane class template
+//
+
+#ifndef INCLUDED_IMATHPLANE_H
+#define INCLUDED_IMATHPLANE_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include "ImathLine.h"
+#include "ImathVec.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// The `Plane3` class represents a half space in 3D, so the normal
+/// may point either towards or away from origin.  The plane `P` can
+/// be represented by Plane3 as either `p` or `-p` corresponding to
+/// the two half-spaces on either side of the plane. Any function
+/// which computes a distance will return either negative or positive
+/// values for the distance indicating which half-space the point is
+/// in. Note that reflection, and intersection functions will operate
+/// as expected.
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Plane3
+{
+  public:
+
+    /// @{
+    /// @name Direct access to member fields
+    
+    /// The normal to the plane
+    Vec3<T> normal;
+    
+    /// The distance from the origin to the plane
+    T distance;
+
+    /// @}
+
+    /// @{
+    ///        @name Constructors
+
+    /// Uninitialized by default
+    IMATH_HOSTDEVICE Plane3() IMATH_NOEXCEPT {}
+
+    /// Initialize with a normal and distance
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Plane3 (const Vec3<T>& normal, T distance) IMATH_NOEXCEPT;
+
+    /// Initialize with a point and a normal
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Plane3 (const Vec3<T>& point, const Vec3<T>& normal) IMATH_NOEXCEPT;
+    
+    /// Initialize with three points
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Plane3 (const Vec3<T>& point1,
+                                               const Vec3<T>& point2,
+                                               const Vec3<T>& point3) IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Manipulation
+    
+    /// Set via a given normal and distance
+    IMATH_HOSTDEVICE void set (const Vec3<T>& normal, T distance) IMATH_NOEXCEPT;
+
+    /// Set via a given point and normal
+    IMATH_HOSTDEVICE void set (const Vec3<T>& point, const Vec3<T>& normal) IMATH_NOEXCEPT;
+
+    /// Set via three points
+    IMATH_HOSTDEVICE void set (const Vec3<T>& point1, const Vec3<T>& point2, const Vec3<T>& point3) IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Utility Methods
+    
+    /// Determine if a line intersects the plane.
+    /// @param line The line
+    /// @param[out] intersection The point of intersection
+    /// @return True if the line intersects the plane.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool
+    intersect (const Line3<T>& line, Vec3<T>& intersection) const IMATH_NOEXCEPT;
+
+    /// Determine if a line intersects the plane.
+    /// @param line The line
+    /// @param[out] parameter The parametric value of the point of intersection
+    /// @return True if the line intersects the plane.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersectT (const Line3<T>& line, T& parameter) const IMATH_NOEXCEPT;
+
+    /// Return the distance from a point to the plane.
+    IMATH_HOSTDEVICE constexpr T distanceTo (const Vec3<T>& point) const IMATH_NOEXCEPT;
+
+    /// Reflect the given point around the plane.
+    IMATH_HOSTDEVICE constexpr Vec3<T> reflectPoint (const Vec3<T>& point) const IMATH_NOEXCEPT;
+
+    /// Reflect the direction vector around the plane
+    IMATH_HOSTDEVICE constexpr Vec3<T> reflectVector (const Vec3<T>& vec) const IMATH_NOEXCEPT;
+
+    /// @}
+};
+
+/// Plane of type float
+typedef Plane3<float> Plane3f;
+
+/// Plane of type double
+typedef Plane3<double> Plane3d;
+
+//---------------
+// Implementation
+//---------------
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Plane3<T>::Plane3 (const Vec3<T>& p0, const Vec3<T>& p1, const Vec3<T>& p2) IMATH_NOEXCEPT
+{
+    set (p0, p1, p2);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Plane3<T>::Plane3 (const Vec3<T>& n, T d) IMATH_NOEXCEPT
+{
+    set (n, d);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Plane3<T>::Plane3 (const Vec3<T>& p, const Vec3<T>& n) IMATH_NOEXCEPT
+{
+    set (p, n);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Plane3<T>::set (const Vec3<T>& point1, const Vec3<T>& point2, const Vec3<T>& point3) IMATH_NOEXCEPT
+{
+    normal = (point2 - point1) % (point3 - point1);
+    normal.normalize();
+    distance = normal ^ point1;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Plane3<T>::set (const Vec3<T>& point, const Vec3<T>& n) IMATH_NOEXCEPT
+{
+    normal = n;
+    normal.normalize();
+    distance = normal ^ point;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Plane3<T>::set (const Vec3<T>& n, T d) IMATH_NOEXCEPT
+{
+    normal = n;
+    normal.normalize();
+    distance = d;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Plane3<T>::distanceTo (const Vec3<T>& point) const IMATH_NOEXCEPT
+{
+    return (point ^ normal) - distance;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Plane3<T>::reflectPoint (const Vec3<T>& point) const IMATH_NOEXCEPT
+{
+    return normal * distanceTo (point) * -2.0 + point;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Plane3<T>::reflectVector (const Vec3<T>& v) const IMATH_NOEXCEPT
+{
+    return normal * (normal ^ v) * 2.0 - v;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Plane3<T>::intersect (const Line3<T>& line, Vec3<T>& point) const IMATH_NOEXCEPT
+{
+    T d = normal ^ line.dir;
+    if (d == 0.0)
+        return false;
+    T t   = -((normal ^ line.pos) - distance) / d;
+    point = line (t);
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Plane3<T>::intersectT (const Line3<T>& line, T& t) const IMATH_NOEXCEPT
+{
+    T d = normal ^ line.dir;
+    if (d == 0.0)
+        return false;
+    t = -((normal ^ line.pos) - distance) / d;
+    return true;
+}
+
+/// Stream output, as "(normal distance)"
+template <class T>
+std::ostream&
+operator<< (std::ostream& o, const Plane3<T>& plane)
+{
+    return o << "(" << plane.normal << ", " << plane.distance << ")";
+}
+
+/// Transform a plane by a matrix
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Plane3<T>
+operator* (const Plane3<T>& plane, const Matrix44<T>& M) IMATH_NOEXCEPT
+{
+    //                        T
+    //                     -1
+    // Could also compute M    but that would suck.
+    //
+
+    Vec3<T> dir1 = Vec3<T> (1, 0, 0) % plane.normal;
+    T dir1Len    = dir1 ^ dir1;
+
+    Vec3<T> tmp = Vec3<T> (0, 1, 0) % plane.normal;
+    T tmpLen    = tmp ^ tmp;
+
+    if (tmpLen > dir1Len)
+    {
+        dir1    = tmp;
+        dir1Len = tmpLen;
+    }
+
+    tmp    = Vec3<T> (0, 0, 1) % plane.normal;
+    tmpLen = tmp ^ tmp;
+
+    if (tmpLen > dir1Len)
+    {
+        dir1 = tmp;
+    }
+
+    Vec3<T> dir2  = dir1 % plane.normal;
+    Vec3<T> point = plane.distance * plane.normal;
+
+    return Plane3<T> (point * M, (point + dir2) * M, (point + dir1) * M);
+}
+
+/// Reflect the pla
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Plane3<T>
+operator- (const Plane3<T>& plane) IMATH_NOEXCEPT
+{
+    return Plane3<T> (-plane.normal, -plane.distance);
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHPLANE_H
diff --git a/src/Imath/ImathPlatform.h b/src/Imath/ImathPlatform.h
new file mode 100644 (file)
index 0000000..5dc32fd
--- /dev/null
@@ -0,0 +1,81 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// This file contains functions and constants which aren't
+// provided by the system libraries, compilers, or includes on
+// certain platforms.
+//
+
+#ifndef INCLUDED_IMATHPLATFORM_H
+#define INCLUDED_IMATHPLATFORM_H
+
+/// @cond Doxygen_Suppress
+
+#include <math.h>
+
+#include "ImathNamespace.h"
+
+#ifdef __cplusplus
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//
+// Helpful macros for checking which C++ standard we are compiling with.
+//
+#if (__cplusplus >= 202002L)
+#    define IMATH_CPLUSPLUS_VERSION 20
+#elif (__cplusplus >= 201703L)
+#    define IMATH_CPLUSPLUS_VERSION 17
+#elif (__cplusplus >= 201402L) || (defined(_MSC_VER) && _MSC_VER >= 1914)
+#    define IMATH_CPLUSPLUS_VERSION 14
+#elif (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900)
+#    define IMATH_CPLUSPLUS_VERSION 11
+#else
+#    error "This version of Imath is meant to work only with C++11 and above"
+#endif
+
+
+//
+// Constexpr C++14 conditional definition
+//
+#if (IMATH_CPLUSPLUS_VERSION >= 14)
+  #define IMATH_CONSTEXPR14 constexpr
+#else
+  #define IMATH_CONSTEXPR14 /* can not be constexpr before c++14 */
+#endif
+
+#endif // __cplusplus
+
+#ifndef M_PI
+#    define M_PI 3.14159265358979323846
+#endif
+
+#ifndef M_PI_2
+#    define M_PI_2 1.57079632679489661923 // pi/2
+#endif
+
+//-----------------------------------------------------------------------------
+//
+//    Some, but not all, C++ compilers support the C99 restrict
+//    keyword or some variant of it, for example, __restrict.
+//
+//-----------------------------------------------------------------------------
+
+#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) || defined(__INTEL_COMPILER)
+#    define IMATH_RESTRICT __restrict
+#else
+#    define IMATH_RESTRICT
+#endif
+
+#ifdef __cplusplus
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // __cplusplus
+
+/// @endcond
+
+#endif // INCLUDED_IMATHPLATFORM_H
diff --git a/src/Imath/ImathQuat.h b/src/Imath/ImathQuat.h
new file mode 100644 (file)
index 0000000..ebe242a
--- /dev/null
@@ -0,0 +1,951 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// A quaternion
+//
+// "Quaternions came from Hamilton ... and have been an unmixed
+// evil to those who have touched them in any way. Vector is a
+// useless survival ... and has never been of the slightest use
+// to any creature."
+//
+//   - Lord Kelvin
+//
+
+#ifndef INCLUDED_IMATHQUAT_H
+#define INCLUDED_IMATHQUAT_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include "ImathMatrix.h"
+
+#include <iostream>
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
+// Disable MS VC++ warnings about conversion from double to float
+#    pragma warning(push)
+#    pragma warning(disable : 4244)
+#endif
+
+///
+/// The Quat class implements the quaternion numerical type -- you
+/// will probably want to use this class to represent orientations
+/// in R3 and to convert between various euler angle reps. You
+/// should probably use Imath::Euler<> for that.
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Quat
+{
+  public:
+
+    /// @{
+    /// @name Direct access to elements
+    
+    /// The real part
+    T r;       
+
+    /// The imaginary vector
+    Vec3<T> v;
+
+    /// @}
+
+    /// Element access: q[0] is the real part, (q[1],q[2],q[3]) is the
+    /// imaginary part.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T& operator[] (int index) IMATH_NOEXCEPT; // as 4D vector
+
+    /// Element access: q[0] is the real part, (q[1],q[2],q[3]) is the
+    /// imaginary part.
+    IMATH_HOSTDEVICE constexpr T operator[] (int index) const IMATH_NOEXCEPT;
+
+    /// @{
+    ///        @name Constructors
+
+    /// Default constructor is the identity quat
+    IMATH_HOSTDEVICE constexpr Quat() IMATH_NOEXCEPT;
+
+    /// Copy constructor
+    IMATH_HOSTDEVICE constexpr Quat (const Quat& q) IMATH_NOEXCEPT;
+
+    /// Construct from a quaternion of a another base type
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat (const Quat<S>& q) IMATH_NOEXCEPT;
+
+    /// Initialize with real part `s` and imaginary vector 1(i,j,k)`
+    IMATH_HOSTDEVICE constexpr Quat (T s, T i, T j, T k) IMATH_NOEXCEPT;
+
+    /// Initialize with real part `s` and imaginary vector `d`
+    IMATH_HOSTDEVICE constexpr Quat (T s, Vec3<T> d) IMATH_NOEXCEPT;
+
+    /// The identity quaternion
+    IMATH_HOSTDEVICE constexpr static Quat<T> identity() IMATH_NOEXCEPT;
+
+    /// Assignment
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator= (const Quat<T>& q) IMATH_NOEXCEPT;
+
+    /// Destructor
+    ~Quat () IMATH_NOEXCEPT = default;
+
+    /// @}
+
+    /// @{
+    /// @name Basic Algebra 
+    ///        
+    /// Note that the operator return values are *NOT* normalized
+    //
+
+    /// Quaternion multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator*= (const Quat<T>& q) IMATH_NOEXCEPT;
+    
+    /// Scalar multiplication: multiply both real and imaginary parts
+    /// by the given scalar.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator*= (T t) IMATH_NOEXCEPT;
+
+    /// Quaterion division, using the inverse()
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator/= (const Quat<T>& q) IMATH_NOEXCEPT;
+
+    /// Scalar division: multiply both real and imaginary parts
+    /// by the given scalar.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator/= (T t) IMATH_NOEXCEPT;
+
+    /// Quaternion addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator+= (const Quat<T>& q) IMATH_NOEXCEPT;
+
+    /// Quaternion subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator-= (const Quat<T>& q) IMATH_NOEXCEPT;
+
+    /// Equality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator== (const Quat<S>& q) const IMATH_NOEXCEPT;
+
+    /// Inequality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator!= (const Quat<S>& q) const IMATH_NOEXCEPT;
+
+    /// @}
+
+
+    /// @{
+    /// @name Query
+    
+    /// Return the R4 length
+    IMATH_HOSTDEVICE constexpr T length() const IMATH_NOEXCEPT; // in R4
+
+    /// Return the angle of the axis/angle representation
+    IMATH_HOSTDEVICE constexpr T angle() const IMATH_NOEXCEPT;
+
+    /// Return the axis of the axis/angle representation
+    IMATH_HOSTDEVICE constexpr Vec3<T> axis() const IMATH_NOEXCEPT;
+
+    /// Return a 3x3 rotation matrix
+    IMATH_HOSTDEVICE constexpr Matrix33<T> toMatrix33() const IMATH_NOEXCEPT;
+
+    /// Return a 4x4 rotation matrix
+    IMATH_HOSTDEVICE constexpr Matrix44<T> toMatrix44() const IMATH_NOEXCEPT;
+
+    /// Return the logarithm of the quaterion
+    IMATH_HOSTDEVICE Quat<T> log() const IMATH_NOEXCEPT;
+
+    /// Return the exponent of the quaterion
+    IMATH_HOSTDEVICE Quat<T> exp() const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Utility Methods
+    
+    /// Invert in place: this = 1 / this.
+    /// @return const reference to this.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T>& invert() IMATH_NOEXCEPT;
+
+    /// Return 1/this, leaving this unchanged.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T> inverse() const IMATH_NOEXCEPT;
+
+    /// Normalize in place
+    /// @return const reference to this.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T>& normalize() IMATH_NOEXCEPT;
+    
+    /// Return a normalized quaternion, leaving this unmodified.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T> normalized() const IMATH_NOEXCEPT;
+
+    /// Rotate the given point by the quaterion.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3<T> rotateVector (const Vec3<T>& original) const IMATH_NOEXCEPT;
+
+    /// Return the Euclidean inner product.
+    IMATH_HOSTDEVICE constexpr T euclideanInnerProduct (const Quat<T>& q) const IMATH_NOEXCEPT;
+
+    /// Set the quaterion to be a rotation around the given axis by the
+    /// given angle.
+    /// @return const reference to this.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T>& setAxisAngle (const Vec3<T>& axis, T radians) IMATH_NOEXCEPT;
+
+    /// Set the quaternion to be a rotation that transforms the
+    /// direction vector `fromDirection` to `toDirection`
+    /// @return const reference to this.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T>&
+    setRotation (const Vec3<T>& fromDirection, const Vec3<T>& toDirection) IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// The base type: In templates that accept a parameter `V`, you
+    /// can refer to `T` as `V::BaseType`
+    typedef T BaseType;
+
+  private:
+    IMATH_HOSTDEVICE void setRotationInternal (const Vec3<T>& f0, const Vec3<T>& t0, Quat<T>& q) IMATH_NOEXCEPT;
+};
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T> slerp (const Quat<T>& q1, const Quat<T>& q2, T t) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T> slerpShortestArc (const Quat<T>& q1, const Quat<T>& q2, T t) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T>
+squad (const Quat<T>& q1, const Quat<T>& q2, const Quat<T>& qa, const Quat<T>& qb, T t) IMATH_NOEXCEPT;
+
+///
+/// From advanced Animation and Rendering Techniques by Watt and Watt,
+/// Page 366:
+///
+/// computing the inner quadrangle points (qa and qb) to guarantee
+/// tangent continuity.
+template <class T>
+IMATH_HOSTDEVICE void intermediate (const Quat<T>& q0,
+                   const Quat<T>& q1,
+                   const Quat<T>& q2,
+                   const Quat<T>& q3,
+                   Quat<T>& qa,
+                   Quat<T>& qb) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE constexpr Matrix33<T> operator* (const Matrix33<T>& M, const Quat<T>& q) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE constexpr Matrix33<T> operator* (const Quat<T>& q, const Matrix33<T>& M) IMATH_NOEXCEPT;
+
+template <class T> std::ostream& operator<< (std::ostream& o, const Quat<T>& q);
+
+template <class T>
+IMATH_HOSTDEVICE constexpr Quat<T> operator* (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE constexpr Quat<T> operator/ (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE constexpr Quat<T> operator/ (const Quat<T>& q, T t) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE constexpr Quat<T> operator* (const Quat<T>& q, T t) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE constexpr Quat<T> operator* (T t, const Quat<T>& q) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE constexpr Quat<T> operator+ (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE constexpr Quat<T> operator- (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE constexpr Quat<T> operator~ (const Quat<T>& q) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE constexpr Quat<T> operator- (const Quat<T>& q) IMATH_NOEXCEPT;
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3<T> operator* (const Vec3<T>& v, const Quat<T>& q) IMATH_NOEXCEPT;
+
+/// Quaternion of type float
+typedef Quat<float> Quatf;
+
+/// Quaternion of type double
+typedef Quat<double> Quatd;
+
+//---------------
+// Implementation
+//---------------
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>::Quat() IMATH_NOEXCEPT : r (1), v (0, 0, 0)
+{
+    // empty
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>::Quat (const Quat<S>& q) IMATH_NOEXCEPT : r (q.r), v (q.v)
+{
+    // empty
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>::Quat (T s, T i, T j, T k) IMATH_NOEXCEPT : r (s), v (i, j, k)
+{
+    // empty
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>::Quat (T s, Vec3<T> d) IMATH_NOEXCEPT : r (s), v (d)
+{
+    // empty
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>::Quat (const Quat<T>& q) IMATH_NOEXCEPT : r (q.r), v (q.v)
+{
+    // empty
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>
+Quat<T>::identity() IMATH_NOEXCEPT
+{
+    return Quat<T>();
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
+Quat<T>::operator= (const Quat<T>& q) IMATH_NOEXCEPT
+{
+    r = q.r;
+    v = q.v;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
+Quat<T>::operator*= (const Quat<T>& q) IMATH_NOEXCEPT
+{
+    T rtmp = r * q.r - (v ^ q.v);
+    v      = r * q.v + v * q.r + v % q.v;
+    r      = rtmp;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
+Quat<T>::operator*= (T t) IMATH_NOEXCEPT
+{
+    r *= t;
+    v *= t;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
+Quat<T>::operator/= (const Quat<T>& q) IMATH_NOEXCEPT
+{
+    *this = *this * q.inverse();
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
+Quat<T>::operator/= (T t) IMATH_NOEXCEPT
+{
+    r /= t;
+    v /= t;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
+Quat<T>::operator+= (const Quat<T>& q) IMATH_NOEXCEPT
+{
+    r += q.r;
+    v += q.v;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
+Quat<T>::operator-= (const Quat<T>& q) IMATH_NOEXCEPT
+{
+    r -= q.r;
+    v -= q.v;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T&
+Quat<T>::operator[] (int index) IMATH_NOEXCEPT
+{
+    return index ? v[index - 1] : r;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Quat<T>::operator[] (int index) const IMATH_NOEXCEPT
+{
+    return index ? v[index - 1] : r;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Quat<T>::operator== (const Quat<S>& q) const IMATH_NOEXCEPT
+{
+    return r == q.r && v == q.v;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Quat<T>::operator!= (const Quat<S>& q) const IMATH_NOEXCEPT
+{
+    return r != q.r || v != q.v;
+}
+
+/// 4D dot product
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+operator^ (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
+{
+    return q1.r * q2.r + (q1.v ^ q2.v);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Quat<T>::length() const IMATH_NOEXCEPT
+{
+    return std::sqrt (r * r + (v ^ v));
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>&
+Quat<T>::normalize() IMATH_NOEXCEPT
+{
+    if (T l = length())
+    {
+        r /= l;
+        v /= l;
+    }
+    else
+    {
+        r = 1;
+        v = Vec3<T> (0);
+    }
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
+Quat<T>::normalized() const IMATH_NOEXCEPT
+{
+    if (T l = length())
+        return Quat (r / l, v / l);
+
+    return Quat();
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
+Quat<T>::inverse() const IMATH_NOEXCEPT
+{
+    //
+    // 1    Q*
+    // - = ----   where Q* is conjugate (operator~)
+    // Q   Q* Q   and (Q* Q) == Q ^ Q (4D dot)
+    //
+
+    T qdot = *this ^ *this;
+    return Quat (r / qdot, -v / qdot);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>&
+Quat<T>::invert() IMATH_NOEXCEPT
+{
+    T qdot = (*this) ^ (*this);
+    r /= qdot;
+    v = -v / qdot;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Vec3<T>
+Quat<T>::rotateVector (const Vec3<T>& original) const IMATH_NOEXCEPT
+{
+    //
+    // Given a vector p and a quaternion q (aka this),
+    // calculate p' = qpq*
+    //
+    // Assumes unit quaternions (because non-unit
+    // quaternions cannot be used to rotate vectors
+    // anyway).
+    //
+
+    Quat<T> vec (0, original); // temporarily promote grade of original
+    Quat<T> inv (*this);
+    inv.v *= -1; // unit multiplicative inverse
+    Quat<T> result = *this * vec * inv;
+    return result.v;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Quat<T>::euclideanInnerProduct (const Quat<T>& q) const IMATH_NOEXCEPT
+{
+    return r * q.r + v.x * q.v.x + v.y * q.v.y + v.z * q.v.z;
+}
+
+///
+/// Compute the angle between two quaternions,
+/// interpreting the quaternions as 4D vectors.
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+angle4D (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
+{
+    Quat<T> d = q1 - q2;
+    T lengthD = std::sqrt (d ^ d);
+
+    Quat<T> s = q1 + q2;
+    T lengthS = std::sqrt (s ^ s);
+
+    return 2 * std::atan2 (lengthD, lengthS);
+}
+
+///
+/// Spherical linear interpolation.
+/// Assumes q1 and q2 are normalized and that q1 != -q2.
+///
+/// This method does *not* interpolate along the shortest
+/// arc between q1 and q2.  If you desire interpolation
+/// along the shortest arc, and q1^q2 is negative, then
+/// consider calling slerpShortestArc(), below, or flipping
+/// the second quaternion explicitly.
+///
+/// The implementation of squad() depends on a slerp()
+/// that interpolates as is, without the automatic
+/// flipping.
+///
+/// Don Hatch explains the method we use here on his
+/// web page, The Right Way to Calculate Stuff, at
+/// http://www.plunk.org/~hatch/rightway.php
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
+slerp (const Quat<T>& q1, const Quat<T>& q2, T t) IMATH_NOEXCEPT
+{
+    T a = angle4D (q1, q2);
+    T s = 1 - t;
+
+    Quat<T> q = sinx_over_x (s * a) / sinx_over_x (a) * s * q1 +
+                sinx_over_x (t * a) / sinx_over_x (a) * t * q2;
+
+    return q.normalized();
+}
+
+///
+/// Spherical linear interpolation along the shortest
+/// arc from q1 to either q2 or -q2, whichever is closer.
+/// Assumes q1 and q2 are unit quaternions.
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
+slerpShortestArc (const Quat<T>& q1, const Quat<T>& q2, T t) IMATH_NOEXCEPT
+{
+    if ((q1 ^ q2) >= 0)
+        return slerp (q1, q2, t);
+    else
+        return slerp (q1, -q2, t);
+}
+
+///
+/// Spherical Cubic Spline Interpolation - from Advanced Animation and
+/// Rendering Techniques by Watt and Watt, Page 366:
+///
+/// A spherical curve is constructed using three spherical linear
+/// interpolations of a quadrangle of unit quaternions: q1, qa, qb,
+/// q2.  Given a set of quaternion keys: q0, q1, q2, q3, this routine
+/// does the interpolation between q1 and q2 by constructing two
+/// intermediate quaternions: qa and qb. The qa and qb are computed by
+/// the intermediate function to guarantee the continuity of tangents
+/// across adjacent cubic segments. The qa represents in-tangent for
+/// q1 and the qb represents the out-tangent for q2.
+///
+/// The q1 q2 is the cubic segment being interpolated.
+///
+/// The q0 is from the previous adjacent segment and q3 is from the
+/// next adjacent segment. The q0 and q3 are used in computing qa and
+/// qb.
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
+spline (const Quat<T>& q0, const Quat<T>& q1, const Quat<T>& q2, const Quat<T>& q3, T t) IMATH_NOEXCEPT
+{
+    Quat<T> qa     = intermediate (q0, q1, q2);
+    Quat<T> qb     = intermediate (q1, q2, q3);
+    Quat<T> result = squad (q1, qa, qb, q2, t);
+
+    return result;
+}
+
+///
+/// Spherical Quadrangle Interpolation - from Advanced Animation and
+/// Rendering Techniques by Watt and Watt, Page 366:
+///
+/// It constructs a spherical cubic interpolation as a series of three
+/// spherical linear interpolations of a quadrangle of unit
+/// quaternions.
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
+squad (const Quat<T>& q1, const Quat<T>& qa, const Quat<T>& qb, const Quat<T>& q2, T t) IMATH_NOEXCEPT
+{
+    Quat<T> r1     = slerp (q1, q2, t);
+    Quat<T> r2     = slerp (qa, qb, t);
+    Quat<T> result = slerp (r1, r2, 2 * t * (1 - t));
+
+    return result;
+}
+
+/// Compute the intermediate point between three quaternions `q0`, `q1`,
+/// and `q2`.
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
+intermediate (const Quat<T>& q0, const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
+{
+    Quat<T> q1inv = q1.inverse();
+    Quat<T> c1    = q1inv * q2;
+    Quat<T> c2    = q1inv * q0;
+    Quat<T> c3    = (T) (-0.25) * (c2.log() + c1.log());
+    Quat<T> qa    = q1 * c3.exp();
+    qa.normalize();
+    return qa;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Quat<T>
+Quat<T>::log() const IMATH_NOEXCEPT
+{
+    //
+    // For unit quaternion, from Advanced Animation and
+    // Rendering Techniques by Watt and Watt, Page 366:
+    //
+
+    T theta = std::acos (std::min (r, (T) 1.0));
+
+    if (theta == 0)
+        return Quat<T> (0, v);
+
+    T sintheta = std::sin (theta);
+
+    T k;
+    if (std::abs(sintheta) < 1 && std::abs(theta) >= std::numeric_limits<T>::max() * std::abs(sintheta))
+        k = 1;
+    else
+        k = theta / sintheta;
+
+    return Quat<T> ((T) 0, v.x * k, v.y * k, v.z * k);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Quat<T>
+Quat<T>::exp() const IMATH_NOEXCEPT
+{
+    //
+    // For pure quaternion (zero scalar part):
+    // from Advanced Animation and Rendering
+    // Techniques by Watt and Watt, Page 366:
+    //
+
+    T theta    = v.length();
+    T sintheta = std::sin (theta);
+
+    T k;
+    if (abs (theta) < 1 && abs (sintheta) >= std::numeric_limits<T>::max() * abs (theta))
+        k = 1;
+    else
+        k = sintheta / theta;
+
+    T costheta = std::cos (theta);
+
+    return Quat<T> (costheta, v.x * k, v.y * k, v.z * k);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Quat<T>::angle() const IMATH_NOEXCEPT
+{
+    return 2 * std::atan2 (v.length(), r);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Quat<T>::axis() const IMATH_NOEXCEPT
+{
+    return v.normalized();
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>&
+Quat<T>::setAxisAngle (const Vec3<T>& axis, T radians) IMATH_NOEXCEPT
+{
+    r = std::cos (radians / 2);
+    v = axis.normalized() * std::sin (radians / 2);
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>&
+Quat<T>::setRotation (const Vec3<T>& from, const Vec3<T>& to) IMATH_NOEXCEPT
+{
+    //
+    // Create a quaternion that rotates vector from into vector to,
+    // such that the rotation is around an axis that is the cross
+    // product of from and to.
+    //
+    // This function calls function setRotationInternal(), which is
+    // numerically accurate only for rotation angles that are not much
+    // greater than pi/2.  In order to achieve good accuracy for angles
+    // greater than pi/2, we split large angles in half, and rotate in
+    // two steps.
+    //
+
+    //
+    // Normalize from and to, yielding f0 and t0.
+    //
+
+    Vec3<T> f0 = from.normalized();
+    Vec3<T> t0 = to.normalized();
+
+    if ((f0 ^ t0) >= 0)
+    {
+        //
+        // The rotation angle is less than or equal to pi/2.
+        //
+
+        setRotationInternal (f0, t0, *this);
+    }
+    else
+    {
+        //
+        // The angle is greater than pi/2.  After computing h0,
+        // which is halfway between f0 and t0, we rotate first
+        // from f0 to h0, then from h0 to t0.
+        //
+
+        Vec3<T> h0 = (f0 + t0).normalized();
+
+        if ((h0 ^ h0) != 0)
+        {
+            setRotationInternal (f0, h0, *this);
+
+            Quat<T> q;
+            setRotationInternal (h0, t0, q);
+
+            *this *= q;
+        }
+        else
+        {
+            //
+            // f0 and t0 point in exactly opposite directions.
+            // Pick an arbitrary axis that is orthogonal to f0,
+            // and rotate by pi.
+            //
+
+            r = T (0);
+
+            Vec3<T> f02 = f0 * f0;
+
+            if (f02.x <= f02.y && f02.x <= f02.z)
+                v = (f0 % Vec3<T> (1, 0, 0)).normalized();
+            else if (f02.y <= f02.z)
+                v = (f0 % Vec3<T> (0, 1, 0)).normalized();
+            else
+                v = (f0 % Vec3<T> (0, 0, 1)).normalized();
+        }
+    }
+
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Quat<T>::setRotationInternal (const Vec3<T>& f0, const Vec3<T>& t0, Quat<T>& q) IMATH_NOEXCEPT
+{
+    //
+    // The following is equivalent to setAxisAngle(n,2*phi),
+    // where the rotation axis, n, is orthogonal to the f0 and
+    // t0 vectors, and 2*phi is the angle between f0 and t0.
+    //
+    // This function is called by setRotation(), above; it assumes
+    // that f0 and t0 are normalized and that the angle between
+    // them is not much greater than pi/2.  This function becomes
+    // numerically inaccurate if f0 and t0 point into nearly
+    // opposite directions.
+    //
+
+    //
+    // Find a normalized vector, h0, that is halfway between f0 and t0.
+    // The angle between f0 and h0 is phi.
+    //
+
+    Vec3<T> h0 = (f0 + t0).normalized();
+
+    //
+    // Store the rotation axis and rotation angle.
+    //
+
+    q.r = f0 ^ h0; //  f0 ^ h0 == cos (phi)
+    q.v = f0 % h0; // (f0 % h0).length() == sin (phi)
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix33<T>
+Quat<T>::toMatrix33() const IMATH_NOEXCEPT
+{
+    return Matrix33<T> (1 - 2 * (v.y * v.y + v.z * v.z),
+                        2 * (v.x * v.y + v.z * r),
+                        2 * (v.z * v.x - v.y * r),
+
+                        2 * (v.x * v.y - v.z * r),
+                        1 - 2 * (v.z * v.z + v.x * v.x),
+                        2 * (v.y * v.z + v.x * r),
+
+                        2 * (v.z * v.x + v.y * r),
+                        2 * (v.y * v.z - v.x * r),
+                        1 - 2 * (v.y * v.y + v.x * v.x));
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix44<T>
+Quat<T>::toMatrix44() const IMATH_NOEXCEPT
+{
+    return Matrix44<T> (1 - 2 * (v.y * v.y + v.z * v.z),
+                        2 * (v.x * v.y + v.z * r),
+                        2 * (v.z * v.x - v.y * r),
+                        0,
+                        2 * (v.x * v.y - v.z * r),
+                        1 - 2 * (v.z * v.z + v.x * v.x),
+                        2 * (v.y * v.z + v.x * r),
+                        0,
+                        2 * (v.z * v.x + v.y * r),
+                        2 * (v.y * v.z - v.x * r),
+                        1 - 2 * (v.y * v.y + v.x * v.x),
+                        0,
+                        0,
+                        0,
+                        0,
+                        1);
+}
+
+/// Transform the quaternion by the matrix
+/// @return M * q
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix33<T>
+operator* (const Matrix33<T>& M, const Quat<T>& q) IMATH_NOEXCEPT
+{
+    return M * q.toMatrix33();
+}
+
+/// Transform the matrix by the quaterion:
+/// @return q * M
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Matrix33<T>
+operator* (const Quat<T>& q, const Matrix33<T>& M) IMATH_NOEXCEPT
+{
+    return q.toMatrix33() * M;
+}
+
+/// Stream output as "(r x y z)"
+template <class T>
+std::ostream&
+operator<< (std::ostream& o, const Quat<T>& q)
+{
+    return o << "(" << q.r << " " << q.v.x << " " << q.v.y << " " << q.v.z << ")";
+}
+
+/// Quaterion multiplication
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>
+operator* (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
+{
+    return Quat<T> (q1.r * q2.r - (q1.v ^ q2.v), q1.r * q2.v + q1.v * q2.r + q1.v % q2.v);
+}
+
+/// Quaterion division
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>
+operator/ (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
+{
+    return q1 * q2.inverse();
+}
+
+/// Quaterion division
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>
+operator/ (const Quat<T>& q, T t) IMATH_NOEXCEPT
+{
+    return Quat<T> (q.r / t, q.v / t);
+}
+
+/// Quaterion*scalar multiplication
+/// @return q * t
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>
+operator* (const Quat<T>& q, T t) IMATH_NOEXCEPT
+{
+    return Quat<T> (q.r * t, q.v * t);
+}
+
+/// Quaterion*scalar multiplication
+/// @return q * t
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>
+operator* (T t, const Quat<T>& q) IMATH_NOEXCEPT
+{
+    return Quat<T> (q.r * t, q.v * t);
+}
+
+/// Quaterion addition
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>
+operator+ (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
+{
+    return Quat<T> (q1.r + q2.r, q1.v + q2.v);
+}
+
+/// Quaterion subtraction
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>
+operator- (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
+{
+    return Quat<T> (q1.r - q2.r, q1.v - q2.v);
+}
+
+/// Compute the conjugate
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>
+operator~ (const Quat<T>& q) IMATH_NOEXCEPT
+{
+    return Quat<T> (q.r, -q.v);
+}
+
+/// Negate the quaterion
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Quat<T>
+operator- (const Quat<T>& q) IMATH_NOEXCEPT
+{
+    return Quat<T> (-q.r, -q.v);
+}
+
+/// Quaterion*vector multiplcation
+/// @return v * q
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Vec3<T>
+operator* (const Vec3<T>& v, const Quat<T>& q) IMATH_NOEXCEPT
+{
+    Vec3<T> a = q.v % v;
+    Vec3<T> b = q.v % a;
+    return v + T (2) * (q.r * a + b);
+}
+
+#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
+#    pragma warning(pop)
+#endif
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHQUAT_H
diff --git a/src/Imath/ImathRandom.cpp b/src/Imath/ImathRandom.cpp
new file mode 100644 (file)
index 0000000..87c47cf
--- /dev/null
@@ -0,0 +1,170 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//-----------------------------------------------------------------------------
+//
+//     Routines that generate pseudo-random numbers compatible
+//     with the standard erand48(), nrand48(), etc. functions.
+//
+//-----------------------------------------------------------------------------
+
+#include "ImathRandom.h"
+#include <cstdint>
+
+IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER
+namespace
+{
+
+//
+// Static state used by Imath::drand48(), Imath::lrand48() and Imath::srand48()
+//
+
+unsigned short staticState[3] = { 0, 0, 0 };
+
+void
+rand48Next (unsigned short state[3])
+{
+    //
+    // drand48() and friends are all based on a linear congruential
+    // sequence,
+    //
+    //   x[n+1] = (a * x[n] + c) % m,
+    //
+    // where a and c are as specified below, and m == (1 << 48)
+    //
+
+    static const uint64_t a = uint64_t (0x5deece66dLL);
+    static const uint64_t c = uint64_t (0xbLL);
+
+    //
+    // Assemble the 48-bit value x[n] from the
+    // three 16-bit values stored in state.
+    //
+
+    // clang-format off
+    uint64_t x = (uint64_t (state[2]) << 32) |
+             (uint64_t (state[1]) << 16) |
+              uint64_t (state[0]);
+    // clang-format on
+
+    //
+    // Compute x[n+1], except for the "modulo m" part.
+    //
+
+    x = a * x + c;
+
+    //
+    // Disassemble the 48 least significant bits of x[n+1] into
+    // three 16-bit values.  Discard the 16 most significant bits;
+    // this takes care of the "modulo m" operation.
+    //
+    // We assume that sizeof (unsigned short) == 2.
+    //
+
+    state[2] = (unsigned short) (x >> 32);
+    state[1] = (unsigned short) (x >> 16);
+    state[0] = (unsigned short) (x);
+}
+
+} // namespace
+
+///
+/// Generate double-precision floating-point values between 0.0 and 1.0:
+///
+/// The exponent is set to 0x3ff, which indicates a value greater
+/// than or equal to 1.0, and less than 2.0.  The 48 most significant
+/// bits of the significand (mantissa) are filled with pseudo-random
+/// bits generated by rand48Next().  The remaining 4 bits are a copy
+/// of the 4 most significant bits of the significand.  This results
+/// in bit patterns between 0x3ff0000000000000 and 0x3fffffffffffffff,
+/// which correspond to uniformly distributed floating-point values
+/// between 1.0 and 1.99999999999999978.  Subtracting 1.0 from those
+/// values produces numbers between 0.0 and 0.99999999999999978, that
+/// is, between 0.0 and 1.0-DBL_EPSILON.
+double
+erand48 (unsigned short state[3])
+{
+    rand48Next (state);
+
+    union
+    {
+        double d;
+        uint64_t i;
+    } u;
+
+    // clang-format off
+    u.i = (uint64_t (0x3ff)    << 52) |        // sign and exponent
+         (uint64_t (state[2]) << 36) | // significand
+         (uint64_t (state[1]) << 20) |
+         (uint64_t (state[0]) <<  4) |
+         (uint64_t (state[2]) >> 12);
+    // clang-format on
+
+    return u.d - 1;
+}
+
+/// Return erand48()
+double
+drand48()
+{
+    return IMATH_INTERNAL_NAMESPACE::erand48 (staticState);
+}
+
+/// Generate uniformly distributed integers between 0 and 0x7fffffff.
+long int
+nrand48 (unsigned short state[3])
+{
+    rand48Next (state);
+
+    // clang-format off
+    return ((long int) (state[2]) << 15) |
+          ((long int) (state[1]) >>  1);
+    // clang-format on
+}
+
+/// Return nrand48()
+long int
+lrand48()
+{
+    return IMATH_INTERNAL_NAMESPACE::nrand48 (staticState);
+}
+
+void
+srand48 (long int seed)
+{
+    staticState[2] = (unsigned short) (seed >> 16);
+    staticState[1] = (unsigned short) (seed);
+    staticState[0] = 0x330e;
+}
+
+float
+Rand32::nextf()
+{
+    //
+    // Generate single-precision floating-point values between 0.0 and 1.0:
+    //
+    // The exponent is set to 0x7f, which indicates a value greater than
+    // or equal to 1.0, and less than 2.0.  The 23 bits of the significand
+    // (mantissa) are filled with pseudo-random bits generated by
+    // Rand32::next().  This results in in bit patterns between 0x3f800000
+    // and 0x3fffffff, which correspond to uniformly distributed floating-
+    // point values between 1.0 and 1.99999988.  Subtracting 1.0 from
+    // those values produces numbers between 0.0 and 0.99999988, that is,
+    // between 0.0 and 1.0-FLT_EPSILON.
+    //
+
+    next();
+
+    union
+    {
+        float f;
+        unsigned int i;
+    } u;
+
+    u.i = 0x3f800000 | (_state & 0x7fffff);
+    return u.f - 1;
+}
+
+IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT
diff --git a/src/Imath/ImathRandom.h b/src/Imath/ImathRandom.h
new file mode 100644 (file)
index 0000000..5dce710
--- /dev/null
@@ -0,0 +1,261 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Generators for uniformly distributed pseudo-random numbers and
+// functions that use those generators to generate numbers with
+// non-uniform distributions
+//
+// Note: class Rand48() calls erand48() and nrand48(), which are not
+// available on all operating systems.  For compatibility we include
+// our own versions of erand48() and nrand48().  Our functions
+// have been reverse-engineered from the corresponding Unix/Linux
+// man page.
+//
+
+#ifndef INCLUDED_IMATHRANDOM_H
+#define INCLUDED_IMATHRANDOM_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+/// Fast random-number generator that generates
+/// a uniformly distributed sequence with a period
+/// length of 2^32.
+class Rand32
+{
+  public:
+
+    /// Constructor, given a seed
+    IMATH_HOSTDEVICE Rand32 (unsigned long int seed = 0);
+
+    /// Re-initialize with a given seed
+    IMATH_HOSTDEVICE void init (unsigned long int seed);
+
+    /// Get the next value in the sequence (range: [false, true])
+    IMATH_HOSTDEVICE bool nextb();
+
+    /// Get the next value in the sequence (range: [0 ... 0xffffffff])
+    IMATH_HOSTDEVICE unsigned long int nexti();
+
+    /// Get the next value in the sequence (range: [0 ... 1[)
+    IMATH_HOSTDEVICE IMATH_EXPORT float nextf ();
+
+    /// Get the next value in the sequence (range [rangeMin ... rangeMax[)
+    IMATH_HOSTDEVICE float nextf (float rangeMin, float rangeMax);
+
+  private:
+    IMATH_HOSTDEVICE void next();
+
+    unsigned long int _state;
+};
+
+/// Random-number generator based on the C Standard Library
+/// functions erand48(), nrand48() & company; generates a
+/// uniformly distributed sequence.
+class Rand48
+{
+  public:
+
+    /// Constructor
+    IMATH_HOSTDEVICE Rand48 (unsigned long int seed = 0);
+
+    /// Re-initialize with a given seed
+    IMATH_HOSTDEVICE void init (unsigned long int seed);
+
+    /// Get the next value in the sequence (range: [false, true])
+    IMATH_HOSTDEVICE bool nextb();
+
+    /// Get the next value in the sequence (range: [0 ... 0x7fffffff])
+    IMATH_HOSTDEVICE long int nexti();
+
+    /// Get the next value in the sequence (range: [0 ... 1[)
+    IMATH_HOSTDEVICE double nextf();
+
+    /// Get the next value in the sequence (range [rangeMin ... rangeMax[)
+    IMATH_HOSTDEVICE double nextf (double rangeMin, double rangeMax);
+
+  private:
+    unsigned short int _state[3];
+};
+
+/// Return random points uniformly distributed in a sphere with
+/// radius 1 around the origin (distance from origin <= 1).
+template <class Vec, class Rand> IMATH_HOSTDEVICE Vec solidSphereRand (Rand& rand);
+
+/// Return random points uniformly distributed on the surface of
+/// a sphere with radius 1 around the origin.
+template <class Vec, class Rand> IMATH_HOSTDEVICE Vec hollowSphereRand (Rand& rand);
+
+/// Return random numbers with a normal (Gaussian)
+/// distribution with zero mean and unit variance.
+template <class Rand> IMATH_HOSTDEVICE float gaussRand (Rand& rand);
+
+/// Return random points whose distance from the origin
+/// has a normal (Gaussian) distribution with zero mean
+/// and unit variance.
+template <class Vec, class Rand> IMATH_HOSTDEVICE Vec gaussSphereRand (Rand& rand);
+
+//---------------------------------
+// erand48(), nrand48() and friends
+//---------------------------------
+
+/// @cond Doxygen_Suppress
+IMATH_HOSTDEVICE IMATH_EXPORT double erand48 (unsigned short state[3]);
+IMATH_HOSTDEVICE IMATH_EXPORT double drand48();
+IMATH_HOSTDEVICE IMATH_EXPORT long int nrand48 (unsigned short state[3]);
+IMATH_HOSTDEVICE IMATH_EXPORT long int lrand48();
+IMATH_HOSTDEVICE IMATH_EXPORT void srand48 (long int seed);
+/// @endcond
+
+//---------------
+// Implementation
+//---------------
+
+IMATH_HOSTDEVICE inline void
+Rand32::init (unsigned long int seed)
+{
+    _state = (seed * 0xa5a573a5L) ^ 0x5a5a5a5aL;
+}
+
+IMATH_HOSTDEVICE inline Rand32::Rand32 (unsigned long int seed)
+{
+    init (seed);
+}
+
+IMATH_HOSTDEVICE inline void
+Rand32::next()
+{
+    _state = 1664525L * _state + 1013904223L;
+}
+
+IMATH_HOSTDEVICE inline bool
+Rand32::nextb()
+{
+    next();
+    // Return the 31st (most significant) bit, by and-ing with 2 ^ 31.
+    return !!(_state & 2147483648UL);
+}
+
+IMATH_HOSTDEVICE inline unsigned long int
+Rand32::nexti()
+{
+    next();
+    return _state & 0xffffffff;
+}
+
+IMATH_HOSTDEVICE inline float
+Rand32::nextf (float rangeMin, float rangeMax)
+{
+    float f = nextf();
+    return rangeMin * (1 - f) + rangeMax * f;
+}
+
+IMATH_HOSTDEVICE inline void
+Rand48::init (unsigned long int seed)
+{
+    seed = (seed * 0xa5a573a5L) ^ 0x5a5a5a5aL;
+
+    _state[0] = (unsigned short int) (seed & 0xFFFF);
+    _state[1] = (unsigned short int) ((seed >> 16) & 0xFFFF);
+    _state[2] = (unsigned short int) (seed & 0xFFFF);
+}
+
+IMATH_HOSTDEVICE inline Rand48::Rand48 (unsigned long int seed)
+{
+    init (seed);
+}
+
+IMATH_HOSTDEVICE inline bool
+Rand48::nextb()
+{
+    return nrand48 (_state) & 1;
+}
+
+IMATH_HOSTDEVICE inline long int
+Rand48::nexti()
+{
+    return nrand48 (_state);
+}
+
+IMATH_HOSTDEVICE inline double
+Rand48::nextf()
+{
+    return erand48 (_state);
+}
+
+IMATH_HOSTDEVICE inline double
+Rand48::nextf (double rangeMin, double rangeMax)
+{
+    double f = nextf();
+    return rangeMin * (1 - f) + rangeMax * f;
+}
+
+template <class Vec, class Rand>
+IMATH_HOSTDEVICE Vec
+solidSphereRand (Rand& rand)
+{
+    Vec v;
+
+    do
+    {
+        for (unsigned int i = 0; i < Vec::dimensions(); i++)
+            v[i] = (typename Vec::BaseType) rand.nextf (-1, 1);
+    } while (v.length2() > 1);
+
+    return v;
+}
+
+template <class Vec, class Rand>
+IMATH_HOSTDEVICE Vec
+hollowSphereRand (Rand& rand)
+{
+    Vec v;
+    typename Vec::BaseType length;
+
+    do
+    {
+        for (unsigned int i = 0; i < Vec::dimensions(); i++)
+            v[i] = (typename Vec::BaseType) rand.nextf (-1, 1);
+
+        length = v.length();
+    } while (length > 1 || length == 0);
+
+    return v / length;
+}
+
+template <class Rand>
+IMATH_HOSTDEVICE float
+gaussRand (Rand& rand)
+{
+    float x;       // Note: to avoid numerical problems with very small
+    float y;       // numbers, we make these variables singe-precision
+    float length2; // floats, but later we call the double-precision log()
+                   // and sqrt() functions instead of logf() and sqrtf().
+    do
+    {
+        x       = float (rand.nextf (-1, 1));
+        y       = float (rand.nextf (-1, 1));
+        length2 = x * x + y * y;
+    } while (length2 >= 1 || length2 == 0);
+
+    return x * sqrt (-2 * log (double (length2)) / length2);
+}
+
+template <class Vec, class Rand>
+IMATH_HOSTDEVICE Vec
+gaussSphereRand (Rand& rand)
+{
+    return hollowSphereRand<Vec> (rand) * gaussRand (rand);
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHRANDOM_H
diff --git a/src/Imath/ImathRoots.h b/src/Imath/ImathRoots.h
new file mode 100644 (file)
index 0000000..6632bec
--- /dev/null
@@ -0,0 +1,211 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Functions to solve linear, quadratic or cubic equations
+//
+// Note: It is possible that an equation has real solutions, but that
+// the solutions (or some intermediate result) are not representable.
+// In this case, either some of the solutions returned are invalid
+// (nan or infinity), or, if floating-point exceptions have been
+// enabled, an exception is thrown.
+//
+
+#ifndef INCLUDED_IMATHROOTS_H
+#define INCLUDED_IMATHROOTS_H
+
+#include "ImathMath.h"
+#include "ImathNamespace.h"
+#include <complex>
+
+/// @cond Doxygen_Suppress
+
+#ifdef __CUDACC__
+#    include <thrust/complex.h>
+#    define COMPLEX_NAMESPACE thrust
+#else
+#    define COMPLEX_NAMESPACE std
+#endif
+
+/// @endcond
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// Solve for x in the linear equation:
+///
+///     a * x + b == 0
+///
+/// @return 1 if the equation has a solution, 0 if there is no
+/// solution, and -1 if all real numbers are solutions.
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int solveLinear (T a, T b, T& x);
+
+///
+/// Solve for x in the quadratic equation:
+///
+///     a * x*x + b * x + c == 0
+///
+/// @return 2 if the equation has two solutions, 1 if the equation has
+/// a single solution, 0 if there is no solution, and -1 if all real
+/// numbers are solutions.
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int solveQuadratic (T a, T b, T c, T x[2]);
+template <class T>
+
+///
+/// Solve for x in the normalized cubic equation:
+///
+///     x*x*x + r * x*x + s * x + t == 0
+///
+/// The equation is solved using Cardano's Formula; even though only
+/// real solutions are produced, some intermediate results are complex
+/// (std::complex<T>).
+///
+/// @return 0 if there is no solution, and -1 if all real
+/// numbers are solutions, otherwise return the number of solutions.
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int solveNormalizedCubic (T r, T s, T t, T x[3]);
+
+///
+/// Solve for x in the cubic equation:
+///
+///     a * x*x*x + b * x*x + c * x + d == 0
+///
+/// The equation is solved using Cardano's Formula; even though only
+/// real solutions are produced, some intermediate results are complex
+/// (std::complex<T>).
+///
+/// @return 0 if there is no solution, and -1 if all real
+/// numbers are solutions, otherwise return the number of solutions.
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int solveCubic (T a, T b, T c, T d, T x[3]);
+
+//---------------
+// Implementation
+//---------------
+
+template <class T>
+IMATH_CONSTEXPR14 int
+solveLinear (T a, T b, T& x)
+{
+    if (a != 0)
+    {
+        x = -b / a;
+        return 1;
+    }
+    else if (b != 0)
+    {
+        return 0;
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+template <class T>
+IMATH_CONSTEXPR14 int
+solveQuadratic (T a, T b, T c, T x[2])
+{
+    if (a == 0)
+    {
+        return solveLinear (b, c, x[0]);
+    }
+    else
+    {
+        T D = b * b - 4 * a * c;
+
+        if (D > 0)
+        {
+            T s = std::sqrt (D);
+            T q = -(b + (b > 0 ? 1 : -1) * s) / T (2);
+
+            x[0] = q / a;
+            x[1] = c / q;
+            return 2;
+        }
+        if (D == 0)
+        {
+            x[0] = -b / (2 * a);
+            return 1;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+}
+
+template <class T>
+IMATH_CONSTEXPR14 int
+solveNormalizedCubic (T r, T s, T t, T x[3])
+{
+    T p  = (3 * s - r * r) / 3;
+    T q  = 2 * r * r * r / 27 - r * s / 3 + t;
+    T p3 = p / 3;
+    T q2 = q / 2;
+    T D  = p3 * p3 * p3 + q2 * q2;
+
+    if (D == 0 && p3 == 0)
+    {
+        x[0] = -r / 3;
+        x[1] = -r / 3;
+        x[2] = -r / 3;
+        return 1;
+    }
+
+    if (D > 0)
+    {
+        auto real_root = [] (T a, T x) -> T {
+            T sign = std::copysign(T(1), a);
+            return sign * std::pow (sign * a, T (1) / x);
+        };
+
+        T u = real_root (-q / 2 + std::sqrt (D), 3);
+        T v = -p / (T (3) * u);
+
+        x[0] = u + v - r / 3;
+        return 1;
+    }
+
+    namespace CN     = COMPLEX_NAMESPACE;
+    CN::complex<T> u = CN::pow (-q / 2 + CN::sqrt (CN::complex<T> (D)), T (1) / T (3));
+    CN::complex<T> v = -p / (T (3) * u);
+
+    const T sqrt3 = T (1.73205080756887729352744634150587); // enough digits
+                                                            // for long double
+    CN::complex<T> y0 (u + v);
+    CN::complex<T> y1 (-(u + v) / T (2) + (u - v) / T (2) * CN::complex<T> (0, sqrt3));
+    CN::complex<T> y2 (-(u + v) / T (2) - (u - v) / T (2) * CN::complex<T> (0, sqrt3));
+
+    if (D == 0)
+    {
+        x[0] = y0.real() - r / 3;
+        x[1] = y1.real() - r / 3;
+        return 2;
+    }
+    else
+    {
+        x[0] = y0.real() - r / 3;
+        x[1] = y1.real() - r / 3;
+        x[2] = y2.real() - r / 3;
+        return 3;
+    }
+}
+
+template <class T>
+IMATH_CONSTEXPR14 int
+solveCubic (T a, T b, T c, T d, T x[3])
+{
+    if (a == 0)
+    {
+        return solveQuadratic (b, c, d, x);
+    }
+    else
+    {
+        return solveNormalizedCubic (b / a, c / a, d / a, x);
+    }
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHROOTS_H
diff --git a/src/Imath/ImathShear.h b/src/Imath/ImathShear.h
new file mode 100644 (file)
index 0000000..994ed5a
--- /dev/null
@@ -0,0 +1,689 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// A representation of a shear transformation
+//
+
+#ifndef INCLUDED_IMATHSHEAR_H
+#define INCLUDED_IMATHSHEAR_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include "ImathMath.h"
+#include "ImathVec.h"
+#include <iostream>
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// Shear6 class template.
+///
+/// A shear matrix is technically defined as having a single nonzero
+/// off-diagonal element; more generally, a shear transformation is
+/// defined by those off-diagonal elements, so in 3D, that means there
+/// are 6 possible elements/coefficients:
+///
+///     | X' |   |  1  YX  ZX  0 |   | X |
+///     | Y' |   | XY   1  ZY  0 |   | Y |
+///     | Z' | = | XZ  YZ   1  0 | = | Z |
+///     | 1  |   |  0   0   0  1 |   | 1 |
+///
+///     X' =      X + YX * Y + ZX * Z
+///     Y' = YX * X +      Y + ZY * Z
+///     Z` = XZ * X + YZ * Y +      Z
+///
+/// See
+/// https://www.cs.drexel.edu/~david/Classes/CS430/Lectures/L-04_3DTransformations.6.pdf
+///
+/// Those variable elements correspond to the 6 values in a Shear6.
+/// So, looking at those equations, "Shear YX", for example, means
+/// that for any point transformed by that matrix, its X values will
+/// have some of their Y values added.  If you're talking
+/// about "Axis A has values from Axis B added to it", there are 6
+/// permutations for A and B (XY, XZ, YX, YZ, ZX, ZY).
+///
+/// Not that Maya has only three values, which represent the
+/// lower/upper (depending on column/row major) triangle of the
+/// matrix.  Houdini is the same as Maya (see
+/// https://www.sidefx.com/docs/houdini/props/obj.html) in this
+/// respect. 
+///
+/// There's another way to look at it. A general affine transformation
+/// in 3D has 12 degrees of freedom - 12 "available" elements in the
+/// 4x4 matrix since a single row/column must be (0,0,0,1).  If you
+/// add up the degrees of freedom from Maya:
+/// 
+/// - 3 translation
+/// - 3 rotation
+/// - 3 scale
+/// - 3 shear
+///
+/// You obviously get the full 12.  So technically, the Shear6 option
+/// of having all 6 shear options is overkill; Imath/Shear6 has 15
+/// values for a 12-degree-of-freedom transformation.  This means that
+/// any nonzero values in those last 3 shear coefficients can be
+/// represented in those standard 12 degrees of freedom.  Here's a
+/// python example of how to do that:
+///
+/// 
+///     >>> import imath
+///     >>> M = imath.M44f()
+///     >>> s = imath.V3f()
+///     >>> h = imath.V3f()
+///     >>> r = imath.V3f()
+///     >>> t = imath.V3f()
+///     # Use Shear.YX (index 3), which is an "extra" shear value
+///     >>> M.setShear((0,0,0,1,0,0))
+///     M44f((1, 1, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))
+///     >>> M.extractSHRT(s, h, r, t)
+///     1
+///     >>> s
+///     V3f(1.41421354, 0.707106769, 1)
+///     >>> h
+///     V3f(1, 0, 0)
+///     >>> r
+///     V3f(0, -0, 0.785398185)
+///     >>> t
+///     V3f(0, 0, 0)
+///   
+/// That shows how to decompose a transform matrix with one of those
+/// "extra" shear coefficients into those standard 12 degrees of
+/// freedom.  But it's not necessarily intuitive; in this case, a
+/// single non-zero shear coefficient resulted in a transform that has
+/// non-uniform scale, a single "standard" shear value, and some
+/// rotation.
+///
+/// So, it would seem that any transform with those extra shear
+/// values set could be translated into Maya to produce the exact same
+/// transformation matrix; but doing this is probably pretty
+/// undesirable, since the result would have some surprising values on
+/// the other transformation attributes, despite being technically
+/// correct.
+///
+/// This usage of "degrees of freedom" is a bit hand-wavey here;
+/// having a total of 12 inputs into the construction of a standard
+/// transformation matrix doesn't necessarily mean that the matrix has
+/// 12 true degrees of freedom, but the standard
+/// translation/rotation/scale/shear matrices have the right
+/// construction to ensure that.  
+/// 
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Shear6
+{
+  public:
+
+    /// @{
+    /// @name Direct access to members
+
+    T xy, xz, yz, yx, zx, zy;
+
+    /// @}
+
+    /// Element access
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T& operator[] (int i);
+
+    /// Element access
+    IMATH_HOSTDEVICE constexpr const T& operator[] (int i) const;
+
+    /// @{
+    /// @name Constructors and Assignment
+
+    /// Initialize to 0
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6();
+    
+    /// Initialize to the given XY, XZ, YZ values
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (T XY, T XZ, T YZ);
+
+    /// Initialize to the given XY, XZ, YZ values held in (v.x, v.y, v.z)
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (const Vec3<T>& v);
+
+    /// Initialize to the given XY, XZ, YZ values held in (v.x, v.y, v.z)
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (const Vec3<S>& v);
+
+    /// Initialize to the given (XY XZ YZ YX ZX ZY) values
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (T XY,              
+                                               T XZ,
+                                               T YZ,
+                                               T YX,
+                                               T ZX,
+                                               T ZY);
+
+    /// Copy constructor
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (const Shear6& h);
+
+    /// Construct from a Shear6 object of another base type
+    template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (const Shear6<S>& h);
+
+    /// Assignment
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator= (const Shear6& h);
+
+    /// Assignment from vector
+    template <class S>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator= (const Vec3<S>& v);
+
+    /// Destructor
+    ~Shear6() = default;
+
+    /// @}
+    
+    /// @{
+    /// @name Compatibility with Sb
+
+    /// Set the value
+    template <class S> IMATH_HOSTDEVICE void setValue (S XY, S XZ, S YZ, S YX, S ZX, S ZY);
+
+    /// Set the value
+    template <class S> IMATH_HOSTDEVICE void setValue (const Shear6<S>& h);
+
+    /// Return the values
+    template <class S>
+    IMATH_HOSTDEVICE void getValue (S& XY, S& XZ, S& YZ, S& YX, S& ZX, S& ZY) const;
+
+    /// Return the value in `h`
+    template <class S> IMATH_HOSTDEVICE void getValue (Shear6<S>& h) const;
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE T* getValue();
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE const T* getValue() const;
+
+    /// @}
+
+    /// @{
+    /// @name Arithmetic and Comparison
+    
+    /// Equality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator== (const Shear6<S>& h) const;
+
+    /// Inequality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator!= (const Shear6<S>& h) const;
+
+    /// Compare two shears and test if they are "approximately equal":
+    /// @return True if the coefficients of this and h are the same with
+    ///        an absolute error of no more than e, i.e., for all i
+    ///     abs (this[i] - h[i]) <= e
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithAbsError (const Shear6<T>& h, T e) const;
+
+    /// Compare two shears and test if they are "approximately equal":
+    /// @return True if the coefficients of this and h are the same with
+    /// a relative error of no more than e, i.e., for all i
+    ///     abs (this[i] - h[i]) <= e * abs (this[i])
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithRelError (const Shear6<T>& h, T e) const;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator+= (const Shear6& h);
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE constexpr Shear6 operator+ (const Shear6& h) const;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator-= (const Shear6& h);
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE constexpr Shear6 operator- (const Shear6& h) const;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE constexpr Shear6 operator-() const;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& negate();
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator*= (const Shear6& h);
+    /// Scalar multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator*= (T a);
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Shear6 operator* (const Shear6& h) const;
+
+    /// Scalar multiplication
+    IMATH_HOSTDEVICE constexpr Shear6 operator* (T a) const;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator/= (const Shear6& h);
+
+    /// Scalar division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator/= (T a);
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Shear6 operator/ (const Shear6& h) const;
+
+    /// Scalar division
+    IMATH_HOSTDEVICE constexpr Shear6 operator/ (T a) const;
+
+    /// @}
+    
+    /// @{
+    /// @name Numerical Limits
+    
+    /// Largest possible negative value
+    IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
+
+    /// Largest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
+
+    /// Smallest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
+
+    /// Smallest possible e for which 1+e != 1
+    IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
+
+    /// @}
+
+    /// Return the number of dimensions, i.e. 6
+    IMATH_HOSTDEVICE constexpr static unsigned int dimensions() { return 6; }
+
+    /// The base type: In templates that accept a parameter `V` (could
+    /// be a Color4), you can refer to `T` as `V::BaseType`
+    typedef T BaseType;
+};
+
+/// Stream output, as "(xy xz yz yx zx zy)"
+template <class T> std::ostream& operator<< (std::ostream& s, const Shear6<T>& h);
+
+/// Reverse multiplication: scalar * Shear6<T>
+template <class S, class T>
+IMATH_HOSTDEVICE constexpr Shear6<T> operator* (S a, const Shear6<T>& h);
+
+/// 3D shear of type float
+typedef Vec3<float> Shear3f;
+
+/// 3D shear of type double
+typedef Vec3<double> Shear3d;
+
+/// Shear6 of type float
+typedef Shear6<float> Shear6f;
+
+/// Shear6 of type double
+typedef Shear6<double> Shear6d;
+
+//-----------------------
+// Implementation of Shear6
+//-----------------------
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T&
+Shear6<T>::operator[] (int i)
+{
+    return (&xy)[i]; // NOSONAR - suppress SonarCloud bug report.
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline const T&
+Shear6<T>::operator[] (int i) const
+{
+    return (&xy)[i]; // NOSONAR - suppress SonarCloud bug report.
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6()
+{
+    xy = xz = yz = yx = zx = zy = 0;
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (T XY, T XZ, T YZ)
+{
+    xy = XY;
+    xz = XZ;
+    yz = YZ;
+    yx = 0;
+    zx = 0;
+    zy = 0;
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (const Vec3<T>& v)
+{
+    xy = v.x;
+    xz = v.y;
+    yz = v.z;
+    yx = 0;
+    zx = 0;
+    zy = 0;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (const Vec3<S>& v)
+{
+    xy = T (v.x);
+    xz = T (v.y);
+    yz = T (v.z);
+    yx = 0;
+    zx = 0;
+    zy = 0;
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (T XY, T XZ, T YZ, T YX, T ZX, T ZY)
+{
+    xy = XY;
+    xz = XZ;
+    yz = YZ;
+    yx = YX;
+    zx = ZX;
+    zy = ZY;
+}
+
+template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (const Shear6& h)
+{
+    xy = h.xy;
+    xz = h.xz;
+    yz = h.yz;
+    yx = h.yx;
+    zx = h.zx;
+    zy = h.zy;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (const Shear6<S>& h)
+{
+    xy = T (h.xy);
+    xz = T (h.xz);
+    yz = T (h.yz);
+    yx = T (h.yx);
+    zx = T (h.zx);
+    zy = T (h.zy);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
+Shear6<T>::operator= (const Shear6& h)
+{
+    xy = h.xy;
+    xz = h.xz;
+    yz = h.yz;
+    yx = h.yx;
+    zx = h.zx;
+    zy = h.zy;
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
+Shear6<T>::operator= (const Vec3<S>& v)
+{
+    xy = T (v.x);
+    xz = T (v.y);
+    yz = T (v.z);
+    yx = 0;
+    zx = 0;
+    zy = 0;
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Shear6<T>::setValue (S XY, S XZ, S YZ, S YX, S ZX, S ZY)
+{
+    xy = T (XY);
+    xz = T (XZ);
+    yz = T (YZ);
+    yx = T (YX);
+    zx = T (ZX);
+    zy = T (ZY);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Shear6<T>::setValue (const Shear6<S>& h)
+{
+    xy = T (h.xy);
+    xz = T (h.xz);
+    yz = T (h.yz);
+    yx = T (h.yx);
+    zx = T (h.zx);
+    zy = T (h.zy);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Shear6<T>::getValue (S& XY, S& XZ, S& YZ, S& YX, S& ZX, S& ZY) const
+{
+    XY = S (xy);
+    XZ = S (xz);
+    YZ = S (yz);
+    YX = S (yx);
+    ZX = S (zx);
+    ZY = S (zy);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Shear6<T>::getValue (Shear6<S>& h) const
+{
+    h.xy = S (xy);
+    h.xz = S (xz);
+    h.yz = S (yz);
+    h.yx = S (yx);
+    h.zx = S (zx);
+    h.zy = S (zy);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline T*
+Shear6<T>::getValue()
+{
+    return (T*) &xy;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const T*
+Shear6<T>::getValue() const
+{
+    return (const T*) &xy;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Shear6<T>::operator== (const Shear6<S>& h) const
+{
+    return xy == h.xy && xz == h.xz && yz == h.yz && yx == h.yx && zx == h.zx && zy == h.zy;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Shear6<T>::operator!= (const Shear6<S>& h) const
+{
+    return xy != h.xy || xz != h.xz || yz != h.yz || yx != h.yx || zx != h.zx || zy != h.zy;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Shear6<T>::equalWithAbsError (const Shear6<T>& h, T e) const
+{
+    for (int i = 0; i < 6; i++)
+        if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], h[i], e))
+            return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Shear6<T>::equalWithRelError (const Shear6<T>& h, T e) const
+{
+    for (int i = 0; i < 6; i++)
+        if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], h[i], e))
+            return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
+Shear6<T>::operator+= (const Shear6& h)
+{
+    xy += h.xy;
+    xz += h.xz;
+    yz += h.yz;
+    yx += h.yx;
+    zx += h.zx;
+    zy += h.zy;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Shear6<T>
+Shear6<T>::operator+ (const Shear6& h) const
+{
+    return Shear6 (xy + h.xy, xz + h.xz, yz + h.yz, yx + h.yx, zx + h.zx, zy + h.zy);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
+Shear6<T>::operator-= (const Shear6& h)
+{
+    xy -= h.xy;
+    xz -= h.xz;
+    yz -= h.yz;
+    yx -= h.yx;
+    zx -= h.zx;
+    zy -= h.zy;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Shear6<T>
+Shear6<T>::operator- (const Shear6& h) const
+{
+    return Shear6 (xy - h.xy, xz - h.xz, yz - h.yz, yx - h.yx, zx - h.zx, zy - h.zy);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Shear6<T>
+Shear6<T>::operator-() const
+{
+    return Shear6 (-xy, -xz, -yz, -yx, -zx, -zy);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
+Shear6<T>::negate()
+{
+    xy = -xy;
+    xz = -xz;
+    yz = -yz;
+    yx = -yx;
+    zx = -zx;
+    zy = -zy;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
+Shear6<T>::operator*= (const Shear6& h)
+{
+    xy *= h.xy;
+    xz *= h.xz;
+    yz *= h.yz;
+    yx *= h.yx;
+    zx *= h.zx;
+    zy *= h.zy;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
+Shear6<T>::operator*= (T a)
+{
+    xy *= a;
+    xz *= a;
+    yz *= a;
+    yx *= a;
+    zx *= a;
+    zy *= a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Shear6<T>
+Shear6<T>::operator* (const Shear6& h) const
+{
+    return Shear6 (xy * h.xy, xz * h.xz, yz * h.yz, yx * h.yx, zx * h.zx, zy * h.zy);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Shear6<T>
+Shear6<T>::operator* (T a) const
+{
+    return Shear6 (xy * a, xz * a, yz * a, yx * a, zx * a, zy * a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
+Shear6<T>::operator/= (const Shear6& h)
+{
+    xy /= h.xy;
+    xz /= h.xz;
+    yz /= h.yz;
+    yx /= h.yx;
+    zx /= h.zx;
+    zy /= h.zy;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
+Shear6<T>::operator/= (T a)
+{
+    xy /= a;
+    xz /= a;
+    yz /= a;
+    yx /= a;
+    zx /= a;
+    zy /= a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Shear6<T>
+Shear6<T>::operator/ (const Shear6& h) const
+{
+    return Shear6 (xy / h.xy, xz / h.xz, yz / h.yz, yx / h.yx, zx / h.zx, zy / h.zy);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Shear6<T>
+Shear6<T>::operator/ (T a) const
+{
+    return Shear6 (xy / a, xz / a, yz / a, yx / a, zx / a, zy / a);
+}
+
+//-----------------------------
+// Stream output implementation
+//-----------------------------
+
+template <class T>
+std::ostream&
+operator<< (std::ostream& s, const Shear6<T>& h)
+{
+    return s << '(' << h.xy << ' ' << h.xz << ' ' << h.yz << h.yx << ' ' << h.zx << ' ' << h.zy
+             << ')';
+}
+
+//-----------------------------------------
+// Implementation of reverse multiplication
+//-----------------------------------------
+
+template <class S, class T>
+IMATH_HOSTDEVICE constexpr inline Shear6<T>
+operator* (S a, const Shear6<T>& h)
+{
+    return Shear6<T> (a * h.xy, a * h.xz, a * h.yz, a * h.yx, a * h.zx, a * h.zy);
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHSHEAR_H
diff --git a/src/Imath/ImathSphere.h b/src/Imath/ImathSphere.h
new file mode 100644 (file)
index 0000000..0680de7
--- /dev/null
@@ -0,0 +1,165 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// A 3D sphere class template
+//
+
+#ifndef INCLUDED_IMATHSPHERE_H
+#define INCLUDED_IMATHSPHERE_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+
+#include "ImathBox.h"
+#include "ImathLine.h"
+#include "ImathVec.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+/// A 3D sphere
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Sphere3
+{
+  public:
+
+    /// @{
+    /// @name Direct access to member fields
+    
+    /// Center
+    Vec3<T> center;
+
+    /// Radius
+    T radius;
+
+    /// @}
+
+    /// @{
+    ///        @name Constructors
+
+    /// Default is center at (0,0,0) and radius of 0.
+    IMATH_HOSTDEVICE constexpr Sphere3() : center (0, 0, 0), radius (0) {}
+
+    /// Initialize to a given center and radius
+    IMATH_HOSTDEVICE constexpr Sphere3 (const Vec3<T>& c, T r) : center (c), radius (r) {}
+
+    /// @}
+    
+    /// @{
+    /// @name Manipulation
+    
+    ///        Set the center and radius of the sphere so that it tightly
+    ///        encloses Box b.
+    IMATH_HOSTDEVICE void circumscribe (const Box<Vec3<T>>& box);
+
+    /// @}
+    
+    /// @{
+    /// @name Utility Methods
+    
+    ///        If the sphere and line `l` intersect, then compute the
+    /// smallest `t` with `t>=0` so that `l(t)` is a point on the sphere.
+    ///
+    /// @param[in] l The line
+    /// @param[out] intersection The point of intersection
+    /// @return True if the sphere and line intersect, false if they
+    ///        do not.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool
+    intersect (const Line3<T>& l, Vec3<T>& intersection) const;
+
+    ///        If the sphere and line `l` intersect, then compute the
+    /// smallest `t` with `t>=0` so that `l(t)` is a point on the sphere.
+    ///
+    /// @param[in] l The line
+    /// @param[out] t The parameter of the line at the intersection point
+    /// @return True if the sphere and line intersect, false if they
+    ///        do not.
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool intersectT (const Line3<T>& l, T& t) const;
+
+    /// @}
+};
+
+/// Sphere of type float
+typedef Sphere3<float> Sphere3f;
+
+/// Sphere of type double
+typedef Sphere3<double> Sphere3d;
+
+//---------------
+// Implementation
+//---------------
+
+template <class T>
+IMATH_HOSTDEVICE inline void
+Sphere3<T>::circumscribe (const Box<Vec3<T>>& box)
+{
+    center = T (0.5) * (box.min + box.max);
+    radius = (box.max - center).length();
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool
+Sphere3<T>::intersectT (const Line3<T>& line, T& t) const
+{
+    bool doesIntersect = true;
+
+    Vec3<T> v = line.pos - center;
+    T B       = T (2.0) * (line.dir ^ v);
+    T C       = (v ^ v) - (radius * radius);
+
+    // compute discriminant
+    // if negative, there is no intersection
+
+    T discr = B * B - T (4.0) * C;
+
+    if (discr < 0.0)
+    {
+        // line and Sphere3 do not intersect
+
+        doesIntersect = false;
+    }
+    else
+    {
+        // t0: (-B - sqrt(B^2 - 4AC)) / 2A  (A = 1)
+
+        T sqroot = std::sqrt (discr);
+        t        = (-B - sqroot) * T (0.5);
+
+        if (t < 0.0)
+        {
+            // no intersection, try t1: (-B + sqrt(B^2 - 4AC)) / 2A  (A = 1)
+
+            t = (-B + sqroot) * T (0.5);
+        }
+
+        if (t < 0.0)
+            doesIntersect = false;
+    }
+
+    return doesIntersect;
+}
+
+template <class T>
+IMATH_CONSTEXPR14 bool
+Sphere3<T>::intersect (const Line3<T>& line, Vec3<T>& intersection) const
+{
+    T t (0);
+
+    if (intersectT (line, t))
+    {
+        intersection = line (t);
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHSPHERE_H
diff --git a/src/Imath/ImathTypeTraits.h b/src/Imath/ImathTypeTraits.h
new file mode 100644 (file)
index 0000000..4e8447d
--- /dev/null
@@ -0,0 +1,217 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// This file contains type traits related to or used by the Imath library.
+//
+
+#ifndef INCLUDED_IMATHTYPETRAITS_H
+#define INCLUDED_IMATHTYPETRAITS_H
+
+#include <type_traits>
+
+#include "ImathPlatform.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+/// Define Imath::enable_if_t to be std for C++14, equivalent for C++11.
+#if (IMATH_CPLUSPLUS_VERSION >= 14)
+    using std::enable_if_t;    // Use C++14 std::enable_if_t
+#else
+    // Define enable_if_t for C++11
+    template <bool B, class T = void>
+    using enable_if_t = typename std::enable_if<B, T>::type;
+#endif
+
+
+/// An enable_if helper to be used in template parameters which results in
+/// much shorter symbols.
+#define IMATH_ENABLE_IF(...) IMATH_INTERNAL_NAMESPACE::enable_if_t<(__VA_ARGS__), int> = 0
+
+
+#if IMATH_FOREIGN_VECTOR_INTEROP
+
+/// @{
+/// @name Detecting interoperable types.
+///
+/// In order to construct or assign from external "compatible" types without
+/// prior knowledge of their definitions, we have a few helper type traits.
+/// The intent of these is to allow custom linear algebra types in an
+/// application that have seamless conversion to and from Imath types.
+///
+/// `has_xy<T,Base>`, `has_xyz<T,Base>`, `has_xyzw<T,Base>` detect if class
+/// `T` has elements `.x`, `.y`, and `.z` all of type `Base` and seems to be
+/// the right size to hold exactly those members and nothing more.
+///
+/// `has_subscript<T,Base,N>` detects if class `T` can perform `T[int]`
+/// to yield a `Base`, and that it seems to be exactly the right size to
+/// hold `N` of those elements.
+///
+/// This is not exact. It's possible that for a particular user-defined
+/// type, this may yield a false negative or false positive. For example:
+///   * A class for a 3-vector that contains an extra element of padding
+///     so that it will have the right size and alignment to use 4-wide
+///     SIMD math ops will appear to be the wrong size.
+///   * A `std::vector<T>` is subscriptable and might have N elements at
+///     runtime, but the size is dynamic and so would fail this test.
+///   * A foreign type may have .x, .y, .z that are not matching our base
+///     type but we still want it to work (with appropriate conversions).
+///
+/// In these cases, user code may declare an exception -- for example,
+/// stating that `mytype` should be considered implicitly convertible to
+/// an Imath::V3f by subscripting:
+///
+///     template<>
+///     struct Imath::has_subscript<mytype, float, 3> : public std::true_type { };
+///
+/// And similarly, user code may correct a potential false positive (that
+/// is, a `mytype` looks like it should be convertible to a V3f, but you
+/// don't want it to ever happen):
+///
+///     template<typename B, int N>
+///     struct Imath::has_subscript<mytype, B, N> : public std::false_type { };
+///
+
+
+/// `has_xy<T,Base>::value` will be true if type `T` has member variables
+/// `.x` and `.y`, all of type `Base`, and the size of a `T` is exactly big
+/// enough to hold 2 Base values.
+template <typename T, typename Base>
+struct has_xy {
+private:
+    typedef char Yes[1];
+    typedef char No[2];
+
+    // Valid only if .x, .y exist and are the right type: return a Yes.
+    template<typename C,
+             IMATH_ENABLE_IF(std::is_same<decltype(C().x), Base>::value),
+             IMATH_ENABLE_IF(std::is_same<decltype(C().y), Base>::value)>
+    static Yes& test(int);
+
+    // Fallback, default to returning a No.
+    template<typename C> static No& test(...);
+public:
+    enum { value = (sizeof(test<T>(0)) == sizeof(Yes)
+                    && sizeof(T) == 2*sizeof(Base))
+      };
+};
+
+
+/// `has_xyz<T,Base>::value` will be true if type `T` has member variables
+/// `.x`, `.y`, and `.z`, all of type `Base`, and the size of a `T` is
+/// exactly big enough to hold 3 Base values.
+template <typename T, typename Base>
+struct has_xyz {
+private:
+    typedef char Yes[1];
+    typedef char No[2];
+
+    // Valid only if .x, .y, .z exist and are the right type: return a Yes.
+    template<typename C,
+             IMATH_ENABLE_IF(std::is_same<decltype(C().x), Base>::value),
+             IMATH_ENABLE_IF(std::is_same<decltype(C().y), Base>::value),
+             IMATH_ENABLE_IF(std::is_same<decltype(C().z), Base>::value)>
+    static Yes& test(int);
+
+    // Fallback, default to returning a No.
+    template<typename C> static No& test(...);
+public:
+    enum { value = (sizeof(test<T>(0)) == sizeof(Yes)
+                    && sizeof(T) == 3*sizeof(Base))
+      };
+};
+
+
+/// `has_xyzw<T,Base>::value` will be true if type `T` has member variables
+/// `.x`, `.y`, `.z`, and `.w`, all of type `Base`, and the size of a `T` is
+/// exactly big enough to hold 4 Base values.
+template <typename T, typename Base>
+struct has_xyzw {
+private:
+    typedef char Yes[1];
+    typedef char No[2];
+
+    // Valid only if .x, .y, .z, .w exist and are the right type: return a Yes.
+    template<typename C,
+             IMATH_ENABLE_IF(std::is_same<decltype(C().x), Base>::value),
+             IMATH_ENABLE_IF(std::is_same<decltype(C().y), Base>::value),
+             IMATH_ENABLE_IF(std::is_same<decltype(C().z), Base>::value),
+             IMATH_ENABLE_IF(std::is_same<decltype(C().w), Base>::value)>
+    static Yes& test(int);
+
+    // Fallback, default to returning a No.
+    template<typename C> static No& test(...);
+public:
+    enum { value = (sizeof(test<T>(0)) == sizeof(Yes)
+                    && sizeof(T) == 4*sizeof(Base))
+      };
+};
+
+
+
+/// `has_subscript<T,Base,Nelem>::value` will be true if type `T` has
+/// subscripting syntax, a `T[int]` returns a `Base`, and the size of a `T`
+/// is exactly big enough to hold `Nelem` `Base` values.
+template <typename T, typename Base, int Nelem>
+struct has_subscript {
+private:
+    typedef char Yes[1];
+    typedef char No[2];
+
+    // Valid only if T[] is possible and is the right type: return a Yes.
+    template<typename C,
+             IMATH_ENABLE_IF(std::is_same<typename std::decay<decltype(C()[0])>::type, Base>::value)>
+    static Yes& test(int);
+
+    // Fallback, default to returning a No.
+    template<typename C> static No& test(...);
+public:
+    enum { value = (sizeof(test<T>(0)) == sizeof(Yes)
+                    && sizeof(T) == Nelem*sizeof(Base))
+      };
+};
+
+
+/// C arrays of just the right length also are qualified for has_subscript.
+template<typename Base, int Nelem>
+struct has_subscript<Base[Nelem], Base, Nelem> : public std::true_type { };
+
+
+
+/// `has_double_subscript<T,Base,Rows,Cols>::value` will be true if type `T`
+/// has 2-level subscripting syntax, a `T[int][int]` returns a `Base`, and
+/// the size of a `T` is exactly big enough to hold `R*C` `Base` values.
+template <typename T, typename Base, int Rows, int Cols>
+struct has_double_subscript {
+private:
+    typedef char Yes[1];
+    typedef char No[2];
+
+    // Valid only if T[][] is possible and is the right type: return a Yes.
+    template<typename C,
+             IMATH_ENABLE_IF(std::is_same<typename std::decay<decltype(C()[0][0])>::type, Base>::value)>
+    static Yes& test(int);
+
+    // Fallback, default to returning a No.
+    template<typename C> static No& test(...);
+public:
+    enum { value = (sizeof(test<T>(0)) == sizeof(Yes)
+                    && sizeof(T) == (Rows*Cols)*sizeof(Base))
+      };
+};
+
+
+/// C arrays of just the right length also are qualified for has_double_subscript.
+template<typename Base, int Rows, int Cols>
+struct has_double_subscript<Base[Rows][Cols], Base, Rows, Cols> : public std::true_type { };
+
+/// @}
+
+#endif
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHTYPETRAITS_H
diff --git a/src/Imath/ImathVec.h b/src/Imath/ImathVec.h
new file mode 100644 (file)
index 0000000..f29968d
--- /dev/null
@@ -0,0 +1,2267 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+// 
+
+//
+// 2D, 3D and 4D point/vector class templates
+//
+
+#ifndef INCLUDED_IMATHVEC_H
+#define INCLUDED_IMATHVEC_H
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+#include "ImathTypeTraits.h"
+
+#include "ImathMath.h"
+
+#include <iostream>
+#include <limits>
+#include <cstdint>
+#include <stdexcept>
+
+#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
+// suppress exception specification warnings
+#    pragma warning(push)
+#    pragma warning(disable : 4290)
+#endif
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+template <class T> class Vec2;
+template <class T> class Vec3;
+template <class T> class Vec4;
+
+/// Enum for the Vec4 to Vec3 conversion constructor
+enum IMATH_EXPORT_ENUM InfException
+{
+    INF_EXCEPTION
+};
+
+///
+/// 2-element vector
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Vec2
+{
+  public:
+
+    /// @{
+    /// @name Direct access to elements
+    
+    T x, y;
+
+    /// @}
+    
+    /// Element access by index.  
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T& operator[] (int i) IMATH_NOEXCEPT;
+
+    /// Element access by index.  
+    IMATH_HOSTDEVICE constexpr const T& operator[] (int i) const IMATH_NOEXCEPT;
+
+    /// @{
+    ///        @name Constructors and Assignment
+
+    /// Uninitialized by default
+    IMATH_HOSTDEVICE Vec2() IMATH_NOEXCEPT;
+
+    /// Initialize to a scalar `(a,a)`
+    IMATH_HOSTDEVICE constexpr explicit Vec2 (T a) IMATH_NOEXCEPT;
+
+    /// Initialize to given elements `(a,b)`
+    IMATH_HOSTDEVICE constexpr Vec2 (T a, T b) IMATH_NOEXCEPT;
+
+    /// Copy constructor
+    IMATH_HOSTDEVICE constexpr Vec2 (const Vec2& v) IMATH_NOEXCEPT;
+
+    /// Construct from Vec2 of another base type
+    template <class S> IMATH_HOSTDEVICE constexpr Vec2 (const Vec2<S>& v) IMATH_NOEXCEPT;
+
+
+    /// Assignment
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator= (const Vec2& v) IMATH_NOEXCEPT;
+
+    /// Destructor
+    ~Vec2() IMATH_NOEXCEPT = default;
+
+    /// @}
+
+#if IMATH_FOREIGN_VECTOR_INTEROP
+    /// @{
+    /// @name Interoperability with other vector types
+    ///
+    /// Construction and assignment are allowed from other classes that
+    /// appear to be equivalent vector types, provided that they have either
+    /// a subscripting operator, or data members .x and .y, that are of the
+    /// same type as the elements of this vector, and their size appears to
+    /// be the right number of elements.
+    ///
+    /// This functionality is disabled for gcc 4.x, which seems to have a
+    /// compiler bug that results in spurious errors. It can also be
+    /// disabled by defining IMATH_FOREIGN_VECTOR_INTEROP to be 0 prior to
+    /// including any Imath header files.
+    ///
+
+    template<typename V, IMATH_ENABLE_IF(has_xy<V,T>::value)>
+    IMATH_HOSTDEVICE explicit constexpr Vec2 (const V& v) IMATH_NOEXCEPT
+        : Vec2(T(v.x), T(v.y)) { }
+
+    template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,2>::value
+                                         && !has_xy<V,T>::value)>
+    IMATH_HOSTDEVICE explicit Vec2 (const V& v) : Vec2(T(v[0]), T(v[1])) { }
+
+    template<typename V, IMATH_ENABLE_IF(has_xy<V,T>::value)>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator= (const V& v) IMATH_NOEXCEPT {
+        x = T(v.x);
+        y = T(v.y);
+        return *this;
+    }
+
+    template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,2>::value
+                                         && !has_xy<V,T>::value)>
+    IMATH_HOSTDEVICE const Vec2& operator= (const V& v) {
+        x = T(v[0]);
+        y = T(v[1]);
+        return *this;
+    }
+#endif
+
+    /// @{
+    /// @name Compatibility with Sb
+
+    /// Set the value
+    template <class S> IMATH_HOSTDEVICE void setValue (S a, S b) IMATH_NOEXCEPT;
+
+    /// Set the value
+    template <class S> IMATH_HOSTDEVICE void setValue (const Vec2<S>& v) IMATH_NOEXCEPT;
+
+    /// Return the value in `a` and `b`
+    template <class S> IMATH_HOSTDEVICE void getValue (S& a, S& b) const IMATH_NOEXCEPT;
+
+    /// Return the value in `v`
+    template <class S> IMATH_HOSTDEVICE void getValue (Vec2<S>& v) const IMATH_NOEXCEPT;
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE T* getValue() IMATH_NOEXCEPT;
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE const T* getValue() const IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Arithmetic and Comparison
+    
+    /// Equality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator== (const Vec2<S>& v) const IMATH_NOEXCEPT;
+
+
+    /// Inequality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator!= (const Vec2<S>& v) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and `m` are the same
+    /// with an absolute error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i][j] - m[i][j]) <= e
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithAbsError (const Vec2<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and m are the same with
+    /// a relative error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i] - v[i][j]) <= e * abs (this[i][j])
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithRelError (const Vec2<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Dot product
+    IMATH_HOSTDEVICE constexpr T dot (const Vec2& v) const IMATH_NOEXCEPT;
+
+    /// Dot product
+    IMATH_HOSTDEVICE constexpr T operator^ (const Vec2& v) const IMATH_NOEXCEPT;
+
+    /// Right-handed cross product, i.e. z component of
+    /// Vec3 (this->x, this->y, 0) % Vec3 (v.x, v.y, 0)
+    IMATH_HOSTDEVICE constexpr T cross (const Vec2& v) const IMATH_NOEXCEPT;
+
+    /// Right-handed cross product, i.e. z component of
+    /// Vec3 (this->x, this->y, 0) % Vec3 (v.x, v.y, 0)
+    IMATH_HOSTDEVICE constexpr T operator% (const Vec2& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator+= (const Vec2& v) IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE constexpr Vec2 operator+ (const Vec2& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator-= (const Vec2& v) IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE constexpr Vec2 operator- (const Vec2& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE constexpr Vec2 operator-() const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& negate() IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator*= (const Vec2& v) IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator*= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Vec2 operator* (const Vec2& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Vec2 operator* (T a) const IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator/= (const Vec2& v) IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator/= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Vec2 operator/ (const Vec2& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Vec2 operator/ (T a) const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Query and Manipulation
+
+    /// Return the Euclidean norm
+    IMATH_HOSTDEVICE T length() const IMATH_NOEXCEPT;
+
+    /// Return the square of the Euclidean norm, i.e. the dot product
+    /// with itself.
+    IMATH_HOSTDEVICE constexpr T length2() const IMATH_NOEXCEPT;
+
+    /// Normalize in place. If length()==0, return a null vector.
+    IMATH_HOSTDEVICE const Vec2& normalize() IMATH_NOEXCEPT;
+
+    /// Normalize in place. If length()==0, throw an exception.
+    const Vec2& normalizeExc();
+    
+    /// Normalize without any checks for length()==0. Slightly faster
+    /// than the other normalization routines, but if v.length() is
+    /// 0.0, the result is undefined.
+    IMATH_HOSTDEVICE const Vec2& normalizeNonNull() IMATH_NOEXCEPT;
+
+    /// Return a normalized vector. Does not modify *this.
+    IMATH_HOSTDEVICE Vec2<T> normalized() const IMATH_NOEXCEPT; 
+
+    /// Return a normalized vector. Does not modify *this. Throw an
+    /// exception if length()==0.
+    Vec2<T> normalizedExc() const;
+
+    /// Return a normalized vector. Does not modify *this, and does
+    /// not check for length()==0. Slightly faster than the other
+    /// normalization routines, but if v.length() is 0.0, the result
+    /// is undefined.
+    IMATH_HOSTDEVICE Vec2<T> normalizedNonNull() const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Numeric Limits
+    
+    /// Largest possible negative value
+    IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
+
+    /// Largest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
+
+    /// Smallest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
+
+    /// Smallest possible e for which 1+e != 1
+    IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
+
+    /// @}
+    
+    /// Return the number of dimensions, i.e. 2
+    IMATH_HOSTDEVICE constexpr static unsigned int dimensions() IMATH_NOEXCEPT { return 2; }
+
+    /// The base type: In templates that accept a parameter `V`, you
+    /// can refer to `T` as `V::BaseType`
+    typedef T BaseType;
+
+  private:
+
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T lengthTiny() const IMATH_NOEXCEPT;
+};
+
+///
+/// 3-element vector
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Vec3
+{
+  public:
+
+    /// @{
+    /// @name Direct access to elements
+
+    T x, y, z;
+
+    /// @}
+    
+    /// Element access by index.  
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T& operator[] (int i) IMATH_NOEXCEPT;
+
+    /// Element access by index.  
+    IMATH_HOSTDEVICE constexpr const T& operator[] (int i) const IMATH_NOEXCEPT;
+
+    /// @{
+    ///        @name Constructors and Assignment
+
+    /// Uninitialized by default
+    IMATH_HOSTDEVICE Vec3() IMATH_NOEXCEPT;
+    
+    /// Initialize to a scalar `(a,a,a)`
+    IMATH_HOSTDEVICE constexpr explicit Vec3 (T a) IMATH_NOEXCEPT;
+
+    /// Initialize to given elements `(a,b,c)`
+    IMATH_HOSTDEVICE constexpr Vec3 (T a, T b, T c) IMATH_NOEXCEPT;
+
+    /// Copy constructor
+    IMATH_HOSTDEVICE constexpr Vec3 (const Vec3& v) IMATH_NOEXCEPT;
+
+    /// Construct from Vec3 of another base type
+    template <class S> IMATH_HOSTDEVICE constexpr Vec3 (const Vec3<S>& v) IMATH_NOEXCEPT;
+
+    /// Vec4 to Vec3 conversion: divide x, y and z by w, even if w is
+    /// 0.  The result depends on how the environment handles
+    /// floating-point exceptions.
+    template <class S> IMATH_HOSTDEVICE explicit constexpr Vec3 (const Vec4<S>& v) IMATH_NOEXCEPT;
+
+    /// Vec4 to Vec3 conversion: divide x, y and z by w.  Throws an
+    /// exception if w is zero or if division by w would overflow.
+    template <class S>
+    explicit IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3 (const Vec4<S>& v, InfException);
+
+    /// Assignment
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator= (const Vec3& v) IMATH_NOEXCEPT;
+
+    /// Destructor
+    ~Vec3() IMATH_NOEXCEPT = default;
+
+    /// @}
+
+#if IMATH_FOREIGN_VECTOR_INTEROP
+    /// @{
+    /// @name Interoperability with other vector types
+    ///
+    /// Construction and assignment are allowed from other classes that
+    /// appear to be equivalent vector types, provided that they have either
+    /// a subscripting operator, or data members .x, .y, .z, that are of the
+    /// same type as the elements of this vector, and their size appears to
+    /// be the right number of elements.
+    ///
+    /// This functionality is disabled for gcc 4.x, which seems to have a
+    /// compiler bug that results in spurious errors. It can also be
+    /// disabled by defining IMATH_FOREIGN_VECTOR_INTEROP to be 0 prior to
+    /// including any Imath header files.
+    ///
+
+    template<typename V, IMATH_ENABLE_IF(has_xyz<V,T>::value)>
+    IMATH_HOSTDEVICE explicit constexpr Vec3 (const V& v) IMATH_NOEXCEPT
+        : Vec3(T(v.x), T(v.y), T(v.z)) { }
+
+    template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,3>::value
+                                         && !has_xyz<V,T>::value)>
+    IMATH_HOSTDEVICE explicit Vec3 (const V& v) : Vec3(T(v[0]), T(v[1]), T(v[2])) { }
+
+    /// Interoperability assignment from another type that behaves as if it
+    /// were an equivalent vector.
+    template<typename V, IMATH_ENABLE_IF(has_xyz<V,T>::value)>
+    IMATH_HOSTDEVICE const Vec3& operator= (const V& v) IMATH_NOEXCEPT {
+        x = T(v.x);
+        y = T(v.y);
+        z = T(v.z);
+        return *this;
+    }
+
+    template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,3>::value
+                                         && !has_xyz<V,T>::value)>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator= (const V& v) {
+        x = T(v[0]);
+        y = T(v[1]);
+        z = T(v[2]);
+        return *this;
+    }
+    /// @}
+#endif
+
+    /// @{
+    /// @name Compatibility with Sb
+
+    /// Set the value
+    template <class S> IMATH_HOSTDEVICE void setValue (S a, S b, S c) IMATH_NOEXCEPT;
+
+    /// Set the value
+    template <class S> IMATH_HOSTDEVICE void setValue (const Vec3<S>& v) IMATH_NOEXCEPT;
+
+    /// Return the value in `a`, `b`, and `c`
+    template <class S> IMATH_HOSTDEVICE void getValue (S& a, S& b, S& c) const IMATH_NOEXCEPT;
+
+    /// Return the value in `v`
+    template <class S> IMATH_HOSTDEVICE void getValue (Vec3<S>& v) const IMATH_NOEXCEPT;
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE T* getValue() IMATH_NOEXCEPT;
+
+    /// Return a raw pointer to the array of values
+    IMATH_HOSTDEVICE const T* getValue() const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Arithmetic and Comparison
+    
+    /// Equality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator== (const Vec3<S>& v) const IMATH_NOEXCEPT;
+
+    /// Inequality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator!= (const Vec3<S>& v) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and `m` are the same
+    /// with an absolute error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i][j] - m[i][j]) <= e
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithAbsError (const Vec3<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and m are the same with
+    /// a relative error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i] - v[i][j]) <= e * abs (this[i][j])
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithRelError (const Vec3<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Dot product
+    IMATH_HOSTDEVICE constexpr T dot (const Vec3& v) const IMATH_NOEXCEPT;
+
+    /// Dot product
+    IMATH_HOSTDEVICE constexpr T operator^ (const Vec3& v) const IMATH_NOEXCEPT;
+
+    /// Right-handed cross product
+    IMATH_HOSTDEVICE constexpr Vec3 cross (const Vec3& v) const IMATH_NOEXCEPT;
+
+    /// Right-handed cross product
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator%= (const Vec3& v) IMATH_NOEXCEPT;
+
+    /// Right-handed cross product
+    IMATH_HOSTDEVICE constexpr Vec3 operator% (const Vec3& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator+= (const Vec3& v) IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE constexpr Vec3 operator+ (const Vec3& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator-= (const Vec3& v) IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE constexpr Vec3 operator- (const Vec3& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE constexpr Vec3 operator-() const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& negate() IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator*= (const Vec3& v) IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator*= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Vec3 operator* (const Vec3& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Vec3 operator* (T a) const IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator/= (const Vec3& v) IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator/= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Vec3 operator/ (const Vec3& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Vec3 operator/ (T a) const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Query and Manipulation
+
+    /// Return the Euclidean norm
+    IMATH_HOSTDEVICE T length() const IMATH_NOEXCEPT;
+
+    /// Return the square of the Euclidean norm, i.e. the dot product
+    /// with itself.
+    IMATH_HOSTDEVICE constexpr T length2() const IMATH_NOEXCEPT;
+
+    /// Normalize in place. If length()==0, return a null vector.
+    IMATH_HOSTDEVICE const Vec3& normalize() IMATH_NOEXCEPT;
+
+    /// Normalize in place. If length()==0, throw an exception.
+    const Vec3& normalizeExc();
+
+    /// Normalize without any checks for length()==0. Slightly faster
+    /// than the other normalization routines, but if v.length() is
+    /// 0.0, the result is undefined.
+    IMATH_HOSTDEVICE const Vec3& normalizeNonNull() IMATH_NOEXCEPT;
+
+    /// Return a normalized vector. Does not modify *this.
+    IMATH_HOSTDEVICE Vec3<T> normalized() const IMATH_NOEXCEPT; // does not modify *this
+
+    /// Return a normalized vector. Does not modify *this. Throw an
+    /// exception if length()==0.
+    Vec3<T> normalizedExc() const;
+
+    /// Return a normalized vector. Does not modify *this, and does
+    /// not check for length()==0. Slightly faster than the other
+    /// normalization routines, but if v.length() is 0.0, the result
+    /// is undefined.
+    IMATH_HOSTDEVICE Vec3<T> normalizedNonNull() const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Numeric Limits
+
+    /// Largest possible negative value
+    IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
+
+    /// Largest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
+
+    /// Smallest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
+
+    /// Smallest possible e for which 1+e != 1
+    IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
+
+    /// @}
+    
+    /// Return the number of dimensions, i.e. 3
+    IMATH_HOSTDEVICE constexpr static unsigned int dimensions() IMATH_NOEXCEPT { return 3; }
+
+    /// The base type: In templates that accept a parameter `V`, you
+    /// can refer to `T` as `V::BaseType`
+    typedef T BaseType;
+
+  private:
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T lengthTiny() const IMATH_NOEXCEPT;
+};
+
+///
+/// 4-element vector
+///
+
+template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Vec4
+{
+  public:
+
+    /// @{
+    /// @name Direct access to elements
+
+    T x, y, z, w;
+
+    /// @}
+    
+    /// Element access by index.  
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T& operator[] (int i) IMATH_NOEXCEPT;
+
+    /// Element access by index.  
+    IMATH_HOSTDEVICE constexpr const T& operator[] (int i) const IMATH_NOEXCEPT;
+
+    /// @{
+    ///        @name Constructors and Assignment
+
+    /// Uninitialized by default
+    IMATH_HOSTDEVICE Vec4() IMATH_NOEXCEPT;                            // no initialization
+
+    /// Initialize to a scalar `(a,a,a,a)`
+    IMATH_HOSTDEVICE constexpr explicit Vec4 (T a) IMATH_NOEXCEPT;
+
+    /// Initialize to given elements `(a,b,c,d)`
+    IMATH_HOSTDEVICE constexpr Vec4 (T a, T b, T c, T d) IMATH_NOEXCEPT;
+
+    /// Copy constructor
+    IMATH_HOSTDEVICE constexpr Vec4 (const Vec4& v) IMATH_NOEXCEPT;
+
+    /// Construct from Vec4 of another base type
+    template <class S> IMATH_HOSTDEVICE constexpr Vec4 (const Vec4<S>& v) IMATH_NOEXCEPT;
+
+    /// Vec3 to Vec4 conversion, sets w to 1.
+    template <class S> IMATH_HOSTDEVICE explicit constexpr Vec4 (const Vec3<S>& v) IMATH_NOEXCEPT;
+
+    /// Assignment
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator= (const Vec4& v) IMATH_NOEXCEPT;
+
+    /// Destructor
+    ~Vec4() IMATH_NOEXCEPT = default;
+
+    /// @}
+
+#if IMATH_FOREIGN_VECTOR_INTEROP
+    /// @{
+    /// @name Interoperability with other vector types
+    ///
+    /// Construction and assignment are allowed from other classes that
+    /// appear to be equivalent vector types, provided that they have either
+    /// a subscripting operator, or data members .x, .y, .z, .w that are of
+    /// the same type as the elements of this vector, and their size appears
+    /// to be the right number of elements.
+    ///
+    /// This functionality is disabled for gcc 4.x, which seems to have a
+    /// compiler bug that results in spurious errors. It can also be
+    /// disabled by defining IMATH_FOREIGN_VECTOR_INTEROP to be 0 prior to
+    /// including any Imath header files.
+    ///
+
+    template<typename V, IMATH_ENABLE_IF(has_xyzw<V,T>::value)>
+    IMATH_HOSTDEVICE explicit constexpr Vec4 (const V& v) IMATH_NOEXCEPT
+        : Vec4(T(v.x), T(v.y), T(v.z), T(v.w)) { }
+
+    template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,4>::value
+                                         && !has_xyzw<V,T>::value)>
+    IMATH_HOSTDEVICE explicit Vec4 (const V& v) : Vec4(T(v[0]), T(v[1]), T(v[2]), T(v[3])) { }
+
+    template<typename V, IMATH_ENABLE_IF(has_xyzw<V,T>::value)>
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator= (const V& v) IMATH_NOEXCEPT {
+        x = T(v.x);
+        y = T(v.y);
+        z = T(v.z);
+        w = T(v.w);
+        return *this;
+    }
+
+    template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,4>::value
+                                         && !has_xyzw<V,T>::value)>
+    IMATH_HOSTDEVICE const Vec4& operator= (const V& v) {
+        x = T(v[0]);
+        y = T(v[1]);
+        z = T(v[2]);
+        w = T(v[3]);
+        return *this;
+    }
+    /// @}
+#endif
+
+    /// @{
+    /// @name Arithmetic and Comparison
+    
+    /// Equality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator== (const Vec4<S>& v) const IMATH_NOEXCEPT;
+
+    /// Inequality
+    template <class S> IMATH_HOSTDEVICE constexpr bool operator!= (const Vec4<S>& v) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and `m` are the same
+    /// with an absolute error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i][j] - m[i][j]) <= e
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithAbsError (const Vec4<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Compare two matrices and test if they are "approximately equal":
+    /// @return True if the coefficients of this and m are the same with
+    /// a relative error of no more than e, i.e., for all i, j:
+    ///
+    ///     abs (this[i] - v[i][j]) <= e * abs (this[i][j])
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithRelError (const Vec4<T>& v, T e) const IMATH_NOEXCEPT;
+
+    /// Dot product
+    IMATH_HOSTDEVICE constexpr T dot (const Vec4& v) const IMATH_NOEXCEPT;
+
+    /// Dot product
+    IMATH_HOSTDEVICE constexpr T operator^ (const Vec4& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator+= (const Vec4& v) IMATH_NOEXCEPT;
+
+    /// Component-wise addition
+    IMATH_HOSTDEVICE constexpr Vec4 operator+ (const Vec4& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator-= (const Vec4& v) IMATH_NOEXCEPT;
+
+    /// Component-wise subtraction
+    IMATH_HOSTDEVICE constexpr Vec4 operator- (const Vec4& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE constexpr Vec4 operator-() const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication by -1
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& negate() IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator*= (const Vec4& v) IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator*= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Vec4 operator* (const Vec4& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise multiplication
+    IMATH_HOSTDEVICE constexpr Vec4 operator* (T a) const IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator/= (const Vec4& v) IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator/= (T a) IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Vec4 operator/ (const Vec4& v) const IMATH_NOEXCEPT;
+
+    /// Component-wise division
+    IMATH_HOSTDEVICE constexpr Vec4 operator/ (T a) const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Query and Manipulation
+
+    /// Return the Euclidean norm
+    IMATH_HOSTDEVICE T length() const IMATH_NOEXCEPT;
+
+    /// Return the square of the Euclidean norm, i.e. the dot product
+    /// with itself.
+    IMATH_HOSTDEVICE constexpr T length2() const IMATH_NOEXCEPT;
+
+    /// Normalize in place. If length()==0, return a null vector.
+    IMATH_HOSTDEVICE const Vec4& normalize() IMATH_NOEXCEPT; // modifies *this
+
+    /// Normalize in place. If length()==0, throw an exception.
+    const Vec4& normalizeExc();
+
+    /// Normalize without any checks for length()==0. Slightly faster
+    /// than the other normalization routines, but if v.length() is
+    /// 0.0, the result is undefined.
+    IMATH_HOSTDEVICE const Vec4& normalizeNonNull() IMATH_NOEXCEPT;
+
+    /// Return a normalized vector. Does not modify *this.
+    IMATH_HOSTDEVICE Vec4<T> normalized() const IMATH_NOEXCEPT; // does not modify *this
+
+    /// Return a normalized vector. Does not modify *this. Throw an
+    /// exception if length()==0.
+    Vec4<T> normalizedExc() const;
+
+    /// Return a normalized vector. Does not modify *this, and does
+    /// not check for length()==0. Slightly faster than the other
+    /// normalization routines, but if v.length() is 0.0, the result
+    /// is undefined.
+    IMATH_HOSTDEVICE Vec4<T> normalizedNonNull() const IMATH_NOEXCEPT;
+
+    /// @}
+    
+    /// @{
+    /// @name Numeric Limits
+    
+    /// Largest possible negative value
+    IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
+
+    /// Largest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
+
+    /// Smallest possible positive value
+    IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
+
+    /// Smallest possible e for which 1+e != 1
+    IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
+
+    /// @}
+    
+    /// Return the number of dimensions, i.e. 4
+    IMATH_HOSTDEVICE constexpr static unsigned int dimensions() IMATH_NOEXCEPT { return 4; }
+
+    /// The base type: In templates that accept a parameter `V`, you
+    /// can refer to `T` as `V::BaseType`
+    typedef T BaseType;
+
+  private:
+    IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T lengthTiny() const IMATH_NOEXCEPT;
+};
+
+/// Stream output, as "(x y)"
+template <class T> std::ostream& operator<< (std::ostream& s, const Vec2<T>& v);
+
+/// Stream output, as "(x y z)"
+template <class T> std::ostream& operator<< (std::ostream& s, const Vec3<T>& v);
+
+/// Stream output, as "(x y z w)"
+template <class T> std::ostream& operator<< (std::ostream& s, const Vec4<T>& v);
+
+/// Reverse multiplication: S * Vec2<T>
+template <class T> IMATH_HOSTDEVICE constexpr Vec2<T> operator* (T a, const Vec2<T>& v) IMATH_NOEXCEPT;
+
+/// Reverse multiplication: S * Vec3<T>
+template <class T> IMATH_HOSTDEVICE constexpr Vec3<T> operator* (T a, const Vec3<T>& v) IMATH_NOEXCEPT;
+
+/// Reverse multiplication: S * Vec4<T>
+template <class T> IMATH_HOSTDEVICE constexpr Vec4<T> operator* (T a, const Vec4<T>& v) IMATH_NOEXCEPT;
+
+//-------------------------
+// Typedefs for convenience
+//-------------------------
+
+/// Vec2 of short
+typedef Vec2<short> V2s;
+
+/// Vec2 of integer
+typedef Vec2<int> V2i;
+
+/// Vec2 of int64_t
+typedef Vec2<int64_t> V2i64;
+
+/// Vec2 of float
+typedef Vec2<float> V2f;
+
+/// Vec2 of double
+typedef Vec2<double> V2d;
+
+/// Vec3 of short
+typedef Vec3<short> V3s;
+
+/// Vec3 of integer
+typedef Vec3<int> V3i;
+
+/// Vec3 of int64_t
+typedef Vec3<int64_t> V3i64;
+
+/// Vec3 of float
+typedef Vec3<float> V3f;
+
+/// Vec3 of double
+typedef Vec3<double> V3d;
+
+/// Vec4 of short
+typedef Vec4<short> V4s;
+
+/// Vec4 of integer
+typedef Vec4<int> V4i;
+
+/// Vec4 of int64_t
+typedef Vec4<int64_t> V4i64;
+
+/// Vec4 of float
+typedef Vec4<float> V4f;
+
+/// Vec4 of double
+typedef Vec4<double> V4d;
+
+//----------------------------------------------------------------------------
+// Specializations for VecN<short>, VecN<int>
+//
+// Normalize and length don't make sense for integer vectors, so disable them.
+//----------------------------------------------------------------------------
+
+/// @cond Doxygen_Suppress
+
+// Vec2<short>
+template <> IMATH_HOSTDEVICE short Vec2<short>::length() const IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE const Vec2<short>& Vec2<short>::normalize() IMATH_NOEXCEPT = delete;
+template <> const Vec2<short>& Vec2<short>::normalizeExc() = delete;
+template <> IMATH_HOSTDEVICE const Vec2<short>& Vec2<short>::normalizeNonNull() IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE Vec2<short> Vec2<short>::normalized() const IMATH_NOEXCEPT = delete;
+template <> Vec2<short> Vec2<short>::normalizedExc() const = delete;
+template <> IMATH_HOSTDEVICE Vec2<short> Vec2<short>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
+
+// Vec2<int>
+template <> IMATH_HOSTDEVICE int Vec2<int>::length() const IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE const Vec2<int>& Vec2<int>::normalize() IMATH_NOEXCEPT = delete;
+template <> const Vec2<int>& Vec2<int>::normalizeExc() = delete;
+template <> IMATH_HOSTDEVICE const Vec2<int>& Vec2<int>::normalizeNonNull() IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE Vec2<int> Vec2<int>::normalized() const IMATH_NOEXCEPT = delete;
+template <> Vec2<int> Vec2<int>::normalizedExc() const = delete;
+template <> IMATH_HOSTDEVICE Vec2<int> Vec2<int>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
+
+// Vec2<int64_t>
+template <> IMATH_HOSTDEVICE int64_t Vec2<int64_t>::length() const IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE const Vec2<int64_t>& Vec2<int64_t>::normalize() IMATH_NOEXCEPT = delete;
+template <> const Vec2<int64_t>& Vec2<int64_t>::normalizeExc() = delete;
+template <> IMATH_HOSTDEVICE const Vec2<int64_t>& Vec2<int64_t>::normalizeNonNull() IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE Vec2<int64_t> Vec2<int64_t>::normalized() const IMATH_NOEXCEPT = delete;
+template <> Vec2<int64_t> Vec2<int64_t>::normalizedExc() const = delete;
+template <> IMATH_HOSTDEVICE Vec2<int64_t> Vec2<int64_t>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
+
+// Vec3<short>
+template <> IMATH_HOSTDEVICE short Vec3<short>::length() const IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE const Vec3<short>& Vec3<short>::normalize() IMATH_NOEXCEPT = delete;
+template <> const Vec3<short>& Vec3<short>::normalizeExc() = delete;
+template <> IMATH_HOSTDEVICE const Vec3<short>& Vec3<short>::normalizeNonNull() IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE Vec3<short> Vec3<short>::normalized() const IMATH_NOEXCEPT = delete;
+template <> Vec3<short> Vec3<short>::normalizedExc() const = delete;
+template <> IMATH_HOSTDEVICE Vec3<short> Vec3<short>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
+
+// Vec3<int>
+template <> IMATH_HOSTDEVICE int Vec3<int>::length() const IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE const Vec3<int>& Vec3<int>::normalize() IMATH_NOEXCEPT = delete;
+template <> const Vec3<int>& Vec3<int>::normalizeExc() = delete;
+template <> IMATH_HOSTDEVICE const Vec3<int>& Vec3<int>::normalizeNonNull() IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE Vec3<int> Vec3<int>::normalized() const IMATH_NOEXCEPT = delete;
+template <> Vec3<int> Vec3<int>::normalizedExc() const = delete;
+template <> IMATH_HOSTDEVICE Vec3<int> Vec3<int>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
+
+// Vec3<int64_t>
+template <> IMATH_HOSTDEVICE int64_t Vec3<int64_t>::length() const IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE const Vec3<int64_t>& Vec3<int64_t>::normalize() IMATH_NOEXCEPT = delete;
+template <> const Vec3<int64_t>& Vec3<int64_t>::normalizeExc() = delete;
+template <> IMATH_HOSTDEVICE const Vec3<int64_t>& Vec3<int64_t>::normalizeNonNull() IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE Vec3<int64_t> Vec3<int64_t>::normalized() const IMATH_NOEXCEPT = delete;
+template <> Vec3<int64_t> Vec3<int64_t>::normalizedExc() const = delete;
+template <> IMATH_HOSTDEVICE Vec3<int64_t> Vec3<int64_t>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
+
+// Vec4<short>
+template <> IMATH_HOSTDEVICE short Vec4<short>::length() const IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE const Vec4<short>& Vec4<short>::normalize() IMATH_NOEXCEPT = delete;
+template <> const Vec4<short>& Vec4<short>::normalizeExc() = delete;
+template <> IMATH_HOSTDEVICE const Vec4<short>& Vec4<short>::normalizeNonNull() IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE Vec4<short> Vec4<short>::normalized() const IMATH_NOEXCEPT = delete;
+template <> Vec4<short> Vec4<short>::normalizedExc() const = delete;
+template <> IMATH_HOSTDEVICE Vec4<short> Vec4<short>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
+
+// Vec4<int>
+template <> IMATH_HOSTDEVICE int Vec4<int>::length() const IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE const Vec4<int>& Vec4<int>::normalize() IMATH_NOEXCEPT = delete;
+template <> const Vec4<int>& Vec4<int>::normalizeExc() = delete;
+template <> IMATH_HOSTDEVICE const Vec4<int>& Vec4<int>::normalizeNonNull() IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE Vec4<int> Vec4<int>::normalized() const IMATH_NOEXCEPT = delete;
+template <> Vec4<int> Vec4<int>::normalizedExc() const = delete;
+template <> IMATH_HOSTDEVICE Vec4<int> Vec4<int>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
+
+// Vec4<int64_t>
+template <> IMATH_HOSTDEVICE int64_t Vec4<int64_t>::length() const IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE const Vec4<int64_t>& Vec4<int64_t>::normalize() IMATH_NOEXCEPT = delete;
+template <> const Vec4<int64_t>& Vec4<int64_t>::normalizeExc() = delete;
+template <> IMATH_HOSTDEVICE const Vec4<int64_t>& Vec4<int64_t>::normalizeNonNull() IMATH_NOEXCEPT = delete;
+template <> IMATH_HOSTDEVICE Vec4<int64_t> Vec4<int64_t>::normalized() const IMATH_NOEXCEPT = delete;
+template <> Vec4<int64_t> Vec4<int64_t>::normalizedExc() const = delete;
+template <> IMATH_HOSTDEVICE Vec4<int64_t> Vec4<int64_t>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
+
+/// @endcond Doxygen_Suppress
+
+//------------------------
+// Implementation of Vec2:
+//------------------------
+
+template <class T>
+IMATH_CONSTEXPR14 IMATH_HOSTDEVICE inline T&
+Vec2<T>::operator[] (int i) IMATH_NOEXCEPT
+{
+    return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
+}
+
+template <class T>
+constexpr IMATH_HOSTDEVICE inline const T&
+Vec2<T>::operator[] (int i) const IMATH_NOEXCEPT
+{
+    return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
+}
+
+template <class T> IMATH_HOSTDEVICE inline Vec2<T>::Vec2() IMATH_NOEXCEPT
+{
+    // empty, and not constexpr because data is uninitialized.
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Vec2<T>::Vec2 (T a) IMATH_NOEXCEPT
+    : x(a), y(a)
+{
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Vec2<T>::Vec2 (T a, T b) IMATH_NOEXCEPT
+    : x(a), y(b)
+{
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Vec2<T>::Vec2 (const Vec2& v) IMATH_NOEXCEPT
+    : x(v.x), y(v.y)
+{
+}
+
+template <class T> template <class S> IMATH_HOSTDEVICE constexpr inline Vec2<T>::Vec2 (const Vec2<S>& v) IMATH_NOEXCEPT
+    : x(T(v.x)), y(T(v.y))
+{
+}
+
+template <class T>
+IMATH_CONSTEXPR14 IMATH_HOSTDEVICE inline const Vec2<T>&
+Vec2<T>::operator= (const Vec2& v) IMATH_NOEXCEPT
+{
+    x = v.x;
+    y = v.y;
+    return *this;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Vec2<T>::setValue (S a, S b) IMATH_NOEXCEPT
+{
+    x = T (a);
+    y = T (b);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Vec2<T>::setValue (const Vec2<S>& v) IMATH_NOEXCEPT
+{
+    x = T (v.x);
+    y = T (v.y);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Vec2<T>::getValue (S& a, S& b) const IMATH_NOEXCEPT
+{
+    a = S (x);
+    b = S (y);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Vec2<T>::getValue (Vec2<S>& v) const IMATH_NOEXCEPT
+{
+    v.x = S (x);
+    v.y = S (y);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline T*
+Vec2<T>::getValue() IMATH_NOEXCEPT
+{
+    return (T*) &x;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const T*
+Vec2<T>::getValue() const IMATH_NOEXCEPT
+{
+    return (const T*) &x;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Vec2<T>::operator== (const Vec2<S>& v) const IMATH_NOEXCEPT
+{
+    return x == v.x && y == v.y;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Vec2<T>::operator!= (const Vec2<S>& v) const IMATH_NOEXCEPT
+{
+    return x != v.x || y != v.y;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Vec2<T>::equalWithAbsError (const Vec2<T>& v, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 2; i++)
+        if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], v[i], e))
+            return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Vec2<T>::equalWithRelError (const Vec2<T>& v, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 2; i++)
+        if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], v[i], e))
+            return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Vec2<T>::dot (const Vec2& v) const IMATH_NOEXCEPT
+{
+    return x * v.x + y * v.y;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Vec2<T>::operator^ (const Vec2& v) const IMATH_NOEXCEPT
+{
+    return dot (v);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Vec2<T>::cross (const Vec2& v) const IMATH_NOEXCEPT
+{
+    return x * v.y - y * v.x;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Vec2<T>::operator% (const Vec2& v) const IMATH_NOEXCEPT
+{
+    return x * v.y - y * v.x;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
+Vec2<T>::operator+= (const Vec2& v) IMATH_NOEXCEPT
+{
+    x += v.x;
+    y += v.y;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec2<T>
+Vec2<T>::operator+ (const Vec2& v) const IMATH_NOEXCEPT
+{
+    return Vec2 (x + v.x, y + v.y);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
+Vec2<T>::operator-= (const Vec2& v) IMATH_NOEXCEPT
+{
+    x -= v.x;
+    y -= v.y;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec2<T>
+Vec2<T>::operator- (const Vec2& v) const IMATH_NOEXCEPT
+{
+    return Vec2 (x - v.x, y - v.y);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec2<T>
+Vec2<T>::operator-() const IMATH_NOEXCEPT
+{
+    return Vec2 (-x, -y);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
+Vec2<T>::negate() IMATH_NOEXCEPT
+{
+    x = -x;
+    y = -y;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
+Vec2<T>::operator*= (const Vec2& v) IMATH_NOEXCEPT
+{
+    x *= v.x;
+    y *= v.y;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
+Vec2<T>::operator*= (T a) IMATH_NOEXCEPT
+{
+    x *= a;
+    y *= a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec2<T>
+Vec2<T>::operator* (const Vec2& v) const IMATH_NOEXCEPT
+{
+    return Vec2 (x * v.x, y * v.y);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec2<T>
+Vec2<T>::operator* (T a) const IMATH_NOEXCEPT
+{
+    return Vec2 (x * a, y * a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
+Vec2<T>::operator/= (const Vec2& v) IMATH_NOEXCEPT
+{
+    x /= v.x;
+    y /= v.y;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
+Vec2<T>::operator/= (T a) IMATH_NOEXCEPT
+{
+    x /= a;
+    y /= a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec2<T>
+Vec2<T>::operator/ (const Vec2& v) const IMATH_NOEXCEPT
+{
+    return Vec2 (x / v.x, y / v.y);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec2<T>
+Vec2<T>::operator/ (T a) const IMATH_NOEXCEPT
+{
+    return Vec2 (x / a, y / a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+Vec2<T>::lengthTiny() const IMATH_NOEXCEPT
+{
+    T absX = std::abs(x);
+    T absY = std::abs(y);
+
+    T max = absX;
+
+    if (max < absY)
+        max = absY;
+
+    if (IMATH_UNLIKELY(max == T (0)))
+        return T (0);
+
+    //
+    // Do not replace the divisions by max with multiplications by 1/max.
+    // Computing 1/max can overflow but the divisions below will always
+    // produce results less than or equal to 1.
+    //
+
+    absX /= max;
+    absY /= max;
+
+    return max * std::sqrt (absX * absX + absY * absY);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline T
+Vec2<T>::length() const IMATH_NOEXCEPT
+{
+    T length2 = dot (*this);
+
+    if (IMATH_UNLIKELY(length2 < T (2) * std::numeric_limits<T>::min()))
+        return lengthTiny();
+
+    return std::sqrt (length2);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Vec2<T>::length2() const IMATH_NOEXCEPT
+{
+    return dot (*this);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const Vec2<T>&
+Vec2<T>::normalize() IMATH_NOEXCEPT
+{
+    T l = length();
+
+    if (IMATH_LIKELY(l != T (0)))
+    {
+        //
+        // Do not replace the divisions by l with multiplications by 1/l.
+        // Computing 1/l can overflow but the divisions below will always
+        // produce results less than or equal to 1.
+        //
+
+        x /= l;
+        y /= l;
+    }
+
+    return *this;
+}
+
+template <class T>
+inline const Vec2<T>&
+Vec2<T>::normalizeExc()
+{
+    T l = length();
+
+    if (IMATH_UNLIKELY(l == T (0)))
+        throw std::domain_error ("Cannot normalize null vector.");
+
+    x /= l;
+    y /= l;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const Vec2<T>&
+Vec2<T>::normalizeNonNull() IMATH_NOEXCEPT
+{
+    T l = length();
+    x /= l;
+    y /= l;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Vec2<T>
+Vec2<T>::normalized() const IMATH_NOEXCEPT
+{
+    T l = length();
+
+    if (IMATH_UNLIKELY(l == T (0)))
+        return Vec2 (T (0));
+
+    return Vec2 (x / l, y / l);
+}
+
+template <class T>
+inline Vec2<T>
+Vec2<T>::normalizedExc() const
+{
+    T l = length();
+
+    if (IMATH_UNLIKELY(l == T (0)))
+        throw std::domain_error ("Cannot normalize null vector.");
+
+    return Vec2 (x / l, y / l);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Vec2<T>
+Vec2<T>::normalizedNonNull() const IMATH_NOEXCEPT
+{
+    T l = length();
+    return Vec2 (x / l, y / l);
+}
+
+//-----------------------
+// Implementation of Vec3
+//-----------------------
+
+template <class T>
+IMATH_HOSTDEVICE
+IMATH_CONSTEXPR14 inline T&
+Vec3<T>::operator[] (int i) IMATH_NOEXCEPT
+{
+    return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline const T&
+Vec3<T>::operator[] (int i) const IMATH_NOEXCEPT
+{
+    return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
+}
+
+template <class T> IMATH_HOSTDEVICE inline Vec3<T>::Vec3() IMATH_NOEXCEPT
+{
+    // empty, and not constexpr because data is uninitialized.
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Vec3<T>::Vec3 (T a) IMATH_NOEXCEPT
+    : x(a), y(a), z(a)
+{
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Vec3<T>::Vec3 (T a, T b, T c) IMATH_NOEXCEPT
+    : x(a), y(b), z(c)
+{
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Vec3<T>::Vec3 (const Vec3& v) IMATH_NOEXCEPT
+    : x(v.x), y(v.y), z(v.z)
+{
+}
+
+template <class T> template <class S>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>::Vec3 (const Vec3<S>& v) IMATH_NOEXCEPT
+    : x(T(v.x)), y(T(v.y)), z(T(v.z))
+{
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
+Vec3<T>::operator= (const Vec3& v) IMATH_NOEXCEPT
+{
+    x = v.x;
+    y = v.y;
+    z = v.z;
+    return *this;
+}
+
+template <class T> template <class S>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>::Vec3 (const Vec4<S>& v) IMATH_NOEXCEPT
+    : x(T(v.x/v.w)), y(T(v.y/v.w)), z(T(v.z/v.w))
+{
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Vec3<T>::Vec3 (const Vec4<S>& v, InfException)
+{
+    T vx = T (v.x);
+    T vy = T (v.y);
+    T vz = T (v.z);
+    T vw = T (v.w);
+
+    T absW = (vw >= T (0)) ? vw : -vw;
+
+    if (absW < 1)
+    {
+        T m = baseTypeMax() * absW;
+
+        if (vx <= -m || vx >= m || vy <= -m || vy >= m || vz <= -m || vz >= m)
+            throw std::domain_error ("Cannot normalize point at infinity.");
+    }
+
+    x = vx / vw;
+    y = vy / vw;
+    z = vz / vw;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Vec3<T>::setValue (S a, S b, S c) IMATH_NOEXCEPT
+{
+    x = T (a);
+    y = T (b);
+    z = T (c);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Vec3<T>::setValue (const Vec3<S>& v) IMATH_NOEXCEPT
+{
+    x = T (v.x);
+    y = T (v.y);
+    z = T (v.z);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Vec3<T>::getValue (S& a, S& b, S& c) const IMATH_NOEXCEPT
+{
+    a = S (x);
+    b = S (y);
+    c = S (z);
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE inline void
+Vec3<T>::getValue (Vec3<S>& v) const IMATH_NOEXCEPT
+{
+    v.x = S (x);
+    v.y = S (y);
+    v.z = S (z);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline T*
+Vec3<T>::getValue() IMATH_NOEXCEPT
+{
+    return (T*) &x;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const T*
+Vec3<T>::getValue() const IMATH_NOEXCEPT
+{
+    return (const T*) &x;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Vec3<T>::operator== (const Vec3<S>& v) const IMATH_NOEXCEPT
+{
+    return x == v.x && y == v.y && z == v.z;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Vec3<T>::operator!= (const Vec3<S>& v) const IMATH_NOEXCEPT
+{
+    return x != v.x || y != v.y || z != v.z;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Vec3<T>::equalWithAbsError (const Vec3<T>& v, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 3; i++)
+        if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], v[i], e))
+            return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Vec3<T>::equalWithRelError (const Vec3<T>& v, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 3; i++)
+        if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], v[i], e))
+            return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Vec3<T>::dot (const Vec3& v) const IMATH_NOEXCEPT
+{
+    return x * v.x + y * v.y + z * v.z;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Vec3<T>::operator^ (const Vec3& v) const IMATH_NOEXCEPT
+{
+    return dot (v);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Vec3<T>::cross (const Vec3& v) const IMATH_NOEXCEPT
+{
+    return Vec3 (y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
+Vec3<T>::operator%= (const Vec3& v) IMATH_NOEXCEPT
+{
+    T a = y * v.z - z * v.y;
+    T b = z * v.x - x * v.z;
+    T c = x * v.y - y * v.x;
+    x   = a;
+    y   = b;
+    z   = c;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Vec3<T>::operator% (const Vec3& v) const IMATH_NOEXCEPT
+{
+    return Vec3 (y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
+Vec3<T>::operator+= (const Vec3& v) IMATH_NOEXCEPT
+{
+    x += v.x;
+    y += v.y;
+    z += v.z;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Vec3<T>::operator+ (const Vec3& v) const IMATH_NOEXCEPT
+{
+    return Vec3 (x + v.x, y + v.y, z + v.z);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
+Vec3<T>::operator-= (const Vec3& v) IMATH_NOEXCEPT
+{
+    x -= v.x;
+    y -= v.y;
+    z -= v.z;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Vec3<T>::operator- (const Vec3& v) const IMATH_NOEXCEPT
+{
+    return Vec3 (x - v.x, y - v.y, z - v.z);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Vec3<T>::operator-() const IMATH_NOEXCEPT
+{
+    return Vec3 (-x, -y, -z);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
+Vec3<T>::negate() IMATH_NOEXCEPT
+{
+    x = -x;
+    y = -y;
+    z = -z;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
+Vec3<T>::operator*= (const Vec3& v) IMATH_NOEXCEPT
+{
+    x *= v.x;
+    y *= v.y;
+    z *= v.z;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
+Vec3<T>::operator*= (T a) IMATH_NOEXCEPT
+{
+    x *= a;
+    y *= a;
+    z *= a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Vec3<T>::operator* (const Vec3& v) const IMATH_NOEXCEPT
+{
+    return Vec3 (x * v.x, y * v.y, z * v.z);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Vec3<T>::operator* (T a) const IMATH_NOEXCEPT
+{
+    return Vec3 (x * a, y * a, z * a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
+Vec3<T>::operator/= (const Vec3& v) IMATH_NOEXCEPT
+{
+    x /= v.x;
+    y /= v.y;
+    z /= v.z;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
+Vec3<T>::operator/= (T a) IMATH_NOEXCEPT
+{
+    x /= a;
+    y /= a;
+    z /= a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Vec3<T>::operator/ (const Vec3& v) const IMATH_NOEXCEPT
+{
+    return Vec3 (x / v.x, y / v.y, z / v.z);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+Vec3<T>::operator/ (T a) const IMATH_NOEXCEPT
+{
+    return Vec3 (x / a, y / a, z / a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+Vec3<T>::lengthTiny() const IMATH_NOEXCEPT
+{
+    T absX = (x >= T (0)) ? x : -x;
+    T absY = (y >= T (0)) ? y : -y;
+    T absZ = (z >= T (0)) ? z : -z;
+
+    T max = absX;
+
+    if (max < absY)
+        max = absY;
+
+    if (max < absZ)
+        max = absZ;
+
+    if (IMATH_UNLIKELY(max == T (0)))
+        return T (0);
+
+    //
+    // Do not replace the divisions by max with multiplications by 1/max.
+    // Computing 1/max can overflow but the divisions below will always
+    // produce results less than or equal to 1.
+    //
+
+    absX /= max;
+    absY /= max;
+    absZ /= max;
+
+    return max * std::sqrt (absX * absX + absY * absY + absZ * absZ);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline T
+Vec3<T>::length() const IMATH_NOEXCEPT
+{
+    T length2 = dot (*this);
+
+    if (IMATH_UNLIKELY(length2 < T (2) * std::numeric_limits<T>::min()))
+        return lengthTiny();
+
+    return std::sqrt (length2);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Vec3<T>::length2() const IMATH_NOEXCEPT
+{
+    return dot (*this);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const Vec3<T>&
+Vec3<T>::normalize() IMATH_NOEXCEPT
+{
+    T l = length();
+
+    if (IMATH_LIKELY(l != T (0)))
+    {
+        //
+        // Do not replace the divisions by l with multiplications by 1/l.
+        // Computing 1/l can overflow but the divisions below will always
+        // produce results less than or equal to 1.
+        //
+
+        x /= l;
+        y /= l;
+        z /= l;
+    }
+
+    return *this;
+}
+
+template <class T>
+inline const Vec3<T>&
+Vec3<T>::normalizeExc()
+{
+    T l = length();
+
+    if (IMATH_UNLIKELY(l == T (0)))
+        throw std::domain_error ("Cannot normalize null vector.");
+
+    x /= l;
+    y /= l;
+    z /= l;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const Vec3<T>&
+Vec3<T>::normalizeNonNull() IMATH_NOEXCEPT
+{
+    T l = length();
+    x /= l;
+    y /= l;
+    z /= l;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Vec3<T>
+Vec3<T>::normalized() const IMATH_NOEXCEPT
+{
+    T l = length();
+
+    if (IMATH_UNLIKELY((l == T (0))))
+        return Vec3 (T (0));
+
+    return Vec3 (x / l, y / l, z / l);
+}
+
+template <class T>
+inline Vec3<T>
+Vec3<T>::normalizedExc() const
+{
+    T l = length();
+
+    if (IMATH_UNLIKELY(l == T (0)))
+        throw std::domain_error ("Cannot normalize null vector.");
+
+    return Vec3 (x / l, y / l, z / l);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Vec3<T>
+Vec3<T>::normalizedNonNull() const IMATH_NOEXCEPT
+{
+    T l = length();
+    return Vec3 (x / l, y / l, z / l);
+}
+
+//-----------------------
+// Implementation of Vec4
+//-----------------------
+
+template <class T>
+IMATH_HOSTDEVICE
+IMATH_CONSTEXPR14 inline T&
+Vec4<T>::operator[] (int i) IMATH_NOEXCEPT
+{
+    return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline const T&
+Vec4<T>::operator[] (int i) const IMATH_NOEXCEPT
+{
+    return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
+}
+
+template <class T> IMATH_HOSTDEVICE inline Vec4<T>::Vec4() IMATH_NOEXCEPT
+{
+    // empty, and not constexpr because data is uninitialized.
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Vec4<T>::Vec4 (T a) IMATH_NOEXCEPT
+    : x(a), y(a), z(a), w(a)
+{
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Vec4<T>::Vec4 (T a, T b, T c, T d) IMATH_NOEXCEPT
+    : x(a), y(b), z(c), w(d)
+{
+}
+
+template <class T> IMATH_HOSTDEVICE constexpr inline Vec4<T>::Vec4 (const Vec4& v) IMATH_NOEXCEPT
+    : x(v.x), y(v.y), z(v.z), w(v.w)
+{
+}
+
+template <class T> template <class S>
+IMATH_HOSTDEVICE constexpr inline Vec4<T>::Vec4 (const Vec4<S>& v) IMATH_NOEXCEPT
+    : x(T(v.x)), y(T(v.y)), z(T(v.z)), w(T(v.w))
+{
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
+Vec4<T>::operator= (const Vec4& v) IMATH_NOEXCEPT
+{
+    x = v.x;
+    y = v.y;
+    z = v.z;
+    w = v.w;
+    return *this;
+}
+
+template <class T> template <class S>
+IMATH_HOSTDEVICE constexpr inline Vec4<T>::Vec4 (const Vec3<S>& v) IMATH_NOEXCEPT
+    : x(T(v.x)), y(T(v.y)), z(T(v.z)), w(T(1))
+{
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Vec4<T>::operator== (const Vec4<S>& v) const IMATH_NOEXCEPT
+{
+    return x == v.x && y == v.y && z == v.z && w == v.w;
+}
+
+template <class T>
+template <class S>
+IMATH_HOSTDEVICE constexpr inline bool
+Vec4<T>::operator!= (const Vec4<S>& v) const IMATH_NOEXCEPT
+{
+    return x != v.x || y != v.y || z != v.z || w != v.w;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Vec4<T>::equalWithAbsError (const Vec4<T>& v, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 4; i++)
+        if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], v[i], e))
+            return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
+Vec4<T>::equalWithRelError (const Vec4<T>& v, T e) const IMATH_NOEXCEPT
+{
+    for (int i = 0; i < 4; i++)
+        if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], v[i], e))
+            return false;
+
+    return true;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Vec4<T>::dot (const Vec4& v) const IMATH_NOEXCEPT
+{
+    return x * v.x + y * v.y + z * v.z + w * v.w;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Vec4<T>::operator^ (const Vec4& v) const IMATH_NOEXCEPT
+{
+    return dot (v);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
+Vec4<T>::operator+= (const Vec4& v) IMATH_NOEXCEPT
+{
+    x += v.x;
+    y += v.y;
+    z += v.z;
+    w += v.w;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec4<T>
+Vec4<T>::operator+ (const Vec4& v) const IMATH_NOEXCEPT
+{
+    return Vec4 (x + v.x, y + v.y, z + v.z, w + v.w);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
+Vec4<T>::operator-= (const Vec4& v) IMATH_NOEXCEPT
+{
+    x -= v.x;
+    y -= v.y;
+    z -= v.z;
+    w -= v.w;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec4<T>
+Vec4<T>::operator- (const Vec4& v) const IMATH_NOEXCEPT
+{
+    return Vec4 (x - v.x, y - v.y, z - v.z, w - v.w);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec4<T>
+Vec4<T>::operator-() const IMATH_NOEXCEPT
+{
+    return Vec4 (-x, -y, -z, -w);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
+Vec4<T>::negate() IMATH_NOEXCEPT
+{
+    x = -x;
+    y = -y;
+    z = -z;
+    w = -w;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
+Vec4<T>::operator*= (const Vec4& v) IMATH_NOEXCEPT
+{
+    x *= v.x;
+    y *= v.y;
+    z *= v.z;
+    w *= v.w;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
+Vec4<T>::operator*= (T a) IMATH_NOEXCEPT
+{
+    x *= a;
+    y *= a;
+    z *= a;
+    w *= a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec4<T>
+Vec4<T>::operator* (const Vec4& v) const IMATH_NOEXCEPT
+{
+    return Vec4 (x * v.x, y * v.y, z * v.z, w * v.w);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec4<T>
+Vec4<T>::operator* (T a) const IMATH_NOEXCEPT
+{
+    return Vec4 (x * a, y * a, z * a, w * a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
+Vec4<T>::operator/= (const Vec4& v) IMATH_NOEXCEPT
+{
+    x /= v.x;
+    y /= v.y;
+    z /= v.z;
+    w /= v.w;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
+Vec4<T>::operator/= (T a) IMATH_NOEXCEPT
+{
+    x /= a;
+    y /= a;
+    z /= a;
+    w /= a;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec4<T>
+Vec4<T>::operator/ (const Vec4& v) const IMATH_NOEXCEPT
+{
+    return Vec4 (x / v.x, y / v.y, z / v.z, w / v.w);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec4<T>
+Vec4<T>::operator/ (T a) const IMATH_NOEXCEPT
+{
+    return Vec4 (x / a, y / a, z / a, w / a);
+}
+
+template <class T>
+IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
+Vec4<T>::lengthTiny() const IMATH_NOEXCEPT
+{
+    T absX = (x >= T (0)) ? x : -x;
+    T absY = (y >= T (0)) ? y : -y;
+    T absZ = (z >= T (0)) ? z : -z;
+    T absW = (w >= T (0)) ? w : -w;
+
+    T max = absX;
+
+    if (max < absY)
+        max = absY;
+
+    if (max < absZ)
+        max = absZ;
+
+    if (max < absW)
+        max = absW;
+
+    if (IMATH_UNLIKELY(max == T (0)))
+        return T (0);
+
+    //
+    // Do not replace the divisions by max with multiplications by 1/max.
+    // Computing 1/max can overflow but the divisions below will always
+    // produce results less than or equal to 1.
+    //
+
+    absX /= max;
+    absY /= max;
+    absZ /= max;
+    absW /= max;
+
+    return max * std::sqrt (absX * absX + absY * absY + absZ * absZ + absW * absW);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline T
+Vec4<T>::length() const IMATH_NOEXCEPT
+{
+    T length2 = dot (*this);
+
+    if (IMATH_UNLIKELY(length2 < T (2) * std::numeric_limits<T>::min()))
+        return lengthTiny();
+
+    return std::sqrt (length2);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline T
+Vec4<T>::length2() const IMATH_NOEXCEPT
+{
+    return dot (*this);
+}
+
+template <class T>
+IMATH_HOSTDEVICE const inline Vec4<T>&
+Vec4<T>::normalize() IMATH_NOEXCEPT
+{
+    T l = length();
+
+    if (IMATH_LIKELY(l != T (0)))
+    {
+        //
+        // Do not replace the divisions by l with multiplications by 1/l.
+        // Computing 1/l can overflow but the divisions below will always
+        // produce results less than or equal to 1.
+        //
+
+        x /= l;
+        y /= l;
+        z /= l;
+        w /= l;
+    }
+
+    return *this;
+}
+
+template <class T>
+const inline Vec4<T>&
+Vec4<T>::normalizeExc()
+{
+    T l = length();
+
+    if (IMATH_UNLIKELY(l == T (0)))
+        throw std::domain_error ("Cannot normalize null vector.");
+
+    x /= l;
+    y /= l;
+    z /= l;
+    w /= l;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline const Vec4<T>&
+Vec4<T>::normalizeNonNull() IMATH_NOEXCEPT
+{
+    T l = length();
+    x /= l;
+    y /= l;
+    z /= l;
+    w /= l;
+    return *this;
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Vec4<T>
+Vec4<T>::normalized() const IMATH_NOEXCEPT
+{
+    T l = length();
+
+    if (IMATH_UNLIKELY(l == T (0)))
+        return Vec4 (T (0));
+
+    return Vec4 (x / l, y / l, z / l, w / l);
+}
+
+template <class T>
+inline Vec4<T>
+Vec4<T>::normalizedExc() const
+{
+    T l = length();
+
+    if (IMATH_UNLIKELY(l == T (0)))
+        throw std::domain_error ("Cannot normalize null vector.");
+
+    return Vec4 (x / l, y / l, z / l, w / l);
+}
+
+template <class T>
+IMATH_HOSTDEVICE inline Vec4<T>
+Vec4<T>::normalizedNonNull() const IMATH_NOEXCEPT
+{
+    T l = length();
+    return Vec4 (x / l, y / l, z / l, w / l);
+}
+
+//-----------------------------
+// Stream output implementation
+//-----------------------------
+
+template <class T>
+std::ostream&
+operator<< (std::ostream& s, const Vec2<T>& v)
+{
+    return s << '(' << v.x << ' ' << v.y << ')';
+}
+
+template <class T>
+std::ostream&
+operator<< (std::ostream& s, const Vec3<T>& v)
+{
+    return s << '(' << v.x << ' ' << v.y << ' ' << v.z << ')';
+}
+
+template <class T>
+std::ostream&
+operator<< (std::ostream& s, const Vec4<T>& v)
+{
+    return s << '(' << v.x << ' ' << v.y << ' ' << v.z << ' ' << v.w << ')';
+}
+
+//-----------------------------------------
+// Implementation of reverse multiplication
+//-----------------------------------------
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec2<T>
+operator* (T a, const Vec2<T>& v) IMATH_NOEXCEPT
+{
+    return Vec2<T> (a * v.x, a * v.y);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec3<T>
+operator* (T a, const Vec3<T>& v) IMATH_NOEXCEPT
+{
+    return Vec3<T> (a * v.x, a * v.y, a * v.z);
+}
+
+template <class T>
+IMATH_HOSTDEVICE constexpr inline Vec4<T>
+operator* (T a, const Vec4<T>& v) IMATH_NOEXCEPT
+{
+    return Vec4<T> (a * v.x, a * v.y, a * v.z, a * v.w);
+}
+
+#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
+#    pragma warning(pop)
+#endif
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHVEC_H
diff --git a/src/Imath/ImathVecAlgo.h b/src/Imath/ImathVecAlgo.h
new file mode 100644 (file)
index 0000000..df62392
--- /dev/null
@@ -0,0 +1,96 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Algorithms applied to or in conjunction with points (Imath::Vec2
+// and Imath::Vec3).
+//
+// The assumption made is that these functions are called much
+// less often than the basic point functions or these functions
+// require more support classes.
+//
+
+#ifndef INCLUDED_IMATHVECALGO_H
+#define INCLUDED_IMATHVECALGO_H
+
+#include "ImathNamespace.h"
+#include "ImathVec.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+/// @cond Doxygen_Suppress
+//
+//  Note: doxygen doesn't understand these templates, so omit these
+//  functions from the docs.
+//
+
+/// Find the projection of vector `t` onto vector `s` (`Vec2`, `Vec3`, `Vec4`)
+///
+/// Only defined for floating-point types, e.g. `V2f`, `V3d`, etc.
+template <class Vec,
+          IMATH_ENABLE_IF(!std::is_integral<typename Vec::BaseType>::value)>
+IMATH_CONSTEXPR14 inline Vec
+project (const Vec& s, const Vec& t) IMATH_NOEXCEPT
+{
+    Vec sNormalized = s.normalized();
+    return sNormalized * (sNormalized ^ t);
+}
+
+/// Find a vector that is perpendicular to `s` and
+/// in the same plane as `s` and `t` (`Vec2`, `Vec3`, `Vec4`)
+///
+/// Only defined for floating-point types, e.g. `V2f`, `V3d`, etc.
+template <class Vec,
+          IMATH_ENABLE_IF(!std::is_integral<typename Vec::BaseType>::value)>
+constexpr inline Vec
+orthogonal (const Vec& s, const Vec& t) IMATH_NOEXCEPT
+{
+    return t - project (s, t);
+}
+
+/// Find the direction of a ray `s` after reflection
+/// off a plane with normal `t` (`Vec2`, `Vec3`, `Vec4`)
+///
+/// Only defined for floating-point types, e.g. `V2f`, `V3d`, etc.
+template <class Vec,
+          IMATH_ENABLE_IF(!std::is_integral<typename Vec::BaseType>::value)>
+constexpr inline Vec
+reflect (const Vec& s, const Vec& t) IMATH_NOEXCEPT
+{
+    return s - typename Vec::BaseType (2) * (s - project (t, s));
+}
+
+/// @endcond
+
+/// Find the vertex of triangle `(v0, v1, v2)` that is closest to point `p`
+/// (`Vec2`, `Vec3`, `Vec4`)
+template <class Vec>
+IMATH_CONSTEXPR14 Vec
+closestVertex (const Vec& v0, const Vec& v1, const Vec& v2, const Vec& p) IMATH_NOEXCEPT
+{
+    Vec nearest                    = v0;
+    typename Vec::BaseType neardot = (v0 - p).length2();
+    typename Vec::BaseType tmp     = (v1 - p).length2();
+
+    if (tmp < neardot)
+    {
+        neardot = tmp;
+        nearest = v1;
+    }
+
+    tmp = (v2 - p).length2();
+
+    if (tmp < neardot)
+    {
+        neardot = tmp;
+        nearest = v2;
+    }
+
+    return nearest;
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHVECALGO_H
diff --git a/src/Imath/half.cpp b/src/Imath/half.cpp
new file mode 100644 (file)
index 0000000..85db22f
--- /dev/null
@@ -0,0 +1,136 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Primary original authors:
+//     Florian Kainz <kainz@ilm.com>
+//     Rod Bogart <rgb@ilm.com>
+//
+
+//---------------------------------------------------------------------------
+//
+//     class half --
+//     implementation of non-inline members
+//
+//---------------------------------------------------------------------------
+
+#include "half.h"
+#include <assert.h>
+
+using namespace std;
+
+#if defined(IMATH_DLL)
+#    define EXPORT_CONST __declspec(dllexport)
+#else
+#    define EXPORT_CONST
+#endif
+
+//-------------------------------------------------------------
+// Lookup tables for half-to-float and float-to-half conversion
+//-------------------------------------------------------------
+
+// clang-format off
+
+#if !defined(IMATH_HALF_NO_LOOKUP_TABLE)
+// Omit the table entirely if IMATH_HALF_NO_LOOKUP_TABLE is
+// defined. Half-to-float conversion must be accomplished either by
+// F16C instructions or the bit-shift algorithm.
+const imath_half_uif_t imath_half_to_float_table_data[1 << 16] =
+#include "toFloat.h"
+
+extern "C" {
+EXPORT_CONST const imath_half_uif_t *imath_half_to_float_table = imath_half_to_float_table_data;
+} // extern "C"
+
+#endif
+
+// clang-format on
+
+//---------------------
+// Stream I/O operators
+//---------------------
+
+IMATH_EXPORT ostream&
+operator<< (ostream& os, half h)
+{
+    os << float (h);
+    return os;
+}
+
+IMATH_EXPORT istream&
+operator>> (istream& is, half& h)
+{
+    float f;
+    is >> f;
+    h = half (f);
+    return is;
+}
+
+//---------------------------------------
+// Functions to print the bit-layout of
+// floats and halfs, mostly for debugging
+//---------------------------------------
+
+IMATH_EXPORT void
+printBits (ostream& os, half h)
+{
+    unsigned short b = h.bits();
+
+    for (int i = 15; i >= 0; i--)
+    {
+        os << (((b >> i) & 1) ? '1' : '0');
+
+        if (i == 15 || i == 10)
+            os << ' ';
+    }
+}
+
+IMATH_EXPORT void
+printBits (ostream& os, float f)
+{
+    half::uif x;
+    x.f = f;
+
+    for (int i = 31; i >= 0; i--)
+    {
+        os << (((x.i >> i) & 1) ? '1' : '0');
+
+        if (i == 31 || i == 23)
+            os << ' ';
+    }
+}
+
+IMATH_EXPORT void
+printBits (char c[19], half h)
+{
+    unsigned short b = h.bits();
+
+    for (int i = 15, j = 0; i >= 0; i--, j++)
+    {
+        c[j] = (((b >> i) & 1) ? '1' : '0');
+
+        if (i == 15 || i == 10)
+            c[++j] = ' ';
+    }
+
+    c[18] = 0;
+}
+
+IMATH_EXPORT void
+printBits (char c[35], float f)
+{
+    half::uif x;
+    x.f = f;
+
+    for (int i = 31, j = 0; i >= 0; i--, j++)
+    {
+        c[j] = (((x.i >> i) & 1) ? '1' : '0');
+
+        if (i == 31 || i == 23)
+            c[++j] = ' ';
+    }
+
+    c[34] = 0;
+}
diff --git a/src/Imath/half.h b/src/Imath/half.h
new file mode 100644 (file)
index 0000000..92b4701
--- /dev/null
@@ -0,0 +1,990 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Primary original authors:
+//     Florian Kainz <kainz@ilm.com>
+//     Rod Bogart <rgb@ilm.com>
+//
+
+#ifndef IMATH_HALF_H_
+#define IMATH_HALF_H_
+
+#include "ImathExport.h"
+#include "ImathNamespace.h"
+#include "ImathPlatform.h"
+
+/// @file half.h
+/// The half type is a 16-bit floating number, compatible with the
+/// IEEE 754-2008 binary16 type.
+///
+/// **Representation of a 32-bit float:**
+///
+/// We assume that a float, f, is an IEEE 754 single-precision
+/// floating point number, whose bits are arranged as follows:
+///
+///     31 (msb)
+///     |
+///     | 30     23
+///     | |      |
+///     | |      | 22                    0 (lsb)
+///     | |      | |                     |
+///     X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
+///
+///     s e        m
+///
+/// S is the sign-bit, e is the exponent and m is the significand.
+///
+/// If e is between 1 and 254, f is a normalized number:
+///
+///             s    e-127
+///     f = (-1)  * 2      * 1.m
+///
+/// If e is 0, and m is not zero, f is a denormalized number:
+///
+///             s    -126
+///     f = (-1)  * 2      * 0.m
+///
+/// If e and m are both zero, f is zero:
+///
+///     f = 0.0
+///
+/// If e is 255, f is an "infinity" or "not a number" (NAN),
+/// depending on whether m is zero or not.
+///
+/// Examples:
+///
+///     0 00000000 00000000000000000000000 = 0.0
+///     0 01111110 00000000000000000000000 = 0.5
+///     0 01111111 00000000000000000000000 = 1.0
+///     0 10000000 00000000000000000000000 = 2.0
+///     0 10000000 10000000000000000000000 = 3.0
+///     1 10000101 11110000010000000000000 = -124.0625
+///     0 11111111 00000000000000000000000 = +infinity
+///     1 11111111 00000000000000000000000 = -infinity
+///     0 11111111 10000000000000000000000 = NAN
+///     1 11111111 11111111111111111111111 = NAN
+///
+/// **Representation of a 16-bit half:**
+///
+/// Here is the bit-layout for a half number, h:
+///
+///     15 (msb)
+///     |
+///     | 14  10
+///     | |   |
+///     | |   | 9        0 (lsb)
+///     | |   | |        |
+///     X XXXXX XXXXXXXXXX
+///
+///     s e     m
+///
+/// S is the sign-bit, e is the exponent and m is the significand.
+///
+/// If e is between 1 and 30, h is a normalized number:
+///
+///             s    e-15
+///     h = (-1)  * 2     * 1.m
+///
+/// If e is 0, and m is not zero, h is a denormalized number:
+///
+///             S    -14
+///     h = (-1)  * 2     * 0.m
+///
+/// If e and m are both zero, h is zero:
+///
+///     h = 0.0
+///
+/// If e is 31, h is an "infinity" or "not a number" (NAN),
+/// depending on whether m is zero or not.
+///
+/// Examples:
+///
+///     0 00000 0000000000 = 0.0
+///     0 01110 0000000000 = 0.5
+///     0 01111 0000000000 = 1.0
+///     0 10000 0000000000 = 2.0
+///     0 10000 1000000000 = 3.0
+///     1 10101 1111000001 = -124.0625
+///     0 11111 0000000000 = +infinity
+///     1 11111 0000000000 = -infinity
+///     0 11111 1000000000 = NAN
+///     1 11111 1111111111 = NAN
+///
+/// **Conversion via Lookup Table:**
+///
+/// Converting from half to float is performed by default using a
+/// lookup table. There are only 65,536 different half numbers; each
+/// of these numbers has been converted and stored in a table pointed
+/// to by the ``imath_half_to_float_table`` pointer.
+///
+/// Prior to Imath v3.1, conversion from float to half was
+/// accomplished with the help of an exponent look table, but this is
+/// now replaced with explicit bit shifting.
+///
+/// **Conversion via Hardware:**
+///
+/// For Imath v3.1, the conversion routines have been extended to use
+/// F16C SSE instructions whenever present and enabled by compiler
+/// flags.
+///
+/// **Conversion via Bit-Shifting**
+///
+/// If F16C SSE instructions are not available, conversion can be
+/// accomplished by a bit-shifting algorithm. For half-to-float
+/// conversion, this is generally slower than the lookup table, but it
+/// may be preferable when memory limits preclude storing of the
+/// 65,536-entry lookup table.
+///
+/// The lookup table symbol is included in the compilation even if
+/// ``IMATH_HALF_USE_LOOKUP_TABLE`` is false, because application code
+/// using the exported ``half.h`` may choose to enable the use of the table.
+///
+/// An implementation can eliminate the table from compilation by
+/// defining the ``IMATH_HALF_NO_LOOKUP_TABLE`` preprocessor symbol.
+/// Simply add:
+///
+///     #define IMATH_HALF_NO_LOOKUP_TABLE
+///
+/// before including ``half.h``, or define the symbol on the compile
+/// command line.
+///
+/// Furthermore, an implementation wishing to receive ``FE_OVERFLOW``
+/// and ``FE_UNDERFLOW`` floating point exceptions when converting
+/// float to half by the bit-shift algorithm can define the
+/// preprocessor symbol ``IMATH_HALF_ENABLE_FP_EXCEPTIONS`` prior to
+/// including ``half.h``:
+///
+///     #define IMATH_HALF_ENABLE_FP_EXCEPTIONS
+///
+/// **Conversion Performance Comparison:**
+///
+/// Testing on a Core i9, the timings are approximately:
+///
+/// half to float
+/// - table: 0.71 ns / call
+/// - no table: 1.06 ns / call
+/// - f16c: 0.45 ns / call
+///
+/// float-to-half:
+/// - original: 5.2 ns / call
+/// - no exp table + opt: 1.27 ns / call
+/// - f16c: 0.45 ns / call
+///
+/// **Note:** the timing above depends on the distribution of the
+/// floats in question.
+///
+
+#ifdef __CUDA_ARCH__
+// do not include intrinsics headers on Cuda
+#elif defined(_WIN32)
+#    include <intrin.h>
+#elif defined(__x86_64__)
+#    include <x86intrin.h>
+#elif defined(__F16C__)
+#    include <immintrin.h>
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+
+#ifdef IMATH_HALF_ENABLE_FP_EXCEPTIONS
+#    include <fenv.h>
+#endif
+
+//-------------------------------------------------------------------------
+// Limits
+//
+// Visual C++ will complain if HALF_DENORM_MIN, HALF_NRM_MIN etc. are not float
+// constants, but at least one other compiler (gcc 2.96) produces incorrect
+// results if they are.
+//-------------------------------------------------------------------------
+
+#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
+
+/// Smallest positive denormalized half
+#    define HALF_DENORM_MIN 5.96046448e-08f
+/// Smallest positive normalized half
+#    define HALF_NRM_MIN 6.10351562e-05f
+/// Smallest positive normalized half
+#    define HALF_MIN 6.10351562e-05f
+/// Largest positive half
+#    define HALF_MAX 65504.0f
+/// Smallest positive e for which ``half(1.0 + e) != half(1.0)``
+#    define HALF_EPSILON 0.00097656f
+#else
+/// Smallest positive denormalized half
+#    define HALF_DENORM_MIN 5.96046448e-08
+/// Smallest positive normalized half
+#    define HALF_NRM_MIN 6.10351562e-05
+/// Smallest positive normalized half
+#    define HALF_MIN 6.10351562e-05f
+/// Largest positive half
+#    define HALF_MAX 65504.0
+/// Smallest positive e for which ``half(1.0 + e) != half(1.0)``
+#    define HALF_EPSILON 0.00097656
+#endif
+
+/// Number of digits in mantissa (significand + hidden leading 1)
+#define HALF_MANT_DIG 11
+/// Number of base 10 digits that can be represented without change:
+///
+/// ``floor( (HALF_MANT_DIG - 1) * log10(2) ) => 3.01... -> 3``
+#define HALF_DIG 3
+/// Number of base-10 digits that are necessary to uniquely represent
+/// all distinct values:
+/// 
+/// ``ceil(HALF_MANT_DIG * log10(2) + 1) => 4.31... -> 5``
+#define HALF_DECIMAL_DIG 5
+/// Base of the exponent
+#define HALF_RADIX 2
+/// Minimum negative integer such that ``HALF_RADIX`` raised to the power
+/// of one less than that integer is a normalized half
+#define HALF_DENORM_MIN_EXP -13
+/// Maximum positive integer such that ``HALF_RADIX`` raised to the power
+/// of one less than that integer is a normalized half
+#define HALF_MAX_EXP 16
+/// Minimum positive integer such that 10 raised to that power is a
+/// normalized half
+#define HALF_DENORM_MIN_10_EXP -4
+/// Maximum positive integer such that 10 raised to that power is a
+/// normalized half
+#define HALF_MAX_10_EXP 4
+
+/// a type for both C-only programs and C++ to use the same utilities
+typedef union imath_half_uif
+{
+    uint32_t i;
+    float f;
+} imath_half_uif_t;
+
+/// a type for both C-only programs and C++ to use the same utilities
+typedef uint16_t imath_half_bits_t;
+
+#if !defined(__cplusplus) && !defined(__CUDACC__)
+/// if we're in a C-only context, alias the half bits type to half
+typedef imath_half_bits_t half;
+#endif
+
+#if !defined(IMATH_HALF_NO_LOOKUP_TABLE)
+#    if defined(__cplusplus)
+extern "C"
+#    else
+extern
+#    endif
+    IMATH_EXPORT const imath_half_uif_t* imath_half_to_float_table;
+#endif
+
+///
+/// Convert half to float
+///
+
+static inline float
+imath_half_to_float (imath_half_bits_t h)
+{
+#if defined(__F16C__)
+    // NB: The intel implementation does seem to treat NaN slightly
+    // different than the original toFloat table does (i.e. where the
+    // 1 bits are, meaning the signalling or not bits). This seems
+    // benign, given that the original library didn't really deal with
+    // signalling vs non-signalling NaNs
+#    ifdef _MSC_VER
+    /* msvc does not seem to have cvtsh_ss :( */
+    return _mm_cvtss_f32 (_mm_cvtph_ps (_mm_set1_epi16 (h)));
+#    else
+    return _cvtsh_ss (h);
+#    endif
+#elif defined(IMATH_HALF_USE_LOOKUP_TABLE) && !defined(IMATH_HALF_NO_LOOKUP_TABLE)
+    return imath_half_to_float_table[h].f;
+#else
+    imath_half_uif_t v;
+    // this code would be clearer, although it does appear to be faster
+    // (1.06 vs 1.08 ns/call) to avoid the constants and just do 4
+    // shifts.
+    //
+    uint32_t hexpmant = ( (uint32_t)(h) << 17 ) >> 4;
+    v.i = ((uint32_t)(h >> 15)) << 31;
+
+    // the likely really does help if most of your numbers are "normal" half numbers
+    if (IMATH_LIKELY ((hexpmant >= 0x00800000)))
+    {
+        v.i |= hexpmant;
+        // either we are a normal number, in which case add in the bias difference
+        // otherwise make sure all exponent bits are set
+        if (IMATH_LIKELY ((hexpmant < 0x0f800000)))
+            v.i += 0x38000000;
+        else
+            v.i |= 0x7f800000;
+    }
+    else if (hexpmant != 0)
+    {
+        // exponent is 0 because we're denormal, don't have to extract
+        // the mantissa, can just use as is
+        //
+        //
+        // other compilers may provide count-leading-zeros primitives,
+        // but we need the community to inform us of the variants
+        uint32_t lc;
+#    if defined(_MSC_VER) && (_M_IX86 || _M_X64)
+        lc = __lzcnt (hexpmant);
+#    elif defined(__GNUC__) || defined(__clang__)
+        lc = (uint32_t) __builtin_clz (hexpmant);
+#    else
+        lc = 0;
+        while (0 == ((hexpmant << lc) & 0x80000000))
+            ++lc;
+#    endif
+        lc -= 8;
+        // so nominally we want to remove that extra bit we shifted
+        // up, but we are going to add that bit back in, then subtract
+        // from it with the 0x38800000 - (lc << 23)....
+        //
+        // by combining, this allows us to skip the & operation (and
+        // remove a constant)
+        //
+        // hexpmant &= ~0x00800000;
+        v.i |= 0x38800000;
+        // lc is now x, where the desired exponent is then
+        // -14 - lc
+        // + 127 -> new exponent
+        v.i |= (hexpmant << lc);
+        v.i -= (lc << 23);
+    }
+    return v.f;
+#endif
+}
+
+///
+/// Convert half to float
+///
+/// Note: This only supports the "round to even" rounding mode, which
+/// was the only mode supported by the original OpenEXR library
+///
+
+static inline imath_half_bits_t
+imath_float_to_half (float f)
+{
+#if defined(__F16C__)
+#    ifdef _MSC_VER
+    // msvc does not seem to have cvtsh_ss :(
+    return _mm_extract_epi16 (
+        _mm_cvtps_ph (_mm_set_ss (f), (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)),
+        0);
+#    else
+    // preserve the fixed rounding mode to nearest
+    return _cvtss_sh (f, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
+#    endif
+#else
+    imath_half_uif_t v;
+    imath_half_bits_t ret;
+    uint32_t e, m, ui, r, shift;
+
+    v.f = f;
+
+    ui  = (v.i & ~0x80000000);
+    ret = ((v.i >> 16) & 0x8000);
+
+    // exponent large enough to result in a normal number, round and return
+    if (ui >= 0x38800000)
+    {
+        // inf or nan
+        if (IMATH_UNLIKELY (ui >= 0x7f800000))
+        {
+            ret |= 0x7c00;
+            if (ui == 0x7f800000)
+                return ret;
+            m = (ui & 0x7fffff) >> 13;
+            // make sure we have at least one bit after shift to preserve nan-ness
+            return ret | (uint16_t)m | (uint16_t)(m == 0);
+        }
+
+        // too large, round to infinity
+        if (IMATH_UNLIKELY (ui > 0x477fefff))
+        {
+#    ifdef IMATH_HALF_ENABLE_FP_EXCEPTIONS
+            feraiseexcept (FE_OVERFLOW);
+#    endif
+            return ret | 0x7c00;
+        }
+
+        ui -= 0x38000000;
+        ui = ((ui + 0x00000fff + ((ui >> 13) & 1)) >> 13);
+        return ret | (uint16_t)ui;
+    }
+
+    // zero or flush to 0
+    if (ui < 0x33000001)
+    {
+#    ifdef IMATH_HALF_ENABLE_FP_EXCEPTIONS
+        if (ui == 0)
+            return ret;
+        feraiseexcept (FE_UNDERFLOW);
+#    endif
+        return ret;
+    }
+
+    // produce a denormalized half
+    e     = (ui >> 23);
+    shift = 0x7e - e;
+    m     = 0x800000 | (ui & 0x7fffff);
+    r     = m << (32 - shift);
+    ret |= (m >> shift);
+    if (r > 0x80000000 || (r == 0x80000000 && (ret & 0x1) != 0))
+        ++ret;
+    return ret;
+#endif
+}
+
+////////////////////////////////////////
+
+#ifdef __cplusplus
+
+#    include <iostream>
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+///
+///
+/// class half represents a 16-bit floating point number
+///
+/// Type half can represent positive and negative numbers whose
+/// magnitude is between roughly 6.1e-5 and 6.5e+4 with a relative
+/// error of 9.8e-4; numbers smaller than 6.1e-5 can be represented
+/// with an absolute error of 6.0e-8.  All integers from -2048 to
+/// +2048 can be represented exactly.
+///
+/// Type half behaves (almost) like the built-in C++ floating point
+/// types.  In arithmetic expressions, half, float and double can be
+/// mixed freely.  Here are a few examples:
+///
+///     half a (3.5);
+///     float b (a + sqrt (a));
+///     a += b;
+///     b += a;
+///     b = a + 7;
+///
+/// Conversions from half to float are lossless; all half numbers
+/// are exactly representable as floats.
+///
+/// Conversions from float to half may not preserve a float's value
+/// exactly.  If a float is not representable as a half, then the
+/// float value is rounded to the nearest representable half.  If a
+/// float value is exactly in the middle between the two closest
+/// representable half values, then the float value is rounded to
+/// the closest half whose least significant bit is zero.
+///
+/// Overflows during float-to-half conversions cause arithmetic
+/// exceptions.  An overflow occurs when the float value to be
+/// converted is too large to be represented as a half, or if the
+/// float value is an infinity or a NAN.
+///
+/// The implementation of type half makes the following assumptions
+/// about the implementation of the built-in C++ types:
+///
+/// * float is an IEEE 754 single-precision number
+/// * sizeof (float) == 4
+/// * sizeof (unsigned int) == sizeof (float)
+/// * alignof (unsigned int) == alignof (float)
+/// * sizeof (uint16_t) == 2
+///
+
+class IMATH_EXPORT_TYPE half
+{
+  public:
+    /// A special tag that lets us initialize a half from the raw bits.
+    enum IMATH_EXPORT_ENUM FromBitsTag
+    {
+        FromBits
+    };
+
+    /// @{
+    ///        @name Constructors
+
+    /// Default construction provides no initialization (hence it is
+    /// not constexpr).
+    half() IMATH_NOEXCEPT = default;
+
+    /// Construct from float
+    half (float f) IMATH_NOEXCEPT;
+
+    /// Construct from bit-vector
+    constexpr half (FromBitsTag, uint16_t bits) IMATH_NOEXCEPT;
+
+    /// Copy constructor
+    constexpr half (const half&) IMATH_NOEXCEPT = default;
+
+    /// Move constructor
+    constexpr half (half&&) IMATH_NOEXCEPT = default;
+
+    /// Destructor
+    ~half() IMATH_NOEXCEPT = default;
+
+    /// @}
+
+    /// Conversion to float
+    operator float() const IMATH_NOEXCEPT;
+
+    /// @{
+    /// @name Basic Algebra
+
+    /// Unary minus
+    constexpr half operator-() const IMATH_NOEXCEPT;
+
+    /// Assignment
+    half& operator= (const half& h) IMATH_NOEXCEPT = default;
+
+    /// Move assignment
+    half& operator= (half&& h) IMATH_NOEXCEPT = default;
+
+    /// Assignment from float
+    half& operator= (float f) IMATH_NOEXCEPT;
+
+    /// Addition assignment
+    half& operator+= (half h) IMATH_NOEXCEPT;
+
+    /// Addition assignment from float
+    half& operator+= (float f) IMATH_NOEXCEPT;
+
+    /// Subtraction assignment
+    half& operator-= (half h) IMATH_NOEXCEPT;
+
+    /// Subtraction assignment from float
+    half& operator-= (float f) IMATH_NOEXCEPT;
+
+    /// Multiplication assignment
+    half& operator*= (half h) IMATH_NOEXCEPT;
+
+    /// Multiplication assignment from float
+    half& operator*= (float f) IMATH_NOEXCEPT;
+
+    /// Division assignment
+    half& operator/= (half h) IMATH_NOEXCEPT;
+
+    /// Division assignment from float
+    half& operator/= (float f) IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// Round to n-bit precision (n should be between 0 and 10).
+    /// After rounding, the significand's 10-n least significant
+    /// bits will be zero.
+    IMATH_CONSTEXPR14 half round (unsigned int n) const IMATH_NOEXCEPT;
+
+    /// @{
+    /// @name Classification
+
+    /// Return true if a normalized number, a denormalized number, or
+    /// zero.
+    constexpr bool isFinite() const IMATH_NOEXCEPT;
+
+    /// Return true if a normalized number.
+    constexpr bool isNormalized() const IMATH_NOEXCEPT;
+
+    /// Return true if a denormalized number.
+    constexpr bool isDenormalized() const IMATH_NOEXCEPT;
+
+    /// Return true if zero.
+    constexpr bool isZero() const IMATH_NOEXCEPT;
+
+    /// Return true if NAN.
+    constexpr bool isNan() const IMATH_NOEXCEPT;
+
+    /// Return true if a positive or a negative infinity
+    constexpr bool isInfinity() const IMATH_NOEXCEPT;
+
+    /// Return true if the sign bit is set (negative)
+    constexpr bool isNegative() const IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Special values
+
+    /// Return +infinity
+    static constexpr half posInf() IMATH_NOEXCEPT;
+
+    /// Return -infinity
+    static constexpr half negInf() IMATH_NOEXCEPT;
+
+    /// Returns a NAN with the bit pattern 0111111111111111
+    static constexpr half qNan() IMATH_NOEXCEPT;
+
+    /// Return a NAN with the bit pattern 0111110111111111
+    static constexpr half sNan() IMATH_NOEXCEPT;
+
+    /// @}
+
+    /// @{
+    /// @name Access to the internal representation
+
+    /// Return the bit pattern
+    constexpr uint16_t bits () const IMATH_NOEXCEPT;
+
+    /// Set the bit pattern
+    IMATH_CONSTEXPR14 void setBits (uint16_t bits) IMATH_NOEXCEPT;
+
+    /// @}
+
+  public:
+    static_assert (sizeof (float) == sizeof (uint32_t),
+                   "Assumption about the size of floats correct");
+    using uif = imath_half_uif;
+
+  private:
+
+    constexpr uint16_t mantissa() const IMATH_NOEXCEPT;
+    constexpr uint16_t exponent() const IMATH_NOEXCEPT;
+
+    uint16_t _h;
+};
+
+//----------------------------
+// Half-from-float constructor
+//----------------------------
+
+inline half::half (float f) IMATH_NOEXCEPT
+    : _h (imath_float_to_half (f))
+{
+}
+
+//------------------------------------------
+// Half from raw bits constructor
+//------------------------------------------
+
+inline constexpr half::half (FromBitsTag, uint16_t bits) IMATH_NOEXCEPT : _h (bits)
+{}
+
+//-------------------------
+// Half-to-float conversion
+//-------------------------
+
+inline half::operator float() const IMATH_NOEXCEPT
+{
+    return imath_half_to_float (_h);
+}
+
+//-------------------------
+// Round to n-bit precision
+//-------------------------
+
+inline IMATH_CONSTEXPR14 half
+half::round (unsigned int n) const IMATH_NOEXCEPT
+{
+    //
+    // Parameter check.
+    //
+
+    if (n >= 10)
+        return *this;
+
+    //
+    // Disassemble h into the sign, s,
+    // and the combined exponent and significand, e.
+    //
+
+    uint16_t s = _h & 0x8000;
+    uint16_t e = _h & 0x7fff;
+
+    //
+    // Round the exponent and significand to the nearest value
+    // where ones occur only in the (10-n) most significant bits.
+    // Note that the exponent adjusts automatically if rounding
+    // up causes the significand to overflow.
+    //
+
+    e >>= 9 - n;
+    e += e & 1;
+    e <<= 9 - n;
+
+    //
+    // Check for exponent overflow.
+    //
+
+    if (e >= 0x7c00)
+    {
+        //
+        // Overflow occurred -- truncate instead of rounding.
+        //
+
+        e = _h;
+        e >>= 10 - n;
+        e <<= 10 - n;
+    }
+
+    //
+    // Put the original sign bit back.
+    //
+
+    half h (FromBits, s | e);
+
+    return h;
+}
+
+//-----------------------
+// Other inline functions
+//-----------------------
+
+inline constexpr half
+half::operator-() const IMATH_NOEXCEPT
+{
+    return half (FromBits, bits() ^ 0x8000);
+}
+
+inline half&
+half::operator= (float f) IMATH_NOEXCEPT
+{
+    *this = half (f);
+    return *this;
+}
+
+inline half&
+half::operator+= (half h) IMATH_NOEXCEPT
+{
+    *this = half (float (*this) + float (h));
+    return *this;
+}
+
+inline half&
+half::operator+= (float f) IMATH_NOEXCEPT
+{
+    *this = half (float (*this) + f);
+    return *this;
+}
+
+inline half&
+half::operator-= (half h) IMATH_NOEXCEPT
+{
+    *this = half (float (*this) - float (h));
+    return *this;
+}
+
+inline half&
+half::operator-= (float f) IMATH_NOEXCEPT
+{
+    *this = half (float (*this) - f);
+    return *this;
+}
+
+inline half&
+half::operator*= (half h) IMATH_NOEXCEPT
+{
+    *this = half (float (*this) * float (h));
+    return *this;
+}
+
+inline half&
+half::operator*= (float f) IMATH_NOEXCEPT
+{
+    *this = half (float (*this) * f);
+    return *this;
+}
+
+inline half&
+half::operator/= (half h) IMATH_NOEXCEPT
+{
+    *this = half (float (*this) / float (h));
+    return *this;
+}
+
+inline half&
+half::operator/= (float f) IMATH_NOEXCEPT
+{
+    *this = half (float (*this) / f);
+    return *this;
+}
+
+inline constexpr uint16_t
+half::mantissa() const IMATH_NOEXCEPT
+{
+    return _h & 0x3ff;
+}
+
+inline constexpr uint16_t
+half::exponent() const IMATH_NOEXCEPT
+{
+    return (_h >> 10) & 0x001f;
+}
+
+inline constexpr bool
+half::isFinite() const IMATH_NOEXCEPT
+{
+    return exponent() < 31;
+}
+
+inline constexpr bool
+half::isNormalized() const IMATH_NOEXCEPT
+{
+    return exponent() > 0 && exponent() < 31;
+}
+
+inline constexpr bool
+half::isDenormalized() const IMATH_NOEXCEPT
+{
+    return exponent() == 0 && mantissa() != 0;
+}
+
+inline constexpr bool
+half::isZero() const IMATH_NOEXCEPT
+{
+    return (_h & 0x7fff) == 0;
+}
+
+inline constexpr bool
+half::isNan() const IMATH_NOEXCEPT
+{
+    return exponent() == 31 && mantissa() != 0;
+}
+
+inline constexpr bool
+half::isInfinity() const IMATH_NOEXCEPT
+{
+    return exponent() == 31 && mantissa() == 0;
+}
+
+inline constexpr bool
+half::isNegative() const IMATH_NOEXCEPT
+{
+    return (_h & 0x8000) != 0;
+}
+
+inline constexpr half
+half::posInf() IMATH_NOEXCEPT
+{
+    return half (FromBits, 0x7c00);
+}
+
+inline constexpr half
+half::negInf() IMATH_NOEXCEPT
+{
+    return half (FromBits, 0xfc00);
+}
+
+inline constexpr half
+half::qNan() IMATH_NOEXCEPT
+{
+    return half (FromBits, 0x7fff);
+}
+
+inline constexpr half
+half::sNan() IMATH_NOEXCEPT
+{
+    return half (FromBits, 0x7dff);
+}
+
+inline constexpr uint16_t
+half::bits() const IMATH_NOEXCEPT
+{
+    return _h;
+}
+
+inline IMATH_CONSTEXPR14 void
+half::setBits (uint16_t bits) IMATH_NOEXCEPT
+{
+    _h = bits;
+}
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+/// Output h to os, formatted as a float
+IMATH_EXPORT std::ostream& operator<< (std::ostream& os, IMATH_INTERNAL_NAMESPACE::half h);
+
+/// Input h from is
+IMATH_EXPORT std::istream& operator>> (std::istream& is, IMATH_INTERNAL_NAMESPACE::half& h);
+
+#include <limits>
+
+namespace std
+{
+
+template <> class numeric_limits<IMATH_INTERNAL_NAMESPACE::half>
+{
+public:
+    static const bool is_specialized = true;
+
+    static constexpr IMATH_INTERNAL_NAMESPACE::half min () IMATH_NOEXCEPT
+    {
+        return IMATH_INTERNAL_NAMESPACE::half (IMATH_INTERNAL_NAMESPACE::half::FromBits, 0x0400); /*HALF_MIN*/
+    }
+    static constexpr IMATH_INTERNAL_NAMESPACE::half max () IMATH_NOEXCEPT
+    {
+        return IMATH_INTERNAL_NAMESPACE::half (IMATH_INTERNAL_NAMESPACE::half::FromBits, 0x7bff); /*HALF_MAX*/
+    }
+    static constexpr IMATH_INTERNAL_NAMESPACE::half lowest ()
+    {
+        return IMATH_INTERNAL_NAMESPACE::half (IMATH_INTERNAL_NAMESPACE::half::FromBits, 0xfbff); /* -HALF_MAX */
+    }
+
+    static constexpr int  digits       = HALF_MANT_DIG;
+    static constexpr int  digits10     = HALF_DIG;
+    static constexpr int  max_digits10 = HALF_DECIMAL_DIG;
+    static constexpr bool is_signed    = true;
+    static constexpr bool is_integer   = false;
+    static constexpr bool is_exact     = false;
+    static constexpr int  radix        = HALF_RADIX;
+    static constexpr IMATH_INTERNAL_NAMESPACE::half epsilon () IMATH_NOEXCEPT
+    {
+        return IMATH_INTERNAL_NAMESPACE::half (IMATH_INTERNAL_NAMESPACE::half::FromBits, 0x1400); /*HALF_EPSILON*/
+    }
+    static constexpr IMATH_INTERNAL_NAMESPACE::half round_error () IMATH_NOEXCEPT
+    {
+        return IMATH_INTERNAL_NAMESPACE::half (IMATH_INTERNAL_NAMESPACE::half::FromBits, 0x3800); /*0.5*/
+    }
+
+    static constexpr int min_exponent   = HALF_DENORM_MIN_EXP;
+    static constexpr int min_exponent10 = HALF_DENORM_MIN_10_EXP;
+    static constexpr int max_exponent   = HALF_MAX_EXP;
+    static constexpr int max_exponent10 = HALF_MAX_10_EXP;
+
+    static constexpr bool               has_infinity      = true;
+    static constexpr bool               has_quiet_NaN     = true;
+    static constexpr bool               has_signaling_NaN = true;
+    static constexpr float_denorm_style has_denorm        = denorm_present;
+    static constexpr bool               has_denorm_loss   = false;
+    static constexpr IMATH_INTERNAL_NAMESPACE::half               infinity () IMATH_NOEXCEPT
+    {
+        return IMATH_INTERNAL_NAMESPACE::half (IMATH_INTERNAL_NAMESPACE::half::FromBits, 0x7c00); /*half::posInf()*/
+    }
+    static constexpr IMATH_INTERNAL_NAMESPACE::half quiet_NaN () IMATH_NOEXCEPT
+    {
+        return IMATH_INTERNAL_NAMESPACE::half (IMATH_INTERNAL_NAMESPACE::half::FromBits, 0x7fff); /*half::qNan()*/
+    }
+    static constexpr IMATH_INTERNAL_NAMESPACE::half signaling_NaN () IMATH_NOEXCEPT
+    {
+        return IMATH_INTERNAL_NAMESPACE::half (IMATH_INTERNAL_NAMESPACE::half::FromBits, 0x7dff); /*half::sNan()*/
+    }
+    static constexpr IMATH_INTERNAL_NAMESPACE::half denorm_min () IMATH_NOEXCEPT
+    {
+        return IMATH_INTERNAL_NAMESPACE::half (IMATH_INTERNAL_NAMESPACE::half::FromBits, 0x0001); /*HALF_DENORM_MIN*/
+    }
+
+    static constexpr bool is_iec559  = false;
+    static constexpr bool is_bounded = false;
+    static constexpr bool is_modulo  = false;
+
+    static constexpr bool              traps           = true;
+    static constexpr bool              tinyness_before = false;
+    static constexpr float_round_style round_style     = round_to_nearest;
+};
+
+} // namespace std
+
+//----------
+// Debugging
+//----------
+
+IMATH_EXPORT void printBits (std::ostream& os, IMATH_INTERNAL_NAMESPACE::half h);
+IMATH_EXPORT void printBits (std::ostream& os, float f);
+IMATH_EXPORT void printBits (char c[19], IMATH_INTERNAL_NAMESPACE::half h);
+IMATH_EXPORT void printBits (char c[35], float f);
+
+#    if !defined(__CUDACC__) && !defined(__CUDA_FP16_HPP__)
+using half = IMATH_INTERNAL_NAMESPACE::half;
+#    else
+#        include <cuda_fp16.h>
+#    endif
+
+#endif // __cplusplus
+
+#endif // IMATH_HALF_H_
diff --git a/src/Imath/halfFunction.h b/src/Imath/halfFunction.h
new file mode 100644 (file)
index 0000000..c1e456f
--- /dev/null
@@ -0,0 +1,147 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//---------------------------------------------------------------------------
+//
+//     halfFunction<T> -- a class for fast evaluation
+//                        of half --> T functions
+//
+//     The constructor for a halfFunction object,
+//
+//         halfFunction (function,
+//                       domainMin, domainMax,
+//                       defaultValue,
+//                       posInfValue, negInfValue,
+//                       nanValue);
+//
+//     evaluates the function for all finite half values in the interval
+//     [domainMin, domainMax], and stores the results in a lookup table.
+//     For finite half values that are not in [domainMin, domainMax], the
+//     constructor stores defaultValue in the table.  For positive infinity,
+//     negative infinity and NANs, posInfValue, negInfValue and nanValue
+//     are stored in the table.
+//
+//     The tabulated function can then be evaluated quickly for arbitrary
+//     half values by calling the the halfFunction object's operator()
+//     method.
+//
+//     Example:
+//
+//         #include <math.h>
+//         #include <halfFunction.h>
+//
+//         halfFunction<half> hsin (sin);
+//
+//         halfFunction<half> hsqrt (sqrt,             // function
+//                                   0, HALF_MAX,      // domain
+//                                   half::qNan(),     // sqrt(x) for x < 0
+//                                   half::posInf(),   // sqrt(+inf)
+//                                   half::qNan(),     // sqrt(-inf)
+//                                   half::qNan());    // sqrt(nan)
+//
+//         half x = hsin (1);
+//         half y = hsqrt (3.5);
+//
+//---------------------------------------------------------------------------
+
+#ifndef _HALF_FUNCTION_H_
+#define _HALF_FUNCTION_H_
+
+/// @cond Doxygen_Suppress
+
+#include "half.h"
+
+#include "ImathConfig.h"
+#ifndef IMATH_HAVE_LARGE_STACK
+#    include <string.h> // need this for memset
+#else
+#endif
+
+#include <float.h>
+
+template <class T> class halfFunction
+{
+  public:
+    //------------
+    // Constructor
+    //------------
+
+    template <class Function>
+    halfFunction (Function f,
+                  half domainMin = -HALF_MAX,
+                  half domainMax = HALF_MAX,
+                  T defaultValue = 0,
+                  T posInfValue  = 0,
+                  T negInfValue  = 0,
+                  T nanValue     = 0);
+
+#ifndef IMATH_HAVE_LARGE_STACK
+    ~halfFunction() { delete[] _lut; }
+    halfFunction (const halfFunction&) = delete;
+    halfFunction& operator= (const halfFunction&) = delete;
+    halfFunction (halfFunction&&)                 = delete;
+    halfFunction& operator= (halfFunction&&) = delete;
+#endif
+
+    //-----------
+    // Evaluation
+    //-----------
+
+    T operator() (half x) const;
+
+  private:
+#ifdef IMATH_HAVE_LARGE_STACK
+    T _lut[1 << 16];
+#else
+    T* _lut;
+#endif
+};
+
+//---------------
+// Implementation
+//---------------
+
+template <class T>
+template <class Function>
+halfFunction<T>::halfFunction (Function f,
+                               half domainMin,
+                               half domainMax,
+                               T defaultValue,
+                               T posInfValue,
+                               T negInfValue,
+                               T nanValue)
+{
+#ifndef IMATH_HAVE_LARGE_STACK
+    _lut = new T[1 << 16];
+#endif
+
+    for (int i = 0; i < (1 << 16); i++)
+    {
+        half x;
+        x.setBits (i);
+
+        if (x.isNan())
+            _lut[i] = nanValue;
+        else if (x.isInfinity())
+            _lut[i] = x.isNegative() ? negInfValue : posInfValue;
+        else if (x < domainMin || x > domainMax)
+            _lut[i] = defaultValue;
+        else
+            _lut[i] = f (x);
+    }
+}
+
+template <class T>
+inline T
+halfFunction<T>::operator() (half x) const
+{
+    return _lut[x.bits()];
+}
+
+
+/// @endcond
+
+
+#endif
diff --git a/src/Imath/halfLimits.h b/src/Imath/halfLimits.h
new file mode 100644 (file)
index 0000000..5e5dd3b
--- /dev/null
@@ -0,0 +1,26 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifndef INCLUDED_HALF_LIMITS_H
+#define INCLUDED_HALF_LIMITS_H
+
+// Warn if half.h hasn't being included
+#ifndef IMATH_HALF_H_
+//
+// This file is now deprecated. It previously included the
+// specialization of std::numeric_limits<half>, but those now appear
+// directly in half.h, because they should be regarded as inseperable
+// from the half class.
+//
+
+#ifdef __GNUC__
+#warning "ImathLimits is deprecated; use #include <half.h>"
+#else
+#pragma message("ImathLimits is deprecated; use #include <half.h>")
+#endif
+
+#include "half.h"
+#endif
+#endif
diff --git a/src/Imath/toFloat.cpp b/src/Imath/toFloat.cpp
new file mode 100644 (file)
index 0000000..20e750d
--- /dev/null
@@ -0,0 +1,130 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//---------------------------------------------------------------------------
+//
+//     toFloat
+//
+//     A program to generate the lookup table for half-to-float
+//     conversion needed by class half.
+//     The program loops over all 65536 possible half numbers,
+//     converts each of them to a float, and prints the result.
+//
+//---------------------------------------------------------------------------
+
+#include <iomanip>
+#include <iostream>
+
+using namespace std;
+
+//---------------------------------------------------
+// Interpret an unsigned short bit pattern as a half,
+// and convert that half to the corresponding float's
+// bit pattern.
+//---------------------------------------------------
+
+unsigned int
+halfToFloat (unsigned short y)
+{
+
+    int s = (y >> 15) & 0x00000001;
+    int e = (y >> 10) & 0x0000001f;
+    int m = y & 0x000003ff;
+
+    if (e == 0)
+    {
+        if (m == 0)
+        {
+            //
+            // Plus or minus zero
+            //
+
+            return s << 31;
+        }
+        else
+        {
+            //
+            // Denormalized number -- renormalize it
+            //
+
+            while (!(m & 0x00000400))
+            {
+                m <<= 1;
+                e -= 1;
+            }
+
+            e += 1;
+            m &= ~0x00000400;
+        }
+    }
+    else if (e == 31)
+    {
+        if (m == 0)
+        {
+            //
+            // Positive or negative infinity
+            //
+
+            return (s << 31) | 0x7f800000;
+        }
+        else
+        {
+            //
+            // Nan -- preserve sign and significand bits
+            //
+
+            return (s << 31) | 0x7f800000 | (m << 13);
+        }
+    }
+
+    //
+    // Normalized number
+    //
+
+    e = e + (127 - 15);
+    m = m << 13;
+
+    //
+    // Assemble s, e and m.
+    //
+
+    return (s << 31) | (e << 23) | m;
+}
+
+//---------------------------------------------
+// Main - prints the half-to-float lookup table
+//---------------------------------------------
+
+int
+main()
+{
+    cout.precision (9);
+    cout.setf (ios_base::hex, ios_base::basefield);
+
+    cout << "//\n"
+            "// This is an automatically generated file.\n"
+            "// Do not edit.\n"
+            "//\n\n";
+
+    cout << "{\n    ";
+
+    const int iMax = (1 << 16);
+
+    for (int i = 0; i < iMax; i++)
+    {
+        cout << "{0x" << setfill ('0') << setw (8) << halfToFloat (i) << "}, ";
+
+        if (i % 4 == 3)
+        {
+            cout << "\n";
+
+            if (i < iMax - 1)
+                cout << "    ";
+        }
+    }
+
+    cout << "};\n";
+    return 0;
+}
diff --git a/src/Imath/toFloat.h b/src/Imath/toFloat.h
new file mode 100644 (file)
index 0000000..5d39a21
--- /dev/null
@@ -0,0 +1,16398 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// This is an automatically generated file.
+// Do not edit.
+//
+
+// clang-format off
+{
+    {0x00000000}, {0x33800000}, {0x34000000}, {0x34400000}, 
+    {0x34800000}, {0x34a00000}, {0x34c00000}, {0x34e00000}, 
+    {0x35000000}, {0x35100000}, {0x35200000}, {0x35300000}, 
+    {0x35400000}, {0x35500000}, {0x35600000}, {0x35700000}, 
+    {0x35800000}, {0x35880000}, {0x35900000}, {0x35980000}, 
+    {0x35a00000}, {0x35a80000}, {0x35b00000}, {0x35b80000}, 
+    {0x35c00000}, {0x35c80000}, {0x35d00000}, {0x35d80000}, 
+    {0x35e00000}, {0x35e80000}, {0x35f00000}, {0x35f80000}, 
+    {0x36000000}, {0x36040000}, {0x36080000}, {0x360c0000}, 
+    {0x36100000}, {0x36140000}, {0x36180000}, {0x361c0000}, 
+    {0x36200000}, {0x36240000}, {0x36280000}, {0x362c0000}, 
+    {0x36300000}, {0x36340000}, {0x36380000}, {0x363c0000}, 
+    {0x36400000}, {0x36440000}, {0x36480000}, {0x364c0000}, 
+    {0x36500000}, {0x36540000}, {0x36580000}, {0x365c0000}, 
+    {0x36600000}, {0x36640000}, {0x36680000}, {0x366c0000}, 
+    {0x36700000}, {0x36740000}, {0x36780000}, {0x367c0000}, 
+    {0x36800000}, {0x36820000}, {0x36840000}, {0x36860000}, 
+    {0x36880000}, {0x368a0000}, {0x368c0000}, {0x368e0000}, 
+    {0x36900000}, {0x36920000}, {0x36940000}, {0x36960000}, 
+    {0x36980000}, {0x369a0000}, {0x369c0000}, {0x369e0000}, 
+    {0x36a00000}, {0x36a20000}, {0x36a40000}, {0x36a60000}, 
+    {0x36a80000}, {0x36aa0000}, {0x36ac0000}, {0x36ae0000}, 
+    {0x36b00000}, {0x36b20000}, {0x36b40000}, {0x36b60000}, 
+    {0x36b80000}, {0x36ba0000}, {0x36bc0000}, {0x36be0000}, 
+    {0x36c00000}, {0x36c20000}, {0x36c40000}, {0x36c60000}, 
+    {0x36c80000}, {0x36ca0000}, {0x36cc0000}, {0x36ce0000}, 
+    {0x36d00000}, {0x36d20000}, {0x36d40000}, {0x36d60000}, 
+    {0x36d80000}, {0x36da0000}, {0x36dc0000}, {0x36de0000}, 
+    {0x36e00000}, {0x36e20000}, {0x36e40000}, {0x36e60000}, 
+    {0x36e80000}, {0x36ea0000}, {0x36ec0000}, {0x36ee0000}, 
+    {0x36f00000}, {0x36f20000}, {0x36f40000}, {0x36f60000}, 
+    {0x36f80000}, {0x36fa0000}, {0x36fc0000}, {0x36fe0000}, 
+    {0x37000000}, {0x37010000}, {0x37020000}, {0x37030000}, 
+    {0x37040000}, {0x37050000}, {0x37060000}, {0x37070000}, 
+    {0x37080000}, {0x37090000}, {0x370a0000}, {0x370b0000}, 
+    {0x370c0000}, {0x370d0000}, {0x370e0000}, {0x370f0000}, 
+    {0x37100000}, {0x37110000}, {0x37120000}, {0x37130000}, 
+    {0x37140000}, {0x37150000}, {0x37160000}, {0x37170000}, 
+    {0x37180000}, {0x37190000}, {0x371a0000}, {0x371b0000}, 
+    {0x371c0000}, {0x371d0000}, {0x371e0000}, {0x371f0000}, 
+    {0x37200000}, {0x37210000}, {0x37220000}, {0x37230000}, 
+    {0x37240000}, {0x37250000}, {0x37260000}, {0x37270000}, 
+    {0x37280000}, {0x37290000}, {0x372a0000}, {0x372b0000}, 
+    {0x372c0000}, {0x372d0000}, {0x372e0000}, {0x372f0000}, 
+    {0x37300000}, {0x37310000}, {0x37320000}, {0x37330000}, 
+    {0x37340000}, {0x37350000}, {0x37360000}, {0x37370000}, 
+    {0x37380000}, {0x37390000}, {0x373a0000}, {0x373b0000}, 
+    {0x373c0000}, {0x373d0000}, {0x373e0000}, {0x373f0000}, 
+    {0x37400000}, {0x37410000}, {0x37420000}, {0x37430000}, 
+    {0x37440000}, {0x37450000}, {0x37460000}, {0x37470000}, 
+    {0x37480000}, {0x37490000}, {0x374a0000}, {0x374b0000}, 
+    {0x374c0000}, {0x374d0000}, {0x374e0000}, {0x374f0000}, 
+    {0x37500000}, {0x37510000}, {0x37520000}, {0x37530000}, 
+    {0x37540000}, {0x37550000}, {0x37560000}, {0x37570000}, 
+    {0x37580000}, {0x37590000}, {0x375a0000}, {0x375b0000}, 
+    {0x375c0000}, {0x375d0000}, {0x375e0000}, {0x375f0000}, 
+    {0x37600000}, {0x37610000}, {0x37620000}, {0x37630000}, 
+    {0x37640000}, {0x37650000}, {0x37660000}, {0x37670000}, 
+    {0x37680000}, {0x37690000}, {0x376a0000}, {0x376b0000}, 
+    {0x376c0000}, {0x376d0000}, {0x376e0000}, {0x376f0000}, 
+    {0x37700000}, {0x37710000}, {0x37720000}, {0x37730000}, 
+    {0x37740000}, {0x37750000}, {0x37760000}, {0x37770000}, 
+    {0x37780000}, {0x37790000}, {0x377a0000}, {0x377b0000}, 
+    {0x377c0000}, {0x377d0000}, {0x377e0000}, {0x377f0000}, 
+    {0x37800000}, {0x37808000}, {0x37810000}, {0x37818000}, 
+    {0x37820000}, {0x37828000}, {0x37830000}, {0x37838000}, 
+    {0x37840000}, {0x37848000}, {0x37850000}, {0x37858000}, 
+    {0x37860000}, {0x37868000}, {0x37870000}, {0x37878000}, 
+    {0x37880000}, {0x37888000}, {0x37890000}, {0x37898000}, 
+    {0x378a0000}, {0x378a8000}, {0x378b0000}, {0x378b8000}, 
+    {0x378c0000}, {0x378c8000}, {0x378d0000}, {0x378d8000}, 
+    {0x378e0000}, {0x378e8000}, {0x378f0000}, {0x378f8000}, 
+    {0x37900000}, {0x37908000}, {0x37910000}, {0x37918000}, 
+    {0x37920000}, {0x37928000}, {0x37930000}, {0x37938000}, 
+    {0x37940000}, {0x37948000}, {0x37950000}, {0x37958000}, 
+    {0x37960000}, {0x37968000}, {0x37970000}, {0x37978000}, 
+    {0x37980000}, {0x37988000}, {0x37990000}, {0x37998000}, 
+    {0x379a0000}, {0x379a8000}, {0x379b0000}, {0x379b8000}, 
+    {0x379c0000}, {0x379c8000}, {0x379d0000}, {0x379d8000}, 
+    {0x379e0000}, {0x379e8000}, {0x379f0000}, {0x379f8000}, 
+    {0x37a00000}, {0x37a08000}, {0x37a10000}, {0x37a18000}, 
+    {0x37a20000}, {0x37a28000}, {0x37a30000}, {0x37a38000}, 
+    {0x37a40000}, {0x37a48000}, {0x37a50000}, {0x37a58000}, 
+    {0x37a60000}, {0x37a68000}, {0x37a70000}, {0x37a78000}, 
+    {0x37a80000}, {0x37a88000}, {0x37a90000}, {0x37a98000}, 
+    {0x37aa0000}, {0x37aa8000}, {0x37ab0000}, {0x37ab8000}, 
+    {0x37ac0000}, {0x37ac8000}, {0x37ad0000}, {0x37ad8000}, 
+    {0x37ae0000}, {0x37ae8000}, {0x37af0000}, {0x37af8000}, 
+    {0x37b00000}, {0x37b08000}, {0x37b10000}, {0x37b18000}, 
+    {0x37b20000}, {0x37b28000}, {0x37b30000}, {0x37b38000}, 
+    {0x37b40000}, {0x37b48000}, {0x37b50000}, {0x37b58000}, 
+    {0x37b60000}, {0x37b68000}, {0x37b70000}, {0x37b78000}, 
+    {0x37b80000}, {0x37b88000}, {0x37b90000}, {0x37b98000}, 
+    {0x37ba0000}, {0x37ba8000}, {0x37bb0000}, {0x37bb8000}, 
+    {0x37bc0000}, {0x37bc8000}, {0x37bd0000}, {0x37bd8000}, 
+    {0x37be0000}, {0x37be8000}, {0x37bf0000}, {0x37bf8000}, 
+    {0x37c00000}, {0x37c08000}, {0x37c10000}, {0x37c18000}, 
+    {0x37c20000}, {0x37c28000}, {0x37c30000}, {0x37c38000}, 
+    {0x37c40000}, {0x37c48000}, {0x37c50000}, {0x37c58000}, 
+    {0x37c60000}, {0x37c68000}, {0x37c70000}, {0x37c78000}, 
+    {0x37c80000}, {0x37c88000}, {0x37c90000}, {0x37c98000}, 
+    {0x37ca0000}, {0x37ca8000}, {0x37cb0000}, {0x37cb8000}, 
+    {0x37cc0000}, {0x37cc8000}, {0x37cd0000}, {0x37cd8000}, 
+    {0x37ce0000}, {0x37ce8000}, {0x37cf0000}, {0x37cf8000}, 
+    {0x37d00000}, {0x37d08000}, {0x37d10000}, {0x37d18000}, 
+    {0x37d20000}, {0x37d28000}, {0x37d30000}, {0x37d38000}, 
+    {0x37d40000}, {0x37d48000}, {0x37d50000}, {0x37d58000}, 
+    {0x37d60000}, {0x37d68000}, {0x37d70000}, {0x37d78000}, 
+    {0x37d80000}, {0x37d88000}, {0x37d90000}, {0x37d98000}, 
+    {0x37da0000}, {0x37da8000}, {0x37db0000}, {0x37db8000}, 
+    {0x37dc0000}, {0x37dc8000}, {0x37dd0000}, {0x37dd8000}, 
+    {0x37de0000}, {0x37de8000}, {0x37df0000}, {0x37df8000}, 
+    {0x37e00000}, {0x37e08000}, {0x37e10000}, {0x37e18000}, 
+    {0x37e20000}, {0x37e28000}, {0x37e30000}, {0x37e38000}, 
+    {0x37e40000}, {0x37e48000}, {0x37e50000}, {0x37e58000}, 
+    {0x37e60000}, {0x37e68000}, {0x37e70000}, {0x37e78000}, 
+    {0x37e80000}, {0x37e88000}, {0x37e90000}, {0x37e98000}, 
+    {0x37ea0000}, {0x37ea8000}, {0x37eb0000}, {0x37eb8000}, 
+    {0x37ec0000}, {0x37ec8000}, {0x37ed0000}, {0x37ed8000}, 
+    {0x37ee0000}, {0x37ee8000}, {0x37ef0000}, {0x37ef8000}, 
+    {0x37f00000}, {0x37f08000}, {0x37f10000}, {0x37f18000}, 
+    {0x37f20000}, {0x37f28000}, {0x37f30000}, {0x37f38000}, 
+    {0x37f40000}, {0x37f48000}, {0x37f50000}, {0x37f58000}, 
+    {0x37f60000}, {0x37f68000}, {0x37f70000}, {0x37f78000}, 
+    {0x37f80000}, {0x37f88000}, {0x37f90000}, {0x37f98000}, 
+    {0x37fa0000}, {0x37fa8000}, {0x37fb0000}, {0x37fb8000}, 
+    {0x37fc0000}, {0x37fc8000}, {0x37fd0000}, {0x37fd8000}, 
+    {0x37fe0000}, {0x37fe8000}, {0x37ff0000}, {0x37ff8000}, 
+    {0x38000000}, {0x38004000}, {0x38008000}, {0x3800c000}, 
+    {0x38010000}, {0x38014000}, {0x38018000}, {0x3801c000}, 
+    {0x38020000}, {0x38024000}, {0x38028000}, {0x3802c000}, 
+    {0x38030000}, {0x38034000}, {0x38038000}, {0x3803c000}, 
+    {0x38040000}, {0x38044000}, {0x38048000}, {0x3804c000}, 
+    {0x38050000}, {0x38054000}, {0x38058000}, {0x3805c000}, 
+    {0x38060000}, {0x38064000}, {0x38068000}, {0x3806c000}, 
+    {0x38070000}, {0x38074000}, {0x38078000}, {0x3807c000}, 
+    {0x38080000}, {0x38084000}, {0x38088000}, {0x3808c000}, 
+    {0x38090000}, {0x38094000}, {0x38098000}, {0x3809c000}, 
+    {0x380a0000}, {0x380a4000}, {0x380a8000}, {0x380ac000}, 
+    {0x380b0000}, {0x380b4000}, {0x380b8000}, {0x380bc000}, 
+    {0x380c0000}, {0x380c4000}, {0x380c8000}, {0x380cc000}, 
+    {0x380d0000}, {0x380d4000}, {0x380d8000}, {0x380dc000}, 
+    {0x380e0000}, {0x380e4000}, {0x380e8000}, {0x380ec000}, 
+    {0x380f0000}, {0x380f4000}, {0x380f8000}, {0x380fc000}, 
+    {0x38100000}, {0x38104000}, {0x38108000}, {0x3810c000}, 
+    {0x38110000}, {0x38114000}, {0x38118000}, {0x3811c000}, 
+    {0x38120000}, {0x38124000}, {0x38128000}, {0x3812c000}, 
+    {0x38130000}, {0x38134000}, {0x38138000}, {0x3813c000}, 
+    {0x38140000}, {0x38144000}, {0x38148000}, {0x3814c000}, 
+    {0x38150000}, {0x38154000}, {0x38158000}, {0x3815c000}, 
+    {0x38160000}, {0x38164000}, {0x38168000}, {0x3816c000}, 
+    {0x38170000}, {0x38174000}, {0x38178000}, {0x3817c000}, 
+    {0x38180000}, {0x38184000}, {0x38188000}, {0x3818c000}, 
+    {0x38190000}, {0x38194000}, {0x38198000}, {0x3819c000}, 
+    {0x381a0000}, {0x381a4000}, {0x381a8000}, {0x381ac000}, 
+    {0x381b0000}, {0x381b4000}, {0x381b8000}, {0x381bc000}, 
+    {0x381c0000}, {0x381c4000}, {0x381c8000}, {0x381cc000}, 
+    {0x381d0000}, {0x381d4000}, {0x381d8000}, {0x381dc000}, 
+    {0x381e0000}, {0x381e4000}, {0x381e8000}, {0x381ec000}, 
+    {0x381f0000}, {0x381f4000}, {0x381f8000}, {0x381fc000}, 
+    {0x38200000}, {0x38204000}, {0x38208000}, {0x3820c000}, 
+    {0x38210000}, {0x38214000}, {0x38218000}, {0x3821c000}, 
+    {0x38220000}, {0x38224000}, {0x38228000}, {0x3822c000}, 
+    {0x38230000}, {0x38234000}, {0x38238000}, {0x3823c000}, 
+    {0x38240000}, {0x38244000}, {0x38248000}, {0x3824c000}, 
+    {0x38250000}, {0x38254000}, {0x38258000}, {0x3825c000}, 
+    {0x38260000}, {0x38264000}, {0x38268000}, {0x3826c000}, 
+    {0x38270000}, {0x38274000}, {0x38278000}, {0x3827c000}, 
+    {0x38280000}, {0x38284000}, {0x38288000}, {0x3828c000}, 
+    {0x38290000}, {0x38294000}, {0x38298000}, {0x3829c000}, 
+    {0x382a0000}, {0x382a4000}, {0x382a8000}, {0x382ac000}, 
+    {0x382b0000}, {0x382b4000}, {0x382b8000}, {0x382bc000}, 
+    {0x382c0000}, {0x382c4000}, {0x382c8000}, {0x382cc000}, 
+    {0x382d0000}, {0x382d4000}, {0x382d8000}, {0x382dc000}, 
+    {0x382e0000}, {0x382e4000}, {0x382e8000}, {0x382ec000}, 
+    {0x382f0000}, {0x382f4000}, {0x382f8000}, {0x382fc000}, 
+    {0x38300000}, {0x38304000}, {0x38308000}, {0x3830c000}, 
+    {0x38310000}, {0x38314000}, {0x38318000}, {0x3831c000}, 
+    {0x38320000}, {0x38324000}, {0x38328000}, {0x3832c000}, 
+    {0x38330000}, {0x38334000}, {0x38338000}, {0x3833c000}, 
+    {0x38340000}, {0x38344000}, {0x38348000}, {0x3834c000}, 
+    {0x38350000}, {0x38354000}, {0x38358000}, {0x3835c000}, 
+    {0x38360000}, {0x38364000}, {0x38368000}, {0x3836c000}, 
+    {0x38370000}, {0x38374000}, {0x38378000}, {0x3837c000}, 
+    {0x38380000}, {0x38384000}, {0x38388000}, {0x3838c000}, 
+    {0x38390000}, {0x38394000}, {0x38398000}, {0x3839c000}, 
+    {0x383a0000}, {0x383a4000}, {0x383a8000}, {0x383ac000}, 
+    {0x383b0000}, {0x383b4000}, {0x383b8000}, {0x383bc000}, 
+    {0x383c0000}, {0x383c4000}, {0x383c8000}, {0x383cc000}, 
+    {0x383d0000}, {0x383d4000}, {0x383d8000}, {0x383dc000}, 
+    {0x383e0000}, {0x383e4000}, {0x383e8000}, {0x383ec000}, 
+    {0x383f0000}, {0x383f4000}, {0x383f8000}, {0x383fc000}, 
+    {0x38400000}, {0x38404000}, {0x38408000}, {0x3840c000}, 
+    {0x38410000}, {0x38414000}, {0x38418000}, {0x3841c000}, 
+    {0x38420000}, {0x38424000}, {0x38428000}, {0x3842c000}, 
+    {0x38430000}, {0x38434000}, {0x38438000}, {0x3843c000}, 
+    {0x38440000}, {0x38444000}, {0x38448000}, {0x3844c000}, 
+    {0x38450000}, {0x38454000}, {0x38458000}, {0x3845c000}, 
+    {0x38460000}, {0x38464000}, {0x38468000}, {0x3846c000}, 
+    {0x38470000}, {0x38474000}, {0x38478000}, {0x3847c000}, 
+    {0x38480000}, {0x38484000}, {0x38488000}, {0x3848c000}, 
+    {0x38490000}, {0x38494000}, {0x38498000}, {0x3849c000}, 
+    {0x384a0000}, {0x384a4000}, {0x384a8000}, {0x384ac000}, 
+    {0x384b0000}, {0x384b4000}, {0x384b8000}, {0x384bc000}, 
+    {0x384c0000}, {0x384c4000}, {0x384c8000}, {0x384cc000}, 
+    {0x384d0000}, {0x384d4000}, {0x384d8000}, {0x384dc000}, 
+    {0x384e0000}, {0x384e4000}, {0x384e8000}, {0x384ec000}, 
+    {0x384f0000}, {0x384f4000}, {0x384f8000}, {0x384fc000}, 
+    {0x38500000}, {0x38504000}, {0x38508000}, {0x3850c000}, 
+    {0x38510000}, {0x38514000}, {0x38518000}, {0x3851c000}, 
+    {0x38520000}, {0x38524000}, {0x38528000}, {0x3852c000}, 
+    {0x38530000}, {0x38534000}, {0x38538000}, {0x3853c000}, 
+    {0x38540000}, {0x38544000}, {0x38548000}, {0x3854c000}, 
+    {0x38550000}, {0x38554000}, {0x38558000}, {0x3855c000}, 
+    {0x38560000}, {0x38564000}, {0x38568000}, {0x3856c000}, 
+    {0x38570000}, {0x38574000}, {0x38578000}, {0x3857c000}, 
+    {0x38580000}, {0x38584000}, {0x38588000}, {0x3858c000}, 
+    {0x38590000}, {0x38594000}, {0x38598000}, {0x3859c000}, 
+    {0x385a0000}, {0x385a4000}, {0x385a8000}, {0x385ac000}, 
+    {0x385b0000}, {0x385b4000}, {0x385b8000}, {0x385bc000}, 
+    {0x385c0000}, {0x385c4000}, {0x385c8000}, {0x385cc000}, 
+    {0x385d0000}, {0x385d4000}, {0x385d8000}, {0x385dc000}, 
+    {0x385e0000}, {0x385e4000}, {0x385e8000}, {0x385ec000}, 
+    {0x385f0000}, {0x385f4000}, {0x385f8000}, {0x385fc000}, 
+    {0x38600000}, {0x38604000}, {0x38608000}, {0x3860c000}, 
+    {0x38610000}, {0x38614000}, {0x38618000}, {0x3861c000}, 
+    {0x38620000}, {0x38624000}, {0x38628000}, {0x3862c000}, 
+    {0x38630000}, {0x38634000}, {0x38638000}, {0x3863c000}, 
+    {0x38640000}, {0x38644000}, {0x38648000}, {0x3864c000}, 
+    {0x38650000}, {0x38654000}, {0x38658000}, {0x3865c000}, 
+    {0x38660000}, {0x38664000}, {0x38668000}, {0x3866c000}, 
+    {0x38670000}, {0x38674000}, {0x38678000}, {0x3867c000}, 
+    {0x38680000}, {0x38684000}, {0x38688000}, {0x3868c000}, 
+    {0x38690000}, {0x38694000}, {0x38698000}, {0x3869c000}, 
+    {0x386a0000}, {0x386a4000}, {0x386a8000}, {0x386ac000}, 
+    {0x386b0000}, {0x386b4000}, {0x386b8000}, {0x386bc000}, 
+    {0x386c0000}, {0x386c4000}, {0x386c8000}, {0x386cc000}, 
+    {0x386d0000}, {0x386d4000}, {0x386d8000}, {0x386dc000}, 
+    {0x386e0000}, {0x386e4000}, {0x386e8000}, {0x386ec000}, 
+    {0x386f0000}, {0x386f4000}, {0x386f8000}, {0x386fc000}, 
+    {0x38700000}, {0x38704000}, {0x38708000}, {0x3870c000}, 
+    {0x38710000}, {0x38714000}, {0x38718000}, {0x3871c000}, 
+    {0x38720000}, {0x38724000}, {0x38728000}, {0x3872c000}, 
+    {0x38730000}, {0x38734000}, {0x38738000}, {0x3873c000}, 
+    {0x38740000}, {0x38744000}, {0x38748000}, {0x3874c000}, 
+    {0x38750000}, {0x38754000}, {0x38758000}, {0x3875c000}, 
+    {0x38760000}, {0x38764000}, {0x38768000}, {0x3876c000}, 
+    {0x38770000}, {0x38774000}, {0x38778000}, {0x3877c000}, 
+    {0x38780000}, {0x38784000}, {0x38788000}, {0x3878c000}, 
+    {0x38790000}, {0x38794000}, {0x38798000}, {0x3879c000}, 
+    {0x387a0000}, {0x387a4000}, {0x387a8000}, {0x387ac000}, 
+    {0x387b0000}, {0x387b4000}, {0x387b8000}, {0x387bc000}, 
+    {0x387c0000}, {0x387c4000}, {0x387c8000}, {0x387cc000}, 
+    {0x387d0000}, {0x387d4000}, {0x387d8000}, {0x387dc000}, 
+    {0x387e0000}, {0x387e4000}, {0x387e8000}, {0x387ec000}, 
+    {0x387f0000}, {0x387f4000}, {0x387f8000}, {0x387fc000}, 
+    {0x38800000}, {0x38802000}, {0x38804000}, {0x38806000}, 
+    {0x38808000}, {0x3880a000}, {0x3880c000}, {0x3880e000}, 
+    {0x38810000}, {0x38812000}, {0x38814000}, {0x38816000}, 
+    {0x38818000}, {0x3881a000}, {0x3881c000}, {0x3881e000}, 
+    {0x38820000}, {0x38822000}, {0x38824000}, {0x38826000}, 
+    {0x38828000}, {0x3882a000}, {0x3882c000}, {0x3882e000}, 
+    {0x38830000}, {0x38832000}, {0x38834000}, {0x38836000}, 
+    {0x38838000}, {0x3883a000}, {0x3883c000}, {0x3883e000}, 
+    {0x38840000}, {0x38842000}, {0x38844000}, {0x38846000}, 
+    {0x38848000}, {0x3884a000}, {0x3884c000}, {0x3884e000}, 
+    {0x38850000}, {0x38852000}, {0x38854000}, {0x38856000}, 
+    {0x38858000}, {0x3885a000}, {0x3885c000}, {0x3885e000}, 
+    {0x38860000}, {0x38862000}, {0x38864000}, {0x38866000}, 
+    {0x38868000}, {0x3886a000}, {0x3886c000}, {0x3886e000}, 
+    {0x38870000}, {0x38872000}, {0x38874000}, {0x38876000}, 
+    {0x38878000}, {0x3887a000}, {0x3887c000}, {0x3887e000}, 
+    {0x38880000}, {0x38882000}, {0x38884000}, {0x38886000}, 
+    {0x38888000}, {0x3888a000}, {0x3888c000}, {0x3888e000}, 
+    {0x38890000}, {0x38892000}, {0x38894000}, {0x38896000}, 
+    {0x38898000}, {0x3889a000}, {0x3889c000}, {0x3889e000}, 
+    {0x388a0000}, {0x388a2000}, {0x388a4000}, {0x388a6000}, 
+    {0x388a8000}, {0x388aa000}, {0x388ac000}, {0x388ae000}, 
+    {0x388b0000}, {0x388b2000}, {0x388b4000}, {0x388b6000}, 
+    {0x388b8000}, {0x388ba000}, {0x388bc000}, {0x388be000}, 
+    {0x388c0000}, {0x388c2000}, {0x388c4000}, {0x388c6000}, 
+    {0x388c8000}, {0x388ca000}, {0x388cc000}, {0x388ce000}, 
+    {0x388d0000}, {0x388d2000}, {0x388d4000}, {0x388d6000}, 
+    {0x388d8000}, {0x388da000}, {0x388dc000}, {0x388de000}, 
+    {0x388e0000}, {0x388e2000}, {0x388e4000}, {0x388e6000}, 
+    {0x388e8000}, {0x388ea000}, {0x388ec000}, {0x388ee000}, 
+    {0x388f0000}, {0x388f2000}, {0x388f4000}, {0x388f6000}, 
+    {0x388f8000}, {0x388fa000}, {0x388fc000}, {0x388fe000}, 
+    {0x38900000}, {0x38902000}, {0x38904000}, {0x38906000}, 
+    {0x38908000}, {0x3890a000}, {0x3890c000}, {0x3890e000}, 
+    {0x38910000}, {0x38912000}, {0x38914000}, {0x38916000}, 
+    {0x38918000}, {0x3891a000}, {0x3891c000}, {0x3891e000}, 
+    {0x38920000}, {0x38922000}, {0x38924000}, {0x38926000}, 
+    {0x38928000}, {0x3892a000}, {0x3892c000}, {0x3892e000}, 
+    {0x38930000}, {0x38932000}, {0x38934000}, {0x38936000}, 
+    {0x38938000}, {0x3893a000}, {0x3893c000}, {0x3893e000}, 
+    {0x38940000}, {0x38942000}, {0x38944000}, {0x38946000}, 
+    {0x38948000}, {0x3894a000}, {0x3894c000}, {0x3894e000}, 
+    {0x38950000}, {0x38952000}, {0x38954000}, {0x38956000}, 
+    {0x38958000}, {0x3895a000}, {0x3895c000}, {0x3895e000}, 
+    {0x38960000}, {0x38962000}, {0x38964000}, {0x38966000}, 
+    {0x38968000}, {0x3896a000}, {0x3896c000}, {0x3896e000}, 
+    {0x38970000}, {0x38972000}, {0x38974000}, {0x38976000}, 
+    {0x38978000}, {0x3897a000}, {0x3897c000}, {0x3897e000}, 
+    {0x38980000}, {0x38982000}, {0x38984000}, {0x38986000}, 
+    {0x38988000}, {0x3898a000}, {0x3898c000}, {0x3898e000}, 
+    {0x38990000}, {0x38992000}, {0x38994000}, {0x38996000}, 
+    {0x38998000}, {0x3899a000}, {0x3899c000}, {0x3899e000}, 
+    {0x389a0000}, {0x389a2000}, {0x389a4000}, {0x389a6000}, 
+    {0x389a8000}, {0x389aa000}, {0x389ac000}, {0x389ae000}, 
+    {0x389b0000}, {0x389b2000}, {0x389b4000}, {0x389b6000}, 
+    {0x389b8000}, {0x389ba000}, {0x389bc000}, {0x389be000}, 
+    {0x389c0000}, {0x389c2000}, {0x389c4000}, {0x389c6000}, 
+    {0x389c8000}, {0x389ca000}, {0x389cc000}, {0x389ce000}, 
+    {0x389d0000}, {0x389d2000}, {0x389d4000}, {0x389d6000}, 
+    {0x389d8000}, {0x389da000}, {0x389dc000}, {0x389de000}, 
+    {0x389e0000}, {0x389e2000}, {0x389e4000}, {0x389e6000}, 
+    {0x389e8000}, {0x389ea000}, {0x389ec000}, {0x389ee000}, 
+    {0x389f0000}, {0x389f2000}, {0x389f4000}, {0x389f6000}, 
+    {0x389f8000}, {0x389fa000}, {0x389fc000}, {0x389fe000}, 
+    {0x38a00000}, {0x38a02000}, {0x38a04000}, {0x38a06000}, 
+    {0x38a08000}, {0x38a0a000}, {0x38a0c000}, {0x38a0e000}, 
+    {0x38a10000}, {0x38a12000}, {0x38a14000}, {0x38a16000}, 
+    {0x38a18000}, {0x38a1a000}, {0x38a1c000}, {0x38a1e000}, 
+    {0x38a20000}, {0x38a22000}, {0x38a24000}, {0x38a26000}, 
+    {0x38a28000}, {0x38a2a000}, {0x38a2c000}, {0x38a2e000}, 
+    {0x38a30000}, {0x38a32000}, {0x38a34000}, {0x38a36000}, 
+    {0x38a38000}, {0x38a3a000}, {0x38a3c000}, {0x38a3e000}, 
+    {0x38a40000}, {0x38a42000}, {0x38a44000}, {0x38a46000}, 
+    {0x38a48000}, {0x38a4a000}, {0x38a4c000}, {0x38a4e000}, 
+    {0x38a50000}, {0x38a52000}, {0x38a54000}, {0x38a56000}, 
+    {0x38a58000}, {0x38a5a000}, {0x38a5c000}, {0x38a5e000}, 
+    {0x38a60000}, {0x38a62000}, {0x38a64000}, {0x38a66000}, 
+    {0x38a68000}, {0x38a6a000}, {0x38a6c000}, {0x38a6e000}, 
+    {0x38a70000}, {0x38a72000}, {0x38a74000}, {0x38a76000}, 
+    {0x38a78000}, {0x38a7a000}, {0x38a7c000}, {0x38a7e000}, 
+    {0x38a80000}, {0x38a82000}, {0x38a84000}, {0x38a86000}, 
+    {0x38a88000}, {0x38a8a000}, {0x38a8c000}, {0x38a8e000}, 
+    {0x38a90000}, {0x38a92000}, {0x38a94000}, {0x38a96000}, 
+    {0x38a98000}, {0x38a9a000}, {0x38a9c000}, {0x38a9e000}, 
+    {0x38aa0000}, {0x38aa2000}, {0x38aa4000}, {0x38aa6000}, 
+    {0x38aa8000}, {0x38aaa000}, {0x38aac000}, {0x38aae000}, 
+    {0x38ab0000}, {0x38ab2000}, {0x38ab4000}, {0x38ab6000}, 
+    {0x38ab8000}, {0x38aba000}, {0x38abc000}, {0x38abe000}, 
+    {0x38ac0000}, {0x38ac2000}, {0x38ac4000}, {0x38ac6000}, 
+    {0x38ac8000}, {0x38aca000}, {0x38acc000}, {0x38ace000}, 
+    {0x38ad0000}, {0x38ad2000}, {0x38ad4000}, {0x38ad6000}, 
+    {0x38ad8000}, {0x38ada000}, {0x38adc000}, {0x38ade000}, 
+    {0x38ae0000}, {0x38ae2000}, {0x38ae4000}, {0x38ae6000}, 
+    {0x38ae8000}, {0x38aea000}, {0x38aec000}, {0x38aee000}, 
+    {0x38af0000}, {0x38af2000}, {0x38af4000}, {0x38af6000}, 
+    {0x38af8000}, {0x38afa000}, {0x38afc000}, {0x38afe000}, 
+    {0x38b00000}, {0x38b02000}, {0x38b04000}, {0x38b06000}, 
+    {0x38b08000}, {0x38b0a000}, {0x38b0c000}, {0x38b0e000}, 
+    {0x38b10000}, {0x38b12000}, {0x38b14000}, {0x38b16000}, 
+    {0x38b18000}, {0x38b1a000}, {0x38b1c000}, {0x38b1e000}, 
+    {0x38b20000}, {0x38b22000}, {0x38b24000}, {0x38b26000}, 
+    {0x38b28000}, {0x38b2a000}, {0x38b2c000}, {0x38b2e000}, 
+    {0x38b30000}, {0x38b32000}, {0x38b34000}, {0x38b36000}, 
+    {0x38b38000}, {0x38b3a000}, {0x38b3c000}, {0x38b3e000}, 
+    {0x38b40000}, {0x38b42000}, {0x38b44000}, {0x38b46000}, 
+    {0x38b48000}, {0x38b4a000}, {0x38b4c000}, {0x38b4e000}, 
+    {0x38b50000}, {0x38b52000}, {0x38b54000}, {0x38b56000}, 
+    {0x38b58000}, {0x38b5a000}, {0x38b5c000}, {0x38b5e000}, 
+    {0x38b60000}, {0x38b62000}, {0x38b64000}, {0x38b66000}, 
+    {0x38b68000}, {0x38b6a000}, {0x38b6c000}, {0x38b6e000}, 
+    {0x38b70000}, {0x38b72000}, {0x38b74000}, {0x38b76000}, 
+    {0x38b78000}, {0x38b7a000}, {0x38b7c000}, {0x38b7e000}, 
+    {0x38b80000}, {0x38b82000}, {0x38b84000}, {0x38b86000}, 
+    {0x38b88000}, {0x38b8a000}, {0x38b8c000}, {0x38b8e000}, 
+    {0x38b90000}, {0x38b92000}, {0x38b94000}, {0x38b96000}, 
+    {0x38b98000}, {0x38b9a000}, {0x38b9c000}, {0x38b9e000}, 
+    {0x38ba0000}, {0x38ba2000}, {0x38ba4000}, {0x38ba6000}, 
+    {0x38ba8000}, {0x38baa000}, {0x38bac000}, {0x38bae000}, 
+    {0x38bb0000}, {0x38bb2000}, {0x38bb4000}, {0x38bb6000}, 
+    {0x38bb8000}, {0x38bba000}, {0x38bbc000}, {0x38bbe000}, 
+    {0x38bc0000}, {0x38bc2000}, {0x38bc4000}, {0x38bc6000}, 
+    {0x38bc8000}, {0x38bca000}, {0x38bcc000}, {0x38bce000}, 
+    {0x38bd0000}, {0x38bd2000}, {0x38bd4000}, {0x38bd6000}, 
+    {0x38bd8000}, {0x38bda000}, {0x38bdc000}, {0x38bde000}, 
+    {0x38be0000}, {0x38be2000}, {0x38be4000}, {0x38be6000}, 
+    {0x38be8000}, {0x38bea000}, {0x38bec000}, {0x38bee000}, 
+    {0x38bf0000}, {0x38bf2000}, {0x38bf4000}, {0x38bf6000}, 
+    {0x38bf8000}, {0x38bfa000}, {0x38bfc000}, {0x38bfe000}, 
+    {0x38c00000}, {0x38c02000}, {0x38c04000}, {0x38c06000}, 
+    {0x38c08000}, {0x38c0a000}, {0x38c0c000}, {0x38c0e000}, 
+    {0x38c10000}, {0x38c12000}, {0x38c14000}, {0x38c16000}, 
+    {0x38c18000}, {0x38c1a000}, {0x38c1c000}, {0x38c1e000}, 
+    {0x38c20000}, {0x38c22000}, {0x38c24000}, {0x38c26000}, 
+    {0x38c28000}, {0x38c2a000}, {0x38c2c000}, {0x38c2e000}, 
+    {0x38c30000}, {0x38c32000}, {0x38c34000}, {0x38c36000}, 
+    {0x38c38000}, {0x38c3a000}, {0x38c3c000}, {0x38c3e000}, 
+    {0x38c40000}, {0x38c42000}, {0x38c44000}, {0x38c46000}, 
+    {0x38c48000}, {0x38c4a000}, {0x38c4c000}, {0x38c4e000}, 
+    {0x38c50000}, {0x38c52000}, {0x38c54000}, {0x38c56000}, 
+    {0x38c58000}, {0x38c5a000}, {0x38c5c000}, {0x38c5e000}, 
+    {0x38c60000}, {0x38c62000}, {0x38c64000}, {0x38c66000}, 
+    {0x38c68000}, {0x38c6a000}, {0x38c6c000}, {0x38c6e000}, 
+    {0x38c70000}, {0x38c72000}, {0x38c74000}, {0x38c76000}, 
+    {0x38c78000}, {0x38c7a000}, {0x38c7c000}, {0x38c7e000}, 
+    {0x38c80000}, {0x38c82000}, {0x38c84000}, {0x38c86000}, 
+    {0x38c88000}, {0x38c8a000}, {0x38c8c000}, {0x38c8e000}, 
+    {0x38c90000}, {0x38c92000}, {0x38c94000}, {0x38c96000}, 
+    {0x38c98000}, {0x38c9a000}, {0x38c9c000}, {0x38c9e000}, 
+    {0x38ca0000}, {0x38ca2000}, {0x38ca4000}, {0x38ca6000}, 
+    {0x38ca8000}, {0x38caa000}, {0x38cac000}, {0x38cae000}, 
+    {0x38cb0000}, {0x38cb2000}, {0x38cb4000}, {0x38cb6000}, 
+    {0x38cb8000}, {0x38cba000}, {0x38cbc000}, {0x38cbe000}, 
+    {0x38cc0000}, {0x38cc2000}, {0x38cc4000}, {0x38cc6000}, 
+    {0x38cc8000}, {0x38cca000}, {0x38ccc000}, {0x38cce000}, 
+    {0x38cd0000}, {0x38cd2000}, {0x38cd4000}, {0x38cd6000}, 
+    {0x38cd8000}, {0x38cda000}, {0x38cdc000}, {0x38cde000}, 
+    {0x38ce0000}, {0x38ce2000}, {0x38ce4000}, {0x38ce6000}, 
+    {0x38ce8000}, {0x38cea000}, {0x38cec000}, {0x38cee000}, 
+    {0x38cf0000}, {0x38cf2000}, {0x38cf4000}, {0x38cf6000}, 
+    {0x38cf8000}, {0x38cfa000}, {0x38cfc000}, {0x38cfe000}, 
+    {0x38d00000}, {0x38d02000}, {0x38d04000}, {0x38d06000}, 
+    {0x38d08000}, {0x38d0a000}, {0x38d0c000}, {0x38d0e000}, 
+    {0x38d10000}, {0x38d12000}, {0x38d14000}, {0x38d16000}, 
+    {0x38d18000}, {0x38d1a000}, {0x38d1c000}, {0x38d1e000}, 
+    {0x38d20000}, {0x38d22000}, {0x38d24000}, {0x38d26000}, 
+    {0x38d28000}, {0x38d2a000}, {0x38d2c000}, {0x38d2e000}, 
+    {0x38d30000}, {0x38d32000}, {0x38d34000}, {0x38d36000}, 
+    {0x38d38000}, {0x38d3a000}, {0x38d3c000}, {0x38d3e000}, 
+    {0x38d40000}, {0x38d42000}, {0x38d44000}, {0x38d46000}, 
+    {0x38d48000}, {0x38d4a000}, {0x38d4c000}, {0x38d4e000}, 
+    {0x38d50000}, {0x38d52000}, {0x38d54000}, {0x38d56000}, 
+    {0x38d58000}, {0x38d5a000}, {0x38d5c000}, {0x38d5e000}, 
+    {0x38d60000}, {0x38d62000}, {0x38d64000}, {0x38d66000}, 
+    {0x38d68000}, {0x38d6a000}, {0x38d6c000}, {0x38d6e000}, 
+    {0x38d70000}, {0x38d72000}, {0x38d74000}, {0x38d76000}, 
+    {0x38d78000}, {0x38d7a000}, {0x38d7c000}, {0x38d7e000}, 
+    {0x38d80000}, {0x38d82000}, {0x38d84000}, {0x38d86000}, 
+    {0x38d88000}, {0x38d8a000}, {0x38d8c000}, {0x38d8e000}, 
+    {0x38d90000}, {0x38d92000}, {0x38d94000}, {0x38d96000}, 
+    {0x38d98000}, {0x38d9a000}, {0x38d9c000}, {0x38d9e000}, 
+    {0x38da0000}, {0x38da2000}, {0x38da4000}, {0x38da6000}, 
+    {0x38da8000}, {0x38daa000}, {0x38dac000}, {0x38dae000}, 
+    {0x38db0000}, {0x38db2000}, {0x38db4000}, {0x38db6000}, 
+    {0x38db8000}, {0x38dba000}, {0x38dbc000}, {0x38dbe000}, 
+    {0x38dc0000}, {0x38dc2000}, {0x38dc4000}, {0x38dc6000}, 
+    {0x38dc8000}, {0x38dca000}, {0x38dcc000}, {0x38dce000}, 
+    {0x38dd0000}, {0x38dd2000}, {0x38dd4000}, {0x38dd6000}, 
+    {0x38dd8000}, {0x38dda000}, {0x38ddc000}, {0x38dde000}, 
+    {0x38de0000}, {0x38de2000}, {0x38de4000}, {0x38de6000}, 
+    {0x38de8000}, {0x38dea000}, {0x38dec000}, {0x38dee000}, 
+    {0x38df0000}, {0x38df2000}, {0x38df4000}, {0x38df6000}, 
+    {0x38df8000}, {0x38dfa000}, {0x38dfc000}, {0x38dfe000}, 
+    {0x38e00000}, {0x38e02000}, {0x38e04000}, {0x38e06000}, 
+    {0x38e08000}, {0x38e0a000}, {0x38e0c000}, {0x38e0e000}, 
+    {0x38e10000}, {0x38e12000}, {0x38e14000}, {0x38e16000}, 
+    {0x38e18000}, {0x38e1a000}, {0x38e1c000}, {0x38e1e000}, 
+    {0x38e20000}, {0x38e22000}, {0x38e24000}, {0x38e26000}, 
+    {0x38e28000}, {0x38e2a000}, {0x38e2c000}, {0x38e2e000}, 
+    {0x38e30000}, {0x38e32000}, {0x38e34000}, {0x38e36000}, 
+    {0x38e38000}, {0x38e3a000}, {0x38e3c000}, {0x38e3e000}, 
+    {0x38e40000}, {0x38e42000}, {0x38e44000}, {0x38e46000}, 
+    {0x38e48000}, {0x38e4a000}, {0x38e4c000}, {0x38e4e000}, 
+    {0x38e50000}, {0x38e52000}, {0x38e54000}, {0x38e56000}, 
+    {0x38e58000}, {0x38e5a000}, {0x38e5c000}, {0x38e5e000}, 
+    {0x38e60000}, {0x38e62000}, {0x38e64000}, {0x38e66000}, 
+    {0x38e68000}, {0x38e6a000}, {0x38e6c000}, {0x38e6e000}, 
+    {0x38e70000}, {0x38e72000}, {0x38e74000}, {0x38e76000}, 
+    {0x38e78000}, {0x38e7a000}, {0x38e7c000}, {0x38e7e000}, 
+    {0x38e80000}, {0x38e82000}, {0x38e84000}, {0x38e86000}, 
+    {0x38e88000}, {0x38e8a000}, {0x38e8c000}, {0x38e8e000}, 
+    {0x38e90000}, {0x38e92000}, {0x38e94000}, {0x38e96000}, 
+    {0x38e98000}, {0x38e9a000}, {0x38e9c000}, {0x38e9e000}, 
+    {0x38ea0000}, {0x38ea2000}, {0x38ea4000}, {0x38ea6000}, 
+    {0x38ea8000}, {0x38eaa000}, {0x38eac000}, {0x38eae000}, 
+    {0x38eb0000}, {0x38eb2000}, {0x38eb4000}, {0x38eb6000}, 
+    {0x38eb8000}, {0x38eba000}, {0x38ebc000}, {0x38ebe000}, 
+    {0x38ec0000}, {0x38ec2000}, {0x38ec4000}, {0x38ec6000}, 
+    {0x38ec8000}, {0x38eca000}, {0x38ecc000}, {0x38ece000}, 
+    {0x38ed0000}, {0x38ed2000}, {0x38ed4000}, {0x38ed6000}, 
+    {0x38ed8000}, {0x38eda000}, {0x38edc000}, {0x38ede000}, 
+    {0x38ee0000}, {0x38ee2000}, {0x38ee4000}, {0x38ee6000}, 
+    {0x38ee8000}, {0x38eea000}, {0x38eec000}, {0x38eee000}, 
+    {0x38ef0000}, {0x38ef2000}, {0x38ef4000}, {0x38ef6000}, 
+    {0x38ef8000}, {0x38efa000}, {0x38efc000}, {0x38efe000}, 
+    {0x38f00000}, {0x38f02000}, {0x38f04000}, {0x38f06000}, 
+    {0x38f08000}, {0x38f0a000}, {0x38f0c000}, {0x38f0e000}, 
+    {0x38f10000}, {0x38f12000}, {0x38f14000}, {0x38f16000}, 
+    {0x38f18000}, {0x38f1a000}, {0x38f1c000}, {0x38f1e000}, 
+    {0x38f20000}, {0x38f22000}, {0x38f24000}, {0x38f26000}, 
+    {0x38f28000}, {0x38f2a000}, {0x38f2c000}, {0x38f2e000}, 
+    {0x38f30000}, {0x38f32000}, {0x38f34000}, {0x38f36000}, 
+    {0x38f38000}, {0x38f3a000}, {0x38f3c000}, {0x38f3e000}, 
+    {0x38f40000}, {0x38f42000}, {0x38f44000}, {0x38f46000}, 
+    {0x38f48000}, {0x38f4a000}, {0x38f4c000}, {0x38f4e000}, 
+    {0x38f50000}, {0x38f52000}, {0x38f54000}, {0x38f56000}, 
+    {0x38f58000}, {0x38f5a000}, {0x38f5c000}, {0x38f5e000}, 
+    {0x38f60000}, {0x38f62000}, {0x38f64000}, {0x38f66000}, 
+    {0x38f68000}, {0x38f6a000}, {0x38f6c000}, {0x38f6e000}, 
+    {0x38f70000}, {0x38f72000}, {0x38f74000}, {0x38f76000}, 
+    {0x38f78000}, {0x38f7a000}, {0x38f7c000}, {0x38f7e000}, 
+    {0x38f80000}, {0x38f82000}, {0x38f84000}, {0x38f86000}, 
+    {0x38f88000}, {0x38f8a000}, {0x38f8c000}, {0x38f8e000}, 
+    {0x38f90000}, {0x38f92000}, {0x38f94000}, {0x38f96000}, 
+    {0x38f98000}, {0x38f9a000}, {0x38f9c000}, {0x38f9e000}, 
+    {0x38fa0000}, {0x38fa2000}, {0x38fa4000}, {0x38fa6000}, 
+    {0x38fa8000}, {0x38faa000}, {0x38fac000}, {0x38fae000}, 
+    {0x38fb0000}, {0x38fb2000}, {0x38fb4000}, {0x38fb6000}, 
+    {0x38fb8000}, {0x38fba000}, {0x38fbc000}, {0x38fbe000}, 
+    {0x38fc0000}, {0x38fc2000}, {0x38fc4000}, {0x38fc6000}, 
+    {0x38fc8000}, {0x38fca000}, {0x38fcc000}, {0x38fce000}, 
+    {0x38fd0000}, {0x38fd2000}, {0x38fd4000}, {0x38fd6000}, 
+    {0x38fd8000}, {0x38fda000}, {0x38fdc000}, {0x38fde000}, 
+    {0x38fe0000}, {0x38fe2000}, {0x38fe4000}, {0x38fe6000}, 
+    {0x38fe8000}, {0x38fea000}, {0x38fec000}, {0x38fee000}, 
+    {0x38ff0000}, {0x38ff2000}, {0x38ff4000}, {0x38ff6000}, 
+    {0x38ff8000}, {0x38ffa000}, {0x38ffc000}, {0x38ffe000}, 
+    {0x39000000}, {0x39002000}, {0x39004000}, {0x39006000}, 
+    {0x39008000}, {0x3900a000}, {0x3900c000}, {0x3900e000}, 
+    {0x39010000}, {0x39012000}, {0x39014000}, {0x39016000}, 
+    {0x39018000}, {0x3901a000}, {0x3901c000}, {0x3901e000}, 
+    {0x39020000}, {0x39022000}, {0x39024000}, {0x39026000}, 
+    {0x39028000}, {0x3902a000}, {0x3902c000}, {0x3902e000}, 
+    {0x39030000}, {0x39032000}, {0x39034000}, {0x39036000}, 
+    {0x39038000}, {0x3903a000}, {0x3903c000}, {0x3903e000}, 
+    {0x39040000}, {0x39042000}, {0x39044000}, {0x39046000}, 
+    {0x39048000}, {0x3904a000}, {0x3904c000}, {0x3904e000}, 
+    {0x39050000}, {0x39052000}, {0x39054000}, {0x39056000}, 
+    {0x39058000}, {0x3905a000}, {0x3905c000}, {0x3905e000}, 
+    {0x39060000}, {0x39062000}, {0x39064000}, {0x39066000}, 
+    {0x39068000}, {0x3906a000}, {0x3906c000}, {0x3906e000}, 
+    {0x39070000}, {0x39072000}, {0x39074000}, {0x39076000}, 
+    {0x39078000}, {0x3907a000}, {0x3907c000}, {0x3907e000}, 
+    {0x39080000}, {0x39082000}, {0x39084000}, {0x39086000}, 
+    {0x39088000}, {0x3908a000}, {0x3908c000}, {0x3908e000}, 
+    {0x39090000}, {0x39092000}, {0x39094000}, {0x39096000}, 
+    {0x39098000}, {0x3909a000}, {0x3909c000}, {0x3909e000}, 
+    {0x390a0000}, {0x390a2000}, {0x390a4000}, {0x390a6000}, 
+    {0x390a8000}, {0x390aa000}, {0x390ac000}, {0x390ae000}, 
+    {0x390b0000}, {0x390b2000}, {0x390b4000}, {0x390b6000}, 
+    {0x390b8000}, {0x390ba000}, {0x390bc000}, {0x390be000}, 
+    {0x390c0000}, {0x390c2000}, {0x390c4000}, {0x390c6000}, 
+    {0x390c8000}, {0x390ca000}, {0x390cc000}, {0x390ce000}, 
+    {0x390d0000}, {0x390d2000}, {0x390d4000}, {0x390d6000}, 
+    {0x390d8000}, {0x390da000}, {0x390dc000}, {0x390de000}, 
+    {0x390e0000}, {0x390e2000}, {0x390e4000}, {0x390e6000}, 
+    {0x390e8000}, {0x390ea000}, {0x390ec000}, {0x390ee000}, 
+    {0x390f0000}, {0x390f2000}, {0x390f4000}, {0x390f6000}, 
+    {0x390f8000}, {0x390fa000}, {0x390fc000}, {0x390fe000}, 
+    {0x39100000}, {0x39102000}, {0x39104000}, {0x39106000}, 
+    {0x39108000}, {0x3910a000}, {0x3910c000}, {0x3910e000}, 
+    {0x39110000}, {0x39112000}, {0x39114000}, {0x39116000}, 
+    {0x39118000}, {0x3911a000}, {0x3911c000}, {0x3911e000}, 
+    {0x39120000}, {0x39122000}, {0x39124000}, {0x39126000}, 
+    {0x39128000}, {0x3912a000}, {0x3912c000}, {0x3912e000}, 
+    {0x39130000}, {0x39132000}, {0x39134000}, {0x39136000}, 
+    {0x39138000}, {0x3913a000}, {0x3913c000}, {0x3913e000}, 
+    {0x39140000}, {0x39142000}, {0x39144000}, {0x39146000}, 
+    {0x39148000}, {0x3914a000}, {0x3914c000}, {0x3914e000}, 
+    {0x39150000}, {0x39152000}, {0x39154000}, {0x39156000}, 
+    {0x39158000}, {0x3915a000}, {0x3915c000}, {0x3915e000}, 
+    {0x39160000}, {0x39162000}, {0x39164000}, {0x39166000}, 
+    {0x39168000}, {0x3916a000}, {0x3916c000}, {0x3916e000}, 
+    {0x39170000}, {0x39172000}, {0x39174000}, {0x39176000}, 
+    {0x39178000}, {0x3917a000}, {0x3917c000}, {0x3917e000}, 
+    {0x39180000}, {0x39182000}, {0x39184000}, {0x39186000}, 
+    {0x39188000}, {0x3918a000}, {0x3918c000}, {0x3918e000}, 
+    {0x39190000}, {0x39192000}, {0x39194000}, {0x39196000}, 
+    {0x39198000}, {0x3919a000}, {0x3919c000}, {0x3919e000}, 
+    {0x391a0000}, {0x391a2000}, {0x391a4000}, {0x391a6000}, 
+    {0x391a8000}, {0x391aa000}, {0x391ac000}, {0x391ae000}, 
+    {0x391b0000}, {0x391b2000}, {0x391b4000}, {0x391b6000}, 
+    {0x391b8000}, {0x391ba000}, {0x391bc000}, {0x391be000}, 
+    {0x391c0000}, {0x391c2000}, {0x391c4000}, {0x391c6000}, 
+    {0x391c8000}, {0x391ca000}, {0x391cc000}, {0x391ce000}, 
+    {0x391d0000}, {0x391d2000}, {0x391d4000}, {0x391d6000}, 
+    {0x391d8000}, {0x391da000}, {0x391dc000}, {0x391de000}, 
+    {0x391e0000}, {0x391e2000}, {0x391e4000}, {0x391e6000}, 
+    {0x391e8000}, {0x391ea000}, {0x391ec000}, {0x391ee000}, 
+    {0x391f0000}, {0x391f2000}, {0x391f4000}, {0x391f6000}, 
+    {0x391f8000}, {0x391fa000}, {0x391fc000}, {0x391fe000}, 
+    {0x39200000}, {0x39202000}, {0x39204000}, {0x39206000}, 
+    {0x39208000}, {0x3920a000}, {0x3920c000}, {0x3920e000}, 
+    {0x39210000}, {0x39212000}, {0x39214000}, {0x39216000}, 
+    {0x39218000}, {0x3921a000}, {0x3921c000}, {0x3921e000}, 
+    {0x39220000}, {0x39222000}, {0x39224000}, {0x39226000}, 
+    {0x39228000}, {0x3922a000}, {0x3922c000}, {0x3922e000}, 
+    {0x39230000}, {0x39232000}, {0x39234000}, {0x39236000}, 
+    {0x39238000}, {0x3923a000}, {0x3923c000}, {0x3923e000}, 
+    {0x39240000}, {0x39242000}, {0x39244000}, {0x39246000}, 
+    {0x39248000}, {0x3924a000}, {0x3924c000}, {0x3924e000}, 
+    {0x39250000}, {0x39252000}, {0x39254000}, {0x39256000}, 
+    {0x39258000}, {0x3925a000}, {0x3925c000}, {0x3925e000}, 
+    {0x39260000}, {0x39262000}, {0x39264000}, {0x39266000}, 
+    {0x39268000}, {0x3926a000}, {0x3926c000}, {0x3926e000}, 
+    {0x39270000}, {0x39272000}, {0x39274000}, {0x39276000}, 
+    {0x39278000}, {0x3927a000}, {0x3927c000}, {0x3927e000}, 
+    {0x39280000}, {0x39282000}, {0x39284000}, {0x39286000}, 
+    {0x39288000}, {0x3928a000}, {0x3928c000}, {0x3928e000}, 
+    {0x39290000}, {0x39292000}, {0x39294000}, {0x39296000}, 
+    {0x39298000}, {0x3929a000}, {0x3929c000}, {0x3929e000}, 
+    {0x392a0000}, {0x392a2000}, {0x392a4000}, {0x392a6000}, 
+    {0x392a8000}, {0x392aa000}, {0x392ac000}, {0x392ae000}, 
+    {0x392b0000}, {0x392b2000}, {0x392b4000}, {0x392b6000}, 
+    {0x392b8000}, {0x392ba000}, {0x392bc000}, {0x392be000}, 
+    {0x392c0000}, {0x392c2000}, {0x392c4000}, {0x392c6000}, 
+    {0x392c8000}, {0x392ca000}, {0x392cc000}, {0x392ce000}, 
+    {0x392d0000}, {0x392d2000}, {0x392d4000}, {0x392d6000}, 
+    {0x392d8000}, {0x392da000}, {0x392dc000}, {0x392de000}, 
+    {0x392e0000}, {0x392e2000}, {0x392e4000}, {0x392e6000}, 
+    {0x392e8000}, {0x392ea000}, {0x392ec000}, {0x392ee000}, 
+    {0x392f0000}, {0x392f2000}, {0x392f4000}, {0x392f6000}, 
+    {0x392f8000}, {0x392fa000}, {0x392fc000}, {0x392fe000}, 
+    {0x39300000}, {0x39302000}, {0x39304000}, {0x39306000}, 
+    {0x39308000}, {0x3930a000}, {0x3930c000}, {0x3930e000}, 
+    {0x39310000}, {0x39312000}, {0x39314000}, {0x39316000}, 
+    {0x39318000}, {0x3931a000}, {0x3931c000}, {0x3931e000}, 
+    {0x39320000}, {0x39322000}, {0x39324000}, {0x39326000}, 
+    {0x39328000}, {0x3932a000}, {0x3932c000}, {0x3932e000}, 
+    {0x39330000}, {0x39332000}, {0x39334000}, {0x39336000}, 
+    {0x39338000}, {0x3933a000}, {0x3933c000}, {0x3933e000}, 
+    {0x39340000}, {0x39342000}, {0x39344000}, {0x39346000}, 
+    {0x39348000}, {0x3934a000}, {0x3934c000}, {0x3934e000}, 
+    {0x39350000}, {0x39352000}, {0x39354000}, {0x39356000}, 
+    {0x39358000}, {0x3935a000}, {0x3935c000}, {0x3935e000}, 
+    {0x39360000}, {0x39362000}, {0x39364000}, {0x39366000}, 
+    {0x39368000}, {0x3936a000}, {0x3936c000}, {0x3936e000}, 
+    {0x39370000}, {0x39372000}, {0x39374000}, {0x39376000}, 
+    {0x39378000}, {0x3937a000}, {0x3937c000}, {0x3937e000}, 
+    {0x39380000}, {0x39382000}, {0x39384000}, {0x39386000}, 
+    {0x39388000}, {0x3938a000}, {0x3938c000}, {0x3938e000}, 
+    {0x39390000}, {0x39392000}, {0x39394000}, {0x39396000}, 
+    {0x39398000}, {0x3939a000}, {0x3939c000}, {0x3939e000}, 
+    {0x393a0000}, {0x393a2000}, {0x393a4000}, {0x393a6000}, 
+    {0x393a8000}, {0x393aa000}, {0x393ac000}, {0x393ae000}, 
+    {0x393b0000}, {0x393b2000}, {0x393b4000}, {0x393b6000}, 
+    {0x393b8000}, {0x393ba000}, {0x393bc000}, {0x393be000}, 
+    {0x393c0000}, {0x393c2000}, {0x393c4000}, {0x393c6000}, 
+    {0x393c8000}, {0x393ca000}, {0x393cc000}, {0x393ce000}, 
+    {0x393d0000}, {0x393d2000}, {0x393d4000}, {0x393d6000}, 
+    {0x393d8000}, {0x393da000}, {0x393dc000}, {0x393de000}, 
+    {0x393e0000}, {0x393e2000}, {0x393e4000}, {0x393e6000}, 
+    {0x393e8000}, {0x393ea000}, {0x393ec000}, {0x393ee000}, 
+    {0x393f0000}, {0x393f2000}, {0x393f4000}, {0x393f6000}, 
+    {0x393f8000}, {0x393fa000}, {0x393fc000}, {0x393fe000}, 
+    {0x39400000}, {0x39402000}, {0x39404000}, {0x39406000}, 
+    {0x39408000}, {0x3940a000}, {0x3940c000}, {0x3940e000}, 
+    {0x39410000}, {0x39412000}, {0x39414000}, {0x39416000}, 
+    {0x39418000}, {0x3941a000}, {0x3941c000}, {0x3941e000}, 
+    {0x39420000}, {0x39422000}, {0x39424000}, {0x39426000}, 
+    {0x39428000}, {0x3942a000}, {0x3942c000}, {0x3942e000}, 
+    {0x39430000}, {0x39432000}, {0x39434000}, {0x39436000}, 
+    {0x39438000}, {0x3943a000}, {0x3943c000}, {0x3943e000}, 
+    {0x39440000}, {0x39442000}, {0x39444000}, {0x39446000}, 
+    {0x39448000}, {0x3944a000}, {0x3944c000}, {0x3944e000}, 
+    {0x39450000}, {0x39452000}, {0x39454000}, {0x39456000}, 
+    {0x39458000}, {0x3945a000}, {0x3945c000}, {0x3945e000}, 
+    {0x39460000}, {0x39462000}, {0x39464000}, {0x39466000}, 
+    {0x39468000}, {0x3946a000}, {0x3946c000}, {0x3946e000}, 
+    {0x39470000}, {0x39472000}, {0x39474000}, {0x39476000}, 
+    {0x39478000}, {0x3947a000}, {0x3947c000}, {0x3947e000}, 
+    {0x39480000}, {0x39482000}, {0x39484000}, {0x39486000}, 
+    {0x39488000}, {0x3948a000}, {0x3948c000}, {0x3948e000}, 
+    {0x39490000}, {0x39492000}, {0x39494000}, {0x39496000}, 
+    {0x39498000}, {0x3949a000}, {0x3949c000}, {0x3949e000}, 
+    {0x394a0000}, {0x394a2000}, {0x394a4000}, {0x394a6000}, 
+    {0x394a8000}, {0x394aa000}, {0x394ac000}, {0x394ae000}, 
+    {0x394b0000}, {0x394b2000}, {0x394b4000}, {0x394b6000}, 
+    {0x394b8000}, {0x394ba000}, {0x394bc000}, {0x394be000}, 
+    {0x394c0000}, {0x394c2000}, {0x394c4000}, {0x394c6000}, 
+    {0x394c8000}, {0x394ca000}, {0x394cc000}, {0x394ce000}, 
+    {0x394d0000}, {0x394d2000}, {0x394d4000}, {0x394d6000}, 
+    {0x394d8000}, {0x394da000}, {0x394dc000}, {0x394de000}, 
+    {0x394e0000}, {0x394e2000}, {0x394e4000}, {0x394e6000}, 
+    {0x394e8000}, {0x394ea000}, {0x394ec000}, {0x394ee000}, 
+    {0x394f0000}, {0x394f2000}, {0x394f4000}, {0x394f6000}, 
+    {0x394f8000}, {0x394fa000}, {0x394fc000}, {0x394fe000}, 
+    {0x39500000}, {0x39502000}, {0x39504000}, {0x39506000}, 
+    {0x39508000}, {0x3950a000}, {0x3950c000}, {0x3950e000}, 
+    {0x39510000}, {0x39512000}, {0x39514000}, {0x39516000}, 
+    {0x39518000}, {0x3951a000}, {0x3951c000}, {0x3951e000}, 
+    {0x39520000}, {0x39522000}, {0x39524000}, {0x39526000}, 
+    {0x39528000}, {0x3952a000}, {0x3952c000}, {0x3952e000}, 
+    {0x39530000}, {0x39532000}, {0x39534000}, {0x39536000}, 
+    {0x39538000}, {0x3953a000}, {0x3953c000}, {0x3953e000}, 
+    {0x39540000}, {0x39542000}, {0x39544000}, {0x39546000}, 
+    {0x39548000}, {0x3954a000}, {0x3954c000}, {0x3954e000}, 
+    {0x39550000}, {0x39552000}, {0x39554000}, {0x39556000}, 
+    {0x39558000}, {0x3955a000}, {0x3955c000}, {0x3955e000}, 
+    {0x39560000}, {0x39562000}, {0x39564000}, {0x39566000}, 
+    {0x39568000}, {0x3956a000}, {0x3956c000}, {0x3956e000}, 
+    {0x39570000}, {0x39572000}, {0x39574000}, {0x39576000}, 
+    {0x39578000}, {0x3957a000}, {0x3957c000}, {0x3957e000}, 
+    {0x39580000}, {0x39582000}, {0x39584000}, {0x39586000}, 
+    {0x39588000}, {0x3958a000}, {0x3958c000}, {0x3958e000}, 
+    {0x39590000}, {0x39592000}, {0x39594000}, {0x39596000}, 
+    {0x39598000}, {0x3959a000}, {0x3959c000}, {0x3959e000}, 
+    {0x395a0000}, {0x395a2000}, {0x395a4000}, {0x395a6000}, 
+    {0x395a8000}, {0x395aa000}, {0x395ac000}, {0x395ae000}, 
+    {0x395b0000}, {0x395b2000}, {0x395b4000}, {0x395b6000}, 
+    {0x395b8000}, {0x395ba000}, {0x395bc000}, {0x395be000}, 
+    {0x395c0000}, {0x395c2000}, {0x395c4000}, {0x395c6000}, 
+    {0x395c8000}, {0x395ca000}, {0x395cc000}, {0x395ce000}, 
+    {0x395d0000}, {0x395d2000}, {0x395d4000}, {0x395d6000}, 
+    {0x395d8000}, {0x395da000}, {0x395dc000}, {0x395de000}, 
+    {0x395e0000}, {0x395e2000}, {0x395e4000}, {0x395e6000}, 
+    {0x395e8000}, {0x395ea000}, {0x395ec000}, {0x395ee000}, 
+    {0x395f0000}, {0x395f2000}, {0x395f4000}, {0x395f6000}, 
+    {0x395f8000}, {0x395fa000}, {0x395fc000}, {0x395fe000}, 
+    {0x39600000}, {0x39602000}, {0x39604000}, {0x39606000}, 
+    {0x39608000}, {0x3960a000}, {0x3960c000}, {0x3960e000}, 
+    {0x39610000}, {0x39612000}, {0x39614000}, {0x39616000}, 
+    {0x39618000}, {0x3961a000}, {0x3961c000}, {0x3961e000}, 
+    {0x39620000}, {0x39622000}, {0x39624000}, {0x39626000}, 
+    {0x39628000}, {0x3962a000}, {0x3962c000}, {0x3962e000}, 
+    {0x39630000}, {0x39632000}, {0x39634000}, {0x39636000}, 
+    {0x39638000}, {0x3963a000}, {0x3963c000}, {0x3963e000}, 
+    {0x39640000}, {0x39642000}, {0x39644000}, {0x39646000}, 
+    {0x39648000}, {0x3964a000}, {0x3964c000}, {0x3964e000}, 
+    {0x39650000}, {0x39652000}, {0x39654000}, {0x39656000}, 
+    {0x39658000}, {0x3965a000}, {0x3965c000}, {0x3965e000}, 
+    {0x39660000}, {0x39662000}, {0x39664000}, {0x39666000}, 
+    {0x39668000}, {0x3966a000}, {0x3966c000}, {0x3966e000}, 
+    {0x39670000}, {0x39672000}, {0x39674000}, {0x39676000}, 
+    {0x39678000}, {0x3967a000}, {0x3967c000}, {0x3967e000}, 
+    {0x39680000}, {0x39682000}, {0x39684000}, {0x39686000}, 
+    {0x39688000}, {0x3968a000}, {0x3968c000}, {0x3968e000}, 
+    {0x39690000}, {0x39692000}, {0x39694000}, {0x39696000}, 
+    {0x39698000}, {0x3969a000}, {0x3969c000}, {0x3969e000}, 
+    {0x396a0000}, {0x396a2000}, {0x396a4000}, {0x396a6000}, 
+    {0x396a8000}, {0x396aa000}, {0x396ac000}, {0x396ae000}, 
+    {0x396b0000}, {0x396b2000}, {0x396b4000}, {0x396b6000}, 
+    {0x396b8000}, {0x396ba000}, {0x396bc000}, {0x396be000}, 
+    {0x396c0000}, {0x396c2000}, {0x396c4000}, {0x396c6000}, 
+    {0x396c8000}, {0x396ca000}, {0x396cc000}, {0x396ce000}, 
+    {0x396d0000}, {0x396d2000}, {0x396d4000}, {0x396d6000}, 
+    {0x396d8000}, {0x396da000}, {0x396dc000}, {0x396de000}, 
+    {0x396e0000}, {0x396e2000}, {0x396e4000}, {0x396e6000}, 
+    {0x396e8000}, {0x396ea000}, {0x396ec000}, {0x396ee000}, 
+    {0x396f0000}, {0x396f2000}, {0x396f4000}, {0x396f6000}, 
+    {0x396f8000}, {0x396fa000}, {0x396fc000}, {0x396fe000}, 
+    {0x39700000}, {0x39702000}, {0x39704000}, {0x39706000}, 
+    {0x39708000}, {0x3970a000}, {0x3970c000}, {0x3970e000}, 
+    {0x39710000}, {0x39712000}, {0x39714000}, {0x39716000}, 
+    {0x39718000}, {0x3971a000}, {0x3971c000}, {0x3971e000}, 
+    {0x39720000}, {0x39722000}, {0x39724000}, {0x39726000}, 
+    {0x39728000}, {0x3972a000}, {0x3972c000}, {0x3972e000}, 
+    {0x39730000}, {0x39732000}, {0x39734000}, {0x39736000}, 
+    {0x39738000}, {0x3973a000}, {0x3973c000}, {0x3973e000}, 
+    {0x39740000}, {0x39742000}, {0x39744000}, {0x39746000}, 
+    {0x39748000}, {0x3974a000}, {0x3974c000}, {0x3974e000}, 
+    {0x39750000}, {0x39752000}, {0x39754000}, {0x39756000}, 
+    {0x39758000}, {0x3975a000}, {0x3975c000}, {0x3975e000}, 
+    {0x39760000}, {0x39762000}, {0x39764000}, {0x39766000}, 
+    {0x39768000}, {0x3976a000}, {0x3976c000}, {0x3976e000}, 
+    {0x39770000}, {0x39772000}, {0x39774000}, {0x39776000}, 
+    {0x39778000}, {0x3977a000}, {0x3977c000}, {0x3977e000}, 
+    {0x39780000}, {0x39782000}, {0x39784000}, {0x39786000}, 
+    {0x39788000}, {0x3978a000}, {0x3978c000}, {0x3978e000}, 
+    {0x39790000}, {0x39792000}, {0x39794000}, {0x39796000}, 
+    {0x39798000}, {0x3979a000}, {0x3979c000}, {0x3979e000}, 
+    {0x397a0000}, {0x397a2000}, {0x397a4000}, {0x397a6000}, 
+    {0x397a8000}, {0x397aa000}, {0x397ac000}, {0x397ae000}, 
+    {0x397b0000}, {0x397b2000}, {0x397b4000}, {0x397b6000}, 
+    {0x397b8000}, {0x397ba000}, {0x397bc000}, {0x397be000}, 
+    {0x397c0000}, {0x397c2000}, {0x397c4000}, {0x397c6000}, 
+    {0x397c8000}, {0x397ca000}, {0x397cc000}, {0x397ce000}, 
+    {0x397d0000}, {0x397d2000}, {0x397d4000}, {0x397d6000}, 
+    {0x397d8000}, {0x397da000}, {0x397dc000}, {0x397de000}, 
+    {0x397e0000}, {0x397e2000}, {0x397e4000}, {0x397e6000}, 
+    {0x397e8000}, {0x397ea000}, {0x397ec000}, {0x397ee000}, 
+    {0x397f0000}, {0x397f2000}, {0x397f4000}, {0x397f6000}, 
+    {0x397f8000}, {0x397fa000}, {0x397fc000}, {0x397fe000}, 
+    {0x39800000}, {0x39802000}, {0x39804000}, {0x39806000}, 
+    {0x39808000}, {0x3980a000}, {0x3980c000}, {0x3980e000}, 
+    {0x39810000}, {0x39812000}, {0x39814000}, {0x39816000}, 
+    {0x39818000}, {0x3981a000}, {0x3981c000}, {0x3981e000}, 
+    {0x39820000}, {0x39822000}, {0x39824000}, {0x39826000}, 
+    {0x39828000}, {0x3982a000}, {0x3982c000}, {0x3982e000}, 
+    {0x39830000}, {0x39832000}, {0x39834000}, {0x39836000}, 
+    {0x39838000}, {0x3983a000}, {0x3983c000}, {0x3983e000}, 
+    {0x39840000}, {0x39842000}, {0x39844000}, {0x39846000}, 
+    {0x39848000}, {0x3984a000}, {0x3984c000}, {0x3984e000}, 
+    {0x39850000}, {0x39852000}, {0x39854000}, {0x39856000}, 
+    {0x39858000}, {0x3985a000}, {0x3985c000}, {0x3985e000}, 
+    {0x39860000}, {0x39862000}, {0x39864000}, {0x39866000}, 
+    {0x39868000}, {0x3986a000}, {0x3986c000}, {0x3986e000}, 
+    {0x39870000}, {0x39872000}, {0x39874000}, {0x39876000}, 
+    {0x39878000}, {0x3987a000}, {0x3987c000}, {0x3987e000}, 
+    {0x39880000}, {0x39882000}, {0x39884000}, {0x39886000}, 
+    {0x39888000}, {0x3988a000}, {0x3988c000}, {0x3988e000}, 
+    {0x39890000}, {0x39892000}, {0x39894000}, {0x39896000}, 
+    {0x39898000}, {0x3989a000}, {0x3989c000}, {0x3989e000}, 
+    {0x398a0000}, {0x398a2000}, {0x398a4000}, {0x398a6000}, 
+    {0x398a8000}, {0x398aa000}, {0x398ac000}, {0x398ae000}, 
+    {0x398b0000}, {0x398b2000}, {0x398b4000}, {0x398b6000}, 
+    {0x398b8000}, {0x398ba000}, {0x398bc000}, {0x398be000}, 
+    {0x398c0000}, {0x398c2000}, {0x398c4000}, {0x398c6000}, 
+    {0x398c8000}, {0x398ca000}, {0x398cc000}, {0x398ce000}, 
+    {0x398d0000}, {0x398d2000}, {0x398d4000}, {0x398d6000}, 
+    {0x398d8000}, {0x398da000}, {0x398dc000}, {0x398de000}, 
+    {0x398e0000}, {0x398e2000}, {0x398e4000}, {0x398e6000}, 
+    {0x398e8000}, {0x398ea000}, {0x398ec000}, {0x398ee000}, 
+    {0x398f0000}, {0x398f2000}, {0x398f4000}, {0x398f6000}, 
+    {0x398f8000}, {0x398fa000}, {0x398fc000}, {0x398fe000}, 
+    {0x39900000}, {0x39902000}, {0x39904000}, {0x39906000}, 
+    {0x39908000}, {0x3990a000}, {0x3990c000}, {0x3990e000}, 
+    {0x39910000}, {0x39912000}, {0x39914000}, {0x39916000}, 
+    {0x39918000}, {0x3991a000}, {0x3991c000}, {0x3991e000}, 
+    {0x39920000}, {0x39922000}, {0x39924000}, {0x39926000}, 
+    {0x39928000}, {0x3992a000}, {0x3992c000}, {0x3992e000}, 
+    {0x39930000}, {0x39932000}, {0x39934000}, {0x39936000}, 
+    {0x39938000}, {0x3993a000}, {0x3993c000}, {0x3993e000}, 
+    {0x39940000}, {0x39942000}, {0x39944000}, {0x39946000}, 
+    {0x39948000}, {0x3994a000}, {0x3994c000}, {0x3994e000}, 
+    {0x39950000}, {0x39952000}, {0x39954000}, {0x39956000}, 
+    {0x39958000}, {0x3995a000}, {0x3995c000}, {0x3995e000}, 
+    {0x39960000}, {0x39962000}, {0x39964000}, {0x39966000}, 
+    {0x39968000}, {0x3996a000}, {0x3996c000}, {0x3996e000}, 
+    {0x39970000}, {0x39972000}, {0x39974000}, {0x39976000}, 
+    {0x39978000}, {0x3997a000}, {0x3997c000}, {0x3997e000}, 
+    {0x39980000}, {0x39982000}, {0x39984000}, {0x39986000}, 
+    {0x39988000}, {0x3998a000}, {0x3998c000}, {0x3998e000}, 
+    {0x39990000}, {0x39992000}, {0x39994000}, {0x39996000}, 
+    {0x39998000}, {0x3999a000}, {0x3999c000}, {0x3999e000}, 
+    {0x399a0000}, {0x399a2000}, {0x399a4000}, {0x399a6000}, 
+    {0x399a8000}, {0x399aa000}, {0x399ac000}, {0x399ae000}, 
+    {0x399b0000}, {0x399b2000}, {0x399b4000}, {0x399b6000}, 
+    {0x399b8000}, {0x399ba000}, {0x399bc000}, {0x399be000}, 
+    {0x399c0000}, {0x399c2000}, {0x399c4000}, {0x399c6000}, 
+    {0x399c8000}, {0x399ca000}, {0x399cc000}, {0x399ce000}, 
+    {0x399d0000}, {0x399d2000}, {0x399d4000}, {0x399d6000}, 
+    {0x399d8000}, {0x399da000}, {0x399dc000}, {0x399de000}, 
+    {0x399e0000}, {0x399e2000}, {0x399e4000}, {0x399e6000}, 
+    {0x399e8000}, {0x399ea000}, {0x399ec000}, {0x399ee000}, 
+    {0x399f0000}, {0x399f2000}, {0x399f4000}, {0x399f6000}, 
+    {0x399f8000}, {0x399fa000}, {0x399fc000}, {0x399fe000}, 
+    {0x39a00000}, {0x39a02000}, {0x39a04000}, {0x39a06000}, 
+    {0x39a08000}, {0x39a0a000}, {0x39a0c000}, {0x39a0e000}, 
+    {0x39a10000}, {0x39a12000}, {0x39a14000}, {0x39a16000}, 
+    {0x39a18000}, {0x39a1a000}, {0x39a1c000}, {0x39a1e000}, 
+    {0x39a20000}, {0x39a22000}, {0x39a24000}, {0x39a26000}, 
+    {0x39a28000}, {0x39a2a000}, {0x39a2c000}, {0x39a2e000}, 
+    {0x39a30000}, {0x39a32000}, {0x39a34000}, {0x39a36000}, 
+    {0x39a38000}, {0x39a3a000}, {0x39a3c000}, {0x39a3e000}, 
+    {0x39a40000}, {0x39a42000}, {0x39a44000}, {0x39a46000}, 
+    {0x39a48000}, {0x39a4a000}, {0x39a4c000}, {0x39a4e000}, 
+    {0x39a50000}, {0x39a52000}, {0x39a54000}, {0x39a56000}, 
+    {0x39a58000}, {0x39a5a000}, {0x39a5c000}, {0x39a5e000}, 
+    {0x39a60000}, {0x39a62000}, {0x39a64000}, {0x39a66000}, 
+    {0x39a68000}, {0x39a6a000}, {0x39a6c000}, {0x39a6e000}, 
+    {0x39a70000}, {0x39a72000}, {0x39a74000}, {0x39a76000}, 
+    {0x39a78000}, {0x39a7a000}, {0x39a7c000}, {0x39a7e000}, 
+    {0x39a80000}, {0x39a82000}, {0x39a84000}, {0x39a86000}, 
+    {0x39a88000}, {0x39a8a000}, {0x39a8c000}, {0x39a8e000}, 
+    {0x39a90000}, {0x39a92000}, {0x39a94000}, {0x39a96000}, 
+    {0x39a98000}, {0x39a9a000}, {0x39a9c000}, {0x39a9e000}, 
+    {0x39aa0000}, {0x39aa2000}, {0x39aa4000}, {0x39aa6000}, 
+    {0x39aa8000}, {0x39aaa000}, {0x39aac000}, {0x39aae000}, 
+    {0x39ab0000}, {0x39ab2000}, {0x39ab4000}, {0x39ab6000}, 
+    {0x39ab8000}, {0x39aba000}, {0x39abc000}, {0x39abe000}, 
+    {0x39ac0000}, {0x39ac2000}, {0x39ac4000}, {0x39ac6000}, 
+    {0x39ac8000}, {0x39aca000}, {0x39acc000}, {0x39ace000}, 
+    {0x39ad0000}, {0x39ad2000}, {0x39ad4000}, {0x39ad6000}, 
+    {0x39ad8000}, {0x39ada000}, {0x39adc000}, {0x39ade000}, 
+    {0x39ae0000}, {0x39ae2000}, {0x39ae4000}, {0x39ae6000}, 
+    {0x39ae8000}, {0x39aea000}, {0x39aec000}, {0x39aee000}, 
+    {0x39af0000}, {0x39af2000}, {0x39af4000}, {0x39af6000}, 
+    {0x39af8000}, {0x39afa000}, {0x39afc000}, {0x39afe000}, 
+    {0x39b00000}, {0x39b02000}, {0x39b04000}, {0x39b06000}, 
+    {0x39b08000}, {0x39b0a000}, {0x39b0c000}, {0x39b0e000}, 
+    {0x39b10000}, {0x39b12000}, {0x39b14000}, {0x39b16000}, 
+    {0x39b18000}, {0x39b1a000}, {0x39b1c000}, {0x39b1e000}, 
+    {0x39b20000}, {0x39b22000}, {0x39b24000}, {0x39b26000}, 
+    {0x39b28000}, {0x39b2a000}, {0x39b2c000}, {0x39b2e000}, 
+    {0x39b30000}, {0x39b32000}, {0x39b34000}, {0x39b36000}, 
+    {0x39b38000}, {0x39b3a000}, {0x39b3c000}, {0x39b3e000}, 
+    {0x39b40000}, {0x39b42000}, {0x39b44000}, {0x39b46000}, 
+    {0x39b48000}, {0x39b4a000}, {0x39b4c000}, {0x39b4e000}, 
+    {0x39b50000}, {0x39b52000}, {0x39b54000}, {0x39b56000}, 
+    {0x39b58000}, {0x39b5a000}, {0x39b5c000}, {0x39b5e000}, 
+    {0x39b60000}, {0x39b62000}, {0x39b64000}, {0x39b66000}, 
+    {0x39b68000}, {0x39b6a000}, {0x39b6c000}, {0x39b6e000}, 
+    {0x39b70000}, {0x39b72000}, {0x39b74000}, {0x39b76000}, 
+    {0x39b78000}, {0x39b7a000}, {0x39b7c000}, {0x39b7e000}, 
+    {0x39b80000}, {0x39b82000}, {0x39b84000}, {0x39b86000}, 
+    {0x39b88000}, {0x39b8a000}, {0x39b8c000}, {0x39b8e000}, 
+    {0x39b90000}, {0x39b92000}, {0x39b94000}, {0x39b96000}, 
+    {0x39b98000}, {0x39b9a000}, {0x39b9c000}, {0x39b9e000}, 
+    {0x39ba0000}, {0x39ba2000}, {0x39ba4000}, {0x39ba6000}, 
+    {0x39ba8000}, {0x39baa000}, {0x39bac000}, {0x39bae000}, 
+    {0x39bb0000}, {0x39bb2000}, {0x39bb4000}, {0x39bb6000}, 
+    {0x39bb8000}, {0x39bba000}, {0x39bbc000}, {0x39bbe000}, 
+    {0x39bc0000}, {0x39bc2000}, {0x39bc4000}, {0x39bc6000}, 
+    {0x39bc8000}, {0x39bca000}, {0x39bcc000}, {0x39bce000}, 
+    {0x39bd0000}, {0x39bd2000}, {0x39bd4000}, {0x39bd6000}, 
+    {0x39bd8000}, {0x39bda000}, {0x39bdc000}, {0x39bde000}, 
+    {0x39be0000}, {0x39be2000}, {0x39be4000}, {0x39be6000}, 
+    {0x39be8000}, {0x39bea000}, {0x39bec000}, {0x39bee000}, 
+    {0x39bf0000}, {0x39bf2000}, {0x39bf4000}, {0x39bf6000}, 
+    {0x39bf8000}, {0x39bfa000}, {0x39bfc000}, {0x39bfe000}, 
+    {0x39c00000}, {0x39c02000}, {0x39c04000}, {0x39c06000}, 
+    {0x39c08000}, {0x39c0a000}, {0x39c0c000}, {0x39c0e000}, 
+    {0x39c10000}, {0x39c12000}, {0x39c14000}, {0x39c16000}, 
+    {0x39c18000}, {0x39c1a000}, {0x39c1c000}, {0x39c1e000}, 
+    {0x39c20000}, {0x39c22000}, {0x39c24000}, {0x39c26000}, 
+    {0x39c28000}, {0x39c2a000}, {0x39c2c000}, {0x39c2e000}, 
+    {0x39c30000}, {0x39c32000}, {0x39c34000}, {0x39c36000}, 
+    {0x39c38000}, {0x39c3a000}, {0x39c3c000}, {0x39c3e000}, 
+    {0x39c40000}, {0x39c42000}, {0x39c44000}, {0x39c46000}, 
+    {0x39c48000}, {0x39c4a000}, {0x39c4c000}, {0x39c4e000}, 
+    {0x39c50000}, {0x39c52000}, {0x39c54000}, {0x39c56000}, 
+    {0x39c58000}, {0x39c5a000}, {0x39c5c000}, {0x39c5e000}, 
+    {0x39c60000}, {0x39c62000}, {0x39c64000}, {0x39c66000}, 
+    {0x39c68000}, {0x39c6a000}, {0x39c6c000}, {0x39c6e000}, 
+    {0x39c70000}, {0x39c72000}, {0x39c74000}, {0x39c76000}, 
+    {0x39c78000}, {0x39c7a000}, {0x39c7c000}, {0x39c7e000}, 
+    {0x39c80000}, {0x39c82000}, {0x39c84000}, {0x39c86000}, 
+    {0x39c88000}, {0x39c8a000}, {0x39c8c000}, {0x39c8e000}, 
+    {0x39c90000}, {0x39c92000}, {0x39c94000}, {0x39c96000}, 
+    {0x39c98000}, {0x39c9a000}, {0x39c9c000}, {0x39c9e000}, 
+    {0x39ca0000}, {0x39ca2000}, {0x39ca4000}, {0x39ca6000}, 
+    {0x39ca8000}, {0x39caa000}, {0x39cac000}, {0x39cae000}, 
+    {0x39cb0000}, {0x39cb2000}, {0x39cb4000}, {0x39cb6000}, 
+    {0x39cb8000}, {0x39cba000}, {0x39cbc000}, {0x39cbe000}, 
+    {0x39cc0000}, {0x39cc2000}, {0x39cc4000}, {0x39cc6000}, 
+    {0x39cc8000}, {0x39cca000}, {0x39ccc000}, {0x39cce000}, 
+    {0x39cd0000}, {0x39cd2000}, {0x39cd4000}, {0x39cd6000}, 
+    {0x39cd8000}, {0x39cda000}, {0x39cdc000}, {0x39cde000}, 
+    {0x39ce0000}, {0x39ce2000}, {0x39ce4000}, {0x39ce6000}, 
+    {0x39ce8000}, {0x39cea000}, {0x39cec000}, {0x39cee000}, 
+    {0x39cf0000}, {0x39cf2000}, {0x39cf4000}, {0x39cf6000}, 
+    {0x39cf8000}, {0x39cfa000}, {0x39cfc000}, {0x39cfe000}, 
+    {0x39d00000}, {0x39d02000}, {0x39d04000}, {0x39d06000}, 
+    {0x39d08000}, {0x39d0a000}, {0x39d0c000}, {0x39d0e000}, 
+    {0x39d10000}, {0x39d12000}, {0x39d14000}, {0x39d16000}, 
+    {0x39d18000}, {0x39d1a000}, {0x39d1c000}, {0x39d1e000}, 
+    {0x39d20000}, {0x39d22000}, {0x39d24000}, {0x39d26000}, 
+    {0x39d28000}, {0x39d2a000}, {0x39d2c000}, {0x39d2e000}, 
+    {0x39d30000}, {0x39d32000}, {0x39d34000}, {0x39d36000}, 
+    {0x39d38000}, {0x39d3a000}, {0x39d3c000}, {0x39d3e000}, 
+    {0x39d40000}, {0x39d42000}, {0x39d44000}, {0x39d46000}, 
+    {0x39d48000}, {0x39d4a000}, {0x39d4c000}, {0x39d4e000}, 
+    {0x39d50000}, {0x39d52000}, {0x39d54000}, {0x39d56000}, 
+    {0x39d58000}, {0x39d5a000}, {0x39d5c000}, {0x39d5e000}, 
+    {0x39d60000}, {0x39d62000}, {0x39d64000}, {0x39d66000}, 
+    {0x39d68000}, {0x39d6a000}, {0x39d6c000}, {0x39d6e000}, 
+    {0x39d70000}, {0x39d72000}, {0x39d74000}, {0x39d76000}, 
+    {0x39d78000}, {0x39d7a000}, {0x39d7c000}, {0x39d7e000}, 
+    {0x39d80000}, {0x39d82000}, {0x39d84000}, {0x39d86000}, 
+    {0x39d88000}, {0x39d8a000}, {0x39d8c000}, {0x39d8e000}, 
+    {0x39d90000}, {0x39d92000}, {0x39d94000}, {0x39d96000}, 
+    {0x39d98000}, {0x39d9a000}, {0x39d9c000}, {0x39d9e000}, 
+    {0x39da0000}, {0x39da2000}, {0x39da4000}, {0x39da6000}, 
+    {0x39da8000}, {0x39daa000}, {0x39dac000}, {0x39dae000}, 
+    {0x39db0000}, {0x39db2000}, {0x39db4000}, {0x39db6000}, 
+    {0x39db8000}, {0x39dba000}, {0x39dbc000}, {0x39dbe000}, 
+    {0x39dc0000}, {0x39dc2000}, {0x39dc4000}, {0x39dc6000}, 
+    {0x39dc8000}, {0x39dca000}, {0x39dcc000}, {0x39dce000}, 
+    {0x39dd0000}, {0x39dd2000}, {0x39dd4000}, {0x39dd6000}, 
+    {0x39dd8000}, {0x39dda000}, {0x39ddc000}, {0x39dde000}, 
+    {0x39de0000}, {0x39de2000}, {0x39de4000}, {0x39de6000}, 
+    {0x39de8000}, {0x39dea000}, {0x39dec000}, {0x39dee000}, 
+    {0x39df0000}, {0x39df2000}, {0x39df4000}, {0x39df6000}, 
+    {0x39df8000}, {0x39dfa000}, {0x39dfc000}, {0x39dfe000}, 
+    {0x39e00000}, {0x39e02000}, {0x39e04000}, {0x39e06000}, 
+    {0x39e08000}, {0x39e0a000}, {0x39e0c000}, {0x39e0e000}, 
+    {0x39e10000}, {0x39e12000}, {0x39e14000}, {0x39e16000}, 
+    {0x39e18000}, {0x39e1a000}, {0x39e1c000}, {0x39e1e000}, 
+    {0x39e20000}, {0x39e22000}, {0x39e24000}, {0x39e26000}, 
+    {0x39e28000}, {0x39e2a000}, {0x39e2c000}, {0x39e2e000}, 
+    {0x39e30000}, {0x39e32000}, {0x39e34000}, {0x39e36000}, 
+    {0x39e38000}, {0x39e3a000}, {0x39e3c000}, {0x39e3e000}, 
+    {0x39e40000}, {0x39e42000}, {0x39e44000}, {0x39e46000}, 
+    {0x39e48000}, {0x39e4a000}, {0x39e4c000}, {0x39e4e000}, 
+    {0x39e50000}, {0x39e52000}, {0x39e54000}, {0x39e56000}, 
+    {0x39e58000}, {0x39e5a000}, {0x39e5c000}, {0x39e5e000}, 
+    {0x39e60000}, {0x39e62000}, {0x39e64000}, {0x39e66000}, 
+    {0x39e68000}, {0x39e6a000}, {0x39e6c000}, {0x39e6e000}, 
+    {0x39e70000}, {0x39e72000}, {0x39e74000}, {0x39e76000}, 
+    {0x39e78000}, {0x39e7a000}, {0x39e7c000}, {0x39e7e000}, 
+    {0x39e80000}, {0x39e82000}, {0x39e84000}, {0x39e86000}, 
+    {0x39e88000}, {0x39e8a000}, {0x39e8c000}, {0x39e8e000}, 
+    {0x39e90000}, {0x39e92000}, {0x39e94000}, {0x39e96000}, 
+    {0x39e98000}, {0x39e9a000}, {0x39e9c000}, {0x39e9e000}, 
+    {0x39ea0000}, {0x39ea2000}, {0x39ea4000}, {0x39ea6000}, 
+    {0x39ea8000}, {0x39eaa000}, {0x39eac000}, {0x39eae000}, 
+    {0x39eb0000}, {0x39eb2000}, {0x39eb4000}, {0x39eb6000}, 
+    {0x39eb8000}, {0x39eba000}, {0x39ebc000}, {0x39ebe000}, 
+    {0x39ec0000}, {0x39ec2000}, {0x39ec4000}, {0x39ec6000}, 
+    {0x39ec8000}, {0x39eca000}, {0x39ecc000}, {0x39ece000}, 
+    {0x39ed0000}, {0x39ed2000}, {0x39ed4000}, {0x39ed6000}, 
+    {0x39ed8000}, {0x39eda000}, {0x39edc000}, {0x39ede000}, 
+    {0x39ee0000}, {0x39ee2000}, {0x39ee4000}, {0x39ee6000}, 
+    {0x39ee8000}, {0x39eea000}, {0x39eec000}, {0x39eee000}, 
+    {0x39ef0000}, {0x39ef2000}, {0x39ef4000}, {0x39ef6000}, 
+    {0x39ef8000}, {0x39efa000}, {0x39efc000}, {0x39efe000}, 
+    {0x39f00000}, {0x39f02000}, {0x39f04000}, {0x39f06000}, 
+    {0x39f08000}, {0x39f0a000}, {0x39f0c000}, {0x39f0e000}, 
+    {0x39f10000}, {0x39f12000}, {0x39f14000}, {0x39f16000}, 
+    {0x39f18000}, {0x39f1a000}, {0x39f1c000}, {0x39f1e000}, 
+    {0x39f20000}, {0x39f22000}, {0x39f24000}, {0x39f26000}, 
+    {0x39f28000}, {0x39f2a000}, {0x39f2c000}, {0x39f2e000}, 
+    {0x39f30000}, {0x39f32000}, {0x39f34000}, {0x39f36000}, 
+    {0x39f38000}, {0x39f3a000}, {0x39f3c000}, {0x39f3e000}, 
+    {0x39f40000}, {0x39f42000}, {0x39f44000}, {0x39f46000}, 
+    {0x39f48000}, {0x39f4a000}, {0x39f4c000}, {0x39f4e000}, 
+    {0x39f50000}, {0x39f52000}, {0x39f54000}, {0x39f56000}, 
+    {0x39f58000}, {0x39f5a000}, {0x39f5c000}, {0x39f5e000}, 
+    {0x39f60000}, {0x39f62000}, {0x39f64000}, {0x39f66000}, 
+    {0x39f68000}, {0x39f6a000}, {0x39f6c000}, {0x39f6e000}, 
+    {0x39f70000}, {0x39f72000}, {0x39f74000}, {0x39f76000}, 
+    {0x39f78000}, {0x39f7a000}, {0x39f7c000}, {0x39f7e000}, 
+    {0x39f80000}, {0x39f82000}, {0x39f84000}, {0x39f86000}, 
+    {0x39f88000}, {0x39f8a000}, {0x39f8c000}, {0x39f8e000}, 
+    {0x39f90000}, {0x39f92000}, {0x39f94000}, {0x39f96000}, 
+    {0x39f98000}, {0x39f9a000}, {0x39f9c000}, {0x39f9e000}, 
+    {0x39fa0000}, {0x39fa2000}, {0x39fa4000}, {0x39fa6000}, 
+    {0x39fa8000}, {0x39faa000}, {0x39fac000}, {0x39fae000}, 
+    {0x39fb0000}, {0x39fb2000}, {0x39fb4000}, {0x39fb6000}, 
+    {0x39fb8000}, {0x39fba000}, {0x39fbc000}, {0x39fbe000}, 
+    {0x39fc0000}, {0x39fc2000}, {0x39fc4000}, {0x39fc6000}, 
+    {0x39fc8000}, {0x39fca000}, {0x39fcc000}, {0x39fce000}, 
+    {0x39fd0000}, {0x39fd2000}, {0x39fd4000}, {0x39fd6000}, 
+    {0x39fd8000}, {0x39fda000}, {0x39fdc000}, {0x39fde000}, 
+    {0x39fe0000}, {0x39fe2000}, {0x39fe4000}, {0x39fe6000}, 
+    {0x39fe8000}, {0x39fea000}, {0x39fec000}, {0x39fee000}, 
+    {0x39ff0000}, {0x39ff2000}, {0x39ff4000}, {0x39ff6000}, 
+    {0x39ff8000}, {0x39ffa000}, {0x39ffc000}, {0x39ffe000}, 
+    {0x3a000000}, {0x3a002000}, {0x3a004000}, {0x3a006000}, 
+    {0x3a008000}, {0x3a00a000}, {0x3a00c000}, {0x3a00e000}, 
+    {0x3a010000}, {0x3a012000}, {0x3a014000}, {0x3a016000}, 
+    {0x3a018000}, {0x3a01a000}, {0x3a01c000}, {0x3a01e000}, 
+    {0x3a020000}, {0x3a022000}, {0x3a024000}, {0x3a026000}, 
+    {0x3a028000}, {0x3a02a000}, {0x3a02c000}, {0x3a02e000}, 
+    {0x3a030000}, {0x3a032000}, {0x3a034000}, {0x3a036000}, 
+    {0x3a038000}, {0x3a03a000}, {0x3a03c000}, {0x3a03e000}, 
+    {0x3a040000}, {0x3a042000}, {0x3a044000}, {0x3a046000}, 
+    {0x3a048000}, {0x3a04a000}, {0x3a04c000}, {0x3a04e000}, 
+    {0x3a050000}, {0x3a052000}, {0x3a054000}, {0x3a056000}, 
+    {0x3a058000}, {0x3a05a000}, {0x3a05c000}, {0x3a05e000}, 
+    {0x3a060000}, {0x3a062000}, {0x3a064000}, {0x3a066000}, 
+    {0x3a068000}, {0x3a06a000}, {0x3a06c000}, {0x3a06e000}, 
+    {0x3a070000}, {0x3a072000}, {0x3a074000}, {0x3a076000}, 
+    {0x3a078000}, {0x3a07a000}, {0x3a07c000}, {0x3a07e000}, 
+    {0x3a080000}, {0x3a082000}, {0x3a084000}, {0x3a086000}, 
+    {0x3a088000}, {0x3a08a000}, {0x3a08c000}, {0x3a08e000}, 
+    {0x3a090000}, {0x3a092000}, {0x3a094000}, {0x3a096000}, 
+    {0x3a098000}, {0x3a09a000}, {0x3a09c000}, {0x3a09e000}, 
+    {0x3a0a0000}, {0x3a0a2000}, {0x3a0a4000}, {0x3a0a6000}, 
+    {0x3a0a8000}, {0x3a0aa000}, {0x3a0ac000}, {0x3a0ae000}, 
+    {0x3a0b0000}, {0x3a0b2000}, {0x3a0b4000}, {0x3a0b6000}, 
+    {0x3a0b8000}, {0x3a0ba000}, {0x3a0bc000}, {0x3a0be000}, 
+    {0x3a0c0000}, {0x3a0c2000}, {0x3a0c4000}, {0x3a0c6000}, 
+    {0x3a0c8000}, {0x3a0ca000}, {0x3a0cc000}, {0x3a0ce000}, 
+    {0x3a0d0000}, {0x3a0d2000}, {0x3a0d4000}, {0x3a0d6000}, 
+    {0x3a0d8000}, {0x3a0da000}, {0x3a0dc000}, {0x3a0de000}, 
+    {0x3a0e0000}, {0x3a0e2000}, {0x3a0e4000}, {0x3a0e6000}, 
+    {0x3a0e8000}, {0x3a0ea000}, {0x3a0ec000}, {0x3a0ee000}, 
+    {0x3a0f0000}, {0x3a0f2000}, {0x3a0f4000}, {0x3a0f6000}, 
+    {0x3a0f8000}, {0x3a0fa000}, {0x3a0fc000}, {0x3a0fe000}, 
+    {0x3a100000}, {0x3a102000}, {0x3a104000}, {0x3a106000}, 
+    {0x3a108000}, {0x3a10a000}, {0x3a10c000}, {0x3a10e000}, 
+    {0x3a110000}, {0x3a112000}, {0x3a114000}, {0x3a116000}, 
+    {0x3a118000}, {0x3a11a000}, {0x3a11c000}, {0x3a11e000}, 
+    {0x3a120000}, {0x3a122000}, {0x3a124000}, {0x3a126000}, 
+    {0x3a128000}, {0x3a12a000}, {0x3a12c000}, {0x3a12e000}, 
+    {0x3a130000}, {0x3a132000}, {0x3a134000}, {0x3a136000}, 
+    {0x3a138000}, {0x3a13a000}, {0x3a13c000}, {0x3a13e000}, 
+    {0x3a140000}, {0x3a142000}, {0x3a144000}, {0x3a146000}, 
+    {0x3a148000}, {0x3a14a000}, {0x3a14c000}, {0x3a14e000}, 
+    {0x3a150000}, {0x3a152000}, {0x3a154000}, {0x3a156000}, 
+    {0x3a158000}, {0x3a15a000}, {0x3a15c000}, {0x3a15e000}, 
+    {0x3a160000}, {0x3a162000}, {0x3a164000}, {0x3a166000}, 
+    {0x3a168000}, {0x3a16a000}, {0x3a16c000}, {0x3a16e000}, 
+    {0x3a170000}, {0x3a172000}, {0x3a174000}, {0x3a176000}, 
+    {0x3a178000}, {0x3a17a000}, {0x3a17c000}, {0x3a17e000}, 
+    {0x3a180000}, {0x3a182000}, {0x3a184000}, {0x3a186000}, 
+    {0x3a188000}, {0x3a18a000}, {0x3a18c000}, {0x3a18e000}, 
+    {0x3a190000}, {0x3a192000}, {0x3a194000}, {0x3a196000}, 
+    {0x3a198000}, {0x3a19a000}, {0x3a19c000}, {0x3a19e000}, 
+    {0x3a1a0000}, {0x3a1a2000}, {0x3a1a4000}, {0x3a1a6000}, 
+    {0x3a1a8000}, {0x3a1aa000}, {0x3a1ac000}, {0x3a1ae000}, 
+    {0x3a1b0000}, {0x3a1b2000}, {0x3a1b4000}, {0x3a1b6000}, 
+    {0x3a1b8000}, {0x3a1ba000}, {0x3a1bc000}, {0x3a1be000}, 
+    {0x3a1c0000}, {0x3a1c2000}, {0x3a1c4000}, {0x3a1c6000}, 
+    {0x3a1c8000}, {0x3a1ca000}, {0x3a1cc000}, {0x3a1ce000}, 
+    {0x3a1d0000}, {0x3a1d2000}, {0x3a1d4000}, {0x3a1d6000}, 
+    {0x3a1d8000}, {0x3a1da000}, {0x3a1dc000}, {0x3a1de000}, 
+    {0x3a1e0000}, {0x3a1e2000}, {0x3a1e4000}, {0x3a1e6000}, 
+    {0x3a1e8000}, {0x3a1ea000}, {0x3a1ec000}, {0x3a1ee000}, 
+    {0x3a1f0000}, {0x3a1f2000}, {0x3a1f4000}, {0x3a1f6000}, 
+    {0x3a1f8000}, {0x3a1fa000}, {0x3a1fc000}, {0x3a1fe000}, 
+    {0x3a200000}, {0x3a202000}, {0x3a204000}, {0x3a206000}, 
+    {0x3a208000}, {0x3a20a000}, {0x3a20c000}, {0x3a20e000}, 
+    {0x3a210000}, {0x3a212000}, {0x3a214000}, {0x3a216000}, 
+    {0x3a218000}, {0x3a21a000}, {0x3a21c000}, {0x3a21e000}, 
+    {0x3a220000}, {0x3a222000}, {0x3a224000}, {0x3a226000}, 
+    {0x3a228000}, {0x3a22a000}, {0x3a22c000}, {0x3a22e000}, 
+    {0x3a230000}, {0x3a232000}, {0x3a234000}, {0x3a236000}, 
+    {0x3a238000}, {0x3a23a000}, {0x3a23c000}, {0x3a23e000}, 
+    {0x3a240000}, {0x3a242000}, {0x3a244000}, {0x3a246000}, 
+    {0x3a248000}, {0x3a24a000}, {0x3a24c000}, {0x3a24e000}, 
+    {0x3a250000}, {0x3a252000}, {0x3a254000}, {0x3a256000}, 
+    {0x3a258000}, {0x3a25a000}, {0x3a25c000}, {0x3a25e000}, 
+    {0x3a260000}, {0x3a262000}, {0x3a264000}, {0x3a266000}, 
+    {0x3a268000}, {0x3a26a000}, {0x3a26c000}, {0x3a26e000}, 
+    {0x3a270000}, {0x3a272000}, {0x3a274000}, {0x3a276000}, 
+    {0x3a278000}, {0x3a27a000}, {0x3a27c000}, {0x3a27e000}, 
+    {0x3a280000}, {0x3a282000}, {0x3a284000}, {0x3a286000}, 
+    {0x3a288000}, {0x3a28a000}, {0x3a28c000}, {0x3a28e000}, 
+    {0x3a290000}, {0x3a292000}, {0x3a294000}, {0x3a296000}, 
+    {0x3a298000}, {0x3a29a000}, {0x3a29c000}, {0x3a29e000}, 
+    {0x3a2a0000}, {0x3a2a2000}, {0x3a2a4000}, {0x3a2a6000}, 
+    {0x3a2a8000}, {0x3a2aa000}, {0x3a2ac000}, {0x3a2ae000}, 
+    {0x3a2b0000}, {0x3a2b2000}, {0x3a2b4000}, {0x3a2b6000}, 
+    {0x3a2b8000}, {0x3a2ba000}, {0x3a2bc000}, {0x3a2be000}, 
+    {0x3a2c0000}, {0x3a2c2000}, {0x3a2c4000}, {0x3a2c6000}, 
+    {0x3a2c8000}, {0x3a2ca000}, {0x3a2cc000}, {0x3a2ce000}, 
+    {0x3a2d0000}, {0x3a2d2000}, {0x3a2d4000}, {0x3a2d6000}, 
+    {0x3a2d8000}, {0x3a2da000}, {0x3a2dc000}, {0x3a2de000}, 
+    {0x3a2e0000}, {0x3a2e2000}, {0x3a2e4000}, {0x3a2e6000}, 
+    {0x3a2e8000}, {0x3a2ea000}, {0x3a2ec000}, {0x3a2ee000}, 
+    {0x3a2f0000}, {0x3a2f2000}, {0x3a2f4000}, {0x3a2f6000}, 
+    {0x3a2f8000}, {0x3a2fa000}, {0x3a2fc000}, {0x3a2fe000}, 
+    {0x3a300000}, {0x3a302000}, {0x3a304000}, {0x3a306000}, 
+    {0x3a308000}, {0x3a30a000}, {0x3a30c000}, {0x3a30e000}, 
+    {0x3a310000}, {0x3a312000}, {0x3a314000}, {0x3a316000}, 
+    {0x3a318000}, {0x3a31a000}, {0x3a31c000}, {0x3a31e000}, 
+    {0x3a320000}, {0x3a322000}, {0x3a324000}, {0x3a326000}, 
+    {0x3a328000}, {0x3a32a000}, {0x3a32c000}, {0x3a32e000}, 
+    {0x3a330000}, {0x3a332000}, {0x3a334000}, {0x3a336000}, 
+    {0x3a338000}, {0x3a33a000}, {0x3a33c000}, {0x3a33e000}, 
+    {0x3a340000}, {0x3a342000}, {0x3a344000}, {0x3a346000}, 
+    {0x3a348000}, {0x3a34a000}, {0x3a34c000}, {0x3a34e000}, 
+    {0x3a350000}, {0x3a352000}, {0x3a354000}, {0x3a356000}, 
+    {0x3a358000}, {0x3a35a000}, {0x3a35c000}, {0x3a35e000}, 
+    {0x3a360000}, {0x3a362000}, {0x3a364000}, {0x3a366000}, 
+    {0x3a368000}, {0x3a36a000}, {0x3a36c000}, {0x3a36e000}, 
+    {0x3a370000}, {0x3a372000}, {0x3a374000}, {0x3a376000}, 
+    {0x3a378000}, {0x3a37a000}, {0x3a37c000}, {0x3a37e000}, 
+    {0x3a380000}, {0x3a382000}, {0x3a384000}, {0x3a386000}, 
+    {0x3a388000}, {0x3a38a000}, {0x3a38c000}, {0x3a38e000}, 
+    {0x3a390000}, {0x3a392000}, {0x3a394000}, {0x3a396000}, 
+    {0x3a398000}, {0x3a39a000}, {0x3a39c000}, {0x3a39e000}, 
+    {0x3a3a0000}, {0x3a3a2000}, {0x3a3a4000}, {0x3a3a6000}, 
+    {0x3a3a8000}, {0x3a3aa000}, {0x3a3ac000}, {0x3a3ae000}, 
+    {0x3a3b0000}, {0x3a3b2000}, {0x3a3b4000}, {0x3a3b6000}, 
+    {0x3a3b8000}, {0x3a3ba000}, {0x3a3bc000}, {0x3a3be000}, 
+    {0x3a3c0000}, {0x3a3c2000}, {0x3a3c4000}, {0x3a3c6000}, 
+    {0x3a3c8000}, {0x3a3ca000}, {0x3a3cc000}, {0x3a3ce000}, 
+    {0x3a3d0000}, {0x3a3d2000}, {0x3a3d4000}, {0x3a3d6000}, 
+    {0x3a3d8000}, {0x3a3da000}, {0x3a3dc000}, {0x3a3de000}, 
+    {0x3a3e0000}, {0x3a3e2000}, {0x3a3e4000}, {0x3a3e6000}, 
+    {0x3a3e8000}, {0x3a3ea000}, {0x3a3ec000}, {0x3a3ee000}, 
+    {0x3a3f0000}, {0x3a3f2000}, {0x3a3f4000}, {0x3a3f6000}, 
+    {0x3a3f8000}, {0x3a3fa000}, {0x3a3fc000}, {0x3a3fe000}, 
+    {0x3a400000}, {0x3a402000}, {0x3a404000}, {0x3a406000}, 
+    {0x3a408000}, {0x3a40a000}, {0x3a40c000}, {0x3a40e000}, 
+    {0x3a410000}, {0x3a412000}, {0x3a414000}, {0x3a416000}, 
+    {0x3a418000}, {0x3a41a000}, {0x3a41c000}, {0x3a41e000}, 
+    {0x3a420000}, {0x3a422000}, {0x3a424000}, {0x3a426000}, 
+    {0x3a428000}, {0x3a42a000}, {0x3a42c000}, {0x3a42e000}, 
+    {0x3a430000}, {0x3a432000}, {0x3a434000}, {0x3a436000}, 
+    {0x3a438000}, {0x3a43a000}, {0x3a43c000}, {0x3a43e000}, 
+    {0x3a440000}, {0x3a442000}, {0x3a444000}, {0x3a446000}, 
+    {0x3a448000}, {0x3a44a000}, {0x3a44c000}, {0x3a44e000}, 
+    {0x3a450000}, {0x3a452000}, {0x3a454000}, {0x3a456000}, 
+    {0x3a458000}, {0x3a45a000}, {0x3a45c000}, {0x3a45e000}, 
+    {0x3a460000}, {0x3a462000}, {0x3a464000}, {0x3a466000}, 
+    {0x3a468000}, {0x3a46a000}, {0x3a46c000}, {0x3a46e000}, 
+    {0x3a470000}, {0x3a472000}, {0x3a474000}, {0x3a476000}, 
+    {0x3a478000}, {0x3a47a000}, {0x3a47c000}, {0x3a47e000}, 
+    {0x3a480000}, {0x3a482000}, {0x3a484000}, {0x3a486000}, 
+    {0x3a488000}, {0x3a48a000}, {0x3a48c000}, {0x3a48e000}, 
+    {0x3a490000}, {0x3a492000}, {0x3a494000}, {0x3a496000}, 
+    {0x3a498000}, {0x3a49a000}, {0x3a49c000}, {0x3a49e000}, 
+    {0x3a4a0000}, {0x3a4a2000}, {0x3a4a4000}, {0x3a4a6000}, 
+    {0x3a4a8000}, {0x3a4aa000}, {0x3a4ac000}, {0x3a4ae000}, 
+    {0x3a4b0000}, {0x3a4b2000}, {0x3a4b4000}, {0x3a4b6000}, 
+    {0x3a4b8000}, {0x3a4ba000}, {0x3a4bc000}, {0x3a4be000}, 
+    {0x3a4c0000}, {0x3a4c2000}, {0x3a4c4000}, {0x3a4c6000}, 
+    {0x3a4c8000}, {0x3a4ca000}, {0x3a4cc000}, {0x3a4ce000}, 
+    {0x3a4d0000}, {0x3a4d2000}, {0x3a4d4000}, {0x3a4d6000}, 
+    {0x3a4d8000}, {0x3a4da000}, {0x3a4dc000}, {0x3a4de000}, 
+    {0x3a4e0000}, {0x3a4e2000}, {0x3a4e4000}, {0x3a4e6000}, 
+    {0x3a4e8000}, {0x3a4ea000}, {0x3a4ec000}, {0x3a4ee000}, 
+    {0x3a4f0000}, {0x3a4f2000}, {0x3a4f4000}, {0x3a4f6000}, 
+    {0x3a4f8000}, {0x3a4fa000}, {0x3a4fc000}, {0x3a4fe000}, 
+    {0x3a500000}, {0x3a502000}, {0x3a504000}, {0x3a506000}, 
+    {0x3a508000}, {0x3a50a000}, {0x3a50c000}, {0x3a50e000}, 
+    {0x3a510000}, {0x3a512000}, {0x3a514000}, {0x3a516000}, 
+    {0x3a518000}, {0x3a51a000}, {0x3a51c000}, {0x3a51e000}, 
+    {0x3a520000}, {0x3a522000}, {0x3a524000}, {0x3a526000}, 
+    {0x3a528000}, {0x3a52a000}, {0x3a52c000}, {0x3a52e000}, 
+    {0x3a530000}, {0x3a532000}, {0x3a534000}, {0x3a536000}, 
+    {0x3a538000}, {0x3a53a000}, {0x3a53c000}, {0x3a53e000}, 
+    {0x3a540000}, {0x3a542000}, {0x3a544000}, {0x3a546000}, 
+    {0x3a548000}, {0x3a54a000}, {0x3a54c000}, {0x3a54e000}, 
+    {0x3a550000}, {0x3a552000}, {0x3a554000}, {0x3a556000}, 
+    {0x3a558000}, {0x3a55a000}, {0x3a55c000}, {0x3a55e000}, 
+    {0x3a560000}, {0x3a562000}, {0x3a564000}, {0x3a566000}, 
+    {0x3a568000}, {0x3a56a000}, {0x3a56c000}, {0x3a56e000}, 
+    {0x3a570000}, {0x3a572000}, {0x3a574000}, {0x3a576000}, 
+    {0x3a578000}, {0x3a57a000}, {0x3a57c000}, {0x3a57e000}, 
+    {0x3a580000}, {0x3a582000}, {0x3a584000}, {0x3a586000}, 
+    {0x3a588000}, {0x3a58a000}, {0x3a58c000}, {0x3a58e000}, 
+    {0x3a590000}, {0x3a592000}, {0x3a594000}, {0x3a596000}, 
+    {0x3a598000}, {0x3a59a000}, {0x3a59c000}, {0x3a59e000}, 
+    {0x3a5a0000}, {0x3a5a2000}, {0x3a5a4000}, {0x3a5a6000}, 
+    {0x3a5a8000}, {0x3a5aa000}, {0x3a5ac000}, {0x3a5ae000}, 
+    {0x3a5b0000}, {0x3a5b2000}, {0x3a5b4000}, {0x3a5b6000}, 
+    {0x3a5b8000}, {0x3a5ba000}, {0x3a5bc000}, {0x3a5be000}, 
+    {0x3a5c0000}, {0x3a5c2000}, {0x3a5c4000}, {0x3a5c6000}, 
+    {0x3a5c8000}, {0x3a5ca000}, {0x3a5cc000}, {0x3a5ce000}, 
+    {0x3a5d0000}, {0x3a5d2000}, {0x3a5d4000}, {0x3a5d6000}, 
+    {0x3a5d8000}, {0x3a5da000}, {0x3a5dc000}, {0x3a5de000}, 
+    {0x3a5e0000}, {0x3a5e2000}, {0x3a5e4000}, {0x3a5e6000}, 
+    {0x3a5e8000}, {0x3a5ea000}, {0x3a5ec000}, {0x3a5ee000}, 
+    {0x3a5f0000}, {0x3a5f2000}, {0x3a5f4000}, {0x3a5f6000}, 
+    {0x3a5f8000}, {0x3a5fa000}, {0x3a5fc000}, {0x3a5fe000}, 
+    {0x3a600000}, {0x3a602000}, {0x3a604000}, {0x3a606000}, 
+    {0x3a608000}, {0x3a60a000}, {0x3a60c000}, {0x3a60e000}, 
+    {0x3a610000}, {0x3a612000}, {0x3a614000}, {0x3a616000}, 
+    {0x3a618000}, {0x3a61a000}, {0x3a61c000}, {0x3a61e000}, 
+    {0x3a620000}, {0x3a622000}, {0x3a624000}, {0x3a626000}, 
+    {0x3a628000}, {0x3a62a000}, {0x3a62c000}, {0x3a62e000}, 
+    {0x3a630000}, {0x3a632000}, {0x3a634000}, {0x3a636000}, 
+    {0x3a638000}, {0x3a63a000}, {0x3a63c000}, {0x3a63e000}, 
+    {0x3a640000}, {0x3a642000}, {0x3a644000}, {0x3a646000}, 
+    {0x3a648000}, {0x3a64a000}, {0x3a64c000}, {0x3a64e000}, 
+    {0x3a650000}, {0x3a652000}, {0x3a654000}, {0x3a656000}, 
+    {0x3a658000}, {0x3a65a000}, {0x3a65c000}, {0x3a65e000}, 
+    {0x3a660000}, {0x3a662000}, {0x3a664000}, {0x3a666000}, 
+    {0x3a668000}, {0x3a66a000}, {0x3a66c000}, {0x3a66e000}, 
+    {0x3a670000}, {0x3a672000}, {0x3a674000}, {0x3a676000}, 
+    {0x3a678000}, {0x3a67a000}, {0x3a67c000}, {0x3a67e000}, 
+    {0x3a680000}, {0x3a682000}, {0x3a684000}, {0x3a686000}, 
+    {0x3a688000}, {0x3a68a000}, {0x3a68c000}, {0x3a68e000}, 
+    {0x3a690000}, {0x3a692000}, {0x3a694000}, {0x3a696000}, 
+    {0x3a698000}, {0x3a69a000}, {0x3a69c000}, {0x3a69e000}, 
+    {0x3a6a0000}, {0x3a6a2000}, {0x3a6a4000}, {0x3a6a6000}, 
+    {0x3a6a8000}, {0x3a6aa000}, {0x3a6ac000}, {0x3a6ae000}, 
+    {0x3a6b0000}, {0x3a6b2000}, {0x3a6b4000}, {0x3a6b6000}, 
+    {0x3a6b8000}, {0x3a6ba000}, {0x3a6bc000}, {0x3a6be000}, 
+    {0x3a6c0000}, {0x3a6c2000}, {0x3a6c4000}, {0x3a6c6000}, 
+    {0x3a6c8000}, {0x3a6ca000}, {0x3a6cc000}, {0x3a6ce000}, 
+    {0x3a6d0000}, {0x3a6d2000}, {0x3a6d4000}, {0x3a6d6000}, 
+    {0x3a6d8000}, {0x3a6da000}, {0x3a6dc000}, {0x3a6de000}, 
+    {0x3a6e0000}, {0x3a6e2000}, {0x3a6e4000}, {0x3a6e6000}, 
+    {0x3a6e8000}, {0x3a6ea000}, {0x3a6ec000}, {0x3a6ee000}, 
+    {0x3a6f0000}, {0x3a6f2000}, {0x3a6f4000}, {0x3a6f6000}, 
+    {0x3a6f8000}, {0x3a6fa000}, {0x3a6fc000}, {0x3a6fe000}, 
+    {0x3a700000}, {0x3a702000}, {0x3a704000}, {0x3a706000}, 
+    {0x3a708000}, {0x3a70a000}, {0x3a70c000}, {0x3a70e000}, 
+    {0x3a710000}, {0x3a712000}, {0x3a714000}, {0x3a716000}, 
+    {0x3a718000}, {0x3a71a000}, {0x3a71c000}, {0x3a71e000}, 
+    {0x3a720000}, {0x3a722000}, {0x3a724000}, {0x3a726000}, 
+    {0x3a728000}, {0x3a72a000}, {0x3a72c000}, {0x3a72e000}, 
+    {0x3a730000}, {0x3a732000}, {0x3a734000}, {0x3a736000}, 
+    {0x3a738000}, {0x3a73a000}, {0x3a73c000}, {0x3a73e000}, 
+    {0x3a740000}, {0x3a742000}, {0x3a744000}, {0x3a746000}, 
+    {0x3a748000}, {0x3a74a000}, {0x3a74c000}, {0x3a74e000}, 
+    {0x3a750000}, {0x3a752000}, {0x3a754000}, {0x3a756000}, 
+    {0x3a758000}, {0x3a75a000}, {0x3a75c000}, {0x3a75e000}, 
+    {0x3a760000}, {0x3a762000}, {0x3a764000}, {0x3a766000}, 
+    {0x3a768000}, {0x3a76a000}, {0x3a76c000}, {0x3a76e000}, 
+    {0x3a770000}, {0x3a772000}, {0x3a774000}, {0x3a776000}, 
+    {0x3a778000}, {0x3a77a000}, {0x3a77c000}, {0x3a77e000}, 
+    {0x3a780000}, {0x3a782000}, {0x3a784000}, {0x3a786000}, 
+    {0x3a788000}, {0x3a78a000}, {0x3a78c000}, {0x3a78e000}, 
+    {0x3a790000}, {0x3a792000}, {0x3a794000}, {0x3a796000}, 
+    {0x3a798000}, {0x3a79a000}, {0x3a79c000}, {0x3a79e000}, 
+    {0x3a7a0000}, {0x3a7a2000}, {0x3a7a4000}, {0x3a7a6000}, 
+    {0x3a7a8000}, {0x3a7aa000}, {0x3a7ac000}, {0x3a7ae000}, 
+    {0x3a7b0000}, {0x3a7b2000}, {0x3a7b4000}, {0x3a7b6000}, 
+    {0x3a7b8000}, {0x3a7ba000}, {0x3a7bc000}, {0x3a7be000}, 
+    {0x3a7c0000}, {0x3a7c2000}, {0x3a7c4000}, {0x3a7c6000}, 
+    {0x3a7c8000}, {0x3a7ca000}, {0x3a7cc000}, {0x3a7ce000}, 
+    {0x3a7d0000}, {0x3a7d2000}, {0x3a7d4000}, {0x3a7d6000}, 
+    {0x3a7d8000}, {0x3a7da000}, {0x3a7dc000}, {0x3a7de000}, 
+    {0x3a7e0000}, {0x3a7e2000}, {0x3a7e4000}, {0x3a7e6000}, 
+    {0x3a7e8000}, {0x3a7ea000}, {0x3a7ec000}, {0x3a7ee000}, 
+    {0x3a7f0000}, {0x3a7f2000}, {0x3a7f4000}, {0x3a7f6000}, 
+    {0x3a7f8000}, {0x3a7fa000}, {0x3a7fc000}, {0x3a7fe000}, 
+    {0x3a800000}, {0x3a802000}, {0x3a804000}, {0x3a806000}, 
+    {0x3a808000}, {0x3a80a000}, {0x3a80c000}, {0x3a80e000}, 
+    {0x3a810000}, {0x3a812000}, {0x3a814000}, {0x3a816000}, 
+    {0x3a818000}, {0x3a81a000}, {0x3a81c000}, {0x3a81e000}, 
+    {0x3a820000}, {0x3a822000}, {0x3a824000}, {0x3a826000}, 
+    {0x3a828000}, {0x3a82a000}, {0x3a82c000}, {0x3a82e000}, 
+    {0x3a830000}, {0x3a832000}, {0x3a834000}, {0x3a836000}, 
+    {0x3a838000}, {0x3a83a000}, {0x3a83c000}, {0x3a83e000}, 
+    {0x3a840000}, {0x3a842000}, {0x3a844000}, {0x3a846000}, 
+    {0x3a848000}, {0x3a84a000}, {0x3a84c000}, {0x3a84e000}, 
+    {0x3a850000}, {0x3a852000}, {0x3a854000}, {0x3a856000}, 
+    {0x3a858000}, {0x3a85a000}, {0x3a85c000}, {0x3a85e000}, 
+    {0x3a860000}, {0x3a862000}, {0x3a864000}, {0x3a866000}, 
+    {0x3a868000}, {0x3a86a000}, {0x3a86c000}, {0x3a86e000}, 
+    {0x3a870000}, {0x3a872000}, {0x3a874000}, {0x3a876000}, 
+    {0x3a878000}, {0x3a87a000}, {0x3a87c000}, {0x3a87e000}, 
+    {0x3a880000}, {0x3a882000}, {0x3a884000}, {0x3a886000}, 
+    {0x3a888000}, {0x3a88a000}, {0x3a88c000}, {0x3a88e000}, 
+    {0x3a890000}, {0x3a892000}, {0x3a894000}, {0x3a896000}, 
+    {0x3a898000}, {0x3a89a000}, {0x3a89c000}, {0x3a89e000}, 
+    {0x3a8a0000}, {0x3a8a2000}, {0x3a8a4000}, {0x3a8a6000}, 
+    {0x3a8a8000}, {0x3a8aa000}, {0x3a8ac000}, {0x3a8ae000}, 
+    {0x3a8b0000}, {0x3a8b2000}, {0x3a8b4000}, {0x3a8b6000}, 
+    {0x3a8b8000}, {0x3a8ba000}, {0x3a8bc000}, {0x3a8be000}, 
+    {0x3a8c0000}, {0x3a8c2000}, {0x3a8c4000}, {0x3a8c6000}, 
+    {0x3a8c8000}, {0x3a8ca000}, {0x3a8cc000}, {0x3a8ce000}, 
+    {0x3a8d0000}, {0x3a8d2000}, {0x3a8d4000}, {0x3a8d6000}, 
+    {0x3a8d8000}, {0x3a8da000}, {0x3a8dc000}, {0x3a8de000}, 
+    {0x3a8e0000}, {0x3a8e2000}, {0x3a8e4000}, {0x3a8e6000}, 
+    {0x3a8e8000}, {0x3a8ea000}, {0x3a8ec000}, {0x3a8ee000}, 
+    {0x3a8f0000}, {0x3a8f2000}, {0x3a8f4000}, {0x3a8f6000}, 
+    {0x3a8f8000}, {0x3a8fa000}, {0x3a8fc000}, {0x3a8fe000}, 
+    {0x3a900000}, {0x3a902000}, {0x3a904000}, {0x3a906000}, 
+    {0x3a908000}, {0x3a90a000}, {0x3a90c000}, {0x3a90e000}, 
+    {0x3a910000}, {0x3a912000}, {0x3a914000}, {0x3a916000}, 
+    {0x3a918000}, {0x3a91a000}, {0x3a91c000}, {0x3a91e000}, 
+    {0x3a920000}, {0x3a922000}, {0x3a924000}, {0x3a926000}, 
+    {0x3a928000}, {0x3a92a000}, {0x3a92c000}, {0x3a92e000}, 
+    {0x3a930000}, {0x3a932000}, {0x3a934000}, {0x3a936000}, 
+    {0x3a938000}, {0x3a93a000}, {0x3a93c000}, {0x3a93e000}, 
+    {0x3a940000}, {0x3a942000}, {0x3a944000}, {0x3a946000}, 
+    {0x3a948000}, {0x3a94a000}, {0x3a94c000}, {0x3a94e000}, 
+    {0x3a950000}, {0x3a952000}, {0x3a954000}, {0x3a956000}, 
+    {0x3a958000}, {0x3a95a000}, {0x3a95c000}, {0x3a95e000}, 
+    {0x3a960000}, {0x3a962000}, {0x3a964000}, {0x3a966000}, 
+    {0x3a968000}, {0x3a96a000}, {0x3a96c000}, {0x3a96e000}, 
+    {0x3a970000}, {0x3a972000}, {0x3a974000}, {0x3a976000}, 
+    {0x3a978000}, {0x3a97a000}, {0x3a97c000}, {0x3a97e000}, 
+    {0x3a980000}, {0x3a982000}, {0x3a984000}, {0x3a986000}, 
+    {0x3a988000}, {0x3a98a000}, {0x3a98c000}, {0x3a98e000}, 
+    {0x3a990000}, {0x3a992000}, {0x3a994000}, {0x3a996000}, 
+    {0x3a998000}, {0x3a99a000}, {0x3a99c000}, {0x3a99e000}, 
+    {0x3a9a0000}, {0x3a9a2000}, {0x3a9a4000}, {0x3a9a6000}, 
+    {0x3a9a8000}, {0x3a9aa000}, {0x3a9ac000}, {0x3a9ae000}, 
+    {0x3a9b0000}, {0x3a9b2000}, {0x3a9b4000}, {0x3a9b6000}, 
+    {0x3a9b8000}, {0x3a9ba000}, {0x3a9bc000}, {0x3a9be000}, 
+    {0x3a9c0000}, {0x3a9c2000}, {0x3a9c4000}, {0x3a9c6000}, 
+    {0x3a9c8000}, {0x3a9ca000}, {0x3a9cc000}, {0x3a9ce000}, 
+    {0x3a9d0000}, {0x3a9d2000}, {0x3a9d4000}, {0x3a9d6000}, 
+    {0x3a9d8000}, {0x3a9da000}, {0x3a9dc000}, {0x3a9de000}, 
+    {0x3a9e0000}, {0x3a9e2000}, {0x3a9e4000}, {0x3a9e6000}, 
+    {0x3a9e8000}, {0x3a9ea000}, {0x3a9ec000}, {0x3a9ee000}, 
+    {0x3a9f0000}, {0x3a9f2000}, {0x3a9f4000}, {0x3a9f6000}, 
+    {0x3a9f8000}, {0x3a9fa000}, {0x3a9fc000}, {0x3a9fe000}, 
+    {0x3aa00000}, {0x3aa02000}, {0x3aa04000}, {0x3aa06000}, 
+    {0x3aa08000}, {0x3aa0a000}, {0x3aa0c000}, {0x3aa0e000}, 
+    {0x3aa10000}, {0x3aa12000}, {0x3aa14000}, {0x3aa16000}, 
+    {0x3aa18000}, {0x3aa1a000}, {0x3aa1c000}, {0x3aa1e000}, 
+    {0x3aa20000}, {0x3aa22000}, {0x3aa24000}, {0x3aa26000}, 
+    {0x3aa28000}, {0x3aa2a000}, {0x3aa2c000}, {0x3aa2e000}, 
+    {0x3aa30000}, {0x3aa32000}, {0x3aa34000}, {0x3aa36000}, 
+    {0x3aa38000}, {0x3aa3a000}, {0x3aa3c000}, {0x3aa3e000}, 
+    {0x3aa40000}, {0x3aa42000}, {0x3aa44000}, {0x3aa46000}, 
+    {0x3aa48000}, {0x3aa4a000}, {0x3aa4c000}, {0x3aa4e000}, 
+    {0x3aa50000}, {0x3aa52000}, {0x3aa54000}, {0x3aa56000}, 
+    {0x3aa58000}, {0x3aa5a000}, {0x3aa5c000}, {0x3aa5e000}, 
+    {0x3aa60000}, {0x3aa62000}, {0x3aa64000}, {0x3aa66000}, 
+    {0x3aa68000}, {0x3aa6a000}, {0x3aa6c000}, {0x3aa6e000}, 
+    {0x3aa70000}, {0x3aa72000}, {0x3aa74000}, {0x3aa76000}, 
+    {0x3aa78000}, {0x3aa7a000}, {0x3aa7c000}, {0x3aa7e000}, 
+    {0x3aa80000}, {0x3aa82000}, {0x3aa84000}, {0x3aa86000}, 
+    {0x3aa88000}, {0x3aa8a000}, {0x3aa8c000}, {0x3aa8e000}, 
+    {0x3aa90000}, {0x3aa92000}, {0x3aa94000}, {0x3aa96000}, 
+    {0x3aa98000}, {0x3aa9a000}, {0x3aa9c000}, {0x3aa9e000}, 
+    {0x3aaa0000}, {0x3aaa2000}, {0x3aaa4000}, {0x3aaa6000}, 
+    {0x3aaa8000}, {0x3aaaa000}, {0x3aaac000}, {0x3aaae000}, 
+    {0x3aab0000}, {0x3aab2000}, {0x3aab4000}, {0x3aab6000}, 
+    {0x3aab8000}, {0x3aaba000}, {0x3aabc000}, {0x3aabe000}, 
+    {0x3aac0000}, {0x3aac2000}, {0x3aac4000}, {0x3aac6000}, 
+    {0x3aac8000}, {0x3aaca000}, {0x3aacc000}, {0x3aace000}, 
+    {0x3aad0000}, {0x3aad2000}, {0x3aad4000}, {0x3aad6000}, 
+    {0x3aad8000}, {0x3aada000}, {0x3aadc000}, {0x3aade000}, 
+    {0x3aae0000}, {0x3aae2000}, {0x3aae4000}, {0x3aae6000}, 
+    {0x3aae8000}, {0x3aaea000}, {0x3aaec000}, {0x3aaee000}, 
+    {0x3aaf0000}, {0x3aaf2000}, {0x3aaf4000}, {0x3aaf6000}, 
+    {0x3aaf8000}, {0x3aafa000}, {0x3aafc000}, {0x3aafe000}, 
+    {0x3ab00000}, {0x3ab02000}, {0x3ab04000}, {0x3ab06000}, 
+    {0x3ab08000}, {0x3ab0a000}, {0x3ab0c000}, {0x3ab0e000}, 
+    {0x3ab10000}, {0x3ab12000}, {0x3ab14000}, {0x3ab16000}, 
+    {0x3ab18000}, {0x3ab1a000}, {0x3ab1c000}, {0x3ab1e000}, 
+    {0x3ab20000}, {0x3ab22000}, {0x3ab24000}, {0x3ab26000}, 
+    {0x3ab28000}, {0x3ab2a000}, {0x3ab2c000}, {0x3ab2e000}, 
+    {0x3ab30000}, {0x3ab32000}, {0x3ab34000}, {0x3ab36000}, 
+    {0x3ab38000}, {0x3ab3a000}, {0x3ab3c000}, {0x3ab3e000}, 
+    {0x3ab40000}, {0x3ab42000}, {0x3ab44000}, {0x3ab46000}, 
+    {0x3ab48000}, {0x3ab4a000}, {0x3ab4c000}, {0x3ab4e000}, 
+    {0x3ab50000}, {0x3ab52000}, {0x3ab54000}, {0x3ab56000}, 
+    {0x3ab58000}, {0x3ab5a000}, {0x3ab5c000}, {0x3ab5e000}, 
+    {0x3ab60000}, {0x3ab62000}, {0x3ab64000}, {0x3ab66000}, 
+    {0x3ab68000}, {0x3ab6a000}, {0x3ab6c000}, {0x3ab6e000}, 
+    {0x3ab70000}, {0x3ab72000}, {0x3ab74000}, {0x3ab76000}, 
+    {0x3ab78000}, {0x3ab7a000}, {0x3ab7c000}, {0x3ab7e000}, 
+    {0x3ab80000}, {0x3ab82000}, {0x3ab84000}, {0x3ab86000}, 
+    {0x3ab88000}, {0x3ab8a000}, {0x3ab8c000}, {0x3ab8e000}, 
+    {0x3ab90000}, {0x3ab92000}, {0x3ab94000}, {0x3ab96000}, 
+    {0x3ab98000}, {0x3ab9a000}, {0x3ab9c000}, {0x3ab9e000}, 
+    {0x3aba0000}, {0x3aba2000}, {0x3aba4000}, {0x3aba6000}, 
+    {0x3aba8000}, {0x3abaa000}, {0x3abac000}, {0x3abae000}, 
+    {0x3abb0000}, {0x3abb2000}, {0x3abb4000}, {0x3abb6000}, 
+    {0x3abb8000}, {0x3abba000}, {0x3abbc000}, {0x3abbe000}, 
+    {0x3abc0000}, {0x3abc2000}, {0x3abc4000}, {0x3abc6000}, 
+    {0x3abc8000}, {0x3abca000}, {0x3abcc000}, {0x3abce000}, 
+    {0x3abd0000}, {0x3abd2000}, {0x3abd4000}, {0x3abd6000}, 
+    {0x3abd8000}, {0x3abda000}, {0x3abdc000}, {0x3abde000}, 
+    {0x3abe0000}, {0x3abe2000}, {0x3abe4000}, {0x3abe6000}, 
+    {0x3abe8000}, {0x3abea000}, {0x3abec000}, {0x3abee000}, 
+    {0x3abf0000}, {0x3abf2000}, {0x3abf4000}, {0x3abf6000}, 
+    {0x3abf8000}, {0x3abfa000}, {0x3abfc000}, {0x3abfe000}, 
+    {0x3ac00000}, {0x3ac02000}, {0x3ac04000}, {0x3ac06000}, 
+    {0x3ac08000}, {0x3ac0a000}, {0x3ac0c000}, {0x3ac0e000}, 
+    {0x3ac10000}, {0x3ac12000}, {0x3ac14000}, {0x3ac16000}, 
+    {0x3ac18000}, {0x3ac1a000}, {0x3ac1c000}, {0x3ac1e000}, 
+    {0x3ac20000}, {0x3ac22000}, {0x3ac24000}, {0x3ac26000}, 
+    {0x3ac28000}, {0x3ac2a000}, {0x3ac2c000}, {0x3ac2e000}, 
+    {0x3ac30000}, {0x3ac32000}, {0x3ac34000}, {0x3ac36000}, 
+    {0x3ac38000}, {0x3ac3a000}, {0x3ac3c000}, {0x3ac3e000}, 
+    {0x3ac40000}, {0x3ac42000}, {0x3ac44000}, {0x3ac46000}, 
+    {0x3ac48000}, {0x3ac4a000}, {0x3ac4c000}, {0x3ac4e000}, 
+    {0x3ac50000}, {0x3ac52000}, {0x3ac54000}, {0x3ac56000}, 
+    {0x3ac58000}, {0x3ac5a000}, {0x3ac5c000}, {0x3ac5e000}, 
+    {0x3ac60000}, {0x3ac62000}, {0x3ac64000}, {0x3ac66000}, 
+    {0x3ac68000}, {0x3ac6a000}, {0x3ac6c000}, {0x3ac6e000}, 
+    {0x3ac70000}, {0x3ac72000}, {0x3ac74000}, {0x3ac76000}, 
+    {0x3ac78000}, {0x3ac7a000}, {0x3ac7c000}, {0x3ac7e000}, 
+    {0x3ac80000}, {0x3ac82000}, {0x3ac84000}, {0x3ac86000}, 
+    {0x3ac88000}, {0x3ac8a000}, {0x3ac8c000}, {0x3ac8e000}, 
+    {0x3ac90000}, {0x3ac92000}, {0x3ac94000}, {0x3ac96000}, 
+    {0x3ac98000}, {0x3ac9a000}, {0x3ac9c000}, {0x3ac9e000}, 
+    {0x3aca0000}, {0x3aca2000}, {0x3aca4000}, {0x3aca6000}, 
+    {0x3aca8000}, {0x3acaa000}, {0x3acac000}, {0x3acae000}, 
+    {0x3acb0000}, {0x3acb2000}, {0x3acb4000}, {0x3acb6000}, 
+    {0x3acb8000}, {0x3acba000}, {0x3acbc000}, {0x3acbe000}, 
+    {0x3acc0000}, {0x3acc2000}, {0x3acc4000}, {0x3acc6000}, 
+    {0x3acc8000}, {0x3acca000}, {0x3accc000}, {0x3acce000}, 
+    {0x3acd0000}, {0x3acd2000}, {0x3acd4000}, {0x3acd6000}, 
+    {0x3acd8000}, {0x3acda000}, {0x3acdc000}, {0x3acde000}, 
+    {0x3ace0000}, {0x3ace2000}, {0x3ace4000}, {0x3ace6000}, 
+    {0x3ace8000}, {0x3acea000}, {0x3acec000}, {0x3acee000}, 
+    {0x3acf0000}, {0x3acf2000}, {0x3acf4000}, {0x3acf6000}, 
+    {0x3acf8000}, {0x3acfa000}, {0x3acfc000}, {0x3acfe000}, 
+    {0x3ad00000}, {0x3ad02000}, {0x3ad04000}, {0x3ad06000}, 
+    {0x3ad08000}, {0x3ad0a000}, {0x3ad0c000}, {0x3ad0e000}, 
+    {0x3ad10000}, {0x3ad12000}, {0x3ad14000}, {0x3ad16000}, 
+    {0x3ad18000}, {0x3ad1a000}, {0x3ad1c000}, {0x3ad1e000}, 
+    {0x3ad20000}, {0x3ad22000}, {0x3ad24000}, {0x3ad26000}, 
+    {0x3ad28000}, {0x3ad2a000}, {0x3ad2c000}, {0x3ad2e000}, 
+    {0x3ad30000}, {0x3ad32000}, {0x3ad34000}, {0x3ad36000}, 
+    {0x3ad38000}, {0x3ad3a000}, {0x3ad3c000}, {0x3ad3e000}, 
+    {0x3ad40000}, {0x3ad42000}, {0x3ad44000}, {0x3ad46000}, 
+    {0x3ad48000}, {0x3ad4a000}, {0x3ad4c000}, {0x3ad4e000}, 
+    {0x3ad50000}, {0x3ad52000}, {0x3ad54000}, {0x3ad56000}, 
+    {0x3ad58000}, {0x3ad5a000}, {0x3ad5c000}, {0x3ad5e000}, 
+    {0x3ad60000}, {0x3ad62000}, {0x3ad64000}, {0x3ad66000}, 
+    {0x3ad68000}, {0x3ad6a000}, {0x3ad6c000}, {0x3ad6e000}, 
+    {0x3ad70000}, {0x3ad72000}, {0x3ad74000}, {0x3ad76000}, 
+    {0x3ad78000}, {0x3ad7a000}, {0x3ad7c000}, {0x3ad7e000}, 
+    {0x3ad80000}, {0x3ad82000}, {0x3ad84000}, {0x3ad86000}, 
+    {0x3ad88000}, {0x3ad8a000}, {0x3ad8c000}, {0x3ad8e000}, 
+    {0x3ad90000}, {0x3ad92000}, {0x3ad94000}, {0x3ad96000}, 
+    {0x3ad98000}, {0x3ad9a000}, {0x3ad9c000}, {0x3ad9e000}, 
+    {0x3ada0000}, {0x3ada2000}, {0x3ada4000}, {0x3ada6000}, 
+    {0x3ada8000}, {0x3adaa000}, {0x3adac000}, {0x3adae000}, 
+    {0x3adb0000}, {0x3adb2000}, {0x3adb4000}, {0x3adb6000}, 
+    {0x3adb8000}, {0x3adba000}, {0x3adbc000}, {0x3adbe000}, 
+    {0x3adc0000}, {0x3adc2000}, {0x3adc4000}, {0x3adc6000}, 
+    {0x3adc8000}, {0x3adca000}, {0x3adcc000}, {0x3adce000}, 
+    {0x3add0000}, {0x3add2000}, {0x3add4000}, {0x3add6000}, 
+    {0x3add8000}, {0x3adda000}, {0x3addc000}, {0x3adde000}, 
+    {0x3ade0000}, {0x3ade2000}, {0x3ade4000}, {0x3ade6000}, 
+    {0x3ade8000}, {0x3adea000}, {0x3adec000}, {0x3adee000}, 
+    {0x3adf0000}, {0x3adf2000}, {0x3adf4000}, {0x3adf6000}, 
+    {0x3adf8000}, {0x3adfa000}, {0x3adfc000}, {0x3adfe000}, 
+    {0x3ae00000}, {0x3ae02000}, {0x3ae04000}, {0x3ae06000}, 
+    {0x3ae08000}, {0x3ae0a000}, {0x3ae0c000}, {0x3ae0e000}, 
+    {0x3ae10000}, {0x3ae12000}, {0x3ae14000}, {0x3ae16000}, 
+    {0x3ae18000}, {0x3ae1a000}, {0x3ae1c000}, {0x3ae1e000}, 
+    {0x3ae20000}, {0x3ae22000}, {0x3ae24000}, {0x3ae26000}, 
+    {0x3ae28000}, {0x3ae2a000}, {0x3ae2c000}, {0x3ae2e000}, 
+    {0x3ae30000}, {0x3ae32000}, {0x3ae34000}, {0x3ae36000}, 
+    {0x3ae38000}, {0x3ae3a000}, {0x3ae3c000}, {0x3ae3e000}, 
+    {0x3ae40000}, {0x3ae42000}, {0x3ae44000}, {0x3ae46000}, 
+    {0x3ae48000}, {0x3ae4a000}, {0x3ae4c000}, {0x3ae4e000}, 
+    {0x3ae50000}, {0x3ae52000}, {0x3ae54000}, {0x3ae56000}, 
+    {0x3ae58000}, {0x3ae5a000}, {0x3ae5c000}, {0x3ae5e000}, 
+    {0x3ae60000}, {0x3ae62000}, {0x3ae64000}, {0x3ae66000}, 
+    {0x3ae68000}, {0x3ae6a000}, {0x3ae6c000}, {0x3ae6e000}, 
+    {0x3ae70000}, {0x3ae72000}, {0x3ae74000}, {0x3ae76000}, 
+    {0x3ae78000}, {0x3ae7a000}, {0x3ae7c000}, {0x3ae7e000}, 
+    {0x3ae80000}, {0x3ae82000}, {0x3ae84000}, {0x3ae86000}, 
+    {0x3ae88000}, {0x3ae8a000}, {0x3ae8c000}, {0x3ae8e000}, 
+    {0x3ae90000}, {0x3ae92000}, {0x3ae94000}, {0x3ae96000}, 
+    {0x3ae98000}, {0x3ae9a000}, {0x3ae9c000}, {0x3ae9e000}, 
+    {0x3aea0000}, {0x3aea2000}, {0x3aea4000}, {0x3aea6000}, 
+    {0x3aea8000}, {0x3aeaa000}, {0x3aeac000}, {0x3aeae000}, 
+    {0x3aeb0000}, {0x3aeb2000}, {0x3aeb4000}, {0x3aeb6000}, 
+    {0x3aeb8000}, {0x3aeba000}, {0x3aebc000}, {0x3aebe000}, 
+    {0x3aec0000}, {0x3aec2000}, {0x3aec4000}, {0x3aec6000}, 
+    {0x3aec8000}, {0x3aeca000}, {0x3aecc000}, {0x3aece000}, 
+    {0x3aed0000}, {0x3aed2000}, {0x3aed4000}, {0x3aed6000}, 
+    {0x3aed8000}, {0x3aeda000}, {0x3aedc000}, {0x3aede000}, 
+    {0x3aee0000}, {0x3aee2000}, {0x3aee4000}, {0x3aee6000}, 
+    {0x3aee8000}, {0x3aeea000}, {0x3aeec000}, {0x3aeee000}, 
+    {0x3aef0000}, {0x3aef2000}, {0x3aef4000}, {0x3aef6000}, 
+    {0x3aef8000}, {0x3aefa000}, {0x3aefc000}, {0x3aefe000}, 
+    {0x3af00000}, {0x3af02000}, {0x3af04000}, {0x3af06000}, 
+    {0x3af08000}, {0x3af0a000}, {0x3af0c000}, {0x3af0e000}, 
+    {0x3af10000}, {0x3af12000}, {0x3af14000}, {0x3af16000}, 
+    {0x3af18000}, {0x3af1a000}, {0x3af1c000}, {0x3af1e000}, 
+    {0x3af20000}, {0x3af22000}, {0x3af24000}, {0x3af26000}, 
+    {0x3af28000}, {0x3af2a000}, {0x3af2c000}, {0x3af2e000}, 
+    {0x3af30000}, {0x3af32000}, {0x3af34000}, {0x3af36000}, 
+    {0x3af38000}, {0x3af3a000}, {0x3af3c000}, {0x3af3e000}, 
+    {0x3af40000}, {0x3af42000}, {0x3af44000}, {0x3af46000}, 
+    {0x3af48000}, {0x3af4a000}, {0x3af4c000}, {0x3af4e000}, 
+    {0x3af50000}, {0x3af52000}, {0x3af54000}, {0x3af56000}, 
+    {0x3af58000}, {0x3af5a000}, {0x3af5c000}, {0x3af5e000}, 
+    {0x3af60000}, {0x3af62000}, {0x3af64000}, {0x3af66000}, 
+    {0x3af68000}, {0x3af6a000}, {0x3af6c000}, {0x3af6e000}, 
+    {0x3af70000}, {0x3af72000}, {0x3af74000}, {0x3af76000}, 
+    {0x3af78000}, {0x3af7a000}, {0x3af7c000}, {0x3af7e000}, 
+    {0x3af80000}, {0x3af82000}, {0x3af84000}, {0x3af86000}, 
+    {0x3af88000}, {0x3af8a000}, {0x3af8c000}, {0x3af8e000}, 
+    {0x3af90000}, {0x3af92000}, {0x3af94000}, {0x3af96000}, 
+    {0x3af98000}, {0x3af9a000}, {0x3af9c000}, {0x3af9e000}, 
+    {0x3afa0000}, {0x3afa2000}, {0x3afa4000}, {0x3afa6000}, 
+    {0x3afa8000}, {0x3afaa000}, {0x3afac000}, {0x3afae000}, 
+    {0x3afb0000}, {0x3afb2000}, {0x3afb4000}, {0x3afb6000}, 
+    {0x3afb8000}, {0x3afba000}, {0x3afbc000}, {0x3afbe000}, 
+    {0x3afc0000}, {0x3afc2000}, {0x3afc4000}, {0x3afc6000}, 
+    {0x3afc8000}, {0x3afca000}, {0x3afcc000}, {0x3afce000}, 
+    {0x3afd0000}, {0x3afd2000}, {0x3afd4000}, {0x3afd6000}, 
+    {0x3afd8000}, {0x3afda000}, {0x3afdc000}, {0x3afde000}, 
+    {0x3afe0000}, {0x3afe2000}, {0x3afe4000}, {0x3afe6000}, 
+    {0x3afe8000}, {0x3afea000}, {0x3afec000}, {0x3afee000}, 
+    {0x3aff0000}, {0x3aff2000}, {0x3aff4000}, {0x3aff6000}, 
+    {0x3aff8000}, {0x3affa000}, {0x3affc000}, {0x3affe000}, 
+    {0x3b000000}, {0x3b002000}, {0x3b004000}, {0x3b006000}, 
+    {0x3b008000}, {0x3b00a000}, {0x3b00c000}, {0x3b00e000}, 
+    {0x3b010000}, {0x3b012000}, {0x3b014000}, {0x3b016000}, 
+    {0x3b018000}, {0x3b01a000}, {0x3b01c000}, {0x3b01e000}, 
+    {0x3b020000}, {0x3b022000}, {0x3b024000}, {0x3b026000}, 
+    {0x3b028000}, {0x3b02a000}, {0x3b02c000}, {0x3b02e000}, 
+    {0x3b030000}, {0x3b032000}, {0x3b034000}, {0x3b036000}, 
+    {0x3b038000}, {0x3b03a000}, {0x3b03c000}, {0x3b03e000}, 
+    {0x3b040000}, {0x3b042000}, {0x3b044000}, {0x3b046000}, 
+    {0x3b048000}, {0x3b04a000}, {0x3b04c000}, {0x3b04e000}, 
+    {0x3b050000}, {0x3b052000}, {0x3b054000}, {0x3b056000}, 
+    {0x3b058000}, {0x3b05a000}, {0x3b05c000}, {0x3b05e000}, 
+    {0x3b060000}, {0x3b062000}, {0x3b064000}, {0x3b066000}, 
+    {0x3b068000}, {0x3b06a000}, {0x3b06c000}, {0x3b06e000}, 
+    {0x3b070000}, {0x3b072000}, {0x3b074000}, {0x3b076000}, 
+    {0x3b078000}, {0x3b07a000}, {0x3b07c000}, {0x3b07e000}, 
+    {0x3b080000}, {0x3b082000}, {0x3b084000}, {0x3b086000}, 
+    {0x3b088000}, {0x3b08a000}, {0x3b08c000}, {0x3b08e000}, 
+    {0x3b090000}, {0x3b092000}, {0x3b094000}, {0x3b096000}, 
+    {0x3b098000}, {0x3b09a000}, {0x3b09c000}, {0x3b09e000}, 
+    {0x3b0a0000}, {0x3b0a2000}, {0x3b0a4000}, {0x3b0a6000}, 
+    {0x3b0a8000}, {0x3b0aa000}, {0x3b0ac000}, {0x3b0ae000}, 
+    {0x3b0b0000}, {0x3b0b2000}, {0x3b0b4000}, {0x3b0b6000}, 
+    {0x3b0b8000}, {0x3b0ba000}, {0x3b0bc000}, {0x3b0be000}, 
+    {0x3b0c0000}, {0x3b0c2000}, {0x3b0c4000}, {0x3b0c6000}, 
+    {0x3b0c8000}, {0x3b0ca000}, {0x3b0cc000}, {0x3b0ce000}, 
+    {0x3b0d0000}, {0x3b0d2000}, {0x3b0d4000}, {0x3b0d6000}, 
+    {0x3b0d8000}, {0x3b0da000}, {0x3b0dc000}, {0x3b0de000}, 
+    {0x3b0e0000}, {0x3b0e2000}, {0x3b0e4000}, {0x3b0e6000}, 
+    {0x3b0e8000}, {0x3b0ea000}, {0x3b0ec000}, {0x3b0ee000}, 
+    {0x3b0f0000}, {0x3b0f2000}, {0x3b0f4000}, {0x3b0f6000}, 
+    {0x3b0f8000}, {0x3b0fa000}, {0x3b0fc000}, {0x3b0fe000}, 
+    {0x3b100000}, {0x3b102000}, {0x3b104000}, {0x3b106000}, 
+    {0x3b108000}, {0x3b10a000}, {0x3b10c000}, {0x3b10e000}, 
+    {0x3b110000}, {0x3b112000}, {0x3b114000}, {0x3b116000}, 
+    {0x3b118000}, {0x3b11a000}, {0x3b11c000}, {0x3b11e000}, 
+    {0x3b120000}, {0x3b122000}, {0x3b124000}, {0x3b126000}, 
+    {0x3b128000}, {0x3b12a000}, {0x3b12c000}, {0x3b12e000}, 
+    {0x3b130000}, {0x3b132000}, {0x3b134000}, {0x3b136000}, 
+    {0x3b138000}, {0x3b13a000}, {0x3b13c000}, {0x3b13e000}, 
+    {0x3b140000}, {0x3b142000}, {0x3b144000}, {0x3b146000}, 
+    {0x3b148000}, {0x3b14a000}, {0x3b14c000}, {0x3b14e000}, 
+    {0x3b150000}, {0x3b152000}, {0x3b154000}, {0x3b156000}, 
+    {0x3b158000}, {0x3b15a000}, {0x3b15c000}, {0x3b15e000}, 
+    {0x3b160000}, {0x3b162000}, {0x3b164000}, {0x3b166000}, 
+    {0x3b168000}, {0x3b16a000}, {0x3b16c000}, {0x3b16e000}, 
+    {0x3b170000}, {0x3b172000}, {0x3b174000}, {0x3b176000}, 
+    {0x3b178000}, {0x3b17a000}, {0x3b17c000}, {0x3b17e000}, 
+    {0x3b180000}, {0x3b182000}, {0x3b184000}, {0x3b186000}, 
+    {0x3b188000}, {0x3b18a000}, {0x3b18c000}, {0x3b18e000}, 
+    {0x3b190000}, {0x3b192000}, {0x3b194000}, {0x3b196000}, 
+    {0x3b198000}, {0x3b19a000}, {0x3b19c000}, {0x3b19e000}, 
+    {0x3b1a0000}, {0x3b1a2000}, {0x3b1a4000}, {0x3b1a6000}, 
+    {0x3b1a8000}, {0x3b1aa000}, {0x3b1ac000}, {0x3b1ae000}, 
+    {0x3b1b0000}, {0x3b1b2000}, {0x3b1b4000}, {0x3b1b6000}, 
+    {0x3b1b8000}, {0x3b1ba000}, {0x3b1bc000}, {0x3b1be000}, 
+    {0x3b1c0000}, {0x3b1c2000}, {0x3b1c4000}, {0x3b1c6000}, 
+    {0x3b1c8000}, {0x3b1ca000}, {0x3b1cc000}, {0x3b1ce000}, 
+    {0x3b1d0000}, {0x3b1d2000}, {0x3b1d4000}, {0x3b1d6000}, 
+    {0x3b1d8000}, {0x3b1da000}, {0x3b1dc000}, {0x3b1de000}, 
+    {0x3b1e0000}, {0x3b1e2000}, {0x3b1e4000}, {0x3b1e6000}, 
+    {0x3b1e8000}, {0x3b1ea000}, {0x3b1ec000}, {0x3b1ee000}, 
+    {0x3b1f0000}, {0x3b1f2000}, {0x3b1f4000}, {0x3b1f6000}, 
+    {0x3b1f8000}, {0x3b1fa000}, {0x3b1fc000}, {0x3b1fe000}, 
+    {0x3b200000}, {0x3b202000}, {0x3b204000}, {0x3b206000}, 
+    {0x3b208000}, {0x3b20a000}, {0x3b20c000}, {0x3b20e000}, 
+    {0x3b210000}, {0x3b212000}, {0x3b214000}, {0x3b216000}, 
+    {0x3b218000}, {0x3b21a000}, {0x3b21c000}, {0x3b21e000}, 
+    {0x3b220000}, {0x3b222000}, {0x3b224000}, {0x3b226000}, 
+    {0x3b228000}, {0x3b22a000}, {0x3b22c000}, {0x3b22e000}, 
+    {0x3b230000}, {0x3b232000}, {0x3b234000}, {0x3b236000}, 
+    {0x3b238000}, {0x3b23a000}, {0x3b23c000}, {0x3b23e000}, 
+    {0x3b240000}, {0x3b242000}, {0x3b244000}, {0x3b246000}, 
+    {0x3b248000}, {0x3b24a000}, {0x3b24c000}, {0x3b24e000}, 
+    {0x3b250000}, {0x3b252000}, {0x3b254000}, {0x3b256000}, 
+    {0x3b258000}, {0x3b25a000}, {0x3b25c000}, {0x3b25e000}, 
+    {0x3b260000}, {0x3b262000}, {0x3b264000}, {0x3b266000}, 
+    {0x3b268000}, {0x3b26a000}, {0x3b26c000}, {0x3b26e000}, 
+    {0x3b270000}, {0x3b272000}, {0x3b274000}, {0x3b276000}, 
+    {0x3b278000}, {0x3b27a000}, {0x3b27c000}, {0x3b27e000}, 
+    {0x3b280000}, {0x3b282000}, {0x3b284000}, {0x3b286000}, 
+    {0x3b288000}, {0x3b28a000}, {0x3b28c000}, {0x3b28e000}, 
+    {0x3b290000}, {0x3b292000}, {0x3b294000}, {0x3b296000}, 
+    {0x3b298000}, {0x3b29a000}, {0x3b29c000}, {0x3b29e000}, 
+    {0x3b2a0000}, {0x3b2a2000}, {0x3b2a4000}, {0x3b2a6000}, 
+    {0x3b2a8000}, {0x3b2aa000}, {0x3b2ac000}, {0x3b2ae000}, 
+    {0x3b2b0000}, {0x3b2b2000}, {0x3b2b4000}, {0x3b2b6000}, 
+    {0x3b2b8000}, {0x3b2ba000}, {0x3b2bc000}, {0x3b2be000}, 
+    {0x3b2c0000}, {0x3b2c2000}, {0x3b2c4000}, {0x3b2c6000}, 
+    {0x3b2c8000}, {0x3b2ca000}, {0x3b2cc000}, {0x3b2ce000}, 
+    {0x3b2d0000}, {0x3b2d2000}, {0x3b2d4000}, {0x3b2d6000}, 
+    {0x3b2d8000}, {0x3b2da000}, {0x3b2dc000}, {0x3b2de000}, 
+    {0x3b2e0000}, {0x3b2e2000}, {0x3b2e4000}, {0x3b2e6000}, 
+    {0x3b2e8000}, {0x3b2ea000}, {0x3b2ec000}, {0x3b2ee000}, 
+    {0x3b2f0000}, {0x3b2f2000}, {0x3b2f4000}, {0x3b2f6000}, 
+    {0x3b2f8000}, {0x3b2fa000}, {0x3b2fc000}, {0x3b2fe000}, 
+    {0x3b300000}, {0x3b302000}, {0x3b304000}, {0x3b306000}, 
+    {0x3b308000}, {0x3b30a000}, {0x3b30c000}, {0x3b30e000}, 
+    {0x3b310000}, {0x3b312000}, {0x3b314000}, {0x3b316000}, 
+    {0x3b318000}, {0x3b31a000}, {0x3b31c000}, {0x3b31e000}, 
+    {0x3b320000}, {0x3b322000}, {0x3b324000}, {0x3b326000}, 
+    {0x3b328000}, {0x3b32a000}, {0x3b32c000}, {0x3b32e000}, 
+    {0x3b330000}, {0x3b332000}, {0x3b334000}, {0x3b336000}, 
+    {0x3b338000}, {0x3b33a000}, {0x3b33c000}, {0x3b33e000}, 
+    {0x3b340000}, {0x3b342000}, {0x3b344000}, {0x3b346000}, 
+    {0x3b348000}, {0x3b34a000}, {0x3b34c000}, {0x3b34e000}, 
+    {0x3b350000}, {0x3b352000}, {0x3b354000}, {0x3b356000}, 
+    {0x3b358000}, {0x3b35a000}, {0x3b35c000}, {0x3b35e000}, 
+    {0x3b360000}, {0x3b362000}, {0x3b364000}, {0x3b366000}, 
+    {0x3b368000}, {0x3b36a000}, {0x3b36c000}, {0x3b36e000}, 
+    {0x3b370000}, {0x3b372000}, {0x3b374000}, {0x3b376000}, 
+    {0x3b378000}, {0x3b37a000}, {0x3b37c000}, {0x3b37e000}, 
+    {0x3b380000}, {0x3b382000}, {0x3b384000}, {0x3b386000}, 
+    {0x3b388000}, {0x3b38a000}, {0x3b38c000}, {0x3b38e000}, 
+    {0x3b390000}, {0x3b392000}, {0x3b394000}, {0x3b396000}, 
+    {0x3b398000}, {0x3b39a000}, {0x3b39c000}, {0x3b39e000}, 
+    {0x3b3a0000}, {0x3b3a2000}, {0x3b3a4000}, {0x3b3a6000}, 
+    {0x3b3a8000}, {0x3b3aa000}, {0x3b3ac000}, {0x3b3ae000}, 
+    {0x3b3b0000}, {0x3b3b2000}, {0x3b3b4000}, {0x3b3b6000}, 
+    {0x3b3b8000}, {0x3b3ba000}, {0x3b3bc000}, {0x3b3be000}, 
+    {0x3b3c0000}, {0x3b3c2000}, {0x3b3c4000}, {0x3b3c6000}, 
+    {0x3b3c8000}, {0x3b3ca000}, {0x3b3cc000}, {0x3b3ce000}, 
+    {0x3b3d0000}, {0x3b3d2000}, {0x3b3d4000}, {0x3b3d6000}, 
+    {0x3b3d8000}, {0x3b3da000}, {0x3b3dc000}, {0x3b3de000}, 
+    {0x3b3e0000}, {0x3b3e2000}, {0x3b3e4000}, {0x3b3e6000}, 
+    {0x3b3e8000}, {0x3b3ea000}, {0x3b3ec000}, {0x3b3ee000}, 
+    {0x3b3f0000}, {0x3b3f2000}, {0x3b3f4000}, {0x3b3f6000}, 
+    {0x3b3f8000}, {0x3b3fa000}, {0x3b3fc000}, {0x3b3fe000}, 
+    {0x3b400000}, {0x3b402000}, {0x3b404000}, {0x3b406000}, 
+    {0x3b408000}, {0x3b40a000}, {0x3b40c000}, {0x3b40e000}, 
+    {0x3b410000}, {0x3b412000}, {0x3b414000}, {0x3b416000}, 
+    {0x3b418000}, {0x3b41a000}, {0x3b41c000}, {0x3b41e000}, 
+    {0x3b420000}, {0x3b422000}, {0x3b424000}, {0x3b426000}, 
+    {0x3b428000}, {0x3b42a000}, {0x3b42c000}, {0x3b42e000}, 
+    {0x3b430000}, {0x3b432000}, {0x3b434000}, {0x3b436000}, 
+    {0x3b438000}, {0x3b43a000}, {0x3b43c000}, {0x3b43e000}, 
+    {0x3b440000}, {0x3b442000}, {0x3b444000}, {0x3b446000}, 
+    {0x3b448000}, {0x3b44a000}, {0x3b44c000}, {0x3b44e000}, 
+    {0x3b450000}, {0x3b452000}, {0x3b454000}, {0x3b456000}, 
+    {0x3b458000}, {0x3b45a000}, {0x3b45c000}, {0x3b45e000}, 
+    {0x3b460000}, {0x3b462000}, {0x3b464000}, {0x3b466000}, 
+    {0x3b468000}, {0x3b46a000}, {0x3b46c000}, {0x3b46e000}, 
+    {0x3b470000}, {0x3b472000}, {0x3b474000}, {0x3b476000}, 
+    {0x3b478000}, {0x3b47a000}, {0x3b47c000}, {0x3b47e000}, 
+    {0x3b480000}, {0x3b482000}, {0x3b484000}, {0x3b486000}, 
+    {0x3b488000}, {0x3b48a000}, {0x3b48c000}, {0x3b48e000}, 
+    {0x3b490000}, {0x3b492000}, {0x3b494000}, {0x3b496000}, 
+    {0x3b498000}, {0x3b49a000}, {0x3b49c000}, {0x3b49e000}, 
+    {0x3b4a0000}, {0x3b4a2000}, {0x3b4a4000}, {0x3b4a6000}, 
+    {0x3b4a8000}, {0x3b4aa000}, {0x3b4ac000}, {0x3b4ae000}, 
+    {0x3b4b0000}, {0x3b4b2000}, {0x3b4b4000}, {0x3b4b6000}, 
+    {0x3b4b8000}, {0x3b4ba000}, {0x3b4bc000}, {0x3b4be000}, 
+    {0x3b4c0000}, {0x3b4c2000}, {0x3b4c4000}, {0x3b4c6000}, 
+    {0x3b4c8000}, {0x3b4ca000}, {0x3b4cc000}, {0x3b4ce000}, 
+    {0x3b4d0000}, {0x3b4d2000}, {0x3b4d4000}, {0x3b4d6000}, 
+    {0x3b4d8000}, {0x3b4da000}, {0x3b4dc000}, {0x3b4de000}, 
+    {0x3b4e0000}, {0x3b4e2000}, {0x3b4e4000}, {0x3b4e6000}, 
+    {0x3b4e8000}, {0x3b4ea000}, {0x3b4ec000}, {0x3b4ee000}, 
+    {0x3b4f0000}, {0x3b4f2000}, {0x3b4f4000}, {0x3b4f6000}, 
+    {0x3b4f8000}, {0x3b4fa000}, {0x3b4fc000}, {0x3b4fe000}, 
+    {0x3b500000}, {0x3b502000}, {0x3b504000}, {0x3b506000}, 
+    {0x3b508000}, {0x3b50a000}, {0x3b50c000}, {0x3b50e000}, 
+    {0x3b510000}, {0x3b512000}, {0x3b514000}, {0x3b516000}, 
+    {0x3b518000}, {0x3b51a000}, {0x3b51c000}, {0x3b51e000}, 
+    {0x3b520000}, {0x3b522000}, {0x3b524000}, {0x3b526000}, 
+    {0x3b528000}, {0x3b52a000}, {0x3b52c000}, {0x3b52e000}, 
+    {0x3b530000}, {0x3b532000}, {0x3b534000}, {0x3b536000}, 
+    {0x3b538000}, {0x3b53a000}, {0x3b53c000}, {0x3b53e000}, 
+    {0x3b540000}, {0x3b542000}, {0x3b544000}, {0x3b546000}, 
+    {0x3b548000}, {0x3b54a000}, {0x3b54c000}, {0x3b54e000}, 
+    {0x3b550000}, {0x3b552000}, {0x3b554000}, {0x3b556000}, 
+    {0x3b558000}, {0x3b55a000}, {0x3b55c000}, {0x3b55e000}, 
+    {0x3b560000}, {0x3b562000}, {0x3b564000}, {0x3b566000}, 
+    {0x3b568000}, {0x3b56a000}, {0x3b56c000}, {0x3b56e000}, 
+    {0x3b570000}, {0x3b572000}, {0x3b574000}, {0x3b576000}, 
+    {0x3b578000}, {0x3b57a000}, {0x3b57c000}, {0x3b57e000}, 
+    {0x3b580000}, {0x3b582000}, {0x3b584000}, {0x3b586000}, 
+    {0x3b588000}, {0x3b58a000}, {0x3b58c000}, {0x3b58e000}, 
+    {0x3b590000}, {0x3b592000}, {0x3b594000}, {0x3b596000}, 
+    {0x3b598000}, {0x3b59a000}, {0x3b59c000}, {0x3b59e000}, 
+    {0x3b5a0000}, {0x3b5a2000}, {0x3b5a4000}, {0x3b5a6000}, 
+    {0x3b5a8000}, {0x3b5aa000}, {0x3b5ac000}, {0x3b5ae000}, 
+    {0x3b5b0000}, {0x3b5b2000}, {0x3b5b4000}, {0x3b5b6000}, 
+    {0x3b5b8000}, {0x3b5ba000}, {0x3b5bc000}, {0x3b5be000}, 
+    {0x3b5c0000}, {0x3b5c2000}, {0x3b5c4000}, {0x3b5c6000}, 
+    {0x3b5c8000}, {0x3b5ca000}, {0x3b5cc000}, {0x3b5ce000}, 
+    {0x3b5d0000}, {0x3b5d2000}, {0x3b5d4000}, {0x3b5d6000}, 
+    {0x3b5d8000}, {0x3b5da000}, {0x3b5dc000}, {0x3b5de000}, 
+    {0x3b5e0000}, {0x3b5e2000}, {0x3b5e4000}, {0x3b5e6000}, 
+    {0x3b5e8000}, {0x3b5ea000}, {0x3b5ec000}, {0x3b5ee000}, 
+    {0x3b5f0000}, {0x3b5f2000}, {0x3b5f4000}, {0x3b5f6000}, 
+    {0x3b5f8000}, {0x3b5fa000}, {0x3b5fc000}, {0x3b5fe000}, 
+    {0x3b600000}, {0x3b602000}, {0x3b604000}, {0x3b606000}, 
+    {0x3b608000}, {0x3b60a000}, {0x3b60c000}, {0x3b60e000}, 
+    {0x3b610000}, {0x3b612000}, {0x3b614000}, {0x3b616000}, 
+    {0x3b618000}, {0x3b61a000}, {0x3b61c000}, {0x3b61e000}, 
+    {0x3b620000}, {0x3b622000}, {0x3b624000}, {0x3b626000}, 
+    {0x3b628000}, {0x3b62a000}, {0x3b62c000}, {0x3b62e000}, 
+    {0x3b630000}, {0x3b632000}, {0x3b634000}, {0x3b636000}, 
+    {0x3b638000}, {0x3b63a000}, {0x3b63c000}, {0x3b63e000}, 
+    {0x3b640000}, {0x3b642000}, {0x3b644000}, {0x3b646000}, 
+    {0x3b648000}, {0x3b64a000}, {0x3b64c000}, {0x3b64e000}, 
+    {0x3b650000}, {0x3b652000}, {0x3b654000}, {0x3b656000}, 
+    {0x3b658000}, {0x3b65a000}, {0x3b65c000}, {0x3b65e000}, 
+    {0x3b660000}, {0x3b662000}, {0x3b664000}, {0x3b666000}, 
+    {0x3b668000}, {0x3b66a000}, {0x3b66c000}, {0x3b66e000}, 
+    {0x3b670000}, {0x3b672000}, {0x3b674000}, {0x3b676000}, 
+    {0x3b678000}, {0x3b67a000}, {0x3b67c000}, {0x3b67e000}, 
+    {0x3b680000}, {0x3b682000}, {0x3b684000}, {0x3b686000}, 
+    {0x3b688000}, {0x3b68a000}, {0x3b68c000}, {0x3b68e000}, 
+    {0x3b690000}, {0x3b692000}, {0x3b694000}, {0x3b696000}, 
+    {0x3b698000}, {0x3b69a000}, {0x3b69c000}, {0x3b69e000}, 
+    {0x3b6a0000}, {0x3b6a2000}, {0x3b6a4000}, {0x3b6a6000}, 
+    {0x3b6a8000}, {0x3b6aa000}, {0x3b6ac000}, {0x3b6ae000}, 
+    {0x3b6b0000}, {0x3b6b2000}, {0x3b6b4000}, {0x3b6b6000}, 
+    {0x3b6b8000}, {0x3b6ba000}, {0x3b6bc000}, {0x3b6be000}, 
+    {0x3b6c0000}, {0x3b6c2000}, {0x3b6c4000}, {0x3b6c6000}, 
+    {0x3b6c8000}, {0x3b6ca000}, {0x3b6cc000}, {0x3b6ce000}, 
+    {0x3b6d0000}, {0x3b6d2000}, {0x3b6d4000}, {0x3b6d6000}, 
+    {0x3b6d8000}, {0x3b6da000}, {0x3b6dc000}, {0x3b6de000}, 
+    {0x3b6e0000}, {0x3b6e2000}, {0x3b6e4000}, {0x3b6e6000}, 
+    {0x3b6e8000}, {0x3b6ea000}, {0x3b6ec000}, {0x3b6ee000}, 
+    {0x3b6f0000}, {0x3b6f2000}, {0x3b6f4000}, {0x3b6f6000}, 
+    {0x3b6f8000}, {0x3b6fa000}, {0x3b6fc000}, {0x3b6fe000}, 
+    {0x3b700000}, {0x3b702000}, {0x3b704000}, {0x3b706000}, 
+    {0x3b708000}, {0x3b70a000}, {0x3b70c000}, {0x3b70e000}, 
+    {0x3b710000}, {0x3b712000}, {0x3b714000}, {0x3b716000}, 
+    {0x3b718000}, {0x3b71a000}, {0x3b71c000}, {0x3b71e000}, 
+    {0x3b720000}, {0x3b722000}, {0x3b724000}, {0x3b726000}, 
+    {0x3b728000}, {0x3b72a000}, {0x3b72c000}, {0x3b72e000}, 
+    {0x3b730000}, {0x3b732000}, {0x3b734000}, {0x3b736000}, 
+    {0x3b738000}, {0x3b73a000}, {0x3b73c000}, {0x3b73e000}, 
+    {0x3b740000}, {0x3b742000}, {0x3b744000}, {0x3b746000}, 
+    {0x3b748000}, {0x3b74a000}, {0x3b74c000}, {0x3b74e000}, 
+    {0x3b750000}, {0x3b752000}, {0x3b754000}, {0x3b756000}, 
+    {0x3b758000}, {0x3b75a000}, {0x3b75c000}, {0x3b75e000}, 
+    {0x3b760000}, {0x3b762000}, {0x3b764000}, {0x3b766000}, 
+    {0x3b768000}, {0x3b76a000}, {0x3b76c000}, {0x3b76e000}, 
+    {0x3b770000}, {0x3b772000}, {0x3b774000}, {0x3b776000}, 
+    {0x3b778000}, {0x3b77a000}, {0x3b77c000}, {0x3b77e000}, 
+    {0x3b780000}, {0x3b782000}, {0x3b784000}, {0x3b786000}, 
+    {0x3b788000}, {0x3b78a000}, {0x3b78c000}, {0x3b78e000}, 
+    {0x3b790000}, {0x3b792000}, {0x3b794000}, {0x3b796000}, 
+    {0x3b798000}, {0x3b79a000}, {0x3b79c000}, {0x3b79e000}, 
+    {0x3b7a0000}, {0x3b7a2000}, {0x3b7a4000}, {0x3b7a6000}, 
+    {0x3b7a8000}, {0x3b7aa000}, {0x3b7ac000}, {0x3b7ae000}, 
+    {0x3b7b0000}, {0x3b7b2000}, {0x3b7b4000}, {0x3b7b6000}, 
+    {0x3b7b8000}, {0x3b7ba000}, {0x3b7bc000}, {0x3b7be000}, 
+    {0x3b7c0000}, {0x3b7c2000}, {0x3b7c4000}, {0x3b7c6000}, 
+    {0x3b7c8000}, {0x3b7ca000}, {0x3b7cc000}, {0x3b7ce000}, 
+    {0x3b7d0000}, {0x3b7d2000}, {0x3b7d4000}, {0x3b7d6000}, 
+    {0x3b7d8000}, {0x3b7da000}, {0x3b7dc000}, {0x3b7de000}, 
+    {0x3b7e0000}, {0x3b7e2000}, {0x3b7e4000}, {0x3b7e6000}, 
+    {0x3b7e8000}, {0x3b7ea000}, {0x3b7ec000}, {0x3b7ee000}, 
+    {0x3b7f0000}, {0x3b7f2000}, {0x3b7f4000}, {0x3b7f6000}, 
+    {0x3b7f8000}, {0x3b7fa000}, {0x3b7fc000}, {0x3b7fe000}, 
+    {0x3b800000}, {0x3b802000}, {0x3b804000}, {0x3b806000}, 
+    {0x3b808000}, {0x3b80a000}, {0x3b80c000}, {0x3b80e000}, 
+    {0x3b810000}, {0x3b812000}, {0x3b814000}, {0x3b816000}, 
+    {0x3b818000}, {0x3b81a000}, {0x3b81c000}, {0x3b81e000}, 
+    {0x3b820000}, {0x3b822000}, {0x3b824000}, {0x3b826000}, 
+    {0x3b828000}, {0x3b82a000}, {0x3b82c000}, {0x3b82e000}, 
+    {0x3b830000}, {0x3b832000}, {0x3b834000}, {0x3b836000}, 
+    {0x3b838000}, {0x3b83a000}, {0x3b83c000}, {0x3b83e000}, 
+    {0x3b840000}, {0x3b842000}, {0x3b844000}, {0x3b846000}, 
+    {0x3b848000}, {0x3b84a000}, {0x3b84c000}, {0x3b84e000}, 
+    {0x3b850000}, {0x3b852000}, {0x3b854000}, {0x3b856000}, 
+    {0x3b858000}, {0x3b85a000}, {0x3b85c000}, {0x3b85e000}, 
+    {0x3b860000}, {0x3b862000}, {0x3b864000}, {0x3b866000}, 
+    {0x3b868000}, {0x3b86a000}, {0x3b86c000}, {0x3b86e000}, 
+    {0x3b870000}, {0x3b872000}, {0x3b874000}, {0x3b876000}, 
+    {0x3b878000}, {0x3b87a000}, {0x3b87c000}, {0x3b87e000}, 
+    {0x3b880000}, {0x3b882000}, {0x3b884000}, {0x3b886000}, 
+    {0x3b888000}, {0x3b88a000}, {0x3b88c000}, {0x3b88e000}, 
+    {0x3b890000}, {0x3b892000}, {0x3b894000}, {0x3b896000}, 
+    {0x3b898000}, {0x3b89a000}, {0x3b89c000}, {0x3b89e000}, 
+    {0x3b8a0000}, {0x3b8a2000}, {0x3b8a4000}, {0x3b8a6000}, 
+    {0x3b8a8000}, {0x3b8aa000}, {0x3b8ac000}, {0x3b8ae000}, 
+    {0x3b8b0000}, {0x3b8b2000}, {0x3b8b4000}, {0x3b8b6000}, 
+    {0x3b8b8000}, {0x3b8ba000}, {0x3b8bc000}, {0x3b8be000}, 
+    {0x3b8c0000}, {0x3b8c2000}, {0x3b8c4000}, {0x3b8c6000}, 
+    {0x3b8c8000}, {0x3b8ca000}, {0x3b8cc000}, {0x3b8ce000}, 
+    {0x3b8d0000}, {0x3b8d2000}, {0x3b8d4000}, {0x3b8d6000}, 
+    {0x3b8d8000}, {0x3b8da000}, {0x3b8dc000}, {0x3b8de000}, 
+    {0x3b8e0000}, {0x3b8e2000}, {0x3b8e4000}, {0x3b8e6000}, 
+    {0x3b8e8000}, {0x3b8ea000}, {0x3b8ec000}, {0x3b8ee000}, 
+    {0x3b8f0000}, {0x3b8f2000}, {0x3b8f4000}, {0x3b8f6000}, 
+    {0x3b8f8000}, {0x3b8fa000}, {0x3b8fc000}, {0x3b8fe000}, 
+    {0x3b900000}, {0x3b902000}, {0x3b904000}, {0x3b906000}, 
+    {0x3b908000}, {0x3b90a000}, {0x3b90c000}, {0x3b90e000}, 
+    {0x3b910000}, {0x3b912000}, {0x3b914000}, {0x3b916000}, 
+    {0x3b918000}, {0x3b91a000}, {0x3b91c000}, {0x3b91e000}, 
+    {0x3b920000}, {0x3b922000}, {0x3b924000}, {0x3b926000}, 
+    {0x3b928000}, {0x3b92a000}, {0x3b92c000}, {0x3b92e000}, 
+    {0x3b930000}, {0x3b932000}, {0x3b934000}, {0x3b936000}, 
+    {0x3b938000}, {0x3b93a000}, {0x3b93c000}, {0x3b93e000}, 
+    {0x3b940000}, {0x3b942000}, {0x3b944000}, {0x3b946000}, 
+    {0x3b948000}, {0x3b94a000}, {0x3b94c000}, {0x3b94e000}, 
+    {0x3b950000}, {0x3b952000}, {0x3b954000}, {0x3b956000}, 
+    {0x3b958000}, {0x3b95a000}, {0x3b95c000}, {0x3b95e000}, 
+    {0x3b960000}, {0x3b962000}, {0x3b964000}, {0x3b966000}, 
+    {0x3b968000}, {0x3b96a000}, {0x3b96c000}, {0x3b96e000}, 
+    {0x3b970000}, {0x3b972000}, {0x3b974000}, {0x3b976000}, 
+    {0x3b978000}, {0x3b97a000}, {0x3b97c000}, {0x3b97e000}, 
+    {0x3b980000}, {0x3b982000}, {0x3b984000}, {0x3b986000}, 
+    {0x3b988000}, {0x3b98a000}, {0x3b98c000}, {0x3b98e000}, 
+    {0x3b990000}, {0x3b992000}, {0x3b994000}, {0x3b996000}, 
+    {0x3b998000}, {0x3b99a000}, {0x3b99c000}, {0x3b99e000}, 
+    {0x3b9a0000}, {0x3b9a2000}, {0x3b9a4000}, {0x3b9a6000}, 
+    {0x3b9a8000}, {0x3b9aa000}, {0x3b9ac000}, {0x3b9ae000}, 
+    {0x3b9b0000}, {0x3b9b2000}, {0x3b9b4000}, {0x3b9b6000}, 
+    {0x3b9b8000}, {0x3b9ba000}, {0x3b9bc000}, {0x3b9be000}, 
+    {0x3b9c0000}, {0x3b9c2000}, {0x3b9c4000}, {0x3b9c6000}, 
+    {0x3b9c8000}, {0x3b9ca000}, {0x3b9cc000}, {0x3b9ce000}, 
+    {0x3b9d0000}, {0x3b9d2000}, {0x3b9d4000}, {0x3b9d6000}, 
+    {0x3b9d8000}, {0x3b9da000}, {0x3b9dc000}, {0x3b9de000}, 
+    {0x3b9e0000}, {0x3b9e2000}, {0x3b9e4000}, {0x3b9e6000}, 
+    {0x3b9e8000}, {0x3b9ea000}, {0x3b9ec000}, {0x3b9ee000}, 
+    {0x3b9f0000}, {0x3b9f2000}, {0x3b9f4000}, {0x3b9f6000}, 
+    {0x3b9f8000}, {0x3b9fa000}, {0x3b9fc000}, {0x3b9fe000}, 
+    {0x3ba00000}, {0x3ba02000}, {0x3ba04000}, {0x3ba06000}, 
+    {0x3ba08000}, {0x3ba0a000}, {0x3ba0c000}, {0x3ba0e000}, 
+    {0x3ba10000}, {0x3ba12000}, {0x3ba14000}, {0x3ba16000}, 
+    {0x3ba18000}, {0x3ba1a000}, {0x3ba1c000}, {0x3ba1e000}, 
+    {0x3ba20000}, {0x3ba22000}, {0x3ba24000}, {0x3ba26000}, 
+    {0x3ba28000}, {0x3ba2a000}, {0x3ba2c000}, {0x3ba2e000}, 
+    {0x3ba30000}, {0x3ba32000}, {0x3ba34000}, {0x3ba36000}, 
+    {0x3ba38000}, {0x3ba3a000}, {0x3ba3c000}, {0x3ba3e000}, 
+    {0x3ba40000}, {0x3ba42000}, {0x3ba44000}, {0x3ba46000}, 
+    {0x3ba48000}, {0x3ba4a000}, {0x3ba4c000}, {0x3ba4e000}, 
+    {0x3ba50000}, {0x3ba52000}, {0x3ba54000}, {0x3ba56000}, 
+    {0x3ba58000}, {0x3ba5a000}, {0x3ba5c000}, {0x3ba5e000}, 
+    {0x3ba60000}, {0x3ba62000}, {0x3ba64000}, {0x3ba66000}, 
+    {0x3ba68000}, {0x3ba6a000}, {0x3ba6c000}, {0x3ba6e000}, 
+    {0x3ba70000}, {0x3ba72000}, {0x3ba74000}, {0x3ba76000}, 
+    {0x3ba78000}, {0x3ba7a000}, {0x3ba7c000}, {0x3ba7e000}, 
+    {0x3ba80000}, {0x3ba82000}, {0x3ba84000}, {0x3ba86000}, 
+    {0x3ba88000}, {0x3ba8a000}, {0x3ba8c000}, {0x3ba8e000}, 
+    {0x3ba90000}, {0x3ba92000}, {0x3ba94000}, {0x3ba96000}, 
+    {0x3ba98000}, {0x3ba9a000}, {0x3ba9c000}, {0x3ba9e000}, 
+    {0x3baa0000}, {0x3baa2000}, {0x3baa4000}, {0x3baa6000}, 
+    {0x3baa8000}, {0x3baaa000}, {0x3baac000}, {0x3baae000}, 
+    {0x3bab0000}, {0x3bab2000}, {0x3bab4000}, {0x3bab6000}, 
+    {0x3bab8000}, {0x3baba000}, {0x3babc000}, {0x3babe000}, 
+    {0x3bac0000}, {0x3bac2000}, {0x3bac4000}, {0x3bac6000}, 
+    {0x3bac8000}, {0x3baca000}, {0x3bacc000}, {0x3bace000}, 
+    {0x3bad0000}, {0x3bad2000}, {0x3bad4000}, {0x3bad6000}, 
+    {0x3bad8000}, {0x3bada000}, {0x3badc000}, {0x3bade000}, 
+    {0x3bae0000}, {0x3bae2000}, {0x3bae4000}, {0x3bae6000}, 
+    {0x3bae8000}, {0x3baea000}, {0x3baec000}, {0x3baee000}, 
+    {0x3baf0000}, {0x3baf2000}, {0x3baf4000}, {0x3baf6000}, 
+    {0x3baf8000}, {0x3bafa000}, {0x3bafc000}, {0x3bafe000}, 
+    {0x3bb00000}, {0x3bb02000}, {0x3bb04000}, {0x3bb06000}, 
+    {0x3bb08000}, {0x3bb0a000}, {0x3bb0c000}, {0x3bb0e000}, 
+    {0x3bb10000}, {0x3bb12000}, {0x3bb14000}, {0x3bb16000}, 
+    {0x3bb18000}, {0x3bb1a000}, {0x3bb1c000}, {0x3bb1e000}, 
+    {0x3bb20000}, {0x3bb22000}, {0x3bb24000}, {0x3bb26000}, 
+    {0x3bb28000}, {0x3bb2a000}, {0x3bb2c000}, {0x3bb2e000}, 
+    {0x3bb30000}, {0x3bb32000}, {0x3bb34000}, {0x3bb36000}, 
+    {0x3bb38000}, {0x3bb3a000}, {0x3bb3c000}, {0x3bb3e000}, 
+    {0x3bb40000}, {0x3bb42000}, {0x3bb44000}, {0x3bb46000}, 
+    {0x3bb48000}, {0x3bb4a000}, {0x3bb4c000}, {0x3bb4e000}, 
+    {0x3bb50000}, {0x3bb52000}, {0x3bb54000}, {0x3bb56000}, 
+    {0x3bb58000}, {0x3bb5a000}, {0x3bb5c000}, {0x3bb5e000}, 
+    {0x3bb60000}, {0x3bb62000}, {0x3bb64000}, {0x3bb66000}, 
+    {0x3bb68000}, {0x3bb6a000}, {0x3bb6c000}, {0x3bb6e000}, 
+    {0x3bb70000}, {0x3bb72000}, {0x3bb74000}, {0x3bb76000}, 
+    {0x3bb78000}, {0x3bb7a000}, {0x3bb7c000}, {0x3bb7e000}, 
+    {0x3bb80000}, {0x3bb82000}, {0x3bb84000}, {0x3bb86000}, 
+    {0x3bb88000}, {0x3bb8a000}, {0x3bb8c000}, {0x3bb8e000}, 
+    {0x3bb90000}, {0x3bb92000}, {0x3bb94000}, {0x3bb96000}, 
+    {0x3bb98000}, {0x3bb9a000}, {0x3bb9c000}, {0x3bb9e000}, 
+    {0x3bba0000}, {0x3bba2000}, {0x3bba4000}, {0x3bba6000}, 
+    {0x3bba8000}, {0x3bbaa000}, {0x3bbac000}, {0x3bbae000}, 
+    {0x3bbb0000}, {0x3bbb2000}, {0x3bbb4000}, {0x3bbb6000}, 
+    {0x3bbb8000}, {0x3bbba000}, {0x3bbbc000}, {0x3bbbe000}, 
+    {0x3bbc0000}, {0x3bbc2000}, {0x3bbc4000}, {0x3bbc6000}, 
+    {0x3bbc8000}, {0x3bbca000}, {0x3bbcc000}, {0x3bbce000}, 
+    {0x3bbd0000}, {0x3bbd2000}, {0x3bbd4000}, {0x3bbd6000}, 
+    {0x3bbd8000}, {0x3bbda000}, {0x3bbdc000}, {0x3bbde000}, 
+    {0x3bbe0000}, {0x3bbe2000}, {0x3bbe4000}, {0x3bbe6000}, 
+    {0x3bbe8000}, {0x3bbea000}, {0x3bbec000}, {0x3bbee000}, 
+    {0x3bbf0000}, {0x3bbf2000}, {0x3bbf4000}, {0x3bbf6000}, 
+    {0x3bbf8000}, {0x3bbfa000}, {0x3bbfc000}, {0x3bbfe000}, 
+    {0x3bc00000}, {0x3bc02000}, {0x3bc04000}, {0x3bc06000}, 
+    {0x3bc08000}, {0x3bc0a000}, {0x3bc0c000}, {0x3bc0e000}, 
+    {0x3bc10000}, {0x3bc12000}, {0x3bc14000}, {0x3bc16000}, 
+    {0x3bc18000}, {0x3bc1a000}, {0x3bc1c000}, {0x3bc1e000}, 
+    {0x3bc20000}, {0x3bc22000}, {0x3bc24000}, {0x3bc26000}, 
+    {0x3bc28000}, {0x3bc2a000}, {0x3bc2c000}, {0x3bc2e000}, 
+    {0x3bc30000}, {0x3bc32000}, {0x3bc34000}, {0x3bc36000}, 
+    {0x3bc38000}, {0x3bc3a000}, {0x3bc3c000}, {0x3bc3e000}, 
+    {0x3bc40000}, {0x3bc42000}, {0x3bc44000}, {0x3bc46000}, 
+    {0x3bc48000}, {0x3bc4a000}, {0x3bc4c000}, {0x3bc4e000}, 
+    {0x3bc50000}, {0x3bc52000}, {0x3bc54000}, {0x3bc56000}, 
+    {0x3bc58000}, {0x3bc5a000}, {0x3bc5c000}, {0x3bc5e000}, 
+    {0x3bc60000}, {0x3bc62000}, {0x3bc64000}, {0x3bc66000}, 
+    {0x3bc68000}, {0x3bc6a000}, {0x3bc6c000}, {0x3bc6e000}, 
+    {0x3bc70000}, {0x3bc72000}, {0x3bc74000}, {0x3bc76000}, 
+    {0x3bc78000}, {0x3bc7a000}, {0x3bc7c000}, {0x3bc7e000}, 
+    {0x3bc80000}, {0x3bc82000}, {0x3bc84000}, {0x3bc86000}, 
+    {0x3bc88000}, {0x3bc8a000}, {0x3bc8c000}, {0x3bc8e000}, 
+    {0x3bc90000}, {0x3bc92000}, {0x3bc94000}, {0x3bc96000}, 
+    {0x3bc98000}, {0x3bc9a000}, {0x3bc9c000}, {0x3bc9e000}, 
+    {0x3bca0000}, {0x3bca2000}, {0x3bca4000}, {0x3bca6000}, 
+    {0x3bca8000}, {0x3bcaa000}, {0x3bcac000}, {0x3bcae000}, 
+    {0x3bcb0000}, {0x3bcb2000}, {0x3bcb4000}, {0x3bcb6000}, 
+    {0x3bcb8000}, {0x3bcba000}, {0x3bcbc000}, {0x3bcbe000}, 
+    {0x3bcc0000}, {0x3bcc2000}, {0x3bcc4000}, {0x3bcc6000}, 
+    {0x3bcc8000}, {0x3bcca000}, {0x3bccc000}, {0x3bcce000}, 
+    {0x3bcd0000}, {0x3bcd2000}, {0x3bcd4000}, {0x3bcd6000}, 
+    {0x3bcd8000}, {0x3bcda000}, {0x3bcdc000}, {0x3bcde000}, 
+    {0x3bce0000}, {0x3bce2000}, {0x3bce4000}, {0x3bce6000}, 
+    {0x3bce8000}, {0x3bcea000}, {0x3bcec000}, {0x3bcee000}, 
+    {0x3bcf0000}, {0x3bcf2000}, {0x3bcf4000}, {0x3bcf6000}, 
+    {0x3bcf8000}, {0x3bcfa000}, {0x3bcfc000}, {0x3bcfe000}, 
+    {0x3bd00000}, {0x3bd02000}, {0x3bd04000}, {0x3bd06000}, 
+    {0x3bd08000}, {0x3bd0a000}, {0x3bd0c000}, {0x3bd0e000}, 
+    {0x3bd10000}, {0x3bd12000}, {0x3bd14000}, {0x3bd16000}, 
+    {0x3bd18000}, {0x3bd1a000}, {0x3bd1c000}, {0x3bd1e000}, 
+    {0x3bd20000}, {0x3bd22000}, {0x3bd24000}, {0x3bd26000}, 
+    {0x3bd28000}, {0x3bd2a000}, {0x3bd2c000}, {0x3bd2e000}, 
+    {0x3bd30000}, {0x3bd32000}, {0x3bd34000}, {0x3bd36000}, 
+    {0x3bd38000}, {0x3bd3a000}, {0x3bd3c000}, {0x3bd3e000}, 
+    {0x3bd40000}, {0x3bd42000}, {0x3bd44000}, {0x3bd46000}, 
+    {0x3bd48000}, {0x3bd4a000}, {0x3bd4c000}, {0x3bd4e000}, 
+    {0x3bd50000}, {0x3bd52000}, {0x3bd54000}, {0x3bd56000}, 
+    {0x3bd58000}, {0x3bd5a000}, {0x3bd5c000}, {0x3bd5e000}, 
+    {0x3bd60000}, {0x3bd62000}, {0x3bd64000}, {0x3bd66000}, 
+    {0x3bd68000}, {0x3bd6a000}, {0x3bd6c000}, {0x3bd6e000}, 
+    {0x3bd70000}, {0x3bd72000}, {0x3bd74000}, {0x3bd76000}, 
+    {0x3bd78000}, {0x3bd7a000}, {0x3bd7c000}, {0x3bd7e000}, 
+    {0x3bd80000}, {0x3bd82000}, {0x3bd84000}, {0x3bd86000}, 
+    {0x3bd88000}, {0x3bd8a000}, {0x3bd8c000}, {0x3bd8e000}, 
+    {0x3bd90000}, {0x3bd92000}, {0x3bd94000}, {0x3bd96000}, 
+    {0x3bd98000}, {0x3bd9a000}, {0x3bd9c000}, {0x3bd9e000}, 
+    {0x3bda0000}, {0x3bda2000}, {0x3bda4000}, {0x3bda6000}, 
+    {0x3bda8000}, {0x3bdaa000}, {0x3bdac000}, {0x3bdae000}, 
+    {0x3bdb0000}, {0x3bdb2000}, {0x3bdb4000}, {0x3bdb6000}, 
+    {0x3bdb8000}, {0x3bdba000}, {0x3bdbc000}, {0x3bdbe000}, 
+    {0x3bdc0000}, {0x3bdc2000}, {0x3bdc4000}, {0x3bdc6000}, 
+    {0x3bdc8000}, {0x3bdca000}, {0x3bdcc000}, {0x3bdce000}, 
+    {0x3bdd0000}, {0x3bdd2000}, {0x3bdd4000}, {0x3bdd6000}, 
+    {0x3bdd8000}, {0x3bdda000}, {0x3bddc000}, {0x3bdde000}, 
+    {0x3bde0000}, {0x3bde2000}, {0x3bde4000}, {0x3bde6000}, 
+    {0x3bde8000}, {0x3bdea000}, {0x3bdec000}, {0x3bdee000}, 
+    {0x3bdf0000}, {0x3bdf2000}, {0x3bdf4000}, {0x3bdf6000}, 
+    {0x3bdf8000}, {0x3bdfa000}, {0x3bdfc000}, {0x3bdfe000}, 
+    {0x3be00000}, {0x3be02000}, {0x3be04000}, {0x3be06000}, 
+    {0x3be08000}, {0x3be0a000}, {0x3be0c000}, {0x3be0e000}, 
+    {0x3be10000}, {0x3be12000}, {0x3be14000}, {0x3be16000}, 
+    {0x3be18000}, {0x3be1a000}, {0x3be1c000}, {0x3be1e000}, 
+    {0x3be20000}, {0x3be22000}, {0x3be24000}, {0x3be26000}, 
+    {0x3be28000}, {0x3be2a000}, {0x3be2c000}, {0x3be2e000}, 
+    {0x3be30000}, {0x3be32000}, {0x3be34000}, {0x3be36000}, 
+    {0x3be38000}, {0x3be3a000}, {0x3be3c000}, {0x3be3e000}, 
+    {0x3be40000}, {0x3be42000}, {0x3be44000}, {0x3be46000}, 
+    {0x3be48000}, {0x3be4a000}, {0x3be4c000}, {0x3be4e000}, 
+    {0x3be50000}, {0x3be52000}, {0x3be54000}, {0x3be56000}, 
+    {0x3be58000}, {0x3be5a000}, {0x3be5c000}, {0x3be5e000}, 
+    {0x3be60000}, {0x3be62000}, {0x3be64000}, {0x3be66000}, 
+    {0x3be68000}, {0x3be6a000}, {0x3be6c000}, {0x3be6e000}, 
+    {0x3be70000}, {0x3be72000}, {0x3be74000}, {0x3be76000}, 
+    {0x3be78000}, {0x3be7a000}, {0x3be7c000}, {0x3be7e000}, 
+    {0x3be80000}, {0x3be82000}, {0x3be84000}, {0x3be86000}, 
+    {0x3be88000}, {0x3be8a000}, {0x3be8c000}, {0x3be8e000}, 
+    {0x3be90000}, {0x3be92000}, {0x3be94000}, {0x3be96000}, 
+    {0x3be98000}, {0x3be9a000}, {0x3be9c000}, {0x3be9e000}, 
+    {0x3bea0000}, {0x3bea2000}, {0x3bea4000}, {0x3bea6000}, 
+    {0x3bea8000}, {0x3beaa000}, {0x3beac000}, {0x3beae000}, 
+    {0x3beb0000}, {0x3beb2000}, {0x3beb4000}, {0x3beb6000}, 
+    {0x3beb8000}, {0x3beba000}, {0x3bebc000}, {0x3bebe000}, 
+    {0x3bec0000}, {0x3bec2000}, {0x3bec4000}, {0x3bec6000}, 
+    {0x3bec8000}, {0x3beca000}, {0x3becc000}, {0x3bece000}, 
+    {0x3bed0000}, {0x3bed2000}, {0x3bed4000}, {0x3bed6000}, 
+    {0x3bed8000}, {0x3beda000}, {0x3bedc000}, {0x3bede000}, 
+    {0x3bee0000}, {0x3bee2000}, {0x3bee4000}, {0x3bee6000}, 
+    {0x3bee8000}, {0x3beea000}, {0x3beec000}, {0x3beee000}, 
+    {0x3bef0000}, {0x3bef2000}, {0x3bef4000}, {0x3bef6000}, 
+    {0x3bef8000}, {0x3befa000}, {0x3befc000}, {0x3befe000}, 
+    {0x3bf00000}, {0x3bf02000}, {0x3bf04000}, {0x3bf06000}, 
+    {0x3bf08000}, {0x3bf0a000}, {0x3bf0c000}, {0x3bf0e000}, 
+    {0x3bf10000}, {0x3bf12000}, {0x3bf14000}, {0x3bf16000}, 
+    {0x3bf18000}, {0x3bf1a000}, {0x3bf1c000}, {0x3bf1e000}, 
+    {0x3bf20000}, {0x3bf22000}, {0x3bf24000}, {0x3bf26000}, 
+    {0x3bf28000}, {0x3bf2a000}, {0x3bf2c000}, {0x3bf2e000}, 
+    {0x3bf30000}, {0x3bf32000}, {0x3bf34000}, {0x3bf36000}, 
+    {0x3bf38000}, {0x3bf3a000}, {0x3bf3c000}, {0x3bf3e000}, 
+    {0x3bf40000}, {0x3bf42000}, {0x3bf44000}, {0x3bf46000}, 
+    {0x3bf48000}, {0x3bf4a000}, {0x3bf4c000}, {0x3bf4e000}, 
+    {0x3bf50000}, {0x3bf52000}, {0x3bf54000}, {0x3bf56000}, 
+    {0x3bf58000}, {0x3bf5a000}, {0x3bf5c000}, {0x3bf5e000}, 
+    {0x3bf60000}, {0x3bf62000}, {0x3bf64000}, {0x3bf66000}, 
+    {0x3bf68000}, {0x3bf6a000}, {0x3bf6c000}, {0x3bf6e000}, 
+    {0x3bf70000}, {0x3bf72000}, {0x3bf74000}, {0x3bf76000}, 
+    {0x3bf78000}, {0x3bf7a000}, {0x3bf7c000}, {0x3bf7e000}, 
+    {0x3bf80000}, {0x3bf82000}, {0x3bf84000}, {0x3bf86000}, 
+    {0x3bf88000}, {0x3bf8a000}, {0x3bf8c000}, {0x3bf8e000}, 
+    {0x3bf90000}, {0x3bf92000}, {0x3bf94000}, {0x3bf96000}, 
+    {0x3bf98000}, {0x3bf9a000}, {0x3bf9c000}, {0x3bf9e000}, 
+    {0x3bfa0000}, {0x3bfa2000}, {0x3bfa4000}, {0x3bfa6000}, 
+    {0x3bfa8000}, {0x3bfaa000}, {0x3bfac000}, {0x3bfae000}, 
+    {0x3bfb0000}, {0x3bfb2000}, {0x3bfb4000}, {0x3bfb6000}, 
+    {0x3bfb8000}, {0x3bfba000}, {0x3bfbc000}, {0x3bfbe000}, 
+    {0x3bfc0000}, {0x3bfc2000}, {0x3bfc4000}, {0x3bfc6000}, 
+    {0x3bfc8000}, {0x3bfca000}, {0x3bfcc000}, {0x3bfce000}, 
+    {0x3bfd0000}, {0x3bfd2000}, {0x3bfd4000}, {0x3bfd6000}, 
+    {0x3bfd8000}, {0x3bfda000}, {0x3bfdc000}, {0x3bfde000}, 
+    {0x3bfe0000}, {0x3bfe2000}, {0x3bfe4000}, {0x3bfe6000}, 
+    {0x3bfe8000}, {0x3bfea000}, {0x3bfec000}, {0x3bfee000}, 
+    {0x3bff0000}, {0x3bff2000}, {0x3bff4000}, {0x3bff6000}, 
+    {0x3bff8000}, {0x3bffa000}, {0x3bffc000}, {0x3bffe000}, 
+    {0x3c000000}, {0x3c002000}, {0x3c004000}, {0x3c006000}, 
+    {0x3c008000}, {0x3c00a000}, {0x3c00c000}, {0x3c00e000}, 
+    {0x3c010000}, {0x3c012000}, {0x3c014000}, {0x3c016000}, 
+    {0x3c018000}, {0x3c01a000}, {0x3c01c000}, {0x3c01e000}, 
+    {0x3c020000}, {0x3c022000}, {0x3c024000}, {0x3c026000}, 
+    {0x3c028000}, {0x3c02a000}, {0x3c02c000}, {0x3c02e000}, 
+    {0x3c030000}, {0x3c032000}, {0x3c034000}, {0x3c036000}, 
+    {0x3c038000}, {0x3c03a000}, {0x3c03c000}, {0x3c03e000}, 
+    {0x3c040000}, {0x3c042000}, {0x3c044000}, {0x3c046000}, 
+    {0x3c048000}, {0x3c04a000}, {0x3c04c000}, {0x3c04e000}, 
+    {0x3c050000}, {0x3c052000}, {0x3c054000}, {0x3c056000}, 
+    {0x3c058000}, {0x3c05a000}, {0x3c05c000}, {0x3c05e000}, 
+    {0x3c060000}, {0x3c062000}, {0x3c064000}, {0x3c066000}, 
+    {0x3c068000}, {0x3c06a000}, {0x3c06c000}, {0x3c06e000}, 
+    {0x3c070000}, {0x3c072000}, {0x3c074000}, {0x3c076000}, 
+    {0x3c078000}, {0x3c07a000}, {0x3c07c000}, {0x3c07e000}, 
+    {0x3c080000}, {0x3c082000}, {0x3c084000}, {0x3c086000}, 
+    {0x3c088000}, {0x3c08a000}, {0x3c08c000}, {0x3c08e000}, 
+    {0x3c090000}, {0x3c092000}, {0x3c094000}, {0x3c096000}, 
+    {0x3c098000}, {0x3c09a000}, {0x3c09c000}, {0x3c09e000}, 
+    {0x3c0a0000}, {0x3c0a2000}, {0x3c0a4000}, {0x3c0a6000}, 
+    {0x3c0a8000}, {0x3c0aa000}, {0x3c0ac000}, {0x3c0ae000}, 
+    {0x3c0b0000}, {0x3c0b2000}, {0x3c0b4000}, {0x3c0b6000}, 
+    {0x3c0b8000}, {0x3c0ba000}, {0x3c0bc000}, {0x3c0be000}, 
+    {0x3c0c0000}, {0x3c0c2000}, {0x3c0c4000}, {0x3c0c6000}, 
+    {0x3c0c8000}, {0x3c0ca000}, {0x3c0cc000}, {0x3c0ce000}, 
+    {0x3c0d0000}, {0x3c0d2000}, {0x3c0d4000}, {0x3c0d6000}, 
+    {0x3c0d8000}, {0x3c0da000}, {0x3c0dc000}, {0x3c0de000}, 
+    {0x3c0e0000}, {0x3c0e2000}, {0x3c0e4000}, {0x3c0e6000}, 
+    {0x3c0e8000}, {0x3c0ea000}, {0x3c0ec000}, {0x3c0ee000}, 
+    {0x3c0f0000}, {0x3c0f2000}, {0x3c0f4000}, {0x3c0f6000}, 
+    {0x3c0f8000}, {0x3c0fa000}, {0x3c0fc000}, {0x3c0fe000}, 
+    {0x3c100000}, {0x3c102000}, {0x3c104000}, {0x3c106000}, 
+    {0x3c108000}, {0x3c10a000}, {0x3c10c000}, {0x3c10e000}, 
+    {0x3c110000}, {0x3c112000}, {0x3c114000}, {0x3c116000}, 
+    {0x3c118000}, {0x3c11a000}, {0x3c11c000}, {0x3c11e000}, 
+    {0x3c120000}, {0x3c122000}, {0x3c124000}, {0x3c126000}, 
+    {0x3c128000}, {0x3c12a000}, {0x3c12c000}, {0x3c12e000}, 
+    {0x3c130000}, {0x3c132000}, {0x3c134000}, {0x3c136000}, 
+    {0x3c138000}, {0x3c13a000}, {0x3c13c000}, {0x3c13e000}, 
+    {0x3c140000}, {0x3c142000}, {0x3c144000}, {0x3c146000}, 
+    {0x3c148000}, {0x3c14a000}, {0x3c14c000}, {0x3c14e000}, 
+    {0x3c150000}, {0x3c152000}, {0x3c154000}, {0x3c156000}, 
+    {0x3c158000}, {0x3c15a000}, {0x3c15c000}, {0x3c15e000}, 
+    {0x3c160000}, {0x3c162000}, {0x3c164000}, {0x3c166000}, 
+    {0x3c168000}, {0x3c16a000}, {0x3c16c000}, {0x3c16e000}, 
+    {0x3c170000}, {0x3c172000}, {0x3c174000}, {0x3c176000}, 
+    {0x3c178000}, {0x3c17a000}, {0x3c17c000}, {0x3c17e000}, 
+    {0x3c180000}, {0x3c182000}, {0x3c184000}, {0x3c186000}, 
+    {0x3c188000}, {0x3c18a000}, {0x3c18c000}, {0x3c18e000}, 
+    {0x3c190000}, {0x3c192000}, {0x3c194000}, {0x3c196000}, 
+    {0x3c198000}, {0x3c19a000}, {0x3c19c000}, {0x3c19e000}, 
+    {0x3c1a0000}, {0x3c1a2000}, {0x3c1a4000}, {0x3c1a6000}, 
+    {0x3c1a8000}, {0x3c1aa000}, {0x3c1ac000}, {0x3c1ae000}, 
+    {0x3c1b0000}, {0x3c1b2000}, {0x3c1b4000}, {0x3c1b6000}, 
+    {0x3c1b8000}, {0x3c1ba000}, {0x3c1bc000}, {0x3c1be000}, 
+    {0x3c1c0000}, {0x3c1c2000}, {0x3c1c4000}, {0x3c1c6000}, 
+    {0x3c1c8000}, {0x3c1ca000}, {0x3c1cc000}, {0x3c1ce000}, 
+    {0x3c1d0000}, {0x3c1d2000}, {0x3c1d4000}, {0x3c1d6000}, 
+    {0x3c1d8000}, {0x3c1da000}, {0x3c1dc000}, {0x3c1de000}, 
+    {0x3c1e0000}, {0x3c1e2000}, {0x3c1e4000}, {0x3c1e6000}, 
+    {0x3c1e8000}, {0x3c1ea000}, {0x3c1ec000}, {0x3c1ee000}, 
+    {0x3c1f0000}, {0x3c1f2000}, {0x3c1f4000}, {0x3c1f6000}, 
+    {0x3c1f8000}, {0x3c1fa000}, {0x3c1fc000}, {0x3c1fe000}, 
+    {0x3c200000}, {0x3c202000}, {0x3c204000}, {0x3c206000}, 
+    {0x3c208000}, {0x3c20a000}, {0x3c20c000}, {0x3c20e000}, 
+    {0x3c210000}, {0x3c212000}, {0x3c214000}, {0x3c216000}, 
+    {0x3c218000}, {0x3c21a000}, {0x3c21c000}, {0x3c21e000}, 
+    {0x3c220000}, {0x3c222000}, {0x3c224000}, {0x3c226000}, 
+    {0x3c228000}, {0x3c22a000}, {0x3c22c000}, {0x3c22e000}, 
+    {0x3c230000}, {0x3c232000}, {0x3c234000}, {0x3c236000}, 
+    {0x3c238000}, {0x3c23a000}, {0x3c23c000}, {0x3c23e000}, 
+    {0x3c240000}, {0x3c242000}, {0x3c244000}, {0x3c246000}, 
+    {0x3c248000}, {0x3c24a000}, {0x3c24c000}, {0x3c24e000}, 
+    {0x3c250000}, {0x3c252000}, {0x3c254000}, {0x3c256000}, 
+    {0x3c258000}, {0x3c25a000}, {0x3c25c000}, {0x3c25e000}, 
+    {0x3c260000}, {0x3c262000}, {0x3c264000}, {0x3c266000}, 
+    {0x3c268000}, {0x3c26a000}, {0x3c26c000}, {0x3c26e000}, 
+    {0x3c270000}, {0x3c272000}, {0x3c274000}, {0x3c276000}, 
+    {0x3c278000}, {0x3c27a000}, {0x3c27c000}, {0x3c27e000}, 
+    {0x3c280000}, {0x3c282000}, {0x3c284000}, {0x3c286000}, 
+    {0x3c288000}, {0x3c28a000}, {0x3c28c000}, {0x3c28e000}, 
+    {0x3c290000}, {0x3c292000}, {0x3c294000}, {0x3c296000}, 
+    {0x3c298000}, {0x3c29a000}, {0x3c29c000}, {0x3c29e000}, 
+    {0x3c2a0000}, {0x3c2a2000}, {0x3c2a4000}, {0x3c2a6000}, 
+    {0x3c2a8000}, {0x3c2aa000}, {0x3c2ac000}, {0x3c2ae000}, 
+    {0x3c2b0000}, {0x3c2b2000}, {0x3c2b4000}, {0x3c2b6000}, 
+    {0x3c2b8000}, {0x3c2ba000}, {0x3c2bc000}, {0x3c2be000}, 
+    {0x3c2c0000}, {0x3c2c2000}, {0x3c2c4000}, {0x3c2c6000}, 
+    {0x3c2c8000}, {0x3c2ca000}, {0x3c2cc000}, {0x3c2ce000}, 
+    {0x3c2d0000}, {0x3c2d2000}, {0x3c2d4000}, {0x3c2d6000}, 
+    {0x3c2d8000}, {0x3c2da000}, {0x3c2dc000}, {0x3c2de000}, 
+    {0x3c2e0000}, {0x3c2e2000}, {0x3c2e4000}, {0x3c2e6000}, 
+    {0x3c2e8000}, {0x3c2ea000}, {0x3c2ec000}, {0x3c2ee000}, 
+    {0x3c2f0000}, {0x3c2f2000}, {0x3c2f4000}, {0x3c2f6000}, 
+    {0x3c2f8000}, {0x3c2fa000}, {0x3c2fc000}, {0x3c2fe000}, 
+    {0x3c300000}, {0x3c302000}, {0x3c304000}, {0x3c306000}, 
+    {0x3c308000}, {0x3c30a000}, {0x3c30c000}, {0x3c30e000}, 
+    {0x3c310000}, {0x3c312000}, {0x3c314000}, {0x3c316000}, 
+    {0x3c318000}, {0x3c31a000}, {0x3c31c000}, {0x3c31e000}, 
+    {0x3c320000}, {0x3c322000}, {0x3c324000}, {0x3c326000}, 
+    {0x3c328000}, {0x3c32a000}, {0x3c32c000}, {0x3c32e000}, 
+    {0x3c330000}, {0x3c332000}, {0x3c334000}, {0x3c336000}, 
+    {0x3c338000}, {0x3c33a000}, {0x3c33c000}, {0x3c33e000}, 
+    {0x3c340000}, {0x3c342000}, {0x3c344000}, {0x3c346000}, 
+    {0x3c348000}, {0x3c34a000}, {0x3c34c000}, {0x3c34e000}, 
+    {0x3c350000}, {0x3c352000}, {0x3c354000}, {0x3c356000}, 
+    {0x3c358000}, {0x3c35a000}, {0x3c35c000}, {0x3c35e000}, 
+    {0x3c360000}, {0x3c362000}, {0x3c364000}, {0x3c366000}, 
+    {0x3c368000}, {0x3c36a000}, {0x3c36c000}, {0x3c36e000}, 
+    {0x3c370000}, {0x3c372000}, {0x3c374000}, {0x3c376000}, 
+    {0x3c378000}, {0x3c37a000}, {0x3c37c000}, {0x3c37e000}, 
+    {0x3c380000}, {0x3c382000}, {0x3c384000}, {0x3c386000}, 
+    {0x3c388000}, {0x3c38a000}, {0x3c38c000}, {0x3c38e000}, 
+    {0x3c390000}, {0x3c392000}, {0x3c394000}, {0x3c396000}, 
+    {0x3c398000}, {0x3c39a000}, {0x3c39c000}, {0x3c39e000}, 
+    {0x3c3a0000}, {0x3c3a2000}, {0x3c3a4000}, {0x3c3a6000}, 
+    {0x3c3a8000}, {0x3c3aa000}, {0x3c3ac000}, {0x3c3ae000}, 
+    {0x3c3b0000}, {0x3c3b2000}, {0x3c3b4000}, {0x3c3b6000}, 
+    {0x3c3b8000}, {0x3c3ba000}, {0x3c3bc000}, {0x3c3be000}, 
+    {0x3c3c0000}, {0x3c3c2000}, {0x3c3c4000}, {0x3c3c6000}, 
+    {0x3c3c8000}, {0x3c3ca000}, {0x3c3cc000}, {0x3c3ce000}, 
+    {0x3c3d0000}, {0x3c3d2000}, {0x3c3d4000}, {0x3c3d6000}, 
+    {0x3c3d8000}, {0x3c3da000}, {0x3c3dc000}, {0x3c3de000}, 
+    {0x3c3e0000}, {0x3c3e2000}, {0x3c3e4000}, {0x3c3e6000}, 
+    {0x3c3e8000}, {0x3c3ea000}, {0x3c3ec000}, {0x3c3ee000}, 
+    {0x3c3f0000}, {0x3c3f2000}, {0x3c3f4000}, {0x3c3f6000}, 
+    {0x3c3f8000}, {0x3c3fa000}, {0x3c3fc000}, {0x3c3fe000}, 
+    {0x3c400000}, {0x3c402000}, {0x3c404000}, {0x3c406000}, 
+    {0x3c408000}, {0x3c40a000}, {0x3c40c000}, {0x3c40e000}, 
+    {0x3c410000}, {0x3c412000}, {0x3c414000}, {0x3c416000}, 
+    {0x3c418000}, {0x3c41a000}, {0x3c41c000}, {0x3c41e000}, 
+    {0x3c420000}, {0x3c422000}, {0x3c424000}, {0x3c426000}, 
+    {0x3c428000}, {0x3c42a000}, {0x3c42c000}, {0x3c42e000}, 
+    {0x3c430000}, {0x3c432000}, {0x3c434000}, {0x3c436000}, 
+    {0x3c438000}, {0x3c43a000}, {0x3c43c000}, {0x3c43e000}, 
+    {0x3c440000}, {0x3c442000}, {0x3c444000}, {0x3c446000}, 
+    {0x3c448000}, {0x3c44a000}, {0x3c44c000}, {0x3c44e000}, 
+    {0x3c450000}, {0x3c452000}, {0x3c454000}, {0x3c456000}, 
+    {0x3c458000}, {0x3c45a000}, {0x3c45c000}, {0x3c45e000}, 
+    {0x3c460000}, {0x3c462000}, {0x3c464000}, {0x3c466000}, 
+    {0x3c468000}, {0x3c46a000}, {0x3c46c000}, {0x3c46e000}, 
+    {0x3c470000}, {0x3c472000}, {0x3c474000}, {0x3c476000}, 
+    {0x3c478000}, {0x3c47a000}, {0x3c47c000}, {0x3c47e000}, 
+    {0x3c480000}, {0x3c482000}, {0x3c484000}, {0x3c486000}, 
+    {0x3c488000}, {0x3c48a000}, {0x3c48c000}, {0x3c48e000}, 
+    {0x3c490000}, {0x3c492000}, {0x3c494000}, {0x3c496000}, 
+    {0x3c498000}, {0x3c49a000}, {0x3c49c000}, {0x3c49e000}, 
+    {0x3c4a0000}, {0x3c4a2000}, {0x3c4a4000}, {0x3c4a6000}, 
+    {0x3c4a8000}, {0x3c4aa000}, {0x3c4ac000}, {0x3c4ae000}, 
+    {0x3c4b0000}, {0x3c4b2000}, {0x3c4b4000}, {0x3c4b6000}, 
+    {0x3c4b8000}, {0x3c4ba000}, {0x3c4bc000}, {0x3c4be000}, 
+    {0x3c4c0000}, {0x3c4c2000}, {0x3c4c4000}, {0x3c4c6000}, 
+    {0x3c4c8000}, {0x3c4ca000}, {0x3c4cc000}, {0x3c4ce000}, 
+    {0x3c4d0000}, {0x3c4d2000}, {0x3c4d4000}, {0x3c4d6000}, 
+    {0x3c4d8000}, {0x3c4da000}, {0x3c4dc000}, {0x3c4de000}, 
+    {0x3c4e0000}, {0x3c4e2000}, {0x3c4e4000}, {0x3c4e6000}, 
+    {0x3c4e8000}, {0x3c4ea000}, {0x3c4ec000}, {0x3c4ee000}, 
+    {0x3c4f0000}, {0x3c4f2000}, {0x3c4f4000}, {0x3c4f6000}, 
+    {0x3c4f8000}, {0x3c4fa000}, {0x3c4fc000}, {0x3c4fe000}, 
+    {0x3c500000}, {0x3c502000}, {0x3c504000}, {0x3c506000}, 
+    {0x3c508000}, {0x3c50a000}, {0x3c50c000}, {0x3c50e000}, 
+    {0x3c510000}, {0x3c512000}, {0x3c514000}, {0x3c516000}, 
+    {0x3c518000}, {0x3c51a000}, {0x3c51c000}, {0x3c51e000}, 
+    {0x3c520000}, {0x3c522000}, {0x3c524000}, {0x3c526000}, 
+    {0x3c528000}, {0x3c52a000}, {0x3c52c000}, {0x3c52e000}, 
+    {0x3c530000}, {0x3c532000}, {0x3c534000}, {0x3c536000}, 
+    {0x3c538000}, {0x3c53a000}, {0x3c53c000}, {0x3c53e000}, 
+    {0x3c540000}, {0x3c542000}, {0x3c544000}, {0x3c546000}, 
+    {0x3c548000}, {0x3c54a000}, {0x3c54c000}, {0x3c54e000}, 
+    {0x3c550000}, {0x3c552000}, {0x3c554000}, {0x3c556000}, 
+    {0x3c558000}, {0x3c55a000}, {0x3c55c000}, {0x3c55e000}, 
+    {0x3c560000}, {0x3c562000}, {0x3c564000}, {0x3c566000}, 
+    {0x3c568000}, {0x3c56a000}, {0x3c56c000}, {0x3c56e000}, 
+    {0x3c570000}, {0x3c572000}, {0x3c574000}, {0x3c576000}, 
+    {0x3c578000}, {0x3c57a000}, {0x3c57c000}, {0x3c57e000}, 
+    {0x3c580000}, {0x3c582000}, {0x3c584000}, {0x3c586000}, 
+    {0x3c588000}, {0x3c58a000}, {0x3c58c000}, {0x3c58e000}, 
+    {0x3c590000}, {0x3c592000}, {0x3c594000}, {0x3c596000}, 
+    {0x3c598000}, {0x3c59a000}, {0x3c59c000}, {0x3c59e000}, 
+    {0x3c5a0000}, {0x3c5a2000}, {0x3c5a4000}, {0x3c5a6000}, 
+    {0x3c5a8000}, {0x3c5aa000}, {0x3c5ac000}, {0x3c5ae000}, 
+    {0x3c5b0000}, {0x3c5b2000}, {0x3c5b4000}, {0x3c5b6000}, 
+    {0x3c5b8000}, {0x3c5ba000}, {0x3c5bc000}, {0x3c5be000}, 
+    {0x3c5c0000}, {0x3c5c2000}, {0x3c5c4000}, {0x3c5c6000}, 
+    {0x3c5c8000}, {0x3c5ca000}, {0x3c5cc000}, {0x3c5ce000}, 
+    {0x3c5d0000}, {0x3c5d2000}, {0x3c5d4000}, {0x3c5d6000}, 
+    {0x3c5d8000}, {0x3c5da000}, {0x3c5dc000}, {0x3c5de000}, 
+    {0x3c5e0000}, {0x3c5e2000}, {0x3c5e4000}, {0x3c5e6000}, 
+    {0x3c5e8000}, {0x3c5ea000}, {0x3c5ec000}, {0x3c5ee000}, 
+    {0x3c5f0000}, {0x3c5f2000}, {0x3c5f4000}, {0x3c5f6000}, 
+    {0x3c5f8000}, {0x3c5fa000}, {0x3c5fc000}, {0x3c5fe000}, 
+    {0x3c600000}, {0x3c602000}, {0x3c604000}, {0x3c606000}, 
+    {0x3c608000}, {0x3c60a000}, {0x3c60c000}, {0x3c60e000}, 
+    {0x3c610000}, {0x3c612000}, {0x3c614000}, {0x3c616000}, 
+    {0x3c618000}, {0x3c61a000}, {0x3c61c000}, {0x3c61e000}, 
+    {0x3c620000}, {0x3c622000}, {0x3c624000}, {0x3c626000}, 
+    {0x3c628000}, {0x3c62a000}, {0x3c62c000}, {0x3c62e000}, 
+    {0x3c630000}, {0x3c632000}, {0x3c634000}, {0x3c636000}, 
+    {0x3c638000}, {0x3c63a000}, {0x3c63c000}, {0x3c63e000}, 
+    {0x3c640000}, {0x3c642000}, {0x3c644000}, {0x3c646000}, 
+    {0x3c648000}, {0x3c64a000}, {0x3c64c000}, {0x3c64e000}, 
+    {0x3c650000}, {0x3c652000}, {0x3c654000}, {0x3c656000}, 
+    {0x3c658000}, {0x3c65a000}, {0x3c65c000}, {0x3c65e000}, 
+    {0x3c660000}, {0x3c662000}, {0x3c664000}, {0x3c666000}, 
+    {0x3c668000}, {0x3c66a000}, {0x3c66c000}, {0x3c66e000}, 
+    {0x3c670000}, {0x3c672000}, {0x3c674000}, {0x3c676000}, 
+    {0x3c678000}, {0x3c67a000}, {0x3c67c000}, {0x3c67e000}, 
+    {0x3c680000}, {0x3c682000}, {0x3c684000}, {0x3c686000}, 
+    {0x3c688000}, {0x3c68a000}, {0x3c68c000}, {0x3c68e000}, 
+    {0x3c690000}, {0x3c692000}, {0x3c694000}, {0x3c696000}, 
+    {0x3c698000}, {0x3c69a000}, {0x3c69c000}, {0x3c69e000}, 
+    {0x3c6a0000}, {0x3c6a2000}, {0x3c6a4000}, {0x3c6a6000}, 
+    {0x3c6a8000}, {0x3c6aa000}, {0x3c6ac000}, {0x3c6ae000}, 
+    {0x3c6b0000}, {0x3c6b2000}, {0x3c6b4000}, {0x3c6b6000}, 
+    {0x3c6b8000}, {0x3c6ba000}, {0x3c6bc000}, {0x3c6be000}, 
+    {0x3c6c0000}, {0x3c6c2000}, {0x3c6c4000}, {0x3c6c6000}, 
+    {0x3c6c8000}, {0x3c6ca000}, {0x3c6cc000}, {0x3c6ce000}, 
+    {0x3c6d0000}, {0x3c6d2000}, {0x3c6d4000}, {0x3c6d6000}, 
+    {0x3c6d8000}, {0x3c6da000}, {0x3c6dc000}, {0x3c6de000}, 
+    {0x3c6e0000}, {0x3c6e2000}, {0x3c6e4000}, {0x3c6e6000}, 
+    {0x3c6e8000}, {0x3c6ea000}, {0x3c6ec000}, {0x3c6ee000}, 
+    {0x3c6f0000}, {0x3c6f2000}, {0x3c6f4000}, {0x3c6f6000}, 
+    {0x3c6f8000}, {0x3c6fa000}, {0x3c6fc000}, {0x3c6fe000}, 
+    {0x3c700000}, {0x3c702000}, {0x3c704000}, {0x3c706000}, 
+    {0x3c708000}, {0x3c70a000}, {0x3c70c000}, {0x3c70e000}, 
+    {0x3c710000}, {0x3c712000}, {0x3c714000}, {0x3c716000}, 
+    {0x3c718000}, {0x3c71a000}, {0x3c71c000}, {0x3c71e000}, 
+    {0x3c720000}, {0x3c722000}, {0x3c724000}, {0x3c726000}, 
+    {0x3c728000}, {0x3c72a000}, {0x3c72c000}, {0x3c72e000}, 
+    {0x3c730000}, {0x3c732000}, {0x3c734000}, {0x3c736000}, 
+    {0x3c738000}, {0x3c73a000}, {0x3c73c000}, {0x3c73e000}, 
+    {0x3c740000}, {0x3c742000}, {0x3c744000}, {0x3c746000}, 
+    {0x3c748000}, {0x3c74a000}, {0x3c74c000}, {0x3c74e000}, 
+    {0x3c750000}, {0x3c752000}, {0x3c754000}, {0x3c756000}, 
+    {0x3c758000}, {0x3c75a000}, {0x3c75c000}, {0x3c75e000}, 
+    {0x3c760000}, {0x3c762000}, {0x3c764000}, {0x3c766000}, 
+    {0x3c768000}, {0x3c76a000}, {0x3c76c000}, {0x3c76e000}, 
+    {0x3c770000}, {0x3c772000}, {0x3c774000}, {0x3c776000}, 
+    {0x3c778000}, {0x3c77a000}, {0x3c77c000}, {0x3c77e000}, 
+    {0x3c780000}, {0x3c782000}, {0x3c784000}, {0x3c786000}, 
+    {0x3c788000}, {0x3c78a000}, {0x3c78c000}, {0x3c78e000}, 
+    {0x3c790000}, {0x3c792000}, {0x3c794000}, {0x3c796000}, 
+    {0x3c798000}, {0x3c79a000}, {0x3c79c000}, {0x3c79e000}, 
+    {0x3c7a0000}, {0x3c7a2000}, {0x3c7a4000}, {0x3c7a6000}, 
+    {0x3c7a8000}, {0x3c7aa000}, {0x3c7ac000}, {0x3c7ae000}, 
+    {0x3c7b0000}, {0x3c7b2000}, {0x3c7b4000}, {0x3c7b6000}, 
+    {0x3c7b8000}, {0x3c7ba000}, {0x3c7bc000}, {0x3c7be000}, 
+    {0x3c7c0000}, {0x3c7c2000}, {0x3c7c4000}, {0x3c7c6000}, 
+    {0x3c7c8000}, {0x3c7ca000}, {0x3c7cc000}, {0x3c7ce000}, 
+    {0x3c7d0000}, {0x3c7d2000}, {0x3c7d4000}, {0x3c7d6000}, 
+    {0x3c7d8000}, {0x3c7da000}, {0x3c7dc000}, {0x3c7de000}, 
+    {0x3c7e0000}, {0x3c7e2000}, {0x3c7e4000}, {0x3c7e6000}, 
+    {0x3c7e8000}, {0x3c7ea000}, {0x3c7ec000}, {0x3c7ee000}, 
+    {0x3c7f0000}, {0x3c7f2000}, {0x3c7f4000}, {0x3c7f6000}, 
+    {0x3c7f8000}, {0x3c7fa000}, {0x3c7fc000}, {0x3c7fe000}, 
+    {0x3c800000}, {0x3c802000}, {0x3c804000}, {0x3c806000}, 
+    {0x3c808000}, {0x3c80a000}, {0x3c80c000}, {0x3c80e000}, 
+    {0x3c810000}, {0x3c812000}, {0x3c814000}, {0x3c816000}, 
+    {0x3c818000}, {0x3c81a000}, {0x3c81c000}, {0x3c81e000}, 
+    {0x3c820000}, {0x3c822000}, {0x3c824000}, {0x3c826000}, 
+    {0x3c828000}, {0x3c82a000}, {0x3c82c000}, {0x3c82e000}, 
+    {0x3c830000}, {0x3c832000}, {0x3c834000}, {0x3c836000}, 
+    {0x3c838000}, {0x3c83a000}, {0x3c83c000}, {0x3c83e000}, 
+    {0x3c840000}, {0x3c842000}, {0x3c844000}, {0x3c846000}, 
+    {0x3c848000}, {0x3c84a000}, {0x3c84c000}, {0x3c84e000}, 
+    {0x3c850000}, {0x3c852000}, {0x3c854000}, {0x3c856000}, 
+    {0x3c858000}, {0x3c85a000}, {0x3c85c000}, {0x3c85e000}, 
+    {0x3c860000}, {0x3c862000}, {0x3c864000}, {0x3c866000}, 
+    {0x3c868000}, {0x3c86a000}, {0x3c86c000}, {0x3c86e000}, 
+    {0x3c870000}, {0x3c872000}, {0x3c874000}, {0x3c876000}, 
+    {0x3c878000}, {0x3c87a000}, {0x3c87c000}, {0x3c87e000}, 
+    {0x3c880000}, {0x3c882000}, {0x3c884000}, {0x3c886000}, 
+    {0x3c888000}, {0x3c88a000}, {0x3c88c000}, {0x3c88e000}, 
+    {0x3c890000}, {0x3c892000}, {0x3c894000}, {0x3c896000}, 
+    {0x3c898000}, {0x3c89a000}, {0x3c89c000}, {0x3c89e000}, 
+    {0x3c8a0000}, {0x3c8a2000}, {0x3c8a4000}, {0x3c8a6000}, 
+    {0x3c8a8000}, {0x3c8aa000}, {0x3c8ac000}, {0x3c8ae000}, 
+    {0x3c8b0000}, {0x3c8b2000}, {0x3c8b4000}, {0x3c8b6000}, 
+    {0x3c8b8000}, {0x3c8ba000}, {0x3c8bc000}, {0x3c8be000}, 
+    {0x3c8c0000}, {0x3c8c2000}, {0x3c8c4000}, {0x3c8c6000}, 
+    {0x3c8c8000}, {0x3c8ca000}, {0x3c8cc000}, {0x3c8ce000}, 
+    {0x3c8d0000}, {0x3c8d2000}, {0x3c8d4000}, {0x3c8d6000}, 
+    {0x3c8d8000}, {0x3c8da000}, {0x3c8dc000}, {0x3c8de000}, 
+    {0x3c8e0000}, {0x3c8e2000}, {0x3c8e4000}, {0x3c8e6000}, 
+    {0x3c8e8000}, {0x3c8ea000}, {0x3c8ec000}, {0x3c8ee000}, 
+    {0x3c8f0000}, {0x3c8f2000}, {0x3c8f4000}, {0x3c8f6000}, 
+    {0x3c8f8000}, {0x3c8fa000}, {0x3c8fc000}, {0x3c8fe000}, 
+    {0x3c900000}, {0x3c902000}, {0x3c904000}, {0x3c906000}, 
+    {0x3c908000}, {0x3c90a000}, {0x3c90c000}, {0x3c90e000}, 
+    {0x3c910000}, {0x3c912000}, {0x3c914000}, {0x3c916000}, 
+    {0x3c918000}, {0x3c91a000}, {0x3c91c000}, {0x3c91e000}, 
+    {0x3c920000}, {0x3c922000}, {0x3c924000}, {0x3c926000}, 
+    {0x3c928000}, {0x3c92a000}, {0x3c92c000}, {0x3c92e000}, 
+    {0x3c930000}, {0x3c932000}, {0x3c934000}, {0x3c936000}, 
+    {0x3c938000}, {0x3c93a000}, {0x3c93c000}, {0x3c93e000}, 
+    {0x3c940000}, {0x3c942000}, {0x3c944000}, {0x3c946000}, 
+    {0x3c948000}, {0x3c94a000}, {0x3c94c000}, {0x3c94e000}, 
+    {0x3c950000}, {0x3c952000}, {0x3c954000}, {0x3c956000}, 
+    {0x3c958000}, {0x3c95a000}, {0x3c95c000}, {0x3c95e000}, 
+    {0x3c960000}, {0x3c962000}, {0x3c964000}, {0x3c966000}, 
+    {0x3c968000}, {0x3c96a000}, {0x3c96c000}, {0x3c96e000}, 
+    {0x3c970000}, {0x3c972000}, {0x3c974000}, {0x3c976000}, 
+    {0x3c978000}, {0x3c97a000}, {0x3c97c000}, {0x3c97e000}, 
+    {0x3c980000}, {0x3c982000}, {0x3c984000}, {0x3c986000}, 
+    {0x3c988000}, {0x3c98a000}, {0x3c98c000}, {0x3c98e000}, 
+    {0x3c990000}, {0x3c992000}, {0x3c994000}, {0x3c996000}, 
+    {0x3c998000}, {0x3c99a000}, {0x3c99c000}, {0x3c99e000}, 
+    {0x3c9a0000}, {0x3c9a2000}, {0x3c9a4000}, {0x3c9a6000}, 
+    {0x3c9a8000}, {0x3c9aa000}, {0x3c9ac000}, {0x3c9ae000}, 
+    {0x3c9b0000}, {0x3c9b2000}, {0x3c9b4000}, {0x3c9b6000}, 
+    {0x3c9b8000}, {0x3c9ba000}, {0x3c9bc000}, {0x3c9be000}, 
+    {0x3c9c0000}, {0x3c9c2000}, {0x3c9c4000}, {0x3c9c6000}, 
+    {0x3c9c8000}, {0x3c9ca000}, {0x3c9cc000}, {0x3c9ce000}, 
+    {0x3c9d0000}, {0x3c9d2000}, {0x3c9d4000}, {0x3c9d6000}, 
+    {0x3c9d8000}, {0x3c9da000}, {0x3c9dc000}, {0x3c9de000}, 
+    {0x3c9e0000}, {0x3c9e2000}, {0x3c9e4000}, {0x3c9e6000}, 
+    {0x3c9e8000}, {0x3c9ea000}, {0x3c9ec000}, {0x3c9ee000}, 
+    {0x3c9f0000}, {0x3c9f2000}, {0x3c9f4000}, {0x3c9f6000}, 
+    {0x3c9f8000}, {0x3c9fa000}, {0x3c9fc000}, {0x3c9fe000}, 
+    {0x3ca00000}, {0x3ca02000}, {0x3ca04000}, {0x3ca06000}, 
+    {0x3ca08000}, {0x3ca0a000}, {0x3ca0c000}, {0x3ca0e000}, 
+    {0x3ca10000}, {0x3ca12000}, {0x3ca14000}, {0x3ca16000}, 
+    {0x3ca18000}, {0x3ca1a000}, {0x3ca1c000}, {0x3ca1e000}, 
+    {0x3ca20000}, {0x3ca22000}, {0x3ca24000}, {0x3ca26000}, 
+    {0x3ca28000}, {0x3ca2a000}, {0x3ca2c000}, {0x3ca2e000}, 
+    {0x3ca30000}, {0x3ca32000}, {0x3ca34000}, {0x3ca36000}, 
+    {0x3ca38000}, {0x3ca3a000}, {0x3ca3c000}, {0x3ca3e000}, 
+    {0x3ca40000}, {0x3ca42000}, {0x3ca44000}, {0x3ca46000}, 
+    {0x3ca48000}, {0x3ca4a000}, {0x3ca4c000}, {0x3ca4e000}, 
+    {0x3ca50000}, {0x3ca52000}, {0x3ca54000}, {0x3ca56000}, 
+    {0x3ca58000}, {0x3ca5a000}, {0x3ca5c000}, {0x3ca5e000}, 
+    {0x3ca60000}, {0x3ca62000}, {0x3ca64000}, {0x3ca66000}, 
+    {0x3ca68000}, {0x3ca6a000}, {0x3ca6c000}, {0x3ca6e000}, 
+    {0x3ca70000}, {0x3ca72000}, {0x3ca74000}, {0x3ca76000}, 
+    {0x3ca78000}, {0x3ca7a000}, {0x3ca7c000}, {0x3ca7e000}, 
+    {0x3ca80000}, {0x3ca82000}, {0x3ca84000}, {0x3ca86000}, 
+    {0x3ca88000}, {0x3ca8a000}, {0x3ca8c000}, {0x3ca8e000}, 
+    {0x3ca90000}, {0x3ca92000}, {0x3ca94000}, {0x3ca96000}, 
+    {0x3ca98000}, {0x3ca9a000}, {0x3ca9c000}, {0x3ca9e000}, 
+    {0x3caa0000}, {0x3caa2000}, {0x3caa4000}, {0x3caa6000}, 
+    {0x3caa8000}, {0x3caaa000}, {0x3caac000}, {0x3caae000}, 
+    {0x3cab0000}, {0x3cab2000}, {0x3cab4000}, {0x3cab6000}, 
+    {0x3cab8000}, {0x3caba000}, {0x3cabc000}, {0x3cabe000}, 
+    {0x3cac0000}, {0x3cac2000}, {0x3cac4000}, {0x3cac6000}, 
+    {0x3cac8000}, {0x3caca000}, {0x3cacc000}, {0x3cace000}, 
+    {0x3cad0000}, {0x3cad2000}, {0x3cad4000}, {0x3cad6000}, 
+    {0x3cad8000}, {0x3cada000}, {0x3cadc000}, {0x3cade000}, 
+    {0x3cae0000}, {0x3cae2000}, {0x3cae4000}, {0x3cae6000}, 
+    {0x3cae8000}, {0x3caea000}, {0x3caec000}, {0x3caee000}, 
+    {0x3caf0000}, {0x3caf2000}, {0x3caf4000}, {0x3caf6000}, 
+    {0x3caf8000}, {0x3cafa000}, {0x3cafc000}, {0x3cafe000}, 
+    {0x3cb00000}, {0x3cb02000}, {0x3cb04000}, {0x3cb06000}, 
+    {0x3cb08000}, {0x3cb0a000}, {0x3cb0c000}, {0x3cb0e000}, 
+    {0x3cb10000}, {0x3cb12000}, {0x3cb14000}, {0x3cb16000}, 
+    {0x3cb18000}, {0x3cb1a000}, {0x3cb1c000}, {0x3cb1e000}, 
+    {0x3cb20000}, {0x3cb22000}, {0x3cb24000}, {0x3cb26000}, 
+    {0x3cb28000}, {0x3cb2a000}, {0x3cb2c000}, {0x3cb2e000}, 
+    {0x3cb30000}, {0x3cb32000}, {0x3cb34000}, {0x3cb36000}, 
+    {0x3cb38000}, {0x3cb3a000}, {0x3cb3c000}, {0x3cb3e000}, 
+    {0x3cb40000}, {0x3cb42000}, {0x3cb44000}, {0x3cb46000}, 
+    {0x3cb48000}, {0x3cb4a000}, {0x3cb4c000}, {0x3cb4e000}, 
+    {0x3cb50000}, {0x3cb52000}, {0x3cb54000}, {0x3cb56000}, 
+    {0x3cb58000}, {0x3cb5a000}, {0x3cb5c000}, {0x3cb5e000}, 
+    {0x3cb60000}, {0x3cb62000}, {0x3cb64000}, {0x3cb66000}, 
+    {0x3cb68000}, {0x3cb6a000}, {0x3cb6c000}, {0x3cb6e000}, 
+    {0x3cb70000}, {0x3cb72000}, {0x3cb74000}, {0x3cb76000}, 
+    {0x3cb78000}, {0x3cb7a000}, {0x3cb7c000}, {0x3cb7e000}, 
+    {0x3cb80000}, {0x3cb82000}, {0x3cb84000}, {0x3cb86000}, 
+    {0x3cb88000}, {0x3cb8a000}, {0x3cb8c000}, {0x3cb8e000}, 
+    {0x3cb90000}, {0x3cb92000}, {0x3cb94000}, {0x3cb96000}, 
+    {0x3cb98000}, {0x3cb9a000}, {0x3cb9c000}, {0x3cb9e000}, 
+    {0x3cba0000}, {0x3cba2000}, {0x3cba4000}, {0x3cba6000}, 
+    {0x3cba8000}, {0x3cbaa000}, {0x3cbac000}, {0x3cbae000}, 
+    {0x3cbb0000}, {0x3cbb2000}, {0x3cbb4000}, {0x3cbb6000}, 
+    {0x3cbb8000}, {0x3cbba000}, {0x3cbbc000}, {0x3cbbe000}, 
+    {0x3cbc0000}, {0x3cbc2000}, {0x3cbc4000}, {0x3cbc6000}, 
+    {0x3cbc8000}, {0x3cbca000}, {0x3cbcc000}, {0x3cbce000}, 
+    {0x3cbd0000}, {0x3cbd2000}, {0x3cbd4000}, {0x3cbd6000}, 
+    {0x3cbd8000}, {0x3cbda000}, {0x3cbdc000}, {0x3cbde000}, 
+    {0x3cbe0000}, {0x3cbe2000}, {0x3cbe4000}, {0x3cbe6000}, 
+    {0x3cbe8000}, {0x3cbea000}, {0x3cbec000}, {0x3cbee000}, 
+    {0x3cbf0000}, {0x3cbf2000}, {0x3cbf4000}, {0x3cbf6000}, 
+    {0x3cbf8000}, {0x3cbfa000}, {0x3cbfc000}, {0x3cbfe000}, 
+    {0x3cc00000}, {0x3cc02000}, {0x3cc04000}, {0x3cc06000}, 
+    {0x3cc08000}, {0x3cc0a000}, {0x3cc0c000}, {0x3cc0e000}, 
+    {0x3cc10000}, {0x3cc12000}, {0x3cc14000}, {0x3cc16000}, 
+    {0x3cc18000}, {0x3cc1a000}, {0x3cc1c000}, {0x3cc1e000}, 
+    {0x3cc20000}, {0x3cc22000}, {0x3cc24000}, {0x3cc26000}, 
+    {0x3cc28000}, {0x3cc2a000}, {0x3cc2c000}, {0x3cc2e000}, 
+    {0x3cc30000}, {0x3cc32000}, {0x3cc34000}, {0x3cc36000}, 
+    {0x3cc38000}, {0x3cc3a000}, {0x3cc3c000}, {0x3cc3e000}, 
+    {0x3cc40000}, {0x3cc42000}, {0x3cc44000}, {0x3cc46000}, 
+    {0x3cc48000}, {0x3cc4a000}, {0x3cc4c000}, {0x3cc4e000}, 
+    {0x3cc50000}, {0x3cc52000}, {0x3cc54000}, {0x3cc56000}, 
+    {0x3cc58000}, {0x3cc5a000}, {0x3cc5c000}, {0x3cc5e000}, 
+    {0x3cc60000}, {0x3cc62000}, {0x3cc64000}, {0x3cc66000}, 
+    {0x3cc68000}, {0x3cc6a000}, {0x3cc6c000}, {0x3cc6e000}, 
+    {0x3cc70000}, {0x3cc72000}, {0x3cc74000}, {0x3cc76000}, 
+    {0x3cc78000}, {0x3cc7a000}, {0x3cc7c000}, {0x3cc7e000}, 
+    {0x3cc80000}, {0x3cc82000}, {0x3cc84000}, {0x3cc86000}, 
+    {0x3cc88000}, {0x3cc8a000}, {0x3cc8c000}, {0x3cc8e000}, 
+    {0x3cc90000}, {0x3cc92000}, {0x3cc94000}, {0x3cc96000}, 
+    {0x3cc98000}, {0x3cc9a000}, {0x3cc9c000}, {0x3cc9e000}, 
+    {0x3cca0000}, {0x3cca2000}, {0x3cca4000}, {0x3cca6000}, 
+    {0x3cca8000}, {0x3ccaa000}, {0x3ccac000}, {0x3ccae000}, 
+    {0x3ccb0000}, {0x3ccb2000}, {0x3ccb4000}, {0x3ccb6000}, 
+    {0x3ccb8000}, {0x3ccba000}, {0x3ccbc000}, {0x3ccbe000}, 
+    {0x3ccc0000}, {0x3ccc2000}, {0x3ccc4000}, {0x3ccc6000}, 
+    {0x3ccc8000}, {0x3ccca000}, {0x3cccc000}, {0x3ccce000}, 
+    {0x3ccd0000}, {0x3ccd2000}, {0x3ccd4000}, {0x3ccd6000}, 
+    {0x3ccd8000}, {0x3ccda000}, {0x3ccdc000}, {0x3ccde000}, 
+    {0x3cce0000}, {0x3cce2000}, {0x3cce4000}, {0x3cce6000}, 
+    {0x3cce8000}, {0x3ccea000}, {0x3ccec000}, {0x3ccee000}, 
+    {0x3ccf0000}, {0x3ccf2000}, {0x3ccf4000}, {0x3ccf6000}, 
+    {0x3ccf8000}, {0x3ccfa000}, {0x3ccfc000}, {0x3ccfe000}, 
+    {0x3cd00000}, {0x3cd02000}, {0x3cd04000}, {0x3cd06000}, 
+    {0x3cd08000}, {0x3cd0a000}, {0x3cd0c000}, {0x3cd0e000}, 
+    {0x3cd10000}, {0x3cd12000}, {0x3cd14000}, {0x3cd16000}, 
+    {0x3cd18000}, {0x3cd1a000}, {0x3cd1c000}, {0x3cd1e000}, 
+    {0x3cd20000}, {0x3cd22000}, {0x3cd24000}, {0x3cd26000}, 
+    {0x3cd28000}, {0x3cd2a000}, {0x3cd2c000}, {0x3cd2e000}, 
+    {0x3cd30000}, {0x3cd32000}, {0x3cd34000}, {0x3cd36000}, 
+    {0x3cd38000}, {0x3cd3a000}, {0x3cd3c000}, {0x3cd3e000}, 
+    {0x3cd40000}, {0x3cd42000}, {0x3cd44000}, {0x3cd46000}, 
+    {0x3cd48000}, {0x3cd4a000}, {0x3cd4c000}, {0x3cd4e000}, 
+    {0x3cd50000}, {0x3cd52000}, {0x3cd54000}, {0x3cd56000}, 
+    {0x3cd58000}, {0x3cd5a000}, {0x3cd5c000}, {0x3cd5e000}, 
+    {0x3cd60000}, {0x3cd62000}, {0x3cd64000}, {0x3cd66000}, 
+    {0x3cd68000}, {0x3cd6a000}, {0x3cd6c000}, {0x3cd6e000}, 
+    {0x3cd70000}, {0x3cd72000}, {0x3cd74000}, {0x3cd76000}, 
+    {0x3cd78000}, {0x3cd7a000}, {0x3cd7c000}, {0x3cd7e000}, 
+    {0x3cd80000}, {0x3cd82000}, {0x3cd84000}, {0x3cd86000}, 
+    {0x3cd88000}, {0x3cd8a000}, {0x3cd8c000}, {0x3cd8e000}, 
+    {0x3cd90000}, {0x3cd92000}, {0x3cd94000}, {0x3cd96000}, 
+    {0x3cd98000}, {0x3cd9a000}, {0x3cd9c000}, {0x3cd9e000}, 
+    {0x3cda0000}, {0x3cda2000}, {0x3cda4000}, {0x3cda6000}, 
+    {0x3cda8000}, {0x3cdaa000}, {0x3cdac000}, {0x3cdae000}, 
+    {0x3cdb0000}, {0x3cdb2000}, {0x3cdb4000}, {0x3cdb6000}, 
+    {0x3cdb8000}, {0x3cdba000}, {0x3cdbc000}, {0x3cdbe000}, 
+    {0x3cdc0000}, {0x3cdc2000}, {0x3cdc4000}, {0x3cdc6000}, 
+    {0x3cdc8000}, {0x3cdca000}, {0x3cdcc000}, {0x3cdce000}, 
+    {0x3cdd0000}, {0x3cdd2000}, {0x3cdd4000}, {0x3cdd6000}, 
+    {0x3cdd8000}, {0x3cdda000}, {0x3cddc000}, {0x3cdde000}, 
+    {0x3cde0000}, {0x3cde2000}, {0x3cde4000}, {0x3cde6000}, 
+    {0x3cde8000}, {0x3cdea000}, {0x3cdec000}, {0x3cdee000}, 
+    {0x3cdf0000}, {0x3cdf2000}, {0x3cdf4000}, {0x3cdf6000}, 
+    {0x3cdf8000}, {0x3cdfa000}, {0x3cdfc000}, {0x3cdfe000}, 
+    {0x3ce00000}, {0x3ce02000}, {0x3ce04000}, {0x3ce06000}, 
+    {0x3ce08000}, {0x3ce0a000}, {0x3ce0c000}, {0x3ce0e000}, 
+    {0x3ce10000}, {0x3ce12000}, {0x3ce14000}, {0x3ce16000}, 
+    {0x3ce18000}, {0x3ce1a000}, {0x3ce1c000}, {0x3ce1e000}, 
+    {0x3ce20000}, {0x3ce22000}, {0x3ce24000}, {0x3ce26000}, 
+    {0x3ce28000}, {0x3ce2a000}, {0x3ce2c000}, {0x3ce2e000}, 
+    {0x3ce30000}, {0x3ce32000}, {0x3ce34000}, {0x3ce36000}, 
+    {0x3ce38000}, {0x3ce3a000}, {0x3ce3c000}, {0x3ce3e000}, 
+    {0x3ce40000}, {0x3ce42000}, {0x3ce44000}, {0x3ce46000}, 
+    {0x3ce48000}, {0x3ce4a000}, {0x3ce4c000}, {0x3ce4e000}, 
+    {0x3ce50000}, {0x3ce52000}, {0x3ce54000}, {0x3ce56000}, 
+    {0x3ce58000}, {0x3ce5a000}, {0x3ce5c000}, {0x3ce5e000}, 
+    {0x3ce60000}, {0x3ce62000}, {0x3ce64000}, {0x3ce66000}, 
+    {0x3ce68000}, {0x3ce6a000}, {0x3ce6c000}, {0x3ce6e000}, 
+    {0x3ce70000}, {0x3ce72000}, {0x3ce74000}, {0x3ce76000}, 
+    {0x3ce78000}, {0x3ce7a000}, {0x3ce7c000}, {0x3ce7e000}, 
+    {0x3ce80000}, {0x3ce82000}, {0x3ce84000}, {0x3ce86000}, 
+    {0x3ce88000}, {0x3ce8a000}, {0x3ce8c000}, {0x3ce8e000}, 
+    {0x3ce90000}, {0x3ce92000}, {0x3ce94000}, {0x3ce96000}, 
+    {0x3ce98000}, {0x3ce9a000}, {0x3ce9c000}, {0x3ce9e000}, 
+    {0x3cea0000}, {0x3cea2000}, {0x3cea4000}, {0x3cea6000}, 
+    {0x3cea8000}, {0x3ceaa000}, {0x3ceac000}, {0x3ceae000}, 
+    {0x3ceb0000}, {0x3ceb2000}, {0x3ceb4000}, {0x3ceb6000}, 
+    {0x3ceb8000}, {0x3ceba000}, {0x3cebc000}, {0x3cebe000}, 
+    {0x3cec0000}, {0x3cec2000}, {0x3cec4000}, {0x3cec6000}, 
+    {0x3cec8000}, {0x3ceca000}, {0x3cecc000}, {0x3cece000}, 
+    {0x3ced0000}, {0x3ced2000}, {0x3ced4000}, {0x3ced6000}, 
+    {0x3ced8000}, {0x3ceda000}, {0x3cedc000}, {0x3cede000}, 
+    {0x3cee0000}, {0x3cee2000}, {0x3cee4000}, {0x3cee6000}, 
+    {0x3cee8000}, {0x3ceea000}, {0x3ceec000}, {0x3ceee000}, 
+    {0x3cef0000}, {0x3cef2000}, {0x3cef4000}, {0x3cef6000}, 
+    {0x3cef8000}, {0x3cefa000}, {0x3cefc000}, {0x3cefe000}, 
+    {0x3cf00000}, {0x3cf02000}, {0x3cf04000}, {0x3cf06000}, 
+    {0x3cf08000}, {0x3cf0a000}, {0x3cf0c000}, {0x3cf0e000}, 
+    {0x3cf10000}, {0x3cf12000}, {0x3cf14000}, {0x3cf16000}, 
+    {0x3cf18000}, {0x3cf1a000}, {0x3cf1c000}, {0x3cf1e000}, 
+    {0x3cf20000}, {0x3cf22000}, {0x3cf24000}, {0x3cf26000}, 
+    {0x3cf28000}, {0x3cf2a000}, {0x3cf2c000}, {0x3cf2e000}, 
+    {0x3cf30000}, {0x3cf32000}, {0x3cf34000}, {0x3cf36000}, 
+    {0x3cf38000}, {0x3cf3a000}, {0x3cf3c000}, {0x3cf3e000}, 
+    {0x3cf40000}, {0x3cf42000}, {0x3cf44000}, {0x3cf46000}, 
+    {0x3cf48000}, {0x3cf4a000}, {0x3cf4c000}, {0x3cf4e000}, 
+    {0x3cf50000}, {0x3cf52000}, {0x3cf54000}, {0x3cf56000}, 
+    {0x3cf58000}, {0x3cf5a000}, {0x3cf5c000}, {0x3cf5e000}, 
+    {0x3cf60000}, {0x3cf62000}, {0x3cf64000}, {0x3cf66000}, 
+    {0x3cf68000}, {0x3cf6a000}, {0x3cf6c000}, {0x3cf6e000}, 
+    {0x3cf70000}, {0x3cf72000}, {0x3cf74000}, {0x3cf76000}, 
+    {0x3cf78000}, {0x3cf7a000}, {0x3cf7c000}, {0x3cf7e000}, 
+    {0x3cf80000}, {0x3cf82000}, {0x3cf84000}, {0x3cf86000}, 
+    {0x3cf88000}, {0x3cf8a000}, {0x3cf8c000}, {0x3cf8e000}, 
+    {0x3cf90000}, {0x3cf92000}, {0x3cf94000}, {0x3cf96000}, 
+    {0x3cf98000}, {0x3cf9a000}, {0x3cf9c000}, {0x3cf9e000}, 
+    {0x3cfa0000}, {0x3cfa2000}, {0x3cfa4000}, {0x3cfa6000}, 
+    {0x3cfa8000}, {0x3cfaa000}, {0x3cfac000}, {0x3cfae000}, 
+    {0x3cfb0000}, {0x3cfb2000}, {0x3cfb4000}, {0x3cfb6000}, 
+    {0x3cfb8000}, {0x3cfba000}, {0x3cfbc000}, {0x3cfbe000}, 
+    {0x3cfc0000}, {0x3cfc2000}, {0x3cfc4000}, {0x3cfc6000}, 
+    {0x3cfc8000}, {0x3cfca000}, {0x3cfcc000}, {0x3cfce000}, 
+    {0x3cfd0000}, {0x3cfd2000}, {0x3cfd4000}, {0x3cfd6000}, 
+    {0x3cfd8000}, {0x3cfda000}, {0x3cfdc000}, {0x3cfde000}, 
+    {0x3cfe0000}, {0x3cfe2000}, {0x3cfe4000}, {0x3cfe6000}, 
+    {0x3cfe8000}, {0x3cfea000}, {0x3cfec000}, {0x3cfee000}, 
+    {0x3cff0000}, {0x3cff2000}, {0x3cff4000}, {0x3cff6000}, 
+    {0x3cff8000}, {0x3cffa000}, {0x3cffc000}, {0x3cffe000}, 
+    {0x3d000000}, {0x3d002000}, {0x3d004000}, {0x3d006000}, 
+    {0x3d008000}, {0x3d00a000}, {0x3d00c000}, {0x3d00e000}, 
+    {0x3d010000}, {0x3d012000}, {0x3d014000}, {0x3d016000}, 
+    {0x3d018000}, {0x3d01a000}, {0x3d01c000}, {0x3d01e000}, 
+    {0x3d020000}, {0x3d022000}, {0x3d024000}, {0x3d026000}, 
+    {0x3d028000}, {0x3d02a000}, {0x3d02c000}, {0x3d02e000}, 
+    {0x3d030000}, {0x3d032000}, {0x3d034000}, {0x3d036000}, 
+    {0x3d038000}, {0x3d03a000}, {0x3d03c000}, {0x3d03e000}, 
+    {0x3d040000}, {0x3d042000}, {0x3d044000}, {0x3d046000}, 
+    {0x3d048000}, {0x3d04a000}, {0x3d04c000}, {0x3d04e000}, 
+    {0x3d050000}, {0x3d052000}, {0x3d054000}, {0x3d056000}, 
+    {0x3d058000}, {0x3d05a000}, {0x3d05c000}, {0x3d05e000}, 
+    {0x3d060000}, {0x3d062000}, {0x3d064000}, {0x3d066000}, 
+    {0x3d068000}, {0x3d06a000}, {0x3d06c000}, {0x3d06e000}, 
+    {0x3d070000}, {0x3d072000}, {0x3d074000}, {0x3d076000}, 
+    {0x3d078000}, {0x3d07a000}, {0x3d07c000}, {0x3d07e000}, 
+    {0x3d080000}, {0x3d082000}, {0x3d084000}, {0x3d086000}, 
+    {0x3d088000}, {0x3d08a000}, {0x3d08c000}, {0x3d08e000}, 
+    {0x3d090000}, {0x3d092000}, {0x3d094000}, {0x3d096000}, 
+    {0x3d098000}, {0x3d09a000}, {0x3d09c000}, {0x3d09e000}, 
+    {0x3d0a0000}, {0x3d0a2000}, {0x3d0a4000}, {0x3d0a6000}, 
+    {0x3d0a8000}, {0x3d0aa000}, {0x3d0ac000}, {0x3d0ae000}, 
+    {0x3d0b0000}, {0x3d0b2000}, {0x3d0b4000}, {0x3d0b6000}, 
+    {0x3d0b8000}, {0x3d0ba000}, {0x3d0bc000}, {0x3d0be000}, 
+    {0x3d0c0000}, {0x3d0c2000}, {0x3d0c4000}, {0x3d0c6000}, 
+    {0x3d0c8000}, {0x3d0ca000}, {0x3d0cc000}, {0x3d0ce000}, 
+    {0x3d0d0000}, {0x3d0d2000}, {0x3d0d4000}, {0x3d0d6000}, 
+    {0x3d0d8000}, {0x3d0da000}, {0x3d0dc000}, {0x3d0de000}, 
+    {0x3d0e0000}, {0x3d0e2000}, {0x3d0e4000}, {0x3d0e6000}, 
+    {0x3d0e8000}, {0x3d0ea000}, {0x3d0ec000}, {0x3d0ee000}, 
+    {0x3d0f0000}, {0x3d0f2000}, {0x3d0f4000}, {0x3d0f6000}, 
+    {0x3d0f8000}, {0x3d0fa000}, {0x3d0fc000}, {0x3d0fe000}, 
+    {0x3d100000}, {0x3d102000}, {0x3d104000}, {0x3d106000}, 
+    {0x3d108000}, {0x3d10a000}, {0x3d10c000}, {0x3d10e000}, 
+    {0x3d110000}, {0x3d112000}, {0x3d114000}, {0x3d116000}, 
+    {0x3d118000}, {0x3d11a000}, {0x3d11c000}, {0x3d11e000}, 
+    {0x3d120000}, {0x3d122000}, {0x3d124000}, {0x3d126000}, 
+    {0x3d128000}, {0x3d12a000}, {0x3d12c000}, {0x3d12e000}, 
+    {0x3d130000}, {0x3d132000}, {0x3d134000}, {0x3d136000}, 
+    {0x3d138000}, {0x3d13a000}, {0x3d13c000}, {0x3d13e000}, 
+    {0x3d140000}, {0x3d142000}, {0x3d144000}, {0x3d146000}, 
+    {0x3d148000}, {0x3d14a000}, {0x3d14c000}, {0x3d14e000}, 
+    {0x3d150000}, {0x3d152000}, {0x3d154000}, {0x3d156000}, 
+    {0x3d158000}, {0x3d15a000}, {0x3d15c000}, {0x3d15e000}, 
+    {0x3d160000}, {0x3d162000}, {0x3d164000}, {0x3d166000}, 
+    {0x3d168000}, {0x3d16a000}, {0x3d16c000}, {0x3d16e000}, 
+    {0x3d170000}, {0x3d172000}, {0x3d174000}, {0x3d176000}, 
+    {0x3d178000}, {0x3d17a000}, {0x3d17c000}, {0x3d17e000}, 
+    {0x3d180000}, {0x3d182000}, {0x3d184000}, {0x3d186000}, 
+    {0x3d188000}, {0x3d18a000}, {0x3d18c000}, {0x3d18e000}, 
+    {0x3d190000}, {0x3d192000}, {0x3d194000}, {0x3d196000}, 
+    {0x3d198000}, {0x3d19a000}, {0x3d19c000}, {0x3d19e000}, 
+    {0x3d1a0000}, {0x3d1a2000}, {0x3d1a4000}, {0x3d1a6000}, 
+    {0x3d1a8000}, {0x3d1aa000}, {0x3d1ac000}, {0x3d1ae000}, 
+    {0x3d1b0000}, {0x3d1b2000}, {0x3d1b4000}, {0x3d1b6000}, 
+    {0x3d1b8000}, {0x3d1ba000}, {0x3d1bc000}, {0x3d1be000}, 
+    {0x3d1c0000}, {0x3d1c2000}, {0x3d1c4000}, {0x3d1c6000}, 
+    {0x3d1c8000}, {0x3d1ca000}, {0x3d1cc000}, {0x3d1ce000}, 
+    {0x3d1d0000}, {0x3d1d2000}, {0x3d1d4000}, {0x3d1d6000}, 
+    {0x3d1d8000}, {0x3d1da000}, {0x3d1dc000}, {0x3d1de000}, 
+    {0x3d1e0000}, {0x3d1e2000}, {0x3d1e4000}, {0x3d1e6000}, 
+    {0x3d1e8000}, {0x3d1ea000}, {0x3d1ec000}, {0x3d1ee000}, 
+    {0x3d1f0000}, {0x3d1f2000}, {0x3d1f4000}, {0x3d1f6000}, 
+    {0x3d1f8000}, {0x3d1fa000}, {0x3d1fc000}, {0x3d1fe000}, 
+    {0x3d200000}, {0x3d202000}, {0x3d204000}, {0x3d206000}, 
+    {0x3d208000}, {0x3d20a000}, {0x3d20c000}, {0x3d20e000}, 
+    {0x3d210000}, {0x3d212000}, {0x3d214000}, {0x3d216000}, 
+    {0x3d218000}, {0x3d21a000}, {0x3d21c000}, {0x3d21e000}, 
+    {0x3d220000}, {0x3d222000}, {0x3d224000}, {0x3d226000}, 
+    {0x3d228000}, {0x3d22a000}, {0x3d22c000}, {0x3d22e000}, 
+    {0x3d230000}, {0x3d232000}, {0x3d234000}, {0x3d236000}, 
+    {0x3d238000}, {0x3d23a000}, {0x3d23c000}, {0x3d23e000}, 
+    {0x3d240000}, {0x3d242000}, {0x3d244000}, {0x3d246000}, 
+    {0x3d248000}, {0x3d24a000}, {0x3d24c000}, {0x3d24e000}, 
+    {0x3d250000}, {0x3d252000}, {0x3d254000}, {0x3d256000}, 
+    {0x3d258000}, {0x3d25a000}, {0x3d25c000}, {0x3d25e000}, 
+    {0x3d260000}, {0x3d262000}, {0x3d264000}, {0x3d266000}, 
+    {0x3d268000}, {0x3d26a000}, {0x3d26c000}, {0x3d26e000}, 
+    {0x3d270000}, {0x3d272000}, {0x3d274000}, {0x3d276000}, 
+    {0x3d278000}, {0x3d27a000}, {0x3d27c000}, {0x3d27e000}, 
+    {0x3d280000}, {0x3d282000}, {0x3d284000}, {0x3d286000}, 
+    {0x3d288000}, {0x3d28a000}, {0x3d28c000}, {0x3d28e000}, 
+    {0x3d290000}, {0x3d292000}, {0x3d294000}, {0x3d296000}, 
+    {0x3d298000}, {0x3d29a000}, {0x3d29c000}, {0x3d29e000}, 
+    {0x3d2a0000}, {0x3d2a2000}, {0x3d2a4000}, {0x3d2a6000}, 
+    {0x3d2a8000}, {0x3d2aa000}, {0x3d2ac000}, {0x3d2ae000}, 
+    {0x3d2b0000}, {0x3d2b2000}, {0x3d2b4000}, {0x3d2b6000}, 
+    {0x3d2b8000}, {0x3d2ba000}, {0x3d2bc000}, {0x3d2be000}, 
+    {0x3d2c0000}, {0x3d2c2000}, {0x3d2c4000}, {0x3d2c6000}, 
+    {0x3d2c8000}, {0x3d2ca000}, {0x3d2cc000}, {0x3d2ce000}, 
+    {0x3d2d0000}, {0x3d2d2000}, {0x3d2d4000}, {0x3d2d6000}, 
+    {0x3d2d8000}, {0x3d2da000}, {0x3d2dc000}, {0x3d2de000}, 
+    {0x3d2e0000}, {0x3d2e2000}, {0x3d2e4000}, {0x3d2e6000}, 
+    {0x3d2e8000}, {0x3d2ea000}, {0x3d2ec000}, {0x3d2ee000}, 
+    {0x3d2f0000}, {0x3d2f2000}, {0x3d2f4000}, {0x3d2f6000}, 
+    {0x3d2f8000}, {0x3d2fa000}, {0x3d2fc000}, {0x3d2fe000}, 
+    {0x3d300000}, {0x3d302000}, {0x3d304000}, {0x3d306000}, 
+    {0x3d308000}, {0x3d30a000}, {0x3d30c000}, {0x3d30e000}, 
+    {0x3d310000}, {0x3d312000}, {0x3d314000}, {0x3d316000}, 
+    {0x3d318000}, {0x3d31a000}, {0x3d31c000}, {0x3d31e000}, 
+    {0x3d320000}, {0x3d322000}, {0x3d324000}, {0x3d326000}, 
+    {0x3d328000}, {0x3d32a000}, {0x3d32c000}, {0x3d32e000}, 
+    {0x3d330000}, {0x3d332000}, {0x3d334000}, {0x3d336000}, 
+    {0x3d338000}, {0x3d33a000}, {0x3d33c000}, {0x3d33e000}, 
+    {0x3d340000}, {0x3d342000}, {0x3d344000}, {0x3d346000}, 
+    {0x3d348000}, {0x3d34a000}, {0x3d34c000}, {0x3d34e000}, 
+    {0x3d350000}, {0x3d352000}, {0x3d354000}, {0x3d356000}, 
+    {0x3d358000}, {0x3d35a000}, {0x3d35c000}, {0x3d35e000}, 
+    {0x3d360000}, {0x3d362000}, {0x3d364000}, {0x3d366000}, 
+    {0x3d368000}, {0x3d36a000}, {0x3d36c000}, {0x3d36e000}, 
+    {0x3d370000}, {0x3d372000}, {0x3d374000}, {0x3d376000}, 
+    {0x3d378000}, {0x3d37a000}, {0x3d37c000}, {0x3d37e000}, 
+    {0x3d380000}, {0x3d382000}, {0x3d384000}, {0x3d386000}, 
+    {0x3d388000}, {0x3d38a000}, {0x3d38c000}, {0x3d38e000}, 
+    {0x3d390000}, {0x3d392000}, {0x3d394000}, {0x3d396000}, 
+    {0x3d398000}, {0x3d39a000}, {0x3d39c000}, {0x3d39e000}, 
+    {0x3d3a0000}, {0x3d3a2000}, {0x3d3a4000}, {0x3d3a6000}, 
+    {0x3d3a8000}, {0x3d3aa000}, {0x3d3ac000}, {0x3d3ae000}, 
+    {0x3d3b0000}, {0x3d3b2000}, {0x3d3b4000}, {0x3d3b6000}, 
+    {0x3d3b8000}, {0x3d3ba000}, {0x3d3bc000}, {0x3d3be000}, 
+    {0x3d3c0000}, {0x3d3c2000}, {0x3d3c4000}, {0x3d3c6000}, 
+    {0x3d3c8000}, {0x3d3ca000}, {0x3d3cc000}, {0x3d3ce000}, 
+    {0x3d3d0000}, {0x3d3d2000}, {0x3d3d4000}, {0x3d3d6000}, 
+    {0x3d3d8000}, {0x3d3da000}, {0x3d3dc000}, {0x3d3de000}, 
+    {0x3d3e0000}, {0x3d3e2000}, {0x3d3e4000}, {0x3d3e6000}, 
+    {0x3d3e8000}, {0x3d3ea000}, {0x3d3ec000}, {0x3d3ee000}, 
+    {0x3d3f0000}, {0x3d3f2000}, {0x3d3f4000}, {0x3d3f6000}, 
+    {0x3d3f8000}, {0x3d3fa000}, {0x3d3fc000}, {0x3d3fe000}, 
+    {0x3d400000}, {0x3d402000}, {0x3d404000}, {0x3d406000}, 
+    {0x3d408000}, {0x3d40a000}, {0x3d40c000}, {0x3d40e000}, 
+    {0x3d410000}, {0x3d412000}, {0x3d414000}, {0x3d416000}, 
+    {0x3d418000}, {0x3d41a000}, {0x3d41c000}, {0x3d41e000}, 
+    {0x3d420000}, {0x3d422000}, {0x3d424000}, {0x3d426000}, 
+    {0x3d428000}, {0x3d42a000}, {0x3d42c000}, {0x3d42e000}, 
+    {0x3d430000}, {0x3d432000}, {0x3d434000}, {0x3d436000}, 
+    {0x3d438000}, {0x3d43a000}, {0x3d43c000}, {0x3d43e000}, 
+    {0x3d440000}, {0x3d442000}, {0x3d444000}, {0x3d446000}, 
+    {0x3d448000}, {0x3d44a000}, {0x3d44c000}, {0x3d44e000}, 
+    {0x3d450000}, {0x3d452000}, {0x3d454000}, {0x3d456000}, 
+    {0x3d458000}, {0x3d45a000}, {0x3d45c000}, {0x3d45e000}, 
+    {0x3d460000}, {0x3d462000}, {0x3d464000}, {0x3d466000}, 
+    {0x3d468000}, {0x3d46a000}, {0x3d46c000}, {0x3d46e000}, 
+    {0x3d470000}, {0x3d472000}, {0x3d474000}, {0x3d476000}, 
+    {0x3d478000}, {0x3d47a000}, {0x3d47c000}, {0x3d47e000}, 
+    {0x3d480000}, {0x3d482000}, {0x3d484000}, {0x3d486000}, 
+    {0x3d488000}, {0x3d48a000}, {0x3d48c000}, {0x3d48e000}, 
+    {0x3d490000}, {0x3d492000}, {0x3d494000}, {0x3d496000}, 
+    {0x3d498000}, {0x3d49a000}, {0x3d49c000}, {0x3d49e000}, 
+    {0x3d4a0000}, {0x3d4a2000}, {0x3d4a4000}, {0x3d4a6000}, 
+    {0x3d4a8000}, {0x3d4aa000}, {0x3d4ac000}, {0x3d4ae000}, 
+    {0x3d4b0000}, {0x3d4b2000}, {0x3d4b4000}, {0x3d4b6000}, 
+    {0x3d4b8000}, {0x3d4ba000}, {0x3d4bc000}, {0x3d4be000}, 
+    {0x3d4c0000}, {0x3d4c2000}, {0x3d4c4000}, {0x3d4c6000}, 
+    {0x3d4c8000}, {0x3d4ca000}, {0x3d4cc000}, {0x3d4ce000}, 
+    {0x3d4d0000}, {0x3d4d2000}, {0x3d4d4000}, {0x3d4d6000}, 
+    {0x3d4d8000}, {0x3d4da000}, {0x3d4dc000}, {0x3d4de000}, 
+    {0x3d4e0000}, {0x3d4e2000}, {0x3d4e4000}, {0x3d4e6000}, 
+    {0x3d4e8000}, {0x3d4ea000}, {0x3d4ec000}, {0x3d4ee000}, 
+    {0x3d4f0000}, {0x3d4f2000}, {0x3d4f4000}, {0x3d4f6000}, 
+    {0x3d4f8000}, {0x3d4fa000}, {0x3d4fc000}, {0x3d4fe000}, 
+    {0x3d500000}, {0x3d502000}, {0x3d504000}, {0x3d506000}, 
+    {0x3d508000}, {0x3d50a000}, {0x3d50c000}, {0x3d50e000}, 
+    {0x3d510000}, {0x3d512000}, {0x3d514000}, {0x3d516000}, 
+    {0x3d518000}, {0x3d51a000}, {0x3d51c000}, {0x3d51e000}, 
+    {0x3d520000}, {0x3d522000}, {0x3d524000}, {0x3d526000}, 
+    {0x3d528000}, {0x3d52a000}, {0x3d52c000}, {0x3d52e000}, 
+    {0x3d530000}, {0x3d532000}, {0x3d534000}, {0x3d536000}, 
+    {0x3d538000}, {0x3d53a000}, {0x3d53c000}, {0x3d53e000}, 
+    {0x3d540000}, {0x3d542000}, {0x3d544000}, {0x3d546000}, 
+    {0x3d548000}, {0x3d54a000}, {0x3d54c000}, {0x3d54e000}, 
+    {0x3d550000}, {0x3d552000}, {0x3d554000}, {0x3d556000}, 
+    {0x3d558000}, {0x3d55a000}, {0x3d55c000}, {0x3d55e000}, 
+    {0x3d560000}, {0x3d562000}, {0x3d564000}, {0x3d566000}, 
+    {0x3d568000}, {0x3d56a000}, {0x3d56c000}, {0x3d56e000}, 
+    {0x3d570000}, {0x3d572000}, {0x3d574000}, {0x3d576000}, 
+    {0x3d578000}, {0x3d57a000}, {0x3d57c000}, {0x3d57e000}, 
+    {0x3d580000}, {0x3d582000}, {0x3d584000}, {0x3d586000}, 
+    {0x3d588000}, {0x3d58a000}, {0x3d58c000}, {0x3d58e000}, 
+    {0x3d590000}, {0x3d592000}, {0x3d594000}, {0x3d596000}, 
+    {0x3d598000}, {0x3d59a000}, {0x3d59c000}, {0x3d59e000}, 
+    {0x3d5a0000}, {0x3d5a2000}, {0x3d5a4000}, {0x3d5a6000}, 
+    {0x3d5a8000}, {0x3d5aa000}, {0x3d5ac000}, {0x3d5ae000}, 
+    {0x3d5b0000}, {0x3d5b2000}, {0x3d5b4000}, {0x3d5b6000}, 
+    {0x3d5b8000}, {0x3d5ba000}, {0x3d5bc000}, {0x3d5be000}, 
+    {0x3d5c0000}, {0x3d5c2000}, {0x3d5c4000}, {0x3d5c6000}, 
+    {0x3d5c8000}, {0x3d5ca000}, {0x3d5cc000}, {0x3d5ce000}, 
+    {0x3d5d0000}, {0x3d5d2000}, {0x3d5d4000}, {0x3d5d6000}, 
+    {0x3d5d8000}, {0x3d5da000}, {0x3d5dc000}, {0x3d5de000}, 
+    {0x3d5e0000}, {0x3d5e2000}, {0x3d5e4000}, {0x3d5e6000}, 
+    {0x3d5e8000}, {0x3d5ea000}, {0x3d5ec000}, {0x3d5ee000}, 
+    {0x3d5f0000}, {0x3d5f2000}, {0x3d5f4000}, {0x3d5f6000}, 
+    {0x3d5f8000}, {0x3d5fa000}, {0x3d5fc000}, {0x3d5fe000}, 
+    {0x3d600000}, {0x3d602000}, {0x3d604000}, {0x3d606000}, 
+    {0x3d608000}, {0x3d60a000}, {0x3d60c000}, {0x3d60e000}, 
+    {0x3d610000}, {0x3d612000}, {0x3d614000}, {0x3d616000}, 
+    {0x3d618000}, {0x3d61a000}, {0x3d61c000}, {0x3d61e000}, 
+    {0x3d620000}, {0x3d622000}, {0x3d624000}, {0x3d626000}, 
+    {0x3d628000}, {0x3d62a000}, {0x3d62c000}, {0x3d62e000}, 
+    {0x3d630000}, {0x3d632000}, {0x3d634000}, {0x3d636000}, 
+    {0x3d638000}, {0x3d63a000}, {0x3d63c000}, {0x3d63e000}, 
+    {0x3d640000}, {0x3d642000}, {0x3d644000}, {0x3d646000}, 
+    {0x3d648000}, {0x3d64a000}, {0x3d64c000}, {0x3d64e000}, 
+    {0x3d650000}, {0x3d652000}, {0x3d654000}, {0x3d656000}, 
+    {0x3d658000}, {0x3d65a000}, {0x3d65c000}, {0x3d65e000}, 
+    {0x3d660000}, {0x3d662000}, {0x3d664000}, {0x3d666000}, 
+    {0x3d668000}, {0x3d66a000}, {0x3d66c000}, {0x3d66e000}, 
+    {0x3d670000}, {0x3d672000}, {0x3d674000}, {0x3d676000}, 
+    {0x3d678000}, {0x3d67a000}, {0x3d67c000}, {0x3d67e000}, 
+    {0x3d680000}, {0x3d682000}, {0x3d684000}, {0x3d686000}, 
+    {0x3d688000}, {0x3d68a000}, {0x3d68c000}, {0x3d68e000}, 
+    {0x3d690000}, {0x3d692000}, {0x3d694000}, {0x3d696000}, 
+    {0x3d698000}, {0x3d69a000}, {0x3d69c000}, {0x3d69e000}, 
+    {0x3d6a0000}, {0x3d6a2000}, {0x3d6a4000}, {0x3d6a6000}, 
+    {0x3d6a8000}, {0x3d6aa000}, {0x3d6ac000}, {0x3d6ae000}, 
+    {0x3d6b0000}, {0x3d6b2000}, {0x3d6b4000}, {0x3d6b6000}, 
+    {0x3d6b8000}, {0x3d6ba000}, {0x3d6bc000}, {0x3d6be000}, 
+    {0x3d6c0000}, {0x3d6c2000}, {0x3d6c4000}, {0x3d6c6000}, 
+    {0x3d6c8000}, {0x3d6ca000}, {0x3d6cc000}, {0x3d6ce000}, 
+    {0x3d6d0000}, {0x3d6d2000}, {0x3d6d4000}, {0x3d6d6000}, 
+    {0x3d6d8000}, {0x3d6da000}, {0x3d6dc000}, {0x3d6de000}, 
+    {0x3d6e0000}, {0x3d6e2000}, {0x3d6e4000}, {0x3d6e6000}, 
+    {0x3d6e8000}, {0x3d6ea000}, {0x3d6ec000}, {0x3d6ee000}, 
+    {0x3d6f0000}, {0x3d6f2000}, {0x3d6f4000}, {0x3d6f6000}, 
+    {0x3d6f8000}, {0x3d6fa000}, {0x3d6fc000}, {0x3d6fe000}, 
+    {0x3d700000}, {0x3d702000}, {0x3d704000}, {0x3d706000}, 
+    {0x3d708000}, {0x3d70a000}, {0x3d70c000}, {0x3d70e000}, 
+    {0x3d710000}, {0x3d712000}, {0x3d714000}, {0x3d716000}, 
+    {0x3d718000}, {0x3d71a000}, {0x3d71c000}, {0x3d71e000}, 
+    {0x3d720000}, {0x3d722000}, {0x3d724000}, {0x3d726000}, 
+    {0x3d728000}, {0x3d72a000}, {0x3d72c000}, {0x3d72e000}, 
+    {0x3d730000}, {0x3d732000}, {0x3d734000}, {0x3d736000}, 
+    {0x3d738000}, {0x3d73a000}, {0x3d73c000}, {0x3d73e000}, 
+    {0x3d740000}, {0x3d742000}, {0x3d744000}, {0x3d746000}, 
+    {0x3d748000}, {0x3d74a000}, {0x3d74c000}, {0x3d74e000}, 
+    {0x3d750000}, {0x3d752000}, {0x3d754000}, {0x3d756000}, 
+    {0x3d758000}, {0x3d75a000}, {0x3d75c000}, {0x3d75e000}, 
+    {0x3d760000}, {0x3d762000}, {0x3d764000}, {0x3d766000}, 
+    {0x3d768000}, {0x3d76a000}, {0x3d76c000}, {0x3d76e000}, 
+    {0x3d770000}, {0x3d772000}, {0x3d774000}, {0x3d776000}, 
+    {0x3d778000}, {0x3d77a000}, {0x3d77c000}, {0x3d77e000}, 
+    {0x3d780000}, {0x3d782000}, {0x3d784000}, {0x3d786000}, 
+    {0x3d788000}, {0x3d78a000}, {0x3d78c000}, {0x3d78e000}, 
+    {0x3d790000}, {0x3d792000}, {0x3d794000}, {0x3d796000}, 
+    {0x3d798000}, {0x3d79a000}, {0x3d79c000}, {0x3d79e000}, 
+    {0x3d7a0000}, {0x3d7a2000}, {0x3d7a4000}, {0x3d7a6000}, 
+    {0x3d7a8000}, {0x3d7aa000}, {0x3d7ac000}, {0x3d7ae000}, 
+    {0x3d7b0000}, {0x3d7b2000}, {0x3d7b4000}, {0x3d7b6000}, 
+    {0x3d7b8000}, {0x3d7ba000}, {0x3d7bc000}, {0x3d7be000}, 
+    {0x3d7c0000}, {0x3d7c2000}, {0x3d7c4000}, {0x3d7c6000}, 
+    {0x3d7c8000}, {0x3d7ca000}, {0x3d7cc000}, {0x3d7ce000}, 
+    {0x3d7d0000}, {0x3d7d2000}, {0x3d7d4000}, {0x3d7d6000}, 
+    {0x3d7d8000}, {0x3d7da000}, {0x3d7dc000}, {0x3d7de000}, 
+    {0x3d7e0000}, {0x3d7e2000}, {0x3d7e4000}, {0x3d7e6000}, 
+    {0x3d7e8000}, {0x3d7ea000}, {0x3d7ec000}, {0x3d7ee000}, 
+    {0x3d7f0000}, {0x3d7f2000}, {0x3d7f4000}, {0x3d7f6000}, 
+    {0x3d7f8000}, {0x3d7fa000}, {0x3d7fc000}, {0x3d7fe000}, 
+    {0x3d800000}, {0x3d802000}, {0x3d804000}, {0x3d806000}, 
+    {0x3d808000}, {0x3d80a000}, {0x3d80c000}, {0x3d80e000}, 
+    {0x3d810000}, {0x3d812000}, {0x3d814000}, {0x3d816000}, 
+    {0x3d818000}, {0x3d81a000}, {0x3d81c000}, {0x3d81e000}, 
+    {0x3d820000}, {0x3d822000}, {0x3d824000}, {0x3d826000}, 
+    {0x3d828000}, {0x3d82a000}, {0x3d82c000}, {0x3d82e000}, 
+    {0x3d830000}, {0x3d832000}, {0x3d834000}, {0x3d836000}, 
+    {0x3d838000}, {0x3d83a000}, {0x3d83c000}, {0x3d83e000}, 
+    {0x3d840000}, {0x3d842000}, {0x3d844000}, {0x3d846000}, 
+    {0x3d848000}, {0x3d84a000}, {0x3d84c000}, {0x3d84e000}, 
+    {0x3d850000}, {0x3d852000}, {0x3d854000}, {0x3d856000}, 
+    {0x3d858000}, {0x3d85a000}, {0x3d85c000}, {0x3d85e000}, 
+    {0x3d860000}, {0x3d862000}, {0x3d864000}, {0x3d866000}, 
+    {0x3d868000}, {0x3d86a000}, {0x3d86c000}, {0x3d86e000}, 
+    {0x3d870000}, {0x3d872000}, {0x3d874000}, {0x3d876000}, 
+    {0x3d878000}, {0x3d87a000}, {0x3d87c000}, {0x3d87e000}, 
+    {0x3d880000}, {0x3d882000}, {0x3d884000}, {0x3d886000}, 
+    {0x3d888000}, {0x3d88a000}, {0x3d88c000}, {0x3d88e000}, 
+    {0x3d890000}, {0x3d892000}, {0x3d894000}, {0x3d896000}, 
+    {0x3d898000}, {0x3d89a000}, {0x3d89c000}, {0x3d89e000}, 
+    {0x3d8a0000}, {0x3d8a2000}, {0x3d8a4000}, {0x3d8a6000}, 
+    {0x3d8a8000}, {0x3d8aa000}, {0x3d8ac000}, {0x3d8ae000}, 
+    {0x3d8b0000}, {0x3d8b2000}, {0x3d8b4000}, {0x3d8b6000}, 
+    {0x3d8b8000}, {0x3d8ba000}, {0x3d8bc000}, {0x3d8be000}, 
+    {0x3d8c0000}, {0x3d8c2000}, {0x3d8c4000}, {0x3d8c6000}, 
+    {0x3d8c8000}, {0x3d8ca000}, {0x3d8cc000}, {0x3d8ce000}, 
+    {0x3d8d0000}, {0x3d8d2000}, {0x3d8d4000}, {0x3d8d6000}, 
+    {0x3d8d8000}, {0x3d8da000}, {0x3d8dc000}, {0x3d8de000}, 
+    {0x3d8e0000}, {0x3d8e2000}, {0x3d8e4000}, {0x3d8e6000}, 
+    {0x3d8e8000}, {0x3d8ea000}, {0x3d8ec000}, {0x3d8ee000}, 
+    {0x3d8f0000}, {0x3d8f2000}, {0x3d8f4000}, {0x3d8f6000}, 
+    {0x3d8f8000}, {0x3d8fa000}, {0x3d8fc000}, {0x3d8fe000}, 
+    {0x3d900000}, {0x3d902000}, {0x3d904000}, {0x3d906000}, 
+    {0x3d908000}, {0x3d90a000}, {0x3d90c000}, {0x3d90e000}, 
+    {0x3d910000}, {0x3d912000}, {0x3d914000}, {0x3d916000}, 
+    {0x3d918000}, {0x3d91a000}, {0x3d91c000}, {0x3d91e000}, 
+    {0x3d920000}, {0x3d922000}, {0x3d924000}, {0x3d926000}, 
+    {0x3d928000}, {0x3d92a000}, {0x3d92c000}, {0x3d92e000}, 
+    {0x3d930000}, {0x3d932000}, {0x3d934000}, {0x3d936000}, 
+    {0x3d938000}, {0x3d93a000}, {0x3d93c000}, {0x3d93e000}, 
+    {0x3d940000}, {0x3d942000}, {0x3d944000}, {0x3d946000}, 
+    {0x3d948000}, {0x3d94a000}, {0x3d94c000}, {0x3d94e000}, 
+    {0x3d950000}, {0x3d952000}, {0x3d954000}, {0x3d956000}, 
+    {0x3d958000}, {0x3d95a000}, {0x3d95c000}, {0x3d95e000}, 
+    {0x3d960000}, {0x3d962000}, {0x3d964000}, {0x3d966000}, 
+    {0x3d968000}, {0x3d96a000}, {0x3d96c000}, {0x3d96e000}, 
+    {0x3d970000}, {0x3d972000}, {0x3d974000}, {0x3d976000}, 
+    {0x3d978000}, {0x3d97a000}, {0x3d97c000}, {0x3d97e000}, 
+    {0x3d980000}, {0x3d982000}, {0x3d984000}, {0x3d986000}, 
+    {0x3d988000}, {0x3d98a000}, {0x3d98c000}, {0x3d98e000}, 
+    {0x3d990000}, {0x3d992000}, {0x3d994000}, {0x3d996000}, 
+    {0x3d998000}, {0x3d99a000}, {0x3d99c000}, {0x3d99e000}, 
+    {0x3d9a0000}, {0x3d9a2000}, {0x3d9a4000}, {0x3d9a6000}, 
+    {0x3d9a8000}, {0x3d9aa000}, {0x3d9ac000}, {0x3d9ae000}, 
+    {0x3d9b0000}, {0x3d9b2000}, {0x3d9b4000}, {0x3d9b6000}, 
+    {0x3d9b8000}, {0x3d9ba000}, {0x3d9bc000}, {0x3d9be000}, 
+    {0x3d9c0000}, {0x3d9c2000}, {0x3d9c4000}, {0x3d9c6000}, 
+    {0x3d9c8000}, {0x3d9ca000}, {0x3d9cc000}, {0x3d9ce000}, 
+    {0x3d9d0000}, {0x3d9d2000}, {0x3d9d4000}, {0x3d9d6000}, 
+    {0x3d9d8000}, {0x3d9da000}, {0x3d9dc000}, {0x3d9de000}, 
+    {0x3d9e0000}, {0x3d9e2000}, {0x3d9e4000}, {0x3d9e6000}, 
+    {0x3d9e8000}, {0x3d9ea000}, {0x3d9ec000}, {0x3d9ee000}, 
+    {0x3d9f0000}, {0x3d9f2000}, {0x3d9f4000}, {0x3d9f6000}, 
+    {0x3d9f8000}, {0x3d9fa000}, {0x3d9fc000}, {0x3d9fe000}, 
+    {0x3da00000}, {0x3da02000}, {0x3da04000}, {0x3da06000}, 
+    {0x3da08000}, {0x3da0a000}, {0x3da0c000}, {0x3da0e000}, 
+    {0x3da10000}, {0x3da12000}, {0x3da14000}, {0x3da16000}, 
+    {0x3da18000}, {0x3da1a000}, {0x3da1c000}, {0x3da1e000}, 
+    {0x3da20000}, {0x3da22000}, {0x3da24000}, {0x3da26000}, 
+    {0x3da28000}, {0x3da2a000}, {0x3da2c000}, {0x3da2e000}, 
+    {0x3da30000}, {0x3da32000}, {0x3da34000}, {0x3da36000}, 
+    {0x3da38000}, {0x3da3a000}, {0x3da3c000}, {0x3da3e000}, 
+    {0x3da40000}, {0x3da42000}, {0x3da44000}, {0x3da46000}, 
+    {0x3da48000}, {0x3da4a000}, {0x3da4c000}, {0x3da4e000}, 
+    {0x3da50000}, {0x3da52000}, {0x3da54000}, {0x3da56000}, 
+    {0x3da58000}, {0x3da5a000}, {0x3da5c000}, {0x3da5e000}, 
+    {0x3da60000}, {0x3da62000}, {0x3da64000}, {0x3da66000}, 
+    {0x3da68000}, {0x3da6a000}, {0x3da6c000}, {0x3da6e000}, 
+    {0x3da70000}, {0x3da72000}, {0x3da74000}, {0x3da76000}, 
+    {0x3da78000}, {0x3da7a000}, {0x3da7c000}, {0x3da7e000}, 
+    {0x3da80000}, {0x3da82000}, {0x3da84000}, {0x3da86000}, 
+    {0x3da88000}, {0x3da8a000}, {0x3da8c000}, {0x3da8e000}, 
+    {0x3da90000}, {0x3da92000}, {0x3da94000}, {0x3da96000}, 
+    {0x3da98000}, {0x3da9a000}, {0x3da9c000}, {0x3da9e000}, 
+    {0x3daa0000}, {0x3daa2000}, {0x3daa4000}, {0x3daa6000}, 
+    {0x3daa8000}, {0x3daaa000}, {0x3daac000}, {0x3daae000}, 
+    {0x3dab0000}, {0x3dab2000}, {0x3dab4000}, {0x3dab6000}, 
+    {0x3dab8000}, {0x3daba000}, {0x3dabc000}, {0x3dabe000}, 
+    {0x3dac0000}, {0x3dac2000}, {0x3dac4000}, {0x3dac6000}, 
+    {0x3dac8000}, {0x3daca000}, {0x3dacc000}, {0x3dace000}, 
+    {0x3dad0000}, {0x3dad2000}, {0x3dad4000}, {0x3dad6000}, 
+    {0x3dad8000}, {0x3dada000}, {0x3dadc000}, {0x3dade000}, 
+    {0x3dae0000}, {0x3dae2000}, {0x3dae4000}, {0x3dae6000}, 
+    {0x3dae8000}, {0x3daea000}, {0x3daec000}, {0x3daee000}, 
+    {0x3daf0000}, {0x3daf2000}, {0x3daf4000}, {0x3daf6000}, 
+    {0x3daf8000}, {0x3dafa000}, {0x3dafc000}, {0x3dafe000}, 
+    {0x3db00000}, {0x3db02000}, {0x3db04000}, {0x3db06000}, 
+    {0x3db08000}, {0x3db0a000}, {0x3db0c000}, {0x3db0e000}, 
+    {0x3db10000}, {0x3db12000}, {0x3db14000}, {0x3db16000}, 
+    {0x3db18000}, {0x3db1a000}, {0x3db1c000}, {0x3db1e000}, 
+    {0x3db20000}, {0x3db22000}, {0x3db24000}, {0x3db26000}, 
+    {0x3db28000}, {0x3db2a000}, {0x3db2c000}, {0x3db2e000}, 
+    {0x3db30000}, {0x3db32000}, {0x3db34000}, {0x3db36000}, 
+    {0x3db38000}, {0x3db3a000}, {0x3db3c000}, {0x3db3e000}, 
+    {0x3db40000}, {0x3db42000}, {0x3db44000}, {0x3db46000}, 
+    {0x3db48000}, {0x3db4a000}, {0x3db4c000}, {0x3db4e000}, 
+    {0x3db50000}, {0x3db52000}, {0x3db54000}, {0x3db56000}, 
+    {0x3db58000}, {0x3db5a000}, {0x3db5c000}, {0x3db5e000}, 
+    {0x3db60000}, {0x3db62000}, {0x3db64000}, {0x3db66000}, 
+    {0x3db68000}, {0x3db6a000}, {0x3db6c000}, {0x3db6e000}, 
+    {0x3db70000}, {0x3db72000}, {0x3db74000}, {0x3db76000}, 
+    {0x3db78000}, {0x3db7a000}, {0x3db7c000}, {0x3db7e000}, 
+    {0x3db80000}, {0x3db82000}, {0x3db84000}, {0x3db86000}, 
+    {0x3db88000}, {0x3db8a000}, {0x3db8c000}, {0x3db8e000}, 
+    {0x3db90000}, {0x3db92000}, {0x3db94000}, {0x3db96000}, 
+    {0x3db98000}, {0x3db9a000}, {0x3db9c000}, {0x3db9e000}, 
+    {0x3dba0000}, {0x3dba2000}, {0x3dba4000}, {0x3dba6000}, 
+    {0x3dba8000}, {0x3dbaa000}, {0x3dbac000}, {0x3dbae000}, 
+    {0x3dbb0000}, {0x3dbb2000}, {0x3dbb4000}, {0x3dbb6000}, 
+    {0x3dbb8000}, {0x3dbba000}, {0x3dbbc000}, {0x3dbbe000}, 
+    {0x3dbc0000}, {0x3dbc2000}, {0x3dbc4000}, {0x3dbc6000}, 
+    {0x3dbc8000}, {0x3dbca000}, {0x3dbcc000}, {0x3dbce000}, 
+    {0x3dbd0000}, {0x3dbd2000}, {0x3dbd4000}, {0x3dbd6000}, 
+    {0x3dbd8000}, {0x3dbda000}, {0x3dbdc000}, {0x3dbde000}, 
+    {0x3dbe0000}, {0x3dbe2000}, {0x3dbe4000}, {0x3dbe6000}, 
+    {0x3dbe8000}, {0x3dbea000}, {0x3dbec000}, {0x3dbee000}, 
+    {0x3dbf0000}, {0x3dbf2000}, {0x3dbf4000}, {0x3dbf6000}, 
+    {0x3dbf8000}, {0x3dbfa000}, {0x3dbfc000}, {0x3dbfe000}, 
+    {0x3dc00000}, {0x3dc02000}, {0x3dc04000}, {0x3dc06000}, 
+    {0x3dc08000}, {0x3dc0a000}, {0x3dc0c000}, {0x3dc0e000}, 
+    {0x3dc10000}, {0x3dc12000}, {0x3dc14000}, {0x3dc16000}, 
+    {0x3dc18000}, {0x3dc1a000}, {0x3dc1c000}, {0x3dc1e000}, 
+    {0x3dc20000}, {0x3dc22000}, {0x3dc24000}, {0x3dc26000}, 
+    {0x3dc28000}, {0x3dc2a000}, {0x3dc2c000}, {0x3dc2e000}, 
+    {0x3dc30000}, {0x3dc32000}, {0x3dc34000}, {0x3dc36000}, 
+    {0x3dc38000}, {0x3dc3a000}, {0x3dc3c000}, {0x3dc3e000}, 
+    {0x3dc40000}, {0x3dc42000}, {0x3dc44000}, {0x3dc46000}, 
+    {0x3dc48000}, {0x3dc4a000}, {0x3dc4c000}, {0x3dc4e000}, 
+    {0x3dc50000}, {0x3dc52000}, {0x3dc54000}, {0x3dc56000}, 
+    {0x3dc58000}, {0x3dc5a000}, {0x3dc5c000}, {0x3dc5e000}, 
+    {0x3dc60000}, {0x3dc62000}, {0x3dc64000}, {0x3dc66000}, 
+    {0x3dc68000}, {0x3dc6a000}, {0x3dc6c000}, {0x3dc6e000}, 
+    {0x3dc70000}, {0x3dc72000}, {0x3dc74000}, {0x3dc76000}, 
+    {0x3dc78000}, {0x3dc7a000}, {0x3dc7c000}, {0x3dc7e000}, 
+    {0x3dc80000}, {0x3dc82000}, {0x3dc84000}, {0x3dc86000}, 
+    {0x3dc88000}, {0x3dc8a000}, {0x3dc8c000}, {0x3dc8e000}, 
+    {0x3dc90000}, {0x3dc92000}, {0x3dc94000}, {0x3dc96000}, 
+    {0x3dc98000}, {0x3dc9a000}, {0x3dc9c000}, {0x3dc9e000}, 
+    {0x3dca0000}, {0x3dca2000}, {0x3dca4000}, {0x3dca6000}, 
+    {0x3dca8000}, {0x3dcaa000}, {0x3dcac000}, {0x3dcae000}, 
+    {0x3dcb0000}, {0x3dcb2000}, {0x3dcb4000}, {0x3dcb6000}, 
+    {0x3dcb8000}, {0x3dcba000}, {0x3dcbc000}, {0x3dcbe000}, 
+    {0x3dcc0000}, {0x3dcc2000}, {0x3dcc4000}, {0x3dcc6000}, 
+    {0x3dcc8000}, {0x3dcca000}, {0x3dccc000}, {0x3dcce000}, 
+    {0x3dcd0000}, {0x3dcd2000}, {0x3dcd4000}, {0x3dcd6000}, 
+    {0x3dcd8000}, {0x3dcda000}, {0x3dcdc000}, {0x3dcde000}, 
+    {0x3dce0000}, {0x3dce2000}, {0x3dce4000}, {0x3dce6000}, 
+    {0x3dce8000}, {0x3dcea000}, {0x3dcec000}, {0x3dcee000}, 
+    {0x3dcf0000}, {0x3dcf2000}, {0x3dcf4000}, {0x3dcf6000}, 
+    {0x3dcf8000}, {0x3dcfa000}, {0x3dcfc000}, {0x3dcfe000}, 
+    {0x3dd00000}, {0x3dd02000}, {0x3dd04000}, {0x3dd06000}, 
+    {0x3dd08000}, {0x3dd0a000}, {0x3dd0c000}, {0x3dd0e000}, 
+    {0x3dd10000}, {0x3dd12000}, {0x3dd14000}, {0x3dd16000}, 
+    {0x3dd18000}, {0x3dd1a000}, {0x3dd1c000}, {0x3dd1e000}, 
+    {0x3dd20000}, {0x3dd22000}, {0x3dd24000}, {0x3dd26000}, 
+    {0x3dd28000}, {0x3dd2a000}, {0x3dd2c000}, {0x3dd2e000}, 
+    {0x3dd30000}, {0x3dd32000}, {0x3dd34000}, {0x3dd36000}, 
+    {0x3dd38000}, {0x3dd3a000}, {0x3dd3c000}, {0x3dd3e000}, 
+    {0x3dd40000}, {0x3dd42000}, {0x3dd44000}, {0x3dd46000}, 
+    {0x3dd48000}, {0x3dd4a000}, {0x3dd4c000}, {0x3dd4e000}, 
+    {0x3dd50000}, {0x3dd52000}, {0x3dd54000}, {0x3dd56000}, 
+    {0x3dd58000}, {0x3dd5a000}, {0x3dd5c000}, {0x3dd5e000}, 
+    {0x3dd60000}, {0x3dd62000}, {0x3dd64000}, {0x3dd66000}, 
+    {0x3dd68000}, {0x3dd6a000}, {0x3dd6c000}, {0x3dd6e000}, 
+    {0x3dd70000}, {0x3dd72000}, {0x3dd74000}, {0x3dd76000}, 
+    {0x3dd78000}, {0x3dd7a000}, {0x3dd7c000}, {0x3dd7e000}, 
+    {0x3dd80000}, {0x3dd82000}, {0x3dd84000}, {0x3dd86000}, 
+    {0x3dd88000}, {0x3dd8a000}, {0x3dd8c000}, {0x3dd8e000}, 
+    {0x3dd90000}, {0x3dd92000}, {0x3dd94000}, {0x3dd96000}, 
+    {0x3dd98000}, {0x3dd9a000}, {0x3dd9c000}, {0x3dd9e000}, 
+    {0x3dda0000}, {0x3dda2000}, {0x3dda4000}, {0x3dda6000}, 
+    {0x3dda8000}, {0x3ddaa000}, {0x3ddac000}, {0x3ddae000}, 
+    {0x3ddb0000}, {0x3ddb2000}, {0x3ddb4000}, {0x3ddb6000}, 
+    {0x3ddb8000}, {0x3ddba000}, {0x3ddbc000}, {0x3ddbe000}, 
+    {0x3ddc0000}, {0x3ddc2000}, {0x3ddc4000}, {0x3ddc6000}, 
+    {0x3ddc8000}, {0x3ddca000}, {0x3ddcc000}, {0x3ddce000}, 
+    {0x3ddd0000}, {0x3ddd2000}, {0x3ddd4000}, {0x3ddd6000}, 
+    {0x3ddd8000}, {0x3ddda000}, {0x3dddc000}, {0x3ddde000}, 
+    {0x3dde0000}, {0x3dde2000}, {0x3dde4000}, {0x3dde6000}, 
+    {0x3dde8000}, {0x3ddea000}, {0x3ddec000}, {0x3ddee000}, 
+    {0x3ddf0000}, {0x3ddf2000}, {0x3ddf4000}, {0x3ddf6000}, 
+    {0x3ddf8000}, {0x3ddfa000}, {0x3ddfc000}, {0x3ddfe000}, 
+    {0x3de00000}, {0x3de02000}, {0x3de04000}, {0x3de06000}, 
+    {0x3de08000}, {0x3de0a000}, {0x3de0c000}, {0x3de0e000}, 
+    {0x3de10000}, {0x3de12000}, {0x3de14000}, {0x3de16000}, 
+    {0x3de18000}, {0x3de1a000}, {0x3de1c000}, {0x3de1e000}, 
+    {0x3de20000}, {0x3de22000}, {0x3de24000}, {0x3de26000}, 
+    {0x3de28000}, {0x3de2a000}, {0x3de2c000}, {0x3de2e000}, 
+    {0x3de30000}, {0x3de32000}, {0x3de34000}, {0x3de36000}, 
+    {0x3de38000}, {0x3de3a000}, {0x3de3c000}, {0x3de3e000}, 
+    {0x3de40000}, {0x3de42000}, {0x3de44000}, {0x3de46000}, 
+    {0x3de48000}, {0x3de4a000}, {0x3de4c000}, {0x3de4e000}, 
+    {0x3de50000}, {0x3de52000}, {0x3de54000}, {0x3de56000}, 
+    {0x3de58000}, {0x3de5a000}, {0x3de5c000}, {0x3de5e000}, 
+    {0x3de60000}, {0x3de62000}, {0x3de64000}, {0x3de66000}, 
+    {0x3de68000}, {0x3de6a000}, {0x3de6c000}, {0x3de6e000}, 
+    {0x3de70000}, {0x3de72000}, {0x3de74000}, {0x3de76000}, 
+    {0x3de78000}, {0x3de7a000}, {0x3de7c000}, {0x3de7e000}, 
+    {0x3de80000}, {0x3de82000}, {0x3de84000}, {0x3de86000}, 
+    {0x3de88000}, {0x3de8a000}, {0x3de8c000}, {0x3de8e000}, 
+    {0x3de90000}, {0x3de92000}, {0x3de94000}, {0x3de96000}, 
+    {0x3de98000}, {0x3de9a000}, {0x3de9c000}, {0x3de9e000}, 
+    {0x3dea0000}, {0x3dea2000}, {0x3dea4000}, {0x3dea6000}, 
+    {0x3dea8000}, {0x3deaa000}, {0x3deac000}, {0x3deae000}, 
+    {0x3deb0000}, {0x3deb2000}, {0x3deb4000}, {0x3deb6000}, 
+    {0x3deb8000}, {0x3deba000}, {0x3debc000}, {0x3debe000}, 
+    {0x3dec0000}, {0x3dec2000}, {0x3dec4000}, {0x3dec6000}, 
+    {0x3dec8000}, {0x3deca000}, {0x3decc000}, {0x3dece000}, 
+    {0x3ded0000}, {0x3ded2000}, {0x3ded4000}, {0x3ded6000}, 
+    {0x3ded8000}, {0x3deda000}, {0x3dedc000}, {0x3dede000}, 
+    {0x3dee0000}, {0x3dee2000}, {0x3dee4000}, {0x3dee6000}, 
+    {0x3dee8000}, {0x3deea000}, {0x3deec000}, {0x3deee000}, 
+    {0x3def0000}, {0x3def2000}, {0x3def4000}, {0x3def6000}, 
+    {0x3def8000}, {0x3defa000}, {0x3defc000}, {0x3defe000}, 
+    {0x3df00000}, {0x3df02000}, {0x3df04000}, {0x3df06000}, 
+    {0x3df08000}, {0x3df0a000}, {0x3df0c000}, {0x3df0e000}, 
+    {0x3df10000}, {0x3df12000}, {0x3df14000}, {0x3df16000}, 
+    {0x3df18000}, {0x3df1a000}, {0x3df1c000}, {0x3df1e000}, 
+    {0x3df20000}, {0x3df22000}, {0x3df24000}, {0x3df26000}, 
+    {0x3df28000}, {0x3df2a000}, {0x3df2c000}, {0x3df2e000}, 
+    {0x3df30000}, {0x3df32000}, {0x3df34000}, {0x3df36000}, 
+    {0x3df38000}, {0x3df3a000}, {0x3df3c000}, {0x3df3e000}, 
+    {0x3df40000}, {0x3df42000}, {0x3df44000}, {0x3df46000}, 
+    {0x3df48000}, {0x3df4a000}, {0x3df4c000}, {0x3df4e000}, 
+    {0x3df50000}, {0x3df52000}, {0x3df54000}, {0x3df56000}, 
+    {0x3df58000}, {0x3df5a000}, {0x3df5c000}, {0x3df5e000}, 
+    {0x3df60000}, {0x3df62000}, {0x3df64000}, {0x3df66000}, 
+    {0x3df68000}, {0x3df6a000}, {0x3df6c000}, {0x3df6e000}, 
+    {0x3df70000}, {0x3df72000}, {0x3df74000}, {0x3df76000}, 
+    {0x3df78000}, {0x3df7a000}, {0x3df7c000}, {0x3df7e000}, 
+    {0x3df80000}, {0x3df82000}, {0x3df84000}, {0x3df86000}, 
+    {0x3df88000}, {0x3df8a000}, {0x3df8c000}, {0x3df8e000}, 
+    {0x3df90000}, {0x3df92000}, {0x3df94000}, {0x3df96000}, 
+    {0x3df98000}, {0x3df9a000}, {0x3df9c000}, {0x3df9e000}, 
+    {0x3dfa0000}, {0x3dfa2000}, {0x3dfa4000}, {0x3dfa6000}, 
+    {0x3dfa8000}, {0x3dfaa000}, {0x3dfac000}, {0x3dfae000}, 
+    {0x3dfb0000}, {0x3dfb2000}, {0x3dfb4000}, {0x3dfb6000}, 
+    {0x3dfb8000}, {0x3dfba000}, {0x3dfbc000}, {0x3dfbe000}, 
+    {0x3dfc0000}, {0x3dfc2000}, {0x3dfc4000}, {0x3dfc6000}, 
+    {0x3dfc8000}, {0x3dfca000}, {0x3dfcc000}, {0x3dfce000}, 
+    {0x3dfd0000}, {0x3dfd2000}, {0x3dfd4000}, {0x3dfd6000}, 
+    {0x3dfd8000}, {0x3dfda000}, {0x3dfdc000}, {0x3dfde000}, 
+    {0x3dfe0000}, {0x3dfe2000}, {0x3dfe4000}, {0x3dfe6000}, 
+    {0x3dfe8000}, {0x3dfea000}, {0x3dfec000}, {0x3dfee000}, 
+    {0x3dff0000}, {0x3dff2000}, {0x3dff4000}, {0x3dff6000}, 
+    {0x3dff8000}, {0x3dffa000}, {0x3dffc000}, {0x3dffe000}, 
+    {0x3e000000}, {0x3e002000}, {0x3e004000}, {0x3e006000}, 
+    {0x3e008000}, {0x3e00a000}, {0x3e00c000}, {0x3e00e000}, 
+    {0x3e010000}, {0x3e012000}, {0x3e014000}, {0x3e016000}, 
+    {0x3e018000}, {0x3e01a000}, {0x3e01c000}, {0x3e01e000}, 
+    {0x3e020000}, {0x3e022000}, {0x3e024000}, {0x3e026000}, 
+    {0x3e028000}, {0x3e02a000}, {0x3e02c000}, {0x3e02e000}, 
+    {0x3e030000}, {0x3e032000}, {0x3e034000}, {0x3e036000}, 
+    {0x3e038000}, {0x3e03a000}, {0x3e03c000}, {0x3e03e000}, 
+    {0x3e040000}, {0x3e042000}, {0x3e044000}, {0x3e046000}, 
+    {0x3e048000}, {0x3e04a000}, {0x3e04c000}, {0x3e04e000}, 
+    {0x3e050000}, {0x3e052000}, {0x3e054000}, {0x3e056000}, 
+    {0x3e058000}, {0x3e05a000}, {0x3e05c000}, {0x3e05e000}, 
+    {0x3e060000}, {0x3e062000}, {0x3e064000}, {0x3e066000}, 
+    {0x3e068000}, {0x3e06a000}, {0x3e06c000}, {0x3e06e000}, 
+    {0x3e070000}, {0x3e072000}, {0x3e074000}, {0x3e076000}, 
+    {0x3e078000}, {0x3e07a000}, {0x3e07c000}, {0x3e07e000}, 
+    {0x3e080000}, {0x3e082000}, {0x3e084000}, {0x3e086000}, 
+    {0x3e088000}, {0x3e08a000}, {0x3e08c000}, {0x3e08e000}, 
+    {0x3e090000}, {0x3e092000}, {0x3e094000}, {0x3e096000}, 
+    {0x3e098000}, {0x3e09a000}, {0x3e09c000}, {0x3e09e000}, 
+    {0x3e0a0000}, {0x3e0a2000}, {0x3e0a4000}, {0x3e0a6000}, 
+    {0x3e0a8000}, {0x3e0aa000}, {0x3e0ac000}, {0x3e0ae000}, 
+    {0x3e0b0000}, {0x3e0b2000}, {0x3e0b4000}, {0x3e0b6000}, 
+    {0x3e0b8000}, {0x3e0ba000}, {0x3e0bc000}, {0x3e0be000}, 
+    {0x3e0c0000}, {0x3e0c2000}, {0x3e0c4000}, {0x3e0c6000}, 
+    {0x3e0c8000}, {0x3e0ca000}, {0x3e0cc000}, {0x3e0ce000}, 
+    {0x3e0d0000}, {0x3e0d2000}, {0x3e0d4000}, {0x3e0d6000}, 
+    {0x3e0d8000}, {0x3e0da000}, {0x3e0dc000}, {0x3e0de000}, 
+    {0x3e0e0000}, {0x3e0e2000}, {0x3e0e4000}, {0x3e0e6000}, 
+    {0x3e0e8000}, {0x3e0ea000}, {0x3e0ec000}, {0x3e0ee000}, 
+    {0x3e0f0000}, {0x3e0f2000}, {0x3e0f4000}, {0x3e0f6000}, 
+    {0x3e0f8000}, {0x3e0fa000}, {0x3e0fc000}, {0x3e0fe000}, 
+    {0x3e100000}, {0x3e102000}, {0x3e104000}, {0x3e106000}, 
+    {0x3e108000}, {0x3e10a000}, {0x3e10c000}, {0x3e10e000}, 
+    {0x3e110000}, {0x3e112000}, {0x3e114000}, {0x3e116000}, 
+    {0x3e118000}, {0x3e11a000}, {0x3e11c000}, {0x3e11e000}, 
+    {0x3e120000}, {0x3e122000}, {0x3e124000}, {0x3e126000}, 
+    {0x3e128000}, {0x3e12a000}, {0x3e12c000}, {0x3e12e000}, 
+    {0x3e130000}, {0x3e132000}, {0x3e134000}, {0x3e136000}, 
+    {0x3e138000}, {0x3e13a000}, {0x3e13c000}, {0x3e13e000}, 
+    {0x3e140000}, {0x3e142000}, {0x3e144000}, {0x3e146000}, 
+    {0x3e148000}, {0x3e14a000}, {0x3e14c000}, {0x3e14e000}, 
+    {0x3e150000}, {0x3e152000}, {0x3e154000}, {0x3e156000}, 
+    {0x3e158000}, {0x3e15a000}, {0x3e15c000}, {0x3e15e000}, 
+    {0x3e160000}, {0x3e162000}, {0x3e164000}, {0x3e166000}, 
+    {0x3e168000}, {0x3e16a000}, {0x3e16c000}, {0x3e16e000}, 
+    {0x3e170000}, {0x3e172000}, {0x3e174000}, {0x3e176000}, 
+    {0x3e178000}, {0x3e17a000}, {0x3e17c000}, {0x3e17e000}, 
+    {0x3e180000}, {0x3e182000}, {0x3e184000}, {0x3e186000}, 
+    {0x3e188000}, {0x3e18a000}, {0x3e18c000}, {0x3e18e000}, 
+    {0x3e190000}, {0x3e192000}, {0x3e194000}, {0x3e196000}, 
+    {0x3e198000}, {0x3e19a000}, {0x3e19c000}, {0x3e19e000}, 
+    {0x3e1a0000}, {0x3e1a2000}, {0x3e1a4000}, {0x3e1a6000}, 
+    {0x3e1a8000}, {0x3e1aa000}, {0x3e1ac000}, {0x3e1ae000}, 
+    {0x3e1b0000}, {0x3e1b2000}, {0x3e1b4000}, {0x3e1b6000}, 
+    {0x3e1b8000}, {0x3e1ba000}, {0x3e1bc000}, {0x3e1be000}, 
+    {0x3e1c0000}, {0x3e1c2000}, {0x3e1c4000}, {0x3e1c6000}, 
+    {0x3e1c8000}, {0x3e1ca000}, {0x3e1cc000}, {0x3e1ce000}, 
+    {0x3e1d0000}, {0x3e1d2000}, {0x3e1d4000}, {0x3e1d6000}, 
+    {0x3e1d8000}, {0x3e1da000}, {0x3e1dc000}, {0x3e1de000}, 
+    {0x3e1e0000}, {0x3e1e2000}, {0x3e1e4000}, {0x3e1e6000}, 
+    {0x3e1e8000}, {0x3e1ea000}, {0x3e1ec000}, {0x3e1ee000}, 
+    {0x3e1f0000}, {0x3e1f2000}, {0x3e1f4000}, {0x3e1f6000}, 
+    {0x3e1f8000}, {0x3e1fa000}, {0x3e1fc000}, {0x3e1fe000}, 
+    {0x3e200000}, {0x3e202000}, {0x3e204000}, {0x3e206000}, 
+    {0x3e208000}, {0x3e20a000}, {0x3e20c000}, {0x3e20e000}, 
+    {0x3e210000}, {0x3e212000}, {0x3e214000}, {0x3e216000}, 
+    {0x3e218000}, {0x3e21a000}, {0x3e21c000}, {0x3e21e000}, 
+    {0x3e220000}, {0x3e222000}, {0x3e224000}, {0x3e226000}, 
+    {0x3e228000}, {0x3e22a000}, {0x3e22c000}, {0x3e22e000}, 
+    {0x3e230000}, {0x3e232000}, {0x3e234000}, {0x3e236000}, 
+    {0x3e238000}, {0x3e23a000}, {0x3e23c000}, {0x3e23e000}, 
+    {0x3e240000}, {0x3e242000}, {0x3e244000}, {0x3e246000}, 
+    {0x3e248000}, {0x3e24a000}, {0x3e24c000}, {0x3e24e000}, 
+    {0x3e250000}, {0x3e252000}, {0x3e254000}, {0x3e256000}, 
+    {0x3e258000}, {0x3e25a000}, {0x3e25c000}, {0x3e25e000}, 
+    {0x3e260000}, {0x3e262000}, {0x3e264000}, {0x3e266000}, 
+    {0x3e268000}, {0x3e26a000}, {0x3e26c000}, {0x3e26e000}, 
+    {0x3e270000}, {0x3e272000}, {0x3e274000}, {0x3e276000}, 
+    {0x3e278000}, {0x3e27a000}, {0x3e27c000}, {0x3e27e000}, 
+    {0x3e280000}, {0x3e282000}, {0x3e284000}, {0x3e286000}, 
+    {0x3e288000}, {0x3e28a000}, {0x3e28c000}, {0x3e28e000}, 
+    {0x3e290000}, {0x3e292000}, {0x3e294000}, {0x3e296000}, 
+    {0x3e298000}, {0x3e29a000}, {0x3e29c000}, {0x3e29e000}, 
+    {0x3e2a0000}, {0x3e2a2000}, {0x3e2a4000}, {0x3e2a6000}, 
+    {0x3e2a8000}, {0x3e2aa000}, {0x3e2ac000}, {0x3e2ae000}, 
+    {0x3e2b0000}, {0x3e2b2000}, {0x3e2b4000}, {0x3e2b6000}, 
+    {0x3e2b8000}, {0x3e2ba000}, {0x3e2bc000}, {0x3e2be000}, 
+    {0x3e2c0000}, {0x3e2c2000}, {0x3e2c4000}, {0x3e2c6000}, 
+    {0x3e2c8000}, {0x3e2ca000}, {0x3e2cc000}, {0x3e2ce000}, 
+    {0x3e2d0000}, {0x3e2d2000}, {0x3e2d4000}, {0x3e2d6000}, 
+    {0x3e2d8000}, {0x3e2da000}, {0x3e2dc000}, {0x3e2de000}, 
+    {0x3e2e0000}, {0x3e2e2000}, {0x3e2e4000}, {0x3e2e6000}, 
+    {0x3e2e8000}, {0x3e2ea000}, {0x3e2ec000}, {0x3e2ee000}, 
+    {0x3e2f0000}, {0x3e2f2000}, {0x3e2f4000}, {0x3e2f6000}, 
+    {0x3e2f8000}, {0x3e2fa000}, {0x3e2fc000}, {0x3e2fe000}, 
+    {0x3e300000}, {0x3e302000}, {0x3e304000}, {0x3e306000}, 
+    {0x3e308000}, {0x3e30a000}, {0x3e30c000}, {0x3e30e000}, 
+    {0x3e310000}, {0x3e312000}, {0x3e314000}, {0x3e316000}, 
+    {0x3e318000}, {0x3e31a000}, {0x3e31c000}, {0x3e31e000}, 
+    {0x3e320000}, {0x3e322000}, {0x3e324000}, {0x3e326000}, 
+    {0x3e328000}, {0x3e32a000}, {0x3e32c000}, {0x3e32e000}, 
+    {0x3e330000}, {0x3e332000}, {0x3e334000}, {0x3e336000}, 
+    {0x3e338000}, {0x3e33a000}, {0x3e33c000}, {0x3e33e000}, 
+    {0x3e340000}, {0x3e342000}, {0x3e344000}, {0x3e346000}, 
+    {0x3e348000}, {0x3e34a000}, {0x3e34c000}, {0x3e34e000}, 
+    {0x3e350000}, {0x3e352000}, {0x3e354000}, {0x3e356000}, 
+    {0x3e358000}, {0x3e35a000}, {0x3e35c000}, {0x3e35e000}, 
+    {0x3e360000}, {0x3e362000}, {0x3e364000}, {0x3e366000}, 
+    {0x3e368000}, {0x3e36a000}, {0x3e36c000}, {0x3e36e000}, 
+    {0x3e370000}, {0x3e372000}, {0x3e374000}, {0x3e376000}, 
+    {0x3e378000}, {0x3e37a000}, {0x3e37c000}, {0x3e37e000}, 
+    {0x3e380000}, {0x3e382000}, {0x3e384000}, {0x3e386000}, 
+    {0x3e388000}, {0x3e38a000}, {0x3e38c000}, {0x3e38e000}, 
+    {0x3e390000}, {0x3e392000}, {0x3e394000}, {0x3e396000}, 
+    {0x3e398000}, {0x3e39a000}, {0x3e39c000}, {0x3e39e000}, 
+    {0x3e3a0000}, {0x3e3a2000}, {0x3e3a4000}, {0x3e3a6000}, 
+    {0x3e3a8000}, {0x3e3aa000}, {0x3e3ac000}, {0x3e3ae000}, 
+    {0x3e3b0000}, {0x3e3b2000}, {0x3e3b4000}, {0x3e3b6000}, 
+    {0x3e3b8000}, {0x3e3ba000}, {0x3e3bc000}, {0x3e3be000}, 
+    {0x3e3c0000}, {0x3e3c2000}, {0x3e3c4000}, {0x3e3c6000}, 
+    {0x3e3c8000}, {0x3e3ca000}, {0x3e3cc000}, {0x3e3ce000}, 
+    {0x3e3d0000}, {0x3e3d2000}, {0x3e3d4000}, {0x3e3d6000}, 
+    {0x3e3d8000}, {0x3e3da000}, {0x3e3dc000}, {0x3e3de000}, 
+    {0x3e3e0000}, {0x3e3e2000}, {0x3e3e4000}, {0x3e3e6000}, 
+    {0x3e3e8000}, {0x3e3ea000}, {0x3e3ec000}, {0x3e3ee000}, 
+    {0x3e3f0000}, {0x3e3f2000}, {0x3e3f4000}, {0x3e3f6000}, 
+    {0x3e3f8000}, {0x3e3fa000}, {0x3e3fc000}, {0x3e3fe000}, 
+    {0x3e400000}, {0x3e402000}, {0x3e404000}, {0x3e406000}, 
+    {0x3e408000}, {0x3e40a000}, {0x3e40c000}, {0x3e40e000}, 
+    {0x3e410000}, {0x3e412000}, {0x3e414000}, {0x3e416000}, 
+    {0x3e418000}, {0x3e41a000}, {0x3e41c000}, {0x3e41e000}, 
+    {0x3e420000}, {0x3e422000}, {0x3e424000}, {0x3e426000}, 
+    {0x3e428000}, {0x3e42a000}, {0x3e42c000}, {0x3e42e000}, 
+    {0x3e430000}, {0x3e432000}, {0x3e434000}, {0x3e436000}, 
+    {0x3e438000}, {0x3e43a000}, {0x3e43c000}, {0x3e43e000}, 
+    {0x3e440000}, {0x3e442000}, {0x3e444000}, {0x3e446000}, 
+    {0x3e448000}, {0x3e44a000}, {0x3e44c000}, {0x3e44e000}, 
+    {0x3e450000}, {0x3e452000}, {0x3e454000}, {0x3e456000}, 
+    {0x3e458000}, {0x3e45a000}, {0x3e45c000}, {0x3e45e000}, 
+    {0x3e460000}, {0x3e462000}, {0x3e464000}, {0x3e466000}, 
+    {0x3e468000}, {0x3e46a000}, {0x3e46c000}, {0x3e46e000}, 
+    {0x3e470000}, {0x3e472000}, {0x3e474000}, {0x3e476000}, 
+    {0x3e478000}, {0x3e47a000}, {0x3e47c000}, {0x3e47e000}, 
+    {0x3e480000}, {0x3e482000}, {0x3e484000}, {0x3e486000}, 
+    {0x3e488000}, {0x3e48a000}, {0x3e48c000}, {0x3e48e000}, 
+    {0x3e490000}, {0x3e492000}, {0x3e494000}, {0x3e496000}, 
+    {0x3e498000}, {0x3e49a000}, {0x3e49c000}, {0x3e49e000}, 
+    {0x3e4a0000}, {0x3e4a2000}, {0x3e4a4000}, {0x3e4a6000}, 
+    {0x3e4a8000}, {0x3e4aa000}, {0x3e4ac000}, {0x3e4ae000}, 
+    {0x3e4b0000}, {0x3e4b2000}, {0x3e4b4000}, {0x3e4b6000}, 
+    {0x3e4b8000}, {0x3e4ba000}, {0x3e4bc000}, {0x3e4be000}, 
+    {0x3e4c0000}, {0x3e4c2000}, {0x3e4c4000}, {0x3e4c6000}, 
+    {0x3e4c8000}, {0x3e4ca000}, {0x3e4cc000}, {0x3e4ce000}, 
+    {0x3e4d0000}, {0x3e4d2000}, {0x3e4d4000}, {0x3e4d6000}, 
+    {0x3e4d8000}, {0x3e4da000}, {0x3e4dc000}, {0x3e4de000}, 
+    {0x3e4e0000}, {0x3e4e2000}, {0x3e4e4000}, {0x3e4e6000}, 
+    {0x3e4e8000}, {0x3e4ea000}, {0x3e4ec000}, {0x3e4ee000}, 
+    {0x3e4f0000}, {0x3e4f2000}, {0x3e4f4000}, {0x3e4f6000}, 
+    {0x3e4f8000}, {0x3e4fa000}, {0x3e4fc000}, {0x3e4fe000}, 
+    {0x3e500000}, {0x3e502000}, {0x3e504000}, {0x3e506000}, 
+    {0x3e508000}, {0x3e50a000}, {0x3e50c000}, {0x3e50e000}, 
+    {0x3e510000}, {0x3e512000}, {0x3e514000}, {0x3e516000}, 
+    {0x3e518000}, {0x3e51a000}, {0x3e51c000}, {0x3e51e000}, 
+    {0x3e520000}, {0x3e522000}, {0x3e524000}, {0x3e526000}, 
+    {0x3e528000}, {0x3e52a000}, {0x3e52c000}, {0x3e52e000}, 
+    {0x3e530000}, {0x3e532000}, {0x3e534000}, {0x3e536000}, 
+    {0x3e538000}, {0x3e53a000}, {0x3e53c000}, {0x3e53e000}, 
+    {0x3e540000}, {0x3e542000}, {0x3e544000}, {0x3e546000}, 
+    {0x3e548000}, {0x3e54a000}, {0x3e54c000}, {0x3e54e000}, 
+    {0x3e550000}, {0x3e552000}, {0x3e554000}, {0x3e556000}, 
+    {0x3e558000}, {0x3e55a000}, {0x3e55c000}, {0x3e55e000}, 
+    {0x3e560000}, {0x3e562000}, {0x3e564000}, {0x3e566000}, 
+    {0x3e568000}, {0x3e56a000}, {0x3e56c000}, {0x3e56e000}, 
+    {0x3e570000}, {0x3e572000}, {0x3e574000}, {0x3e576000}, 
+    {0x3e578000}, {0x3e57a000}, {0x3e57c000}, {0x3e57e000}, 
+    {0x3e580000}, {0x3e582000}, {0x3e584000}, {0x3e586000}, 
+    {0x3e588000}, {0x3e58a000}, {0x3e58c000}, {0x3e58e000}, 
+    {0x3e590000}, {0x3e592000}, {0x3e594000}, {0x3e596000}, 
+    {0x3e598000}, {0x3e59a000}, {0x3e59c000}, {0x3e59e000}, 
+    {0x3e5a0000}, {0x3e5a2000}, {0x3e5a4000}, {0x3e5a6000}, 
+    {0x3e5a8000}, {0x3e5aa000}, {0x3e5ac000}, {0x3e5ae000}, 
+    {0x3e5b0000}, {0x3e5b2000}, {0x3e5b4000}, {0x3e5b6000}, 
+    {0x3e5b8000}, {0x3e5ba000}, {0x3e5bc000}, {0x3e5be000}, 
+    {0x3e5c0000}, {0x3e5c2000}, {0x3e5c4000}, {0x3e5c6000}, 
+    {0x3e5c8000}, {0x3e5ca000}, {0x3e5cc000}, {0x3e5ce000}, 
+    {0x3e5d0000}, {0x3e5d2000}, {0x3e5d4000}, {0x3e5d6000}, 
+    {0x3e5d8000}, {0x3e5da000}, {0x3e5dc000}, {0x3e5de000}, 
+    {0x3e5e0000}, {0x3e5e2000}, {0x3e5e4000}, {0x3e5e6000}, 
+    {0x3e5e8000}, {0x3e5ea000}, {0x3e5ec000}, {0x3e5ee000}, 
+    {0x3e5f0000}, {0x3e5f2000}, {0x3e5f4000}, {0x3e5f6000}, 
+    {0x3e5f8000}, {0x3e5fa000}, {0x3e5fc000}, {0x3e5fe000}, 
+    {0x3e600000}, {0x3e602000}, {0x3e604000}, {0x3e606000}, 
+    {0x3e608000}, {0x3e60a000}, {0x3e60c000}, {0x3e60e000}, 
+    {0x3e610000}, {0x3e612000}, {0x3e614000}, {0x3e616000}, 
+    {0x3e618000}, {0x3e61a000}, {0x3e61c000}, {0x3e61e000}, 
+    {0x3e620000}, {0x3e622000}, {0x3e624000}, {0x3e626000}, 
+    {0x3e628000}, {0x3e62a000}, {0x3e62c000}, {0x3e62e000}, 
+    {0x3e630000}, {0x3e632000}, {0x3e634000}, {0x3e636000}, 
+    {0x3e638000}, {0x3e63a000}, {0x3e63c000}, {0x3e63e000}, 
+    {0x3e640000}, {0x3e642000}, {0x3e644000}, {0x3e646000}, 
+    {0x3e648000}, {0x3e64a000}, {0x3e64c000}, {0x3e64e000}, 
+    {0x3e650000}, {0x3e652000}, {0x3e654000}, {0x3e656000}, 
+    {0x3e658000}, {0x3e65a000}, {0x3e65c000}, {0x3e65e000}, 
+    {0x3e660000}, {0x3e662000}, {0x3e664000}, {0x3e666000}, 
+    {0x3e668000}, {0x3e66a000}, {0x3e66c000}, {0x3e66e000}, 
+    {0x3e670000}, {0x3e672000}, {0x3e674000}, {0x3e676000}, 
+    {0x3e678000}, {0x3e67a000}, {0x3e67c000}, {0x3e67e000}, 
+    {0x3e680000}, {0x3e682000}, {0x3e684000}, {0x3e686000}, 
+    {0x3e688000}, {0x3e68a000}, {0x3e68c000}, {0x3e68e000}, 
+    {0x3e690000}, {0x3e692000}, {0x3e694000}, {0x3e696000}, 
+    {0x3e698000}, {0x3e69a000}, {0x3e69c000}, {0x3e69e000}, 
+    {0x3e6a0000}, {0x3e6a2000}, {0x3e6a4000}, {0x3e6a6000}, 
+    {0x3e6a8000}, {0x3e6aa000}, {0x3e6ac000}, {0x3e6ae000}, 
+    {0x3e6b0000}, {0x3e6b2000}, {0x3e6b4000}, {0x3e6b6000}, 
+    {0x3e6b8000}, {0x3e6ba000}, {0x3e6bc000}, {0x3e6be000}, 
+    {0x3e6c0000}, {0x3e6c2000}, {0x3e6c4000}, {0x3e6c6000}, 
+    {0x3e6c8000}, {0x3e6ca000}, {0x3e6cc000}, {0x3e6ce000}, 
+    {0x3e6d0000}, {0x3e6d2000}, {0x3e6d4000}, {0x3e6d6000}, 
+    {0x3e6d8000}, {0x3e6da000}, {0x3e6dc000}, {0x3e6de000}, 
+    {0x3e6e0000}, {0x3e6e2000}, {0x3e6e4000}, {0x3e6e6000}, 
+    {0x3e6e8000}, {0x3e6ea000}, {0x3e6ec000}, {0x3e6ee000}, 
+    {0x3e6f0000}, {0x3e6f2000}, {0x3e6f4000}, {0x3e6f6000}, 
+    {0x3e6f8000}, {0x3e6fa000}, {0x3e6fc000}, {0x3e6fe000}, 
+    {0x3e700000}, {0x3e702000}, {0x3e704000}, {0x3e706000}, 
+    {0x3e708000}, {0x3e70a000}, {0x3e70c000}, {0x3e70e000}, 
+    {0x3e710000}, {0x3e712000}, {0x3e714000}, {0x3e716000}, 
+    {0x3e718000}, {0x3e71a000}, {0x3e71c000}, {0x3e71e000}, 
+    {0x3e720000}, {0x3e722000}, {0x3e724000}, {0x3e726000}, 
+    {0x3e728000}, {0x3e72a000}, {0x3e72c000}, {0x3e72e000}, 
+    {0x3e730000}, {0x3e732000}, {0x3e734000}, {0x3e736000}, 
+    {0x3e738000}, {0x3e73a000}, {0x3e73c000}, {0x3e73e000}, 
+    {0x3e740000}, {0x3e742000}, {0x3e744000}, {0x3e746000}, 
+    {0x3e748000}, {0x3e74a000}, {0x3e74c000}, {0x3e74e000}, 
+    {0x3e750000}, {0x3e752000}, {0x3e754000}, {0x3e756000}, 
+    {0x3e758000}, {0x3e75a000}, {0x3e75c000}, {0x3e75e000}, 
+    {0x3e760000}, {0x3e762000}, {0x3e764000}, {0x3e766000}, 
+    {0x3e768000}, {0x3e76a000}, {0x3e76c000}, {0x3e76e000}, 
+    {0x3e770000}, {0x3e772000}, {0x3e774000}, {0x3e776000}, 
+    {0x3e778000}, {0x3e77a000}, {0x3e77c000}, {0x3e77e000}, 
+    {0x3e780000}, {0x3e782000}, {0x3e784000}, {0x3e786000}, 
+    {0x3e788000}, {0x3e78a000}, {0x3e78c000}, {0x3e78e000}, 
+    {0x3e790000}, {0x3e792000}, {0x3e794000}, {0x3e796000}, 
+    {0x3e798000}, {0x3e79a000}, {0x3e79c000}, {0x3e79e000}, 
+    {0x3e7a0000}, {0x3e7a2000}, {0x3e7a4000}, {0x3e7a6000}, 
+    {0x3e7a8000}, {0x3e7aa000}, {0x3e7ac000}, {0x3e7ae000}, 
+    {0x3e7b0000}, {0x3e7b2000}, {0x3e7b4000}, {0x3e7b6000}, 
+    {0x3e7b8000}, {0x3e7ba000}, {0x3e7bc000}, {0x3e7be000}, 
+    {0x3e7c0000}, {0x3e7c2000}, {0x3e7c4000}, {0x3e7c6000}, 
+    {0x3e7c8000}, {0x3e7ca000}, {0x3e7cc000}, {0x3e7ce000}, 
+    {0x3e7d0000}, {0x3e7d2000}, {0x3e7d4000}, {0x3e7d6000}, 
+    {0x3e7d8000}, {0x3e7da000}, {0x3e7dc000}, {0x3e7de000}, 
+    {0x3e7e0000}, {0x3e7e2000}, {0x3e7e4000}, {0x3e7e6000}, 
+    {0x3e7e8000}, {0x3e7ea000}, {0x3e7ec000}, {0x3e7ee000}, 
+    {0x3e7f0000}, {0x3e7f2000}, {0x3e7f4000}, {0x3e7f6000}, 
+    {0x3e7f8000}, {0x3e7fa000}, {0x3e7fc000}, {0x3e7fe000}, 
+    {0x3e800000}, {0x3e802000}, {0x3e804000}, {0x3e806000}, 
+    {0x3e808000}, {0x3e80a000}, {0x3e80c000}, {0x3e80e000}, 
+    {0x3e810000}, {0x3e812000}, {0x3e814000}, {0x3e816000}, 
+    {0x3e818000}, {0x3e81a000}, {0x3e81c000}, {0x3e81e000}, 
+    {0x3e820000}, {0x3e822000}, {0x3e824000}, {0x3e826000}, 
+    {0x3e828000}, {0x3e82a000}, {0x3e82c000}, {0x3e82e000}, 
+    {0x3e830000}, {0x3e832000}, {0x3e834000}, {0x3e836000}, 
+    {0x3e838000}, {0x3e83a000}, {0x3e83c000}, {0x3e83e000}, 
+    {0x3e840000}, {0x3e842000}, {0x3e844000}, {0x3e846000}, 
+    {0x3e848000}, {0x3e84a000}, {0x3e84c000}, {0x3e84e000}, 
+    {0x3e850000}, {0x3e852000}, {0x3e854000}, {0x3e856000}, 
+    {0x3e858000}, {0x3e85a000}, {0x3e85c000}, {0x3e85e000}, 
+    {0x3e860000}, {0x3e862000}, {0x3e864000}, {0x3e866000}, 
+    {0x3e868000}, {0x3e86a000}, {0x3e86c000}, {0x3e86e000}, 
+    {0x3e870000}, {0x3e872000}, {0x3e874000}, {0x3e876000}, 
+    {0x3e878000}, {0x3e87a000}, {0x3e87c000}, {0x3e87e000}, 
+    {0x3e880000}, {0x3e882000}, {0x3e884000}, {0x3e886000}, 
+    {0x3e888000}, {0x3e88a000}, {0x3e88c000}, {0x3e88e000}, 
+    {0x3e890000}, {0x3e892000}, {0x3e894000}, {0x3e896000}, 
+    {0x3e898000}, {0x3e89a000}, {0x3e89c000}, {0x3e89e000}, 
+    {0x3e8a0000}, {0x3e8a2000}, {0x3e8a4000}, {0x3e8a6000}, 
+    {0x3e8a8000}, {0x3e8aa000}, {0x3e8ac000}, {0x3e8ae000}, 
+    {0x3e8b0000}, {0x3e8b2000}, {0x3e8b4000}, {0x3e8b6000}, 
+    {0x3e8b8000}, {0x3e8ba000}, {0x3e8bc000}, {0x3e8be000}, 
+    {0x3e8c0000}, {0x3e8c2000}, {0x3e8c4000}, {0x3e8c6000}, 
+    {0x3e8c8000}, {0x3e8ca000}, {0x3e8cc000}, {0x3e8ce000}, 
+    {0x3e8d0000}, {0x3e8d2000}, {0x3e8d4000}, {0x3e8d6000}, 
+    {0x3e8d8000}, {0x3e8da000}, {0x3e8dc000}, {0x3e8de000}, 
+    {0x3e8e0000}, {0x3e8e2000}, {0x3e8e4000}, {0x3e8e6000}, 
+    {0x3e8e8000}, {0x3e8ea000}, {0x3e8ec000}, {0x3e8ee000}, 
+    {0x3e8f0000}, {0x3e8f2000}, {0x3e8f4000}, {0x3e8f6000}, 
+    {0x3e8f8000}, {0x3e8fa000}, {0x3e8fc000}, {0x3e8fe000}, 
+    {0x3e900000}, {0x3e902000}, {0x3e904000}, {0x3e906000}, 
+    {0x3e908000}, {0x3e90a000}, {0x3e90c000}, {0x3e90e000}, 
+    {0x3e910000}, {0x3e912000}, {0x3e914000}, {0x3e916000}, 
+    {0x3e918000}, {0x3e91a000}, {0x3e91c000}, {0x3e91e000}, 
+    {0x3e920000}, {0x3e922000}, {0x3e924000}, {0x3e926000}, 
+    {0x3e928000}, {0x3e92a000}, {0x3e92c000}, {0x3e92e000}, 
+    {0x3e930000}, {0x3e932000}, {0x3e934000}, {0x3e936000}, 
+    {0x3e938000}, {0x3e93a000}, {0x3e93c000}, {0x3e93e000}, 
+    {0x3e940000}, {0x3e942000}, {0x3e944000}, {0x3e946000}, 
+    {0x3e948000}, {0x3e94a000}, {0x3e94c000}, {0x3e94e000}, 
+    {0x3e950000}, {0x3e952000}, {0x3e954000}, {0x3e956000}, 
+    {0x3e958000}, {0x3e95a000}, {0x3e95c000}, {0x3e95e000}, 
+    {0x3e960000}, {0x3e962000}, {0x3e964000}, {0x3e966000}, 
+    {0x3e968000}, {0x3e96a000}, {0x3e96c000}, {0x3e96e000}, 
+    {0x3e970000}, {0x3e972000}, {0x3e974000}, {0x3e976000}, 
+    {0x3e978000}, {0x3e97a000}, {0x3e97c000}, {0x3e97e000}, 
+    {0x3e980000}, {0x3e982000}, {0x3e984000}, {0x3e986000}, 
+    {0x3e988000}, {0x3e98a000}, {0x3e98c000}, {0x3e98e000}, 
+    {0x3e990000}, {0x3e992000}, {0x3e994000}, {0x3e996000}, 
+    {0x3e998000}, {0x3e99a000}, {0x3e99c000}, {0x3e99e000}, 
+    {0x3e9a0000}, {0x3e9a2000}, {0x3e9a4000}, {0x3e9a6000}, 
+    {0x3e9a8000}, {0x3e9aa000}, {0x3e9ac000}, {0x3e9ae000}, 
+    {0x3e9b0000}, {0x3e9b2000}, {0x3e9b4000}, {0x3e9b6000}, 
+    {0x3e9b8000}, {0x3e9ba000}, {0x3e9bc000}, {0x3e9be000}, 
+    {0x3e9c0000}, {0x3e9c2000}, {0x3e9c4000}, {0x3e9c6000}, 
+    {0x3e9c8000}, {0x3e9ca000}, {0x3e9cc000}, {0x3e9ce000}, 
+    {0x3e9d0000}, {0x3e9d2000}, {0x3e9d4000}, {0x3e9d6000}, 
+    {0x3e9d8000}, {0x3e9da000}, {0x3e9dc000}, {0x3e9de000}, 
+    {0x3e9e0000}, {0x3e9e2000}, {0x3e9e4000}, {0x3e9e6000}, 
+    {0x3e9e8000}, {0x3e9ea000}, {0x3e9ec000}, {0x3e9ee000}, 
+    {0x3e9f0000}, {0x3e9f2000}, {0x3e9f4000}, {0x3e9f6000}, 
+    {0x3e9f8000}, {0x3e9fa000}, {0x3e9fc000}, {0x3e9fe000}, 
+    {0x3ea00000}, {0x3ea02000}, {0x3ea04000}, {0x3ea06000}, 
+    {0x3ea08000}, {0x3ea0a000}, {0x3ea0c000}, {0x3ea0e000}, 
+    {0x3ea10000}, {0x3ea12000}, {0x3ea14000}, {0x3ea16000}, 
+    {0x3ea18000}, {0x3ea1a000}, {0x3ea1c000}, {0x3ea1e000}, 
+    {0x3ea20000}, {0x3ea22000}, {0x3ea24000}, {0x3ea26000}, 
+    {0x3ea28000}, {0x3ea2a000}, {0x3ea2c000}, {0x3ea2e000}, 
+    {0x3ea30000}, {0x3ea32000}, {0x3ea34000}, {0x3ea36000}, 
+    {0x3ea38000}, {0x3ea3a000}, {0x3ea3c000}, {0x3ea3e000}, 
+    {0x3ea40000}, {0x3ea42000}, {0x3ea44000}, {0x3ea46000}, 
+    {0x3ea48000}, {0x3ea4a000}, {0x3ea4c000}, {0x3ea4e000}, 
+    {0x3ea50000}, {0x3ea52000}, {0x3ea54000}, {0x3ea56000}, 
+    {0x3ea58000}, {0x3ea5a000}, {0x3ea5c000}, {0x3ea5e000}, 
+    {0x3ea60000}, {0x3ea62000}, {0x3ea64000}, {0x3ea66000}, 
+    {0x3ea68000}, {0x3ea6a000}, {0x3ea6c000}, {0x3ea6e000}, 
+    {0x3ea70000}, {0x3ea72000}, {0x3ea74000}, {0x3ea76000}, 
+    {0x3ea78000}, {0x3ea7a000}, {0x3ea7c000}, {0x3ea7e000}, 
+    {0x3ea80000}, {0x3ea82000}, {0x3ea84000}, {0x3ea86000}, 
+    {0x3ea88000}, {0x3ea8a000}, {0x3ea8c000}, {0x3ea8e000}, 
+    {0x3ea90000}, {0x3ea92000}, {0x3ea94000}, {0x3ea96000}, 
+    {0x3ea98000}, {0x3ea9a000}, {0x3ea9c000}, {0x3ea9e000}, 
+    {0x3eaa0000}, {0x3eaa2000}, {0x3eaa4000}, {0x3eaa6000}, 
+    {0x3eaa8000}, {0x3eaaa000}, {0x3eaac000}, {0x3eaae000}, 
+    {0x3eab0000}, {0x3eab2000}, {0x3eab4000}, {0x3eab6000}, 
+    {0x3eab8000}, {0x3eaba000}, {0x3eabc000}, {0x3eabe000}, 
+    {0x3eac0000}, {0x3eac2000}, {0x3eac4000}, {0x3eac6000}, 
+    {0x3eac8000}, {0x3eaca000}, {0x3eacc000}, {0x3eace000}, 
+    {0x3ead0000}, {0x3ead2000}, {0x3ead4000}, {0x3ead6000}, 
+    {0x3ead8000}, {0x3eada000}, {0x3eadc000}, {0x3eade000}, 
+    {0x3eae0000}, {0x3eae2000}, {0x3eae4000}, {0x3eae6000}, 
+    {0x3eae8000}, {0x3eaea000}, {0x3eaec000}, {0x3eaee000}, 
+    {0x3eaf0000}, {0x3eaf2000}, {0x3eaf4000}, {0x3eaf6000}, 
+    {0x3eaf8000}, {0x3eafa000}, {0x3eafc000}, {0x3eafe000}, 
+    {0x3eb00000}, {0x3eb02000}, {0x3eb04000}, {0x3eb06000}, 
+    {0x3eb08000}, {0x3eb0a000}, {0x3eb0c000}, {0x3eb0e000}, 
+    {0x3eb10000}, {0x3eb12000}, {0x3eb14000}, {0x3eb16000}, 
+    {0x3eb18000}, {0x3eb1a000}, {0x3eb1c000}, {0x3eb1e000}, 
+    {0x3eb20000}, {0x3eb22000}, {0x3eb24000}, {0x3eb26000}, 
+    {0x3eb28000}, {0x3eb2a000}, {0x3eb2c000}, {0x3eb2e000}, 
+    {0x3eb30000}, {0x3eb32000}, {0x3eb34000}, {0x3eb36000}, 
+    {0x3eb38000}, {0x3eb3a000}, {0x3eb3c000}, {0x3eb3e000}, 
+    {0x3eb40000}, {0x3eb42000}, {0x3eb44000}, {0x3eb46000}, 
+    {0x3eb48000}, {0x3eb4a000}, {0x3eb4c000}, {0x3eb4e000}, 
+    {0x3eb50000}, {0x3eb52000}, {0x3eb54000}, {0x3eb56000}, 
+    {0x3eb58000}, {0x3eb5a000}, {0x3eb5c000}, {0x3eb5e000}, 
+    {0x3eb60000}, {0x3eb62000}, {0x3eb64000}, {0x3eb66000}, 
+    {0x3eb68000}, {0x3eb6a000}, {0x3eb6c000}, {0x3eb6e000}, 
+    {0x3eb70000}, {0x3eb72000}, {0x3eb74000}, {0x3eb76000}, 
+    {0x3eb78000}, {0x3eb7a000}, {0x3eb7c000}, {0x3eb7e000}, 
+    {0x3eb80000}, {0x3eb82000}, {0x3eb84000}, {0x3eb86000}, 
+    {0x3eb88000}, {0x3eb8a000}, {0x3eb8c000}, {0x3eb8e000}, 
+    {0x3eb90000}, {0x3eb92000}, {0x3eb94000}, {0x3eb96000}, 
+    {0x3eb98000}, {0x3eb9a000}, {0x3eb9c000}, {0x3eb9e000}, 
+    {0x3eba0000}, {0x3eba2000}, {0x3eba4000}, {0x3eba6000}, 
+    {0x3eba8000}, {0x3ebaa000}, {0x3ebac000}, {0x3ebae000}, 
+    {0x3ebb0000}, {0x3ebb2000}, {0x3ebb4000}, {0x3ebb6000}, 
+    {0x3ebb8000}, {0x3ebba000}, {0x3ebbc000}, {0x3ebbe000}, 
+    {0x3ebc0000}, {0x3ebc2000}, {0x3ebc4000}, {0x3ebc6000}, 
+    {0x3ebc8000}, {0x3ebca000}, {0x3ebcc000}, {0x3ebce000}, 
+    {0x3ebd0000}, {0x3ebd2000}, {0x3ebd4000}, {0x3ebd6000}, 
+    {0x3ebd8000}, {0x3ebda000}, {0x3ebdc000}, {0x3ebde000}, 
+    {0x3ebe0000}, {0x3ebe2000}, {0x3ebe4000}, {0x3ebe6000}, 
+    {0x3ebe8000}, {0x3ebea000}, {0x3ebec000}, {0x3ebee000}, 
+    {0x3ebf0000}, {0x3ebf2000}, {0x3ebf4000}, {0x3ebf6000}, 
+    {0x3ebf8000}, {0x3ebfa000}, {0x3ebfc000}, {0x3ebfe000}, 
+    {0x3ec00000}, {0x3ec02000}, {0x3ec04000}, {0x3ec06000}, 
+    {0x3ec08000}, {0x3ec0a000}, {0x3ec0c000}, {0x3ec0e000}, 
+    {0x3ec10000}, {0x3ec12000}, {0x3ec14000}, {0x3ec16000}, 
+    {0x3ec18000}, {0x3ec1a000}, {0x3ec1c000}, {0x3ec1e000}, 
+    {0x3ec20000}, {0x3ec22000}, {0x3ec24000}, {0x3ec26000}, 
+    {0x3ec28000}, {0x3ec2a000}, {0x3ec2c000}, {0x3ec2e000}, 
+    {0x3ec30000}, {0x3ec32000}, {0x3ec34000}, {0x3ec36000}, 
+    {0x3ec38000}, {0x3ec3a000}, {0x3ec3c000}, {0x3ec3e000}, 
+    {0x3ec40000}, {0x3ec42000}, {0x3ec44000}, {0x3ec46000}, 
+    {0x3ec48000}, {0x3ec4a000}, {0x3ec4c000}, {0x3ec4e000}, 
+    {0x3ec50000}, {0x3ec52000}, {0x3ec54000}, {0x3ec56000}, 
+    {0x3ec58000}, {0x3ec5a000}, {0x3ec5c000}, {0x3ec5e000}, 
+    {0x3ec60000}, {0x3ec62000}, {0x3ec64000}, {0x3ec66000}, 
+    {0x3ec68000}, {0x3ec6a000}, {0x3ec6c000}, {0x3ec6e000}, 
+    {0x3ec70000}, {0x3ec72000}, {0x3ec74000}, {0x3ec76000}, 
+    {0x3ec78000}, {0x3ec7a000}, {0x3ec7c000}, {0x3ec7e000}, 
+    {0x3ec80000}, {0x3ec82000}, {0x3ec84000}, {0x3ec86000}, 
+    {0x3ec88000}, {0x3ec8a000}, {0x3ec8c000}, {0x3ec8e000}, 
+    {0x3ec90000}, {0x3ec92000}, {0x3ec94000}, {0x3ec96000}, 
+    {0x3ec98000}, {0x3ec9a000}, {0x3ec9c000}, {0x3ec9e000}, 
+    {0x3eca0000}, {0x3eca2000}, {0x3eca4000}, {0x3eca6000}, 
+    {0x3eca8000}, {0x3ecaa000}, {0x3ecac000}, {0x3ecae000}, 
+    {0x3ecb0000}, {0x3ecb2000}, {0x3ecb4000}, {0x3ecb6000}, 
+    {0x3ecb8000}, {0x3ecba000}, {0x3ecbc000}, {0x3ecbe000}, 
+    {0x3ecc0000}, {0x3ecc2000}, {0x3ecc4000}, {0x3ecc6000}, 
+    {0x3ecc8000}, {0x3ecca000}, {0x3eccc000}, {0x3ecce000}, 
+    {0x3ecd0000}, {0x3ecd2000}, {0x3ecd4000}, {0x3ecd6000}, 
+    {0x3ecd8000}, {0x3ecda000}, {0x3ecdc000}, {0x3ecde000}, 
+    {0x3ece0000}, {0x3ece2000}, {0x3ece4000}, {0x3ece6000}, 
+    {0x3ece8000}, {0x3ecea000}, {0x3ecec000}, {0x3ecee000}, 
+    {0x3ecf0000}, {0x3ecf2000}, {0x3ecf4000}, {0x3ecf6000}, 
+    {0x3ecf8000}, {0x3ecfa000}, {0x3ecfc000}, {0x3ecfe000}, 
+    {0x3ed00000}, {0x3ed02000}, {0x3ed04000}, {0x3ed06000}, 
+    {0x3ed08000}, {0x3ed0a000}, {0x3ed0c000}, {0x3ed0e000}, 
+    {0x3ed10000}, {0x3ed12000}, {0x3ed14000}, {0x3ed16000}, 
+    {0x3ed18000}, {0x3ed1a000}, {0x3ed1c000}, {0x3ed1e000}, 
+    {0x3ed20000}, {0x3ed22000}, {0x3ed24000}, {0x3ed26000}, 
+    {0x3ed28000}, {0x3ed2a000}, {0x3ed2c000}, {0x3ed2e000}, 
+    {0x3ed30000}, {0x3ed32000}, {0x3ed34000}, {0x3ed36000}, 
+    {0x3ed38000}, {0x3ed3a000}, {0x3ed3c000}, {0x3ed3e000}, 
+    {0x3ed40000}, {0x3ed42000}, {0x3ed44000}, {0x3ed46000}, 
+    {0x3ed48000}, {0x3ed4a000}, {0x3ed4c000}, {0x3ed4e000}, 
+    {0x3ed50000}, {0x3ed52000}, {0x3ed54000}, {0x3ed56000}, 
+    {0x3ed58000}, {0x3ed5a000}, {0x3ed5c000}, {0x3ed5e000}, 
+    {0x3ed60000}, {0x3ed62000}, {0x3ed64000}, {0x3ed66000}, 
+    {0x3ed68000}, {0x3ed6a000}, {0x3ed6c000}, {0x3ed6e000}, 
+    {0x3ed70000}, {0x3ed72000}, {0x3ed74000}, {0x3ed76000}, 
+    {0x3ed78000}, {0x3ed7a000}, {0x3ed7c000}, {0x3ed7e000}, 
+    {0x3ed80000}, {0x3ed82000}, {0x3ed84000}, {0x3ed86000}, 
+    {0x3ed88000}, {0x3ed8a000}, {0x3ed8c000}, {0x3ed8e000}, 
+    {0x3ed90000}, {0x3ed92000}, {0x3ed94000}, {0x3ed96000}, 
+    {0x3ed98000}, {0x3ed9a000}, {0x3ed9c000}, {0x3ed9e000}, 
+    {0x3eda0000}, {0x3eda2000}, {0x3eda4000}, {0x3eda6000}, 
+    {0x3eda8000}, {0x3edaa000}, {0x3edac000}, {0x3edae000}, 
+    {0x3edb0000}, {0x3edb2000}, {0x3edb4000}, {0x3edb6000}, 
+    {0x3edb8000}, {0x3edba000}, {0x3edbc000}, {0x3edbe000}, 
+    {0x3edc0000}, {0x3edc2000}, {0x3edc4000}, {0x3edc6000}, 
+    {0x3edc8000}, {0x3edca000}, {0x3edcc000}, {0x3edce000}, 
+    {0x3edd0000}, {0x3edd2000}, {0x3edd4000}, {0x3edd6000}, 
+    {0x3edd8000}, {0x3edda000}, {0x3eddc000}, {0x3edde000}, 
+    {0x3ede0000}, {0x3ede2000}, {0x3ede4000}, {0x3ede6000}, 
+    {0x3ede8000}, {0x3edea000}, {0x3edec000}, {0x3edee000}, 
+    {0x3edf0000}, {0x3edf2000}, {0x3edf4000}, {0x3edf6000}, 
+    {0x3edf8000}, {0x3edfa000}, {0x3edfc000}, {0x3edfe000}, 
+    {0x3ee00000}, {0x3ee02000}, {0x3ee04000}, {0x3ee06000}, 
+    {0x3ee08000}, {0x3ee0a000}, {0x3ee0c000}, {0x3ee0e000}, 
+    {0x3ee10000}, {0x3ee12000}, {0x3ee14000}, {0x3ee16000}, 
+    {0x3ee18000}, {0x3ee1a000}, {0x3ee1c000}, {0x3ee1e000}, 
+    {0x3ee20000}, {0x3ee22000}, {0x3ee24000}, {0x3ee26000}, 
+    {0x3ee28000}, {0x3ee2a000}, {0x3ee2c000}, {0x3ee2e000}, 
+    {0x3ee30000}, {0x3ee32000}, {0x3ee34000}, {0x3ee36000}, 
+    {0x3ee38000}, {0x3ee3a000}, {0x3ee3c000}, {0x3ee3e000}, 
+    {0x3ee40000}, {0x3ee42000}, {0x3ee44000}, {0x3ee46000}, 
+    {0x3ee48000}, {0x3ee4a000}, {0x3ee4c000}, {0x3ee4e000}, 
+    {0x3ee50000}, {0x3ee52000}, {0x3ee54000}, {0x3ee56000}, 
+    {0x3ee58000}, {0x3ee5a000}, {0x3ee5c000}, {0x3ee5e000}, 
+    {0x3ee60000}, {0x3ee62000}, {0x3ee64000}, {0x3ee66000}, 
+    {0x3ee68000}, {0x3ee6a000}, {0x3ee6c000}, {0x3ee6e000}, 
+    {0x3ee70000}, {0x3ee72000}, {0x3ee74000}, {0x3ee76000}, 
+    {0x3ee78000}, {0x3ee7a000}, {0x3ee7c000}, {0x3ee7e000}, 
+    {0x3ee80000}, {0x3ee82000}, {0x3ee84000}, {0x3ee86000}, 
+    {0x3ee88000}, {0x3ee8a000}, {0x3ee8c000}, {0x3ee8e000}, 
+    {0x3ee90000}, {0x3ee92000}, {0x3ee94000}, {0x3ee96000}, 
+    {0x3ee98000}, {0x3ee9a000}, {0x3ee9c000}, {0x3ee9e000}, 
+    {0x3eea0000}, {0x3eea2000}, {0x3eea4000}, {0x3eea6000}, 
+    {0x3eea8000}, {0x3eeaa000}, {0x3eeac000}, {0x3eeae000}, 
+    {0x3eeb0000}, {0x3eeb2000}, {0x3eeb4000}, {0x3eeb6000}, 
+    {0x3eeb8000}, {0x3eeba000}, {0x3eebc000}, {0x3eebe000}, 
+    {0x3eec0000}, {0x3eec2000}, {0x3eec4000}, {0x3eec6000}, 
+    {0x3eec8000}, {0x3eeca000}, {0x3eecc000}, {0x3eece000}, 
+    {0x3eed0000}, {0x3eed2000}, {0x3eed4000}, {0x3eed6000}, 
+    {0x3eed8000}, {0x3eeda000}, {0x3eedc000}, {0x3eede000}, 
+    {0x3eee0000}, {0x3eee2000}, {0x3eee4000}, {0x3eee6000}, 
+    {0x3eee8000}, {0x3eeea000}, {0x3eeec000}, {0x3eeee000}, 
+    {0x3eef0000}, {0x3eef2000}, {0x3eef4000}, {0x3eef6000}, 
+    {0x3eef8000}, {0x3eefa000}, {0x3eefc000}, {0x3eefe000}, 
+    {0x3ef00000}, {0x3ef02000}, {0x3ef04000}, {0x3ef06000}, 
+    {0x3ef08000}, {0x3ef0a000}, {0x3ef0c000}, {0x3ef0e000}, 
+    {0x3ef10000}, {0x3ef12000}, {0x3ef14000}, {0x3ef16000}, 
+    {0x3ef18000}, {0x3ef1a000}, {0x3ef1c000}, {0x3ef1e000}, 
+    {0x3ef20000}, {0x3ef22000}, {0x3ef24000}, {0x3ef26000}, 
+    {0x3ef28000}, {0x3ef2a000}, {0x3ef2c000}, {0x3ef2e000}, 
+    {0x3ef30000}, {0x3ef32000}, {0x3ef34000}, {0x3ef36000}, 
+    {0x3ef38000}, {0x3ef3a000}, {0x3ef3c000}, {0x3ef3e000}, 
+    {0x3ef40000}, {0x3ef42000}, {0x3ef44000}, {0x3ef46000}, 
+    {0x3ef48000}, {0x3ef4a000}, {0x3ef4c000}, {0x3ef4e000}, 
+    {0x3ef50000}, {0x3ef52000}, {0x3ef54000}, {0x3ef56000}, 
+    {0x3ef58000}, {0x3ef5a000}, {0x3ef5c000}, {0x3ef5e000}, 
+    {0x3ef60000}, {0x3ef62000}, {0x3ef64000}, {0x3ef66000}, 
+    {0x3ef68000}, {0x3ef6a000}, {0x3ef6c000}, {0x3ef6e000}, 
+    {0x3ef70000}, {0x3ef72000}, {0x3ef74000}, {0x3ef76000}, 
+    {0x3ef78000}, {0x3ef7a000}, {0x3ef7c000}, {0x3ef7e000}, 
+    {0x3ef80000}, {0x3ef82000}, {0x3ef84000}, {0x3ef86000}, 
+    {0x3ef88000}, {0x3ef8a000}, {0x3ef8c000}, {0x3ef8e000}, 
+    {0x3ef90000}, {0x3ef92000}, {0x3ef94000}, {0x3ef96000}, 
+    {0x3ef98000}, {0x3ef9a000}, {0x3ef9c000}, {0x3ef9e000}, 
+    {0x3efa0000}, {0x3efa2000}, {0x3efa4000}, {0x3efa6000}, 
+    {0x3efa8000}, {0x3efaa000}, {0x3efac000}, {0x3efae000}, 
+    {0x3efb0000}, {0x3efb2000}, {0x3efb4000}, {0x3efb6000}, 
+    {0x3efb8000}, {0x3efba000}, {0x3efbc000}, {0x3efbe000}, 
+    {0x3efc0000}, {0x3efc2000}, {0x3efc4000}, {0x3efc6000}, 
+    {0x3efc8000}, {0x3efca000}, {0x3efcc000}, {0x3efce000}, 
+    {0x3efd0000}, {0x3efd2000}, {0x3efd4000}, {0x3efd6000}, 
+    {0x3efd8000}, {0x3efda000}, {0x3efdc000}, {0x3efde000}, 
+    {0x3efe0000}, {0x3efe2000}, {0x3efe4000}, {0x3efe6000}, 
+    {0x3efe8000}, {0x3efea000}, {0x3efec000}, {0x3efee000}, 
+    {0x3eff0000}, {0x3eff2000}, {0x3eff4000}, {0x3eff6000}, 
+    {0x3eff8000}, {0x3effa000}, {0x3effc000}, {0x3effe000}, 
+    {0x3f000000}, {0x3f002000}, {0x3f004000}, {0x3f006000}, 
+    {0x3f008000}, {0x3f00a000}, {0x3f00c000}, {0x3f00e000}, 
+    {0x3f010000}, {0x3f012000}, {0x3f014000}, {0x3f016000}, 
+    {0x3f018000}, {0x3f01a000}, {0x3f01c000}, {0x3f01e000}, 
+    {0x3f020000}, {0x3f022000}, {0x3f024000}, {0x3f026000}, 
+    {0x3f028000}, {0x3f02a000}, {0x3f02c000}, {0x3f02e000}, 
+    {0x3f030000}, {0x3f032000}, {0x3f034000}, {0x3f036000}, 
+    {0x3f038000}, {0x3f03a000}, {0x3f03c000}, {0x3f03e000}, 
+    {0x3f040000}, {0x3f042000}, {0x3f044000}, {0x3f046000}, 
+    {0x3f048000}, {0x3f04a000}, {0x3f04c000}, {0x3f04e000}, 
+    {0x3f050000}, {0x3f052000}, {0x3f054000}, {0x3f056000}, 
+    {0x3f058000}, {0x3f05a000}, {0x3f05c000}, {0x3f05e000}, 
+    {0x3f060000}, {0x3f062000}, {0x3f064000}, {0x3f066000}, 
+    {0x3f068000}, {0x3f06a000}, {0x3f06c000}, {0x3f06e000}, 
+    {0x3f070000}, {0x3f072000}, {0x3f074000}, {0x3f076000}, 
+    {0x3f078000}, {0x3f07a000}, {0x3f07c000}, {0x3f07e000}, 
+    {0x3f080000}, {0x3f082000}, {0x3f084000}, {0x3f086000}, 
+    {0x3f088000}, {0x3f08a000}, {0x3f08c000}, {0x3f08e000}, 
+    {0x3f090000}, {0x3f092000}, {0x3f094000}, {0x3f096000}, 
+    {0x3f098000}, {0x3f09a000}, {0x3f09c000}, {0x3f09e000}, 
+    {0x3f0a0000}, {0x3f0a2000}, {0x3f0a4000}, {0x3f0a6000}, 
+    {0x3f0a8000}, {0x3f0aa000}, {0x3f0ac000}, {0x3f0ae000}, 
+    {0x3f0b0000}, {0x3f0b2000}, {0x3f0b4000}, {0x3f0b6000}, 
+    {0x3f0b8000}, {0x3f0ba000}, {0x3f0bc000}, {0x3f0be000}, 
+    {0x3f0c0000}, {0x3f0c2000}, {0x3f0c4000}, {0x3f0c6000}, 
+    {0x3f0c8000}, {0x3f0ca000}, {0x3f0cc000}, {0x3f0ce000}, 
+    {0x3f0d0000}, {0x3f0d2000}, {0x3f0d4000}, {0x3f0d6000}, 
+    {0x3f0d8000}, {0x3f0da000}, {0x3f0dc000}, {0x3f0de000}, 
+    {0x3f0e0000}, {0x3f0e2000}, {0x3f0e4000}, {0x3f0e6000}, 
+    {0x3f0e8000}, {0x3f0ea000}, {0x3f0ec000}, {0x3f0ee000}, 
+    {0x3f0f0000}, {0x3f0f2000}, {0x3f0f4000}, {0x3f0f6000}, 
+    {0x3f0f8000}, {0x3f0fa000}, {0x3f0fc000}, {0x3f0fe000}, 
+    {0x3f100000}, {0x3f102000}, {0x3f104000}, {0x3f106000}, 
+    {0x3f108000}, {0x3f10a000}, {0x3f10c000}, {0x3f10e000}, 
+    {0x3f110000}, {0x3f112000}, {0x3f114000}, {0x3f116000}, 
+    {0x3f118000}, {0x3f11a000}, {0x3f11c000}, {0x3f11e000}, 
+    {0x3f120000}, {0x3f122000}, {0x3f124000}, {0x3f126000}, 
+    {0x3f128000}, {0x3f12a000}, {0x3f12c000}, {0x3f12e000}, 
+    {0x3f130000}, {0x3f132000}, {0x3f134000}, {0x3f136000}, 
+    {0x3f138000}, {0x3f13a000}, {0x3f13c000}, {0x3f13e000}, 
+    {0x3f140000}, {0x3f142000}, {0x3f144000}, {0x3f146000}, 
+    {0x3f148000}, {0x3f14a000}, {0x3f14c000}, {0x3f14e000}, 
+    {0x3f150000}, {0x3f152000}, {0x3f154000}, {0x3f156000}, 
+    {0x3f158000}, {0x3f15a000}, {0x3f15c000}, {0x3f15e000}, 
+    {0x3f160000}, {0x3f162000}, {0x3f164000}, {0x3f166000}, 
+    {0x3f168000}, {0x3f16a000}, {0x3f16c000}, {0x3f16e000}, 
+    {0x3f170000}, {0x3f172000}, {0x3f174000}, {0x3f176000}, 
+    {0x3f178000}, {0x3f17a000}, {0x3f17c000}, {0x3f17e000}, 
+    {0x3f180000}, {0x3f182000}, {0x3f184000}, {0x3f186000}, 
+    {0x3f188000}, {0x3f18a000}, {0x3f18c000}, {0x3f18e000}, 
+    {0x3f190000}, {0x3f192000}, {0x3f194000}, {0x3f196000}, 
+    {0x3f198000}, {0x3f19a000}, {0x3f19c000}, {0x3f19e000}, 
+    {0x3f1a0000}, {0x3f1a2000}, {0x3f1a4000}, {0x3f1a6000}, 
+    {0x3f1a8000}, {0x3f1aa000}, {0x3f1ac000}, {0x3f1ae000}, 
+    {0x3f1b0000}, {0x3f1b2000}, {0x3f1b4000}, {0x3f1b6000}, 
+    {0x3f1b8000}, {0x3f1ba000}, {0x3f1bc000}, {0x3f1be000}, 
+    {0x3f1c0000}, {0x3f1c2000}, {0x3f1c4000}, {0x3f1c6000}, 
+    {0x3f1c8000}, {0x3f1ca000}, {0x3f1cc000}, {0x3f1ce000}, 
+    {0x3f1d0000}, {0x3f1d2000}, {0x3f1d4000}, {0x3f1d6000}, 
+    {0x3f1d8000}, {0x3f1da000}, {0x3f1dc000}, {0x3f1de000}, 
+    {0x3f1e0000}, {0x3f1e2000}, {0x3f1e4000}, {0x3f1e6000}, 
+    {0x3f1e8000}, {0x3f1ea000}, {0x3f1ec000}, {0x3f1ee000}, 
+    {0x3f1f0000}, {0x3f1f2000}, {0x3f1f4000}, {0x3f1f6000}, 
+    {0x3f1f8000}, {0x3f1fa000}, {0x3f1fc000}, {0x3f1fe000}, 
+    {0x3f200000}, {0x3f202000}, {0x3f204000}, {0x3f206000}, 
+    {0x3f208000}, {0x3f20a000}, {0x3f20c000}, {0x3f20e000}, 
+    {0x3f210000}, {0x3f212000}, {0x3f214000}, {0x3f216000}, 
+    {0x3f218000}, {0x3f21a000}, {0x3f21c000}, {0x3f21e000}, 
+    {0x3f220000}, {0x3f222000}, {0x3f224000}, {0x3f226000}, 
+    {0x3f228000}, {0x3f22a000}, {0x3f22c000}, {0x3f22e000}, 
+    {0x3f230000}, {0x3f232000}, {0x3f234000}, {0x3f236000}, 
+    {0x3f238000}, {0x3f23a000}, {0x3f23c000}, {0x3f23e000}, 
+    {0x3f240000}, {0x3f242000}, {0x3f244000}, {0x3f246000}, 
+    {0x3f248000}, {0x3f24a000}, {0x3f24c000}, {0x3f24e000}, 
+    {0x3f250000}, {0x3f252000}, {0x3f254000}, {0x3f256000}, 
+    {0x3f258000}, {0x3f25a000}, {0x3f25c000}, {0x3f25e000}, 
+    {0x3f260000}, {0x3f262000}, {0x3f264000}, {0x3f266000}, 
+    {0x3f268000}, {0x3f26a000}, {0x3f26c000}, {0x3f26e000}, 
+    {0x3f270000}, {0x3f272000}, {0x3f274000}, {0x3f276000}, 
+    {0x3f278000}, {0x3f27a000}, {0x3f27c000}, {0x3f27e000}, 
+    {0x3f280000}, {0x3f282000}, {0x3f284000}, {0x3f286000}, 
+    {0x3f288000}, {0x3f28a000}, {0x3f28c000}, {0x3f28e000}, 
+    {0x3f290000}, {0x3f292000}, {0x3f294000}, {0x3f296000}, 
+    {0x3f298000}, {0x3f29a000}, {0x3f29c000}, {0x3f29e000}, 
+    {0x3f2a0000}, {0x3f2a2000}, {0x3f2a4000}, {0x3f2a6000}, 
+    {0x3f2a8000}, {0x3f2aa000}, {0x3f2ac000}, {0x3f2ae000}, 
+    {0x3f2b0000}, {0x3f2b2000}, {0x3f2b4000}, {0x3f2b6000}, 
+    {0x3f2b8000}, {0x3f2ba000}, {0x3f2bc000}, {0x3f2be000}, 
+    {0x3f2c0000}, {0x3f2c2000}, {0x3f2c4000}, {0x3f2c6000}, 
+    {0x3f2c8000}, {0x3f2ca000}, {0x3f2cc000}, {0x3f2ce000}, 
+    {0x3f2d0000}, {0x3f2d2000}, {0x3f2d4000}, {0x3f2d6000}, 
+    {0x3f2d8000}, {0x3f2da000}, {0x3f2dc000}, {0x3f2de000}, 
+    {0x3f2e0000}, {0x3f2e2000}, {0x3f2e4000}, {0x3f2e6000}, 
+    {0x3f2e8000}, {0x3f2ea000}, {0x3f2ec000}, {0x3f2ee000}, 
+    {0x3f2f0000}, {0x3f2f2000}, {0x3f2f4000}, {0x3f2f6000}, 
+    {0x3f2f8000}, {0x3f2fa000}, {0x3f2fc000}, {0x3f2fe000}, 
+    {0x3f300000}, {0x3f302000}, {0x3f304000}, {0x3f306000}, 
+    {0x3f308000}, {0x3f30a000}, {0x3f30c000}, {0x3f30e000}, 
+    {0x3f310000}, {0x3f312000}, {0x3f314000}, {0x3f316000}, 
+    {0x3f318000}, {0x3f31a000}, {0x3f31c000}, {0x3f31e000}, 
+    {0x3f320000}, {0x3f322000}, {0x3f324000}, {0x3f326000}, 
+    {0x3f328000}, {0x3f32a000}, {0x3f32c000}, {0x3f32e000}, 
+    {0x3f330000}, {0x3f332000}, {0x3f334000}, {0x3f336000}, 
+    {0x3f338000}, {0x3f33a000}, {0x3f33c000}, {0x3f33e000}, 
+    {0x3f340000}, {0x3f342000}, {0x3f344000}, {0x3f346000}, 
+    {0x3f348000}, {0x3f34a000}, {0x3f34c000}, {0x3f34e000}, 
+    {0x3f350000}, {0x3f352000}, {0x3f354000}, {0x3f356000}, 
+    {0x3f358000}, {0x3f35a000}, {0x3f35c000}, {0x3f35e000}, 
+    {0x3f360000}, {0x3f362000}, {0x3f364000}, {0x3f366000}, 
+    {0x3f368000}, {0x3f36a000}, {0x3f36c000}, {0x3f36e000}, 
+    {0x3f370000}, {0x3f372000}, {0x3f374000}, {0x3f376000}, 
+    {0x3f378000}, {0x3f37a000}, {0x3f37c000}, {0x3f37e000}, 
+    {0x3f380000}, {0x3f382000}, {0x3f384000}, {0x3f386000}, 
+    {0x3f388000}, {0x3f38a000}, {0x3f38c000}, {0x3f38e000}, 
+    {0x3f390000}, {0x3f392000}, {0x3f394000}, {0x3f396000}, 
+    {0x3f398000}, {0x3f39a000}, {0x3f39c000}, {0x3f39e000}, 
+    {0x3f3a0000}, {0x3f3a2000}, {0x3f3a4000}, {0x3f3a6000}, 
+    {0x3f3a8000}, {0x3f3aa000}, {0x3f3ac000}, {0x3f3ae000}, 
+    {0x3f3b0000}, {0x3f3b2000}, {0x3f3b4000}, {0x3f3b6000}, 
+    {0x3f3b8000}, {0x3f3ba000}, {0x3f3bc000}, {0x3f3be000}, 
+    {0x3f3c0000}, {0x3f3c2000}, {0x3f3c4000}, {0x3f3c6000}, 
+    {0x3f3c8000}, {0x3f3ca000}, {0x3f3cc000}, {0x3f3ce000}, 
+    {0x3f3d0000}, {0x3f3d2000}, {0x3f3d4000}, {0x3f3d6000}, 
+    {0x3f3d8000}, {0x3f3da000}, {0x3f3dc000}, {0x3f3de000}, 
+    {0x3f3e0000}, {0x3f3e2000}, {0x3f3e4000}, {0x3f3e6000}, 
+    {0x3f3e8000}, {0x3f3ea000}, {0x3f3ec000}, {0x3f3ee000}, 
+    {0x3f3f0000}, {0x3f3f2000}, {0x3f3f4000}, {0x3f3f6000}, 
+    {0x3f3f8000}, {0x3f3fa000}, {0x3f3fc000}, {0x3f3fe000}, 
+    {0x3f400000}, {0x3f402000}, {0x3f404000}, {0x3f406000}, 
+    {0x3f408000}, {0x3f40a000}, {0x3f40c000}, {0x3f40e000}, 
+    {0x3f410000}, {0x3f412000}, {0x3f414000}, {0x3f416000}, 
+    {0x3f418000}, {0x3f41a000}, {0x3f41c000}, {0x3f41e000}, 
+    {0x3f420000}, {0x3f422000}, {0x3f424000}, {0x3f426000}, 
+    {0x3f428000}, {0x3f42a000}, {0x3f42c000}, {0x3f42e000}, 
+    {0x3f430000}, {0x3f432000}, {0x3f434000}, {0x3f436000}, 
+    {0x3f438000}, {0x3f43a000}, {0x3f43c000}, {0x3f43e000}, 
+    {0x3f440000}, {0x3f442000}, {0x3f444000}, {0x3f446000}, 
+    {0x3f448000}, {0x3f44a000}, {0x3f44c000}, {0x3f44e000}, 
+    {0x3f450000}, {0x3f452000}, {0x3f454000}, {0x3f456000}, 
+    {0x3f458000}, {0x3f45a000}, {0x3f45c000}, {0x3f45e000}, 
+    {0x3f460000}, {0x3f462000}, {0x3f464000}, {0x3f466000}, 
+    {0x3f468000}, {0x3f46a000}, {0x3f46c000}, {0x3f46e000}, 
+    {0x3f470000}, {0x3f472000}, {0x3f474000}, {0x3f476000}, 
+    {0x3f478000}, {0x3f47a000}, {0x3f47c000}, {0x3f47e000}, 
+    {0x3f480000}, {0x3f482000}, {0x3f484000}, {0x3f486000}, 
+    {0x3f488000}, {0x3f48a000}, {0x3f48c000}, {0x3f48e000}, 
+    {0x3f490000}, {0x3f492000}, {0x3f494000}, {0x3f496000}, 
+    {0x3f498000}, {0x3f49a000}, {0x3f49c000}, {0x3f49e000}, 
+    {0x3f4a0000}, {0x3f4a2000}, {0x3f4a4000}, {0x3f4a6000}, 
+    {0x3f4a8000}, {0x3f4aa000}, {0x3f4ac000}, {0x3f4ae000}, 
+    {0x3f4b0000}, {0x3f4b2000}, {0x3f4b4000}, {0x3f4b6000}, 
+    {0x3f4b8000}, {0x3f4ba000}, {0x3f4bc000}, {0x3f4be000}, 
+    {0x3f4c0000}, {0x3f4c2000}, {0x3f4c4000}, {0x3f4c6000}, 
+    {0x3f4c8000}, {0x3f4ca000}, {0x3f4cc000}, {0x3f4ce000}, 
+    {0x3f4d0000}, {0x3f4d2000}, {0x3f4d4000}, {0x3f4d6000}, 
+    {0x3f4d8000}, {0x3f4da000}, {0x3f4dc000}, {0x3f4de000}, 
+    {0x3f4e0000}, {0x3f4e2000}, {0x3f4e4000}, {0x3f4e6000}, 
+    {0x3f4e8000}, {0x3f4ea000}, {0x3f4ec000}, {0x3f4ee000}, 
+    {0x3f4f0000}, {0x3f4f2000}, {0x3f4f4000}, {0x3f4f6000}, 
+    {0x3f4f8000}, {0x3f4fa000}, {0x3f4fc000}, {0x3f4fe000}, 
+    {0x3f500000}, {0x3f502000}, {0x3f504000}, {0x3f506000}, 
+    {0x3f508000}, {0x3f50a000}, {0x3f50c000}, {0x3f50e000}, 
+    {0x3f510000}, {0x3f512000}, {0x3f514000}, {0x3f516000}, 
+    {0x3f518000}, {0x3f51a000}, {0x3f51c000}, {0x3f51e000}, 
+    {0x3f520000}, {0x3f522000}, {0x3f524000}, {0x3f526000}, 
+    {0x3f528000}, {0x3f52a000}, {0x3f52c000}, {0x3f52e000}, 
+    {0x3f530000}, {0x3f532000}, {0x3f534000}, {0x3f536000}, 
+    {0x3f538000}, {0x3f53a000}, {0x3f53c000}, {0x3f53e000}, 
+    {0x3f540000}, {0x3f542000}, {0x3f544000}, {0x3f546000}, 
+    {0x3f548000}, {0x3f54a000}, {0x3f54c000}, {0x3f54e000}, 
+    {0x3f550000}, {0x3f552000}, {0x3f554000}, {0x3f556000}, 
+    {0x3f558000}, {0x3f55a000}, {0x3f55c000}, {0x3f55e000}, 
+    {0x3f560000}, {0x3f562000}, {0x3f564000}, {0x3f566000}, 
+    {0x3f568000}, {0x3f56a000}, {0x3f56c000}, {0x3f56e000}, 
+    {0x3f570000}, {0x3f572000}, {0x3f574000}, {0x3f576000}, 
+    {0x3f578000}, {0x3f57a000}, {0x3f57c000}, {0x3f57e000}, 
+    {0x3f580000}, {0x3f582000}, {0x3f584000}, {0x3f586000}, 
+    {0x3f588000}, {0x3f58a000}, {0x3f58c000}, {0x3f58e000}, 
+    {0x3f590000}, {0x3f592000}, {0x3f594000}, {0x3f596000}, 
+    {0x3f598000}, {0x3f59a000}, {0x3f59c000}, {0x3f59e000}, 
+    {0x3f5a0000}, {0x3f5a2000}, {0x3f5a4000}, {0x3f5a6000}, 
+    {0x3f5a8000}, {0x3f5aa000}, {0x3f5ac000}, {0x3f5ae000}, 
+    {0x3f5b0000}, {0x3f5b2000}, {0x3f5b4000}, {0x3f5b6000}, 
+    {0x3f5b8000}, {0x3f5ba000}, {0x3f5bc000}, {0x3f5be000}, 
+    {0x3f5c0000}, {0x3f5c2000}, {0x3f5c4000}, {0x3f5c6000}, 
+    {0x3f5c8000}, {0x3f5ca000}, {0x3f5cc000}, {0x3f5ce000}, 
+    {0x3f5d0000}, {0x3f5d2000}, {0x3f5d4000}, {0x3f5d6000}, 
+    {0x3f5d8000}, {0x3f5da000}, {0x3f5dc000}, {0x3f5de000}, 
+    {0x3f5e0000}, {0x3f5e2000}, {0x3f5e4000}, {0x3f5e6000}, 
+    {0x3f5e8000}, {0x3f5ea000}, {0x3f5ec000}, {0x3f5ee000}, 
+    {0x3f5f0000}, {0x3f5f2000}, {0x3f5f4000}, {0x3f5f6000}, 
+    {0x3f5f8000}, {0x3f5fa000}, {0x3f5fc000}, {0x3f5fe000}, 
+    {0x3f600000}, {0x3f602000}, {0x3f604000}, {0x3f606000}, 
+    {0x3f608000}, {0x3f60a000}, {0x3f60c000}, {0x3f60e000}, 
+    {0x3f610000}, {0x3f612000}, {0x3f614000}, {0x3f616000}, 
+    {0x3f618000}, {0x3f61a000}, {0x3f61c000}, {0x3f61e000}, 
+    {0x3f620000}, {0x3f622000}, {0x3f624000}, {0x3f626000}, 
+    {0x3f628000}, {0x3f62a000}, {0x3f62c000}, {0x3f62e000}, 
+    {0x3f630000}, {0x3f632000}, {0x3f634000}, {0x3f636000}, 
+    {0x3f638000}, {0x3f63a000}, {0x3f63c000}, {0x3f63e000}, 
+    {0x3f640000}, {0x3f642000}, {0x3f644000}, {0x3f646000}, 
+    {0x3f648000}, {0x3f64a000}, {0x3f64c000}, {0x3f64e000}, 
+    {0x3f650000}, {0x3f652000}, {0x3f654000}, {0x3f656000}, 
+    {0x3f658000}, {0x3f65a000}, {0x3f65c000}, {0x3f65e000}, 
+    {0x3f660000}, {0x3f662000}, {0x3f664000}, {0x3f666000}, 
+    {0x3f668000}, {0x3f66a000}, {0x3f66c000}, {0x3f66e000}, 
+    {0x3f670000}, {0x3f672000}, {0x3f674000}, {0x3f676000}, 
+    {0x3f678000}, {0x3f67a000}, {0x3f67c000}, {0x3f67e000}, 
+    {0x3f680000}, {0x3f682000}, {0x3f684000}, {0x3f686000}, 
+    {0x3f688000}, {0x3f68a000}, {0x3f68c000}, {0x3f68e000}, 
+    {0x3f690000}, {0x3f692000}, {0x3f694000}, {0x3f696000}, 
+    {0x3f698000}, {0x3f69a000}, {0x3f69c000}, {0x3f69e000}, 
+    {0x3f6a0000}, {0x3f6a2000}, {0x3f6a4000}, {0x3f6a6000}, 
+    {0x3f6a8000}, {0x3f6aa000}, {0x3f6ac000}, {0x3f6ae000}, 
+    {0x3f6b0000}, {0x3f6b2000}, {0x3f6b4000}, {0x3f6b6000}, 
+    {0x3f6b8000}, {0x3f6ba000}, {0x3f6bc000}, {0x3f6be000}, 
+    {0x3f6c0000}, {0x3f6c2000}, {0x3f6c4000}, {0x3f6c6000}, 
+    {0x3f6c8000}, {0x3f6ca000}, {0x3f6cc000}, {0x3f6ce000}, 
+    {0x3f6d0000}, {0x3f6d2000}, {0x3f6d4000}, {0x3f6d6000}, 
+    {0x3f6d8000}, {0x3f6da000}, {0x3f6dc000}, {0x3f6de000}, 
+    {0x3f6e0000}, {0x3f6e2000}, {0x3f6e4000}, {0x3f6e6000}, 
+    {0x3f6e8000}, {0x3f6ea000}, {0x3f6ec000}, {0x3f6ee000}, 
+    {0x3f6f0000}, {0x3f6f2000}, {0x3f6f4000}, {0x3f6f6000}, 
+    {0x3f6f8000}, {0x3f6fa000}, {0x3f6fc000}, {0x3f6fe000}, 
+    {0x3f700000}, {0x3f702000}, {0x3f704000}, {0x3f706000}, 
+    {0x3f708000}, {0x3f70a000}, {0x3f70c000}, {0x3f70e000}, 
+    {0x3f710000}, {0x3f712000}, {0x3f714000}, {0x3f716000}, 
+    {0x3f718000}, {0x3f71a000}, {0x3f71c000}, {0x3f71e000}, 
+    {0x3f720000}, {0x3f722000}, {0x3f724000}, {0x3f726000}, 
+    {0x3f728000}, {0x3f72a000}, {0x3f72c000}, {0x3f72e000}, 
+    {0x3f730000}, {0x3f732000}, {0x3f734000}, {0x3f736000}, 
+    {0x3f738000}, {0x3f73a000}, {0x3f73c000}, {0x3f73e000}, 
+    {0x3f740000}, {0x3f742000}, {0x3f744000}, {0x3f746000}, 
+    {0x3f748000}, {0x3f74a000}, {0x3f74c000}, {0x3f74e000}, 
+    {0x3f750000}, {0x3f752000}, {0x3f754000}, {0x3f756000}, 
+    {0x3f758000}, {0x3f75a000}, {0x3f75c000}, {0x3f75e000}, 
+    {0x3f760000}, {0x3f762000}, {0x3f764000}, {0x3f766000}, 
+    {0x3f768000}, {0x3f76a000}, {0x3f76c000}, {0x3f76e000}, 
+    {0x3f770000}, {0x3f772000}, {0x3f774000}, {0x3f776000}, 
+    {0x3f778000}, {0x3f77a000}, {0x3f77c000}, {0x3f77e000}, 
+    {0x3f780000}, {0x3f782000}, {0x3f784000}, {0x3f786000}, 
+    {0x3f788000}, {0x3f78a000}, {0x3f78c000}, {0x3f78e000}, 
+    {0x3f790000}, {0x3f792000}, {0x3f794000}, {0x3f796000}, 
+    {0x3f798000}, {0x3f79a000}, {0x3f79c000}, {0x3f79e000}, 
+    {0x3f7a0000}, {0x3f7a2000}, {0x3f7a4000}, {0x3f7a6000}, 
+    {0x3f7a8000}, {0x3f7aa000}, {0x3f7ac000}, {0x3f7ae000}, 
+    {0x3f7b0000}, {0x3f7b2000}, {0x3f7b4000}, {0x3f7b6000}, 
+    {0x3f7b8000}, {0x3f7ba000}, {0x3f7bc000}, {0x3f7be000}, 
+    {0x3f7c0000}, {0x3f7c2000}, {0x3f7c4000}, {0x3f7c6000}, 
+    {0x3f7c8000}, {0x3f7ca000}, {0x3f7cc000}, {0x3f7ce000}, 
+    {0x3f7d0000}, {0x3f7d2000}, {0x3f7d4000}, {0x3f7d6000}, 
+    {0x3f7d8000}, {0x3f7da000}, {0x3f7dc000}, {0x3f7de000}, 
+    {0x3f7e0000}, {0x3f7e2000}, {0x3f7e4000}, {0x3f7e6000}, 
+    {0x3f7e8000}, {0x3f7ea000}, {0x3f7ec000}, {0x3f7ee000}, 
+    {0x3f7f0000}, {0x3f7f2000}, {0x3f7f4000}, {0x3f7f6000}, 
+    {0x3f7f8000}, {0x3f7fa000}, {0x3f7fc000}, {0x3f7fe000}, 
+    {0x3f800000}, {0x3f802000}, {0x3f804000}, {0x3f806000}, 
+    {0x3f808000}, {0x3f80a000}, {0x3f80c000}, {0x3f80e000}, 
+    {0x3f810000}, {0x3f812000}, {0x3f814000}, {0x3f816000}, 
+    {0x3f818000}, {0x3f81a000}, {0x3f81c000}, {0x3f81e000}, 
+    {0x3f820000}, {0x3f822000}, {0x3f824000}, {0x3f826000}, 
+    {0x3f828000}, {0x3f82a000}, {0x3f82c000}, {0x3f82e000}, 
+    {0x3f830000}, {0x3f832000}, {0x3f834000}, {0x3f836000}, 
+    {0x3f838000}, {0x3f83a000}, {0x3f83c000}, {0x3f83e000}, 
+    {0x3f840000}, {0x3f842000}, {0x3f844000}, {0x3f846000}, 
+    {0x3f848000}, {0x3f84a000}, {0x3f84c000}, {0x3f84e000}, 
+    {0x3f850000}, {0x3f852000}, {0x3f854000}, {0x3f856000}, 
+    {0x3f858000}, {0x3f85a000}, {0x3f85c000}, {0x3f85e000}, 
+    {0x3f860000}, {0x3f862000}, {0x3f864000}, {0x3f866000}, 
+    {0x3f868000}, {0x3f86a000}, {0x3f86c000}, {0x3f86e000}, 
+    {0x3f870000}, {0x3f872000}, {0x3f874000}, {0x3f876000}, 
+    {0x3f878000}, {0x3f87a000}, {0x3f87c000}, {0x3f87e000}, 
+    {0x3f880000}, {0x3f882000}, {0x3f884000}, {0x3f886000}, 
+    {0x3f888000}, {0x3f88a000}, {0x3f88c000}, {0x3f88e000}, 
+    {0x3f890000}, {0x3f892000}, {0x3f894000}, {0x3f896000}, 
+    {0x3f898000}, {0x3f89a000}, {0x3f89c000}, {0x3f89e000}, 
+    {0x3f8a0000}, {0x3f8a2000}, {0x3f8a4000}, {0x3f8a6000}, 
+    {0x3f8a8000}, {0x3f8aa000}, {0x3f8ac000}, {0x3f8ae000}, 
+    {0x3f8b0000}, {0x3f8b2000}, {0x3f8b4000}, {0x3f8b6000}, 
+    {0x3f8b8000}, {0x3f8ba000}, {0x3f8bc000}, {0x3f8be000}, 
+    {0x3f8c0000}, {0x3f8c2000}, {0x3f8c4000}, {0x3f8c6000}, 
+    {0x3f8c8000}, {0x3f8ca000}, {0x3f8cc000}, {0x3f8ce000}, 
+    {0x3f8d0000}, {0x3f8d2000}, {0x3f8d4000}, {0x3f8d6000}, 
+    {0x3f8d8000}, {0x3f8da000}, {0x3f8dc000}, {0x3f8de000}, 
+    {0x3f8e0000}, {0x3f8e2000}, {0x3f8e4000}, {0x3f8e6000}, 
+    {0x3f8e8000}, {0x3f8ea000}, {0x3f8ec000}, {0x3f8ee000}, 
+    {0x3f8f0000}, {0x3f8f2000}, {0x3f8f4000}, {0x3f8f6000}, 
+    {0x3f8f8000}, {0x3f8fa000}, {0x3f8fc000}, {0x3f8fe000}, 
+    {0x3f900000}, {0x3f902000}, {0x3f904000}, {0x3f906000}, 
+    {0x3f908000}, {0x3f90a000}, {0x3f90c000}, {0x3f90e000}, 
+    {0x3f910000}, {0x3f912000}, {0x3f914000}, {0x3f916000}, 
+    {0x3f918000}, {0x3f91a000}, {0x3f91c000}, {0x3f91e000}, 
+    {0x3f920000}, {0x3f922000}, {0x3f924000}, {0x3f926000}, 
+    {0x3f928000}, {0x3f92a000}, {0x3f92c000}, {0x3f92e000}, 
+    {0x3f930000}, {0x3f932000}, {0x3f934000}, {0x3f936000}, 
+    {0x3f938000}, {0x3f93a000}, {0x3f93c000}, {0x3f93e000}, 
+    {0x3f940000}, {0x3f942000}, {0x3f944000}, {0x3f946000}, 
+    {0x3f948000}, {0x3f94a000}, {0x3f94c000}, {0x3f94e000}, 
+    {0x3f950000}, {0x3f952000}, {0x3f954000}, {0x3f956000}, 
+    {0x3f958000}, {0x3f95a000}, {0x3f95c000}, {0x3f95e000}, 
+    {0x3f960000}, {0x3f962000}, {0x3f964000}, {0x3f966000}, 
+    {0x3f968000}, {0x3f96a000}, {0x3f96c000}, {0x3f96e000}, 
+    {0x3f970000}, {0x3f972000}, {0x3f974000}, {0x3f976000}, 
+    {0x3f978000}, {0x3f97a000}, {0x3f97c000}, {0x3f97e000}, 
+    {0x3f980000}, {0x3f982000}, {0x3f984000}, {0x3f986000}, 
+    {0x3f988000}, {0x3f98a000}, {0x3f98c000}, {0x3f98e000}, 
+    {0x3f990000}, {0x3f992000}, {0x3f994000}, {0x3f996000}, 
+    {0x3f998000}, {0x3f99a000}, {0x3f99c000}, {0x3f99e000}, 
+    {0x3f9a0000}, {0x3f9a2000}, {0x3f9a4000}, {0x3f9a6000}, 
+    {0x3f9a8000}, {0x3f9aa000}, {0x3f9ac000}, {0x3f9ae000}, 
+    {0x3f9b0000}, {0x3f9b2000}, {0x3f9b4000}, {0x3f9b6000}, 
+    {0x3f9b8000}, {0x3f9ba000}, {0x3f9bc000}, {0x3f9be000}, 
+    {0x3f9c0000}, {0x3f9c2000}, {0x3f9c4000}, {0x3f9c6000}, 
+    {0x3f9c8000}, {0x3f9ca000}, {0x3f9cc000}, {0x3f9ce000}, 
+    {0x3f9d0000}, {0x3f9d2000}, {0x3f9d4000}, {0x3f9d6000}, 
+    {0x3f9d8000}, {0x3f9da000}, {0x3f9dc000}, {0x3f9de000}, 
+    {0x3f9e0000}, {0x3f9e2000}, {0x3f9e4000}, {0x3f9e6000}, 
+    {0x3f9e8000}, {0x3f9ea000}, {0x3f9ec000}, {0x3f9ee000}, 
+    {0x3f9f0000}, {0x3f9f2000}, {0x3f9f4000}, {0x3f9f6000}, 
+    {0x3f9f8000}, {0x3f9fa000}, {0x3f9fc000}, {0x3f9fe000}, 
+    {0x3fa00000}, {0x3fa02000}, {0x3fa04000}, {0x3fa06000}, 
+    {0x3fa08000}, {0x3fa0a000}, {0x3fa0c000}, {0x3fa0e000}, 
+    {0x3fa10000}, {0x3fa12000}, {0x3fa14000}, {0x3fa16000}, 
+    {0x3fa18000}, {0x3fa1a000}, {0x3fa1c000}, {0x3fa1e000}, 
+    {0x3fa20000}, {0x3fa22000}, {0x3fa24000}, {0x3fa26000}, 
+    {0x3fa28000}, {0x3fa2a000}, {0x3fa2c000}, {0x3fa2e000}, 
+    {0x3fa30000}, {0x3fa32000}, {0x3fa34000}, {0x3fa36000}, 
+    {0x3fa38000}, {0x3fa3a000}, {0x3fa3c000}, {0x3fa3e000}, 
+    {0x3fa40000}, {0x3fa42000}, {0x3fa44000}, {0x3fa46000}, 
+    {0x3fa48000}, {0x3fa4a000}, {0x3fa4c000}, {0x3fa4e000}, 
+    {0x3fa50000}, {0x3fa52000}, {0x3fa54000}, {0x3fa56000}, 
+    {0x3fa58000}, {0x3fa5a000}, {0x3fa5c000}, {0x3fa5e000}, 
+    {0x3fa60000}, {0x3fa62000}, {0x3fa64000}, {0x3fa66000}, 
+    {0x3fa68000}, {0x3fa6a000}, {0x3fa6c000}, {0x3fa6e000}, 
+    {0x3fa70000}, {0x3fa72000}, {0x3fa74000}, {0x3fa76000}, 
+    {0x3fa78000}, {0x3fa7a000}, {0x3fa7c000}, {0x3fa7e000}, 
+    {0x3fa80000}, {0x3fa82000}, {0x3fa84000}, {0x3fa86000}, 
+    {0x3fa88000}, {0x3fa8a000}, {0x3fa8c000}, {0x3fa8e000}, 
+    {0x3fa90000}, {0x3fa92000}, {0x3fa94000}, {0x3fa96000}, 
+    {0x3fa98000}, {0x3fa9a000}, {0x3fa9c000}, {0x3fa9e000}, 
+    {0x3faa0000}, {0x3faa2000}, {0x3faa4000}, {0x3faa6000}, 
+    {0x3faa8000}, {0x3faaa000}, {0x3faac000}, {0x3faae000}, 
+    {0x3fab0000}, {0x3fab2000}, {0x3fab4000}, {0x3fab6000}, 
+    {0x3fab8000}, {0x3faba000}, {0x3fabc000}, {0x3fabe000}, 
+    {0x3fac0000}, {0x3fac2000}, {0x3fac4000}, {0x3fac6000}, 
+    {0x3fac8000}, {0x3faca000}, {0x3facc000}, {0x3face000}, 
+    {0x3fad0000}, {0x3fad2000}, {0x3fad4000}, {0x3fad6000}, 
+    {0x3fad8000}, {0x3fada000}, {0x3fadc000}, {0x3fade000}, 
+    {0x3fae0000}, {0x3fae2000}, {0x3fae4000}, {0x3fae6000}, 
+    {0x3fae8000}, {0x3faea000}, {0x3faec000}, {0x3faee000}, 
+    {0x3faf0000}, {0x3faf2000}, {0x3faf4000}, {0x3faf6000}, 
+    {0x3faf8000}, {0x3fafa000}, {0x3fafc000}, {0x3fafe000}, 
+    {0x3fb00000}, {0x3fb02000}, {0x3fb04000}, {0x3fb06000}, 
+    {0x3fb08000}, {0x3fb0a000}, {0x3fb0c000}, {0x3fb0e000}, 
+    {0x3fb10000}, {0x3fb12000}, {0x3fb14000}, {0x3fb16000}, 
+    {0x3fb18000}, {0x3fb1a000}, {0x3fb1c000}, {0x3fb1e000}, 
+    {0x3fb20000}, {0x3fb22000}, {0x3fb24000}, {0x3fb26000}, 
+    {0x3fb28000}, {0x3fb2a000}, {0x3fb2c000}, {0x3fb2e000}, 
+    {0x3fb30000}, {0x3fb32000}, {0x3fb34000}, {0x3fb36000}, 
+    {0x3fb38000}, {0x3fb3a000}, {0x3fb3c000}, {0x3fb3e000}, 
+    {0x3fb40000}, {0x3fb42000}, {0x3fb44000}, {0x3fb46000}, 
+    {0x3fb48000}, {0x3fb4a000}, {0x3fb4c000}, {0x3fb4e000}, 
+    {0x3fb50000}, {0x3fb52000}, {0x3fb54000}, {0x3fb56000}, 
+    {0x3fb58000}, {0x3fb5a000}, {0x3fb5c000}, {0x3fb5e000}, 
+    {0x3fb60000}, {0x3fb62000}, {0x3fb64000}, {0x3fb66000}, 
+    {0x3fb68000}, {0x3fb6a000}, {0x3fb6c000}, {0x3fb6e000}, 
+    {0x3fb70000}, {0x3fb72000}, {0x3fb74000}, {0x3fb76000}, 
+    {0x3fb78000}, {0x3fb7a000}, {0x3fb7c000}, {0x3fb7e000}, 
+    {0x3fb80000}, {0x3fb82000}, {0x3fb84000}, {0x3fb86000}, 
+    {0x3fb88000}, {0x3fb8a000}, {0x3fb8c000}, {0x3fb8e000}, 
+    {0x3fb90000}, {0x3fb92000}, {0x3fb94000}, {0x3fb96000}, 
+    {0x3fb98000}, {0x3fb9a000}, {0x3fb9c000}, {0x3fb9e000}, 
+    {0x3fba0000}, {0x3fba2000}, {0x3fba4000}, {0x3fba6000}, 
+    {0x3fba8000}, {0x3fbaa000}, {0x3fbac000}, {0x3fbae000}, 
+    {0x3fbb0000}, {0x3fbb2000}, {0x3fbb4000}, {0x3fbb6000}, 
+    {0x3fbb8000}, {0x3fbba000}, {0x3fbbc000}, {0x3fbbe000}, 
+    {0x3fbc0000}, {0x3fbc2000}, {0x3fbc4000}, {0x3fbc6000}, 
+    {0x3fbc8000}, {0x3fbca000}, {0x3fbcc000}, {0x3fbce000}, 
+    {0x3fbd0000}, {0x3fbd2000}, {0x3fbd4000}, {0x3fbd6000}, 
+    {0x3fbd8000}, {0x3fbda000}, {0x3fbdc000}, {0x3fbde000}, 
+    {0x3fbe0000}, {0x3fbe2000}, {0x3fbe4000}, {0x3fbe6000}, 
+    {0x3fbe8000}, {0x3fbea000}, {0x3fbec000}, {0x3fbee000}, 
+    {0x3fbf0000}, {0x3fbf2000}, {0x3fbf4000}, {0x3fbf6000}, 
+    {0x3fbf8000}, {0x3fbfa000}, {0x3fbfc000}, {0x3fbfe000}, 
+    {0x3fc00000}, {0x3fc02000}, {0x3fc04000}, {0x3fc06000}, 
+    {0x3fc08000}, {0x3fc0a000}, {0x3fc0c000}, {0x3fc0e000}, 
+    {0x3fc10000}, {0x3fc12000}, {0x3fc14000}, {0x3fc16000}, 
+    {0x3fc18000}, {0x3fc1a000}, {0x3fc1c000}, {0x3fc1e000}, 
+    {0x3fc20000}, {0x3fc22000}, {0x3fc24000}, {0x3fc26000}, 
+    {0x3fc28000}, {0x3fc2a000}, {0x3fc2c000}, {0x3fc2e000}, 
+    {0x3fc30000}, {0x3fc32000}, {0x3fc34000}, {0x3fc36000}, 
+    {0x3fc38000}, {0x3fc3a000}, {0x3fc3c000}, {0x3fc3e000}, 
+    {0x3fc40000}, {0x3fc42000}, {0x3fc44000}, {0x3fc46000}, 
+    {0x3fc48000}, {0x3fc4a000}, {0x3fc4c000}, {0x3fc4e000}, 
+    {0x3fc50000}, {0x3fc52000}, {0x3fc54000}, {0x3fc56000}, 
+    {0x3fc58000}, {0x3fc5a000}, {0x3fc5c000}, {0x3fc5e000}, 
+    {0x3fc60000}, {0x3fc62000}, {0x3fc64000}, {0x3fc66000}, 
+    {0x3fc68000}, {0x3fc6a000}, {0x3fc6c000}, {0x3fc6e000}, 
+    {0x3fc70000}, {0x3fc72000}, {0x3fc74000}, {0x3fc76000}, 
+    {0x3fc78000}, {0x3fc7a000}, {0x3fc7c000}, {0x3fc7e000}, 
+    {0x3fc80000}, {0x3fc82000}, {0x3fc84000}, {0x3fc86000}, 
+    {0x3fc88000}, {0x3fc8a000}, {0x3fc8c000}, {0x3fc8e000}, 
+    {0x3fc90000}, {0x3fc92000}, {0x3fc94000}, {0x3fc96000}, 
+    {0x3fc98000}, {0x3fc9a000}, {0x3fc9c000}, {0x3fc9e000}, 
+    {0x3fca0000}, {0x3fca2000}, {0x3fca4000}, {0x3fca6000}, 
+    {0x3fca8000}, {0x3fcaa000}, {0x3fcac000}, {0x3fcae000}, 
+    {0x3fcb0000}, {0x3fcb2000}, {0x3fcb4000}, {0x3fcb6000}, 
+    {0x3fcb8000}, {0x3fcba000}, {0x3fcbc000}, {0x3fcbe000}, 
+    {0x3fcc0000}, {0x3fcc2000}, {0x3fcc4000}, {0x3fcc6000}, 
+    {0x3fcc8000}, {0x3fcca000}, {0x3fccc000}, {0x3fcce000}, 
+    {0x3fcd0000}, {0x3fcd2000}, {0x3fcd4000}, {0x3fcd6000}, 
+    {0x3fcd8000}, {0x3fcda000}, {0x3fcdc000}, {0x3fcde000}, 
+    {0x3fce0000}, {0x3fce2000}, {0x3fce4000}, {0x3fce6000}, 
+    {0x3fce8000}, {0x3fcea000}, {0x3fcec000}, {0x3fcee000}, 
+    {0x3fcf0000}, {0x3fcf2000}, {0x3fcf4000}, {0x3fcf6000}, 
+    {0x3fcf8000}, {0x3fcfa000}, {0x3fcfc000}, {0x3fcfe000}, 
+    {0x3fd00000}, {0x3fd02000}, {0x3fd04000}, {0x3fd06000}, 
+    {0x3fd08000}, {0x3fd0a000}, {0x3fd0c000}, {0x3fd0e000}, 
+    {0x3fd10000}, {0x3fd12000}, {0x3fd14000}, {0x3fd16000}, 
+    {0x3fd18000}, {0x3fd1a000}, {0x3fd1c000}, {0x3fd1e000}, 
+    {0x3fd20000}, {0x3fd22000}, {0x3fd24000}, {0x3fd26000}, 
+    {0x3fd28000}, {0x3fd2a000}, {0x3fd2c000}, {0x3fd2e000}, 
+    {0x3fd30000}, {0x3fd32000}, {0x3fd34000}, {0x3fd36000}, 
+    {0x3fd38000}, {0x3fd3a000}, {0x3fd3c000}, {0x3fd3e000}, 
+    {0x3fd40000}, {0x3fd42000}, {0x3fd44000}, {0x3fd46000}, 
+    {0x3fd48000}, {0x3fd4a000}, {0x3fd4c000}, {0x3fd4e000}, 
+    {0x3fd50000}, {0x3fd52000}, {0x3fd54000}, {0x3fd56000}, 
+    {0x3fd58000}, {0x3fd5a000}, {0x3fd5c000}, {0x3fd5e000}, 
+    {0x3fd60000}, {0x3fd62000}, {0x3fd64000}, {0x3fd66000}, 
+    {0x3fd68000}, {0x3fd6a000}, {0x3fd6c000}, {0x3fd6e000}, 
+    {0x3fd70000}, {0x3fd72000}, {0x3fd74000}, {0x3fd76000}, 
+    {0x3fd78000}, {0x3fd7a000}, {0x3fd7c000}, {0x3fd7e000}, 
+    {0x3fd80000}, {0x3fd82000}, {0x3fd84000}, {0x3fd86000}, 
+    {0x3fd88000}, {0x3fd8a000}, {0x3fd8c000}, {0x3fd8e000}, 
+    {0x3fd90000}, {0x3fd92000}, {0x3fd94000}, {0x3fd96000}, 
+    {0x3fd98000}, {0x3fd9a000}, {0x3fd9c000}, {0x3fd9e000}, 
+    {0x3fda0000}, {0x3fda2000}, {0x3fda4000}, {0x3fda6000}, 
+    {0x3fda8000}, {0x3fdaa000}, {0x3fdac000}, {0x3fdae000}, 
+    {0x3fdb0000}, {0x3fdb2000}, {0x3fdb4000}, {0x3fdb6000}, 
+    {0x3fdb8000}, {0x3fdba000}, {0x3fdbc000}, {0x3fdbe000}, 
+    {0x3fdc0000}, {0x3fdc2000}, {0x3fdc4000}, {0x3fdc6000}, 
+    {0x3fdc8000}, {0x3fdca000}, {0x3fdcc000}, {0x3fdce000}, 
+    {0x3fdd0000}, {0x3fdd2000}, {0x3fdd4000}, {0x3fdd6000}, 
+    {0x3fdd8000}, {0x3fdda000}, {0x3fddc000}, {0x3fdde000}, 
+    {0x3fde0000}, {0x3fde2000}, {0x3fde4000}, {0x3fde6000}, 
+    {0x3fde8000}, {0x3fdea000}, {0x3fdec000}, {0x3fdee000}, 
+    {0x3fdf0000}, {0x3fdf2000}, {0x3fdf4000}, {0x3fdf6000}, 
+    {0x3fdf8000}, {0x3fdfa000}, {0x3fdfc000}, {0x3fdfe000}, 
+    {0x3fe00000}, {0x3fe02000}, {0x3fe04000}, {0x3fe06000}, 
+    {0x3fe08000}, {0x3fe0a000}, {0x3fe0c000}, {0x3fe0e000}, 
+    {0x3fe10000}, {0x3fe12000}, {0x3fe14000}, {0x3fe16000}, 
+    {0x3fe18000}, {0x3fe1a000}, {0x3fe1c000}, {0x3fe1e000}, 
+    {0x3fe20000}, {0x3fe22000}, {0x3fe24000}, {0x3fe26000}, 
+    {0x3fe28000}, {0x3fe2a000}, {0x3fe2c000}, {0x3fe2e000}, 
+    {0x3fe30000}, {0x3fe32000}, {0x3fe34000}, {0x3fe36000}, 
+    {0x3fe38000}, {0x3fe3a000}, {0x3fe3c000}, {0x3fe3e000}, 
+    {0x3fe40000}, {0x3fe42000}, {0x3fe44000}, {0x3fe46000}, 
+    {0x3fe48000}, {0x3fe4a000}, {0x3fe4c000}, {0x3fe4e000}, 
+    {0x3fe50000}, {0x3fe52000}, {0x3fe54000}, {0x3fe56000}, 
+    {0x3fe58000}, {0x3fe5a000}, {0x3fe5c000}, {0x3fe5e000}, 
+    {0x3fe60000}, {0x3fe62000}, {0x3fe64000}, {0x3fe66000}, 
+    {0x3fe68000}, {0x3fe6a000}, {0x3fe6c000}, {0x3fe6e000}, 
+    {0x3fe70000}, {0x3fe72000}, {0x3fe74000}, {0x3fe76000}, 
+    {0x3fe78000}, {0x3fe7a000}, {0x3fe7c000}, {0x3fe7e000}, 
+    {0x3fe80000}, {0x3fe82000}, {0x3fe84000}, {0x3fe86000}, 
+    {0x3fe88000}, {0x3fe8a000}, {0x3fe8c000}, {0x3fe8e000}, 
+    {0x3fe90000}, {0x3fe92000}, {0x3fe94000}, {0x3fe96000}, 
+    {0x3fe98000}, {0x3fe9a000}, {0x3fe9c000}, {0x3fe9e000}, 
+    {0x3fea0000}, {0x3fea2000}, {0x3fea4000}, {0x3fea6000}, 
+    {0x3fea8000}, {0x3feaa000}, {0x3feac000}, {0x3feae000}, 
+    {0x3feb0000}, {0x3feb2000}, {0x3feb4000}, {0x3feb6000}, 
+    {0x3feb8000}, {0x3feba000}, {0x3febc000}, {0x3febe000}, 
+    {0x3fec0000}, {0x3fec2000}, {0x3fec4000}, {0x3fec6000}, 
+    {0x3fec8000}, {0x3feca000}, {0x3fecc000}, {0x3fece000}, 
+    {0x3fed0000}, {0x3fed2000}, {0x3fed4000}, {0x3fed6000}, 
+    {0x3fed8000}, {0x3feda000}, {0x3fedc000}, {0x3fede000}, 
+    {0x3fee0000}, {0x3fee2000}, {0x3fee4000}, {0x3fee6000}, 
+    {0x3fee8000}, {0x3feea000}, {0x3feec000}, {0x3feee000}, 
+    {0x3fef0000}, {0x3fef2000}, {0x3fef4000}, {0x3fef6000}, 
+    {0x3fef8000}, {0x3fefa000}, {0x3fefc000}, {0x3fefe000}, 
+    {0x3ff00000}, {0x3ff02000}, {0x3ff04000}, {0x3ff06000}, 
+    {0x3ff08000}, {0x3ff0a000}, {0x3ff0c000}, {0x3ff0e000}, 
+    {0x3ff10000}, {0x3ff12000}, {0x3ff14000}, {0x3ff16000}, 
+    {0x3ff18000}, {0x3ff1a000}, {0x3ff1c000}, {0x3ff1e000}, 
+    {0x3ff20000}, {0x3ff22000}, {0x3ff24000}, {0x3ff26000}, 
+    {0x3ff28000}, {0x3ff2a000}, {0x3ff2c000}, {0x3ff2e000}, 
+    {0x3ff30000}, {0x3ff32000}, {0x3ff34000}, {0x3ff36000}, 
+    {0x3ff38000}, {0x3ff3a000}, {0x3ff3c000}, {0x3ff3e000}, 
+    {0x3ff40000}, {0x3ff42000}, {0x3ff44000}, {0x3ff46000}, 
+    {0x3ff48000}, {0x3ff4a000}, {0x3ff4c000}, {0x3ff4e000}, 
+    {0x3ff50000}, {0x3ff52000}, {0x3ff54000}, {0x3ff56000}, 
+    {0x3ff58000}, {0x3ff5a000}, {0x3ff5c000}, {0x3ff5e000}, 
+    {0x3ff60000}, {0x3ff62000}, {0x3ff64000}, {0x3ff66000}, 
+    {0x3ff68000}, {0x3ff6a000}, {0x3ff6c000}, {0x3ff6e000}, 
+    {0x3ff70000}, {0x3ff72000}, {0x3ff74000}, {0x3ff76000}, 
+    {0x3ff78000}, {0x3ff7a000}, {0x3ff7c000}, {0x3ff7e000}, 
+    {0x3ff80000}, {0x3ff82000}, {0x3ff84000}, {0x3ff86000}, 
+    {0x3ff88000}, {0x3ff8a000}, {0x3ff8c000}, {0x3ff8e000}, 
+    {0x3ff90000}, {0x3ff92000}, {0x3ff94000}, {0x3ff96000}, 
+    {0x3ff98000}, {0x3ff9a000}, {0x3ff9c000}, {0x3ff9e000}, 
+    {0x3ffa0000}, {0x3ffa2000}, {0x3ffa4000}, {0x3ffa6000}, 
+    {0x3ffa8000}, {0x3ffaa000}, {0x3ffac000}, {0x3ffae000}, 
+    {0x3ffb0000}, {0x3ffb2000}, {0x3ffb4000}, {0x3ffb6000}, 
+    {0x3ffb8000}, {0x3ffba000}, {0x3ffbc000}, {0x3ffbe000}, 
+    {0x3ffc0000}, {0x3ffc2000}, {0x3ffc4000}, {0x3ffc6000}, 
+    {0x3ffc8000}, {0x3ffca000}, {0x3ffcc000}, {0x3ffce000}, 
+    {0x3ffd0000}, {0x3ffd2000}, {0x3ffd4000}, {0x3ffd6000}, 
+    {0x3ffd8000}, {0x3ffda000}, {0x3ffdc000}, {0x3ffde000}, 
+    {0x3ffe0000}, {0x3ffe2000}, {0x3ffe4000}, {0x3ffe6000}, 
+    {0x3ffe8000}, {0x3ffea000}, {0x3ffec000}, {0x3ffee000}, 
+    {0x3fff0000}, {0x3fff2000}, {0x3fff4000}, {0x3fff6000}, 
+    {0x3fff8000}, {0x3fffa000}, {0x3fffc000}, {0x3fffe000}, 
+    {0x40000000}, {0x40002000}, {0x40004000}, {0x40006000}, 
+    {0x40008000}, {0x4000a000}, {0x4000c000}, {0x4000e000}, 
+    {0x40010000}, {0x40012000}, {0x40014000}, {0x40016000}, 
+    {0x40018000}, {0x4001a000}, {0x4001c000}, {0x4001e000}, 
+    {0x40020000}, {0x40022000}, {0x40024000}, {0x40026000}, 
+    {0x40028000}, {0x4002a000}, {0x4002c000}, {0x4002e000}, 
+    {0x40030000}, {0x40032000}, {0x40034000}, {0x40036000}, 
+    {0x40038000}, {0x4003a000}, {0x4003c000}, {0x4003e000}, 
+    {0x40040000}, {0x40042000}, {0x40044000}, {0x40046000}, 
+    {0x40048000}, {0x4004a000}, {0x4004c000}, {0x4004e000}, 
+    {0x40050000}, {0x40052000}, {0x40054000}, {0x40056000}, 
+    {0x40058000}, {0x4005a000}, {0x4005c000}, {0x4005e000}, 
+    {0x40060000}, {0x40062000}, {0x40064000}, {0x40066000}, 
+    {0x40068000}, {0x4006a000}, {0x4006c000}, {0x4006e000}, 
+    {0x40070000}, {0x40072000}, {0x40074000}, {0x40076000}, 
+    {0x40078000}, {0x4007a000}, {0x4007c000}, {0x4007e000}, 
+    {0x40080000}, {0x40082000}, {0x40084000}, {0x40086000}, 
+    {0x40088000}, {0x4008a000}, {0x4008c000}, {0x4008e000}, 
+    {0x40090000}, {0x40092000}, {0x40094000}, {0x40096000}, 
+    {0x40098000}, {0x4009a000}, {0x4009c000}, {0x4009e000}, 
+    {0x400a0000}, {0x400a2000}, {0x400a4000}, {0x400a6000}, 
+    {0x400a8000}, {0x400aa000}, {0x400ac000}, {0x400ae000}, 
+    {0x400b0000}, {0x400b2000}, {0x400b4000}, {0x400b6000}, 
+    {0x400b8000}, {0x400ba000}, {0x400bc000}, {0x400be000}, 
+    {0x400c0000}, {0x400c2000}, {0x400c4000}, {0x400c6000}, 
+    {0x400c8000}, {0x400ca000}, {0x400cc000}, {0x400ce000}, 
+    {0x400d0000}, {0x400d2000}, {0x400d4000}, {0x400d6000}, 
+    {0x400d8000}, {0x400da000}, {0x400dc000}, {0x400de000}, 
+    {0x400e0000}, {0x400e2000}, {0x400e4000}, {0x400e6000}, 
+    {0x400e8000}, {0x400ea000}, {0x400ec000}, {0x400ee000}, 
+    {0x400f0000}, {0x400f2000}, {0x400f4000}, {0x400f6000}, 
+    {0x400f8000}, {0x400fa000}, {0x400fc000}, {0x400fe000}, 
+    {0x40100000}, {0x40102000}, {0x40104000}, {0x40106000}, 
+    {0x40108000}, {0x4010a000}, {0x4010c000}, {0x4010e000}, 
+    {0x40110000}, {0x40112000}, {0x40114000}, {0x40116000}, 
+    {0x40118000}, {0x4011a000}, {0x4011c000}, {0x4011e000}, 
+    {0x40120000}, {0x40122000}, {0x40124000}, {0x40126000}, 
+    {0x40128000}, {0x4012a000}, {0x4012c000}, {0x4012e000}, 
+    {0x40130000}, {0x40132000}, {0x40134000}, {0x40136000}, 
+    {0x40138000}, {0x4013a000}, {0x4013c000}, {0x4013e000}, 
+    {0x40140000}, {0x40142000}, {0x40144000}, {0x40146000}, 
+    {0x40148000}, {0x4014a000}, {0x4014c000}, {0x4014e000}, 
+    {0x40150000}, {0x40152000}, {0x40154000}, {0x40156000}, 
+    {0x40158000}, {0x4015a000}, {0x4015c000}, {0x4015e000}, 
+    {0x40160000}, {0x40162000}, {0x40164000}, {0x40166000}, 
+    {0x40168000}, {0x4016a000}, {0x4016c000}, {0x4016e000}, 
+    {0x40170000}, {0x40172000}, {0x40174000}, {0x40176000}, 
+    {0x40178000}, {0x4017a000}, {0x4017c000}, {0x4017e000}, 
+    {0x40180000}, {0x40182000}, {0x40184000}, {0x40186000}, 
+    {0x40188000}, {0x4018a000}, {0x4018c000}, {0x4018e000}, 
+    {0x40190000}, {0x40192000}, {0x40194000}, {0x40196000}, 
+    {0x40198000}, {0x4019a000}, {0x4019c000}, {0x4019e000}, 
+    {0x401a0000}, {0x401a2000}, {0x401a4000}, {0x401a6000}, 
+    {0x401a8000}, {0x401aa000}, {0x401ac000}, {0x401ae000}, 
+    {0x401b0000}, {0x401b2000}, {0x401b4000}, {0x401b6000}, 
+    {0x401b8000}, {0x401ba000}, {0x401bc000}, {0x401be000}, 
+    {0x401c0000}, {0x401c2000}, {0x401c4000}, {0x401c6000}, 
+    {0x401c8000}, {0x401ca000}, {0x401cc000}, {0x401ce000}, 
+    {0x401d0000}, {0x401d2000}, {0x401d4000}, {0x401d6000}, 
+    {0x401d8000}, {0x401da000}, {0x401dc000}, {0x401de000}, 
+    {0x401e0000}, {0x401e2000}, {0x401e4000}, {0x401e6000}, 
+    {0x401e8000}, {0x401ea000}, {0x401ec000}, {0x401ee000}, 
+    {0x401f0000}, {0x401f2000}, {0x401f4000}, {0x401f6000}, 
+    {0x401f8000}, {0x401fa000}, {0x401fc000}, {0x401fe000}, 
+    {0x40200000}, {0x40202000}, {0x40204000}, {0x40206000}, 
+    {0x40208000}, {0x4020a000}, {0x4020c000}, {0x4020e000}, 
+    {0x40210000}, {0x40212000}, {0x40214000}, {0x40216000}, 
+    {0x40218000}, {0x4021a000}, {0x4021c000}, {0x4021e000}, 
+    {0x40220000}, {0x40222000}, {0x40224000}, {0x40226000}, 
+    {0x40228000}, {0x4022a000}, {0x4022c000}, {0x4022e000}, 
+    {0x40230000}, {0x40232000}, {0x40234000}, {0x40236000}, 
+    {0x40238000}, {0x4023a000}, {0x4023c000}, {0x4023e000}, 
+    {0x40240000}, {0x40242000}, {0x40244000}, {0x40246000}, 
+    {0x40248000}, {0x4024a000}, {0x4024c000}, {0x4024e000}, 
+    {0x40250000}, {0x40252000}, {0x40254000}, {0x40256000}, 
+    {0x40258000}, {0x4025a000}, {0x4025c000}, {0x4025e000}, 
+    {0x40260000}, {0x40262000}, {0x40264000}, {0x40266000}, 
+    {0x40268000}, {0x4026a000}, {0x4026c000}, {0x4026e000}, 
+    {0x40270000}, {0x40272000}, {0x40274000}, {0x40276000}, 
+    {0x40278000}, {0x4027a000}, {0x4027c000}, {0x4027e000}, 
+    {0x40280000}, {0x40282000}, {0x40284000}, {0x40286000}, 
+    {0x40288000}, {0x4028a000}, {0x4028c000}, {0x4028e000}, 
+    {0x40290000}, {0x40292000}, {0x40294000}, {0x40296000}, 
+    {0x40298000}, {0x4029a000}, {0x4029c000}, {0x4029e000}, 
+    {0x402a0000}, {0x402a2000}, {0x402a4000}, {0x402a6000}, 
+    {0x402a8000}, {0x402aa000}, {0x402ac000}, {0x402ae000}, 
+    {0x402b0000}, {0x402b2000}, {0x402b4000}, {0x402b6000}, 
+    {0x402b8000}, {0x402ba000}, {0x402bc000}, {0x402be000}, 
+    {0x402c0000}, {0x402c2000}, {0x402c4000}, {0x402c6000}, 
+    {0x402c8000}, {0x402ca000}, {0x402cc000}, {0x402ce000}, 
+    {0x402d0000}, {0x402d2000}, {0x402d4000}, {0x402d6000}, 
+    {0x402d8000}, {0x402da000}, {0x402dc000}, {0x402de000}, 
+    {0x402e0000}, {0x402e2000}, {0x402e4000}, {0x402e6000}, 
+    {0x402e8000}, {0x402ea000}, {0x402ec000}, {0x402ee000}, 
+    {0x402f0000}, {0x402f2000}, {0x402f4000}, {0x402f6000}, 
+    {0x402f8000}, {0x402fa000}, {0x402fc000}, {0x402fe000}, 
+    {0x40300000}, {0x40302000}, {0x40304000}, {0x40306000}, 
+    {0x40308000}, {0x4030a000}, {0x4030c000}, {0x4030e000}, 
+    {0x40310000}, {0x40312000}, {0x40314000}, {0x40316000}, 
+    {0x40318000}, {0x4031a000}, {0x4031c000}, {0x4031e000}, 
+    {0x40320000}, {0x40322000}, {0x40324000}, {0x40326000}, 
+    {0x40328000}, {0x4032a000}, {0x4032c000}, {0x4032e000}, 
+    {0x40330000}, {0x40332000}, {0x40334000}, {0x40336000}, 
+    {0x40338000}, {0x4033a000}, {0x4033c000}, {0x4033e000}, 
+    {0x40340000}, {0x40342000}, {0x40344000}, {0x40346000}, 
+    {0x40348000}, {0x4034a000}, {0x4034c000}, {0x4034e000}, 
+    {0x40350000}, {0x40352000}, {0x40354000}, {0x40356000}, 
+    {0x40358000}, {0x4035a000}, {0x4035c000}, {0x4035e000}, 
+    {0x40360000}, {0x40362000}, {0x40364000}, {0x40366000}, 
+    {0x40368000}, {0x4036a000}, {0x4036c000}, {0x4036e000}, 
+    {0x40370000}, {0x40372000}, {0x40374000}, {0x40376000}, 
+    {0x40378000}, {0x4037a000}, {0x4037c000}, {0x4037e000}, 
+    {0x40380000}, {0x40382000}, {0x40384000}, {0x40386000}, 
+    {0x40388000}, {0x4038a000}, {0x4038c000}, {0x4038e000}, 
+    {0x40390000}, {0x40392000}, {0x40394000}, {0x40396000}, 
+    {0x40398000}, {0x4039a000}, {0x4039c000}, {0x4039e000}, 
+    {0x403a0000}, {0x403a2000}, {0x403a4000}, {0x403a6000}, 
+    {0x403a8000}, {0x403aa000}, {0x403ac000}, {0x403ae000}, 
+    {0x403b0000}, {0x403b2000}, {0x403b4000}, {0x403b6000}, 
+    {0x403b8000}, {0x403ba000}, {0x403bc000}, {0x403be000}, 
+    {0x403c0000}, {0x403c2000}, {0x403c4000}, {0x403c6000}, 
+    {0x403c8000}, {0x403ca000}, {0x403cc000}, {0x403ce000}, 
+    {0x403d0000}, {0x403d2000}, {0x403d4000}, {0x403d6000}, 
+    {0x403d8000}, {0x403da000}, {0x403dc000}, {0x403de000}, 
+    {0x403e0000}, {0x403e2000}, {0x403e4000}, {0x403e6000}, 
+    {0x403e8000}, {0x403ea000}, {0x403ec000}, {0x403ee000}, 
+    {0x403f0000}, {0x403f2000}, {0x403f4000}, {0x403f6000}, 
+    {0x403f8000}, {0x403fa000}, {0x403fc000}, {0x403fe000}, 
+    {0x40400000}, {0x40402000}, {0x40404000}, {0x40406000}, 
+    {0x40408000}, {0x4040a000}, {0x4040c000}, {0x4040e000}, 
+    {0x40410000}, {0x40412000}, {0x40414000}, {0x40416000}, 
+    {0x40418000}, {0x4041a000}, {0x4041c000}, {0x4041e000}, 
+    {0x40420000}, {0x40422000}, {0x40424000}, {0x40426000}, 
+    {0x40428000}, {0x4042a000}, {0x4042c000}, {0x4042e000}, 
+    {0x40430000}, {0x40432000}, {0x40434000}, {0x40436000}, 
+    {0x40438000}, {0x4043a000}, {0x4043c000}, {0x4043e000}, 
+    {0x40440000}, {0x40442000}, {0x40444000}, {0x40446000}, 
+    {0x40448000}, {0x4044a000}, {0x4044c000}, {0x4044e000}, 
+    {0x40450000}, {0x40452000}, {0x40454000}, {0x40456000}, 
+    {0x40458000}, {0x4045a000}, {0x4045c000}, {0x4045e000}, 
+    {0x40460000}, {0x40462000}, {0x40464000}, {0x40466000}, 
+    {0x40468000}, {0x4046a000}, {0x4046c000}, {0x4046e000}, 
+    {0x40470000}, {0x40472000}, {0x40474000}, {0x40476000}, 
+    {0x40478000}, {0x4047a000}, {0x4047c000}, {0x4047e000}, 
+    {0x40480000}, {0x40482000}, {0x40484000}, {0x40486000}, 
+    {0x40488000}, {0x4048a000}, {0x4048c000}, {0x4048e000}, 
+    {0x40490000}, {0x40492000}, {0x40494000}, {0x40496000}, 
+    {0x40498000}, {0x4049a000}, {0x4049c000}, {0x4049e000}, 
+    {0x404a0000}, {0x404a2000}, {0x404a4000}, {0x404a6000}, 
+    {0x404a8000}, {0x404aa000}, {0x404ac000}, {0x404ae000}, 
+    {0x404b0000}, {0x404b2000}, {0x404b4000}, {0x404b6000}, 
+    {0x404b8000}, {0x404ba000}, {0x404bc000}, {0x404be000}, 
+    {0x404c0000}, {0x404c2000}, {0x404c4000}, {0x404c6000}, 
+    {0x404c8000}, {0x404ca000}, {0x404cc000}, {0x404ce000}, 
+    {0x404d0000}, {0x404d2000}, {0x404d4000}, {0x404d6000}, 
+    {0x404d8000}, {0x404da000}, {0x404dc000}, {0x404de000}, 
+    {0x404e0000}, {0x404e2000}, {0x404e4000}, {0x404e6000}, 
+    {0x404e8000}, {0x404ea000}, {0x404ec000}, {0x404ee000}, 
+    {0x404f0000}, {0x404f2000}, {0x404f4000}, {0x404f6000}, 
+    {0x404f8000}, {0x404fa000}, {0x404fc000}, {0x404fe000}, 
+    {0x40500000}, {0x40502000}, {0x40504000}, {0x40506000}, 
+    {0x40508000}, {0x4050a000}, {0x4050c000}, {0x4050e000}, 
+    {0x40510000}, {0x40512000}, {0x40514000}, {0x40516000}, 
+    {0x40518000}, {0x4051a000}, {0x4051c000}, {0x4051e000}, 
+    {0x40520000}, {0x40522000}, {0x40524000}, {0x40526000}, 
+    {0x40528000}, {0x4052a000}, {0x4052c000}, {0x4052e000}, 
+    {0x40530000}, {0x40532000}, {0x40534000}, {0x40536000}, 
+    {0x40538000}, {0x4053a000}, {0x4053c000}, {0x4053e000}, 
+    {0x40540000}, {0x40542000}, {0x40544000}, {0x40546000}, 
+    {0x40548000}, {0x4054a000}, {0x4054c000}, {0x4054e000}, 
+    {0x40550000}, {0x40552000}, {0x40554000}, {0x40556000}, 
+    {0x40558000}, {0x4055a000}, {0x4055c000}, {0x4055e000}, 
+    {0x40560000}, {0x40562000}, {0x40564000}, {0x40566000}, 
+    {0x40568000}, {0x4056a000}, {0x4056c000}, {0x4056e000}, 
+    {0x40570000}, {0x40572000}, {0x40574000}, {0x40576000}, 
+    {0x40578000}, {0x4057a000}, {0x4057c000}, {0x4057e000}, 
+    {0x40580000}, {0x40582000}, {0x40584000}, {0x40586000}, 
+    {0x40588000}, {0x4058a000}, {0x4058c000}, {0x4058e000}, 
+    {0x40590000}, {0x40592000}, {0x40594000}, {0x40596000}, 
+    {0x40598000}, {0x4059a000}, {0x4059c000}, {0x4059e000}, 
+    {0x405a0000}, {0x405a2000}, {0x405a4000}, {0x405a6000}, 
+    {0x405a8000}, {0x405aa000}, {0x405ac000}, {0x405ae000}, 
+    {0x405b0000}, {0x405b2000}, {0x405b4000}, {0x405b6000}, 
+    {0x405b8000}, {0x405ba000}, {0x405bc000}, {0x405be000}, 
+    {0x405c0000}, {0x405c2000}, {0x405c4000}, {0x405c6000}, 
+    {0x405c8000}, {0x405ca000}, {0x405cc000}, {0x405ce000}, 
+    {0x405d0000}, {0x405d2000}, {0x405d4000}, {0x405d6000}, 
+    {0x405d8000}, {0x405da000}, {0x405dc000}, {0x405de000}, 
+    {0x405e0000}, {0x405e2000}, {0x405e4000}, {0x405e6000}, 
+    {0x405e8000}, {0x405ea000}, {0x405ec000}, {0x405ee000}, 
+    {0x405f0000}, {0x405f2000}, {0x405f4000}, {0x405f6000}, 
+    {0x405f8000}, {0x405fa000}, {0x405fc000}, {0x405fe000}, 
+    {0x40600000}, {0x40602000}, {0x40604000}, {0x40606000}, 
+    {0x40608000}, {0x4060a000}, {0x4060c000}, {0x4060e000}, 
+    {0x40610000}, {0x40612000}, {0x40614000}, {0x40616000}, 
+    {0x40618000}, {0x4061a000}, {0x4061c000}, {0x4061e000}, 
+    {0x40620000}, {0x40622000}, {0x40624000}, {0x40626000}, 
+    {0x40628000}, {0x4062a000}, {0x4062c000}, {0x4062e000}, 
+    {0x40630000}, {0x40632000}, {0x40634000}, {0x40636000}, 
+    {0x40638000}, {0x4063a000}, {0x4063c000}, {0x4063e000}, 
+    {0x40640000}, {0x40642000}, {0x40644000}, {0x40646000}, 
+    {0x40648000}, {0x4064a000}, {0x4064c000}, {0x4064e000}, 
+    {0x40650000}, {0x40652000}, {0x40654000}, {0x40656000}, 
+    {0x40658000}, {0x4065a000}, {0x4065c000}, {0x4065e000}, 
+    {0x40660000}, {0x40662000}, {0x40664000}, {0x40666000}, 
+    {0x40668000}, {0x4066a000}, {0x4066c000}, {0x4066e000}, 
+    {0x40670000}, {0x40672000}, {0x40674000}, {0x40676000}, 
+    {0x40678000}, {0x4067a000}, {0x4067c000}, {0x4067e000}, 
+    {0x40680000}, {0x40682000}, {0x40684000}, {0x40686000}, 
+    {0x40688000}, {0x4068a000}, {0x4068c000}, {0x4068e000}, 
+    {0x40690000}, {0x40692000}, {0x40694000}, {0x40696000}, 
+    {0x40698000}, {0x4069a000}, {0x4069c000}, {0x4069e000}, 
+    {0x406a0000}, {0x406a2000}, {0x406a4000}, {0x406a6000}, 
+    {0x406a8000}, {0x406aa000}, {0x406ac000}, {0x406ae000}, 
+    {0x406b0000}, {0x406b2000}, {0x406b4000}, {0x406b6000}, 
+    {0x406b8000}, {0x406ba000}, {0x406bc000}, {0x406be000}, 
+    {0x406c0000}, {0x406c2000}, {0x406c4000}, {0x406c6000}, 
+    {0x406c8000}, {0x406ca000}, {0x406cc000}, {0x406ce000}, 
+    {0x406d0000}, {0x406d2000}, {0x406d4000}, {0x406d6000}, 
+    {0x406d8000}, {0x406da000}, {0x406dc000}, {0x406de000}, 
+    {0x406e0000}, {0x406e2000}, {0x406e4000}, {0x406e6000}, 
+    {0x406e8000}, {0x406ea000}, {0x406ec000}, {0x406ee000}, 
+    {0x406f0000}, {0x406f2000}, {0x406f4000}, {0x406f6000}, 
+    {0x406f8000}, {0x406fa000}, {0x406fc000}, {0x406fe000}, 
+    {0x40700000}, {0x40702000}, {0x40704000}, {0x40706000}, 
+    {0x40708000}, {0x4070a000}, {0x4070c000}, {0x4070e000}, 
+    {0x40710000}, {0x40712000}, {0x40714000}, {0x40716000}, 
+    {0x40718000}, {0x4071a000}, {0x4071c000}, {0x4071e000}, 
+    {0x40720000}, {0x40722000}, {0x40724000}, {0x40726000}, 
+    {0x40728000}, {0x4072a000}, {0x4072c000}, {0x4072e000}, 
+    {0x40730000}, {0x40732000}, {0x40734000}, {0x40736000}, 
+    {0x40738000}, {0x4073a000}, {0x4073c000}, {0x4073e000}, 
+    {0x40740000}, {0x40742000}, {0x40744000}, {0x40746000}, 
+    {0x40748000}, {0x4074a000}, {0x4074c000}, {0x4074e000}, 
+    {0x40750000}, {0x40752000}, {0x40754000}, {0x40756000}, 
+    {0x40758000}, {0x4075a000}, {0x4075c000}, {0x4075e000}, 
+    {0x40760000}, {0x40762000}, {0x40764000}, {0x40766000}, 
+    {0x40768000}, {0x4076a000}, {0x4076c000}, {0x4076e000}, 
+    {0x40770000}, {0x40772000}, {0x40774000}, {0x40776000}, 
+    {0x40778000}, {0x4077a000}, {0x4077c000}, {0x4077e000}, 
+    {0x40780000}, {0x40782000}, {0x40784000}, {0x40786000}, 
+    {0x40788000}, {0x4078a000}, {0x4078c000}, {0x4078e000}, 
+    {0x40790000}, {0x40792000}, {0x40794000}, {0x40796000}, 
+    {0x40798000}, {0x4079a000}, {0x4079c000}, {0x4079e000}, 
+    {0x407a0000}, {0x407a2000}, {0x407a4000}, {0x407a6000}, 
+    {0x407a8000}, {0x407aa000}, {0x407ac000}, {0x407ae000}, 
+    {0x407b0000}, {0x407b2000}, {0x407b4000}, {0x407b6000}, 
+    {0x407b8000}, {0x407ba000}, {0x407bc000}, {0x407be000}, 
+    {0x407c0000}, {0x407c2000}, {0x407c4000}, {0x407c6000}, 
+    {0x407c8000}, {0x407ca000}, {0x407cc000}, {0x407ce000}, 
+    {0x407d0000}, {0x407d2000}, {0x407d4000}, {0x407d6000}, 
+    {0x407d8000}, {0x407da000}, {0x407dc000}, {0x407de000}, 
+    {0x407e0000}, {0x407e2000}, {0x407e4000}, {0x407e6000}, 
+    {0x407e8000}, {0x407ea000}, {0x407ec000}, {0x407ee000}, 
+    {0x407f0000}, {0x407f2000}, {0x407f4000}, {0x407f6000}, 
+    {0x407f8000}, {0x407fa000}, {0x407fc000}, {0x407fe000}, 
+    {0x40800000}, {0x40802000}, {0x40804000}, {0x40806000}, 
+    {0x40808000}, {0x4080a000}, {0x4080c000}, {0x4080e000}, 
+    {0x40810000}, {0x40812000}, {0x40814000}, {0x40816000}, 
+    {0x40818000}, {0x4081a000}, {0x4081c000}, {0x4081e000}, 
+    {0x40820000}, {0x40822000}, {0x40824000}, {0x40826000}, 
+    {0x40828000}, {0x4082a000}, {0x4082c000}, {0x4082e000}, 
+    {0x40830000}, {0x40832000}, {0x40834000}, {0x40836000}, 
+    {0x40838000}, {0x4083a000}, {0x4083c000}, {0x4083e000}, 
+    {0x40840000}, {0x40842000}, {0x40844000}, {0x40846000}, 
+    {0x40848000}, {0x4084a000}, {0x4084c000}, {0x4084e000}, 
+    {0x40850000}, {0x40852000}, {0x40854000}, {0x40856000}, 
+    {0x40858000}, {0x4085a000}, {0x4085c000}, {0x4085e000}, 
+    {0x40860000}, {0x40862000}, {0x40864000}, {0x40866000}, 
+    {0x40868000}, {0x4086a000}, {0x4086c000}, {0x4086e000}, 
+    {0x40870000}, {0x40872000}, {0x40874000}, {0x40876000}, 
+    {0x40878000}, {0x4087a000}, {0x4087c000}, {0x4087e000}, 
+    {0x40880000}, {0x40882000}, {0x40884000}, {0x40886000}, 
+    {0x40888000}, {0x4088a000}, {0x4088c000}, {0x4088e000}, 
+    {0x40890000}, {0x40892000}, {0x40894000}, {0x40896000}, 
+    {0x40898000}, {0x4089a000}, {0x4089c000}, {0x4089e000}, 
+    {0x408a0000}, {0x408a2000}, {0x408a4000}, {0x408a6000}, 
+    {0x408a8000}, {0x408aa000}, {0x408ac000}, {0x408ae000}, 
+    {0x408b0000}, {0x408b2000}, {0x408b4000}, {0x408b6000}, 
+    {0x408b8000}, {0x408ba000}, {0x408bc000}, {0x408be000}, 
+    {0x408c0000}, {0x408c2000}, {0x408c4000}, {0x408c6000}, 
+    {0x408c8000}, {0x408ca000}, {0x408cc000}, {0x408ce000}, 
+    {0x408d0000}, {0x408d2000}, {0x408d4000}, {0x408d6000}, 
+    {0x408d8000}, {0x408da000}, {0x408dc000}, {0x408de000}, 
+    {0x408e0000}, {0x408e2000}, {0x408e4000}, {0x408e6000}, 
+    {0x408e8000}, {0x408ea000}, {0x408ec000}, {0x408ee000}, 
+    {0x408f0000}, {0x408f2000}, {0x408f4000}, {0x408f6000}, 
+    {0x408f8000}, {0x408fa000}, {0x408fc000}, {0x408fe000}, 
+    {0x40900000}, {0x40902000}, {0x40904000}, {0x40906000}, 
+    {0x40908000}, {0x4090a000}, {0x4090c000}, {0x4090e000}, 
+    {0x40910000}, {0x40912000}, {0x40914000}, {0x40916000}, 
+    {0x40918000}, {0x4091a000}, {0x4091c000}, {0x4091e000}, 
+    {0x40920000}, {0x40922000}, {0x40924000}, {0x40926000}, 
+    {0x40928000}, {0x4092a000}, {0x4092c000}, {0x4092e000}, 
+    {0x40930000}, {0x40932000}, {0x40934000}, {0x40936000}, 
+    {0x40938000}, {0x4093a000}, {0x4093c000}, {0x4093e000}, 
+    {0x40940000}, {0x40942000}, {0x40944000}, {0x40946000}, 
+    {0x40948000}, {0x4094a000}, {0x4094c000}, {0x4094e000}, 
+    {0x40950000}, {0x40952000}, {0x40954000}, {0x40956000}, 
+    {0x40958000}, {0x4095a000}, {0x4095c000}, {0x4095e000}, 
+    {0x40960000}, {0x40962000}, {0x40964000}, {0x40966000}, 
+    {0x40968000}, {0x4096a000}, {0x4096c000}, {0x4096e000}, 
+    {0x40970000}, {0x40972000}, {0x40974000}, {0x40976000}, 
+    {0x40978000}, {0x4097a000}, {0x4097c000}, {0x4097e000}, 
+    {0x40980000}, {0x40982000}, {0x40984000}, {0x40986000}, 
+    {0x40988000}, {0x4098a000}, {0x4098c000}, {0x4098e000}, 
+    {0x40990000}, {0x40992000}, {0x40994000}, {0x40996000}, 
+    {0x40998000}, {0x4099a000}, {0x4099c000}, {0x4099e000}, 
+    {0x409a0000}, {0x409a2000}, {0x409a4000}, {0x409a6000}, 
+    {0x409a8000}, {0x409aa000}, {0x409ac000}, {0x409ae000}, 
+    {0x409b0000}, {0x409b2000}, {0x409b4000}, {0x409b6000}, 
+    {0x409b8000}, {0x409ba000}, {0x409bc000}, {0x409be000}, 
+    {0x409c0000}, {0x409c2000}, {0x409c4000}, {0x409c6000}, 
+    {0x409c8000}, {0x409ca000}, {0x409cc000}, {0x409ce000}, 
+    {0x409d0000}, {0x409d2000}, {0x409d4000}, {0x409d6000}, 
+    {0x409d8000}, {0x409da000}, {0x409dc000}, {0x409de000}, 
+    {0x409e0000}, {0x409e2000}, {0x409e4000}, {0x409e6000}, 
+    {0x409e8000}, {0x409ea000}, {0x409ec000}, {0x409ee000}, 
+    {0x409f0000}, {0x409f2000}, {0x409f4000}, {0x409f6000}, 
+    {0x409f8000}, {0x409fa000}, {0x409fc000}, {0x409fe000}, 
+    {0x40a00000}, {0x40a02000}, {0x40a04000}, {0x40a06000}, 
+    {0x40a08000}, {0x40a0a000}, {0x40a0c000}, {0x40a0e000}, 
+    {0x40a10000}, {0x40a12000}, {0x40a14000}, {0x40a16000}, 
+    {0x40a18000}, {0x40a1a000}, {0x40a1c000}, {0x40a1e000}, 
+    {0x40a20000}, {0x40a22000}, {0x40a24000}, {0x40a26000}, 
+    {0x40a28000}, {0x40a2a000}, {0x40a2c000}, {0x40a2e000}, 
+    {0x40a30000}, {0x40a32000}, {0x40a34000}, {0x40a36000}, 
+    {0x40a38000}, {0x40a3a000}, {0x40a3c000}, {0x40a3e000}, 
+    {0x40a40000}, {0x40a42000}, {0x40a44000}, {0x40a46000}, 
+    {0x40a48000}, {0x40a4a000}, {0x40a4c000}, {0x40a4e000}, 
+    {0x40a50000}, {0x40a52000}, {0x40a54000}, {0x40a56000}, 
+    {0x40a58000}, {0x40a5a000}, {0x40a5c000}, {0x40a5e000}, 
+    {0x40a60000}, {0x40a62000}, {0x40a64000}, {0x40a66000}, 
+    {0x40a68000}, {0x40a6a000}, {0x40a6c000}, {0x40a6e000}, 
+    {0x40a70000}, {0x40a72000}, {0x40a74000}, {0x40a76000}, 
+    {0x40a78000}, {0x40a7a000}, {0x40a7c000}, {0x40a7e000}, 
+    {0x40a80000}, {0x40a82000}, {0x40a84000}, {0x40a86000}, 
+    {0x40a88000}, {0x40a8a000}, {0x40a8c000}, {0x40a8e000}, 
+    {0x40a90000}, {0x40a92000}, {0x40a94000}, {0x40a96000}, 
+    {0x40a98000}, {0x40a9a000}, {0x40a9c000}, {0x40a9e000}, 
+    {0x40aa0000}, {0x40aa2000}, {0x40aa4000}, {0x40aa6000}, 
+    {0x40aa8000}, {0x40aaa000}, {0x40aac000}, {0x40aae000}, 
+    {0x40ab0000}, {0x40ab2000}, {0x40ab4000}, {0x40ab6000}, 
+    {0x40ab8000}, {0x40aba000}, {0x40abc000}, {0x40abe000}, 
+    {0x40ac0000}, {0x40ac2000}, {0x40ac4000}, {0x40ac6000}, 
+    {0x40ac8000}, {0x40aca000}, {0x40acc000}, {0x40ace000}, 
+    {0x40ad0000}, {0x40ad2000}, {0x40ad4000}, {0x40ad6000}, 
+    {0x40ad8000}, {0x40ada000}, {0x40adc000}, {0x40ade000}, 
+    {0x40ae0000}, {0x40ae2000}, {0x40ae4000}, {0x40ae6000}, 
+    {0x40ae8000}, {0x40aea000}, {0x40aec000}, {0x40aee000}, 
+    {0x40af0000}, {0x40af2000}, {0x40af4000}, {0x40af6000}, 
+    {0x40af8000}, {0x40afa000}, {0x40afc000}, {0x40afe000}, 
+    {0x40b00000}, {0x40b02000}, {0x40b04000}, {0x40b06000}, 
+    {0x40b08000}, {0x40b0a000}, {0x40b0c000}, {0x40b0e000}, 
+    {0x40b10000}, {0x40b12000}, {0x40b14000}, {0x40b16000}, 
+    {0x40b18000}, {0x40b1a000}, {0x40b1c000}, {0x40b1e000}, 
+    {0x40b20000}, {0x40b22000}, {0x40b24000}, {0x40b26000}, 
+    {0x40b28000}, {0x40b2a000}, {0x40b2c000}, {0x40b2e000}, 
+    {0x40b30000}, {0x40b32000}, {0x40b34000}, {0x40b36000}, 
+    {0x40b38000}, {0x40b3a000}, {0x40b3c000}, {0x40b3e000}, 
+    {0x40b40000}, {0x40b42000}, {0x40b44000}, {0x40b46000}, 
+    {0x40b48000}, {0x40b4a000}, {0x40b4c000}, {0x40b4e000}, 
+    {0x40b50000}, {0x40b52000}, {0x40b54000}, {0x40b56000}, 
+    {0x40b58000}, {0x40b5a000}, {0x40b5c000}, {0x40b5e000}, 
+    {0x40b60000}, {0x40b62000}, {0x40b64000}, {0x40b66000}, 
+    {0x40b68000}, {0x40b6a000}, {0x40b6c000}, {0x40b6e000}, 
+    {0x40b70000}, {0x40b72000}, {0x40b74000}, {0x40b76000}, 
+    {0x40b78000}, {0x40b7a000}, {0x40b7c000}, {0x40b7e000}, 
+    {0x40b80000}, {0x40b82000}, {0x40b84000}, {0x40b86000}, 
+    {0x40b88000}, {0x40b8a000}, {0x40b8c000}, {0x40b8e000}, 
+    {0x40b90000}, {0x40b92000}, {0x40b94000}, {0x40b96000}, 
+    {0x40b98000}, {0x40b9a000}, {0x40b9c000}, {0x40b9e000}, 
+    {0x40ba0000}, {0x40ba2000}, {0x40ba4000}, {0x40ba6000}, 
+    {0x40ba8000}, {0x40baa000}, {0x40bac000}, {0x40bae000}, 
+    {0x40bb0000}, {0x40bb2000}, {0x40bb4000}, {0x40bb6000}, 
+    {0x40bb8000}, {0x40bba000}, {0x40bbc000}, {0x40bbe000}, 
+    {0x40bc0000}, {0x40bc2000}, {0x40bc4000}, {0x40bc6000}, 
+    {0x40bc8000}, {0x40bca000}, {0x40bcc000}, {0x40bce000}, 
+    {0x40bd0000}, {0x40bd2000}, {0x40bd4000}, {0x40bd6000}, 
+    {0x40bd8000}, {0x40bda000}, {0x40bdc000}, {0x40bde000}, 
+    {0x40be0000}, {0x40be2000}, {0x40be4000}, {0x40be6000}, 
+    {0x40be8000}, {0x40bea000}, {0x40bec000}, {0x40bee000}, 
+    {0x40bf0000}, {0x40bf2000}, {0x40bf4000}, {0x40bf6000}, 
+    {0x40bf8000}, {0x40bfa000}, {0x40bfc000}, {0x40bfe000}, 
+    {0x40c00000}, {0x40c02000}, {0x40c04000}, {0x40c06000}, 
+    {0x40c08000}, {0x40c0a000}, {0x40c0c000}, {0x40c0e000}, 
+    {0x40c10000}, {0x40c12000}, {0x40c14000}, {0x40c16000}, 
+    {0x40c18000}, {0x40c1a000}, {0x40c1c000}, {0x40c1e000}, 
+    {0x40c20000}, {0x40c22000}, {0x40c24000}, {0x40c26000}, 
+    {0x40c28000}, {0x40c2a000}, {0x40c2c000}, {0x40c2e000}, 
+    {0x40c30000}, {0x40c32000}, {0x40c34000}, {0x40c36000}, 
+    {0x40c38000}, {0x40c3a000}, {0x40c3c000}, {0x40c3e000}, 
+    {0x40c40000}, {0x40c42000}, {0x40c44000}, {0x40c46000}, 
+    {0x40c48000}, {0x40c4a000}, {0x40c4c000}, {0x40c4e000}, 
+    {0x40c50000}, {0x40c52000}, {0x40c54000}, {0x40c56000}, 
+    {0x40c58000}, {0x40c5a000}, {0x40c5c000}, {0x40c5e000}, 
+    {0x40c60000}, {0x40c62000}, {0x40c64000}, {0x40c66000}, 
+    {0x40c68000}, {0x40c6a000}, {0x40c6c000}, {0x40c6e000}, 
+    {0x40c70000}, {0x40c72000}, {0x40c74000}, {0x40c76000}, 
+    {0x40c78000}, {0x40c7a000}, {0x40c7c000}, {0x40c7e000}, 
+    {0x40c80000}, {0x40c82000}, {0x40c84000}, {0x40c86000}, 
+    {0x40c88000}, {0x40c8a000}, {0x40c8c000}, {0x40c8e000}, 
+    {0x40c90000}, {0x40c92000}, {0x40c94000}, {0x40c96000}, 
+    {0x40c98000}, {0x40c9a000}, {0x40c9c000}, {0x40c9e000}, 
+    {0x40ca0000}, {0x40ca2000}, {0x40ca4000}, {0x40ca6000}, 
+    {0x40ca8000}, {0x40caa000}, {0x40cac000}, {0x40cae000}, 
+    {0x40cb0000}, {0x40cb2000}, {0x40cb4000}, {0x40cb6000}, 
+    {0x40cb8000}, {0x40cba000}, {0x40cbc000}, {0x40cbe000}, 
+    {0x40cc0000}, {0x40cc2000}, {0x40cc4000}, {0x40cc6000}, 
+    {0x40cc8000}, {0x40cca000}, {0x40ccc000}, {0x40cce000}, 
+    {0x40cd0000}, {0x40cd2000}, {0x40cd4000}, {0x40cd6000}, 
+    {0x40cd8000}, {0x40cda000}, {0x40cdc000}, {0x40cde000}, 
+    {0x40ce0000}, {0x40ce2000}, {0x40ce4000}, {0x40ce6000}, 
+    {0x40ce8000}, {0x40cea000}, {0x40cec000}, {0x40cee000}, 
+    {0x40cf0000}, {0x40cf2000}, {0x40cf4000}, {0x40cf6000}, 
+    {0x40cf8000}, {0x40cfa000}, {0x40cfc000}, {0x40cfe000}, 
+    {0x40d00000}, {0x40d02000}, {0x40d04000}, {0x40d06000}, 
+    {0x40d08000}, {0x40d0a000}, {0x40d0c000}, {0x40d0e000}, 
+    {0x40d10000}, {0x40d12000}, {0x40d14000}, {0x40d16000}, 
+    {0x40d18000}, {0x40d1a000}, {0x40d1c000}, {0x40d1e000}, 
+    {0x40d20000}, {0x40d22000}, {0x40d24000}, {0x40d26000}, 
+    {0x40d28000}, {0x40d2a000}, {0x40d2c000}, {0x40d2e000}, 
+    {0x40d30000}, {0x40d32000}, {0x40d34000}, {0x40d36000}, 
+    {0x40d38000}, {0x40d3a000}, {0x40d3c000}, {0x40d3e000}, 
+    {0x40d40000}, {0x40d42000}, {0x40d44000}, {0x40d46000}, 
+    {0x40d48000}, {0x40d4a000}, {0x40d4c000}, {0x40d4e000}, 
+    {0x40d50000}, {0x40d52000}, {0x40d54000}, {0x40d56000}, 
+    {0x40d58000}, {0x40d5a000}, {0x40d5c000}, {0x40d5e000}, 
+    {0x40d60000}, {0x40d62000}, {0x40d64000}, {0x40d66000}, 
+    {0x40d68000}, {0x40d6a000}, {0x40d6c000}, {0x40d6e000}, 
+    {0x40d70000}, {0x40d72000}, {0x40d74000}, {0x40d76000}, 
+    {0x40d78000}, {0x40d7a000}, {0x40d7c000}, {0x40d7e000}, 
+    {0x40d80000}, {0x40d82000}, {0x40d84000}, {0x40d86000}, 
+    {0x40d88000}, {0x40d8a000}, {0x40d8c000}, {0x40d8e000}, 
+    {0x40d90000}, {0x40d92000}, {0x40d94000}, {0x40d96000}, 
+    {0x40d98000}, {0x40d9a000}, {0x40d9c000}, {0x40d9e000}, 
+    {0x40da0000}, {0x40da2000}, {0x40da4000}, {0x40da6000}, 
+    {0x40da8000}, {0x40daa000}, {0x40dac000}, {0x40dae000}, 
+    {0x40db0000}, {0x40db2000}, {0x40db4000}, {0x40db6000}, 
+    {0x40db8000}, {0x40dba000}, {0x40dbc000}, {0x40dbe000}, 
+    {0x40dc0000}, {0x40dc2000}, {0x40dc4000}, {0x40dc6000}, 
+    {0x40dc8000}, {0x40dca000}, {0x40dcc000}, {0x40dce000}, 
+    {0x40dd0000}, {0x40dd2000}, {0x40dd4000}, {0x40dd6000}, 
+    {0x40dd8000}, {0x40dda000}, {0x40ddc000}, {0x40dde000}, 
+    {0x40de0000}, {0x40de2000}, {0x40de4000}, {0x40de6000}, 
+    {0x40de8000}, {0x40dea000}, {0x40dec000}, {0x40dee000}, 
+    {0x40df0000}, {0x40df2000}, {0x40df4000}, {0x40df6000}, 
+    {0x40df8000}, {0x40dfa000}, {0x40dfc000}, {0x40dfe000}, 
+    {0x40e00000}, {0x40e02000}, {0x40e04000}, {0x40e06000}, 
+    {0x40e08000}, {0x40e0a000}, {0x40e0c000}, {0x40e0e000}, 
+    {0x40e10000}, {0x40e12000}, {0x40e14000}, {0x40e16000}, 
+    {0x40e18000}, {0x40e1a000}, {0x40e1c000}, {0x40e1e000}, 
+    {0x40e20000}, {0x40e22000}, {0x40e24000}, {0x40e26000}, 
+    {0x40e28000}, {0x40e2a000}, {0x40e2c000}, {0x40e2e000}, 
+    {0x40e30000}, {0x40e32000}, {0x40e34000}, {0x40e36000}, 
+    {0x40e38000}, {0x40e3a000}, {0x40e3c000}, {0x40e3e000}, 
+    {0x40e40000}, {0x40e42000}, {0x40e44000}, {0x40e46000}, 
+    {0x40e48000}, {0x40e4a000}, {0x40e4c000}, {0x40e4e000}, 
+    {0x40e50000}, {0x40e52000}, {0x40e54000}, {0x40e56000}, 
+    {0x40e58000}, {0x40e5a000}, {0x40e5c000}, {0x40e5e000}, 
+    {0x40e60000}, {0x40e62000}, {0x40e64000}, {0x40e66000}, 
+    {0x40e68000}, {0x40e6a000}, {0x40e6c000}, {0x40e6e000}, 
+    {0x40e70000}, {0x40e72000}, {0x40e74000}, {0x40e76000}, 
+    {0x40e78000}, {0x40e7a000}, {0x40e7c000}, {0x40e7e000}, 
+    {0x40e80000}, {0x40e82000}, {0x40e84000}, {0x40e86000}, 
+    {0x40e88000}, {0x40e8a000}, {0x40e8c000}, {0x40e8e000}, 
+    {0x40e90000}, {0x40e92000}, {0x40e94000}, {0x40e96000}, 
+    {0x40e98000}, {0x40e9a000}, {0x40e9c000}, {0x40e9e000}, 
+    {0x40ea0000}, {0x40ea2000}, {0x40ea4000}, {0x40ea6000}, 
+    {0x40ea8000}, {0x40eaa000}, {0x40eac000}, {0x40eae000}, 
+    {0x40eb0000}, {0x40eb2000}, {0x40eb4000}, {0x40eb6000}, 
+    {0x40eb8000}, {0x40eba000}, {0x40ebc000}, {0x40ebe000}, 
+    {0x40ec0000}, {0x40ec2000}, {0x40ec4000}, {0x40ec6000}, 
+    {0x40ec8000}, {0x40eca000}, {0x40ecc000}, {0x40ece000}, 
+    {0x40ed0000}, {0x40ed2000}, {0x40ed4000}, {0x40ed6000}, 
+    {0x40ed8000}, {0x40eda000}, {0x40edc000}, {0x40ede000}, 
+    {0x40ee0000}, {0x40ee2000}, {0x40ee4000}, {0x40ee6000}, 
+    {0x40ee8000}, {0x40eea000}, {0x40eec000}, {0x40eee000}, 
+    {0x40ef0000}, {0x40ef2000}, {0x40ef4000}, {0x40ef6000}, 
+    {0x40ef8000}, {0x40efa000}, {0x40efc000}, {0x40efe000}, 
+    {0x40f00000}, {0x40f02000}, {0x40f04000}, {0x40f06000}, 
+    {0x40f08000}, {0x40f0a000}, {0x40f0c000}, {0x40f0e000}, 
+    {0x40f10000}, {0x40f12000}, {0x40f14000}, {0x40f16000}, 
+    {0x40f18000}, {0x40f1a000}, {0x40f1c000}, {0x40f1e000}, 
+    {0x40f20000}, {0x40f22000}, {0x40f24000}, {0x40f26000}, 
+    {0x40f28000}, {0x40f2a000}, {0x40f2c000}, {0x40f2e000}, 
+    {0x40f30000}, {0x40f32000}, {0x40f34000}, {0x40f36000}, 
+    {0x40f38000}, {0x40f3a000}, {0x40f3c000}, {0x40f3e000}, 
+    {0x40f40000}, {0x40f42000}, {0x40f44000}, {0x40f46000}, 
+    {0x40f48000}, {0x40f4a000}, {0x40f4c000}, {0x40f4e000}, 
+    {0x40f50000}, {0x40f52000}, {0x40f54000}, {0x40f56000}, 
+    {0x40f58000}, {0x40f5a000}, {0x40f5c000}, {0x40f5e000}, 
+    {0x40f60000}, {0x40f62000}, {0x40f64000}, {0x40f66000}, 
+    {0x40f68000}, {0x40f6a000}, {0x40f6c000}, {0x40f6e000}, 
+    {0x40f70000}, {0x40f72000}, {0x40f74000}, {0x40f76000}, 
+    {0x40f78000}, {0x40f7a000}, {0x40f7c000}, {0x40f7e000}, 
+    {0x40f80000}, {0x40f82000}, {0x40f84000}, {0x40f86000}, 
+    {0x40f88000}, {0x40f8a000}, {0x40f8c000}, {0x40f8e000}, 
+    {0x40f90000}, {0x40f92000}, {0x40f94000}, {0x40f96000}, 
+    {0x40f98000}, {0x40f9a000}, {0x40f9c000}, {0x40f9e000}, 
+    {0x40fa0000}, {0x40fa2000}, {0x40fa4000}, {0x40fa6000}, 
+    {0x40fa8000}, {0x40faa000}, {0x40fac000}, {0x40fae000}, 
+    {0x40fb0000}, {0x40fb2000}, {0x40fb4000}, {0x40fb6000}, 
+    {0x40fb8000}, {0x40fba000}, {0x40fbc000}, {0x40fbe000}, 
+    {0x40fc0000}, {0x40fc2000}, {0x40fc4000}, {0x40fc6000}, 
+    {0x40fc8000}, {0x40fca000}, {0x40fcc000}, {0x40fce000}, 
+    {0x40fd0000}, {0x40fd2000}, {0x40fd4000}, {0x40fd6000}, 
+    {0x40fd8000}, {0x40fda000}, {0x40fdc000}, {0x40fde000}, 
+    {0x40fe0000}, {0x40fe2000}, {0x40fe4000}, {0x40fe6000}, 
+    {0x40fe8000}, {0x40fea000}, {0x40fec000}, {0x40fee000}, 
+    {0x40ff0000}, {0x40ff2000}, {0x40ff4000}, {0x40ff6000}, 
+    {0x40ff8000}, {0x40ffa000}, {0x40ffc000}, {0x40ffe000}, 
+    {0x41000000}, {0x41002000}, {0x41004000}, {0x41006000}, 
+    {0x41008000}, {0x4100a000}, {0x4100c000}, {0x4100e000}, 
+    {0x41010000}, {0x41012000}, {0x41014000}, {0x41016000}, 
+    {0x41018000}, {0x4101a000}, {0x4101c000}, {0x4101e000}, 
+    {0x41020000}, {0x41022000}, {0x41024000}, {0x41026000}, 
+    {0x41028000}, {0x4102a000}, {0x4102c000}, {0x4102e000}, 
+    {0x41030000}, {0x41032000}, {0x41034000}, {0x41036000}, 
+    {0x41038000}, {0x4103a000}, {0x4103c000}, {0x4103e000}, 
+    {0x41040000}, {0x41042000}, {0x41044000}, {0x41046000}, 
+    {0x41048000}, {0x4104a000}, {0x4104c000}, {0x4104e000}, 
+    {0x41050000}, {0x41052000}, {0x41054000}, {0x41056000}, 
+    {0x41058000}, {0x4105a000}, {0x4105c000}, {0x4105e000}, 
+    {0x41060000}, {0x41062000}, {0x41064000}, {0x41066000}, 
+    {0x41068000}, {0x4106a000}, {0x4106c000}, {0x4106e000}, 
+    {0x41070000}, {0x41072000}, {0x41074000}, {0x41076000}, 
+    {0x41078000}, {0x4107a000}, {0x4107c000}, {0x4107e000}, 
+    {0x41080000}, {0x41082000}, {0x41084000}, {0x41086000}, 
+    {0x41088000}, {0x4108a000}, {0x4108c000}, {0x4108e000}, 
+    {0x41090000}, {0x41092000}, {0x41094000}, {0x41096000}, 
+    {0x41098000}, {0x4109a000}, {0x4109c000}, {0x4109e000}, 
+    {0x410a0000}, {0x410a2000}, {0x410a4000}, {0x410a6000}, 
+    {0x410a8000}, {0x410aa000}, {0x410ac000}, {0x410ae000}, 
+    {0x410b0000}, {0x410b2000}, {0x410b4000}, {0x410b6000}, 
+    {0x410b8000}, {0x410ba000}, {0x410bc000}, {0x410be000}, 
+    {0x410c0000}, {0x410c2000}, {0x410c4000}, {0x410c6000}, 
+    {0x410c8000}, {0x410ca000}, {0x410cc000}, {0x410ce000}, 
+    {0x410d0000}, {0x410d2000}, {0x410d4000}, {0x410d6000}, 
+    {0x410d8000}, {0x410da000}, {0x410dc000}, {0x410de000}, 
+    {0x410e0000}, {0x410e2000}, {0x410e4000}, {0x410e6000}, 
+    {0x410e8000}, {0x410ea000}, {0x410ec000}, {0x410ee000}, 
+    {0x410f0000}, {0x410f2000}, {0x410f4000}, {0x410f6000}, 
+    {0x410f8000}, {0x410fa000}, {0x410fc000}, {0x410fe000}, 
+    {0x41100000}, {0x41102000}, {0x41104000}, {0x41106000}, 
+    {0x41108000}, {0x4110a000}, {0x4110c000}, {0x4110e000}, 
+    {0x41110000}, {0x41112000}, {0x41114000}, {0x41116000}, 
+    {0x41118000}, {0x4111a000}, {0x4111c000}, {0x4111e000}, 
+    {0x41120000}, {0x41122000}, {0x41124000}, {0x41126000}, 
+    {0x41128000}, {0x4112a000}, {0x4112c000}, {0x4112e000}, 
+    {0x41130000}, {0x41132000}, {0x41134000}, {0x41136000}, 
+    {0x41138000}, {0x4113a000}, {0x4113c000}, {0x4113e000}, 
+    {0x41140000}, {0x41142000}, {0x41144000}, {0x41146000}, 
+    {0x41148000}, {0x4114a000}, {0x4114c000}, {0x4114e000}, 
+    {0x41150000}, {0x41152000}, {0x41154000}, {0x41156000}, 
+    {0x41158000}, {0x4115a000}, {0x4115c000}, {0x4115e000}, 
+    {0x41160000}, {0x41162000}, {0x41164000}, {0x41166000}, 
+    {0x41168000}, {0x4116a000}, {0x4116c000}, {0x4116e000}, 
+    {0x41170000}, {0x41172000}, {0x41174000}, {0x41176000}, 
+    {0x41178000}, {0x4117a000}, {0x4117c000}, {0x4117e000}, 
+    {0x41180000}, {0x41182000}, {0x41184000}, {0x41186000}, 
+    {0x41188000}, {0x4118a000}, {0x4118c000}, {0x4118e000}, 
+    {0x41190000}, {0x41192000}, {0x41194000}, {0x41196000}, 
+    {0x41198000}, {0x4119a000}, {0x4119c000}, {0x4119e000}, 
+    {0x411a0000}, {0x411a2000}, {0x411a4000}, {0x411a6000}, 
+    {0x411a8000}, {0x411aa000}, {0x411ac000}, {0x411ae000}, 
+    {0x411b0000}, {0x411b2000}, {0x411b4000}, {0x411b6000}, 
+    {0x411b8000}, {0x411ba000}, {0x411bc000}, {0x411be000}, 
+    {0x411c0000}, {0x411c2000}, {0x411c4000}, {0x411c6000}, 
+    {0x411c8000}, {0x411ca000}, {0x411cc000}, {0x411ce000}, 
+    {0x411d0000}, {0x411d2000}, {0x411d4000}, {0x411d6000}, 
+    {0x411d8000}, {0x411da000}, {0x411dc000}, {0x411de000}, 
+    {0x411e0000}, {0x411e2000}, {0x411e4000}, {0x411e6000}, 
+    {0x411e8000}, {0x411ea000}, {0x411ec000}, {0x411ee000}, 
+    {0x411f0000}, {0x411f2000}, {0x411f4000}, {0x411f6000}, 
+    {0x411f8000}, {0x411fa000}, {0x411fc000}, {0x411fe000}, 
+    {0x41200000}, {0x41202000}, {0x41204000}, {0x41206000}, 
+    {0x41208000}, {0x4120a000}, {0x4120c000}, {0x4120e000}, 
+    {0x41210000}, {0x41212000}, {0x41214000}, {0x41216000}, 
+    {0x41218000}, {0x4121a000}, {0x4121c000}, {0x4121e000}, 
+    {0x41220000}, {0x41222000}, {0x41224000}, {0x41226000}, 
+    {0x41228000}, {0x4122a000}, {0x4122c000}, {0x4122e000}, 
+    {0x41230000}, {0x41232000}, {0x41234000}, {0x41236000}, 
+    {0x41238000}, {0x4123a000}, {0x4123c000}, {0x4123e000}, 
+    {0x41240000}, {0x41242000}, {0x41244000}, {0x41246000}, 
+    {0x41248000}, {0x4124a000}, {0x4124c000}, {0x4124e000}, 
+    {0x41250000}, {0x41252000}, {0x41254000}, {0x41256000}, 
+    {0x41258000}, {0x4125a000}, {0x4125c000}, {0x4125e000}, 
+    {0x41260000}, {0x41262000}, {0x41264000}, {0x41266000}, 
+    {0x41268000}, {0x4126a000}, {0x4126c000}, {0x4126e000}, 
+    {0x41270000}, {0x41272000}, {0x41274000}, {0x41276000}, 
+    {0x41278000}, {0x4127a000}, {0x4127c000}, {0x4127e000}, 
+    {0x41280000}, {0x41282000}, {0x41284000}, {0x41286000}, 
+    {0x41288000}, {0x4128a000}, {0x4128c000}, {0x4128e000}, 
+    {0x41290000}, {0x41292000}, {0x41294000}, {0x41296000}, 
+    {0x41298000}, {0x4129a000}, {0x4129c000}, {0x4129e000}, 
+    {0x412a0000}, {0x412a2000}, {0x412a4000}, {0x412a6000}, 
+    {0x412a8000}, {0x412aa000}, {0x412ac000}, {0x412ae000}, 
+    {0x412b0000}, {0x412b2000}, {0x412b4000}, {0x412b6000}, 
+    {0x412b8000}, {0x412ba000}, {0x412bc000}, {0x412be000}, 
+    {0x412c0000}, {0x412c2000}, {0x412c4000}, {0x412c6000}, 
+    {0x412c8000}, {0x412ca000}, {0x412cc000}, {0x412ce000}, 
+    {0x412d0000}, {0x412d2000}, {0x412d4000}, {0x412d6000}, 
+    {0x412d8000}, {0x412da000}, {0x412dc000}, {0x412de000}, 
+    {0x412e0000}, {0x412e2000}, {0x412e4000}, {0x412e6000}, 
+    {0x412e8000}, {0x412ea000}, {0x412ec000}, {0x412ee000}, 
+    {0x412f0000}, {0x412f2000}, {0x412f4000}, {0x412f6000}, 
+    {0x412f8000}, {0x412fa000}, {0x412fc000}, {0x412fe000}, 
+    {0x41300000}, {0x41302000}, {0x41304000}, {0x41306000}, 
+    {0x41308000}, {0x4130a000}, {0x4130c000}, {0x4130e000}, 
+    {0x41310000}, {0x41312000}, {0x41314000}, {0x41316000}, 
+    {0x41318000}, {0x4131a000}, {0x4131c000}, {0x4131e000}, 
+    {0x41320000}, {0x41322000}, {0x41324000}, {0x41326000}, 
+    {0x41328000}, {0x4132a000}, {0x4132c000}, {0x4132e000}, 
+    {0x41330000}, {0x41332000}, {0x41334000}, {0x41336000}, 
+    {0x41338000}, {0x4133a000}, {0x4133c000}, {0x4133e000}, 
+    {0x41340000}, {0x41342000}, {0x41344000}, {0x41346000}, 
+    {0x41348000}, {0x4134a000}, {0x4134c000}, {0x4134e000}, 
+    {0x41350000}, {0x41352000}, {0x41354000}, {0x41356000}, 
+    {0x41358000}, {0x4135a000}, {0x4135c000}, {0x4135e000}, 
+    {0x41360000}, {0x41362000}, {0x41364000}, {0x41366000}, 
+    {0x41368000}, {0x4136a000}, {0x4136c000}, {0x4136e000}, 
+    {0x41370000}, {0x41372000}, {0x41374000}, {0x41376000}, 
+    {0x41378000}, {0x4137a000}, {0x4137c000}, {0x4137e000}, 
+    {0x41380000}, {0x41382000}, {0x41384000}, {0x41386000}, 
+    {0x41388000}, {0x4138a000}, {0x4138c000}, {0x4138e000}, 
+    {0x41390000}, {0x41392000}, {0x41394000}, {0x41396000}, 
+    {0x41398000}, {0x4139a000}, {0x4139c000}, {0x4139e000}, 
+    {0x413a0000}, {0x413a2000}, {0x413a4000}, {0x413a6000}, 
+    {0x413a8000}, {0x413aa000}, {0x413ac000}, {0x413ae000}, 
+    {0x413b0000}, {0x413b2000}, {0x413b4000}, {0x413b6000}, 
+    {0x413b8000}, {0x413ba000}, {0x413bc000}, {0x413be000}, 
+    {0x413c0000}, {0x413c2000}, {0x413c4000}, {0x413c6000}, 
+    {0x413c8000}, {0x413ca000}, {0x413cc000}, {0x413ce000}, 
+    {0x413d0000}, {0x413d2000}, {0x413d4000}, {0x413d6000}, 
+    {0x413d8000}, {0x413da000}, {0x413dc000}, {0x413de000}, 
+    {0x413e0000}, {0x413e2000}, {0x413e4000}, {0x413e6000}, 
+    {0x413e8000}, {0x413ea000}, {0x413ec000}, {0x413ee000}, 
+    {0x413f0000}, {0x413f2000}, {0x413f4000}, {0x413f6000}, 
+    {0x413f8000}, {0x413fa000}, {0x413fc000}, {0x413fe000}, 
+    {0x41400000}, {0x41402000}, {0x41404000}, {0x41406000}, 
+    {0x41408000}, {0x4140a000}, {0x4140c000}, {0x4140e000}, 
+    {0x41410000}, {0x41412000}, {0x41414000}, {0x41416000}, 
+    {0x41418000}, {0x4141a000}, {0x4141c000}, {0x4141e000}, 
+    {0x41420000}, {0x41422000}, {0x41424000}, {0x41426000}, 
+    {0x41428000}, {0x4142a000}, {0x4142c000}, {0x4142e000}, 
+    {0x41430000}, {0x41432000}, {0x41434000}, {0x41436000}, 
+    {0x41438000}, {0x4143a000}, {0x4143c000}, {0x4143e000}, 
+    {0x41440000}, {0x41442000}, {0x41444000}, {0x41446000}, 
+    {0x41448000}, {0x4144a000}, {0x4144c000}, {0x4144e000}, 
+    {0x41450000}, {0x41452000}, {0x41454000}, {0x41456000}, 
+    {0x41458000}, {0x4145a000}, {0x4145c000}, {0x4145e000}, 
+    {0x41460000}, {0x41462000}, {0x41464000}, {0x41466000}, 
+    {0x41468000}, {0x4146a000}, {0x4146c000}, {0x4146e000}, 
+    {0x41470000}, {0x41472000}, {0x41474000}, {0x41476000}, 
+    {0x41478000}, {0x4147a000}, {0x4147c000}, {0x4147e000}, 
+    {0x41480000}, {0x41482000}, {0x41484000}, {0x41486000}, 
+    {0x41488000}, {0x4148a000}, {0x4148c000}, {0x4148e000}, 
+    {0x41490000}, {0x41492000}, {0x41494000}, {0x41496000}, 
+    {0x41498000}, {0x4149a000}, {0x4149c000}, {0x4149e000}, 
+    {0x414a0000}, {0x414a2000}, {0x414a4000}, {0x414a6000}, 
+    {0x414a8000}, {0x414aa000}, {0x414ac000}, {0x414ae000}, 
+    {0x414b0000}, {0x414b2000}, {0x414b4000}, {0x414b6000}, 
+    {0x414b8000}, {0x414ba000}, {0x414bc000}, {0x414be000}, 
+    {0x414c0000}, {0x414c2000}, {0x414c4000}, {0x414c6000}, 
+    {0x414c8000}, {0x414ca000}, {0x414cc000}, {0x414ce000}, 
+    {0x414d0000}, {0x414d2000}, {0x414d4000}, {0x414d6000}, 
+    {0x414d8000}, {0x414da000}, {0x414dc000}, {0x414de000}, 
+    {0x414e0000}, {0x414e2000}, {0x414e4000}, {0x414e6000}, 
+    {0x414e8000}, {0x414ea000}, {0x414ec000}, {0x414ee000}, 
+    {0x414f0000}, {0x414f2000}, {0x414f4000}, {0x414f6000}, 
+    {0x414f8000}, {0x414fa000}, {0x414fc000}, {0x414fe000}, 
+    {0x41500000}, {0x41502000}, {0x41504000}, {0x41506000}, 
+    {0x41508000}, {0x4150a000}, {0x4150c000}, {0x4150e000}, 
+    {0x41510000}, {0x41512000}, {0x41514000}, {0x41516000}, 
+    {0x41518000}, {0x4151a000}, {0x4151c000}, {0x4151e000}, 
+    {0x41520000}, {0x41522000}, {0x41524000}, {0x41526000}, 
+    {0x41528000}, {0x4152a000}, {0x4152c000}, {0x4152e000}, 
+    {0x41530000}, {0x41532000}, {0x41534000}, {0x41536000}, 
+    {0x41538000}, {0x4153a000}, {0x4153c000}, {0x4153e000}, 
+    {0x41540000}, {0x41542000}, {0x41544000}, {0x41546000}, 
+    {0x41548000}, {0x4154a000}, {0x4154c000}, {0x4154e000}, 
+    {0x41550000}, {0x41552000}, {0x41554000}, {0x41556000}, 
+    {0x41558000}, {0x4155a000}, {0x4155c000}, {0x4155e000}, 
+    {0x41560000}, {0x41562000}, {0x41564000}, {0x41566000}, 
+    {0x41568000}, {0x4156a000}, {0x4156c000}, {0x4156e000}, 
+    {0x41570000}, {0x41572000}, {0x41574000}, {0x41576000}, 
+    {0x41578000}, {0x4157a000}, {0x4157c000}, {0x4157e000}, 
+    {0x41580000}, {0x41582000}, {0x41584000}, {0x41586000}, 
+    {0x41588000}, {0x4158a000}, {0x4158c000}, {0x4158e000}, 
+    {0x41590000}, {0x41592000}, {0x41594000}, {0x41596000}, 
+    {0x41598000}, {0x4159a000}, {0x4159c000}, {0x4159e000}, 
+    {0x415a0000}, {0x415a2000}, {0x415a4000}, {0x415a6000}, 
+    {0x415a8000}, {0x415aa000}, {0x415ac000}, {0x415ae000}, 
+    {0x415b0000}, {0x415b2000}, {0x415b4000}, {0x415b6000}, 
+    {0x415b8000}, {0x415ba000}, {0x415bc000}, {0x415be000}, 
+    {0x415c0000}, {0x415c2000}, {0x415c4000}, {0x415c6000}, 
+    {0x415c8000}, {0x415ca000}, {0x415cc000}, {0x415ce000}, 
+    {0x415d0000}, {0x415d2000}, {0x415d4000}, {0x415d6000}, 
+    {0x415d8000}, {0x415da000}, {0x415dc000}, {0x415de000}, 
+    {0x415e0000}, {0x415e2000}, {0x415e4000}, {0x415e6000}, 
+    {0x415e8000}, {0x415ea000}, {0x415ec000}, {0x415ee000}, 
+    {0x415f0000}, {0x415f2000}, {0x415f4000}, {0x415f6000}, 
+    {0x415f8000}, {0x415fa000}, {0x415fc000}, {0x415fe000}, 
+    {0x41600000}, {0x41602000}, {0x41604000}, {0x41606000}, 
+    {0x41608000}, {0x4160a000}, {0x4160c000}, {0x4160e000}, 
+    {0x41610000}, {0x41612000}, {0x41614000}, {0x41616000}, 
+    {0x41618000}, {0x4161a000}, {0x4161c000}, {0x4161e000}, 
+    {0x41620000}, {0x41622000}, {0x41624000}, {0x41626000}, 
+    {0x41628000}, {0x4162a000}, {0x4162c000}, {0x4162e000}, 
+    {0x41630000}, {0x41632000}, {0x41634000}, {0x41636000}, 
+    {0x41638000}, {0x4163a000}, {0x4163c000}, {0x4163e000}, 
+    {0x41640000}, {0x41642000}, {0x41644000}, {0x41646000}, 
+    {0x41648000}, {0x4164a000}, {0x4164c000}, {0x4164e000}, 
+    {0x41650000}, {0x41652000}, {0x41654000}, {0x41656000}, 
+    {0x41658000}, {0x4165a000}, {0x4165c000}, {0x4165e000}, 
+    {0x41660000}, {0x41662000}, {0x41664000}, {0x41666000}, 
+    {0x41668000}, {0x4166a000}, {0x4166c000}, {0x4166e000}, 
+    {0x41670000}, {0x41672000}, {0x41674000}, {0x41676000}, 
+    {0x41678000}, {0x4167a000}, {0x4167c000}, {0x4167e000}, 
+    {0x41680000}, {0x41682000}, {0x41684000}, {0x41686000}, 
+    {0x41688000}, {0x4168a000}, {0x4168c000}, {0x4168e000}, 
+    {0x41690000}, {0x41692000}, {0x41694000}, {0x41696000}, 
+    {0x41698000}, {0x4169a000}, {0x4169c000}, {0x4169e000}, 
+    {0x416a0000}, {0x416a2000}, {0x416a4000}, {0x416a6000}, 
+    {0x416a8000}, {0x416aa000}, {0x416ac000}, {0x416ae000}, 
+    {0x416b0000}, {0x416b2000}, {0x416b4000}, {0x416b6000}, 
+    {0x416b8000}, {0x416ba000}, {0x416bc000}, {0x416be000}, 
+    {0x416c0000}, {0x416c2000}, {0x416c4000}, {0x416c6000}, 
+    {0x416c8000}, {0x416ca000}, {0x416cc000}, {0x416ce000}, 
+    {0x416d0000}, {0x416d2000}, {0x416d4000}, {0x416d6000}, 
+    {0x416d8000}, {0x416da000}, {0x416dc000}, {0x416de000}, 
+    {0x416e0000}, {0x416e2000}, {0x416e4000}, {0x416e6000}, 
+    {0x416e8000}, {0x416ea000}, {0x416ec000}, {0x416ee000}, 
+    {0x416f0000}, {0x416f2000}, {0x416f4000}, {0x416f6000}, 
+    {0x416f8000}, {0x416fa000}, {0x416fc000}, {0x416fe000}, 
+    {0x41700000}, {0x41702000}, {0x41704000}, {0x41706000}, 
+    {0x41708000}, {0x4170a000}, {0x4170c000}, {0x4170e000}, 
+    {0x41710000}, {0x41712000}, {0x41714000}, {0x41716000}, 
+    {0x41718000}, {0x4171a000}, {0x4171c000}, {0x4171e000}, 
+    {0x41720000}, {0x41722000}, {0x41724000}, {0x41726000}, 
+    {0x41728000}, {0x4172a000}, {0x4172c000}, {0x4172e000}, 
+    {0x41730000}, {0x41732000}, {0x41734000}, {0x41736000}, 
+    {0x41738000}, {0x4173a000}, {0x4173c000}, {0x4173e000}, 
+    {0x41740000}, {0x41742000}, {0x41744000}, {0x41746000}, 
+    {0x41748000}, {0x4174a000}, {0x4174c000}, {0x4174e000}, 
+    {0x41750000}, {0x41752000}, {0x41754000}, {0x41756000}, 
+    {0x41758000}, {0x4175a000}, {0x4175c000}, {0x4175e000}, 
+    {0x41760000}, {0x41762000}, {0x41764000}, {0x41766000}, 
+    {0x41768000}, {0x4176a000}, {0x4176c000}, {0x4176e000}, 
+    {0x41770000}, {0x41772000}, {0x41774000}, {0x41776000}, 
+    {0x41778000}, {0x4177a000}, {0x4177c000}, {0x4177e000}, 
+    {0x41780000}, {0x41782000}, {0x41784000}, {0x41786000}, 
+    {0x41788000}, {0x4178a000}, {0x4178c000}, {0x4178e000}, 
+    {0x41790000}, {0x41792000}, {0x41794000}, {0x41796000}, 
+    {0x41798000}, {0x4179a000}, {0x4179c000}, {0x4179e000}, 
+    {0x417a0000}, {0x417a2000}, {0x417a4000}, {0x417a6000}, 
+    {0x417a8000}, {0x417aa000}, {0x417ac000}, {0x417ae000}, 
+    {0x417b0000}, {0x417b2000}, {0x417b4000}, {0x417b6000}, 
+    {0x417b8000}, {0x417ba000}, {0x417bc000}, {0x417be000}, 
+    {0x417c0000}, {0x417c2000}, {0x417c4000}, {0x417c6000}, 
+    {0x417c8000}, {0x417ca000}, {0x417cc000}, {0x417ce000}, 
+    {0x417d0000}, {0x417d2000}, {0x417d4000}, {0x417d6000}, 
+    {0x417d8000}, {0x417da000}, {0x417dc000}, {0x417de000}, 
+    {0x417e0000}, {0x417e2000}, {0x417e4000}, {0x417e6000}, 
+    {0x417e8000}, {0x417ea000}, {0x417ec000}, {0x417ee000}, 
+    {0x417f0000}, {0x417f2000}, {0x417f4000}, {0x417f6000}, 
+    {0x417f8000}, {0x417fa000}, {0x417fc000}, {0x417fe000}, 
+    {0x41800000}, {0x41802000}, {0x41804000}, {0x41806000}, 
+    {0x41808000}, {0x4180a000}, {0x4180c000}, {0x4180e000}, 
+    {0x41810000}, {0x41812000}, {0x41814000}, {0x41816000}, 
+    {0x41818000}, {0x4181a000}, {0x4181c000}, {0x4181e000}, 
+    {0x41820000}, {0x41822000}, {0x41824000}, {0x41826000}, 
+    {0x41828000}, {0x4182a000}, {0x4182c000}, {0x4182e000}, 
+    {0x41830000}, {0x41832000}, {0x41834000}, {0x41836000}, 
+    {0x41838000}, {0x4183a000}, {0x4183c000}, {0x4183e000}, 
+    {0x41840000}, {0x41842000}, {0x41844000}, {0x41846000}, 
+    {0x41848000}, {0x4184a000}, {0x4184c000}, {0x4184e000}, 
+    {0x41850000}, {0x41852000}, {0x41854000}, {0x41856000}, 
+    {0x41858000}, {0x4185a000}, {0x4185c000}, {0x4185e000}, 
+    {0x41860000}, {0x41862000}, {0x41864000}, {0x41866000}, 
+    {0x41868000}, {0x4186a000}, {0x4186c000}, {0x4186e000}, 
+    {0x41870000}, {0x41872000}, {0x41874000}, {0x41876000}, 
+    {0x41878000}, {0x4187a000}, {0x4187c000}, {0x4187e000}, 
+    {0x41880000}, {0x41882000}, {0x41884000}, {0x41886000}, 
+    {0x41888000}, {0x4188a000}, {0x4188c000}, {0x4188e000}, 
+    {0x41890000}, {0x41892000}, {0x41894000}, {0x41896000}, 
+    {0x41898000}, {0x4189a000}, {0x4189c000}, {0x4189e000}, 
+    {0x418a0000}, {0x418a2000}, {0x418a4000}, {0x418a6000}, 
+    {0x418a8000}, {0x418aa000}, {0x418ac000}, {0x418ae000}, 
+    {0x418b0000}, {0x418b2000}, {0x418b4000}, {0x418b6000}, 
+    {0x418b8000}, {0x418ba000}, {0x418bc000}, {0x418be000}, 
+    {0x418c0000}, {0x418c2000}, {0x418c4000}, {0x418c6000}, 
+    {0x418c8000}, {0x418ca000}, {0x418cc000}, {0x418ce000}, 
+    {0x418d0000}, {0x418d2000}, {0x418d4000}, {0x418d6000}, 
+    {0x418d8000}, {0x418da000}, {0x418dc000}, {0x418de000}, 
+    {0x418e0000}, {0x418e2000}, {0x418e4000}, {0x418e6000}, 
+    {0x418e8000}, {0x418ea000}, {0x418ec000}, {0x418ee000}, 
+    {0x418f0000}, {0x418f2000}, {0x418f4000}, {0x418f6000}, 
+    {0x418f8000}, {0x418fa000}, {0x418fc000}, {0x418fe000}, 
+    {0x41900000}, {0x41902000}, {0x41904000}, {0x41906000}, 
+    {0x41908000}, {0x4190a000}, {0x4190c000}, {0x4190e000}, 
+    {0x41910000}, {0x41912000}, {0x41914000}, {0x41916000}, 
+    {0x41918000}, {0x4191a000}, {0x4191c000}, {0x4191e000}, 
+    {0x41920000}, {0x41922000}, {0x41924000}, {0x41926000}, 
+    {0x41928000}, {0x4192a000}, {0x4192c000}, {0x4192e000}, 
+    {0x41930000}, {0x41932000}, {0x41934000}, {0x41936000}, 
+    {0x41938000}, {0x4193a000}, {0x4193c000}, {0x4193e000}, 
+    {0x41940000}, {0x41942000}, {0x41944000}, {0x41946000}, 
+    {0x41948000}, {0x4194a000}, {0x4194c000}, {0x4194e000}, 
+    {0x41950000}, {0x41952000}, {0x41954000}, {0x41956000}, 
+    {0x41958000}, {0x4195a000}, {0x4195c000}, {0x4195e000}, 
+    {0x41960000}, {0x41962000}, {0x41964000}, {0x41966000}, 
+    {0x41968000}, {0x4196a000}, {0x4196c000}, {0x4196e000}, 
+    {0x41970000}, {0x41972000}, {0x41974000}, {0x41976000}, 
+    {0x41978000}, {0x4197a000}, {0x4197c000}, {0x4197e000}, 
+    {0x41980000}, {0x41982000}, {0x41984000}, {0x41986000}, 
+    {0x41988000}, {0x4198a000}, {0x4198c000}, {0x4198e000}, 
+    {0x41990000}, {0x41992000}, {0x41994000}, {0x41996000}, 
+    {0x41998000}, {0x4199a000}, {0x4199c000}, {0x4199e000}, 
+    {0x419a0000}, {0x419a2000}, {0x419a4000}, {0x419a6000}, 
+    {0x419a8000}, {0x419aa000}, {0x419ac000}, {0x419ae000}, 
+    {0x419b0000}, {0x419b2000}, {0x419b4000}, {0x419b6000}, 
+    {0x419b8000}, {0x419ba000}, {0x419bc000}, {0x419be000}, 
+    {0x419c0000}, {0x419c2000}, {0x419c4000}, {0x419c6000}, 
+    {0x419c8000}, {0x419ca000}, {0x419cc000}, {0x419ce000}, 
+    {0x419d0000}, {0x419d2000}, {0x419d4000}, {0x419d6000}, 
+    {0x419d8000}, {0x419da000}, {0x419dc000}, {0x419de000}, 
+    {0x419e0000}, {0x419e2000}, {0x419e4000}, {0x419e6000}, 
+    {0x419e8000}, {0x419ea000}, {0x419ec000}, {0x419ee000}, 
+    {0x419f0000}, {0x419f2000}, {0x419f4000}, {0x419f6000}, 
+    {0x419f8000}, {0x419fa000}, {0x419fc000}, {0x419fe000}, 
+    {0x41a00000}, {0x41a02000}, {0x41a04000}, {0x41a06000}, 
+    {0x41a08000}, {0x41a0a000}, {0x41a0c000}, {0x41a0e000}, 
+    {0x41a10000}, {0x41a12000}, {0x41a14000}, {0x41a16000}, 
+    {0x41a18000}, {0x41a1a000}, {0x41a1c000}, {0x41a1e000}, 
+    {0x41a20000}, {0x41a22000}, {0x41a24000}, {0x41a26000}, 
+    {0x41a28000}, {0x41a2a000}, {0x41a2c000}, {0x41a2e000}, 
+    {0x41a30000}, {0x41a32000}, {0x41a34000}, {0x41a36000}, 
+    {0x41a38000}, {0x41a3a000}, {0x41a3c000}, {0x41a3e000}, 
+    {0x41a40000}, {0x41a42000}, {0x41a44000}, {0x41a46000}, 
+    {0x41a48000}, {0x41a4a000}, {0x41a4c000}, {0x41a4e000}, 
+    {0x41a50000}, {0x41a52000}, {0x41a54000}, {0x41a56000}, 
+    {0x41a58000}, {0x41a5a000}, {0x41a5c000}, {0x41a5e000}, 
+    {0x41a60000}, {0x41a62000}, {0x41a64000}, {0x41a66000}, 
+    {0x41a68000}, {0x41a6a000}, {0x41a6c000}, {0x41a6e000}, 
+    {0x41a70000}, {0x41a72000}, {0x41a74000}, {0x41a76000}, 
+    {0x41a78000}, {0x41a7a000}, {0x41a7c000}, {0x41a7e000}, 
+    {0x41a80000}, {0x41a82000}, {0x41a84000}, {0x41a86000}, 
+    {0x41a88000}, {0x41a8a000}, {0x41a8c000}, {0x41a8e000}, 
+    {0x41a90000}, {0x41a92000}, {0x41a94000}, {0x41a96000}, 
+    {0x41a98000}, {0x41a9a000}, {0x41a9c000}, {0x41a9e000}, 
+    {0x41aa0000}, {0x41aa2000}, {0x41aa4000}, {0x41aa6000}, 
+    {0x41aa8000}, {0x41aaa000}, {0x41aac000}, {0x41aae000}, 
+    {0x41ab0000}, {0x41ab2000}, {0x41ab4000}, {0x41ab6000}, 
+    {0x41ab8000}, {0x41aba000}, {0x41abc000}, {0x41abe000}, 
+    {0x41ac0000}, {0x41ac2000}, {0x41ac4000}, {0x41ac6000}, 
+    {0x41ac8000}, {0x41aca000}, {0x41acc000}, {0x41ace000}, 
+    {0x41ad0000}, {0x41ad2000}, {0x41ad4000}, {0x41ad6000}, 
+    {0x41ad8000}, {0x41ada000}, {0x41adc000}, {0x41ade000}, 
+    {0x41ae0000}, {0x41ae2000}, {0x41ae4000}, {0x41ae6000}, 
+    {0x41ae8000}, {0x41aea000}, {0x41aec000}, {0x41aee000}, 
+    {0x41af0000}, {0x41af2000}, {0x41af4000}, {0x41af6000}, 
+    {0x41af8000}, {0x41afa000}, {0x41afc000}, {0x41afe000}, 
+    {0x41b00000}, {0x41b02000}, {0x41b04000}, {0x41b06000}, 
+    {0x41b08000}, {0x41b0a000}, {0x41b0c000}, {0x41b0e000}, 
+    {0x41b10000}, {0x41b12000}, {0x41b14000}, {0x41b16000}, 
+    {0x41b18000}, {0x41b1a000}, {0x41b1c000}, {0x41b1e000}, 
+    {0x41b20000}, {0x41b22000}, {0x41b24000}, {0x41b26000}, 
+    {0x41b28000}, {0x41b2a000}, {0x41b2c000}, {0x41b2e000}, 
+    {0x41b30000}, {0x41b32000}, {0x41b34000}, {0x41b36000}, 
+    {0x41b38000}, {0x41b3a000}, {0x41b3c000}, {0x41b3e000}, 
+    {0x41b40000}, {0x41b42000}, {0x41b44000}, {0x41b46000}, 
+    {0x41b48000}, {0x41b4a000}, {0x41b4c000}, {0x41b4e000}, 
+    {0x41b50000}, {0x41b52000}, {0x41b54000}, {0x41b56000}, 
+    {0x41b58000}, {0x41b5a000}, {0x41b5c000}, {0x41b5e000}, 
+    {0x41b60000}, {0x41b62000}, {0x41b64000}, {0x41b66000}, 
+    {0x41b68000}, {0x41b6a000}, {0x41b6c000}, {0x41b6e000}, 
+    {0x41b70000}, {0x41b72000}, {0x41b74000}, {0x41b76000}, 
+    {0x41b78000}, {0x41b7a000}, {0x41b7c000}, {0x41b7e000}, 
+    {0x41b80000}, {0x41b82000}, {0x41b84000}, {0x41b86000}, 
+    {0x41b88000}, {0x41b8a000}, {0x41b8c000}, {0x41b8e000}, 
+    {0x41b90000}, {0x41b92000}, {0x41b94000}, {0x41b96000}, 
+    {0x41b98000}, {0x41b9a000}, {0x41b9c000}, {0x41b9e000}, 
+    {0x41ba0000}, {0x41ba2000}, {0x41ba4000}, {0x41ba6000}, 
+    {0x41ba8000}, {0x41baa000}, {0x41bac000}, {0x41bae000}, 
+    {0x41bb0000}, {0x41bb2000}, {0x41bb4000}, {0x41bb6000}, 
+    {0x41bb8000}, {0x41bba000}, {0x41bbc000}, {0x41bbe000}, 
+    {0x41bc0000}, {0x41bc2000}, {0x41bc4000}, {0x41bc6000}, 
+    {0x41bc8000}, {0x41bca000}, {0x41bcc000}, {0x41bce000}, 
+    {0x41bd0000}, {0x41bd2000}, {0x41bd4000}, {0x41bd6000}, 
+    {0x41bd8000}, {0x41bda000}, {0x41bdc000}, {0x41bde000}, 
+    {0x41be0000}, {0x41be2000}, {0x41be4000}, {0x41be6000}, 
+    {0x41be8000}, {0x41bea000}, {0x41bec000}, {0x41bee000}, 
+    {0x41bf0000}, {0x41bf2000}, {0x41bf4000}, {0x41bf6000}, 
+    {0x41bf8000}, {0x41bfa000}, {0x41bfc000}, {0x41bfe000}, 
+    {0x41c00000}, {0x41c02000}, {0x41c04000}, {0x41c06000}, 
+    {0x41c08000}, {0x41c0a000}, {0x41c0c000}, {0x41c0e000}, 
+    {0x41c10000}, {0x41c12000}, {0x41c14000}, {0x41c16000}, 
+    {0x41c18000}, {0x41c1a000}, {0x41c1c000}, {0x41c1e000}, 
+    {0x41c20000}, {0x41c22000}, {0x41c24000}, {0x41c26000}, 
+    {0x41c28000}, {0x41c2a000}, {0x41c2c000}, {0x41c2e000}, 
+    {0x41c30000}, {0x41c32000}, {0x41c34000}, {0x41c36000}, 
+    {0x41c38000}, {0x41c3a000}, {0x41c3c000}, {0x41c3e000}, 
+    {0x41c40000}, {0x41c42000}, {0x41c44000}, {0x41c46000}, 
+    {0x41c48000}, {0x41c4a000}, {0x41c4c000}, {0x41c4e000}, 
+    {0x41c50000}, {0x41c52000}, {0x41c54000}, {0x41c56000}, 
+    {0x41c58000}, {0x41c5a000}, {0x41c5c000}, {0x41c5e000}, 
+    {0x41c60000}, {0x41c62000}, {0x41c64000}, {0x41c66000}, 
+    {0x41c68000}, {0x41c6a000}, {0x41c6c000}, {0x41c6e000}, 
+    {0x41c70000}, {0x41c72000}, {0x41c74000}, {0x41c76000}, 
+    {0x41c78000}, {0x41c7a000}, {0x41c7c000}, {0x41c7e000}, 
+    {0x41c80000}, {0x41c82000}, {0x41c84000}, {0x41c86000}, 
+    {0x41c88000}, {0x41c8a000}, {0x41c8c000}, {0x41c8e000}, 
+    {0x41c90000}, {0x41c92000}, {0x41c94000}, {0x41c96000}, 
+    {0x41c98000}, {0x41c9a000}, {0x41c9c000}, {0x41c9e000}, 
+    {0x41ca0000}, {0x41ca2000}, {0x41ca4000}, {0x41ca6000}, 
+    {0x41ca8000}, {0x41caa000}, {0x41cac000}, {0x41cae000}, 
+    {0x41cb0000}, {0x41cb2000}, {0x41cb4000}, {0x41cb6000}, 
+    {0x41cb8000}, {0x41cba000}, {0x41cbc000}, {0x41cbe000}, 
+    {0x41cc0000}, {0x41cc2000}, {0x41cc4000}, {0x41cc6000}, 
+    {0x41cc8000}, {0x41cca000}, {0x41ccc000}, {0x41cce000}, 
+    {0x41cd0000}, {0x41cd2000}, {0x41cd4000}, {0x41cd6000}, 
+    {0x41cd8000}, {0x41cda000}, {0x41cdc000}, {0x41cde000}, 
+    {0x41ce0000}, {0x41ce2000}, {0x41ce4000}, {0x41ce6000}, 
+    {0x41ce8000}, {0x41cea000}, {0x41cec000}, {0x41cee000}, 
+    {0x41cf0000}, {0x41cf2000}, {0x41cf4000}, {0x41cf6000}, 
+    {0x41cf8000}, {0x41cfa000}, {0x41cfc000}, {0x41cfe000}, 
+    {0x41d00000}, {0x41d02000}, {0x41d04000}, {0x41d06000}, 
+    {0x41d08000}, {0x41d0a000}, {0x41d0c000}, {0x41d0e000}, 
+    {0x41d10000}, {0x41d12000}, {0x41d14000}, {0x41d16000}, 
+    {0x41d18000}, {0x41d1a000}, {0x41d1c000}, {0x41d1e000}, 
+    {0x41d20000}, {0x41d22000}, {0x41d24000}, {0x41d26000}, 
+    {0x41d28000}, {0x41d2a000}, {0x41d2c000}, {0x41d2e000}, 
+    {0x41d30000}, {0x41d32000}, {0x41d34000}, {0x41d36000}, 
+    {0x41d38000}, {0x41d3a000}, {0x41d3c000}, {0x41d3e000}, 
+    {0x41d40000}, {0x41d42000}, {0x41d44000}, {0x41d46000}, 
+    {0x41d48000}, {0x41d4a000}, {0x41d4c000}, {0x41d4e000}, 
+    {0x41d50000}, {0x41d52000}, {0x41d54000}, {0x41d56000}, 
+    {0x41d58000}, {0x41d5a000}, {0x41d5c000}, {0x41d5e000}, 
+    {0x41d60000}, {0x41d62000}, {0x41d64000}, {0x41d66000}, 
+    {0x41d68000}, {0x41d6a000}, {0x41d6c000}, {0x41d6e000}, 
+    {0x41d70000}, {0x41d72000}, {0x41d74000}, {0x41d76000}, 
+    {0x41d78000}, {0x41d7a000}, {0x41d7c000}, {0x41d7e000}, 
+    {0x41d80000}, {0x41d82000}, {0x41d84000}, {0x41d86000}, 
+    {0x41d88000}, {0x41d8a000}, {0x41d8c000}, {0x41d8e000}, 
+    {0x41d90000}, {0x41d92000}, {0x41d94000}, {0x41d96000}, 
+    {0x41d98000}, {0x41d9a000}, {0x41d9c000}, {0x41d9e000}, 
+    {0x41da0000}, {0x41da2000}, {0x41da4000}, {0x41da6000}, 
+    {0x41da8000}, {0x41daa000}, {0x41dac000}, {0x41dae000}, 
+    {0x41db0000}, {0x41db2000}, {0x41db4000}, {0x41db6000}, 
+    {0x41db8000}, {0x41dba000}, {0x41dbc000}, {0x41dbe000}, 
+    {0x41dc0000}, {0x41dc2000}, {0x41dc4000}, {0x41dc6000}, 
+    {0x41dc8000}, {0x41dca000}, {0x41dcc000}, {0x41dce000}, 
+    {0x41dd0000}, {0x41dd2000}, {0x41dd4000}, {0x41dd6000}, 
+    {0x41dd8000}, {0x41dda000}, {0x41ddc000}, {0x41dde000}, 
+    {0x41de0000}, {0x41de2000}, {0x41de4000}, {0x41de6000}, 
+    {0x41de8000}, {0x41dea000}, {0x41dec000}, {0x41dee000}, 
+    {0x41df0000}, {0x41df2000}, {0x41df4000}, {0x41df6000}, 
+    {0x41df8000}, {0x41dfa000}, {0x41dfc000}, {0x41dfe000}, 
+    {0x41e00000}, {0x41e02000}, {0x41e04000}, {0x41e06000}, 
+    {0x41e08000}, {0x41e0a000}, {0x41e0c000}, {0x41e0e000}, 
+    {0x41e10000}, {0x41e12000}, {0x41e14000}, {0x41e16000}, 
+    {0x41e18000}, {0x41e1a000}, {0x41e1c000}, {0x41e1e000}, 
+    {0x41e20000}, {0x41e22000}, {0x41e24000}, {0x41e26000}, 
+    {0x41e28000}, {0x41e2a000}, {0x41e2c000}, {0x41e2e000}, 
+    {0x41e30000}, {0x41e32000}, {0x41e34000}, {0x41e36000}, 
+    {0x41e38000}, {0x41e3a000}, {0x41e3c000}, {0x41e3e000}, 
+    {0x41e40000}, {0x41e42000}, {0x41e44000}, {0x41e46000}, 
+    {0x41e48000}, {0x41e4a000}, {0x41e4c000}, {0x41e4e000}, 
+    {0x41e50000}, {0x41e52000}, {0x41e54000}, {0x41e56000}, 
+    {0x41e58000}, {0x41e5a000}, {0x41e5c000}, {0x41e5e000}, 
+    {0x41e60000}, {0x41e62000}, {0x41e64000}, {0x41e66000}, 
+    {0x41e68000}, {0x41e6a000}, {0x41e6c000}, {0x41e6e000}, 
+    {0x41e70000}, {0x41e72000}, {0x41e74000}, {0x41e76000}, 
+    {0x41e78000}, {0x41e7a000}, {0x41e7c000}, {0x41e7e000}, 
+    {0x41e80000}, {0x41e82000}, {0x41e84000}, {0x41e86000}, 
+    {0x41e88000}, {0x41e8a000}, {0x41e8c000}, {0x41e8e000}, 
+    {0x41e90000}, {0x41e92000}, {0x41e94000}, {0x41e96000}, 
+    {0x41e98000}, {0x41e9a000}, {0x41e9c000}, {0x41e9e000}, 
+    {0x41ea0000}, {0x41ea2000}, {0x41ea4000}, {0x41ea6000}, 
+    {0x41ea8000}, {0x41eaa000}, {0x41eac000}, {0x41eae000}, 
+    {0x41eb0000}, {0x41eb2000}, {0x41eb4000}, {0x41eb6000}, 
+    {0x41eb8000}, {0x41eba000}, {0x41ebc000}, {0x41ebe000}, 
+    {0x41ec0000}, {0x41ec2000}, {0x41ec4000}, {0x41ec6000}, 
+    {0x41ec8000}, {0x41eca000}, {0x41ecc000}, {0x41ece000}, 
+    {0x41ed0000}, {0x41ed2000}, {0x41ed4000}, {0x41ed6000}, 
+    {0x41ed8000}, {0x41eda000}, {0x41edc000}, {0x41ede000}, 
+    {0x41ee0000}, {0x41ee2000}, {0x41ee4000}, {0x41ee6000}, 
+    {0x41ee8000}, {0x41eea000}, {0x41eec000}, {0x41eee000}, 
+    {0x41ef0000}, {0x41ef2000}, {0x41ef4000}, {0x41ef6000}, 
+    {0x41ef8000}, {0x41efa000}, {0x41efc000}, {0x41efe000}, 
+    {0x41f00000}, {0x41f02000}, {0x41f04000}, {0x41f06000}, 
+    {0x41f08000}, {0x41f0a000}, {0x41f0c000}, {0x41f0e000}, 
+    {0x41f10000}, {0x41f12000}, {0x41f14000}, {0x41f16000}, 
+    {0x41f18000}, {0x41f1a000}, {0x41f1c000}, {0x41f1e000}, 
+    {0x41f20000}, {0x41f22000}, {0x41f24000}, {0x41f26000}, 
+    {0x41f28000}, {0x41f2a000}, {0x41f2c000}, {0x41f2e000}, 
+    {0x41f30000}, {0x41f32000}, {0x41f34000}, {0x41f36000}, 
+    {0x41f38000}, {0x41f3a000}, {0x41f3c000}, {0x41f3e000}, 
+    {0x41f40000}, {0x41f42000}, {0x41f44000}, {0x41f46000}, 
+    {0x41f48000}, {0x41f4a000}, {0x41f4c000}, {0x41f4e000}, 
+    {0x41f50000}, {0x41f52000}, {0x41f54000}, {0x41f56000}, 
+    {0x41f58000}, {0x41f5a000}, {0x41f5c000}, {0x41f5e000}, 
+    {0x41f60000}, {0x41f62000}, {0x41f64000}, {0x41f66000}, 
+    {0x41f68000}, {0x41f6a000}, {0x41f6c000}, {0x41f6e000}, 
+    {0x41f70000}, {0x41f72000}, {0x41f74000}, {0x41f76000}, 
+    {0x41f78000}, {0x41f7a000}, {0x41f7c000}, {0x41f7e000}, 
+    {0x41f80000}, {0x41f82000}, {0x41f84000}, {0x41f86000}, 
+    {0x41f88000}, {0x41f8a000}, {0x41f8c000}, {0x41f8e000}, 
+    {0x41f90000}, {0x41f92000}, {0x41f94000}, {0x41f96000}, 
+    {0x41f98000}, {0x41f9a000}, {0x41f9c000}, {0x41f9e000}, 
+    {0x41fa0000}, {0x41fa2000}, {0x41fa4000}, {0x41fa6000}, 
+    {0x41fa8000}, {0x41faa000}, {0x41fac000}, {0x41fae000}, 
+    {0x41fb0000}, {0x41fb2000}, {0x41fb4000}, {0x41fb6000}, 
+    {0x41fb8000}, {0x41fba000}, {0x41fbc000}, {0x41fbe000}, 
+    {0x41fc0000}, {0x41fc2000}, {0x41fc4000}, {0x41fc6000}, 
+    {0x41fc8000}, {0x41fca000}, {0x41fcc000}, {0x41fce000}, 
+    {0x41fd0000}, {0x41fd2000}, {0x41fd4000}, {0x41fd6000}, 
+    {0x41fd8000}, {0x41fda000}, {0x41fdc000}, {0x41fde000}, 
+    {0x41fe0000}, {0x41fe2000}, {0x41fe4000}, {0x41fe6000}, 
+    {0x41fe8000}, {0x41fea000}, {0x41fec000}, {0x41fee000}, 
+    {0x41ff0000}, {0x41ff2000}, {0x41ff4000}, {0x41ff6000}, 
+    {0x41ff8000}, {0x41ffa000}, {0x41ffc000}, {0x41ffe000}, 
+    {0x42000000}, {0x42002000}, {0x42004000}, {0x42006000}, 
+    {0x42008000}, {0x4200a000}, {0x4200c000}, {0x4200e000}, 
+    {0x42010000}, {0x42012000}, {0x42014000}, {0x42016000}, 
+    {0x42018000}, {0x4201a000}, {0x4201c000}, {0x4201e000}, 
+    {0x42020000}, {0x42022000}, {0x42024000}, {0x42026000}, 
+    {0x42028000}, {0x4202a000}, {0x4202c000}, {0x4202e000}, 
+    {0x42030000}, {0x42032000}, {0x42034000}, {0x42036000}, 
+    {0x42038000}, {0x4203a000}, {0x4203c000}, {0x4203e000}, 
+    {0x42040000}, {0x42042000}, {0x42044000}, {0x42046000}, 
+    {0x42048000}, {0x4204a000}, {0x4204c000}, {0x4204e000}, 
+    {0x42050000}, {0x42052000}, {0x42054000}, {0x42056000}, 
+    {0x42058000}, {0x4205a000}, {0x4205c000}, {0x4205e000}, 
+    {0x42060000}, {0x42062000}, {0x42064000}, {0x42066000}, 
+    {0x42068000}, {0x4206a000}, {0x4206c000}, {0x4206e000}, 
+    {0x42070000}, {0x42072000}, {0x42074000}, {0x42076000}, 
+    {0x42078000}, {0x4207a000}, {0x4207c000}, {0x4207e000}, 
+    {0x42080000}, {0x42082000}, {0x42084000}, {0x42086000}, 
+    {0x42088000}, {0x4208a000}, {0x4208c000}, {0x4208e000}, 
+    {0x42090000}, {0x42092000}, {0x42094000}, {0x42096000}, 
+    {0x42098000}, {0x4209a000}, {0x4209c000}, {0x4209e000}, 
+    {0x420a0000}, {0x420a2000}, {0x420a4000}, {0x420a6000}, 
+    {0x420a8000}, {0x420aa000}, {0x420ac000}, {0x420ae000}, 
+    {0x420b0000}, {0x420b2000}, {0x420b4000}, {0x420b6000}, 
+    {0x420b8000}, {0x420ba000}, {0x420bc000}, {0x420be000}, 
+    {0x420c0000}, {0x420c2000}, {0x420c4000}, {0x420c6000}, 
+    {0x420c8000}, {0x420ca000}, {0x420cc000}, {0x420ce000}, 
+    {0x420d0000}, {0x420d2000}, {0x420d4000}, {0x420d6000}, 
+    {0x420d8000}, {0x420da000}, {0x420dc000}, {0x420de000}, 
+    {0x420e0000}, {0x420e2000}, {0x420e4000}, {0x420e6000}, 
+    {0x420e8000}, {0x420ea000}, {0x420ec000}, {0x420ee000}, 
+    {0x420f0000}, {0x420f2000}, {0x420f4000}, {0x420f6000}, 
+    {0x420f8000}, {0x420fa000}, {0x420fc000}, {0x420fe000}, 
+    {0x42100000}, {0x42102000}, {0x42104000}, {0x42106000}, 
+    {0x42108000}, {0x4210a000}, {0x4210c000}, {0x4210e000}, 
+    {0x42110000}, {0x42112000}, {0x42114000}, {0x42116000}, 
+    {0x42118000}, {0x4211a000}, {0x4211c000}, {0x4211e000}, 
+    {0x42120000}, {0x42122000}, {0x42124000}, {0x42126000}, 
+    {0x42128000}, {0x4212a000}, {0x4212c000}, {0x4212e000}, 
+    {0x42130000}, {0x42132000}, {0x42134000}, {0x42136000}, 
+    {0x42138000}, {0x4213a000}, {0x4213c000}, {0x4213e000}, 
+    {0x42140000}, {0x42142000}, {0x42144000}, {0x42146000}, 
+    {0x42148000}, {0x4214a000}, {0x4214c000}, {0x4214e000}, 
+    {0x42150000}, {0x42152000}, {0x42154000}, {0x42156000}, 
+    {0x42158000}, {0x4215a000}, {0x4215c000}, {0x4215e000}, 
+    {0x42160000}, {0x42162000}, {0x42164000}, {0x42166000}, 
+    {0x42168000}, {0x4216a000}, {0x4216c000}, {0x4216e000}, 
+    {0x42170000}, {0x42172000}, {0x42174000}, {0x42176000}, 
+    {0x42178000}, {0x4217a000}, {0x4217c000}, {0x4217e000}, 
+    {0x42180000}, {0x42182000}, {0x42184000}, {0x42186000}, 
+    {0x42188000}, {0x4218a000}, {0x4218c000}, {0x4218e000}, 
+    {0x42190000}, {0x42192000}, {0x42194000}, {0x42196000}, 
+    {0x42198000}, {0x4219a000}, {0x4219c000}, {0x4219e000}, 
+    {0x421a0000}, {0x421a2000}, {0x421a4000}, {0x421a6000}, 
+    {0x421a8000}, {0x421aa000}, {0x421ac000}, {0x421ae000}, 
+    {0x421b0000}, {0x421b2000}, {0x421b4000}, {0x421b6000}, 
+    {0x421b8000}, {0x421ba000}, {0x421bc000}, {0x421be000}, 
+    {0x421c0000}, {0x421c2000}, {0x421c4000}, {0x421c6000}, 
+    {0x421c8000}, {0x421ca000}, {0x421cc000}, {0x421ce000}, 
+    {0x421d0000}, {0x421d2000}, {0x421d4000}, {0x421d6000}, 
+    {0x421d8000}, {0x421da000}, {0x421dc000}, {0x421de000}, 
+    {0x421e0000}, {0x421e2000}, {0x421e4000}, {0x421e6000}, 
+    {0x421e8000}, {0x421ea000}, {0x421ec000}, {0x421ee000}, 
+    {0x421f0000}, {0x421f2000}, {0x421f4000}, {0x421f6000}, 
+    {0x421f8000}, {0x421fa000}, {0x421fc000}, {0x421fe000}, 
+    {0x42200000}, {0x42202000}, {0x42204000}, {0x42206000}, 
+    {0x42208000}, {0x4220a000}, {0x4220c000}, {0x4220e000}, 
+    {0x42210000}, {0x42212000}, {0x42214000}, {0x42216000}, 
+    {0x42218000}, {0x4221a000}, {0x4221c000}, {0x4221e000}, 
+    {0x42220000}, {0x42222000}, {0x42224000}, {0x42226000}, 
+    {0x42228000}, {0x4222a000}, {0x4222c000}, {0x4222e000}, 
+    {0x42230000}, {0x42232000}, {0x42234000}, {0x42236000}, 
+    {0x42238000}, {0x4223a000}, {0x4223c000}, {0x4223e000}, 
+    {0x42240000}, {0x42242000}, {0x42244000}, {0x42246000}, 
+    {0x42248000}, {0x4224a000}, {0x4224c000}, {0x4224e000}, 
+    {0x42250000}, {0x42252000}, {0x42254000}, {0x42256000}, 
+    {0x42258000}, {0x4225a000}, {0x4225c000}, {0x4225e000}, 
+    {0x42260000}, {0x42262000}, {0x42264000}, {0x42266000}, 
+    {0x42268000}, {0x4226a000}, {0x4226c000}, {0x4226e000}, 
+    {0x42270000}, {0x42272000}, {0x42274000}, {0x42276000}, 
+    {0x42278000}, {0x4227a000}, {0x4227c000}, {0x4227e000}, 
+    {0x42280000}, {0x42282000}, {0x42284000}, {0x42286000}, 
+    {0x42288000}, {0x4228a000}, {0x4228c000}, {0x4228e000}, 
+    {0x42290000}, {0x42292000}, {0x42294000}, {0x42296000}, 
+    {0x42298000}, {0x4229a000}, {0x4229c000}, {0x4229e000}, 
+    {0x422a0000}, {0x422a2000}, {0x422a4000}, {0x422a6000}, 
+    {0x422a8000}, {0x422aa000}, {0x422ac000}, {0x422ae000}, 
+    {0x422b0000}, {0x422b2000}, {0x422b4000}, {0x422b6000}, 
+    {0x422b8000}, {0x422ba000}, {0x422bc000}, {0x422be000}, 
+    {0x422c0000}, {0x422c2000}, {0x422c4000}, {0x422c6000}, 
+    {0x422c8000}, {0x422ca000}, {0x422cc000}, {0x422ce000}, 
+    {0x422d0000}, {0x422d2000}, {0x422d4000}, {0x422d6000}, 
+    {0x422d8000}, {0x422da000}, {0x422dc000}, {0x422de000}, 
+    {0x422e0000}, {0x422e2000}, {0x422e4000}, {0x422e6000}, 
+    {0x422e8000}, {0x422ea000}, {0x422ec000}, {0x422ee000}, 
+    {0x422f0000}, {0x422f2000}, {0x422f4000}, {0x422f6000}, 
+    {0x422f8000}, {0x422fa000}, {0x422fc000}, {0x422fe000}, 
+    {0x42300000}, {0x42302000}, {0x42304000}, {0x42306000}, 
+    {0x42308000}, {0x4230a000}, {0x4230c000}, {0x4230e000}, 
+    {0x42310000}, {0x42312000}, {0x42314000}, {0x42316000}, 
+    {0x42318000}, {0x4231a000}, {0x4231c000}, {0x4231e000}, 
+    {0x42320000}, {0x42322000}, {0x42324000}, {0x42326000}, 
+    {0x42328000}, {0x4232a000}, {0x4232c000}, {0x4232e000}, 
+    {0x42330000}, {0x42332000}, {0x42334000}, {0x42336000}, 
+    {0x42338000}, {0x4233a000}, {0x4233c000}, {0x4233e000}, 
+    {0x42340000}, {0x42342000}, {0x42344000}, {0x42346000}, 
+    {0x42348000}, {0x4234a000}, {0x4234c000}, {0x4234e000}, 
+    {0x42350000}, {0x42352000}, {0x42354000}, {0x42356000}, 
+    {0x42358000}, {0x4235a000}, {0x4235c000}, {0x4235e000}, 
+    {0x42360000}, {0x42362000}, {0x42364000}, {0x42366000}, 
+    {0x42368000}, {0x4236a000}, {0x4236c000}, {0x4236e000}, 
+    {0x42370000}, {0x42372000}, {0x42374000}, {0x42376000}, 
+    {0x42378000}, {0x4237a000}, {0x4237c000}, {0x4237e000}, 
+    {0x42380000}, {0x42382000}, {0x42384000}, {0x42386000}, 
+    {0x42388000}, {0x4238a000}, {0x4238c000}, {0x4238e000}, 
+    {0x42390000}, {0x42392000}, {0x42394000}, {0x42396000}, 
+    {0x42398000}, {0x4239a000}, {0x4239c000}, {0x4239e000}, 
+    {0x423a0000}, {0x423a2000}, {0x423a4000}, {0x423a6000}, 
+    {0x423a8000}, {0x423aa000}, {0x423ac000}, {0x423ae000}, 
+    {0x423b0000}, {0x423b2000}, {0x423b4000}, {0x423b6000}, 
+    {0x423b8000}, {0x423ba000}, {0x423bc000}, {0x423be000}, 
+    {0x423c0000}, {0x423c2000}, {0x423c4000}, {0x423c6000}, 
+    {0x423c8000}, {0x423ca000}, {0x423cc000}, {0x423ce000}, 
+    {0x423d0000}, {0x423d2000}, {0x423d4000}, {0x423d6000}, 
+    {0x423d8000}, {0x423da000}, {0x423dc000}, {0x423de000}, 
+    {0x423e0000}, {0x423e2000}, {0x423e4000}, {0x423e6000}, 
+    {0x423e8000}, {0x423ea000}, {0x423ec000}, {0x423ee000}, 
+    {0x423f0000}, {0x423f2000}, {0x423f4000}, {0x423f6000}, 
+    {0x423f8000}, {0x423fa000}, {0x423fc000}, {0x423fe000}, 
+    {0x42400000}, {0x42402000}, {0x42404000}, {0x42406000}, 
+    {0x42408000}, {0x4240a000}, {0x4240c000}, {0x4240e000}, 
+    {0x42410000}, {0x42412000}, {0x42414000}, {0x42416000}, 
+    {0x42418000}, {0x4241a000}, {0x4241c000}, {0x4241e000}, 
+    {0x42420000}, {0x42422000}, {0x42424000}, {0x42426000}, 
+    {0x42428000}, {0x4242a000}, {0x4242c000}, {0x4242e000}, 
+    {0x42430000}, {0x42432000}, {0x42434000}, {0x42436000}, 
+    {0x42438000}, {0x4243a000}, {0x4243c000}, {0x4243e000}, 
+    {0x42440000}, {0x42442000}, {0x42444000}, {0x42446000}, 
+    {0x42448000}, {0x4244a000}, {0x4244c000}, {0x4244e000}, 
+    {0x42450000}, {0x42452000}, {0x42454000}, {0x42456000}, 
+    {0x42458000}, {0x4245a000}, {0x4245c000}, {0x4245e000}, 
+    {0x42460000}, {0x42462000}, {0x42464000}, {0x42466000}, 
+    {0x42468000}, {0x4246a000}, {0x4246c000}, {0x4246e000}, 
+    {0x42470000}, {0x42472000}, {0x42474000}, {0x42476000}, 
+    {0x42478000}, {0x4247a000}, {0x4247c000}, {0x4247e000}, 
+    {0x42480000}, {0x42482000}, {0x42484000}, {0x42486000}, 
+    {0x42488000}, {0x4248a000}, {0x4248c000}, {0x4248e000}, 
+    {0x42490000}, {0x42492000}, {0x42494000}, {0x42496000}, 
+    {0x42498000}, {0x4249a000}, {0x4249c000}, {0x4249e000}, 
+    {0x424a0000}, {0x424a2000}, {0x424a4000}, {0x424a6000}, 
+    {0x424a8000}, {0x424aa000}, {0x424ac000}, {0x424ae000}, 
+    {0x424b0000}, {0x424b2000}, {0x424b4000}, {0x424b6000}, 
+    {0x424b8000}, {0x424ba000}, {0x424bc000}, {0x424be000}, 
+    {0x424c0000}, {0x424c2000}, {0x424c4000}, {0x424c6000}, 
+    {0x424c8000}, {0x424ca000}, {0x424cc000}, {0x424ce000}, 
+    {0x424d0000}, {0x424d2000}, {0x424d4000}, {0x424d6000}, 
+    {0x424d8000}, {0x424da000}, {0x424dc000}, {0x424de000}, 
+    {0x424e0000}, {0x424e2000}, {0x424e4000}, {0x424e6000}, 
+    {0x424e8000}, {0x424ea000}, {0x424ec000}, {0x424ee000}, 
+    {0x424f0000}, {0x424f2000}, {0x424f4000}, {0x424f6000}, 
+    {0x424f8000}, {0x424fa000}, {0x424fc000}, {0x424fe000}, 
+    {0x42500000}, {0x42502000}, {0x42504000}, {0x42506000}, 
+    {0x42508000}, {0x4250a000}, {0x4250c000}, {0x4250e000}, 
+    {0x42510000}, {0x42512000}, {0x42514000}, {0x42516000}, 
+    {0x42518000}, {0x4251a000}, {0x4251c000}, {0x4251e000}, 
+    {0x42520000}, {0x42522000}, {0x42524000}, {0x42526000}, 
+    {0x42528000}, {0x4252a000}, {0x4252c000}, {0x4252e000}, 
+    {0x42530000}, {0x42532000}, {0x42534000}, {0x42536000}, 
+    {0x42538000}, {0x4253a000}, {0x4253c000}, {0x4253e000}, 
+    {0x42540000}, {0x42542000}, {0x42544000}, {0x42546000}, 
+    {0x42548000}, {0x4254a000}, {0x4254c000}, {0x4254e000}, 
+    {0x42550000}, {0x42552000}, {0x42554000}, {0x42556000}, 
+    {0x42558000}, {0x4255a000}, {0x4255c000}, {0x4255e000}, 
+    {0x42560000}, {0x42562000}, {0x42564000}, {0x42566000}, 
+    {0x42568000}, {0x4256a000}, {0x4256c000}, {0x4256e000}, 
+    {0x42570000}, {0x42572000}, {0x42574000}, {0x42576000}, 
+    {0x42578000}, {0x4257a000}, {0x4257c000}, {0x4257e000}, 
+    {0x42580000}, {0x42582000}, {0x42584000}, {0x42586000}, 
+    {0x42588000}, {0x4258a000}, {0x4258c000}, {0x4258e000}, 
+    {0x42590000}, {0x42592000}, {0x42594000}, {0x42596000}, 
+    {0x42598000}, {0x4259a000}, {0x4259c000}, {0x4259e000}, 
+    {0x425a0000}, {0x425a2000}, {0x425a4000}, {0x425a6000}, 
+    {0x425a8000}, {0x425aa000}, {0x425ac000}, {0x425ae000}, 
+    {0x425b0000}, {0x425b2000}, {0x425b4000}, {0x425b6000}, 
+    {0x425b8000}, {0x425ba000}, {0x425bc000}, {0x425be000}, 
+    {0x425c0000}, {0x425c2000}, {0x425c4000}, {0x425c6000}, 
+    {0x425c8000}, {0x425ca000}, {0x425cc000}, {0x425ce000}, 
+    {0x425d0000}, {0x425d2000}, {0x425d4000}, {0x425d6000}, 
+    {0x425d8000}, {0x425da000}, {0x425dc000}, {0x425de000}, 
+    {0x425e0000}, {0x425e2000}, {0x425e4000}, {0x425e6000}, 
+    {0x425e8000}, {0x425ea000}, {0x425ec000}, {0x425ee000}, 
+    {0x425f0000}, {0x425f2000}, {0x425f4000}, {0x425f6000}, 
+    {0x425f8000}, {0x425fa000}, {0x425fc000}, {0x425fe000}, 
+    {0x42600000}, {0x42602000}, {0x42604000}, {0x42606000}, 
+    {0x42608000}, {0x4260a000}, {0x4260c000}, {0x4260e000}, 
+    {0x42610000}, {0x42612000}, {0x42614000}, {0x42616000}, 
+    {0x42618000}, {0x4261a000}, {0x4261c000}, {0x4261e000}, 
+    {0x42620000}, {0x42622000}, {0x42624000}, {0x42626000}, 
+    {0x42628000}, {0x4262a000}, {0x4262c000}, {0x4262e000}, 
+    {0x42630000}, {0x42632000}, {0x42634000}, {0x42636000}, 
+    {0x42638000}, {0x4263a000}, {0x4263c000}, {0x4263e000}, 
+    {0x42640000}, {0x42642000}, {0x42644000}, {0x42646000}, 
+    {0x42648000}, {0x4264a000}, {0x4264c000}, {0x4264e000}, 
+    {0x42650000}, {0x42652000}, {0x42654000}, {0x42656000}, 
+    {0x42658000}, {0x4265a000}, {0x4265c000}, {0x4265e000}, 
+    {0x42660000}, {0x42662000}, {0x42664000}, {0x42666000}, 
+    {0x42668000}, {0x4266a000}, {0x4266c000}, {0x4266e000}, 
+    {0x42670000}, {0x42672000}, {0x42674000}, {0x42676000}, 
+    {0x42678000}, {0x4267a000}, {0x4267c000}, {0x4267e000}, 
+    {0x42680000}, {0x42682000}, {0x42684000}, {0x42686000}, 
+    {0x42688000}, {0x4268a000}, {0x4268c000}, {0x4268e000}, 
+    {0x42690000}, {0x42692000}, {0x42694000}, {0x42696000}, 
+    {0x42698000}, {0x4269a000}, {0x4269c000}, {0x4269e000}, 
+    {0x426a0000}, {0x426a2000}, {0x426a4000}, {0x426a6000}, 
+    {0x426a8000}, {0x426aa000}, {0x426ac000}, {0x426ae000}, 
+    {0x426b0000}, {0x426b2000}, {0x426b4000}, {0x426b6000}, 
+    {0x426b8000}, {0x426ba000}, {0x426bc000}, {0x426be000}, 
+    {0x426c0000}, {0x426c2000}, {0x426c4000}, {0x426c6000}, 
+    {0x426c8000}, {0x426ca000}, {0x426cc000}, {0x426ce000}, 
+    {0x426d0000}, {0x426d2000}, {0x426d4000}, {0x426d6000}, 
+    {0x426d8000}, {0x426da000}, {0x426dc000}, {0x426de000}, 
+    {0x426e0000}, {0x426e2000}, {0x426e4000}, {0x426e6000}, 
+    {0x426e8000}, {0x426ea000}, {0x426ec000}, {0x426ee000}, 
+    {0x426f0000}, {0x426f2000}, {0x426f4000}, {0x426f6000}, 
+    {0x426f8000}, {0x426fa000}, {0x426fc000}, {0x426fe000}, 
+    {0x42700000}, {0x42702000}, {0x42704000}, {0x42706000}, 
+    {0x42708000}, {0x4270a000}, {0x4270c000}, {0x4270e000}, 
+    {0x42710000}, {0x42712000}, {0x42714000}, {0x42716000}, 
+    {0x42718000}, {0x4271a000}, {0x4271c000}, {0x4271e000}, 
+    {0x42720000}, {0x42722000}, {0x42724000}, {0x42726000}, 
+    {0x42728000}, {0x4272a000}, {0x4272c000}, {0x4272e000}, 
+    {0x42730000}, {0x42732000}, {0x42734000}, {0x42736000}, 
+    {0x42738000}, {0x4273a000}, {0x4273c000}, {0x4273e000}, 
+    {0x42740000}, {0x42742000}, {0x42744000}, {0x42746000}, 
+    {0x42748000}, {0x4274a000}, {0x4274c000}, {0x4274e000}, 
+    {0x42750000}, {0x42752000}, {0x42754000}, {0x42756000}, 
+    {0x42758000}, {0x4275a000}, {0x4275c000}, {0x4275e000}, 
+    {0x42760000}, {0x42762000}, {0x42764000}, {0x42766000}, 
+    {0x42768000}, {0x4276a000}, {0x4276c000}, {0x4276e000}, 
+    {0x42770000}, {0x42772000}, {0x42774000}, {0x42776000}, 
+    {0x42778000}, {0x4277a000}, {0x4277c000}, {0x4277e000}, 
+    {0x42780000}, {0x42782000}, {0x42784000}, {0x42786000}, 
+    {0x42788000}, {0x4278a000}, {0x4278c000}, {0x4278e000}, 
+    {0x42790000}, {0x42792000}, {0x42794000}, {0x42796000}, 
+    {0x42798000}, {0x4279a000}, {0x4279c000}, {0x4279e000}, 
+    {0x427a0000}, {0x427a2000}, {0x427a4000}, {0x427a6000}, 
+    {0x427a8000}, {0x427aa000}, {0x427ac000}, {0x427ae000}, 
+    {0x427b0000}, {0x427b2000}, {0x427b4000}, {0x427b6000}, 
+    {0x427b8000}, {0x427ba000}, {0x427bc000}, {0x427be000}, 
+    {0x427c0000}, {0x427c2000}, {0x427c4000}, {0x427c6000}, 
+    {0x427c8000}, {0x427ca000}, {0x427cc000}, {0x427ce000}, 
+    {0x427d0000}, {0x427d2000}, {0x427d4000}, {0x427d6000}, 
+    {0x427d8000}, {0x427da000}, {0x427dc000}, {0x427de000}, 
+    {0x427e0000}, {0x427e2000}, {0x427e4000}, {0x427e6000}, 
+    {0x427e8000}, {0x427ea000}, {0x427ec000}, {0x427ee000}, 
+    {0x427f0000}, {0x427f2000}, {0x427f4000}, {0x427f6000}, 
+    {0x427f8000}, {0x427fa000}, {0x427fc000}, {0x427fe000}, 
+    {0x42800000}, {0x42802000}, {0x42804000}, {0x42806000}, 
+    {0x42808000}, {0x4280a000}, {0x4280c000}, {0x4280e000}, 
+    {0x42810000}, {0x42812000}, {0x42814000}, {0x42816000}, 
+    {0x42818000}, {0x4281a000}, {0x4281c000}, {0x4281e000}, 
+    {0x42820000}, {0x42822000}, {0x42824000}, {0x42826000}, 
+    {0x42828000}, {0x4282a000}, {0x4282c000}, {0x4282e000}, 
+    {0x42830000}, {0x42832000}, {0x42834000}, {0x42836000}, 
+    {0x42838000}, {0x4283a000}, {0x4283c000}, {0x4283e000}, 
+    {0x42840000}, {0x42842000}, {0x42844000}, {0x42846000}, 
+    {0x42848000}, {0x4284a000}, {0x4284c000}, {0x4284e000}, 
+    {0x42850000}, {0x42852000}, {0x42854000}, {0x42856000}, 
+    {0x42858000}, {0x4285a000}, {0x4285c000}, {0x4285e000}, 
+    {0x42860000}, {0x42862000}, {0x42864000}, {0x42866000}, 
+    {0x42868000}, {0x4286a000}, {0x4286c000}, {0x4286e000}, 
+    {0x42870000}, {0x42872000}, {0x42874000}, {0x42876000}, 
+    {0x42878000}, {0x4287a000}, {0x4287c000}, {0x4287e000}, 
+    {0x42880000}, {0x42882000}, {0x42884000}, {0x42886000}, 
+    {0x42888000}, {0x4288a000}, {0x4288c000}, {0x4288e000}, 
+    {0x42890000}, {0x42892000}, {0x42894000}, {0x42896000}, 
+    {0x42898000}, {0x4289a000}, {0x4289c000}, {0x4289e000}, 
+    {0x428a0000}, {0x428a2000}, {0x428a4000}, {0x428a6000}, 
+    {0x428a8000}, {0x428aa000}, {0x428ac000}, {0x428ae000}, 
+    {0x428b0000}, {0x428b2000}, {0x428b4000}, {0x428b6000}, 
+    {0x428b8000}, {0x428ba000}, {0x428bc000}, {0x428be000}, 
+    {0x428c0000}, {0x428c2000}, {0x428c4000}, {0x428c6000}, 
+    {0x428c8000}, {0x428ca000}, {0x428cc000}, {0x428ce000}, 
+    {0x428d0000}, {0x428d2000}, {0x428d4000}, {0x428d6000}, 
+    {0x428d8000}, {0x428da000}, {0x428dc000}, {0x428de000}, 
+    {0x428e0000}, {0x428e2000}, {0x428e4000}, {0x428e6000}, 
+    {0x428e8000}, {0x428ea000}, {0x428ec000}, {0x428ee000}, 
+    {0x428f0000}, {0x428f2000}, {0x428f4000}, {0x428f6000}, 
+    {0x428f8000}, {0x428fa000}, {0x428fc000}, {0x428fe000}, 
+    {0x42900000}, {0x42902000}, {0x42904000}, {0x42906000}, 
+    {0x42908000}, {0x4290a000}, {0x4290c000}, {0x4290e000}, 
+    {0x42910000}, {0x42912000}, {0x42914000}, {0x42916000}, 
+    {0x42918000}, {0x4291a000}, {0x4291c000}, {0x4291e000}, 
+    {0x42920000}, {0x42922000}, {0x42924000}, {0x42926000}, 
+    {0x42928000}, {0x4292a000}, {0x4292c000}, {0x4292e000}, 
+    {0x42930000}, {0x42932000}, {0x42934000}, {0x42936000}, 
+    {0x42938000}, {0x4293a000}, {0x4293c000}, {0x4293e000}, 
+    {0x42940000}, {0x42942000}, {0x42944000}, {0x42946000}, 
+    {0x42948000}, {0x4294a000}, {0x4294c000}, {0x4294e000}, 
+    {0x42950000}, {0x42952000}, {0x42954000}, {0x42956000}, 
+    {0x42958000}, {0x4295a000}, {0x4295c000}, {0x4295e000}, 
+    {0x42960000}, {0x42962000}, {0x42964000}, {0x42966000}, 
+    {0x42968000}, {0x4296a000}, {0x4296c000}, {0x4296e000}, 
+    {0x42970000}, {0x42972000}, {0x42974000}, {0x42976000}, 
+    {0x42978000}, {0x4297a000}, {0x4297c000}, {0x4297e000}, 
+    {0x42980000}, {0x42982000}, {0x42984000}, {0x42986000}, 
+    {0x42988000}, {0x4298a000}, {0x4298c000}, {0x4298e000}, 
+    {0x42990000}, {0x42992000}, {0x42994000}, {0x42996000}, 
+    {0x42998000}, {0x4299a000}, {0x4299c000}, {0x4299e000}, 
+    {0x429a0000}, {0x429a2000}, {0x429a4000}, {0x429a6000}, 
+    {0x429a8000}, {0x429aa000}, {0x429ac000}, {0x429ae000}, 
+    {0x429b0000}, {0x429b2000}, {0x429b4000}, {0x429b6000}, 
+    {0x429b8000}, {0x429ba000}, {0x429bc000}, {0x429be000}, 
+    {0x429c0000}, {0x429c2000}, {0x429c4000}, {0x429c6000}, 
+    {0x429c8000}, {0x429ca000}, {0x429cc000}, {0x429ce000}, 
+    {0x429d0000}, {0x429d2000}, {0x429d4000}, {0x429d6000}, 
+    {0x429d8000}, {0x429da000}, {0x429dc000}, {0x429de000}, 
+    {0x429e0000}, {0x429e2000}, {0x429e4000}, {0x429e6000}, 
+    {0x429e8000}, {0x429ea000}, {0x429ec000}, {0x429ee000}, 
+    {0x429f0000}, {0x429f2000}, {0x429f4000}, {0x429f6000}, 
+    {0x429f8000}, {0x429fa000}, {0x429fc000}, {0x429fe000}, 
+    {0x42a00000}, {0x42a02000}, {0x42a04000}, {0x42a06000}, 
+    {0x42a08000}, {0x42a0a000}, {0x42a0c000}, {0x42a0e000}, 
+    {0x42a10000}, {0x42a12000}, {0x42a14000}, {0x42a16000}, 
+    {0x42a18000}, {0x42a1a000}, {0x42a1c000}, {0x42a1e000}, 
+    {0x42a20000}, {0x42a22000}, {0x42a24000}, {0x42a26000}, 
+    {0x42a28000}, {0x42a2a000}, {0x42a2c000}, {0x42a2e000}, 
+    {0x42a30000}, {0x42a32000}, {0x42a34000}, {0x42a36000}, 
+    {0x42a38000}, {0x42a3a000}, {0x42a3c000}, {0x42a3e000}, 
+    {0x42a40000}, {0x42a42000}, {0x42a44000}, {0x42a46000}, 
+    {0x42a48000}, {0x42a4a000}, {0x42a4c000}, {0x42a4e000}, 
+    {0x42a50000}, {0x42a52000}, {0x42a54000}, {0x42a56000}, 
+    {0x42a58000}, {0x42a5a000}, {0x42a5c000}, {0x42a5e000}, 
+    {0x42a60000}, {0x42a62000}, {0x42a64000}, {0x42a66000}, 
+    {0x42a68000}, {0x42a6a000}, {0x42a6c000}, {0x42a6e000}, 
+    {0x42a70000}, {0x42a72000}, {0x42a74000}, {0x42a76000}, 
+    {0x42a78000}, {0x42a7a000}, {0x42a7c000}, {0x42a7e000}, 
+    {0x42a80000}, {0x42a82000}, {0x42a84000}, {0x42a86000}, 
+    {0x42a88000}, {0x42a8a000}, {0x42a8c000}, {0x42a8e000}, 
+    {0x42a90000}, {0x42a92000}, {0x42a94000}, {0x42a96000}, 
+    {0x42a98000}, {0x42a9a000}, {0x42a9c000}, {0x42a9e000}, 
+    {0x42aa0000}, {0x42aa2000}, {0x42aa4000}, {0x42aa6000}, 
+    {0x42aa8000}, {0x42aaa000}, {0x42aac000}, {0x42aae000}, 
+    {0x42ab0000}, {0x42ab2000}, {0x42ab4000}, {0x42ab6000}, 
+    {0x42ab8000}, {0x42aba000}, {0x42abc000}, {0x42abe000}, 
+    {0x42ac0000}, {0x42ac2000}, {0x42ac4000}, {0x42ac6000}, 
+    {0x42ac8000}, {0x42aca000}, {0x42acc000}, {0x42ace000}, 
+    {0x42ad0000}, {0x42ad2000}, {0x42ad4000}, {0x42ad6000}, 
+    {0x42ad8000}, {0x42ada000}, {0x42adc000}, {0x42ade000}, 
+    {0x42ae0000}, {0x42ae2000}, {0x42ae4000}, {0x42ae6000}, 
+    {0x42ae8000}, {0x42aea000}, {0x42aec000}, {0x42aee000}, 
+    {0x42af0000}, {0x42af2000}, {0x42af4000}, {0x42af6000}, 
+    {0x42af8000}, {0x42afa000}, {0x42afc000}, {0x42afe000}, 
+    {0x42b00000}, {0x42b02000}, {0x42b04000}, {0x42b06000}, 
+    {0x42b08000}, {0x42b0a000}, {0x42b0c000}, {0x42b0e000}, 
+    {0x42b10000}, {0x42b12000}, {0x42b14000}, {0x42b16000}, 
+    {0x42b18000}, {0x42b1a000}, {0x42b1c000}, {0x42b1e000}, 
+    {0x42b20000}, {0x42b22000}, {0x42b24000}, {0x42b26000}, 
+    {0x42b28000}, {0x42b2a000}, {0x42b2c000}, {0x42b2e000}, 
+    {0x42b30000}, {0x42b32000}, {0x42b34000}, {0x42b36000}, 
+    {0x42b38000}, {0x42b3a000}, {0x42b3c000}, {0x42b3e000}, 
+    {0x42b40000}, {0x42b42000}, {0x42b44000}, {0x42b46000}, 
+    {0x42b48000}, {0x42b4a000}, {0x42b4c000}, {0x42b4e000}, 
+    {0x42b50000}, {0x42b52000}, {0x42b54000}, {0x42b56000}, 
+    {0x42b58000}, {0x42b5a000}, {0x42b5c000}, {0x42b5e000}, 
+    {0x42b60000}, {0x42b62000}, {0x42b64000}, {0x42b66000}, 
+    {0x42b68000}, {0x42b6a000}, {0x42b6c000}, {0x42b6e000}, 
+    {0x42b70000}, {0x42b72000}, {0x42b74000}, {0x42b76000}, 
+    {0x42b78000}, {0x42b7a000}, {0x42b7c000}, {0x42b7e000}, 
+    {0x42b80000}, {0x42b82000}, {0x42b84000}, {0x42b86000}, 
+    {0x42b88000}, {0x42b8a000}, {0x42b8c000}, {0x42b8e000}, 
+    {0x42b90000}, {0x42b92000}, {0x42b94000}, {0x42b96000}, 
+    {0x42b98000}, {0x42b9a000}, {0x42b9c000}, {0x42b9e000}, 
+    {0x42ba0000}, {0x42ba2000}, {0x42ba4000}, {0x42ba6000}, 
+    {0x42ba8000}, {0x42baa000}, {0x42bac000}, {0x42bae000}, 
+    {0x42bb0000}, {0x42bb2000}, {0x42bb4000}, {0x42bb6000}, 
+    {0x42bb8000}, {0x42bba000}, {0x42bbc000}, {0x42bbe000}, 
+    {0x42bc0000}, {0x42bc2000}, {0x42bc4000}, {0x42bc6000}, 
+    {0x42bc8000}, {0x42bca000}, {0x42bcc000}, {0x42bce000}, 
+    {0x42bd0000}, {0x42bd2000}, {0x42bd4000}, {0x42bd6000}, 
+    {0x42bd8000}, {0x42bda000}, {0x42bdc000}, {0x42bde000}, 
+    {0x42be0000}, {0x42be2000}, {0x42be4000}, {0x42be6000}, 
+    {0x42be8000}, {0x42bea000}, {0x42bec000}, {0x42bee000}, 
+    {0x42bf0000}, {0x42bf2000}, {0x42bf4000}, {0x42bf6000}, 
+    {0x42bf8000}, {0x42bfa000}, {0x42bfc000}, {0x42bfe000}, 
+    {0x42c00000}, {0x42c02000}, {0x42c04000}, {0x42c06000}, 
+    {0x42c08000}, {0x42c0a000}, {0x42c0c000}, {0x42c0e000}, 
+    {0x42c10000}, {0x42c12000}, {0x42c14000}, {0x42c16000}, 
+    {0x42c18000}, {0x42c1a000}, {0x42c1c000}, {0x42c1e000}, 
+    {0x42c20000}, {0x42c22000}, {0x42c24000}, {0x42c26000}, 
+    {0x42c28000}, {0x42c2a000}, {0x42c2c000}, {0x42c2e000}, 
+    {0x42c30000}, {0x42c32000}, {0x42c34000}, {0x42c36000}, 
+    {0x42c38000}, {0x42c3a000}, {0x42c3c000}, {0x42c3e000}, 
+    {0x42c40000}, {0x42c42000}, {0x42c44000}, {0x42c46000}, 
+    {0x42c48000}, {0x42c4a000}, {0x42c4c000}, {0x42c4e000}, 
+    {0x42c50000}, {0x42c52000}, {0x42c54000}, {0x42c56000}, 
+    {0x42c58000}, {0x42c5a000}, {0x42c5c000}, {0x42c5e000}, 
+    {0x42c60000}, {0x42c62000}, {0x42c64000}, {0x42c66000}, 
+    {0x42c68000}, {0x42c6a000}, {0x42c6c000}, {0x42c6e000}, 
+    {0x42c70000}, {0x42c72000}, {0x42c74000}, {0x42c76000}, 
+    {0x42c78000}, {0x42c7a000}, {0x42c7c000}, {0x42c7e000}, 
+    {0x42c80000}, {0x42c82000}, {0x42c84000}, {0x42c86000}, 
+    {0x42c88000}, {0x42c8a000}, {0x42c8c000}, {0x42c8e000}, 
+    {0x42c90000}, {0x42c92000}, {0x42c94000}, {0x42c96000}, 
+    {0x42c98000}, {0x42c9a000}, {0x42c9c000}, {0x42c9e000}, 
+    {0x42ca0000}, {0x42ca2000}, {0x42ca4000}, {0x42ca6000}, 
+    {0x42ca8000}, {0x42caa000}, {0x42cac000}, {0x42cae000}, 
+    {0x42cb0000}, {0x42cb2000}, {0x42cb4000}, {0x42cb6000}, 
+    {0x42cb8000}, {0x42cba000}, {0x42cbc000}, {0x42cbe000}, 
+    {0x42cc0000}, {0x42cc2000}, {0x42cc4000}, {0x42cc6000}, 
+    {0x42cc8000}, {0x42cca000}, {0x42ccc000}, {0x42cce000}, 
+    {0x42cd0000}, {0x42cd2000}, {0x42cd4000}, {0x42cd6000}, 
+    {0x42cd8000}, {0x42cda000}, {0x42cdc000}, {0x42cde000}, 
+    {0x42ce0000}, {0x42ce2000}, {0x42ce4000}, {0x42ce6000}, 
+    {0x42ce8000}, {0x42cea000}, {0x42cec000}, {0x42cee000}, 
+    {0x42cf0000}, {0x42cf2000}, {0x42cf4000}, {0x42cf6000}, 
+    {0x42cf8000}, {0x42cfa000}, {0x42cfc000}, {0x42cfe000}, 
+    {0x42d00000}, {0x42d02000}, {0x42d04000}, {0x42d06000}, 
+    {0x42d08000}, {0x42d0a000}, {0x42d0c000}, {0x42d0e000}, 
+    {0x42d10000}, {0x42d12000}, {0x42d14000}, {0x42d16000}, 
+    {0x42d18000}, {0x42d1a000}, {0x42d1c000}, {0x42d1e000}, 
+    {0x42d20000}, {0x42d22000}, {0x42d24000}, {0x42d26000}, 
+    {0x42d28000}, {0x42d2a000}, {0x42d2c000}, {0x42d2e000}, 
+    {0x42d30000}, {0x42d32000}, {0x42d34000}, {0x42d36000}, 
+    {0x42d38000}, {0x42d3a000}, {0x42d3c000}, {0x42d3e000}, 
+    {0x42d40000}, {0x42d42000}, {0x42d44000}, {0x42d46000}, 
+    {0x42d48000}, {0x42d4a000}, {0x42d4c000}, {0x42d4e000}, 
+    {0x42d50000}, {0x42d52000}, {0x42d54000}, {0x42d56000}, 
+    {0x42d58000}, {0x42d5a000}, {0x42d5c000}, {0x42d5e000}, 
+    {0x42d60000}, {0x42d62000}, {0x42d64000}, {0x42d66000}, 
+    {0x42d68000}, {0x42d6a000}, {0x42d6c000}, {0x42d6e000}, 
+    {0x42d70000}, {0x42d72000}, {0x42d74000}, {0x42d76000}, 
+    {0x42d78000}, {0x42d7a000}, {0x42d7c000}, {0x42d7e000}, 
+    {0x42d80000}, {0x42d82000}, {0x42d84000}, {0x42d86000}, 
+    {0x42d88000}, {0x42d8a000}, {0x42d8c000}, {0x42d8e000}, 
+    {0x42d90000}, {0x42d92000}, {0x42d94000}, {0x42d96000}, 
+    {0x42d98000}, {0x42d9a000}, {0x42d9c000}, {0x42d9e000}, 
+    {0x42da0000}, {0x42da2000}, {0x42da4000}, {0x42da6000}, 
+    {0x42da8000}, {0x42daa000}, {0x42dac000}, {0x42dae000}, 
+    {0x42db0000}, {0x42db2000}, {0x42db4000}, {0x42db6000}, 
+    {0x42db8000}, {0x42dba000}, {0x42dbc000}, {0x42dbe000}, 
+    {0x42dc0000}, {0x42dc2000}, {0x42dc4000}, {0x42dc6000}, 
+    {0x42dc8000}, {0x42dca000}, {0x42dcc000}, {0x42dce000}, 
+    {0x42dd0000}, {0x42dd2000}, {0x42dd4000}, {0x42dd6000}, 
+    {0x42dd8000}, {0x42dda000}, {0x42ddc000}, {0x42dde000}, 
+    {0x42de0000}, {0x42de2000}, {0x42de4000}, {0x42de6000}, 
+    {0x42de8000}, {0x42dea000}, {0x42dec000}, {0x42dee000}, 
+    {0x42df0000}, {0x42df2000}, {0x42df4000}, {0x42df6000}, 
+    {0x42df8000}, {0x42dfa000}, {0x42dfc000}, {0x42dfe000}, 
+    {0x42e00000}, {0x42e02000}, {0x42e04000}, {0x42e06000}, 
+    {0x42e08000}, {0x42e0a000}, {0x42e0c000}, {0x42e0e000}, 
+    {0x42e10000}, {0x42e12000}, {0x42e14000}, {0x42e16000}, 
+    {0x42e18000}, {0x42e1a000}, {0x42e1c000}, {0x42e1e000}, 
+    {0x42e20000}, {0x42e22000}, {0x42e24000}, {0x42e26000}, 
+    {0x42e28000}, {0x42e2a000}, {0x42e2c000}, {0x42e2e000}, 
+    {0x42e30000}, {0x42e32000}, {0x42e34000}, {0x42e36000}, 
+    {0x42e38000}, {0x42e3a000}, {0x42e3c000}, {0x42e3e000}, 
+    {0x42e40000}, {0x42e42000}, {0x42e44000}, {0x42e46000}, 
+    {0x42e48000}, {0x42e4a000}, {0x42e4c000}, {0x42e4e000}, 
+    {0x42e50000}, {0x42e52000}, {0x42e54000}, {0x42e56000}, 
+    {0x42e58000}, {0x42e5a000}, {0x42e5c000}, {0x42e5e000}, 
+    {0x42e60000}, {0x42e62000}, {0x42e64000}, {0x42e66000}, 
+    {0x42e68000}, {0x42e6a000}, {0x42e6c000}, {0x42e6e000}, 
+    {0x42e70000}, {0x42e72000}, {0x42e74000}, {0x42e76000}, 
+    {0x42e78000}, {0x42e7a000}, {0x42e7c000}, {0x42e7e000}, 
+    {0x42e80000}, {0x42e82000}, {0x42e84000}, {0x42e86000}, 
+    {0x42e88000}, {0x42e8a000}, {0x42e8c000}, {0x42e8e000}, 
+    {0x42e90000}, {0x42e92000}, {0x42e94000}, {0x42e96000}, 
+    {0x42e98000}, {0x42e9a000}, {0x42e9c000}, {0x42e9e000}, 
+    {0x42ea0000}, {0x42ea2000}, {0x42ea4000}, {0x42ea6000}, 
+    {0x42ea8000}, {0x42eaa000}, {0x42eac000}, {0x42eae000}, 
+    {0x42eb0000}, {0x42eb2000}, {0x42eb4000}, {0x42eb6000}, 
+    {0x42eb8000}, {0x42eba000}, {0x42ebc000}, {0x42ebe000}, 
+    {0x42ec0000}, {0x42ec2000}, {0x42ec4000}, {0x42ec6000}, 
+    {0x42ec8000}, {0x42eca000}, {0x42ecc000}, {0x42ece000}, 
+    {0x42ed0000}, {0x42ed2000}, {0x42ed4000}, {0x42ed6000}, 
+    {0x42ed8000}, {0x42eda000}, {0x42edc000}, {0x42ede000}, 
+    {0x42ee0000}, {0x42ee2000}, {0x42ee4000}, {0x42ee6000}, 
+    {0x42ee8000}, {0x42eea000}, {0x42eec000}, {0x42eee000}, 
+    {0x42ef0000}, {0x42ef2000}, {0x42ef4000}, {0x42ef6000}, 
+    {0x42ef8000}, {0x42efa000}, {0x42efc000}, {0x42efe000}, 
+    {0x42f00000}, {0x42f02000}, {0x42f04000}, {0x42f06000}, 
+    {0x42f08000}, {0x42f0a000}, {0x42f0c000}, {0x42f0e000}, 
+    {0x42f10000}, {0x42f12000}, {0x42f14000}, {0x42f16000}, 
+    {0x42f18000}, {0x42f1a000}, {0x42f1c000}, {0x42f1e000}, 
+    {0x42f20000}, {0x42f22000}, {0x42f24000}, {0x42f26000}, 
+    {0x42f28000}, {0x42f2a000}, {0x42f2c000}, {0x42f2e000}, 
+    {0x42f30000}, {0x42f32000}, {0x42f34000}, {0x42f36000}, 
+    {0x42f38000}, {0x42f3a000}, {0x42f3c000}, {0x42f3e000}, 
+    {0x42f40000}, {0x42f42000}, {0x42f44000}, {0x42f46000}, 
+    {0x42f48000}, {0x42f4a000}, {0x42f4c000}, {0x42f4e000}, 
+    {0x42f50000}, {0x42f52000}, {0x42f54000}, {0x42f56000}, 
+    {0x42f58000}, {0x42f5a000}, {0x42f5c000}, {0x42f5e000}, 
+    {0x42f60000}, {0x42f62000}, {0x42f64000}, {0x42f66000}, 
+    {0x42f68000}, {0x42f6a000}, {0x42f6c000}, {0x42f6e000}, 
+    {0x42f70000}, {0x42f72000}, {0x42f74000}, {0x42f76000}, 
+    {0x42f78000}, {0x42f7a000}, {0x42f7c000}, {0x42f7e000}, 
+    {0x42f80000}, {0x42f82000}, {0x42f84000}, {0x42f86000}, 
+    {0x42f88000}, {0x42f8a000}, {0x42f8c000}, {0x42f8e000}, 
+    {0x42f90000}, {0x42f92000}, {0x42f94000}, {0x42f96000}, 
+    {0x42f98000}, {0x42f9a000}, {0x42f9c000}, {0x42f9e000}, 
+    {0x42fa0000}, {0x42fa2000}, {0x42fa4000}, {0x42fa6000}, 
+    {0x42fa8000}, {0x42faa000}, {0x42fac000}, {0x42fae000}, 
+    {0x42fb0000}, {0x42fb2000}, {0x42fb4000}, {0x42fb6000}, 
+    {0x42fb8000}, {0x42fba000}, {0x42fbc000}, {0x42fbe000}, 
+    {0x42fc0000}, {0x42fc2000}, {0x42fc4000}, {0x42fc6000}, 
+    {0x42fc8000}, {0x42fca000}, {0x42fcc000}, {0x42fce000}, 
+    {0x42fd0000}, {0x42fd2000}, {0x42fd4000}, {0x42fd6000}, 
+    {0x42fd8000}, {0x42fda000}, {0x42fdc000}, {0x42fde000}, 
+    {0x42fe0000}, {0x42fe2000}, {0x42fe4000}, {0x42fe6000}, 
+    {0x42fe8000}, {0x42fea000}, {0x42fec000}, {0x42fee000}, 
+    {0x42ff0000}, {0x42ff2000}, {0x42ff4000}, {0x42ff6000}, 
+    {0x42ff8000}, {0x42ffa000}, {0x42ffc000}, {0x42ffe000}, 
+    {0x43000000}, {0x43002000}, {0x43004000}, {0x43006000}, 
+    {0x43008000}, {0x4300a000}, {0x4300c000}, {0x4300e000}, 
+    {0x43010000}, {0x43012000}, {0x43014000}, {0x43016000}, 
+    {0x43018000}, {0x4301a000}, {0x4301c000}, {0x4301e000}, 
+    {0x43020000}, {0x43022000}, {0x43024000}, {0x43026000}, 
+    {0x43028000}, {0x4302a000}, {0x4302c000}, {0x4302e000}, 
+    {0x43030000}, {0x43032000}, {0x43034000}, {0x43036000}, 
+    {0x43038000}, {0x4303a000}, {0x4303c000}, {0x4303e000}, 
+    {0x43040000}, {0x43042000}, {0x43044000}, {0x43046000}, 
+    {0x43048000}, {0x4304a000}, {0x4304c000}, {0x4304e000}, 
+    {0x43050000}, {0x43052000}, {0x43054000}, {0x43056000}, 
+    {0x43058000}, {0x4305a000}, {0x4305c000}, {0x4305e000}, 
+    {0x43060000}, {0x43062000}, {0x43064000}, {0x43066000}, 
+    {0x43068000}, {0x4306a000}, {0x4306c000}, {0x4306e000}, 
+    {0x43070000}, {0x43072000}, {0x43074000}, {0x43076000}, 
+    {0x43078000}, {0x4307a000}, {0x4307c000}, {0x4307e000}, 
+    {0x43080000}, {0x43082000}, {0x43084000}, {0x43086000}, 
+    {0x43088000}, {0x4308a000}, {0x4308c000}, {0x4308e000}, 
+    {0x43090000}, {0x43092000}, {0x43094000}, {0x43096000}, 
+    {0x43098000}, {0x4309a000}, {0x4309c000}, {0x4309e000}, 
+    {0x430a0000}, {0x430a2000}, {0x430a4000}, {0x430a6000}, 
+    {0x430a8000}, {0x430aa000}, {0x430ac000}, {0x430ae000}, 
+    {0x430b0000}, {0x430b2000}, {0x430b4000}, {0x430b6000}, 
+    {0x430b8000}, {0x430ba000}, {0x430bc000}, {0x430be000}, 
+    {0x430c0000}, {0x430c2000}, {0x430c4000}, {0x430c6000}, 
+    {0x430c8000}, {0x430ca000}, {0x430cc000}, {0x430ce000}, 
+    {0x430d0000}, {0x430d2000}, {0x430d4000}, {0x430d6000}, 
+    {0x430d8000}, {0x430da000}, {0x430dc000}, {0x430de000}, 
+    {0x430e0000}, {0x430e2000}, {0x430e4000}, {0x430e6000}, 
+    {0x430e8000}, {0x430ea000}, {0x430ec000}, {0x430ee000}, 
+    {0x430f0000}, {0x430f2000}, {0x430f4000}, {0x430f6000}, 
+    {0x430f8000}, {0x430fa000}, {0x430fc000}, {0x430fe000}, 
+    {0x43100000}, {0x43102000}, {0x43104000}, {0x43106000}, 
+    {0x43108000}, {0x4310a000}, {0x4310c000}, {0x4310e000}, 
+    {0x43110000}, {0x43112000}, {0x43114000}, {0x43116000}, 
+    {0x43118000}, {0x4311a000}, {0x4311c000}, {0x4311e000}, 
+    {0x43120000}, {0x43122000}, {0x43124000}, {0x43126000}, 
+    {0x43128000}, {0x4312a000}, {0x4312c000}, {0x4312e000}, 
+    {0x43130000}, {0x43132000}, {0x43134000}, {0x43136000}, 
+    {0x43138000}, {0x4313a000}, {0x4313c000}, {0x4313e000}, 
+    {0x43140000}, {0x43142000}, {0x43144000}, {0x43146000}, 
+    {0x43148000}, {0x4314a000}, {0x4314c000}, {0x4314e000}, 
+    {0x43150000}, {0x43152000}, {0x43154000}, {0x43156000}, 
+    {0x43158000}, {0x4315a000}, {0x4315c000}, {0x4315e000}, 
+    {0x43160000}, {0x43162000}, {0x43164000}, {0x43166000}, 
+    {0x43168000}, {0x4316a000}, {0x4316c000}, {0x4316e000}, 
+    {0x43170000}, {0x43172000}, {0x43174000}, {0x43176000}, 
+    {0x43178000}, {0x4317a000}, {0x4317c000}, {0x4317e000}, 
+    {0x43180000}, {0x43182000}, {0x43184000}, {0x43186000}, 
+    {0x43188000}, {0x4318a000}, {0x4318c000}, {0x4318e000}, 
+    {0x43190000}, {0x43192000}, {0x43194000}, {0x43196000}, 
+    {0x43198000}, {0x4319a000}, {0x4319c000}, {0x4319e000}, 
+    {0x431a0000}, {0x431a2000}, {0x431a4000}, {0x431a6000}, 
+    {0x431a8000}, {0x431aa000}, {0x431ac000}, {0x431ae000}, 
+    {0x431b0000}, {0x431b2000}, {0x431b4000}, {0x431b6000}, 
+    {0x431b8000}, {0x431ba000}, {0x431bc000}, {0x431be000}, 
+    {0x431c0000}, {0x431c2000}, {0x431c4000}, {0x431c6000}, 
+    {0x431c8000}, {0x431ca000}, {0x431cc000}, {0x431ce000}, 
+    {0x431d0000}, {0x431d2000}, {0x431d4000}, {0x431d6000}, 
+    {0x431d8000}, {0x431da000}, {0x431dc000}, {0x431de000}, 
+    {0x431e0000}, {0x431e2000}, {0x431e4000}, {0x431e6000}, 
+    {0x431e8000}, {0x431ea000}, {0x431ec000}, {0x431ee000}, 
+    {0x431f0000}, {0x431f2000}, {0x431f4000}, {0x431f6000}, 
+    {0x431f8000}, {0x431fa000}, {0x431fc000}, {0x431fe000}, 
+    {0x43200000}, {0x43202000}, {0x43204000}, {0x43206000}, 
+    {0x43208000}, {0x4320a000}, {0x4320c000}, {0x4320e000}, 
+    {0x43210000}, {0x43212000}, {0x43214000}, {0x43216000}, 
+    {0x43218000}, {0x4321a000}, {0x4321c000}, {0x4321e000}, 
+    {0x43220000}, {0x43222000}, {0x43224000}, {0x43226000}, 
+    {0x43228000}, {0x4322a000}, {0x4322c000}, {0x4322e000}, 
+    {0x43230000}, {0x43232000}, {0x43234000}, {0x43236000}, 
+    {0x43238000}, {0x4323a000}, {0x4323c000}, {0x4323e000}, 
+    {0x43240000}, {0x43242000}, {0x43244000}, {0x43246000}, 
+    {0x43248000}, {0x4324a000}, {0x4324c000}, {0x4324e000}, 
+    {0x43250000}, {0x43252000}, {0x43254000}, {0x43256000}, 
+    {0x43258000}, {0x4325a000}, {0x4325c000}, {0x4325e000}, 
+    {0x43260000}, {0x43262000}, {0x43264000}, {0x43266000}, 
+    {0x43268000}, {0x4326a000}, {0x4326c000}, {0x4326e000}, 
+    {0x43270000}, {0x43272000}, {0x43274000}, {0x43276000}, 
+    {0x43278000}, {0x4327a000}, {0x4327c000}, {0x4327e000}, 
+    {0x43280000}, {0x43282000}, {0x43284000}, {0x43286000}, 
+    {0x43288000}, {0x4328a000}, {0x4328c000}, {0x4328e000}, 
+    {0x43290000}, {0x43292000}, {0x43294000}, {0x43296000}, 
+    {0x43298000}, {0x4329a000}, {0x4329c000}, {0x4329e000}, 
+    {0x432a0000}, {0x432a2000}, {0x432a4000}, {0x432a6000}, 
+    {0x432a8000}, {0x432aa000}, {0x432ac000}, {0x432ae000}, 
+    {0x432b0000}, {0x432b2000}, {0x432b4000}, {0x432b6000}, 
+    {0x432b8000}, {0x432ba000}, {0x432bc000}, {0x432be000}, 
+    {0x432c0000}, {0x432c2000}, {0x432c4000}, {0x432c6000}, 
+    {0x432c8000}, {0x432ca000}, {0x432cc000}, {0x432ce000}, 
+    {0x432d0000}, {0x432d2000}, {0x432d4000}, {0x432d6000}, 
+    {0x432d8000}, {0x432da000}, {0x432dc000}, {0x432de000}, 
+    {0x432e0000}, {0x432e2000}, {0x432e4000}, {0x432e6000}, 
+    {0x432e8000}, {0x432ea000}, {0x432ec000}, {0x432ee000}, 
+    {0x432f0000}, {0x432f2000}, {0x432f4000}, {0x432f6000}, 
+    {0x432f8000}, {0x432fa000}, {0x432fc000}, {0x432fe000}, 
+    {0x43300000}, {0x43302000}, {0x43304000}, {0x43306000}, 
+    {0x43308000}, {0x4330a000}, {0x4330c000}, {0x4330e000}, 
+    {0x43310000}, {0x43312000}, {0x43314000}, {0x43316000}, 
+    {0x43318000}, {0x4331a000}, {0x4331c000}, {0x4331e000}, 
+    {0x43320000}, {0x43322000}, {0x43324000}, {0x43326000}, 
+    {0x43328000}, {0x4332a000}, {0x4332c000}, {0x4332e000}, 
+    {0x43330000}, {0x43332000}, {0x43334000}, {0x43336000}, 
+    {0x43338000}, {0x4333a000}, {0x4333c000}, {0x4333e000}, 
+    {0x43340000}, {0x43342000}, {0x43344000}, {0x43346000}, 
+    {0x43348000}, {0x4334a000}, {0x4334c000}, {0x4334e000}, 
+    {0x43350000}, {0x43352000}, {0x43354000}, {0x43356000}, 
+    {0x43358000}, {0x4335a000}, {0x4335c000}, {0x4335e000}, 
+    {0x43360000}, {0x43362000}, {0x43364000}, {0x43366000}, 
+    {0x43368000}, {0x4336a000}, {0x4336c000}, {0x4336e000}, 
+    {0x43370000}, {0x43372000}, {0x43374000}, {0x43376000}, 
+    {0x43378000}, {0x4337a000}, {0x4337c000}, {0x4337e000}, 
+    {0x43380000}, {0x43382000}, {0x43384000}, {0x43386000}, 
+    {0x43388000}, {0x4338a000}, {0x4338c000}, {0x4338e000}, 
+    {0x43390000}, {0x43392000}, {0x43394000}, {0x43396000}, 
+    {0x43398000}, {0x4339a000}, {0x4339c000}, {0x4339e000}, 
+    {0x433a0000}, {0x433a2000}, {0x433a4000}, {0x433a6000}, 
+    {0x433a8000}, {0x433aa000}, {0x433ac000}, {0x433ae000}, 
+    {0x433b0000}, {0x433b2000}, {0x433b4000}, {0x433b6000}, 
+    {0x433b8000}, {0x433ba000}, {0x433bc000}, {0x433be000}, 
+    {0x433c0000}, {0x433c2000}, {0x433c4000}, {0x433c6000}, 
+    {0x433c8000}, {0x433ca000}, {0x433cc000}, {0x433ce000}, 
+    {0x433d0000}, {0x433d2000}, {0x433d4000}, {0x433d6000}, 
+    {0x433d8000}, {0x433da000}, {0x433dc000}, {0x433de000}, 
+    {0x433e0000}, {0x433e2000}, {0x433e4000}, {0x433e6000}, 
+    {0x433e8000}, {0x433ea000}, {0x433ec000}, {0x433ee000}, 
+    {0x433f0000}, {0x433f2000}, {0x433f4000}, {0x433f6000}, 
+    {0x433f8000}, {0x433fa000}, {0x433fc000}, {0x433fe000}, 
+    {0x43400000}, {0x43402000}, {0x43404000}, {0x43406000}, 
+    {0x43408000}, {0x4340a000}, {0x4340c000}, {0x4340e000}, 
+    {0x43410000}, {0x43412000}, {0x43414000}, {0x43416000}, 
+    {0x43418000}, {0x4341a000}, {0x4341c000}, {0x4341e000}, 
+    {0x43420000}, {0x43422000}, {0x43424000}, {0x43426000}, 
+    {0x43428000}, {0x4342a000}, {0x4342c000}, {0x4342e000}, 
+    {0x43430000}, {0x43432000}, {0x43434000}, {0x43436000}, 
+    {0x43438000}, {0x4343a000}, {0x4343c000}, {0x4343e000}, 
+    {0x43440000}, {0x43442000}, {0x43444000}, {0x43446000}, 
+    {0x43448000}, {0x4344a000}, {0x4344c000}, {0x4344e000}, 
+    {0x43450000}, {0x43452000}, {0x43454000}, {0x43456000}, 
+    {0x43458000}, {0x4345a000}, {0x4345c000}, {0x4345e000}, 
+    {0x43460000}, {0x43462000}, {0x43464000}, {0x43466000}, 
+    {0x43468000}, {0x4346a000}, {0x4346c000}, {0x4346e000}, 
+    {0x43470000}, {0x43472000}, {0x43474000}, {0x43476000}, 
+    {0x43478000}, {0x4347a000}, {0x4347c000}, {0x4347e000}, 
+    {0x43480000}, {0x43482000}, {0x43484000}, {0x43486000}, 
+    {0x43488000}, {0x4348a000}, {0x4348c000}, {0x4348e000}, 
+    {0x43490000}, {0x43492000}, {0x43494000}, {0x43496000}, 
+    {0x43498000}, {0x4349a000}, {0x4349c000}, {0x4349e000}, 
+    {0x434a0000}, {0x434a2000}, {0x434a4000}, {0x434a6000}, 
+    {0x434a8000}, {0x434aa000}, {0x434ac000}, {0x434ae000}, 
+    {0x434b0000}, {0x434b2000}, {0x434b4000}, {0x434b6000}, 
+    {0x434b8000}, {0x434ba000}, {0x434bc000}, {0x434be000}, 
+    {0x434c0000}, {0x434c2000}, {0x434c4000}, {0x434c6000}, 
+    {0x434c8000}, {0x434ca000}, {0x434cc000}, {0x434ce000}, 
+    {0x434d0000}, {0x434d2000}, {0x434d4000}, {0x434d6000}, 
+    {0x434d8000}, {0x434da000}, {0x434dc000}, {0x434de000}, 
+    {0x434e0000}, {0x434e2000}, {0x434e4000}, {0x434e6000}, 
+    {0x434e8000}, {0x434ea000}, {0x434ec000}, {0x434ee000}, 
+    {0x434f0000}, {0x434f2000}, {0x434f4000}, {0x434f6000}, 
+    {0x434f8000}, {0x434fa000}, {0x434fc000}, {0x434fe000}, 
+    {0x43500000}, {0x43502000}, {0x43504000}, {0x43506000}, 
+    {0x43508000}, {0x4350a000}, {0x4350c000}, {0x4350e000}, 
+    {0x43510000}, {0x43512000}, {0x43514000}, {0x43516000}, 
+    {0x43518000}, {0x4351a000}, {0x4351c000}, {0x4351e000}, 
+    {0x43520000}, {0x43522000}, {0x43524000}, {0x43526000}, 
+    {0x43528000}, {0x4352a000}, {0x4352c000}, {0x4352e000}, 
+    {0x43530000}, {0x43532000}, {0x43534000}, {0x43536000}, 
+    {0x43538000}, {0x4353a000}, {0x4353c000}, {0x4353e000}, 
+    {0x43540000}, {0x43542000}, {0x43544000}, {0x43546000}, 
+    {0x43548000}, {0x4354a000}, {0x4354c000}, {0x4354e000}, 
+    {0x43550000}, {0x43552000}, {0x43554000}, {0x43556000}, 
+    {0x43558000}, {0x4355a000}, {0x4355c000}, {0x4355e000}, 
+    {0x43560000}, {0x43562000}, {0x43564000}, {0x43566000}, 
+    {0x43568000}, {0x4356a000}, {0x4356c000}, {0x4356e000}, 
+    {0x43570000}, {0x43572000}, {0x43574000}, {0x43576000}, 
+    {0x43578000}, {0x4357a000}, {0x4357c000}, {0x4357e000}, 
+    {0x43580000}, {0x43582000}, {0x43584000}, {0x43586000}, 
+    {0x43588000}, {0x4358a000}, {0x4358c000}, {0x4358e000}, 
+    {0x43590000}, {0x43592000}, {0x43594000}, {0x43596000}, 
+    {0x43598000}, {0x4359a000}, {0x4359c000}, {0x4359e000}, 
+    {0x435a0000}, {0x435a2000}, {0x435a4000}, {0x435a6000}, 
+    {0x435a8000}, {0x435aa000}, {0x435ac000}, {0x435ae000}, 
+    {0x435b0000}, {0x435b2000}, {0x435b4000}, {0x435b6000}, 
+    {0x435b8000}, {0x435ba000}, {0x435bc000}, {0x435be000}, 
+    {0x435c0000}, {0x435c2000}, {0x435c4000}, {0x435c6000}, 
+    {0x435c8000}, {0x435ca000}, {0x435cc000}, {0x435ce000}, 
+    {0x435d0000}, {0x435d2000}, {0x435d4000}, {0x435d6000}, 
+    {0x435d8000}, {0x435da000}, {0x435dc000}, {0x435de000}, 
+    {0x435e0000}, {0x435e2000}, {0x435e4000}, {0x435e6000}, 
+    {0x435e8000}, {0x435ea000}, {0x435ec000}, {0x435ee000}, 
+    {0x435f0000}, {0x435f2000}, {0x435f4000}, {0x435f6000}, 
+    {0x435f8000}, {0x435fa000}, {0x435fc000}, {0x435fe000}, 
+    {0x43600000}, {0x43602000}, {0x43604000}, {0x43606000}, 
+    {0x43608000}, {0x4360a000}, {0x4360c000}, {0x4360e000}, 
+    {0x43610000}, {0x43612000}, {0x43614000}, {0x43616000}, 
+    {0x43618000}, {0x4361a000}, {0x4361c000}, {0x4361e000}, 
+    {0x43620000}, {0x43622000}, {0x43624000}, {0x43626000}, 
+    {0x43628000}, {0x4362a000}, {0x4362c000}, {0x4362e000}, 
+    {0x43630000}, {0x43632000}, {0x43634000}, {0x43636000}, 
+    {0x43638000}, {0x4363a000}, {0x4363c000}, {0x4363e000}, 
+    {0x43640000}, {0x43642000}, {0x43644000}, {0x43646000}, 
+    {0x43648000}, {0x4364a000}, {0x4364c000}, {0x4364e000}, 
+    {0x43650000}, {0x43652000}, {0x43654000}, {0x43656000}, 
+    {0x43658000}, {0x4365a000}, {0x4365c000}, {0x4365e000}, 
+    {0x43660000}, {0x43662000}, {0x43664000}, {0x43666000}, 
+    {0x43668000}, {0x4366a000}, {0x4366c000}, {0x4366e000}, 
+    {0x43670000}, {0x43672000}, {0x43674000}, {0x43676000}, 
+    {0x43678000}, {0x4367a000}, {0x4367c000}, {0x4367e000}, 
+    {0x43680000}, {0x43682000}, {0x43684000}, {0x43686000}, 
+    {0x43688000}, {0x4368a000}, {0x4368c000}, {0x4368e000}, 
+    {0x43690000}, {0x43692000}, {0x43694000}, {0x43696000}, 
+    {0x43698000}, {0x4369a000}, {0x4369c000}, {0x4369e000}, 
+    {0x436a0000}, {0x436a2000}, {0x436a4000}, {0x436a6000}, 
+    {0x436a8000}, {0x436aa000}, {0x436ac000}, {0x436ae000}, 
+    {0x436b0000}, {0x436b2000}, {0x436b4000}, {0x436b6000}, 
+    {0x436b8000}, {0x436ba000}, {0x436bc000}, {0x436be000}, 
+    {0x436c0000}, {0x436c2000}, {0x436c4000}, {0x436c6000}, 
+    {0x436c8000}, {0x436ca000}, {0x436cc000}, {0x436ce000}, 
+    {0x436d0000}, {0x436d2000}, {0x436d4000}, {0x436d6000}, 
+    {0x436d8000}, {0x436da000}, {0x436dc000}, {0x436de000}, 
+    {0x436e0000}, {0x436e2000}, {0x436e4000}, {0x436e6000}, 
+    {0x436e8000}, {0x436ea000}, {0x436ec000}, {0x436ee000}, 
+    {0x436f0000}, {0x436f2000}, {0x436f4000}, {0x436f6000}, 
+    {0x436f8000}, {0x436fa000}, {0x436fc000}, {0x436fe000}, 
+    {0x43700000}, {0x43702000}, {0x43704000}, {0x43706000}, 
+    {0x43708000}, {0x4370a000}, {0x4370c000}, {0x4370e000}, 
+    {0x43710000}, {0x43712000}, {0x43714000}, {0x43716000}, 
+    {0x43718000}, {0x4371a000}, {0x4371c000}, {0x4371e000}, 
+    {0x43720000}, {0x43722000}, {0x43724000}, {0x43726000}, 
+    {0x43728000}, {0x4372a000}, {0x4372c000}, {0x4372e000}, 
+    {0x43730000}, {0x43732000}, {0x43734000}, {0x43736000}, 
+    {0x43738000}, {0x4373a000}, {0x4373c000}, {0x4373e000}, 
+    {0x43740000}, {0x43742000}, {0x43744000}, {0x43746000}, 
+    {0x43748000}, {0x4374a000}, {0x4374c000}, {0x4374e000}, 
+    {0x43750000}, {0x43752000}, {0x43754000}, {0x43756000}, 
+    {0x43758000}, {0x4375a000}, {0x4375c000}, {0x4375e000}, 
+    {0x43760000}, {0x43762000}, {0x43764000}, {0x43766000}, 
+    {0x43768000}, {0x4376a000}, {0x4376c000}, {0x4376e000}, 
+    {0x43770000}, {0x43772000}, {0x43774000}, {0x43776000}, 
+    {0x43778000}, {0x4377a000}, {0x4377c000}, {0x4377e000}, 
+    {0x43780000}, {0x43782000}, {0x43784000}, {0x43786000}, 
+    {0x43788000}, {0x4378a000}, {0x4378c000}, {0x4378e000}, 
+    {0x43790000}, {0x43792000}, {0x43794000}, {0x43796000}, 
+    {0x43798000}, {0x4379a000}, {0x4379c000}, {0x4379e000}, 
+    {0x437a0000}, {0x437a2000}, {0x437a4000}, {0x437a6000}, 
+    {0x437a8000}, {0x437aa000}, {0x437ac000}, {0x437ae000}, 
+    {0x437b0000}, {0x437b2000}, {0x437b4000}, {0x437b6000}, 
+    {0x437b8000}, {0x437ba000}, {0x437bc000}, {0x437be000}, 
+    {0x437c0000}, {0x437c2000}, {0x437c4000}, {0x437c6000}, 
+    {0x437c8000}, {0x437ca000}, {0x437cc000}, {0x437ce000}, 
+    {0x437d0000}, {0x437d2000}, {0x437d4000}, {0x437d6000}, 
+    {0x437d8000}, {0x437da000}, {0x437dc000}, {0x437de000}, 
+    {0x437e0000}, {0x437e2000}, {0x437e4000}, {0x437e6000}, 
+    {0x437e8000}, {0x437ea000}, {0x437ec000}, {0x437ee000}, 
+    {0x437f0000}, {0x437f2000}, {0x437f4000}, {0x437f6000}, 
+    {0x437f8000}, {0x437fa000}, {0x437fc000}, {0x437fe000}, 
+    {0x43800000}, {0x43802000}, {0x43804000}, {0x43806000}, 
+    {0x43808000}, {0x4380a000}, {0x4380c000}, {0x4380e000}, 
+    {0x43810000}, {0x43812000}, {0x43814000}, {0x43816000}, 
+    {0x43818000}, {0x4381a000}, {0x4381c000}, {0x4381e000}, 
+    {0x43820000}, {0x43822000}, {0x43824000}, {0x43826000}, 
+    {0x43828000}, {0x4382a000}, {0x4382c000}, {0x4382e000}, 
+    {0x43830000}, {0x43832000}, {0x43834000}, {0x43836000}, 
+    {0x43838000}, {0x4383a000}, {0x4383c000}, {0x4383e000}, 
+    {0x43840000}, {0x43842000}, {0x43844000}, {0x43846000}, 
+    {0x43848000}, {0x4384a000}, {0x4384c000}, {0x4384e000}, 
+    {0x43850000}, {0x43852000}, {0x43854000}, {0x43856000}, 
+    {0x43858000}, {0x4385a000}, {0x4385c000}, {0x4385e000}, 
+    {0x43860000}, {0x43862000}, {0x43864000}, {0x43866000}, 
+    {0x43868000}, {0x4386a000}, {0x4386c000}, {0x4386e000}, 
+    {0x43870000}, {0x43872000}, {0x43874000}, {0x43876000}, 
+    {0x43878000}, {0x4387a000}, {0x4387c000}, {0x4387e000}, 
+    {0x43880000}, {0x43882000}, {0x43884000}, {0x43886000}, 
+    {0x43888000}, {0x4388a000}, {0x4388c000}, {0x4388e000}, 
+    {0x43890000}, {0x43892000}, {0x43894000}, {0x43896000}, 
+    {0x43898000}, {0x4389a000}, {0x4389c000}, {0x4389e000}, 
+    {0x438a0000}, {0x438a2000}, {0x438a4000}, {0x438a6000}, 
+    {0x438a8000}, {0x438aa000}, {0x438ac000}, {0x438ae000}, 
+    {0x438b0000}, {0x438b2000}, {0x438b4000}, {0x438b6000}, 
+    {0x438b8000}, {0x438ba000}, {0x438bc000}, {0x438be000}, 
+    {0x438c0000}, {0x438c2000}, {0x438c4000}, {0x438c6000}, 
+    {0x438c8000}, {0x438ca000}, {0x438cc000}, {0x438ce000}, 
+    {0x438d0000}, {0x438d2000}, {0x438d4000}, {0x438d6000}, 
+    {0x438d8000}, {0x438da000}, {0x438dc000}, {0x438de000}, 
+    {0x438e0000}, {0x438e2000}, {0x438e4000}, {0x438e6000}, 
+    {0x438e8000}, {0x438ea000}, {0x438ec000}, {0x438ee000}, 
+    {0x438f0000}, {0x438f2000}, {0x438f4000}, {0x438f6000}, 
+    {0x438f8000}, {0x438fa000}, {0x438fc000}, {0x438fe000}, 
+    {0x43900000}, {0x43902000}, {0x43904000}, {0x43906000}, 
+    {0x43908000}, {0x4390a000}, {0x4390c000}, {0x4390e000}, 
+    {0x43910000}, {0x43912000}, {0x43914000}, {0x43916000}, 
+    {0x43918000}, {0x4391a000}, {0x4391c000}, {0x4391e000}, 
+    {0x43920000}, {0x43922000}, {0x43924000}, {0x43926000}, 
+    {0x43928000}, {0x4392a000}, {0x4392c000}, {0x4392e000}, 
+    {0x43930000}, {0x43932000}, {0x43934000}, {0x43936000}, 
+    {0x43938000}, {0x4393a000}, {0x4393c000}, {0x4393e000}, 
+    {0x43940000}, {0x43942000}, {0x43944000}, {0x43946000}, 
+    {0x43948000}, {0x4394a000}, {0x4394c000}, {0x4394e000}, 
+    {0x43950000}, {0x43952000}, {0x43954000}, {0x43956000}, 
+    {0x43958000}, {0x4395a000}, {0x4395c000}, {0x4395e000}, 
+    {0x43960000}, {0x43962000}, {0x43964000}, {0x43966000}, 
+    {0x43968000}, {0x4396a000}, {0x4396c000}, {0x4396e000}, 
+    {0x43970000}, {0x43972000}, {0x43974000}, {0x43976000}, 
+    {0x43978000}, {0x4397a000}, {0x4397c000}, {0x4397e000}, 
+    {0x43980000}, {0x43982000}, {0x43984000}, {0x43986000}, 
+    {0x43988000}, {0x4398a000}, {0x4398c000}, {0x4398e000}, 
+    {0x43990000}, {0x43992000}, {0x43994000}, {0x43996000}, 
+    {0x43998000}, {0x4399a000}, {0x4399c000}, {0x4399e000}, 
+    {0x439a0000}, {0x439a2000}, {0x439a4000}, {0x439a6000}, 
+    {0x439a8000}, {0x439aa000}, {0x439ac000}, {0x439ae000}, 
+    {0x439b0000}, {0x439b2000}, {0x439b4000}, {0x439b6000}, 
+    {0x439b8000}, {0x439ba000}, {0x439bc000}, {0x439be000}, 
+    {0x439c0000}, {0x439c2000}, {0x439c4000}, {0x439c6000}, 
+    {0x439c8000}, {0x439ca000}, {0x439cc000}, {0x439ce000}, 
+    {0x439d0000}, {0x439d2000}, {0x439d4000}, {0x439d6000}, 
+    {0x439d8000}, {0x439da000}, {0x439dc000}, {0x439de000}, 
+    {0x439e0000}, {0x439e2000}, {0x439e4000}, {0x439e6000}, 
+    {0x439e8000}, {0x439ea000}, {0x439ec000}, {0x439ee000}, 
+    {0x439f0000}, {0x439f2000}, {0x439f4000}, {0x439f6000}, 
+    {0x439f8000}, {0x439fa000}, {0x439fc000}, {0x439fe000}, 
+    {0x43a00000}, {0x43a02000}, {0x43a04000}, {0x43a06000}, 
+    {0x43a08000}, {0x43a0a000}, {0x43a0c000}, {0x43a0e000}, 
+    {0x43a10000}, {0x43a12000}, {0x43a14000}, {0x43a16000}, 
+    {0x43a18000}, {0x43a1a000}, {0x43a1c000}, {0x43a1e000}, 
+    {0x43a20000}, {0x43a22000}, {0x43a24000}, {0x43a26000}, 
+    {0x43a28000}, {0x43a2a000}, {0x43a2c000}, {0x43a2e000}, 
+    {0x43a30000}, {0x43a32000}, {0x43a34000}, {0x43a36000}, 
+    {0x43a38000}, {0x43a3a000}, {0x43a3c000}, {0x43a3e000}, 
+    {0x43a40000}, {0x43a42000}, {0x43a44000}, {0x43a46000}, 
+    {0x43a48000}, {0x43a4a000}, {0x43a4c000}, {0x43a4e000}, 
+    {0x43a50000}, {0x43a52000}, {0x43a54000}, {0x43a56000}, 
+    {0x43a58000}, {0x43a5a000}, {0x43a5c000}, {0x43a5e000}, 
+    {0x43a60000}, {0x43a62000}, {0x43a64000}, {0x43a66000}, 
+    {0x43a68000}, {0x43a6a000}, {0x43a6c000}, {0x43a6e000}, 
+    {0x43a70000}, {0x43a72000}, {0x43a74000}, {0x43a76000}, 
+    {0x43a78000}, {0x43a7a000}, {0x43a7c000}, {0x43a7e000}, 
+    {0x43a80000}, {0x43a82000}, {0x43a84000}, {0x43a86000}, 
+    {0x43a88000}, {0x43a8a000}, {0x43a8c000}, {0x43a8e000}, 
+    {0x43a90000}, {0x43a92000}, {0x43a94000}, {0x43a96000}, 
+    {0x43a98000}, {0x43a9a000}, {0x43a9c000}, {0x43a9e000}, 
+    {0x43aa0000}, {0x43aa2000}, {0x43aa4000}, {0x43aa6000}, 
+    {0x43aa8000}, {0x43aaa000}, {0x43aac000}, {0x43aae000}, 
+    {0x43ab0000}, {0x43ab2000}, {0x43ab4000}, {0x43ab6000}, 
+    {0x43ab8000}, {0x43aba000}, {0x43abc000}, {0x43abe000}, 
+    {0x43ac0000}, {0x43ac2000}, {0x43ac4000}, {0x43ac6000}, 
+    {0x43ac8000}, {0x43aca000}, {0x43acc000}, {0x43ace000}, 
+    {0x43ad0000}, {0x43ad2000}, {0x43ad4000}, {0x43ad6000}, 
+    {0x43ad8000}, {0x43ada000}, {0x43adc000}, {0x43ade000}, 
+    {0x43ae0000}, {0x43ae2000}, {0x43ae4000}, {0x43ae6000}, 
+    {0x43ae8000}, {0x43aea000}, {0x43aec000}, {0x43aee000}, 
+    {0x43af0000}, {0x43af2000}, {0x43af4000}, {0x43af6000}, 
+    {0x43af8000}, {0x43afa000}, {0x43afc000}, {0x43afe000}, 
+    {0x43b00000}, {0x43b02000}, {0x43b04000}, {0x43b06000}, 
+    {0x43b08000}, {0x43b0a000}, {0x43b0c000}, {0x43b0e000}, 
+    {0x43b10000}, {0x43b12000}, {0x43b14000}, {0x43b16000}, 
+    {0x43b18000}, {0x43b1a000}, {0x43b1c000}, {0x43b1e000}, 
+    {0x43b20000}, {0x43b22000}, {0x43b24000}, {0x43b26000}, 
+    {0x43b28000}, {0x43b2a000}, {0x43b2c000}, {0x43b2e000}, 
+    {0x43b30000}, {0x43b32000}, {0x43b34000}, {0x43b36000}, 
+    {0x43b38000}, {0x43b3a000}, {0x43b3c000}, {0x43b3e000}, 
+    {0x43b40000}, {0x43b42000}, {0x43b44000}, {0x43b46000}, 
+    {0x43b48000}, {0x43b4a000}, {0x43b4c000}, {0x43b4e000}, 
+    {0x43b50000}, {0x43b52000}, {0x43b54000}, {0x43b56000}, 
+    {0x43b58000}, {0x43b5a000}, {0x43b5c000}, {0x43b5e000}, 
+    {0x43b60000}, {0x43b62000}, {0x43b64000}, {0x43b66000}, 
+    {0x43b68000}, {0x43b6a000}, {0x43b6c000}, {0x43b6e000}, 
+    {0x43b70000}, {0x43b72000}, {0x43b74000}, {0x43b76000}, 
+    {0x43b78000}, {0x43b7a000}, {0x43b7c000}, {0x43b7e000}, 
+    {0x43b80000}, {0x43b82000}, {0x43b84000}, {0x43b86000}, 
+    {0x43b88000}, {0x43b8a000}, {0x43b8c000}, {0x43b8e000}, 
+    {0x43b90000}, {0x43b92000}, {0x43b94000}, {0x43b96000}, 
+    {0x43b98000}, {0x43b9a000}, {0x43b9c000}, {0x43b9e000}, 
+    {0x43ba0000}, {0x43ba2000}, {0x43ba4000}, {0x43ba6000}, 
+    {0x43ba8000}, {0x43baa000}, {0x43bac000}, {0x43bae000}, 
+    {0x43bb0000}, {0x43bb2000}, {0x43bb4000}, {0x43bb6000}, 
+    {0x43bb8000}, {0x43bba000}, {0x43bbc000}, {0x43bbe000}, 
+    {0x43bc0000}, {0x43bc2000}, {0x43bc4000}, {0x43bc6000}, 
+    {0x43bc8000}, {0x43bca000}, {0x43bcc000}, {0x43bce000}, 
+    {0x43bd0000}, {0x43bd2000}, {0x43bd4000}, {0x43bd6000}, 
+    {0x43bd8000}, {0x43bda000}, {0x43bdc000}, {0x43bde000}, 
+    {0x43be0000}, {0x43be2000}, {0x43be4000}, {0x43be6000}, 
+    {0x43be8000}, {0x43bea000}, {0x43bec000}, {0x43bee000}, 
+    {0x43bf0000}, {0x43bf2000}, {0x43bf4000}, {0x43bf6000}, 
+    {0x43bf8000}, {0x43bfa000}, {0x43bfc000}, {0x43bfe000}, 
+    {0x43c00000}, {0x43c02000}, {0x43c04000}, {0x43c06000}, 
+    {0x43c08000}, {0x43c0a000}, {0x43c0c000}, {0x43c0e000}, 
+    {0x43c10000}, {0x43c12000}, {0x43c14000}, {0x43c16000}, 
+    {0x43c18000}, {0x43c1a000}, {0x43c1c000}, {0x43c1e000}, 
+    {0x43c20000}, {0x43c22000}, {0x43c24000}, {0x43c26000}, 
+    {0x43c28000}, {0x43c2a000}, {0x43c2c000}, {0x43c2e000}, 
+    {0x43c30000}, {0x43c32000}, {0x43c34000}, {0x43c36000}, 
+    {0x43c38000}, {0x43c3a000}, {0x43c3c000}, {0x43c3e000}, 
+    {0x43c40000}, {0x43c42000}, {0x43c44000}, {0x43c46000}, 
+    {0x43c48000}, {0x43c4a000}, {0x43c4c000}, {0x43c4e000}, 
+    {0x43c50000}, {0x43c52000}, {0x43c54000}, {0x43c56000}, 
+    {0x43c58000}, {0x43c5a000}, {0x43c5c000}, {0x43c5e000}, 
+    {0x43c60000}, {0x43c62000}, {0x43c64000}, {0x43c66000}, 
+    {0x43c68000}, {0x43c6a000}, {0x43c6c000}, {0x43c6e000}, 
+    {0x43c70000}, {0x43c72000}, {0x43c74000}, {0x43c76000}, 
+    {0x43c78000}, {0x43c7a000}, {0x43c7c000}, {0x43c7e000}, 
+    {0x43c80000}, {0x43c82000}, {0x43c84000}, {0x43c86000}, 
+    {0x43c88000}, {0x43c8a000}, {0x43c8c000}, {0x43c8e000}, 
+    {0x43c90000}, {0x43c92000}, {0x43c94000}, {0x43c96000}, 
+    {0x43c98000}, {0x43c9a000}, {0x43c9c000}, {0x43c9e000}, 
+    {0x43ca0000}, {0x43ca2000}, {0x43ca4000}, {0x43ca6000}, 
+    {0x43ca8000}, {0x43caa000}, {0x43cac000}, {0x43cae000}, 
+    {0x43cb0000}, {0x43cb2000}, {0x43cb4000}, {0x43cb6000}, 
+    {0x43cb8000}, {0x43cba000}, {0x43cbc000}, {0x43cbe000}, 
+    {0x43cc0000}, {0x43cc2000}, {0x43cc4000}, {0x43cc6000}, 
+    {0x43cc8000}, {0x43cca000}, {0x43ccc000}, {0x43cce000}, 
+    {0x43cd0000}, {0x43cd2000}, {0x43cd4000}, {0x43cd6000}, 
+    {0x43cd8000}, {0x43cda000}, {0x43cdc000}, {0x43cde000}, 
+    {0x43ce0000}, {0x43ce2000}, {0x43ce4000}, {0x43ce6000}, 
+    {0x43ce8000}, {0x43cea000}, {0x43cec000}, {0x43cee000}, 
+    {0x43cf0000}, {0x43cf2000}, {0x43cf4000}, {0x43cf6000}, 
+    {0x43cf8000}, {0x43cfa000}, {0x43cfc000}, {0x43cfe000}, 
+    {0x43d00000}, {0x43d02000}, {0x43d04000}, {0x43d06000}, 
+    {0x43d08000}, {0x43d0a000}, {0x43d0c000}, {0x43d0e000}, 
+    {0x43d10000}, {0x43d12000}, {0x43d14000}, {0x43d16000}, 
+    {0x43d18000}, {0x43d1a000}, {0x43d1c000}, {0x43d1e000}, 
+    {0x43d20000}, {0x43d22000}, {0x43d24000}, {0x43d26000}, 
+    {0x43d28000}, {0x43d2a000}, {0x43d2c000}, {0x43d2e000}, 
+    {0x43d30000}, {0x43d32000}, {0x43d34000}, {0x43d36000}, 
+    {0x43d38000}, {0x43d3a000}, {0x43d3c000}, {0x43d3e000}, 
+    {0x43d40000}, {0x43d42000}, {0x43d44000}, {0x43d46000}, 
+    {0x43d48000}, {0x43d4a000}, {0x43d4c000}, {0x43d4e000}, 
+    {0x43d50000}, {0x43d52000}, {0x43d54000}, {0x43d56000}, 
+    {0x43d58000}, {0x43d5a000}, {0x43d5c000}, {0x43d5e000}, 
+    {0x43d60000}, {0x43d62000}, {0x43d64000}, {0x43d66000}, 
+    {0x43d68000}, {0x43d6a000}, {0x43d6c000}, {0x43d6e000}, 
+    {0x43d70000}, {0x43d72000}, {0x43d74000}, {0x43d76000}, 
+    {0x43d78000}, {0x43d7a000}, {0x43d7c000}, {0x43d7e000}, 
+    {0x43d80000}, {0x43d82000}, {0x43d84000}, {0x43d86000}, 
+    {0x43d88000}, {0x43d8a000}, {0x43d8c000}, {0x43d8e000}, 
+    {0x43d90000}, {0x43d92000}, {0x43d94000}, {0x43d96000}, 
+    {0x43d98000}, {0x43d9a000}, {0x43d9c000}, {0x43d9e000}, 
+    {0x43da0000}, {0x43da2000}, {0x43da4000}, {0x43da6000}, 
+    {0x43da8000}, {0x43daa000}, {0x43dac000}, {0x43dae000}, 
+    {0x43db0000}, {0x43db2000}, {0x43db4000}, {0x43db6000}, 
+    {0x43db8000}, {0x43dba000}, {0x43dbc000}, {0x43dbe000}, 
+    {0x43dc0000}, {0x43dc2000}, {0x43dc4000}, {0x43dc6000}, 
+    {0x43dc8000}, {0x43dca000}, {0x43dcc000}, {0x43dce000}, 
+    {0x43dd0000}, {0x43dd2000}, {0x43dd4000}, {0x43dd6000}, 
+    {0x43dd8000}, {0x43dda000}, {0x43ddc000}, {0x43dde000}, 
+    {0x43de0000}, {0x43de2000}, {0x43de4000}, {0x43de6000}, 
+    {0x43de8000}, {0x43dea000}, {0x43dec000}, {0x43dee000}, 
+    {0x43df0000}, {0x43df2000}, {0x43df4000}, {0x43df6000}, 
+    {0x43df8000}, {0x43dfa000}, {0x43dfc000}, {0x43dfe000}, 
+    {0x43e00000}, {0x43e02000}, {0x43e04000}, {0x43e06000}, 
+    {0x43e08000}, {0x43e0a000}, {0x43e0c000}, {0x43e0e000}, 
+    {0x43e10000}, {0x43e12000}, {0x43e14000}, {0x43e16000}, 
+    {0x43e18000}, {0x43e1a000}, {0x43e1c000}, {0x43e1e000}, 
+    {0x43e20000}, {0x43e22000}, {0x43e24000}, {0x43e26000}, 
+    {0x43e28000}, {0x43e2a000}, {0x43e2c000}, {0x43e2e000}, 
+    {0x43e30000}, {0x43e32000}, {0x43e34000}, {0x43e36000}, 
+    {0x43e38000}, {0x43e3a000}, {0x43e3c000}, {0x43e3e000}, 
+    {0x43e40000}, {0x43e42000}, {0x43e44000}, {0x43e46000}, 
+    {0x43e48000}, {0x43e4a000}, {0x43e4c000}, {0x43e4e000}, 
+    {0x43e50000}, {0x43e52000}, {0x43e54000}, {0x43e56000}, 
+    {0x43e58000}, {0x43e5a000}, {0x43e5c000}, {0x43e5e000}, 
+    {0x43e60000}, {0x43e62000}, {0x43e64000}, {0x43e66000}, 
+    {0x43e68000}, {0x43e6a000}, {0x43e6c000}, {0x43e6e000}, 
+    {0x43e70000}, {0x43e72000}, {0x43e74000}, {0x43e76000}, 
+    {0x43e78000}, {0x43e7a000}, {0x43e7c000}, {0x43e7e000}, 
+    {0x43e80000}, {0x43e82000}, {0x43e84000}, {0x43e86000}, 
+    {0x43e88000}, {0x43e8a000}, {0x43e8c000}, {0x43e8e000}, 
+    {0x43e90000}, {0x43e92000}, {0x43e94000}, {0x43e96000}, 
+    {0x43e98000}, {0x43e9a000}, {0x43e9c000}, {0x43e9e000}, 
+    {0x43ea0000}, {0x43ea2000}, {0x43ea4000}, {0x43ea6000}, 
+    {0x43ea8000}, {0x43eaa000}, {0x43eac000}, {0x43eae000}, 
+    {0x43eb0000}, {0x43eb2000}, {0x43eb4000}, {0x43eb6000}, 
+    {0x43eb8000}, {0x43eba000}, {0x43ebc000}, {0x43ebe000}, 
+    {0x43ec0000}, {0x43ec2000}, {0x43ec4000}, {0x43ec6000}, 
+    {0x43ec8000}, {0x43eca000}, {0x43ecc000}, {0x43ece000}, 
+    {0x43ed0000}, {0x43ed2000}, {0x43ed4000}, {0x43ed6000}, 
+    {0x43ed8000}, {0x43eda000}, {0x43edc000}, {0x43ede000}, 
+    {0x43ee0000}, {0x43ee2000}, {0x43ee4000}, {0x43ee6000}, 
+    {0x43ee8000}, {0x43eea000}, {0x43eec000}, {0x43eee000}, 
+    {0x43ef0000}, {0x43ef2000}, {0x43ef4000}, {0x43ef6000}, 
+    {0x43ef8000}, {0x43efa000}, {0x43efc000}, {0x43efe000}, 
+    {0x43f00000}, {0x43f02000}, {0x43f04000}, {0x43f06000}, 
+    {0x43f08000}, {0x43f0a000}, {0x43f0c000}, {0x43f0e000}, 
+    {0x43f10000}, {0x43f12000}, {0x43f14000}, {0x43f16000}, 
+    {0x43f18000}, {0x43f1a000}, {0x43f1c000}, {0x43f1e000}, 
+    {0x43f20000}, {0x43f22000}, {0x43f24000}, {0x43f26000}, 
+    {0x43f28000}, {0x43f2a000}, {0x43f2c000}, {0x43f2e000}, 
+    {0x43f30000}, {0x43f32000}, {0x43f34000}, {0x43f36000}, 
+    {0x43f38000}, {0x43f3a000}, {0x43f3c000}, {0x43f3e000}, 
+    {0x43f40000}, {0x43f42000}, {0x43f44000}, {0x43f46000}, 
+    {0x43f48000}, {0x43f4a000}, {0x43f4c000}, {0x43f4e000}, 
+    {0x43f50000}, {0x43f52000}, {0x43f54000}, {0x43f56000}, 
+    {0x43f58000}, {0x43f5a000}, {0x43f5c000}, {0x43f5e000}, 
+    {0x43f60000}, {0x43f62000}, {0x43f64000}, {0x43f66000}, 
+    {0x43f68000}, {0x43f6a000}, {0x43f6c000}, {0x43f6e000}, 
+    {0x43f70000}, {0x43f72000}, {0x43f74000}, {0x43f76000}, 
+    {0x43f78000}, {0x43f7a000}, {0x43f7c000}, {0x43f7e000}, 
+    {0x43f80000}, {0x43f82000}, {0x43f84000}, {0x43f86000}, 
+    {0x43f88000}, {0x43f8a000}, {0x43f8c000}, {0x43f8e000}, 
+    {0x43f90000}, {0x43f92000}, {0x43f94000}, {0x43f96000}, 
+    {0x43f98000}, {0x43f9a000}, {0x43f9c000}, {0x43f9e000}, 
+    {0x43fa0000}, {0x43fa2000}, {0x43fa4000}, {0x43fa6000}, 
+    {0x43fa8000}, {0x43faa000}, {0x43fac000}, {0x43fae000}, 
+    {0x43fb0000}, {0x43fb2000}, {0x43fb4000}, {0x43fb6000}, 
+    {0x43fb8000}, {0x43fba000}, {0x43fbc000}, {0x43fbe000}, 
+    {0x43fc0000}, {0x43fc2000}, {0x43fc4000}, {0x43fc6000}, 
+    {0x43fc8000}, {0x43fca000}, {0x43fcc000}, {0x43fce000}, 
+    {0x43fd0000}, {0x43fd2000}, {0x43fd4000}, {0x43fd6000}, 
+    {0x43fd8000}, {0x43fda000}, {0x43fdc000}, {0x43fde000}, 
+    {0x43fe0000}, {0x43fe2000}, {0x43fe4000}, {0x43fe6000}, 
+    {0x43fe8000}, {0x43fea000}, {0x43fec000}, {0x43fee000}, 
+    {0x43ff0000}, {0x43ff2000}, {0x43ff4000}, {0x43ff6000}, 
+    {0x43ff8000}, {0x43ffa000}, {0x43ffc000}, {0x43ffe000}, 
+    {0x44000000}, {0x44002000}, {0x44004000}, {0x44006000}, 
+    {0x44008000}, {0x4400a000}, {0x4400c000}, {0x4400e000}, 
+    {0x44010000}, {0x44012000}, {0x44014000}, {0x44016000}, 
+    {0x44018000}, {0x4401a000}, {0x4401c000}, {0x4401e000}, 
+    {0x44020000}, {0x44022000}, {0x44024000}, {0x44026000}, 
+    {0x44028000}, {0x4402a000}, {0x4402c000}, {0x4402e000}, 
+    {0x44030000}, {0x44032000}, {0x44034000}, {0x44036000}, 
+    {0x44038000}, {0x4403a000}, {0x4403c000}, {0x4403e000}, 
+    {0x44040000}, {0x44042000}, {0x44044000}, {0x44046000}, 
+    {0x44048000}, {0x4404a000}, {0x4404c000}, {0x4404e000}, 
+    {0x44050000}, {0x44052000}, {0x44054000}, {0x44056000}, 
+    {0x44058000}, {0x4405a000}, {0x4405c000}, {0x4405e000}, 
+    {0x44060000}, {0x44062000}, {0x44064000}, {0x44066000}, 
+    {0x44068000}, {0x4406a000}, {0x4406c000}, {0x4406e000}, 
+    {0x44070000}, {0x44072000}, {0x44074000}, {0x44076000}, 
+    {0x44078000}, {0x4407a000}, {0x4407c000}, {0x4407e000}, 
+    {0x44080000}, {0x44082000}, {0x44084000}, {0x44086000}, 
+    {0x44088000}, {0x4408a000}, {0x4408c000}, {0x4408e000}, 
+    {0x44090000}, {0x44092000}, {0x44094000}, {0x44096000}, 
+    {0x44098000}, {0x4409a000}, {0x4409c000}, {0x4409e000}, 
+    {0x440a0000}, {0x440a2000}, {0x440a4000}, {0x440a6000}, 
+    {0x440a8000}, {0x440aa000}, {0x440ac000}, {0x440ae000}, 
+    {0x440b0000}, {0x440b2000}, {0x440b4000}, {0x440b6000}, 
+    {0x440b8000}, {0x440ba000}, {0x440bc000}, {0x440be000}, 
+    {0x440c0000}, {0x440c2000}, {0x440c4000}, {0x440c6000}, 
+    {0x440c8000}, {0x440ca000}, {0x440cc000}, {0x440ce000}, 
+    {0x440d0000}, {0x440d2000}, {0x440d4000}, {0x440d6000}, 
+    {0x440d8000}, {0x440da000}, {0x440dc000}, {0x440de000}, 
+    {0x440e0000}, {0x440e2000}, {0x440e4000}, {0x440e6000}, 
+    {0x440e8000}, {0x440ea000}, {0x440ec000}, {0x440ee000}, 
+    {0x440f0000}, {0x440f2000}, {0x440f4000}, {0x440f6000}, 
+    {0x440f8000}, {0x440fa000}, {0x440fc000}, {0x440fe000}, 
+    {0x44100000}, {0x44102000}, {0x44104000}, {0x44106000}, 
+    {0x44108000}, {0x4410a000}, {0x4410c000}, {0x4410e000}, 
+    {0x44110000}, {0x44112000}, {0x44114000}, {0x44116000}, 
+    {0x44118000}, {0x4411a000}, {0x4411c000}, {0x4411e000}, 
+    {0x44120000}, {0x44122000}, {0x44124000}, {0x44126000}, 
+    {0x44128000}, {0x4412a000}, {0x4412c000}, {0x4412e000}, 
+    {0x44130000}, {0x44132000}, {0x44134000}, {0x44136000}, 
+    {0x44138000}, {0x4413a000}, {0x4413c000}, {0x4413e000}, 
+    {0x44140000}, {0x44142000}, {0x44144000}, {0x44146000}, 
+    {0x44148000}, {0x4414a000}, {0x4414c000}, {0x4414e000}, 
+    {0x44150000}, {0x44152000}, {0x44154000}, {0x44156000}, 
+    {0x44158000}, {0x4415a000}, {0x4415c000}, {0x4415e000}, 
+    {0x44160000}, {0x44162000}, {0x44164000}, {0x44166000}, 
+    {0x44168000}, {0x4416a000}, {0x4416c000}, {0x4416e000}, 
+    {0x44170000}, {0x44172000}, {0x44174000}, {0x44176000}, 
+    {0x44178000}, {0x4417a000}, {0x4417c000}, {0x4417e000}, 
+    {0x44180000}, {0x44182000}, {0x44184000}, {0x44186000}, 
+    {0x44188000}, {0x4418a000}, {0x4418c000}, {0x4418e000}, 
+    {0x44190000}, {0x44192000}, {0x44194000}, {0x44196000}, 
+    {0x44198000}, {0x4419a000}, {0x4419c000}, {0x4419e000}, 
+    {0x441a0000}, {0x441a2000}, {0x441a4000}, {0x441a6000}, 
+    {0x441a8000}, {0x441aa000}, {0x441ac000}, {0x441ae000}, 
+    {0x441b0000}, {0x441b2000}, {0x441b4000}, {0x441b6000}, 
+    {0x441b8000}, {0x441ba000}, {0x441bc000}, {0x441be000}, 
+    {0x441c0000}, {0x441c2000}, {0x441c4000}, {0x441c6000}, 
+    {0x441c8000}, {0x441ca000}, {0x441cc000}, {0x441ce000}, 
+    {0x441d0000}, {0x441d2000}, {0x441d4000}, {0x441d6000}, 
+    {0x441d8000}, {0x441da000}, {0x441dc000}, {0x441de000}, 
+    {0x441e0000}, {0x441e2000}, {0x441e4000}, {0x441e6000}, 
+    {0x441e8000}, {0x441ea000}, {0x441ec000}, {0x441ee000}, 
+    {0x441f0000}, {0x441f2000}, {0x441f4000}, {0x441f6000}, 
+    {0x441f8000}, {0x441fa000}, {0x441fc000}, {0x441fe000}, 
+    {0x44200000}, {0x44202000}, {0x44204000}, {0x44206000}, 
+    {0x44208000}, {0x4420a000}, {0x4420c000}, {0x4420e000}, 
+    {0x44210000}, {0x44212000}, {0x44214000}, {0x44216000}, 
+    {0x44218000}, {0x4421a000}, {0x4421c000}, {0x4421e000}, 
+    {0x44220000}, {0x44222000}, {0x44224000}, {0x44226000}, 
+    {0x44228000}, {0x4422a000}, {0x4422c000}, {0x4422e000}, 
+    {0x44230000}, {0x44232000}, {0x44234000}, {0x44236000}, 
+    {0x44238000}, {0x4423a000}, {0x4423c000}, {0x4423e000}, 
+    {0x44240000}, {0x44242000}, {0x44244000}, {0x44246000}, 
+    {0x44248000}, {0x4424a000}, {0x4424c000}, {0x4424e000}, 
+    {0x44250000}, {0x44252000}, {0x44254000}, {0x44256000}, 
+    {0x44258000}, {0x4425a000}, {0x4425c000}, {0x4425e000}, 
+    {0x44260000}, {0x44262000}, {0x44264000}, {0x44266000}, 
+    {0x44268000}, {0x4426a000}, {0x4426c000}, {0x4426e000}, 
+    {0x44270000}, {0x44272000}, {0x44274000}, {0x44276000}, 
+    {0x44278000}, {0x4427a000}, {0x4427c000}, {0x4427e000}, 
+    {0x44280000}, {0x44282000}, {0x44284000}, {0x44286000}, 
+    {0x44288000}, {0x4428a000}, {0x4428c000}, {0x4428e000}, 
+    {0x44290000}, {0x44292000}, {0x44294000}, {0x44296000}, 
+    {0x44298000}, {0x4429a000}, {0x4429c000}, {0x4429e000}, 
+    {0x442a0000}, {0x442a2000}, {0x442a4000}, {0x442a6000}, 
+    {0x442a8000}, {0x442aa000}, {0x442ac000}, {0x442ae000}, 
+    {0x442b0000}, {0x442b2000}, {0x442b4000}, {0x442b6000}, 
+    {0x442b8000}, {0x442ba000}, {0x442bc000}, {0x442be000}, 
+    {0x442c0000}, {0x442c2000}, {0x442c4000}, {0x442c6000}, 
+    {0x442c8000}, {0x442ca000}, {0x442cc000}, {0x442ce000}, 
+    {0x442d0000}, {0x442d2000}, {0x442d4000}, {0x442d6000}, 
+    {0x442d8000}, {0x442da000}, {0x442dc000}, {0x442de000}, 
+    {0x442e0000}, {0x442e2000}, {0x442e4000}, {0x442e6000}, 
+    {0x442e8000}, {0x442ea000}, {0x442ec000}, {0x442ee000}, 
+    {0x442f0000}, {0x442f2000}, {0x442f4000}, {0x442f6000}, 
+    {0x442f8000}, {0x442fa000}, {0x442fc000}, {0x442fe000}, 
+    {0x44300000}, {0x44302000}, {0x44304000}, {0x44306000}, 
+    {0x44308000}, {0x4430a000}, {0x4430c000}, {0x4430e000}, 
+    {0x44310000}, {0x44312000}, {0x44314000}, {0x44316000}, 
+    {0x44318000}, {0x4431a000}, {0x4431c000}, {0x4431e000}, 
+    {0x44320000}, {0x44322000}, {0x44324000}, {0x44326000}, 
+    {0x44328000}, {0x4432a000}, {0x4432c000}, {0x4432e000}, 
+    {0x44330000}, {0x44332000}, {0x44334000}, {0x44336000}, 
+    {0x44338000}, {0x4433a000}, {0x4433c000}, {0x4433e000}, 
+    {0x44340000}, {0x44342000}, {0x44344000}, {0x44346000}, 
+    {0x44348000}, {0x4434a000}, {0x4434c000}, {0x4434e000}, 
+    {0x44350000}, {0x44352000}, {0x44354000}, {0x44356000}, 
+    {0x44358000}, {0x4435a000}, {0x4435c000}, {0x4435e000}, 
+    {0x44360000}, {0x44362000}, {0x44364000}, {0x44366000}, 
+    {0x44368000}, {0x4436a000}, {0x4436c000}, {0x4436e000}, 
+    {0x44370000}, {0x44372000}, {0x44374000}, {0x44376000}, 
+    {0x44378000}, {0x4437a000}, {0x4437c000}, {0x4437e000}, 
+    {0x44380000}, {0x44382000}, {0x44384000}, {0x44386000}, 
+    {0x44388000}, {0x4438a000}, {0x4438c000}, {0x4438e000}, 
+    {0x44390000}, {0x44392000}, {0x44394000}, {0x44396000}, 
+    {0x44398000}, {0x4439a000}, {0x4439c000}, {0x4439e000}, 
+    {0x443a0000}, {0x443a2000}, {0x443a4000}, {0x443a6000}, 
+    {0x443a8000}, {0x443aa000}, {0x443ac000}, {0x443ae000}, 
+    {0x443b0000}, {0x443b2000}, {0x443b4000}, {0x443b6000}, 
+    {0x443b8000}, {0x443ba000}, {0x443bc000}, {0x443be000}, 
+    {0x443c0000}, {0x443c2000}, {0x443c4000}, {0x443c6000}, 
+    {0x443c8000}, {0x443ca000}, {0x443cc000}, {0x443ce000}, 
+    {0x443d0000}, {0x443d2000}, {0x443d4000}, {0x443d6000}, 
+    {0x443d8000}, {0x443da000}, {0x443dc000}, {0x443de000}, 
+    {0x443e0000}, {0x443e2000}, {0x443e4000}, {0x443e6000}, 
+    {0x443e8000}, {0x443ea000}, {0x443ec000}, {0x443ee000}, 
+    {0x443f0000}, {0x443f2000}, {0x443f4000}, {0x443f6000}, 
+    {0x443f8000}, {0x443fa000}, {0x443fc000}, {0x443fe000}, 
+    {0x44400000}, {0x44402000}, {0x44404000}, {0x44406000}, 
+    {0x44408000}, {0x4440a000}, {0x4440c000}, {0x4440e000}, 
+    {0x44410000}, {0x44412000}, {0x44414000}, {0x44416000}, 
+    {0x44418000}, {0x4441a000}, {0x4441c000}, {0x4441e000}, 
+    {0x44420000}, {0x44422000}, {0x44424000}, {0x44426000}, 
+    {0x44428000}, {0x4442a000}, {0x4442c000}, {0x4442e000}, 
+    {0x44430000}, {0x44432000}, {0x44434000}, {0x44436000}, 
+    {0x44438000}, {0x4443a000}, {0x4443c000}, {0x4443e000}, 
+    {0x44440000}, {0x44442000}, {0x44444000}, {0x44446000}, 
+    {0x44448000}, {0x4444a000}, {0x4444c000}, {0x4444e000}, 
+    {0x44450000}, {0x44452000}, {0x44454000}, {0x44456000}, 
+    {0x44458000}, {0x4445a000}, {0x4445c000}, {0x4445e000}, 
+    {0x44460000}, {0x44462000}, {0x44464000}, {0x44466000}, 
+    {0x44468000}, {0x4446a000}, {0x4446c000}, {0x4446e000}, 
+    {0x44470000}, {0x44472000}, {0x44474000}, {0x44476000}, 
+    {0x44478000}, {0x4447a000}, {0x4447c000}, {0x4447e000}, 
+    {0x44480000}, {0x44482000}, {0x44484000}, {0x44486000}, 
+    {0x44488000}, {0x4448a000}, {0x4448c000}, {0x4448e000}, 
+    {0x44490000}, {0x44492000}, {0x44494000}, {0x44496000}, 
+    {0x44498000}, {0x4449a000}, {0x4449c000}, {0x4449e000}, 
+    {0x444a0000}, {0x444a2000}, {0x444a4000}, {0x444a6000}, 
+    {0x444a8000}, {0x444aa000}, {0x444ac000}, {0x444ae000}, 
+    {0x444b0000}, {0x444b2000}, {0x444b4000}, {0x444b6000}, 
+    {0x444b8000}, {0x444ba000}, {0x444bc000}, {0x444be000}, 
+    {0x444c0000}, {0x444c2000}, {0x444c4000}, {0x444c6000}, 
+    {0x444c8000}, {0x444ca000}, {0x444cc000}, {0x444ce000}, 
+    {0x444d0000}, {0x444d2000}, {0x444d4000}, {0x444d6000}, 
+    {0x444d8000}, {0x444da000}, {0x444dc000}, {0x444de000}, 
+    {0x444e0000}, {0x444e2000}, {0x444e4000}, {0x444e6000}, 
+    {0x444e8000}, {0x444ea000}, {0x444ec000}, {0x444ee000}, 
+    {0x444f0000}, {0x444f2000}, {0x444f4000}, {0x444f6000}, 
+    {0x444f8000}, {0x444fa000}, {0x444fc000}, {0x444fe000}, 
+    {0x44500000}, {0x44502000}, {0x44504000}, {0x44506000}, 
+    {0x44508000}, {0x4450a000}, {0x4450c000}, {0x4450e000}, 
+    {0x44510000}, {0x44512000}, {0x44514000}, {0x44516000}, 
+    {0x44518000}, {0x4451a000}, {0x4451c000}, {0x4451e000}, 
+    {0x44520000}, {0x44522000}, {0x44524000}, {0x44526000}, 
+    {0x44528000}, {0x4452a000}, {0x4452c000}, {0x4452e000}, 
+    {0x44530000}, {0x44532000}, {0x44534000}, {0x44536000}, 
+    {0x44538000}, {0x4453a000}, {0x4453c000}, {0x4453e000}, 
+    {0x44540000}, {0x44542000}, {0x44544000}, {0x44546000}, 
+    {0x44548000}, {0x4454a000}, {0x4454c000}, {0x4454e000}, 
+    {0x44550000}, {0x44552000}, {0x44554000}, {0x44556000}, 
+    {0x44558000}, {0x4455a000}, {0x4455c000}, {0x4455e000}, 
+    {0x44560000}, {0x44562000}, {0x44564000}, {0x44566000}, 
+    {0x44568000}, {0x4456a000}, {0x4456c000}, {0x4456e000}, 
+    {0x44570000}, {0x44572000}, {0x44574000}, {0x44576000}, 
+    {0x44578000}, {0x4457a000}, {0x4457c000}, {0x4457e000}, 
+    {0x44580000}, {0x44582000}, {0x44584000}, {0x44586000}, 
+    {0x44588000}, {0x4458a000}, {0x4458c000}, {0x4458e000}, 
+    {0x44590000}, {0x44592000}, {0x44594000}, {0x44596000}, 
+    {0x44598000}, {0x4459a000}, {0x4459c000}, {0x4459e000}, 
+    {0x445a0000}, {0x445a2000}, {0x445a4000}, {0x445a6000}, 
+    {0x445a8000}, {0x445aa000}, {0x445ac000}, {0x445ae000}, 
+    {0x445b0000}, {0x445b2000}, {0x445b4000}, {0x445b6000}, 
+    {0x445b8000}, {0x445ba000}, {0x445bc000}, {0x445be000}, 
+    {0x445c0000}, {0x445c2000}, {0x445c4000}, {0x445c6000}, 
+    {0x445c8000}, {0x445ca000}, {0x445cc000}, {0x445ce000}, 
+    {0x445d0000}, {0x445d2000}, {0x445d4000}, {0x445d6000}, 
+    {0x445d8000}, {0x445da000}, {0x445dc000}, {0x445de000}, 
+    {0x445e0000}, {0x445e2000}, {0x445e4000}, {0x445e6000}, 
+    {0x445e8000}, {0x445ea000}, {0x445ec000}, {0x445ee000}, 
+    {0x445f0000}, {0x445f2000}, {0x445f4000}, {0x445f6000}, 
+    {0x445f8000}, {0x445fa000}, {0x445fc000}, {0x445fe000}, 
+    {0x44600000}, {0x44602000}, {0x44604000}, {0x44606000}, 
+    {0x44608000}, {0x4460a000}, {0x4460c000}, {0x4460e000}, 
+    {0x44610000}, {0x44612000}, {0x44614000}, {0x44616000}, 
+    {0x44618000}, {0x4461a000}, {0x4461c000}, {0x4461e000}, 
+    {0x44620000}, {0x44622000}, {0x44624000}, {0x44626000}, 
+    {0x44628000}, {0x4462a000}, {0x4462c000}, {0x4462e000}, 
+    {0x44630000}, {0x44632000}, {0x44634000}, {0x44636000}, 
+    {0x44638000}, {0x4463a000}, {0x4463c000}, {0x4463e000}, 
+    {0x44640000}, {0x44642000}, {0x44644000}, {0x44646000}, 
+    {0x44648000}, {0x4464a000}, {0x4464c000}, {0x4464e000}, 
+    {0x44650000}, {0x44652000}, {0x44654000}, {0x44656000}, 
+    {0x44658000}, {0x4465a000}, {0x4465c000}, {0x4465e000}, 
+    {0x44660000}, {0x44662000}, {0x44664000}, {0x44666000}, 
+    {0x44668000}, {0x4466a000}, {0x4466c000}, {0x4466e000}, 
+    {0x44670000}, {0x44672000}, {0x44674000}, {0x44676000}, 
+    {0x44678000}, {0x4467a000}, {0x4467c000}, {0x4467e000}, 
+    {0x44680000}, {0x44682000}, {0x44684000}, {0x44686000}, 
+    {0x44688000}, {0x4468a000}, {0x4468c000}, {0x4468e000}, 
+    {0x44690000}, {0x44692000}, {0x44694000}, {0x44696000}, 
+    {0x44698000}, {0x4469a000}, {0x4469c000}, {0x4469e000}, 
+    {0x446a0000}, {0x446a2000}, {0x446a4000}, {0x446a6000}, 
+    {0x446a8000}, {0x446aa000}, {0x446ac000}, {0x446ae000}, 
+    {0x446b0000}, {0x446b2000}, {0x446b4000}, {0x446b6000}, 
+    {0x446b8000}, {0x446ba000}, {0x446bc000}, {0x446be000}, 
+    {0x446c0000}, {0x446c2000}, {0x446c4000}, {0x446c6000}, 
+    {0x446c8000}, {0x446ca000}, {0x446cc000}, {0x446ce000}, 
+    {0x446d0000}, {0x446d2000}, {0x446d4000}, {0x446d6000}, 
+    {0x446d8000}, {0x446da000}, {0x446dc000}, {0x446de000}, 
+    {0x446e0000}, {0x446e2000}, {0x446e4000}, {0x446e6000}, 
+    {0x446e8000}, {0x446ea000}, {0x446ec000}, {0x446ee000}, 
+    {0x446f0000}, {0x446f2000}, {0x446f4000}, {0x446f6000}, 
+    {0x446f8000}, {0x446fa000}, {0x446fc000}, {0x446fe000}, 
+    {0x44700000}, {0x44702000}, {0x44704000}, {0x44706000}, 
+    {0x44708000}, {0x4470a000}, {0x4470c000}, {0x4470e000}, 
+    {0x44710000}, {0x44712000}, {0x44714000}, {0x44716000}, 
+    {0x44718000}, {0x4471a000}, {0x4471c000}, {0x4471e000}, 
+    {0x44720000}, {0x44722000}, {0x44724000}, {0x44726000}, 
+    {0x44728000}, {0x4472a000}, {0x4472c000}, {0x4472e000}, 
+    {0x44730000}, {0x44732000}, {0x44734000}, {0x44736000}, 
+    {0x44738000}, {0x4473a000}, {0x4473c000}, {0x4473e000}, 
+    {0x44740000}, {0x44742000}, {0x44744000}, {0x44746000}, 
+    {0x44748000}, {0x4474a000}, {0x4474c000}, {0x4474e000}, 
+    {0x44750000}, {0x44752000}, {0x44754000}, {0x44756000}, 
+    {0x44758000}, {0x4475a000}, {0x4475c000}, {0x4475e000}, 
+    {0x44760000}, {0x44762000}, {0x44764000}, {0x44766000}, 
+    {0x44768000}, {0x4476a000}, {0x4476c000}, {0x4476e000}, 
+    {0x44770000}, {0x44772000}, {0x44774000}, {0x44776000}, 
+    {0x44778000}, {0x4477a000}, {0x4477c000}, {0x4477e000}, 
+    {0x44780000}, {0x44782000}, {0x44784000}, {0x44786000}, 
+    {0x44788000}, {0x4478a000}, {0x4478c000}, {0x4478e000}, 
+    {0x44790000}, {0x44792000}, {0x44794000}, {0x44796000}, 
+    {0x44798000}, {0x4479a000}, {0x4479c000}, {0x4479e000}, 
+    {0x447a0000}, {0x447a2000}, {0x447a4000}, {0x447a6000}, 
+    {0x447a8000}, {0x447aa000}, {0x447ac000}, {0x447ae000}, 
+    {0x447b0000}, {0x447b2000}, {0x447b4000}, {0x447b6000}, 
+    {0x447b8000}, {0x447ba000}, {0x447bc000}, {0x447be000}, 
+    {0x447c0000}, {0x447c2000}, {0x447c4000}, {0x447c6000}, 
+    {0x447c8000}, {0x447ca000}, {0x447cc000}, {0x447ce000}, 
+    {0x447d0000}, {0x447d2000}, {0x447d4000}, {0x447d6000}, 
+    {0x447d8000}, {0x447da000}, {0x447dc000}, {0x447de000}, 
+    {0x447e0000}, {0x447e2000}, {0x447e4000}, {0x447e6000}, 
+    {0x447e8000}, {0x447ea000}, {0x447ec000}, {0x447ee000}, 
+    {0x447f0000}, {0x447f2000}, {0x447f4000}, {0x447f6000}, 
+    {0x447f8000}, {0x447fa000}, {0x447fc000}, {0x447fe000}, 
+    {0x44800000}, {0x44802000}, {0x44804000}, {0x44806000}, 
+    {0x44808000}, {0x4480a000}, {0x4480c000}, {0x4480e000}, 
+    {0x44810000}, {0x44812000}, {0x44814000}, {0x44816000}, 
+    {0x44818000}, {0x4481a000}, {0x4481c000}, {0x4481e000}, 
+    {0x44820000}, {0x44822000}, {0x44824000}, {0x44826000}, 
+    {0x44828000}, {0x4482a000}, {0x4482c000}, {0x4482e000}, 
+    {0x44830000}, {0x44832000}, {0x44834000}, {0x44836000}, 
+    {0x44838000}, {0x4483a000}, {0x4483c000}, {0x4483e000}, 
+    {0x44840000}, {0x44842000}, {0x44844000}, {0x44846000}, 
+    {0x44848000}, {0x4484a000}, {0x4484c000}, {0x4484e000}, 
+    {0x44850000}, {0x44852000}, {0x44854000}, {0x44856000}, 
+    {0x44858000}, {0x4485a000}, {0x4485c000}, {0x4485e000}, 
+    {0x44860000}, {0x44862000}, {0x44864000}, {0x44866000}, 
+    {0x44868000}, {0x4486a000}, {0x4486c000}, {0x4486e000}, 
+    {0x44870000}, {0x44872000}, {0x44874000}, {0x44876000}, 
+    {0x44878000}, {0x4487a000}, {0x4487c000}, {0x4487e000}, 
+    {0x44880000}, {0x44882000}, {0x44884000}, {0x44886000}, 
+    {0x44888000}, {0x4488a000}, {0x4488c000}, {0x4488e000}, 
+    {0x44890000}, {0x44892000}, {0x44894000}, {0x44896000}, 
+    {0x44898000}, {0x4489a000}, {0x4489c000}, {0x4489e000}, 
+    {0x448a0000}, {0x448a2000}, {0x448a4000}, {0x448a6000}, 
+    {0x448a8000}, {0x448aa000}, {0x448ac000}, {0x448ae000}, 
+    {0x448b0000}, {0x448b2000}, {0x448b4000}, {0x448b6000}, 
+    {0x448b8000}, {0x448ba000}, {0x448bc000}, {0x448be000}, 
+    {0x448c0000}, {0x448c2000}, {0x448c4000}, {0x448c6000}, 
+    {0x448c8000}, {0x448ca000}, {0x448cc000}, {0x448ce000}, 
+    {0x448d0000}, {0x448d2000}, {0x448d4000}, {0x448d6000}, 
+    {0x448d8000}, {0x448da000}, {0x448dc000}, {0x448de000}, 
+    {0x448e0000}, {0x448e2000}, {0x448e4000}, {0x448e6000}, 
+    {0x448e8000}, {0x448ea000}, {0x448ec000}, {0x448ee000}, 
+    {0x448f0000}, {0x448f2000}, {0x448f4000}, {0x448f6000}, 
+    {0x448f8000}, {0x448fa000}, {0x448fc000}, {0x448fe000}, 
+    {0x44900000}, {0x44902000}, {0x44904000}, {0x44906000}, 
+    {0x44908000}, {0x4490a000}, {0x4490c000}, {0x4490e000}, 
+    {0x44910000}, {0x44912000}, {0x44914000}, {0x44916000}, 
+    {0x44918000}, {0x4491a000}, {0x4491c000}, {0x4491e000}, 
+    {0x44920000}, {0x44922000}, {0x44924000}, {0x44926000}, 
+    {0x44928000}, {0x4492a000}, {0x4492c000}, {0x4492e000}, 
+    {0x44930000}, {0x44932000}, {0x44934000}, {0x44936000}, 
+    {0x44938000}, {0x4493a000}, {0x4493c000}, {0x4493e000}, 
+    {0x44940000}, {0x44942000}, {0x44944000}, {0x44946000}, 
+    {0x44948000}, {0x4494a000}, {0x4494c000}, {0x4494e000}, 
+    {0x44950000}, {0x44952000}, {0x44954000}, {0x44956000}, 
+    {0x44958000}, {0x4495a000}, {0x4495c000}, {0x4495e000}, 
+    {0x44960000}, {0x44962000}, {0x44964000}, {0x44966000}, 
+    {0x44968000}, {0x4496a000}, {0x4496c000}, {0x4496e000}, 
+    {0x44970000}, {0x44972000}, {0x44974000}, {0x44976000}, 
+    {0x44978000}, {0x4497a000}, {0x4497c000}, {0x4497e000}, 
+    {0x44980000}, {0x44982000}, {0x44984000}, {0x44986000}, 
+    {0x44988000}, {0x4498a000}, {0x4498c000}, {0x4498e000}, 
+    {0x44990000}, {0x44992000}, {0x44994000}, {0x44996000}, 
+    {0x44998000}, {0x4499a000}, {0x4499c000}, {0x4499e000}, 
+    {0x449a0000}, {0x449a2000}, {0x449a4000}, {0x449a6000}, 
+    {0x449a8000}, {0x449aa000}, {0x449ac000}, {0x449ae000}, 
+    {0x449b0000}, {0x449b2000}, {0x449b4000}, {0x449b6000}, 
+    {0x449b8000}, {0x449ba000}, {0x449bc000}, {0x449be000}, 
+    {0x449c0000}, {0x449c2000}, {0x449c4000}, {0x449c6000}, 
+    {0x449c8000}, {0x449ca000}, {0x449cc000}, {0x449ce000}, 
+    {0x449d0000}, {0x449d2000}, {0x449d4000}, {0x449d6000}, 
+    {0x449d8000}, {0x449da000}, {0x449dc000}, {0x449de000}, 
+    {0x449e0000}, {0x449e2000}, {0x449e4000}, {0x449e6000}, 
+    {0x449e8000}, {0x449ea000}, {0x449ec000}, {0x449ee000}, 
+    {0x449f0000}, {0x449f2000}, {0x449f4000}, {0x449f6000}, 
+    {0x449f8000}, {0x449fa000}, {0x449fc000}, {0x449fe000}, 
+    {0x44a00000}, {0x44a02000}, {0x44a04000}, {0x44a06000}, 
+    {0x44a08000}, {0x44a0a000}, {0x44a0c000}, {0x44a0e000}, 
+    {0x44a10000}, {0x44a12000}, {0x44a14000}, {0x44a16000}, 
+    {0x44a18000}, {0x44a1a000}, {0x44a1c000}, {0x44a1e000}, 
+    {0x44a20000}, {0x44a22000}, {0x44a24000}, {0x44a26000}, 
+    {0x44a28000}, {0x44a2a000}, {0x44a2c000}, {0x44a2e000}, 
+    {0x44a30000}, {0x44a32000}, {0x44a34000}, {0x44a36000}, 
+    {0x44a38000}, {0x44a3a000}, {0x44a3c000}, {0x44a3e000}, 
+    {0x44a40000}, {0x44a42000}, {0x44a44000}, {0x44a46000}, 
+    {0x44a48000}, {0x44a4a000}, {0x44a4c000}, {0x44a4e000}, 
+    {0x44a50000}, {0x44a52000}, {0x44a54000}, {0x44a56000}, 
+    {0x44a58000}, {0x44a5a000}, {0x44a5c000}, {0x44a5e000}, 
+    {0x44a60000}, {0x44a62000}, {0x44a64000}, {0x44a66000}, 
+    {0x44a68000}, {0x44a6a000}, {0x44a6c000}, {0x44a6e000}, 
+    {0x44a70000}, {0x44a72000}, {0x44a74000}, {0x44a76000}, 
+    {0x44a78000}, {0x44a7a000}, {0x44a7c000}, {0x44a7e000}, 
+    {0x44a80000}, {0x44a82000}, {0x44a84000}, {0x44a86000}, 
+    {0x44a88000}, {0x44a8a000}, {0x44a8c000}, {0x44a8e000}, 
+    {0x44a90000}, {0x44a92000}, {0x44a94000}, {0x44a96000}, 
+    {0x44a98000}, {0x44a9a000}, {0x44a9c000}, {0x44a9e000}, 
+    {0x44aa0000}, {0x44aa2000}, {0x44aa4000}, {0x44aa6000}, 
+    {0x44aa8000}, {0x44aaa000}, {0x44aac000}, {0x44aae000}, 
+    {0x44ab0000}, {0x44ab2000}, {0x44ab4000}, {0x44ab6000}, 
+    {0x44ab8000}, {0x44aba000}, {0x44abc000}, {0x44abe000}, 
+    {0x44ac0000}, {0x44ac2000}, {0x44ac4000}, {0x44ac6000}, 
+    {0x44ac8000}, {0x44aca000}, {0x44acc000}, {0x44ace000}, 
+    {0x44ad0000}, {0x44ad2000}, {0x44ad4000}, {0x44ad6000}, 
+    {0x44ad8000}, {0x44ada000}, {0x44adc000}, {0x44ade000}, 
+    {0x44ae0000}, {0x44ae2000}, {0x44ae4000}, {0x44ae6000}, 
+    {0x44ae8000}, {0x44aea000}, {0x44aec000}, {0x44aee000}, 
+    {0x44af0000}, {0x44af2000}, {0x44af4000}, {0x44af6000}, 
+    {0x44af8000}, {0x44afa000}, {0x44afc000}, {0x44afe000}, 
+    {0x44b00000}, {0x44b02000}, {0x44b04000}, {0x44b06000}, 
+    {0x44b08000}, {0x44b0a000}, {0x44b0c000}, {0x44b0e000}, 
+    {0x44b10000}, {0x44b12000}, {0x44b14000}, {0x44b16000}, 
+    {0x44b18000}, {0x44b1a000}, {0x44b1c000}, {0x44b1e000}, 
+    {0x44b20000}, {0x44b22000}, {0x44b24000}, {0x44b26000}, 
+    {0x44b28000}, {0x44b2a000}, {0x44b2c000}, {0x44b2e000}, 
+    {0x44b30000}, {0x44b32000}, {0x44b34000}, {0x44b36000}, 
+    {0x44b38000}, {0x44b3a000}, {0x44b3c000}, {0x44b3e000}, 
+    {0x44b40000}, {0x44b42000}, {0x44b44000}, {0x44b46000}, 
+    {0x44b48000}, {0x44b4a000}, {0x44b4c000}, {0x44b4e000}, 
+    {0x44b50000}, {0x44b52000}, {0x44b54000}, {0x44b56000}, 
+    {0x44b58000}, {0x44b5a000}, {0x44b5c000}, {0x44b5e000}, 
+    {0x44b60000}, {0x44b62000}, {0x44b64000}, {0x44b66000}, 
+    {0x44b68000}, {0x44b6a000}, {0x44b6c000}, {0x44b6e000}, 
+    {0x44b70000}, {0x44b72000}, {0x44b74000}, {0x44b76000}, 
+    {0x44b78000}, {0x44b7a000}, {0x44b7c000}, {0x44b7e000}, 
+    {0x44b80000}, {0x44b82000}, {0x44b84000}, {0x44b86000}, 
+    {0x44b88000}, {0x44b8a000}, {0x44b8c000}, {0x44b8e000}, 
+    {0x44b90000}, {0x44b92000}, {0x44b94000}, {0x44b96000}, 
+    {0x44b98000}, {0x44b9a000}, {0x44b9c000}, {0x44b9e000}, 
+    {0x44ba0000}, {0x44ba2000}, {0x44ba4000}, {0x44ba6000}, 
+    {0x44ba8000}, {0x44baa000}, {0x44bac000}, {0x44bae000}, 
+    {0x44bb0000}, {0x44bb2000}, {0x44bb4000}, {0x44bb6000}, 
+    {0x44bb8000}, {0x44bba000}, {0x44bbc000}, {0x44bbe000}, 
+    {0x44bc0000}, {0x44bc2000}, {0x44bc4000}, {0x44bc6000}, 
+    {0x44bc8000}, {0x44bca000}, {0x44bcc000}, {0x44bce000}, 
+    {0x44bd0000}, {0x44bd2000}, {0x44bd4000}, {0x44bd6000}, 
+    {0x44bd8000}, {0x44bda000}, {0x44bdc000}, {0x44bde000}, 
+    {0x44be0000}, {0x44be2000}, {0x44be4000}, {0x44be6000}, 
+    {0x44be8000}, {0x44bea000}, {0x44bec000}, {0x44bee000}, 
+    {0x44bf0000}, {0x44bf2000}, {0x44bf4000}, {0x44bf6000}, 
+    {0x44bf8000}, {0x44bfa000}, {0x44bfc000}, {0x44bfe000}, 
+    {0x44c00000}, {0x44c02000}, {0x44c04000}, {0x44c06000}, 
+    {0x44c08000}, {0x44c0a000}, {0x44c0c000}, {0x44c0e000}, 
+    {0x44c10000}, {0x44c12000}, {0x44c14000}, {0x44c16000}, 
+    {0x44c18000}, {0x44c1a000}, {0x44c1c000}, {0x44c1e000}, 
+    {0x44c20000}, {0x44c22000}, {0x44c24000}, {0x44c26000}, 
+    {0x44c28000}, {0x44c2a000}, {0x44c2c000}, {0x44c2e000}, 
+    {0x44c30000}, {0x44c32000}, {0x44c34000}, {0x44c36000}, 
+    {0x44c38000}, {0x44c3a000}, {0x44c3c000}, {0x44c3e000}, 
+    {0x44c40000}, {0x44c42000}, {0x44c44000}, {0x44c46000}, 
+    {0x44c48000}, {0x44c4a000}, {0x44c4c000}, {0x44c4e000}, 
+    {0x44c50000}, {0x44c52000}, {0x44c54000}, {0x44c56000}, 
+    {0x44c58000}, {0x44c5a000}, {0x44c5c000}, {0x44c5e000}, 
+    {0x44c60000}, {0x44c62000}, {0x44c64000}, {0x44c66000}, 
+    {0x44c68000}, {0x44c6a000}, {0x44c6c000}, {0x44c6e000}, 
+    {0x44c70000}, {0x44c72000}, {0x44c74000}, {0x44c76000}, 
+    {0x44c78000}, {0x44c7a000}, {0x44c7c000}, {0x44c7e000}, 
+    {0x44c80000}, {0x44c82000}, {0x44c84000}, {0x44c86000}, 
+    {0x44c88000}, {0x44c8a000}, {0x44c8c000}, {0x44c8e000}, 
+    {0x44c90000}, {0x44c92000}, {0x44c94000}, {0x44c96000}, 
+    {0x44c98000}, {0x44c9a000}, {0x44c9c000}, {0x44c9e000}, 
+    {0x44ca0000}, {0x44ca2000}, {0x44ca4000}, {0x44ca6000}, 
+    {0x44ca8000}, {0x44caa000}, {0x44cac000}, {0x44cae000}, 
+    {0x44cb0000}, {0x44cb2000}, {0x44cb4000}, {0x44cb6000}, 
+    {0x44cb8000}, {0x44cba000}, {0x44cbc000}, {0x44cbe000}, 
+    {0x44cc0000}, {0x44cc2000}, {0x44cc4000}, {0x44cc6000}, 
+    {0x44cc8000}, {0x44cca000}, {0x44ccc000}, {0x44cce000}, 
+    {0x44cd0000}, {0x44cd2000}, {0x44cd4000}, {0x44cd6000}, 
+    {0x44cd8000}, {0x44cda000}, {0x44cdc000}, {0x44cde000}, 
+    {0x44ce0000}, {0x44ce2000}, {0x44ce4000}, {0x44ce6000}, 
+    {0x44ce8000}, {0x44cea000}, {0x44cec000}, {0x44cee000}, 
+    {0x44cf0000}, {0x44cf2000}, {0x44cf4000}, {0x44cf6000}, 
+    {0x44cf8000}, {0x44cfa000}, {0x44cfc000}, {0x44cfe000}, 
+    {0x44d00000}, {0x44d02000}, {0x44d04000}, {0x44d06000}, 
+    {0x44d08000}, {0x44d0a000}, {0x44d0c000}, {0x44d0e000}, 
+    {0x44d10000}, {0x44d12000}, {0x44d14000}, {0x44d16000}, 
+    {0x44d18000}, {0x44d1a000}, {0x44d1c000}, {0x44d1e000}, 
+    {0x44d20000}, {0x44d22000}, {0x44d24000}, {0x44d26000}, 
+    {0x44d28000}, {0x44d2a000}, {0x44d2c000}, {0x44d2e000}, 
+    {0x44d30000}, {0x44d32000}, {0x44d34000}, {0x44d36000}, 
+    {0x44d38000}, {0x44d3a000}, {0x44d3c000}, {0x44d3e000}, 
+    {0x44d40000}, {0x44d42000}, {0x44d44000}, {0x44d46000}, 
+    {0x44d48000}, {0x44d4a000}, {0x44d4c000}, {0x44d4e000}, 
+    {0x44d50000}, {0x44d52000}, {0x44d54000}, {0x44d56000}, 
+    {0x44d58000}, {0x44d5a000}, {0x44d5c000}, {0x44d5e000}, 
+    {0x44d60000}, {0x44d62000}, {0x44d64000}, {0x44d66000}, 
+    {0x44d68000}, {0x44d6a000}, {0x44d6c000}, {0x44d6e000}, 
+    {0x44d70000}, {0x44d72000}, {0x44d74000}, {0x44d76000}, 
+    {0x44d78000}, {0x44d7a000}, {0x44d7c000}, {0x44d7e000}, 
+    {0x44d80000}, {0x44d82000}, {0x44d84000}, {0x44d86000}, 
+    {0x44d88000}, {0x44d8a000}, {0x44d8c000}, {0x44d8e000}, 
+    {0x44d90000}, {0x44d92000}, {0x44d94000}, {0x44d96000}, 
+    {0x44d98000}, {0x44d9a000}, {0x44d9c000}, {0x44d9e000}, 
+    {0x44da0000}, {0x44da2000}, {0x44da4000}, {0x44da6000}, 
+    {0x44da8000}, {0x44daa000}, {0x44dac000}, {0x44dae000}, 
+    {0x44db0000}, {0x44db2000}, {0x44db4000}, {0x44db6000}, 
+    {0x44db8000}, {0x44dba000}, {0x44dbc000}, {0x44dbe000}, 
+    {0x44dc0000}, {0x44dc2000}, {0x44dc4000}, {0x44dc6000}, 
+    {0x44dc8000}, {0x44dca000}, {0x44dcc000}, {0x44dce000}, 
+    {0x44dd0000}, {0x44dd2000}, {0x44dd4000}, {0x44dd6000}, 
+    {0x44dd8000}, {0x44dda000}, {0x44ddc000}, {0x44dde000}, 
+    {0x44de0000}, {0x44de2000}, {0x44de4000}, {0x44de6000}, 
+    {0x44de8000}, {0x44dea000}, {0x44dec000}, {0x44dee000}, 
+    {0x44df0000}, {0x44df2000}, {0x44df4000}, {0x44df6000}, 
+    {0x44df8000}, {0x44dfa000}, {0x44dfc000}, {0x44dfe000}, 
+    {0x44e00000}, {0x44e02000}, {0x44e04000}, {0x44e06000}, 
+    {0x44e08000}, {0x44e0a000}, {0x44e0c000}, {0x44e0e000}, 
+    {0x44e10000}, {0x44e12000}, {0x44e14000}, {0x44e16000}, 
+    {0x44e18000}, {0x44e1a000}, {0x44e1c000}, {0x44e1e000}, 
+    {0x44e20000}, {0x44e22000}, {0x44e24000}, {0x44e26000}, 
+    {0x44e28000}, {0x44e2a000}, {0x44e2c000}, {0x44e2e000}, 
+    {0x44e30000}, {0x44e32000}, {0x44e34000}, {0x44e36000}, 
+    {0x44e38000}, {0x44e3a000}, {0x44e3c000}, {0x44e3e000}, 
+    {0x44e40000}, {0x44e42000}, {0x44e44000}, {0x44e46000}, 
+    {0x44e48000}, {0x44e4a000}, {0x44e4c000}, {0x44e4e000}, 
+    {0x44e50000}, {0x44e52000}, {0x44e54000}, {0x44e56000}, 
+    {0x44e58000}, {0x44e5a000}, {0x44e5c000}, {0x44e5e000}, 
+    {0x44e60000}, {0x44e62000}, {0x44e64000}, {0x44e66000}, 
+    {0x44e68000}, {0x44e6a000}, {0x44e6c000}, {0x44e6e000}, 
+    {0x44e70000}, {0x44e72000}, {0x44e74000}, {0x44e76000}, 
+    {0x44e78000}, {0x44e7a000}, {0x44e7c000}, {0x44e7e000}, 
+    {0x44e80000}, {0x44e82000}, {0x44e84000}, {0x44e86000}, 
+    {0x44e88000}, {0x44e8a000}, {0x44e8c000}, {0x44e8e000}, 
+    {0x44e90000}, {0x44e92000}, {0x44e94000}, {0x44e96000}, 
+    {0x44e98000}, {0x44e9a000}, {0x44e9c000}, {0x44e9e000}, 
+    {0x44ea0000}, {0x44ea2000}, {0x44ea4000}, {0x44ea6000}, 
+    {0x44ea8000}, {0x44eaa000}, {0x44eac000}, {0x44eae000}, 
+    {0x44eb0000}, {0x44eb2000}, {0x44eb4000}, {0x44eb6000}, 
+    {0x44eb8000}, {0x44eba000}, {0x44ebc000}, {0x44ebe000}, 
+    {0x44ec0000}, {0x44ec2000}, {0x44ec4000}, {0x44ec6000}, 
+    {0x44ec8000}, {0x44eca000}, {0x44ecc000}, {0x44ece000}, 
+    {0x44ed0000}, {0x44ed2000}, {0x44ed4000}, {0x44ed6000}, 
+    {0x44ed8000}, {0x44eda000}, {0x44edc000}, {0x44ede000}, 
+    {0x44ee0000}, {0x44ee2000}, {0x44ee4000}, {0x44ee6000}, 
+    {0x44ee8000}, {0x44eea000}, {0x44eec000}, {0x44eee000}, 
+    {0x44ef0000}, {0x44ef2000}, {0x44ef4000}, {0x44ef6000}, 
+    {0x44ef8000}, {0x44efa000}, {0x44efc000}, {0x44efe000}, 
+    {0x44f00000}, {0x44f02000}, {0x44f04000}, {0x44f06000}, 
+    {0x44f08000}, {0x44f0a000}, {0x44f0c000}, {0x44f0e000}, 
+    {0x44f10000}, {0x44f12000}, {0x44f14000}, {0x44f16000}, 
+    {0x44f18000}, {0x44f1a000}, {0x44f1c000}, {0x44f1e000}, 
+    {0x44f20000}, {0x44f22000}, {0x44f24000}, {0x44f26000}, 
+    {0x44f28000}, {0x44f2a000}, {0x44f2c000}, {0x44f2e000}, 
+    {0x44f30000}, {0x44f32000}, {0x44f34000}, {0x44f36000}, 
+    {0x44f38000}, {0x44f3a000}, {0x44f3c000}, {0x44f3e000}, 
+    {0x44f40000}, {0x44f42000}, {0x44f44000}, {0x44f46000}, 
+    {0x44f48000}, {0x44f4a000}, {0x44f4c000}, {0x44f4e000}, 
+    {0x44f50000}, {0x44f52000}, {0x44f54000}, {0x44f56000}, 
+    {0x44f58000}, {0x44f5a000}, {0x44f5c000}, {0x44f5e000}, 
+    {0x44f60000}, {0x44f62000}, {0x44f64000}, {0x44f66000}, 
+    {0x44f68000}, {0x44f6a000}, {0x44f6c000}, {0x44f6e000}, 
+    {0x44f70000}, {0x44f72000}, {0x44f74000}, {0x44f76000}, 
+    {0x44f78000}, {0x44f7a000}, {0x44f7c000}, {0x44f7e000}, 
+    {0x44f80000}, {0x44f82000}, {0x44f84000}, {0x44f86000}, 
+    {0x44f88000}, {0x44f8a000}, {0x44f8c000}, {0x44f8e000}, 
+    {0x44f90000}, {0x44f92000}, {0x44f94000}, {0x44f96000}, 
+    {0x44f98000}, {0x44f9a000}, {0x44f9c000}, {0x44f9e000}, 
+    {0x44fa0000}, {0x44fa2000}, {0x44fa4000}, {0x44fa6000}, 
+    {0x44fa8000}, {0x44faa000}, {0x44fac000}, {0x44fae000}, 
+    {0x44fb0000}, {0x44fb2000}, {0x44fb4000}, {0x44fb6000}, 
+    {0x44fb8000}, {0x44fba000}, {0x44fbc000}, {0x44fbe000}, 
+    {0x44fc0000}, {0x44fc2000}, {0x44fc4000}, {0x44fc6000}, 
+    {0x44fc8000}, {0x44fca000}, {0x44fcc000}, {0x44fce000}, 
+    {0x44fd0000}, {0x44fd2000}, {0x44fd4000}, {0x44fd6000}, 
+    {0x44fd8000}, {0x44fda000}, {0x44fdc000}, {0x44fde000}, 
+    {0x44fe0000}, {0x44fe2000}, {0x44fe4000}, {0x44fe6000}, 
+    {0x44fe8000}, {0x44fea000}, {0x44fec000}, {0x44fee000}, 
+    {0x44ff0000}, {0x44ff2000}, {0x44ff4000}, {0x44ff6000}, 
+    {0x44ff8000}, {0x44ffa000}, {0x44ffc000}, {0x44ffe000}, 
+    {0x45000000}, {0x45002000}, {0x45004000}, {0x45006000}, 
+    {0x45008000}, {0x4500a000}, {0x4500c000}, {0x4500e000}, 
+    {0x45010000}, {0x45012000}, {0x45014000}, {0x45016000}, 
+    {0x45018000}, {0x4501a000}, {0x4501c000}, {0x4501e000}, 
+    {0x45020000}, {0x45022000}, {0x45024000}, {0x45026000}, 
+    {0x45028000}, {0x4502a000}, {0x4502c000}, {0x4502e000}, 
+    {0x45030000}, {0x45032000}, {0x45034000}, {0x45036000}, 
+    {0x45038000}, {0x4503a000}, {0x4503c000}, {0x4503e000}, 
+    {0x45040000}, {0x45042000}, {0x45044000}, {0x45046000}, 
+    {0x45048000}, {0x4504a000}, {0x4504c000}, {0x4504e000}, 
+    {0x45050000}, {0x45052000}, {0x45054000}, {0x45056000}, 
+    {0x45058000}, {0x4505a000}, {0x4505c000}, {0x4505e000}, 
+    {0x45060000}, {0x45062000}, {0x45064000}, {0x45066000}, 
+    {0x45068000}, {0x4506a000}, {0x4506c000}, {0x4506e000}, 
+    {0x45070000}, {0x45072000}, {0x45074000}, {0x45076000}, 
+    {0x45078000}, {0x4507a000}, {0x4507c000}, {0x4507e000}, 
+    {0x45080000}, {0x45082000}, {0x45084000}, {0x45086000}, 
+    {0x45088000}, {0x4508a000}, {0x4508c000}, {0x4508e000}, 
+    {0x45090000}, {0x45092000}, {0x45094000}, {0x45096000}, 
+    {0x45098000}, {0x4509a000}, {0x4509c000}, {0x4509e000}, 
+    {0x450a0000}, {0x450a2000}, {0x450a4000}, {0x450a6000}, 
+    {0x450a8000}, {0x450aa000}, {0x450ac000}, {0x450ae000}, 
+    {0x450b0000}, {0x450b2000}, {0x450b4000}, {0x450b6000}, 
+    {0x450b8000}, {0x450ba000}, {0x450bc000}, {0x450be000}, 
+    {0x450c0000}, {0x450c2000}, {0x450c4000}, {0x450c6000}, 
+    {0x450c8000}, {0x450ca000}, {0x450cc000}, {0x450ce000}, 
+    {0x450d0000}, {0x450d2000}, {0x450d4000}, {0x450d6000}, 
+    {0x450d8000}, {0x450da000}, {0x450dc000}, {0x450de000}, 
+    {0x450e0000}, {0x450e2000}, {0x450e4000}, {0x450e6000}, 
+    {0x450e8000}, {0x450ea000}, {0x450ec000}, {0x450ee000}, 
+    {0x450f0000}, {0x450f2000}, {0x450f4000}, {0x450f6000}, 
+    {0x450f8000}, {0x450fa000}, {0x450fc000}, {0x450fe000}, 
+    {0x45100000}, {0x45102000}, {0x45104000}, {0x45106000}, 
+    {0x45108000}, {0x4510a000}, {0x4510c000}, {0x4510e000}, 
+    {0x45110000}, {0x45112000}, {0x45114000}, {0x45116000}, 
+    {0x45118000}, {0x4511a000}, {0x4511c000}, {0x4511e000}, 
+    {0x45120000}, {0x45122000}, {0x45124000}, {0x45126000}, 
+    {0x45128000}, {0x4512a000}, {0x4512c000}, {0x4512e000}, 
+    {0x45130000}, {0x45132000}, {0x45134000}, {0x45136000}, 
+    {0x45138000}, {0x4513a000}, {0x4513c000}, {0x4513e000}, 
+    {0x45140000}, {0x45142000}, {0x45144000}, {0x45146000}, 
+    {0x45148000}, {0x4514a000}, {0x4514c000}, {0x4514e000}, 
+    {0x45150000}, {0x45152000}, {0x45154000}, {0x45156000}, 
+    {0x45158000}, {0x4515a000}, {0x4515c000}, {0x4515e000}, 
+    {0x45160000}, {0x45162000}, {0x45164000}, {0x45166000}, 
+    {0x45168000}, {0x4516a000}, {0x4516c000}, {0x4516e000}, 
+    {0x45170000}, {0x45172000}, {0x45174000}, {0x45176000}, 
+    {0x45178000}, {0x4517a000}, {0x4517c000}, {0x4517e000}, 
+    {0x45180000}, {0x45182000}, {0x45184000}, {0x45186000}, 
+    {0x45188000}, {0x4518a000}, {0x4518c000}, {0x4518e000}, 
+    {0x45190000}, {0x45192000}, {0x45194000}, {0x45196000}, 
+    {0x45198000}, {0x4519a000}, {0x4519c000}, {0x4519e000}, 
+    {0x451a0000}, {0x451a2000}, {0x451a4000}, {0x451a6000}, 
+    {0x451a8000}, {0x451aa000}, {0x451ac000}, {0x451ae000}, 
+    {0x451b0000}, {0x451b2000}, {0x451b4000}, {0x451b6000}, 
+    {0x451b8000}, {0x451ba000}, {0x451bc000}, {0x451be000}, 
+    {0x451c0000}, {0x451c2000}, {0x451c4000}, {0x451c6000}, 
+    {0x451c8000}, {0x451ca000}, {0x451cc000}, {0x451ce000}, 
+    {0x451d0000}, {0x451d2000}, {0x451d4000}, {0x451d6000}, 
+    {0x451d8000}, {0x451da000}, {0x451dc000}, {0x451de000}, 
+    {0x451e0000}, {0x451e2000}, {0x451e4000}, {0x451e6000}, 
+    {0x451e8000}, {0x451ea000}, {0x451ec000}, {0x451ee000}, 
+    {0x451f0000}, {0x451f2000}, {0x451f4000}, {0x451f6000}, 
+    {0x451f8000}, {0x451fa000}, {0x451fc000}, {0x451fe000}, 
+    {0x45200000}, {0x45202000}, {0x45204000}, {0x45206000}, 
+    {0x45208000}, {0x4520a000}, {0x4520c000}, {0x4520e000}, 
+    {0x45210000}, {0x45212000}, {0x45214000}, {0x45216000}, 
+    {0x45218000}, {0x4521a000}, {0x4521c000}, {0x4521e000}, 
+    {0x45220000}, {0x45222000}, {0x45224000}, {0x45226000}, 
+    {0x45228000}, {0x4522a000}, {0x4522c000}, {0x4522e000}, 
+    {0x45230000}, {0x45232000}, {0x45234000}, {0x45236000}, 
+    {0x45238000}, {0x4523a000}, {0x4523c000}, {0x4523e000}, 
+    {0x45240000}, {0x45242000}, {0x45244000}, {0x45246000}, 
+    {0x45248000}, {0x4524a000}, {0x4524c000}, {0x4524e000}, 
+    {0x45250000}, {0x45252000}, {0x45254000}, {0x45256000}, 
+    {0x45258000}, {0x4525a000}, {0x4525c000}, {0x4525e000}, 
+    {0x45260000}, {0x45262000}, {0x45264000}, {0x45266000}, 
+    {0x45268000}, {0x4526a000}, {0x4526c000}, {0x4526e000}, 
+    {0x45270000}, {0x45272000}, {0x45274000}, {0x45276000}, 
+    {0x45278000}, {0x4527a000}, {0x4527c000}, {0x4527e000}, 
+    {0x45280000}, {0x45282000}, {0x45284000}, {0x45286000}, 
+    {0x45288000}, {0x4528a000}, {0x4528c000}, {0x4528e000}, 
+    {0x45290000}, {0x45292000}, {0x45294000}, {0x45296000}, 
+    {0x45298000}, {0x4529a000}, {0x4529c000}, {0x4529e000}, 
+    {0x452a0000}, {0x452a2000}, {0x452a4000}, {0x452a6000}, 
+    {0x452a8000}, {0x452aa000}, {0x452ac000}, {0x452ae000}, 
+    {0x452b0000}, {0x452b2000}, {0x452b4000}, {0x452b6000}, 
+    {0x452b8000}, {0x452ba000}, {0x452bc000}, {0x452be000}, 
+    {0x452c0000}, {0x452c2000}, {0x452c4000}, {0x452c6000}, 
+    {0x452c8000}, {0x452ca000}, {0x452cc000}, {0x452ce000}, 
+    {0x452d0000}, {0x452d2000}, {0x452d4000}, {0x452d6000}, 
+    {0x452d8000}, {0x452da000}, {0x452dc000}, {0x452de000}, 
+    {0x452e0000}, {0x452e2000}, {0x452e4000}, {0x452e6000}, 
+    {0x452e8000}, {0x452ea000}, {0x452ec000}, {0x452ee000}, 
+    {0x452f0000}, {0x452f2000}, {0x452f4000}, {0x452f6000}, 
+    {0x452f8000}, {0x452fa000}, {0x452fc000}, {0x452fe000}, 
+    {0x45300000}, {0x45302000}, {0x45304000}, {0x45306000}, 
+    {0x45308000}, {0x4530a000}, {0x4530c000}, {0x4530e000}, 
+    {0x45310000}, {0x45312000}, {0x45314000}, {0x45316000}, 
+    {0x45318000}, {0x4531a000}, {0x4531c000}, {0x4531e000}, 
+    {0x45320000}, {0x45322000}, {0x45324000}, {0x45326000}, 
+    {0x45328000}, {0x4532a000}, {0x4532c000}, {0x4532e000}, 
+    {0x45330000}, {0x45332000}, {0x45334000}, {0x45336000}, 
+    {0x45338000}, {0x4533a000}, {0x4533c000}, {0x4533e000}, 
+    {0x45340000}, {0x45342000}, {0x45344000}, {0x45346000}, 
+    {0x45348000}, {0x4534a000}, {0x4534c000}, {0x4534e000}, 
+    {0x45350000}, {0x45352000}, {0x45354000}, {0x45356000}, 
+    {0x45358000}, {0x4535a000}, {0x4535c000}, {0x4535e000}, 
+    {0x45360000}, {0x45362000}, {0x45364000}, {0x45366000}, 
+    {0x45368000}, {0x4536a000}, {0x4536c000}, {0x4536e000}, 
+    {0x45370000}, {0x45372000}, {0x45374000}, {0x45376000}, 
+    {0x45378000}, {0x4537a000}, {0x4537c000}, {0x4537e000}, 
+    {0x45380000}, {0x45382000}, {0x45384000}, {0x45386000}, 
+    {0x45388000}, {0x4538a000}, {0x4538c000}, {0x4538e000}, 
+    {0x45390000}, {0x45392000}, {0x45394000}, {0x45396000}, 
+    {0x45398000}, {0x4539a000}, {0x4539c000}, {0x4539e000}, 
+    {0x453a0000}, {0x453a2000}, {0x453a4000}, {0x453a6000}, 
+    {0x453a8000}, {0x453aa000}, {0x453ac000}, {0x453ae000}, 
+    {0x453b0000}, {0x453b2000}, {0x453b4000}, {0x453b6000}, 
+    {0x453b8000}, {0x453ba000}, {0x453bc000}, {0x453be000}, 
+    {0x453c0000}, {0x453c2000}, {0x453c4000}, {0x453c6000}, 
+    {0x453c8000}, {0x453ca000}, {0x453cc000}, {0x453ce000}, 
+    {0x453d0000}, {0x453d2000}, {0x453d4000}, {0x453d6000}, 
+    {0x453d8000}, {0x453da000}, {0x453dc000}, {0x453de000}, 
+    {0x453e0000}, {0x453e2000}, {0x453e4000}, {0x453e6000}, 
+    {0x453e8000}, {0x453ea000}, {0x453ec000}, {0x453ee000}, 
+    {0x453f0000}, {0x453f2000}, {0x453f4000}, {0x453f6000}, 
+    {0x453f8000}, {0x453fa000}, {0x453fc000}, {0x453fe000}, 
+    {0x45400000}, {0x45402000}, {0x45404000}, {0x45406000}, 
+    {0x45408000}, {0x4540a000}, {0x4540c000}, {0x4540e000}, 
+    {0x45410000}, {0x45412000}, {0x45414000}, {0x45416000}, 
+    {0x45418000}, {0x4541a000}, {0x4541c000}, {0x4541e000}, 
+    {0x45420000}, {0x45422000}, {0x45424000}, {0x45426000}, 
+    {0x45428000}, {0x4542a000}, {0x4542c000}, {0x4542e000}, 
+    {0x45430000}, {0x45432000}, {0x45434000}, {0x45436000}, 
+    {0x45438000}, {0x4543a000}, {0x4543c000}, {0x4543e000}, 
+    {0x45440000}, {0x45442000}, {0x45444000}, {0x45446000}, 
+    {0x45448000}, {0x4544a000}, {0x4544c000}, {0x4544e000}, 
+    {0x45450000}, {0x45452000}, {0x45454000}, {0x45456000}, 
+    {0x45458000}, {0x4545a000}, {0x4545c000}, {0x4545e000}, 
+    {0x45460000}, {0x45462000}, {0x45464000}, {0x45466000}, 
+    {0x45468000}, {0x4546a000}, {0x4546c000}, {0x4546e000}, 
+    {0x45470000}, {0x45472000}, {0x45474000}, {0x45476000}, 
+    {0x45478000}, {0x4547a000}, {0x4547c000}, {0x4547e000}, 
+    {0x45480000}, {0x45482000}, {0x45484000}, {0x45486000}, 
+    {0x45488000}, {0x4548a000}, {0x4548c000}, {0x4548e000}, 
+    {0x45490000}, {0x45492000}, {0x45494000}, {0x45496000}, 
+    {0x45498000}, {0x4549a000}, {0x4549c000}, {0x4549e000}, 
+    {0x454a0000}, {0x454a2000}, {0x454a4000}, {0x454a6000}, 
+    {0x454a8000}, {0x454aa000}, {0x454ac000}, {0x454ae000}, 
+    {0x454b0000}, {0x454b2000}, {0x454b4000}, {0x454b6000}, 
+    {0x454b8000}, {0x454ba000}, {0x454bc000}, {0x454be000}, 
+    {0x454c0000}, {0x454c2000}, {0x454c4000}, {0x454c6000}, 
+    {0x454c8000}, {0x454ca000}, {0x454cc000}, {0x454ce000}, 
+    {0x454d0000}, {0x454d2000}, {0x454d4000}, {0x454d6000}, 
+    {0x454d8000}, {0x454da000}, {0x454dc000}, {0x454de000}, 
+    {0x454e0000}, {0x454e2000}, {0x454e4000}, {0x454e6000}, 
+    {0x454e8000}, {0x454ea000}, {0x454ec000}, {0x454ee000}, 
+    {0x454f0000}, {0x454f2000}, {0x454f4000}, {0x454f6000}, 
+    {0x454f8000}, {0x454fa000}, {0x454fc000}, {0x454fe000}, 
+    {0x45500000}, {0x45502000}, {0x45504000}, {0x45506000}, 
+    {0x45508000}, {0x4550a000}, {0x4550c000}, {0x4550e000}, 
+    {0x45510000}, {0x45512000}, {0x45514000}, {0x45516000}, 
+    {0x45518000}, {0x4551a000}, {0x4551c000}, {0x4551e000}, 
+    {0x45520000}, {0x45522000}, {0x45524000}, {0x45526000}, 
+    {0x45528000}, {0x4552a000}, {0x4552c000}, {0x4552e000}, 
+    {0x45530000}, {0x45532000}, {0x45534000}, {0x45536000}, 
+    {0x45538000}, {0x4553a000}, {0x4553c000}, {0x4553e000}, 
+    {0x45540000}, {0x45542000}, {0x45544000}, {0x45546000}, 
+    {0x45548000}, {0x4554a000}, {0x4554c000}, {0x4554e000}, 
+    {0x45550000}, {0x45552000}, {0x45554000}, {0x45556000}, 
+    {0x45558000}, {0x4555a000}, {0x4555c000}, {0x4555e000}, 
+    {0x45560000}, {0x45562000}, {0x45564000}, {0x45566000}, 
+    {0x45568000}, {0x4556a000}, {0x4556c000}, {0x4556e000}, 
+    {0x45570000}, {0x45572000}, {0x45574000}, {0x45576000}, 
+    {0x45578000}, {0x4557a000}, {0x4557c000}, {0x4557e000}, 
+    {0x45580000}, {0x45582000}, {0x45584000}, {0x45586000}, 
+    {0x45588000}, {0x4558a000}, {0x4558c000}, {0x4558e000}, 
+    {0x45590000}, {0x45592000}, {0x45594000}, {0x45596000}, 
+    {0x45598000}, {0x4559a000}, {0x4559c000}, {0x4559e000}, 
+    {0x455a0000}, {0x455a2000}, {0x455a4000}, {0x455a6000}, 
+    {0x455a8000}, {0x455aa000}, {0x455ac000}, {0x455ae000}, 
+    {0x455b0000}, {0x455b2000}, {0x455b4000}, {0x455b6000}, 
+    {0x455b8000}, {0x455ba000}, {0x455bc000}, {0x455be000}, 
+    {0x455c0000}, {0x455c2000}, {0x455c4000}, {0x455c6000}, 
+    {0x455c8000}, {0x455ca000}, {0x455cc000}, {0x455ce000}, 
+    {0x455d0000}, {0x455d2000}, {0x455d4000}, {0x455d6000}, 
+    {0x455d8000}, {0x455da000}, {0x455dc000}, {0x455de000}, 
+    {0x455e0000}, {0x455e2000}, {0x455e4000}, {0x455e6000}, 
+    {0x455e8000}, {0x455ea000}, {0x455ec000}, {0x455ee000}, 
+    {0x455f0000}, {0x455f2000}, {0x455f4000}, {0x455f6000}, 
+    {0x455f8000}, {0x455fa000}, {0x455fc000}, {0x455fe000}, 
+    {0x45600000}, {0x45602000}, {0x45604000}, {0x45606000}, 
+    {0x45608000}, {0x4560a000}, {0x4560c000}, {0x4560e000}, 
+    {0x45610000}, {0x45612000}, {0x45614000}, {0x45616000}, 
+    {0x45618000}, {0x4561a000}, {0x4561c000}, {0x4561e000}, 
+    {0x45620000}, {0x45622000}, {0x45624000}, {0x45626000}, 
+    {0x45628000}, {0x4562a000}, {0x4562c000}, {0x4562e000}, 
+    {0x45630000}, {0x45632000}, {0x45634000}, {0x45636000}, 
+    {0x45638000}, {0x4563a000}, {0x4563c000}, {0x4563e000}, 
+    {0x45640000}, {0x45642000}, {0x45644000}, {0x45646000}, 
+    {0x45648000}, {0x4564a000}, {0x4564c000}, {0x4564e000}, 
+    {0x45650000}, {0x45652000}, {0x45654000}, {0x45656000}, 
+    {0x45658000}, {0x4565a000}, {0x4565c000}, {0x4565e000}, 
+    {0x45660000}, {0x45662000}, {0x45664000}, {0x45666000}, 
+    {0x45668000}, {0x4566a000}, {0x4566c000}, {0x4566e000}, 
+    {0x45670000}, {0x45672000}, {0x45674000}, {0x45676000}, 
+    {0x45678000}, {0x4567a000}, {0x4567c000}, {0x4567e000}, 
+    {0x45680000}, {0x45682000}, {0x45684000}, {0x45686000}, 
+    {0x45688000}, {0x4568a000}, {0x4568c000}, {0x4568e000}, 
+    {0x45690000}, {0x45692000}, {0x45694000}, {0x45696000}, 
+    {0x45698000}, {0x4569a000}, {0x4569c000}, {0x4569e000}, 
+    {0x456a0000}, {0x456a2000}, {0x456a4000}, {0x456a6000}, 
+    {0x456a8000}, {0x456aa000}, {0x456ac000}, {0x456ae000}, 
+    {0x456b0000}, {0x456b2000}, {0x456b4000}, {0x456b6000}, 
+    {0x456b8000}, {0x456ba000}, {0x456bc000}, {0x456be000}, 
+    {0x456c0000}, {0x456c2000}, {0x456c4000}, {0x456c6000}, 
+    {0x456c8000}, {0x456ca000}, {0x456cc000}, {0x456ce000}, 
+    {0x456d0000}, {0x456d2000}, {0x456d4000}, {0x456d6000}, 
+    {0x456d8000}, {0x456da000}, {0x456dc000}, {0x456de000}, 
+    {0x456e0000}, {0x456e2000}, {0x456e4000}, {0x456e6000}, 
+    {0x456e8000}, {0x456ea000}, {0x456ec000}, {0x456ee000}, 
+    {0x456f0000}, {0x456f2000}, {0x456f4000}, {0x456f6000}, 
+    {0x456f8000}, {0x456fa000}, {0x456fc000}, {0x456fe000}, 
+    {0x45700000}, {0x45702000}, {0x45704000}, {0x45706000}, 
+    {0x45708000}, {0x4570a000}, {0x4570c000}, {0x4570e000}, 
+    {0x45710000}, {0x45712000}, {0x45714000}, {0x45716000}, 
+    {0x45718000}, {0x4571a000}, {0x4571c000}, {0x4571e000}, 
+    {0x45720000}, {0x45722000}, {0x45724000}, {0x45726000}, 
+    {0x45728000}, {0x4572a000}, {0x4572c000}, {0x4572e000}, 
+    {0x45730000}, {0x45732000}, {0x45734000}, {0x45736000}, 
+    {0x45738000}, {0x4573a000}, {0x4573c000}, {0x4573e000}, 
+    {0x45740000}, {0x45742000}, {0x45744000}, {0x45746000}, 
+    {0x45748000}, {0x4574a000}, {0x4574c000}, {0x4574e000}, 
+    {0x45750000}, {0x45752000}, {0x45754000}, {0x45756000}, 
+    {0x45758000}, {0x4575a000}, {0x4575c000}, {0x4575e000}, 
+    {0x45760000}, {0x45762000}, {0x45764000}, {0x45766000}, 
+    {0x45768000}, {0x4576a000}, {0x4576c000}, {0x4576e000}, 
+    {0x45770000}, {0x45772000}, {0x45774000}, {0x45776000}, 
+    {0x45778000}, {0x4577a000}, {0x4577c000}, {0x4577e000}, 
+    {0x45780000}, {0x45782000}, {0x45784000}, {0x45786000}, 
+    {0x45788000}, {0x4578a000}, {0x4578c000}, {0x4578e000}, 
+    {0x45790000}, {0x45792000}, {0x45794000}, {0x45796000}, 
+    {0x45798000}, {0x4579a000}, {0x4579c000}, {0x4579e000}, 
+    {0x457a0000}, {0x457a2000}, {0x457a4000}, {0x457a6000}, 
+    {0x457a8000}, {0x457aa000}, {0x457ac000}, {0x457ae000}, 
+    {0x457b0000}, {0x457b2000}, {0x457b4000}, {0x457b6000}, 
+    {0x457b8000}, {0x457ba000}, {0x457bc000}, {0x457be000}, 
+    {0x457c0000}, {0x457c2000}, {0x457c4000}, {0x457c6000}, 
+    {0x457c8000}, {0x457ca000}, {0x457cc000}, {0x457ce000}, 
+    {0x457d0000}, {0x457d2000}, {0x457d4000}, {0x457d6000}, 
+    {0x457d8000}, {0x457da000}, {0x457dc000}, {0x457de000}, 
+    {0x457e0000}, {0x457e2000}, {0x457e4000}, {0x457e6000}, 
+    {0x457e8000}, {0x457ea000}, {0x457ec000}, {0x457ee000}, 
+    {0x457f0000}, {0x457f2000}, {0x457f4000}, {0x457f6000}, 
+    {0x457f8000}, {0x457fa000}, {0x457fc000}, {0x457fe000}, 
+    {0x45800000}, {0x45802000}, {0x45804000}, {0x45806000}, 
+    {0x45808000}, {0x4580a000}, {0x4580c000}, {0x4580e000}, 
+    {0x45810000}, {0x45812000}, {0x45814000}, {0x45816000}, 
+    {0x45818000}, {0x4581a000}, {0x4581c000}, {0x4581e000}, 
+    {0x45820000}, {0x45822000}, {0x45824000}, {0x45826000}, 
+    {0x45828000}, {0x4582a000}, {0x4582c000}, {0x4582e000}, 
+    {0x45830000}, {0x45832000}, {0x45834000}, {0x45836000}, 
+    {0x45838000}, {0x4583a000}, {0x4583c000}, {0x4583e000}, 
+    {0x45840000}, {0x45842000}, {0x45844000}, {0x45846000}, 
+    {0x45848000}, {0x4584a000}, {0x4584c000}, {0x4584e000}, 
+    {0x45850000}, {0x45852000}, {0x45854000}, {0x45856000}, 
+    {0x45858000}, {0x4585a000}, {0x4585c000}, {0x4585e000}, 
+    {0x45860000}, {0x45862000}, {0x45864000}, {0x45866000}, 
+    {0x45868000}, {0x4586a000}, {0x4586c000}, {0x4586e000}, 
+    {0x45870000}, {0x45872000}, {0x45874000}, {0x45876000}, 
+    {0x45878000}, {0x4587a000}, {0x4587c000}, {0x4587e000}, 
+    {0x45880000}, {0x45882000}, {0x45884000}, {0x45886000}, 
+    {0x45888000}, {0x4588a000}, {0x4588c000}, {0x4588e000}, 
+    {0x45890000}, {0x45892000}, {0x45894000}, {0x45896000}, 
+    {0x45898000}, {0x4589a000}, {0x4589c000}, {0x4589e000}, 
+    {0x458a0000}, {0x458a2000}, {0x458a4000}, {0x458a6000}, 
+    {0x458a8000}, {0x458aa000}, {0x458ac000}, {0x458ae000}, 
+    {0x458b0000}, {0x458b2000}, {0x458b4000}, {0x458b6000}, 
+    {0x458b8000}, {0x458ba000}, {0x458bc000}, {0x458be000}, 
+    {0x458c0000}, {0x458c2000}, {0x458c4000}, {0x458c6000}, 
+    {0x458c8000}, {0x458ca000}, {0x458cc000}, {0x458ce000}, 
+    {0x458d0000}, {0x458d2000}, {0x458d4000}, {0x458d6000}, 
+    {0x458d8000}, {0x458da000}, {0x458dc000}, {0x458de000}, 
+    {0x458e0000}, {0x458e2000}, {0x458e4000}, {0x458e6000}, 
+    {0x458e8000}, {0x458ea000}, {0x458ec000}, {0x458ee000}, 
+    {0x458f0000}, {0x458f2000}, {0x458f4000}, {0x458f6000}, 
+    {0x458f8000}, {0x458fa000}, {0x458fc000}, {0x458fe000}, 
+    {0x45900000}, {0x45902000}, {0x45904000}, {0x45906000}, 
+    {0x45908000}, {0x4590a000}, {0x4590c000}, {0x4590e000}, 
+    {0x45910000}, {0x45912000}, {0x45914000}, {0x45916000}, 
+    {0x45918000}, {0x4591a000}, {0x4591c000}, {0x4591e000}, 
+    {0x45920000}, {0x45922000}, {0x45924000}, {0x45926000}, 
+    {0x45928000}, {0x4592a000}, {0x4592c000}, {0x4592e000}, 
+    {0x45930000}, {0x45932000}, {0x45934000}, {0x45936000}, 
+    {0x45938000}, {0x4593a000}, {0x4593c000}, {0x4593e000}, 
+    {0x45940000}, {0x45942000}, {0x45944000}, {0x45946000}, 
+    {0x45948000}, {0x4594a000}, {0x4594c000}, {0x4594e000}, 
+    {0x45950000}, {0x45952000}, {0x45954000}, {0x45956000}, 
+    {0x45958000}, {0x4595a000}, {0x4595c000}, {0x4595e000}, 
+    {0x45960000}, {0x45962000}, {0x45964000}, {0x45966000}, 
+    {0x45968000}, {0x4596a000}, {0x4596c000}, {0x4596e000}, 
+    {0x45970000}, {0x45972000}, {0x45974000}, {0x45976000}, 
+    {0x45978000}, {0x4597a000}, {0x4597c000}, {0x4597e000}, 
+    {0x45980000}, {0x45982000}, {0x45984000}, {0x45986000}, 
+    {0x45988000}, {0x4598a000}, {0x4598c000}, {0x4598e000}, 
+    {0x45990000}, {0x45992000}, {0x45994000}, {0x45996000}, 
+    {0x45998000}, {0x4599a000}, {0x4599c000}, {0x4599e000}, 
+    {0x459a0000}, {0x459a2000}, {0x459a4000}, {0x459a6000}, 
+    {0x459a8000}, {0x459aa000}, {0x459ac000}, {0x459ae000}, 
+    {0x459b0000}, {0x459b2000}, {0x459b4000}, {0x459b6000}, 
+    {0x459b8000}, {0x459ba000}, {0x459bc000}, {0x459be000}, 
+    {0x459c0000}, {0x459c2000}, {0x459c4000}, {0x459c6000}, 
+    {0x459c8000}, {0x459ca000}, {0x459cc000}, {0x459ce000}, 
+    {0x459d0000}, {0x459d2000}, {0x459d4000}, {0x459d6000}, 
+    {0x459d8000}, {0x459da000}, {0x459dc000}, {0x459de000}, 
+    {0x459e0000}, {0x459e2000}, {0x459e4000}, {0x459e6000}, 
+    {0x459e8000}, {0x459ea000}, {0x459ec000}, {0x459ee000}, 
+    {0x459f0000}, {0x459f2000}, {0x459f4000}, {0x459f6000}, 
+    {0x459f8000}, {0x459fa000}, {0x459fc000}, {0x459fe000}, 
+    {0x45a00000}, {0x45a02000}, {0x45a04000}, {0x45a06000}, 
+    {0x45a08000}, {0x45a0a000}, {0x45a0c000}, {0x45a0e000}, 
+    {0x45a10000}, {0x45a12000}, {0x45a14000}, {0x45a16000}, 
+    {0x45a18000}, {0x45a1a000}, {0x45a1c000}, {0x45a1e000}, 
+    {0x45a20000}, {0x45a22000}, {0x45a24000}, {0x45a26000}, 
+    {0x45a28000}, {0x45a2a000}, {0x45a2c000}, {0x45a2e000}, 
+    {0x45a30000}, {0x45a32000}, {0x45a34000}, {0x45a36000}, 
+    {0x45a38000}, {0x45a3a000}, {0x45a3c000}, {0x45a3e000}, 
+    {0x45a40000}, {0x45a42000}, {0x45a44000}, {0x45a46000}, 
+    {0x45a48000}, {0x45a4a000}, {0x45a4c000}, {0x45a4e000}, 
+    {0x45a50000}, {0x45a52000}, {0x45a54000}, {0x45a56000}, 
+    {0x45a58000}, {0x45a5a000}, {0x45a5c000}, {0x45a5e000}, 
+    {0x45a60000}, {0x45a62000}, {0x45a64000}, {0x45a66000}, 
+    {0x45a68000}, {0x45a6a000}, {0x45a6c000}, {0x45a6e000}, 
+    {0x45a70000}, {0x45a72000}, {0x45a74000}, {0x45a76000}, 
+    {0x45a78000}, {0x45a7a000}, {0x45a7c000}, {0x45a7e000}, 
+    {0x45a80000}, {0x45a82000}, {0x45a84000}, {0x45a86000}, 
+    {0x45a88000}, {0x45a8a000}, {0x45a8c000}, {0x45a8e000}, 
+    {0x45a90000}, {0x45a92000}, {0x45a94000}, {0x45a96000}, 
+    {0x45a98000}, {0x45a9a000}, {0x45a9c000}, {0x45a9e000}, 
+    {0x45aa0000}, {0x45aa2000}, {0x45aa4000}, {0x45aa6000}, 
+    {0x45aa8000}, {0x45aaa000}, {0x45aac000}, {0x45aae000}, 
+    {0x45ab0000}, {0x45ab2000}, {0x45ab4000}, {0x45ab6000}, 
+    {0x45ab8000}, {0x45aba000}, {0x45abc000}, {0x45abe000}, 
+    {0x45ac0000}, {0x45ac2000}, {0x45ac4000}, {0x45ac6000}, 
+    {0x45ac8000}, {0x45aca000}, {0x45acc000}, {0x45ace000}, 
+    {0x45ad0000}, {0x45ad2000}, {0x45ad4000}, {0x45ad6000}, 
+    {0x45ad8000}, {0x45ada000}, {0x45adc000}, {0x45ade000}, 
+    {0x45ae0000}, {0x45ae2000}, {0x45ae4000}, {0x45ae6000}, 
+    {0x45ae8000}, {0x45aea000}, {0x45aec000}, {0x45aee000}, 
+    {0x45af0000}, {0x45af2000}, {0x45af4000}, {0x45af6000}, 
+    {0x45af8000}, {0x45afa000}, {0x45afc000}, {0x45afe000}, 
+    {0x45b00000}, {0x45b02000}, {0x45b04000}, {0x45b06000}, 
+    {0x45b08000}, {0x45b0a000}, {0x45b0c000}, {0x45b0e000}, 
+    {0x45b10000}, {0x45b12000}, {0x45b14000}, {0x45b16000}, 
+    {0x45b18000}, {0x45b1a000}, {0x45b1c000}, {0x45b1e000}, 
+    {0x45b20000}, {0x45b22000}, {0x45b24000}, {0x45b26000}, 
+    {0x45b28000}, {0x45b2a000}, {0x45b2c000}, {0x45b2e000}, 
+    {0x45b30000}, {0x45b32000}, {0x45b34000}, {0x45b36000}, 
+    {0x45b38000}, {0x45b3a000}, {0x45b3c000}, {0x45b3e000}, 
+    {0x45b40000}, {0x45b42000}, {0x45b44000}, {0x45b46000}, 
+    {0x45b48000}, {0x45b4a000}, {0x45b4c000}, {0x45b4e000}, 
+    {0x45b50000}, {0x45b52000}, {0x45b54000}, {0x45b56000}, 
+    {0x45b58000}, {0x45b5a000}, {0x45b5c000}, {0x45b5e000}, 
+    {0x45b60000}, {0x45b62000}, {0x45b64000}, {0x45b66000}, 
+    {0x45b68000}, {0x45b6a000}, {0x45b6c000}, {0x45b6e000}, 
+    {0x45b70000}, {0x45b72000}, {0x45b74000}, {0x45b76000}, 
+    {0x45b78000}, {0x45b7a000}, {0x45b7c000}, {0x45b7e000}, 
+    {0x45b80000}, {0x45b82000}, {0x45b84000}, {0x45b86000}, 
+    {0x45b88000}, {0x45b8a000}, {0x45b8c000}, {0x45b8e000}, 
+    {0x45b90000}, {0x45b92000}, {0x45b94000}, {0x45b96000}, 
+    {0x45b98000}, {0x45b9a000}, {0x45b9c000}, {0x45b9e000}, 
+    {0x45ba0000}, {0x45ba2000}, {0x45ba4000}, {0x45ba6000}, 
+    {0x45ba8000}, {0x45baa000}, {0x45bac000}, {0x45bae000}, 
+    {0x45bb0000}, {0x45bb2000}, {0x45bb4000}, {0x45bb6000}, 
+    {0x45bb8000}, {0x45bba000}, {0x45bbc000}, {0x45bbe000}, 
+    {0x45bc0000}, {0x45bc2000}, {0x45bc4000}, {0x45bc6000}, 
+    {0x45bc8000}, {0x45bca000}, {0x45bcc000}, {0x45bce000}, 
+    {0x45bd0000}, {0x45bd2000}, {0x45bd4000}, {0x45bd6000}, 
+    {0x45bd8000}, {0x45bda000}, {0x45bdc000}, {0x45bde000}, 
+    {0x45be0000}, {0x45be2000}, {0x45be4000}, {0x45be6000}, 
+    {0x45be8000}, {0x45bea000}, {0x45bec000}, {0x45bee000}, 
+    {0x45bf0000}, {0x45bf2000}, {0x45bf4000}, {0x45bf6000}, 
+    {0x45bf8000}, {0x45bfa000}, {0x45bfc000}, {0x45bfe000}, 
+    {0x45c00000}, {0x45c02000}, {0x45c04000}, {0x45c06000}, 
+    {0x45c08000}, {0x45c0a000}, {0x45c0c000}, {0x45c0e000}, 
+    {0x45c10000}, {0x45c12000}, {0x45c14000}, {0x45c16000}, 
+    {0x45c18000}, {0x45c1a000}, {0x45c1c000}, {0x45c1e000}, 
+    {0x45c20000}, {0x45c22000}, {0x45c24000}, {0x45c26000}, 
+    {0x45c28000}, {0x45c2a000}, {0x45c2c000}, {0x45c2e000}, 
+    {0x45c30000}, {0x45c32000}, {0x45c34000}, {0x45c36000}, 
+    {0x45c38000}, {0x45c3a000}, {0x45c3c000}, {0x45c3e000}, 
+    {0x45c40000}, {0x45c42000}, {0x45c44000}, {0x45c46000}, 
+    {0x45c48000}, {0x45c4a000}, {0x45c4c000}, {0x45c4e000}, 
+    {0x45c50000}, {0x45c52000}, {0x45c54000}, {0x45c56000}, 
+    {0x45c58000}, {0x45c5a000}, {0x45c5c000}, {0x45c5e000}, 
+    {0x45c60000}, {0x45c62000}, {0x45c64000}, {0x45c66000}, 
+    {0x45c68000}, {0x45c6a000}, {0x45c6c000}, {0x45c6e000}, 
+    {0x45c70000}, {0x45c72000}, {0x45c74000}, {0x45c76000}, 
+    {0x45c78000}, {0x45c7a000}, {0x45c7c000}, {0x45c7e000}, 
+    {0x45c80000}, {0x45c82000}, {0x45c84000}, {0x45c86000}, 
+    {0x45c88000}, {0x45c8a000}, {0x45c8c000}, {0x45c8e000}, 
+    {0x45c90000}, {0x45c92000}, {0x45c94000}, {0x45c96000}, 
+    {0x45c98000}, {0x45c9a000}, {0x45c9c000}, {0x45c9e000}, 
+    {0x45ca0000}, {0x45ca2000}, {0x45ca4000}, {0x45ca6000}, 
+    {0x45ca8000}, {0x45caa000}, {0x45cac000}, {0x45cae000}, 
+    {0x45cb0000}, {0x45cb2000}, {0x45cb4000}, {0x45cb6000}, 
+    {0x45cb8000}, {0x45cba000}, {0x45cbc000}, {0x45cbe000}, 
+    {0x45cc0000}, {0x45cc2000}, {0x45cc4000}, {0x45cc6000}, 
+    {0x45cc8000}, {0x45cca000}, {0x45ccc000}, {0x45cce000}, 
+    {0x45cd0000}, {0x45cd2000}, {0x45cd4000}, {0x45cd6000}, 
+    {0x45cd8000}, {0x45cda000}, {0x45cdc000}, {0x45cde000}, 
+    {0x45ce0000}, {0x45ce2000}, {0x45ce4000}, {0x45ce6000}, 
+    {0x45ce8000}, {0x45cea000}, {0x45cec000}, {0x45cee000}, 
+    {0x45cf0000}, {0x45cf2000}, {0x45cf4000}, {0x45cf6000}, 
+    {0x45cf8000}, {0x45cfa000}, {0x45cfc000}, {0x45cfe000}, 
+    {0x45d00000}, {0x45d02000}, {0x45d04000}, {0x45d06000}, 
+    {0x45d08000}, {0x45d0a000}, {0x45d0c000}, {0x45d0e000}, 
+    {0x45d10000}, {0x45d12000}, {0x45d14000}, {0x45d16000}, 
+    {0x45d18000}, {0x45d1a000}, {0x45d1c000}, {0x45d1e000}, 
+    {0x45d20000}, {0x45d22000}, {0x45d24000}, {0x45d26000}, 
+    {0x45d28000}, {0x45d2a000}, {0x45d2c000}, {0x45d2e000}, 
+    {0x45d30000}, {0x45d32000}, {0x45d34000}, {0x45d36000}, 
+    {0x45d38000}, {0x45d3a000}, {0x45d3c000}, {0x45d3e000}, 
+    {0x45d40000}, {0x45d42000}, {0x45d44000}, {0x45d46000}, 
+    {0x45d48000}, {0x45d4a000}, {0x45d4c000}, {0x45d4e000}, 
+    {0x45d50000}, {0x45d52000}, {0x45d54000}, {0x45d56000}, 
+    {0x45d58000}, {0x45d5a000}, {0x45d5c000}, {0x45d5e000}, 
+    {0x45d60000}, {0x45d62000}, {0x45d64000}, {0x45d66000}, 
+    {0x45d68000}, {0x45d6a000}, {0x45d6c000}, {0x45d6e000}, 
+    {0x45d70000}, {0x45d72000}, {0x45d74000}, {0x45d76000}, 
+    {0x45d78000}, {0x45d7a000}, {0x45d7c000}, {0x45d7e000}, 
+    {0x45d80000}, {0x45d82000}, {0x45d84000}, {0x45d86000}, 
+    {0x45d88000}, {0x45d8a000}, {0x45d8c000}, {0x45d8e000}, 
+    {0x45d90000}, {0x45d92000}, {0x45d94000}, {0x45d96000}, 
+    {0x45d98000}, {0x45d9a000}, {0x45d9c000}, {0x45d9e000}, 
+    {0x45da0000}, {0x45da2000}, {0x45da4000}, {0x45da6000}, 
+    {0x45da8000}, {0x45daa000}, {0x45dac000}, {0x45dae000}, 
+    {0x45db0000}, {0x45db2000}, {0x45db4000}, {0x45db6000}, 
+    {0x45db8000}, {0x45dba000}, {0x45dbc000}, {0x45dbe000}, 
+    {0x45dc0000}, {0x45dc2000}, {0x45dc4000}, {0x45dc6000}, 
+    {0x45dc8000}, {0x45dca000}, {0x45dcc000}, {0x45dce000}, 
+    {0x45dd0000}, {0x45dd2000}, {0x45dd4000}, {0x45dd6000}, 
+    {0x45dd8000}, {0x45dda000}, {0x45ddc000}, {0x45dde000}, 
+    {0x45de0000}, {0x45de2000}, {0x45de4000}, {0x45de6000}, 
+    {0x45de8000}, {0x45dea000}, {0x45dec000}, {0x45dee000}, 
+    {0x45df0000}, {0x45df2000}, {0x45df4000}, {0x45df6000}, 
+    {0x45df8000}, {0x45dfa000}, {0x45dfc000}, {0x45dfe000}, 
+    {0x45e00000}, {0x45e02000}, {0x45e04000}, {0x45e06000}, 
+    {0x45e08000}, {0x45e0a000}, {0x45e0c000}, {0x45e0e000}, 
+    {0x45e10000}, {0x45e12000}, {0x45e14000}, {0x45e16000}, 
+    {0x45e18000}, {0x45e1a000}, {0x45e1c000}, {0x45e1e000}, 
+    {0x45e20000}, {0x45e22000}, {0x45e24000}, {0x45e26000}, 
+    {0x45e28000}, {0x45e2a000}, {0x45e2c000}, {0x45e2e000}, 
+    {0x45e30000}, {0x45e32000}, {0x45e34000}, {0x45e36000}, 
+    {0x45e38000}, {0x45e3a000}, {0x45e3c000}, {0x45e3e000}, 
+    {0x45e40000}, {0x45e42000}, {0x45e44000}, {0x45e46000}, 
+    {0x45e48000}, {0x45e4a000}, {0x45e4c000}, {0x45e4e000}, 
+    {0x45e50000}, {0x45e52000}, {0x45e54000}, {0x45e56000}, 
+    {0x45e58000}, {0x45e5a000}, {0x45e5c000}, {0x45e5e000}, 
+    {0x45e60000}, {0x45e62000}, {0x45e64000}, {0x45e66000}, 
+    {0x45e68000}, {0x45e6a000}, {0x45e6c000}, {0x45e6e000}, 
+    {0x45e70000}, {0x45e72000}, {0x45e74000}, {0x45e76000}, 
+    {0x45e78000}, {0x45e7a000}, {0x45e7c000}, {0x45e7e000}, 
+    {0x45e80000}, {0x45e82000}, {0x45e84000}, {0x45e86000}, 
+    {0x45e88000}, {0x45e8a000}, {0x45e8c000}, {0x45e8e000}, 
+    {0x45e90000}, {0x45e92000}, {0x45e94000}, {0x45e96000}, 
+    {0x45e98000}, {0x45e9a000}, {0x45e9c000}, {0x45e9e000}, 
+    {0x45ea0000}, {0x45ea2000}, {0x45ea4000}, {0x45ea6000}, 
+    {0x45ea8000}, {0x45eaa000}, {0x45eac000}, {0x45eae000}, 
+    {0x45eb0000}, {0x45eb2000}, {0x45eb4000}, {0x45eb6000}, 
+    {0x45eb8000}, {0x45eba000}, {0x45ebc000}, {0x45ebe000}, 
+    {0x45ec0000}, {0x45ec2000}, {0x45ec4000}, {0x45ec6000}, 
+    {0x45ec8000}, {0x45eca000}, {0x45ecc000}, {0x45ece000}, 
+    {0x45ed0000}, {0x45ed2000}, {0x45ed4000}, {0x45ed6000}, 
+    {0x45ed8000}, {0x45eda000}, {0x45edc000}, {0x45ede000}, 
+    {0x45ee0000}, {0x45ee2000}, {0x45ee4000}, {0x45ee6000}, 
+    {0x45ee8000}, {0x45eea000}, {0x45eec000}, {0x45eee000}, 
+    {0x45ef0000}, {0x45ef2000}, {0x45ef4000}, {0x45ef6000}, 
+    {0x45ef8000}, {0x45efa000}, {0x45efc000}, {0x45efe000}, 
+    {0x45f00000}, {0x45f02000}, {0x45f04000}, {0x45f06000}, 
+    {0x45f08000}, {0x45f0a000}, {0x45f0c000}, {0x45f0e000}, 
+    {0x45f10000}, {0x45f12000}, {0x45f14000}, {0x45f16000}, 
+    {0x45f18000}, {0x45f1a000}, {0x45f1c000}, {0x45f1e000}, 
+    {0x45f20000}, {0x45f22000}, {0x45f24000}, {0x45f26000}, 
+    {0x45f28000}, {0x45f2a000}, {0x45f2c000}, {0x45f2e000}, 
+    {0x45f30000}, {0x45f32000}, {0x45f34000}, {0x45f36000}, 
+    {0x45f38000}, {0x45f3a000}, {0x45f3c000}, {0x45f3e000}, 
+    {0x45f40000}, {0x45f42000}, {0x45f44000}, {0x45f46000}, 
+    {0x45f48000}, {0x45f4a000}, {0x45f4c000}, {0x45f4e000}, 
+    {0x45f50000}, {0x45f52000}, {0x45f54000}, {0x45f56000}, 
+    {0x45f58000}, {0x45f5a000}, {0x45f5c000}, {0x45f5e000}, 
+    {0x45f60000}, {0x45f62000}, {0x45f64000}, {0x45f66000}, 
+    {0x45f68000}, {0x45f6a000}, {0x45f6c000}, {0x45f6e000}, 
+    {0x45f70000}, {0x45f72000}, {0x45f74000}, {0x45f76000}, 
+    {0x45f78000}, {0x45f7a000}, {0x45f7c000}, {0x45f7e000}, 
+    {0x45f80000}, {0x45f82000}, {0x45f84000}, {0x45f86000}, 
+    {0x45f88000}, {0x45f8a000}, {0x45f8c000}, {0x45f8e000}, 
+    {0x45f90000}, {0x45f92000}, {0x45f94000}, {0x45f96000}, 
+    {0x45f98000}, {0x45f9a000}, {0x45f9c000}, {0x45f9e000}, 
+    {0x45fa0000}, {0x45fa2000}, {0x45fa4000}, {0x45fa6000}, 
+    {0x45fa8000}, {0x45faa000}, {0x45fac000}, {0x45fae000}, 
+    {0x45fb0000}, {0x45fb2000}, {0x45fb4000}, {0x45fb6000}, 
+    {0x45fb8000}, {0x45fba000}, {0x45fbc000}, {0x45fbe000}, 
+    {0x45fc0000}, {0x45fc2000}, {0x45fc4000}, {0x45fc6000}, 
+    {0x45fc8000}, {0x45fca000}, {0x45fcc000}, {0x45fce000}, 
+    {0x45fd0000}, {0x45fd2000}, {0x45fd4000}, {0x45fd6000}, 
+    {0x45fd8000}, {0x45fda000}, {0x45fdc000}, {0x45fde000}, 
+    {0x45fe0000}, {0x45fe2000}, {0x45fe4000}, {0x45fe6000}, 
+    {0x45fe8000}, {0x45fea000}, {0x45fec000}, {0x45fee000}, 
+    {0x45ff0000}, {0x45ff2000}, {0x45ff4000}, {0x45ff6000}, 
+    {0x45ff8000}, {0x45ffa000}, {0x45ffc000}, {0x45ffe000}, 
+    {0x46000000}, {0x46002000}, {0x46004000}, {0x46006000}, 
+    {0x46008000}, {0x4600a000}, {0x4600c000}, {0x4600e000}, 
+    {0x46010000}, {0x46012000}, {0x46014000}, {0x46016000}, 
+    {0x46018000}, {0x4601a000}, {0x4601c000}, {0x4601e000}, 
+    {0x46020000}, {0x46022000}, {0x46024000}, {0x46026000}, 
+    {0x46028000}, {0x4602a000}, {0x4602c000}, {0x4602e000}, 
+    {0x46030000}, {0x46032000}, {0x46034000}, {0x46036000}, 
+    {0x46038000}, {0x4603a000}, {0x4603c000}, {0x4603e000}, 
+    {0x46040000}, {0x46042000}, {0x46044000}, {0x46046000}, 
+    {0x46048000}, {0x4604a000}, {0x4604c000}, {0x4604e000}, 
+    {0x46050000}, {0x46052000}, {0x46054000}, {0x46056000}, 
+    {0x46058000}, {0x4605a000}, {0x4605c000}, {0x4605e000}, 
+    {0x46060000}, {0x46062000}, {0x46064000}, {0x46066000}, 
+    {0x46068000}, {0x4606a000}, {0x4606c000}, {0x4606e000}, 
+    {0x46070000}, {0x46072000}, {0x46074000}, {0x46076000}, 
+    {0x46078000}, {0x4607a000}, {0x4607c000}, {0x4607e000}, 
+    {0x46080000}, {0x46082000}, {0x46084000}, {0x46086000}, 
+    {0x46088000}, {0x4608a000}, {0x4608c000}, {0x4608e000}, 
+    {0x46090000}, {0x46092000}, {0x46094000}, {0x46096000}, 
+    {0x46098000}, {0x4609a000}, {0x4609c000}, {0x4609e000}, 
+    {0x460a0000}, {0x460a2000}, {0x460a4000}, {0x460a6000}, 
+    {0x460a8000}, {0x460aa000}, {0x460ac000}, {0x460ae000}, 
+    {0x460b0000}, {0x460b2000}, {0x460b4000}, {0x460b6000}, 
+    {0x460b8000}, {0x460ba000}, {0x460bc000}, {0x460be000}, 
+    {0x460c0000}, {0x460c2000}, {0x460c4000}, {0x460c6000}, 
+    {0x460c8000}, {0x460ca000}, {0x460cc000}, {0x460ce000}, 
+    {0x460d0000}, {0x460d2000}, {0x460d4000}, {0x460d6000}, 
+    {0x460d8000}, {0x460da000}, {0x460dc000}, {0x460de000}, 
+    {0x460e0000}, {0x460e2000}, {0x460e4000}, {0x460e6000}, 
+    {0x460e8000}, {0x460ea000}, {0x460ec000}, {0x460ee000}, 
+    {0x460f0000}, {0x460f2000}, {0x460f4000}, {0x460f6000}, 
+    {0x460f8000}, {0x460fa000}, {0x460fc000}, {0x460fe000}, 
+    {0x46100000}, {0x46102000}, {0x46104000}, {0x46106000}, 
+    {0x46108000}, {0x4610a000}, {0x4610c000}, {0x4610e000}, 
+    {0x46110000}, {0x46112000}, {0x46114000}, {0x46116000}, 
+    {0x46118000}, {0x4611a000}, {0x4611c000}, {0x4611e000}, 
+    {0x46120000}, {0x46122000}, {0x46124000}, {0x46126000}, 
+    {0x46128000}, {0x4612a000}, {0x4612c000}, {0x4612e000}, 
+    {0x46130000}, {0x46132000}, {0x46134000}, {0x46136000}, 
+    {0x46138000}, {0x4613a000}, {0x4613c000}, {0x4613e000}, 
+    {0x46140000}, {0x46142000}, {0x46144000}, {0x46146000}, 
+    {0x46148000}, {0x4614a000}, {0x4614c000}, {0x4614e000}, 
+    {0x46150000}, {0x46152000}, {0x46154000}, {0x46156000}, 
+    {0x46158000}, {0x4615a000}, {0x4615c000}, {0x4615e000}, 
+    {0x46160000}, {0x46162000}, {0x46164000}, {0x46166000}, 
+    {0x46168000}, {0x4616a000}, {0x4616c000}, {0x4616e000}, 
+    {0x46170000}, {0x46172000}, {0x46174000}, {0x46176000}, 
+    {0x46178000}, {0x4617a000}, {0x4617c000}, {0x4617e000}, 
+    {0x46180000}, {0x46182000}, {0x46184000}, {0x46186000}, 
+    {0x46188000}, {0x4618a000}, {0x4618c000}, {0x4618e000}, 
+    {0x46190000}, {0x46192000}, {0x46194000}, {0x46196000}, 
+    {0x46198000}, {0x4619a000}, {0x4619c000}, {0x4619e000}, 
+    {0x461a0000}, {0x461a2000}, {0x461a4000}, {0x461a6000}, 
+    {0x461a8000}, {0x461aa000}, {0x461ac000}, {0x461ae000}, 
+    {0x461b0000}, {0x461b2000}, {0x461b4000}, {0x461b6000}, 
+    {0x461b8000}, {0x461ba000}, {0x461bc000}, {0x461be000}, 
+    {0x461c0000}, {0x461c2000}, {0x461c4000}, {0x461c6000}, 
+    {0x461c8000}, {0x461ca000}, {0x461cc000}, {0x461ce000}, 
+    {0x461d0000}, {0x461d2000}, {0x461d4000}, {0x461d6000}, 
+    {0x461d8000}, {0x461da000}, {0x461dc000}, {0x461de000}, 
+    {0x461e0000}, {0x461e2000}, {0x461e4000}, {0x461e6000}, 
+    {0x461e8000}, {0x461ea000}, {0x461ec000}, {0x461ee000}, 
+    {0x461f0000}, {0x461f2000}, {0x461f4000}, {0x461f6000}, 
+    {0x461f8000}, {0x461fa000}, {0x461fc000}, {0x461fe000}, 
+    {0x46200000}, {0x46202000}, {0x46204000}, {0x46206000}, 
+    {0x46208000}, {0x4620a000}, {0x4620c000}, {0x4620e000}, 
+    {0x46210000}, {0x46212000}, {0x46214000}, {0x46216000}, 
+    {0x46218000}, {0x4621a000}, {0x4621c000}, {0x4621e000}, 
+    {0x46220000}, {0x46222000}, {0x46224000}, {0x46226000}, 
+    {0x46228000}, {0x4622a000}, {0x4622c000}, {0x4622e000}, 
+    {0x46230000}, {0x46232000}, {0x46234000}, {0x46236000}, 
+    {0x46238000}, {0x4623a000}, {0x4623c000}, {0x4623e000}, 
+    {0x46240000}, {0x46242000}, {0x46244000}, {0x46246000}, 
+    {0x46248000}, {0x4624a000}, {0x4624c000}, {0x4624e000}, 
+    {0x46250000}, {0x46252000}, {0x46254000}, {0x46256000}, 
+    {0x46258000}, {0x4625a000}, {0x4625c000}, {0x4625e000}, 
+    {0x46260000}, {0x46262000}, {0x46264000}, {0x46266000}, 
+    {0x46268000}, {0x4626a000}, {0x4626c000}, {0x4626e000}, 
+    {0x46270000}, {0x46272000}, {0x46274000}, {0x46276000}, 
+    {0x46278000}, {0x4627a000}, {0x4627c000}, {0x4627e000}, 
+    {0x46280000}, {0x46282000}, {0x46284000}, {0x46286000}, 
+    {0x46288000}, {0x4628a000}, {0x4628c000}, {0x4628e000}, 
+    {0x46290000}, {0x46292000}, {0x46294000}, {0x46296000}, 
+    {0x46298000}, {0x4629a000}, {0x4629c000}, {0x4629e000}, 
+    {0x462a0000}, {0x462a2000}, {0x462a4000}, {0x462a6000}, 
+    {0x462a8000}, {0x462aa000}, {0x462ac000}, {0x462ae000}, 
+    {0x462b0000}, {0x462b2000}, {0x462b4000}, {0x462b6000}, 
+    {0x462b8000}, {0x462ba000}, {0x462bc000}, {0x462be000}, 
+    {0x462c0000}, {0x462c2000}, {0x462c4000}, {0x462c6000}, 
+    {0x462c8000}, {0x462ca000}, {0x462cc000}, {0x462ce000}, 
+    {0x462d0000}, {0x462d2000}, {0x462d4000}, {0x462d6000}, 
+    {0x462d8000}, {0x462da000}, {0x462dc000}, {0x462de000}, 
+    {0x462e0000}, {0x462e2000}, {0x462e4000}, {0x462e6000}, 
+    {0x462e8000}, {0x462ea000}, {0x462ec000}, {0x462ee000}, 
+    {0x462f0000}, {0x462f2000}, {0x462f4000}, {0x462f6000}, 
+    {0x462f8000}, {0x462fa000}, {0x462fc000}, {0x462fe000}, 
+    {0x46300000}, {0x46302000}, {0x46304000}, {0x46306000}, 
+    {0x46308000}, {0x4630a000}, {0x4630c000}, {0x4630e000}, 
+    {0x46310000}, {0x46312000}, {0x46314000}, {0x46316000}, 
+    {0x46318000}, {0x4631a000}, {0x4631c000}, {0x4631e000}, 
+    {0x46320000}, {0x46322000}, {0x46324000}, {0x46326000}, 
+    {0x46328000}, {0x4632a000}, {0x4632c000}, {0x4632e000}, 
+    {0x46330000}, {0x46332000}, {0x46334000}, {0x46336000}, 
+    {0x46338000}, {0x4633a000}, {0x4633c000}, {0x4633e000}, 
+    {0x46340000}, {0x46342000}, {0x46344000}, {0x46346000}, 
+    {0x46348000}, {0x4634a000}, {0x4634c000}, {0x4634e000}, 
+    {0x46350000}, {0x46352000}, {0x46354000}, {0x46356000}, 
+    {0x46358000}, {0x4635a000}, {0x4635c000}, {0x4635e000}, 
+    {0x46360000}, {0x46362000}, {0x46364000}, {0x46366000}, 
+    {0x46368000}, {0x4636a000}, {0x4636c000}, {0x4636e000}, 
+    {0x46370000}, {0x46372000}, {0x46374000}, {0x46376000}, 
+    {0x46378000}, {0x4637a000}, {0x4637c000}, {0x4637e000}, 
+    {0x46380000}, {0x46382000}, {0x46384000}, {0x46386000}, 
+    {0x46388000}, {0x4638a000}, {0x4638c000}, {0x4638e000}, 
+    {0x46390000}, {0x46392000}, {0x46394000}, {0x46396000}, 
+    {0x46398000}, {0x4639a000}, {0x4639c000}, {0x4639e000}, 
+    {0x463a0000}, {0x463a2000}, {0x463a4000}, {0x463a6000}, 
+    {0x463a8000}, {0x463aa000}, {0x463ac000}, {0x463ae000}, 
+    {0x463b0000}, {0x463b2000}, {0x463b4000}, {0x463b6000}, 
+    {0x463b8000}, {0x463ba000}, {0x463bc000}, {0x463be000}, 
+    {0x463c0000}, {0x463c2000}, {0x463c4000}, {0x463c6000}, 
+    {0x463c8000}, {0x463ca000}, {0x463cc000}, {0x463ce000}, 
+    {0x463d0000}, {0x463d2000}, {0x463d4000}, {0x463d6000}, 
+    {0x463d8000}, {0x463da000}, {0x463dc000}, {0x463de000}, 
+    {0x463e0000}, {0x463e2000}, {0x463e4000}, {0x463e6000}, 
+    {0x463e8000}, {0x463ea000}, {0x463ec000}, {0x463ee000}, 
+    {0x463f0000}, {0x463f2000}, {0x463f4000}, {0x463f6000}, 
+    {0x463f8000}, {0x463fa000}, {0x463fc000}, {0x463fe000}, 
+    {0x46400000}, {0x46402000}, {0x46404000}, {0x46406000}, 
+    {0x46408000}, {0x4640a000}, {0x4640c000}, {0x4640e000}, 
+    {0x46410000}, {0x46412000}, {0x46414000}, {0x46416000}, 
+    {0x46418000}, {0x4641a000}, {0x4641c000}, {0x4641e000}, 
+    {0x46420000}, {0x46422000}, {0x46424000}, {0x46426000}, 
+    {0x46428000}, {0x4642a000}, {0x4642c000}, {0x4642e000}, 
+    {0x46430000}, {0x46432000}, {0x46434000}, {0x46436000}, 
+    {0x46438000}, {0x4643a000}, {0x4643c000}, {0x4643e000}, 
+    {0x46440000}, {0x46442000}, {0x46444000}, {0x46446000}, 
+    {0x46448000}, {0x4644a000}, {0x4644c000}, {0x4644e000}, 
+    {0x46450000}, {0x46452000}, {0x46454000}, {0x46456000}, 
+    {0x46458000}, {0x4645a000}, {0x4645c000}, {0x4645e000}, 
+    {0x46460000}, {0x46462000}, {0x46464000}, {0x46466000}, 
+    {0x46468000}, {0x4646a000}, {0x4646c000}, {0x4646e000}, 
+    {0x46470000}, {0x46472000}, {0x46474000}, {0x46476000}, 
+    {0x46478000}, {0x4647a000}, {0x4647c000}, {0x4647e000}, 
+    {0x46480000}, {0x46482000}, {0x46484000}, {0x46486000}, 
+    {0x46488000}, {0x4648a000}, {0x4648c000}, {0x4648e000}, 
+    {0x46490000}, {0x46492000}, {0x46494000}, {0x46496000}, 
+    {0x46498000}, {0x4649a000}, {0x4649c000}, {0x4649e000}, 
+    {0x464a0000}, {0x464a2000}, {0x464a4000}, {0x464a6000}, 
+    {0x464a8000}, {0x464aa000}, {0x464ac000}, {0x464ae000}, 
+    {0x464b0000}, {0x464b2000}, {0x464b4000}, {0x464b6000}, 
+    {0x464b8000}, {0x464ba000}, {0x464bc000}, {0x464be000}, 
+    {0x464c0000}, {0x464c2000}, {0x464c4000}, {0x464c6000}, 
+    {0x464c8000}, {0x464ca000}, {0x464cc000}, {0x464ce000}, 
+    {0x464d0000}, {0x464d2000}, {0x464d4000}, {0x464d6000}, 
+    {0x464d8000}, {0x464da000}, {0x464dc000}, {0x464de000}, 
+    {0x464e0000}, {0x464e2000}, {0x464e4000}, {0x464e6000}, 
+    {0x464e8000}, {0x464ea000}, {0x464ec000}, {0x464ee000}, 
+    {0x464f0000}, {0x464f2000}, {0x464f4000}, {0x464f6000}, 
+    {0x464f8000}, {0x464fa000}, {0x464fc000}, {0x464fe000}, 
+    {0x46500000}, {0x46502000}, {0x46504000}, {0x46506000}, 
+    {0x46508000}, {0x4650a000}, {0x4650c000}, {0x4650e000}, 
+    {0x46510000}, {0x46512000}, {0x46514000}, {0x46516000}, 
+    {0x46518000}, {0x4651a000}, {0x4651c000}, {0x4651e000}, 
+    {0x46520000}, {0x46522000}, {0x46524000}, {0x46526000}, 
+    {0x46528000}, {0x4652a000}, {0x4652c000}, {0x4652e000}, 
+    {0x46530000}, {0x46532000}, {0x46534000}, {0x46536000}, 
+    {0x46538000}, {0x4653a000}, {0x4653c000}, {0x4653e000}, 
+    {0x46540000}, {0x46542000}, {0x46544000}, {0x46546000}, 
+    {0x46548000}, {0x4654a000}, {0x4654c000}, {0x4654e000}, 
+    {0x46550000}, {0x46552000}, {0x46554000}, {0x46556000}, 
+    {0x46558000}, {0x4655a000}, {0x4655c000}, {0x4655e000}, 
+    {0x46560000}, {0x46562000}, {0x46564000}, {0x46566000}, 
+    {0x46568000}, {0x4656a000}, {0x4656c000}, {0x4656e000}, 
+    {0x46570000}, {0x46572000}, {0x46574000}, {0x46576000}, 
+    {0x46578000}, {0x4657a000}, {0x4657c000}, {0x4657e000}, 
+    {0x46580000}, {0x46582000}, {0x46584000}, {0x46586000}, 
+    {0x46588000}, {0x4658a000}, {0x4658c000}, {0x4658e000}, 
+    {0x46590000}, {0x46592000}, {0x46594000}, {0x46596000}, 
+    {0x46598000}, {0x4659a000}, {0x4659c000}, {0x4659e000}, 
+    {0x465a0000}, {0x465a2000}, {0x465a4000}, {0x465a6000}, 
+    {0x465a8000}, {0x465aa000}, {0x465ac000}, {0x465ae000}, 
+    {0x465b0000}, {0x465b2000}, {0x465b4000}, {0x465b6000}, 
+    {0x465b8000}, {0x465ba000}, {0x465bc000}, {0x465be000}, 
+    {0x465c0000}, {0x465c2000}, {0x465c4000}, {0x465c6000}, 
+    {0x465c8000}, {0x465ca000}, {0x465cc000}, {0x465ce000}, 
+    {0x465d0000}, {0x465d2000}, {0x465d4000}, {0x465d6000}, 
+    {0x465d8000}, {0x465da000}, {0x465dc000}, {0x465de000}, 
+    {0x465e0000}, {0x465e2000}, {0x465e4000}, {0x465e6000}, 
+    {0x465e8000}, {0x465ea000}, {0x465ec000}, {0x465ee000}, 
+    {0x465f0000}, {0x465f2000}, {0x465f4000}, {0x465f6000}, 
+    {0x465f8000}, {0x465fa000}, {0x465fc000}, {0x465fe000}, 
+    {0x46600000}, {0x46602000}, {0x46604000}, {0x46606000}, 
+    {0x46608000}, {0x4660a000}, {0x4660c000}, {0x4660e000}, 
+    {0x46610000}, {0x46612000}, {0x46614000}, {0x46616000}, 
+    {0x46618000}, {0x4661a000}, {0x4661c000}, {0x4661e000}, 
+    {0x46620000}, {0x46622000}, {0x46624000}, {0x46626000}, 
+    {0x46628000}, {0x4662a000}, {0x4662c000}, {0x4662e000}, 
+    {0x46630000}, {0x46632000}, {0x46634000}, {0x46636000}, 
+    {0x46638000}, {0x4663a000}, {0x4663c000}, {0x4663e000}, 
+    {0x46640000}, {0x46642000}, {0x46644000}, {0x46646000}, 
+    {0x46648000}, {0x4664a000}, {0x4664c000}, {0x4664e000}, 
+    {0x46650000}, {0x46652000}, {0x46654000}, {0x46656000}, 
+    {0x46658000}, {0x4665a000}, {0x4665c000}, {0x4665e000}, 
+    {0x46660000}, {0x46662000}, {0x46664000}, {0x46666000}, 
+    {0x46668000}, {0x4666a000}, {0x4666c000}, {0x4666e000}, 
+    {0x46670000}, {0x46672000}, {0x46674000}, {0x46676000}, 
+    {0x46678000}, {0x4667a000}, {0x4667c000}, {0x4667e000}, 
+    {0x46680000}, {0x46682000}, {0x46684000}, {0x46686000}, 
+    {0x46688000}, {0x4668a000}, {0x4668c000}, {0x4668e000}, 
+    {0x46690000}, {0x46692000}, {0x46694000}, {0x46696000}, 
+    {0x46698000}, {0x4669a000}, {0x4669c000}, {0x4669e000}, 
+    {0x466a0000}, {0x466a2000}, {0x466a4000}, {0x466a6000}, 
+    {0x466a8000}, {0x466aa000}, {0x466ac000}, {0x466ae000}, 
+    {0x466b0000}, {0x466b2000}, {0x466b4000}, {0x466b6000}, 
+    {0x466b8000}, {0x466ba000}, {0x466bc000}, {0x466be000}, 
+    {0x466c0000}, {0x466c2000}, {0x466c4000}, {0x466c6000}, 
+    {0x466c8000}, {0x466ca000}, {0x466cc000}, {0x466ce000}, 
+    {0x466d0000}, {0x466d2000}, {0x466d4000}, {0x466d6000}, 
+    {0x466d8000}, {0x466da000}, {0x466dc000}, {0x466de000}, 
+    {0x466e0000}, {0x466e2000}, {0x466e4000}, {0x466e6000}, 
+    {0x466e8000}, {0x466ea000}, {0x466ec000}, {0x466ee000}, 
+    {0x466f0000}, {0x466f2000}, {0x466f4000}, {0x466f6000}, 
+    {0x466f8000}, {0x466fa000}, {0x466fc000}, {0x466fe000}, 
+    {0x46700000}, {0x46702000}, {0x46704000}, {0x46706000}, 
+    {0x46708000}, {0x4670a000}, {0x4670c000}, {0x4670e000}, 
+    {0x46710000}, {0x46712000}, {0x46714000}, {0x46716000}, 
+    {0x46718000}, {0x4671a000}, {0x4671c000}, {0x4671e000}, 
+    {0x46720000}, {0x46722000}, {0x46724000}, {0x46726000}, 
+    {0x46728000}, {0x4672a000}, {0x4672c000}, {0x4672e000}, 
+    {0x46730000}, {0x46732000}, {0x46734000}, {0x46736000}, 
+    {0x46738000}, {0x4673a000}, {0x4673c000}, {0x4673e000}, 
+    {0x46740000}, {0x46742000}, {0x46744000}, {0x46746000}, 
+    {0x46748000}, {0x4674a000}, {0x4674c000}, {0x4674e000}, 
+    {0x46750000}, {0x46752000}, {0x46754000}, {0x46756000}, 
+    {0x46758000}, {0x4675a000}, {0x4675c000}, {0x4675e000}, 
+    {0x46760000}, {0x46762000}, {0x46764000}, {0x46766000}, 
+    {0x46768000}, {0x4676a000}, {0x4676c000}, {0x4676e000}, 
+    {0x46770000}, {0x46772000}, {0x46774000}, {0x46776000}, 
+    {0x46778000}, {0x4677a000}, {0x4677c000}, {0x4677e000}, 
+    {0x46780000}, {0x46782000}, {0x46784000}, {0x46786000}, 
+    {0x46788000}, {0x4678a000}, {0x4678c000}, {0x4678e000}, 
+    {0x46790000}, {0x46792000}, {0x46794000}, {0x46796000}, 
+    {0x46798000}, {0x4679a000}, {0x4679c000}, {0x4679e000}, 
+    {0x467a0000}, {0x467a2000}, {0x467a4000}, {0x467a6000}, 
+    {0x467a8000}, {0x467aa000}, {0x467ac000}, {0x467ae000}, 
+    {0x467b0000}, {0x467b2000}, {0x467b4000}, {0x467b6000}, 
+    {0x467b8000}, {0x467ba000}, {0x467bc000}, {0x467be000}, 
+    {0x467c0000}, {0x467c2000}, {0x467c4000}, {0x467c6000}, 
+    {0x467c8000}, {0x467ca000}, {0x467cc000}, {0x467ce000}, 
+    {0x467d0000}, {0x467d2000}, {0x467d4000}, {0x467d6000}, 
+    {0x467d8000}, {0x467da000}, {0x467dc000}, {0x467de000}, 
+    {0x467e0000}, {0x467e2000}, {0x467e4000}, {0x467e6000}, 
+    {0x467e8000}, {0x467ea000}, {0x467ec000}, {0x467ee000}, 
+    {0x467f0000}, {0x467f2000}, {0x467f4000}, {0x467f6000}, 
+    {0x467f8000}, {0x467fa000}, {0x467fc000}, {0x467fe000}, 
+    {0x46800000}, {0x46802000}, {0x46804000}, {0x46806000}, 
+    {0x46808000}, {0x4680a000}, {0x4680c000}, {0x4680e000}, 
+    {0x46810000}, {0x46812000}, {0x46814000}, {0x46816000}, 
+    {0x46818000}, {0x4681a000}, {0x4681c000}, {0x4681e000}, 
+    {0x46820000}, {0x46822000}, {0x46824000}, {0x46826000}, 
+    {0x46828000}, {0x4682a000}, {0x4682c000}, {0x4682e000}, 
+    {0x46830000}, {0x46832000}, {0x46834000}, {0x46836000}, 
+    {0x46838000}, {0x4683a000}, {0x4683c000}, {0x4683e000}, 
+    {0x46840000}, {0x46842000}, {0x46844000}, {0x46846000}, 
+    {0x46848000}, {0x4684a000}, {0x4684c000}, {0x4684e000}, 
+    {0x46850000}, {0x46852000}, {0x46854000}, {0x46856000}, 
+    {0x46858000}, {0x4685a000}, {0x4685c000}, {0x4685e000}, 
+    {0x46860000}, {0x46862000}, {0x46864000}, {0x46866000}, 
+    {0x46868000}, {0x4686a000}, {0x4686c000}, {0x4686e000}, 
+    {0x46870000}, {0x46872000}, {0x46874000}, {0x46876000}, 
+    {0x46878000}, {0x4687a000}, {0x4687c000}, {0x4687e000}, 
+    {0x46880000}, {0x46882000}, {0x46884000}, {0x46886000}, 
+    {0x46888000}, {0x4688a000}, {0x4688c000}, {0x4688e000}, 
+    {0x46890000}, {0x46892000}, {0x46894000}, {0x46896000}, 
+    {0x46898000}, {0x4689a000}, {0x4689c000}, {0x4689e000}, 
+    {0x468a0000}, {0x468a2000}, {0x468a4000}, {0x468a6000}, 
+    {0x468a8000}, {0x468aa000}, {0x468ac000}, {0x468ae000}, 
+    {0x468b0000}, {0x468b2000}, {0x468b4000}, {0x468b6000}, 
+    {0x468b8000}, {0x468ba000}, {0x468bc000}, {0x468be000}, 
+    {0x468c0000}, {0x468c2000}, {0x468c4000}, {0x468c6000}, 
+    {0x468c8000}, {0x468ca000}, {0x468cc000}, {0x468ce000}, 
+    {0x468d0000}, {0x468d2000}, {0x468d4000}, {0x468d6000}, 
+    {0x468d8000}, {0x468da000}, {0x468dc000}, {0x468de000}, 
+    {0x468e0000}, {0x468e2000}, {0x468e4000}, {0x468e6000}, 
+    {0x468e8000}, {0x468ea000}, {0x468ec000}, {0x468ee000}, 
+    {0x468f0000}, {0x468f2000}, {0x468f4000}, {0x468f6000}, 
+    {0x468f8000}, {0x468fa000}, {0x468fc000}, {0x468fe000}, 
+    {0x46900000}, {0x46902000}, {0x46904000}, {0x46906000}, 
+    {0x46908000}, {0x4690a000}, {0x4690c000}, {0x4690e000}, 
+    {0x46910000}, {0x46912000}, {0x46914000}, {0x46916000}, 
+    {0x46918000}, {0x4691a000}, {0x4691c000}, {0x4691e000}, 
+    {0x46920000}, {0x46922000}, {0x46924000}, {0x46926000}, 
+    {0x46928000}, {0x4692a000}, {0x4692c000}, {0x4692e000}, 
+    {0x46930000}, {0x46932000}, {0x46934000}, {0x46936000}, 
+    {0x46938000}, {0x4693a000}, {0x4693c000}, {0x4693e000}, 
+    {0x46940000}, {0x46942000}, {0x46944000}, {0x46946000}, 
+    {0x46948000}, {0x4694a000}, {0x4694c000}, {0x4694e000}, 
+    {0x46950000}, {0x46952000}, {0x46954000}, {0x46956000}, 
+    {0x46958000}, {0x4695a000}, {0x4695c000}, {0x4695e000}, 
+    {0x46960000}, {0x46962000}, {0x46964000}, {0x46966000}, 
+    {0x46968000}, {0x4696a000}, {0x4696c000}, {0x4696e000}, 
+    {0x46970000}, {0x46972000}, {0x46974000}, {0x46976000}, 
+    {0x46978000}, {0x4697a000}, {0x4697c000}, {0x4697e000}, 
+    {0x46980000}, {0x46982000}, {0x46984000}, {0x46986000}, 
+    {0x46988000}, {0x4698a000}, {0x4698c000}, {0x4698e000}, 
+    {0x46990000}, {0x46992000}, {0x46994000}, {0x46996000}, 
+    {0x46998000}, {0x4699a000}, {0x4699c000}, {0x4699e000}, 
+    {0x469a0000}, {0x469a2000}, {0x469a4000}, {0x469a6000}, 
+    {0x469a8000}, {0x469aa000}, {0x469ac000}, {0x469ae000}, 
+    {0x469b0000}, {0x469b2000}, {0x469b4000}, {0x469b6000}, 
+    {0x469b8000}, {0x469ba000}, {0x469bc000}, {0x469be000}, 
+    {0x469c0000}, {0x469c2000}, {0x469c4000}, {0x469c6000}, 
+    {0x469c8000}, {0x469ca000}, {0x469cc000}, {0x469ce000}, 
+    {0x469d0000}, {0x469d2000}, {0x469d4000}, {0x469d6000}, 
+    {0x469d8000}, {0x469da000}, {0x469dc000}, {0x469de000}, 
+    {0x469e0000}, {0x469e2000}, {0x469e4000}, {0x469e6000}, 
+    {0x469e8000}, {0x469ea000}, {0x469ec000}, {0x469ee000}, 
+    {0x469f0000}, {0x469f2000}, {0x469f4000}, {0x469f6000}, 
+    {0x469f8000}, {0x469fa000}, {0x469fc000}, {0x469fe000}, 
+    {0x46a00000}, {0x46a02000}, {0x46a04000}, {0x46a06000}, 
+    {0x46a08000}, {0x46a0a000}, {0x46a0c000}, {0x46a0e000}, 
+    {0x46a10000}, {0x46a12000}, {0x46a14000}, {0x46a16000}, 
+    {0x46a18000}, {0x46a1a000}, {0x46a1c000}, {0x46a1e000}, 
+    {0x46a20000}, {0x46a22000}, {0x46a24000}, {0x46a26000}, 
+    {0x46a28000}, {0x46a2a000}, {0x46a2c000}, {0x46a2e000}, 
+    {0x46a30000}, {0x46a32000}, {0x46a34000}, {0x46a36000}, 
+    {0x46a38000}, {0x46a3a000}, {0x46a3c000}, {0x46a3e000}, 
+    {0x46a40000}, {0x46a42000}, {0x46a44000}, {0x46a46000}, 
+    {0x46a48000}, {0x46a4a000}, {0x46a4c000}, {0x46a4e000}, 
+    {0x46a50000}, {0x46a52000}, {0x46a54000}, {0x46a56000}, 
+    {0x46a58000}, {0x46a5a000}, {0x46a5c000}, {0x46a5e000}, 
+    {0x46a60000}, {0x46a62000}, {0x46a64000}, {0x46a66000}, 
+    {0x46a68000}, {0x46a6a000}, {0x46a6c000}, {0x46a6e000}, 
+    {0x46a70000}, {0x46a72000}, {0x46a74000}, {0x46a76000}, 
+    {0x46a78000}, {0x46a7a000}, {0x46a7c000}, {0x46a7e000}, 
+    {0x46a80000}, {0x46a82000}, {0x46a84000}, {0x46a86000}, 
+    {0x46a88000}, {0x46a8a000}, {0x46a8c000}, {0x46a8e000}, 
+    {0x46a90000}, {0x46a92000}, {0x46a94000}, {0x46a96000}, 
+    {0x46a98000}, {0x46a9a000}, {0x46a9c000}, {0x46a9e000}, 
+    {0x46aa0000}, {0x46aa2000}, {0x46aa4000}, {0x46aa6000}, 
+    {0x46aa8000}, {0x46aaa000}, {0x46aac000}, {0x46aae000}, 
+    {0x46ab0000}, {0x46ab2000}, {0x46ab4000}, {0x46ab6000}, 
+    {0x46ab8000}, {0x46aba000}, {0x46abc000}, {0x46abe000}, 
+    {0x46ac0000}, {0x46ac2000}, {0x46ac4000}, {0x46ac6000}, 
+    {0x46ac8000}, {0x46aca000}, {0x46acc000}, {0x46ace000}, 
+    {0x46ad0000}, {0x46ad2000}, {0x46ad4000}, {0x46ad6000}, 
+    {0x46ad8000}, {0x46ada000}, {0x46adc000}, {0x46ade000}, 
+    {0x46ae0000}, {0x46ae2000}, {0x46ae4000}, {0x46ae6000}, 
+    {0x46ae8000}, {0x46aea000}, {0x46aec000}, {0x46aee000}, 
+    {0x46af0000}, {0x46af2000}, {0x46af4000}, {0x46af6000}, 
+    {0x46af8000}, {0x46afa000}, {0x46afc000}, {0x46afe000}, 
+    {0x46b00000}, {0x46b02000}, {0x46b04000}, {0x46b06000}, 
+    {0x46b08000}, {0x46b0a000}, {0x46b0c000}, {0x46b0e000}, 
+    {0x46b10000}, {0x46b12000}, {0x46b14000}, {0x46b16000}, 
+    {0x46b18000}, {0x46b1a000}, {0x46b1c000}, {0x46b1e000}, 
+    {0x46b20000}, {0x46b22000}, {0x46b24000}, {0x46b26000}, 
+    {0x46b28000}, {0x46b2a000}, {0x46b2c000}, {0x46b2e000}, 
+    {0x46b30000}, {0x46b32000}, {0x46b34000}, {0x46b36000}, 
+    {0x46b38000}, {0x46b3a000}, {0x46b3c000}, {0x46b3e000}, 
+    {0x46b40000}, {0x46b42000}, {0x46b44000}, {0x46b46000}, 
+    {0x46b48000}, {0x46b4a000}, {0x46b4c000}, {0x46b4e000}, 
+    {0x46b50000}, {0x46b52000}, {0x46b54000}, {0x46b56000}, 
+    {0x46b58000}, {0x46b5a000}, {0x46b5c000}, {0x46b5e000}, 
+    {0x46b60000}, {0x46b62000}, {0x46b64000}, {0x46b66000}, 
+    {0x46b68000}, {0x46b6a000}, {0x46b6c000}, {0x46b6e000}, 
+    {0x46b70000}, {0x46b72000}, {0x46b74000}, {0x46b76000}, 
+    {0x46b78000}, {0x46b7a000}, {0x46b7c000}, {0x46b7e000}, 
+    {0x46b80000}, {0x46b82000}, {0x46b84000}, {0x46b86000}, 
+    {0x46b88000}, {0x46b8a000}, {0x46b8c000}, {0x46b8e000}, 
+    {0x46b90000}, {0x46b92000}, {0x46b94000}, {0x46b96000}, 
+    {0x46b98000}, {0x46b9a000}, {0x46b9c000}, {0x46b9e000}, 
+    {0x46ba0000}, {0x46ba2000}, {0x46ba4000}, {0x46ba6000}, 
+    {0x46ba8000}, {0x46baa000}, {0x46bac000}, {0x46bae000}, 
+    {0x46bb0000}, {0x46bb2000}, {0x46bb4000}, {0x46bb6000}, 
+    {0x46bb8000}, {0x46bba000}, {0x46bbc000}, {0x46bbe000}, 
+    {0x46bc0000}, {0x46bc2000}, {0x46bc4000}, {0x46bc6000}, 
+    {0x46bc8000}, {0x46bca000}, {0x46bcc000}, {0x46bce000}, 
+    {0x46bd0000}, {0x46bd2000}, {0x46bd4000}, {0x46bd6000}, 
+    {0x46bd8000}, {0x46bda000}, {0x46bdc000}, {0x46bde000}, 
+    {0x46be0000}, {0x46be2000}, {0x46be4000}, {0x46be6000}, 
+    {0x46be8000}, {0x46bea000}, {0x46bec000}, {0x46bee000}, 
+    {0x46bf0000}, {0x46bf2000}, {0x46bf4000}, {0x46bf6000}, 
+    {0x46bf8000}, {0x46bfa000}, {0x46bfc000}, {0x46bfe000}, 
+    {0x46c00000}, {0x46c02000}, {0x46c04000}, {0x46c06000}, 
+    {0x46c08000}, {0x46c0a000}, {0x46c0c000}, {0x46c0e000}, 
+    {0x46c10000}, {0x46c12000}, {0x46c14000}, {0x46c16000}, 
+    {0x46c18000}, {0x46c1a000}, {0x46c1c000}, {0x46c1e000}, 
+    {0x46c20000}, {0x46c22000}, {0x46c24000}, {0x46c26000}, 
+    {0x46c28000}, {0x46c2a000}, {0x46c2c000}, {0x46c2e000}, 
+    {0x46c30000}, {0x46c32000}, {0x46c34000}, {0x46c36000}, 
+    {0x46c38000}, {0x46c3a000}, {0x46c3c000}, {0x46c3e000}, 
+    {0x46c40000}, {0x46c42000}, {0x46c44000}, {0x46c46000}, 
+    {0x46c48000}, {0x46c4a000}, {0x46c4c000}, {0x46c4e000}, 
+    {0x46c50000}, {0x46c52000}, {0x46c54000}, {0x46c56000}, 
+    {0x46c58000}, {0x46c5a000}, {0x46c5c000}, {0x46c5e000}, 
+    {0x46c60000}, {0x46c62000}, {0x46c64000}, {0x46c66000}, 
+    {0x46c68000}, {0x46c6a000}, {0x46c6c000}, {0x46c6e000}, 
+    {0x46c70000}, {0x46c72000}, {0x46c74000}, {0x46c76000}, 
+    {0x46c78000}, {0x46c7a000}, {0x46c7c000}, {0x46c7e000}, 
+    {0x46c80000}, {0x46c82000}, {0x46c84000}, {0x46c86000}, 
+    {0x46c88000}, {0x46c8a000}, {0x46c8c000}, {0x46c8e000}, 
+    {0x46c90000}, {0x46c92000}, {0x46c94000}, {0x46c96000}, 
+    {0x46c98000}, {0x46c9a000}, {0x46c9c000}, {0x46c9e000}, 
+    {0x46ca0000}, {0x46ca2000}, {0x46ca4000}, {0x46ca6000}, 
+    {0x46ca8000}, {0x46caa000}, {0x46cac000}, {0x46cae000}, 
+    {0x46cb0000}, {0x46cb2000}, {0x46cb4000}, {0x46cb6000}, 
+    {0x46cb8000}, {0x46cba000}, {0x46cbc000}, {0x46cbe000}, 
+    {0x46cc0000}, {0x46cc2000}, {0x46cc4000}, {0x46cc6000}, 
+    {0x46cc8000}, {0x46cca000}, {0x46ccc000}, {0x46cce000}, 
+    {0x46cd0000}, {0x46cd2000}, {0x46cd4000}, {0x46cd6000}, 
+    {0x46cd8000}, {0x46cda000}, {0x46cdc000}, {0x46cde000}, 
+    {0x46ce0000}, {0x46ce2000}, {0x46ce4000}, {0x46ce6000}, 
+    {0x46ce8000}, {0x46cea000}, {0x46cec000}, {0x46cee000}, 
+    {0x46cf0000}, {0x46cf2000}, {0x46cf4000}, {0x46cf6000}, 
+    {0x46cf8000}, {0x46cfa000}, {0x46cfc000}, {0x46cfe000}, 
+    {0x46d00000}, {0x46d02000}, {0x46d04000}, {0x46d06000}, 
+    {0x46d08000}, {0x46d0a000}, {0x46d0c000}, {0x46d0e000}, 
+    {0x46d10000}, {0x46d12000}, {0x46d14000}, {0x46d16000}, 
+    {0x46d18000}, {0x46d1a000}, {0x46d1c000}, {0x46d1e000}, 
+    {0x46d20000}, {0x46d22000}, {0x46d24000}, {0x46d26000}, 
+    {0x46d28000}, {0x46d2a000}, {0x46d2c000}, {0x46d2e000}, 
+    {0x46d30000}, {0x46d32000}, {0x46d34000}, {0x46d36000}, 
+    {0x46d38000}, {0x46d3a000}, {0x46d3c000}, {0x46d3e000}, 
+    {0x46d40000}, {0x46d42000}, {0x46d44000}, {0x46d46000}, 
+    {0x46d48000}, {0x46d4a000}, {0x46d4c000}, {0x46d4e000}, 
+    {0x46d50000}, {0x46d52000}, {0x46d54000}, {0x46d56000}, 
+    {0x46d58000}, {0x46d5a000}, {0x46d5c000}, {0x46d5e000}, 
+    {0x46d60000}, {0x46d62000}, {0x46d64000}, {0x46d66000}, 
+    {0x46d68000}, {0x46d6a000}, {0x46d6c000}, {0x46d6e000}, 
+    {0x46d70000}, {0x46d72000}, {0x46d74000}, {0x46d76000}, 
+    {0x46d78000}, {0x46d7a000}, {0x46d7c000}, {0x46d7e000}, 
+    {0x46d80000}, {0x46d82000}, {0x46d84000}, {0x46d86000}, 
+    {0x46d88000}, {0x46d8a000}, {0x46d8c000}, {0x46d8e000}, 
+    {0x46d90000}, {0x46d92000}, {0x46d94000}, {0x46d96000}, 
+    {0x46d98000}, {0x46d9a000}, {0x46d9c000}, {0x46d9e000}, 
+    {0x46da0000}, {0x46da2000}, {0x46da4000}, {0x46da6000}, 
+    {0x46da8000}, {0x46daa000}, {0x46dac000}, {0x46dae000}, 
+    {0x46db0000}, {0x46db2000}, {0x46db4000}, {0x46db6000}, 
+    {0x46db8000}, {0x46dba000}, {0x46dbc000}, {0x46dbe000}, 
+    {0x46dc0000}, {0x46dc2000}, {0x46dc4000}, {0x46dc6000}, 
+    {0x46dc8000}, {0x46dca000}, {0x46dcc000}, {0x46dce000}, 
+    {0x46dd0000}, {0x46dd2000}, {0x46dd4000}, {0x46dd6000}, 
+    {0x46dd8000}, {0x46dda000}, {0x46ddc000}, {0x46dde000}, 
+    {0x46de0000}, {0x46de2000}, {0x46de4000}, {0x46de6000}, 
+    {0x46de8000}, {0x46dea000}, {0x46dec000}, {0x46dee000}, 
+    {0x46df0000}, {0x46df2000}, {0x46df4000}, {0x46df6000}, 
+    {0x46df8000}, {0x46dfa000}, {0x46dfc000}, {0x46dfe000}, 
+    {0x46e00000}, {0x46e02000}, {0x46e04000}, {0x46e06000}, 
+    {0x46e08000}, {0x46e0a000}, {0x46e0c000}, {0x46e0e000}, 
+    {0x46e10000}, {0x46e12000}, {0x46e14000}, {0x46e16000}, 
+    {0x46e18000}, {0x46e1a000}, {0x46e1c000}, {0x46e1e000}, 
+    {0x46e20000}, {0x46e22000}, {0x46e24000}, {0x46e26000}, 
+    {0x46e28000}, {0x46e2a000}, {0x46e2c000}, {0x46e2e000}, 
+    {0x46e30000}, {0x46e32000}, {0x46e34000}, {0x46e36000}, 
+    {0x46e38000}, {0x46e3a000}, {0x46e3c000}, {0x46e3e000}, 
+    {0x46e40000}, {0x46e42000}, {0x46e44000}, {0x46e46000}, 
+    {0x46e48000}, {0x46e4a000}, {0x46e4c000}, {0x46e4e000}, 
+    {0x46e50000}, {0x46e52000}, {0x46e54000}, {0x46e56000}, 
+    {0x46e58000}, {0x46e5a000}, {0x46e5c000}, {0x46e5e000}, 
+    {0x46e60000}, {0x46e62000}, {0x46e64000}, {0x46e66000}, 
+    {0x46e68000}, {0x46e6a000}, {0x46e6c000}, {0x46e6e000}, 
+    {0x46e70000}, {0x46e72000}, {0x46e74000}, {0x46e76000}, 
+    {0x46e78000}, {0x46e7a000}, {0x46e7c000}, {0x46e7e000}, 
+    {0x46e80000}, {0x46e82000}, {0x46e84000}, {0x46e86000}, 
+    {0x46e88000}, {0x46e8a000}, {0x46e8c000}, {0x46e8e000}, 
+    {0x46e90000}, {0x46e92000}, {0x46e94000}, {0x46e96000}, 
+    {0x46e98000}, {0x46e9a000}, {0x46e9c000}, {0x46e9e000}, 
+    {0x46ea0000}, {0x46ea2000}, {0x46ea4000}, {0x46ea6000}, 
+    {0x46ea8000}, {0x46eaa000}, {0x46eac000}, {0x46eae000}, 
+    {0x46eb0000}, {0x46eb2000}, {0x46eb4000}, {0x46eb6000}, 
+    {0x46eb8000}, {0x46eba000}, {0x46ebc000}, {0x46ebe000}, 
+    {0x46ec0000}, {0x46ec2000}, {0x46ec4000}, {0x46ec6000}, 
+    {0x46ec8000}, {0x46eca000}, {0x46ecc000}, {0x46ece000}, 
+    {0x46ed0000}, {0x46ed2000}, {0x46ed4000}, {0x46ed6000}, 
+    {0x46ed8000}, {0x46eda000}, {0x46edc000}, {0x46ede000}, 
+    {0x46ee0000}, {0x46ee2000}, {0x46ee4000}, {0x46ee6000}, 
+    {0x46ee8000}, {0x46eea000}, {0x46eec000}, {0x46eee000}, 
+    {0x46ef0000}, {0x46ef2000}, {0x46ef4000}, {0x46ef6000}, 
+    {0x46ef8000}, {0x46efa000}, {0x46efc000}, {0x46efe000}, 
+    {0x46f00000}, {0x46f02000}, {0x46f04000}, {0x46f06000}, 
+    {0x46f08000}, {0x46f0a000}, {0x46f0c000}, {0x46f0e000}, 
+    {0x46f10000}, {0x46f12000}, {0x46f14000}, {0x46f16000}, 
+    {0x46f18000}, {0x46f1a000}, {0x46f1c000}, {0x46f1e000}, 
+    {0x46f20000}, {0x46f22000}, {0x46f24000}, {0x46f26000}, 
+    {0x46f28000}, {0x46f2a000}, {0x46f2c000}, {0x46f2e000}, 
+    {0x46f30000}, {0x46f32000}, {0x46f34000}, {0x46f36000}, 
+    {0x46f38000}, {0x46f3a000}, {0x46f3c000}, {0x46f3e000}, 
+    {0x46f40000}, {0x46f42000}, {0x46f44000}, {0x46f46000}, 
+    {0x46f48000}, {0x46f4a000}, {0x46f4c000}, {0x46f4e000}, 
+    {0x46f50000}, {0x46f52000}, {0x46f54000}, {0x46f56000}, 
+    {0x46f58000}, {0x46f5a000}, {0x46f5c000}, {0x46f5e000}, 
+    {0x46f60000}, {0x46f62000}, {0x46f64000}, {0x46f66000}, 
+    {0x46f68000}, {0x46f6a000}, {0x46f6c000}, {0x46f6e000}, 
+    {0x46f70000}, {0x46f72000}, {0x46f74000}, {0x46f76000}, 
+    {0x46f78000}, {0x46f7a000}, {0x46f7c000}, {0x46f7e000}, 
+    {0x46f80000}, {0x46f82000}, {0x46f84000}, {0x46f86000}, 
+    {0x46f88000}, {0x46f8a000}, {0x46f8c000}, {0x46f8e000}, 
+    {0x46f90000}, {0x46f92000}, {0x46f94000}, {0x46f96000}, 
+    {0x46f98000}, {0x46f9a000}, {0x46f9c000}, {0x46f9e000}, 
+    {0x46fa0000}, {0x46fa2000}, {0x46fa4000}, {0x46fa6000}, 
+    {0x46fa8000}, {0x46faa000}, {0x46fac000}, {0x46fae000}, 
+    {0x46fb0000}, {0x46fb2000}, {0x46fb4000}, {0x46fb6000}, 
+    {0x46fb8000}, {0x46fba000}, {0x46fbc000}, {0x46fbe000}, 
+    {0x46fc0000}, {0x46fc2000}, {0x46fc4000}, {0x46fc6000}, 
+    {0x46fc8000}, {0x46fca000}, {0x46fcc000}, {0x46fce000}, 
+    {0x46fd0000}, {0x46fd2000}, {0x46fd4000}, {0x46fd6000}, 
+    {0x46fd8000}, {0x46fda000}, {0x46fdc000}, {0x46fde000}, 
+    {0x46fe0000}, {0x46fe2000}, {0x46fe4000}, {0x46fe6000}, 
+    {0x46fe8000}, {0x46fea000}, {0x46fec000}, {0x46fee000}, 
+    {0x46ff0000}, {0x46ff2000}, {0x46ff4000}, {0x46ff6000}, 
+    {0x46ff8000}, {0x46ffa000}, {0x46ffc000}, {0x46ffe000}, 
+    {0x47000000}, {0x47002000}, {0x47004000}, {0x47006000}, 
+    {0x47008000}, {0x4700a000}, {0x4700c000}, {0x4700e000}, 
+    {0x47010000}, {0x47012000}, {0x47014000}, {0x47016000}, 
+    {0x47018000}, {0x4701a000}, {0x4701c000}, {0x4701e000}, 
+    {0x47020000}, {0x47022000}, {0x47024000}, {0x47026000}, 
+    {0x47028000}, {0x4702a000}, {0x4702c000}, {0x4702e000}, 
+    {0x47030000}, {0x47032000}, {0x47034000}, {0x47036000}, 
+    {0x47038000}, {0x4703a000}, {0x4703c000}, {0x4703e000}, 
+    {0x47040000}, {0x47042000}, {0x47044000}, {0x47046000}, 
+    {0x47048000}, {0x4704a000}, {0x4704c000}, {0x4704e000}, 
+    {0x47050000}, {0x47052000}, {0x47054000}, {0x47056000}, 
+    {0x47058000}, {0x4705a000}, {0x4705c000}, {0x4705e000}, 
+    {0x47060000}, {0x47062000}, {0x47064000}, {0x47066000}, 
+    {0x47068000}, {0x4706a000}, {0x4706c000}, {0x4706e000}, 
+    {0x47070000}, {0x47072000}, {0x47074000}, {0x47076000}, 
+    {0x47078000}, {0x4707a000}, {0x4707c000}, {0x4707e000}, 
+    {0x47080000}, {0x47082000}, {0x47084000}, {0x47086000}, 
+    {0x47088000}, {0x4708a000}, {0x4708c000}, {0x4708e000}, 
+    {0x47090000}, {0x47092000}, {0x47094000}, {0x47096000}, 
+    {0x47098000}, {0x4709a000}, {0x4709c000}, {0x4709e000}, 
+    {0x470a0000}, {0x470a2000}, {0x470a4000}, {0x470a6000}, 
+    {0x470a8000}, {0x470aa000}, {0x470ac000}, {0x470ae000}, 
+    {0x470b0000}, {0x470b2000}, {0x470b4000}, {0x470b6000}, 
+    {0x470b8000}, {0x470ba000}, {0x470bc000}, {0x470be000}, 
+    {0x470c0000}, {0x470c2000}, {0x470c4000}, {0x470c6000}, 
+    {0x470c8000}, {0x470ca000}, {0x470cc000}, {0x470ce000}, 
+    {0x470d0000}, {0x470d2000}, {0x470d4000}, {0x470d6000}, 
+    {0x470d8000}, {0x470da000}, {0x470dc000}, {0x470de000}, 
+    {0x470e0000}, {0x470e2000}, {0x470e4000}, {0x470e6000}, 
+    {0x470e8000}, {0x470ea000}, {0x470ec000}, {0x470ee000}, 
+    {0x470f0000}, {0x470f2000}, {0x470f4000}, {0x470f6000}, 
+    {0x470f8000}, {0x470fa000}, {0x470fc000}, {0x470fe000}, 
+    {0x47100000}, {0x47102000}, {0x47104000}, {0x47106000}, 
+    {0x47108000}, {0x4710a000}, {0x4710c000}, {0x4710e000}, 
+    {0x47110000}, {0x47112000}, {0x47114000}, {0x47116000}, 
+    {0x47118000}, {0x4711a000}, {0x4711c000}, {0x4711e000}, 
+    {0x47120000}, {0x47122000}, {0x47124000}, {0x47126000}, 
+    {0x47128000}, {0x4712a000}, {0x4712c000}, {0x4712e000}, 
+    {0x47130000}, {0x47132000}, {0x47134000}, {0x47136000}, 
+    {0x47138000}, {0x4713a000}, {0x4713c000}, {0x4713e000}, 
+    {0x47140000}, {0x47142000}, {0x47144000}, {0x47146000}, 
+    {0x47148000}, {0x4714a000}, {0x4714c000}, {0x4714e000}, 
+    {0x47150000}, {0x47152000}, {0x47154000}, {0x47156000}, 
+    {0x47158000}, {0x4715a000}, {0x4715c000}, {0x4715e000}, 
+    {0x47160000}, {0x47162000}, {0x47164000}, {0x47166000}, 
+    {0x47168000}, {0x4716a000}, {0x4716c000}, {0x4716e000}, 
+    {0x47170000}, {0x47172000}, {0x47174000}, {0x47176000}, 
+    {0x47178000}, {0x4717a000}, {0x4717c000}, {0x4717e000}, 
+    {0x47180000}, {0x47182000}, {0x47184000}, {0x47186000}, 
+    {0x47188000}, {0x4718a000}, {0x4718c000}, {0x4718e000}, 
+    {0x47190000}, {0x47192000}, {0x47194000}, {0x47196000}, 
+    {0x47198000}, {0x4719a000}, {0x4719c000}, {0x4719e000}, 
+    {0x471a0000}, {0x471a2000}, {0x471a4000}, {0x471a6000}, 
+    {0x471a8000}, {0x471aa000}, {0x471ac000}, {0x471ae000}, 
+    {0x471b0000}, {0x471b2000}, {0x471b4000}, {0x471b6000}, 
+    {0x471b8000}, {0x471ba000}, {0x471bc000}, {0x471be000}, 
+    {0x471c0000}, {0x471c2000}, {0x471c4000}, {0x471c6000}, 
+    {0x471c8000}, {0x471ca000}, {0x471cc000}, {0x471ce000}, 
+    {0x471d0000}, {0x471d2000}, {0x471d4000}, {0x471d6000}, 
+    {0x471d8000}, {0x471da000}, {0x471dc000}, {0x471de000}, 
+    {0x471e0000}, {0x471e2000}, {0x471e4000}, {0x471e6000}, 
+    {0x471e8000}, {0x471ea000}, {0x471ec000}, {0x471ee000}, 
+    {0x471f0000}, {0x471f2000}, {0x471f4000}, {0x471f6000}, 
+    {0x471f8000}, {0x471fa000}, {0x471fc000}, {0x471fe000}, 
+    {0x47200000}, {0x47202000}, {0x47204000}, {0x47206000}, 
+    {0x47208000}, {0x4720a000}, {0x4720c000}, {0x4720e000}, 
+    {0x47210000}, {0x47212000}, {0x47214000}, {0x47216000}, 
+    {0x47218000}, {0x4721a000}, {0x4721c000}, {0x4721e000}, 
+    {0x47220000}, {0x47222000}, {0x47224000}, {0x47226000}, 
+    {0x47228000}, {0x4722a000}, {0x4722c000}, {0x4722e000}, 
+    {0x47230000}, {0x47232000}, {0x47234000}, {0x47236000}, 
+    {0x47238000}, {0x4723a000}, {0x4723c000}, {0x4723e000}, 
+    {0x47240000}, {0x47242000}, {0x47244000}, {0x47246000}, 
+    {0x47248000}, {0x4724a000}, {0x4724c000}, {0x4724e000}, 
+    {0x47250000}, {0x47252000}, {0x47254000}, {0x47256000}, 
+    {0x47258000}, {0x4725a000}, {0x4725c000}, {0x4725e000}, 
+    {0x47260000}, {0x47262000}, {0x47264000}, {0x47266000}, 
+    {0x47268000}, {0x4726a000}, {0x4726c000}, {0x4726e000}, 
+    {0x47270000}, {0x47272000}, {0x47274000}, {0x47276000}, 
+    {0x47278000}, {0x4727a000}, {0x4727c000}, {0x4727e000}, 
+    {0x47280000}, {0x47282000}, {0x47284000}, {0x47286000}, 
+    {0x47288000}, {0x4728a000}, {0x4728c000}, {0x4728e000}, 
+    {0x47290000}, {0x47292000}, {0x47294000}, {0x47296000}, 
+    {0x47298000}, {0x4729a000}, {0x4729c000}, {0x4729e000}, 
+    {0x472a0000}, {0x472a2000}, {0x472a4000}, {0x472a6000}, 
+    {0x472a8000}, {0x472aa000}, {0x472ac000}, {0x472ae000}, 
+    {0x472b0000}, {0x472b2000}, {0x472b4000}, {0x472b6000}, 
+    {0x472b8000}, {0x472ba000}, {0x472bc000}, {0x472be000}, 
+    {0x472c0000}, {0x472c2000}, {0x472c4000}, {0x472c6000}, 
+    {0x472c8000}, {0x472ca000}, {0x472cc000}, {0x472ce000}, 
+    {0x472d0000}, {0x472d2000}, {0x472d4000}, {0x472d6000}, 
+    {0x472d8000}, {0x472da000}, {0x472dc000}, {0x472de000}, 
+    {0x472e0000}, {0x472e2000}, {0x472e4000}, {0x472e6000}, 
+    {0x472e8000}, {0x472ea000}, {0x472ec000}, {0x472ee000}, 
+    {0x472f0000}, {0x472f2000}, {0x472f4000}, {0x472f6000}, 
+    {0x472f8000}, {0x472fa000}, {0x472fc000}, {0x472fe000}, 
+    {0x47300000}, {0x47302000}, {0x47304000}, {0x47306000}, 
+    {0x47308000}, {0x4730a000}, {0x4730c000}, {0x4730e000}, 
+    {0x47310000}, {0x47312000}, {0x47314000}, {0x47316000}, 
+    {0x47318000}, {0x4731a000}, {0x4731c000}, {0x4731e000}, 
+    {0x47320000}, {0x47322000}, {0x47324000}, {0x47326000}, 
+    {0x47328000}, {0x4732a000}, {0x4732c000}, {0x4732e000}, 
+    {0x47330000}, {0x47332000}, {0x47334000}, {0x47336000}, 
+    {0x47338000}, {0x4733a000}, {0x4733c000}, {0x4733e000}, 
+    {0x47340000}, {0x47342000}, {0x47344000}, {0x47346000}, 
+    {0x47348000}, {0x4734a000}, {0x4734c000}, {0x4734e000}, 
+    {0x47350000}, {0x47352000}, {0x47354000}, {0x47356000}, 
+    {0x47358000}, {0x4735a000}, {0x4735c000}, {0x4735e000}, 
+    {0x47360000}, {0x47362000}, {0x47364000}, {0x47366000}, 
+    {0x47368000}, {0x4736a000}, {0x4736c000}, {0x4736e000}, 
+    {0x47370000}, {0x47372000}, {0x47374000}, {0x47376000}, 
+    {0x47378000}, {0x4737a000}, {0x4737c000}, {0x4737e000}, 
+    {0x47380000}, {0x47382000}, {0x47384000}, {0x47386000}, 
+    {0x47388000}, {0x4738a000}, {0x4738c000}, {0x4738e000}, 
+    {0x47390000}, {0x47392000}, {0x47394000}, {0x47396000}, 
+    {0x47398000}, {0x4739a000}, {0x4739c000}, {0x4739e000}, 
+    {0x473a0000}, {0x473a2000}, {0x473a4000}, {0x473a6000}, 
+    {0x473a8000}, {0x473aa000}, {0x473ac000}, {0x473ae000}, 
+    {0x473b0000}, {0x473b2000}, {0x473b4000}, {0x473b6000}, 
+    {0x473b8000}, {0x473ba000}, {0x473bc000}, {0x473be000}, 
+    {0x473c0000}, {0x473c2000}, {0x473c4000}, {0x473c6000}, 
+    {0x473c8000}, {0x473ca000}, {0x473cc000}, {0x473ce000}, 
+    {0x473d0000}, {0x473d2000}, {0x473d4000}, {0x473d6000}, 
+    {0x473d8000}, {0x473da000}, {0x473dc000}, {0x473de000}, 
+    {0x473e0000}, {0x473e2000}, {0x473e4000}, {0x473e6000}, 
+    {0x473e8000}, {0x473ea000}, {0x473ec000}, {0x473ee000}, 
+    {0x473f0000}, {0x473f2000}, {0x473f4000}, {0x473f6000}, 
+    {0x473f8000}, {0x473fa000}, {0x473fc000}, {0x473fe000}, 
+    {0x47400000}, {0x47402000}, {0x47404000}, {0x47406000}, 
+    {0x47408000}, {0x4740a000}, {0x4740c000}, {0x4740e000}, 
+    {0x47410000}, {0x47412000}, {0x47414000}, {0x47416000}, 
+    {0x47418000}, {0x4741a000}, {0x4741c000}, {0x4741e000}, 
+    {0x47420000}, {0x47422000}, {0x47424000}, {0x47426000}, 
+    {0x47428000}, {0x4742a000}, {0x4742c000}, {0x4742e000}, 
+    {0x47430000}, {0x47432000}, {0x47434000}, {0x47436000}, 
+    {0x47438000}, {0x4743a000}, {0x4743c000}, {0x4743e000}, 
+    {0x47440000}, {0x47442000}, {0x47444000}, {0x47446000}, 
+    {0x47448000}, {0x4744a000}, {0x4744c000}, {0x4744e000}, 
+    {0x47450000}, {0x47452000}, {0x47454000}, {0x47456000}, 
+    {0x47458000}, {0x4745a000}, {0x4745c000}, {0x4745e000}, 
+    {0x47460000}, {0x47462000}, {0x47464000}, {0x47466000}, 
+    {0x47468000}, {0x4746a000}, {0x4746c000}, {0x4746e000}, 
+    {0x47470000}, {0x47472000}, {0x47474000}, {0x47476000}, 
+    {0x47478000}, {0x4747a000}, {0x4747c000}, {0x4747e000}, 
+    {0x47480000}, {0x47482000}, {0x47484000}, {0x47486000}, 
+    {0x47488000}, {0x4748a000}, {0x4748c000}, {0x4748e000}, 
+    {0x47490000}, {0x47492000}, {0x47494000}, {0x47496000}, 
+    {0x47498000}, {0x4749a000}, {0x4749c000}, {0x4749e000}, 
+    {0x474a0000}, {0x474a2000}, {0x474a4000}, {0x474a6000}, 
+    {0x474a8000}, {0x474aa000}, {0x474ac000}, {0x474ae000}, 
+    {0x474b0000}, {0x474b2000}, {0x474b4000}, {0x474b6000}, 
+    {0x474b8000}, {0x474ba000}, {0x474bc000}, {0x474be000}, 
+    {0x474c0000}, {0x474c2000}, {0x474c4000}, {0x474c6000}, 
+    {0x474c8000}, {0x474ca000}, {0x474cc000}, {0x474ce000}, 
+    {0x474d0000}, {0x474d2000}, {0x474d4000}, {0x474d6000}, 
+    {0x474d8000}, {0x474da000}, {0x474dc000}, {0x474de000}, 
+    {0x474e0000}, {0x474e2000}, {0x474e4000}, {0x474e6000}, 
+    {0x474e8000}, {0x474ea000}, {0x474ec000}, {0x474ee000}, 
+    {0x474f0000}, {0x474f2000}, {0x474f4000}, {0x474f6000}, 
+    {0x474f8000}, {0x474fa000}, {0x474fc000}, {0x474fe000}, 
+    {0x47500000}, {0x47502000}, {0x47504000}, {0x47506000}, 
+    {0x47508000}, {0x4750a000}, {0x4750c000}, {0x4750e000}, 
+    {0x47510000}, {0x47512000}, {0x47514000}, {0x47516000}, 
+    {0x47518000}, {0x4751a000}, {0x4751c000}, {0x4751e000}, 
+    {0x47520000}, {0x47522000}, {0x47524000}, {0x47526000}, 
+    {0x47528000}, {0x4752a000}, {0x4752c000}, {0x4752e000}, 
+    {0x47530000}, {0x47532000}, {0x47534000}, {0x47536000}, 
+    {0x47538000}, {0x4753a000}, {0x4753c000}, {0x4753e000}, 
+    {0x47540000}, {0x47542000}, {0x47544000}, {0x47546000}, 
+    {0x47548000}, {0x4754a000}, {0x4754c000}, {0x4754e000}, 
+    {0x47550000}, {0x47552000}, {0x47554000}, {0x47556000}, 
+    {0x47558000}, {0x4755a000}, {0x4755c000}, {0x4755e000}, 
+    {0x47560000}, {0x47562000}, {0x47564000}, {0x47566000}, 
+    {0x47568000}, {0x4756a000}, {0x4756c000}, {0x4756e000}, 
+    {0x47570000}, {0x47572000}, {0x47574000}, {0x47576000}, 
+    {0x47578000}, {0x4757a000}, {0x4757c000}, {0x4757e000}, 
+    {0x47580000}, {0x47582000}, {0x47584000}, {0x47586000}, 
+    {0x47588000}, {0x4758a000}, {0x4758c000}, {0x4758e000}, 
+    {0x47590000}, {0x47592000}, {0x47594000}, {0x47596000}, 
+    {0x47598000}, {0x4759a000}, {0x4759c000}, {0x4759e000}, 
+    {0x475a0000}, {0x475a2000}, {0x475a4000}, {0x475a6000}, 
+    {0x475a8000}, {0x475aa000}, {0x475ac000}, {0x475ae000}, 
+    {0x475b0000}, {0x475b2000}, {0x475b4000}, {0x475b6000}, 
+    {0x475b8000}, {0x475ba000}, {0x475bc000}, {0x475be000}, 
+    {0x475c0000}, {0x475c2000}, {0x475c4000}, {0x475c6000}, 
+    {0x475c8000}, {0x475ca000}, {0x475cc000}, {0x475ce000}, 
+    {0x475d0000}, {0x475d2000}, {0x475d4000}, {0x475d6000}, 
+    {0x475d8000}, {0x475da000}, {0x475dc000}, {0x475de000}, 
+    {0x475e0000}, {0x475e2000}, {0x475e4000}, {0x475e6000}, 
+    {0x475e8000}, {0x475ea000}, {0x475ec000}, {0x475ee000}, 
+    {0x475f0000}, {0x475f2000}, {0x475f4000}, {0x475f6000}, 
+    {0x475f8000}, {0x475fa000}, {0x475fc000}, {0x475fe000}, 
+    {0x47600000}, {0x47602000}, {0x47604000}, {0x47606000}, 
+    {0x47608000}, {0x4760a000}, {0x4760c000}, {0x4760e000}, 
+    {0x47610000}, {0x47612000}, {0x47614000}, {0x47616000}, 
+    {0x47618000}, {0x4761a000}, {0x4761c000}, {0x4761e000}, 
+    {0x47620000}, {0x47622000}, {0x47624000}, {0x47626000}, 
+    {0x47628000}, {0x4762a000}, {0x4762c000}, {0x4762e000}, 
+    {0x47630000}, {0x47632000}, {0x47634000}, {0x47636000}, 
+    {0x47638000}, {0x4763a000}, {0x4763c000}, {0x4763e000}, 
+    {0x47640000}, {0x47642000}, {0x47644000}, {0x47646000}, 
+    {0x47648000}, {0x4764a000}, {0x4764c000}, {0x4764e000}, 
+    {0x47650000}, {0x47652000}, {0x47654000}, {0x47656000}, 
+    {0x47658000}, {0x4765a000}, {0x4765c000}, {0x4765e000}, 
+    {0x47660000}, {0x47662000}, {0x47664000}, {0x47666000}, 
+    {0x47668000}, {0x4766a000}, {0x4766c000}, {0x4766e000}, 
+    {0x47670000}, {0x47672000}, {0x47674000}, {0x47676000}, 
+    {0x47678000}, {0x4767a000}, {0x4767c000}, {0x4767e000}, 
+    {0x47680000}, {0x47682000}, {0x47684000}, {0x47686000}, 
+    {0x47688000}, {0x4768a000}, {0x4768c000}, {0x4768e000}, 
+    {0x47690000}, {0x47692000}, {0x47694000}, {0x47696000}, 
+    {0x47698000}, {0x4769a000}, {0x4769c000}, {0x4769e000}, 
+    {0x476a0000}, {0x476a2000}, {0x476a4000}, {0x476a6000}, 
+    {0x476a8000}, {0x476aa000}, {0x476ac000}, {0x476ae000}, 
+    {0x476b0000}, {0x476b2000}, {0x476b4000}, {0x476b6000}, 
+    {0x476b8000}, {0x476ba000}, {0x476bc000}, {0x476be000}, 
+    {0x476c0000}, {0x476c2000}, {0x476c4000}, {0x476c6000}, 
+    {0x476c8000}, {0x476ca000}, {0x476cc000}, {0x476ce000}, 
+    {0x476d0000}, {0x476d2000}, {0x476d4000}, {0x476d6000}, 
+    {0x476d8000}, {0x476da000}, {0x476dc000}, {0x476de000}, 
+    {0x476e0000}, {0x476e2000}, {0x476e4000}, {0x476e6000}, 
+    {0x476e8000}, {0x476ea000}, {0x476ec000}, {0x476ee000}, 
+    {0x476f0000}, {0x476f2000}, {0x476f4000}, {0x476f6000}, 
+    {0x476f8000}, {0x476fa000}, {0x476fc000}, {0x476fe000}, 
+    {0x47700000}, {0x47702000}, {0x47704000}, {0x47706000}, 
+    {0x47708000}, {0x4770a000}, {0x4770c000}, {0x4770e000}, 
+    {0x47710000}, {0x47712000}, {0x47714000}, {0x47716000}, 
+    {0x47718000}, {0x4771a000}, {0x4771c000}, {0x4771e000}, 
+    {0x47720000}, {0x47722000}, {0x47724000}, {0x47726000}, 
+    {0x47728000}, {0x4772a000}, {0x4772c000}, {0x4772e000}, 
+    {0x47730000}, {0x47732000}, {0x47734000}, {0x47736000}, 
+    {0x47738000}, {0x4773a000}, {0x4773c000}, {0x4773e000}, 
+    {0x47740000}, {0x47742000}, {0x47744000}, {0x47746000}, 
+    {0x47748000}, {0x4774a000}, {0x4774c000}, {0x4774e000}, 
+    {0x47750000}, {0x47752000}, {0x47754000}, {0x47756000}, 
+    {0x47758000}, {0x4775a000}, {0x4775c000}, {0x4775e000}, 
+    {0x47760000}, {0x47762000}, {0x47764000}, {0x47766000}, 
+    {0x47768000}, {0x4776a000}, {0x4776c000}, {0x4776e000}, 
+    {0x47770000}, {0x47772000}, {0x47774000}, {0x47776000}, 
+    {0x47778000}, {0x4777a000}, {0x4777c000}, {0x4777e000}, 
+    {0x47780000}, {0x47782000}, {0x47784000}, {0x47786000}, 
+    {0x47788000}, {0x4778a000}, {0x4778c000}, {0x4778e000}, 
+    {0x47790000}, {0x47792000}, {0x47794000}, {0x47796000}, 
+    {0x47798000}, {0x4779a000}, {0x4779c000}, {0x4779e000}, 
+    {0x477a0000}, {0x477a2000}, {0x477a4000}, {0x477a6000}, 
+    {0x477a8000}, {0x477aa000}, {0x477ac000}, {0x477ae000}, 
+    {0x477b0000}, {0x477b2000}, {0x477b4000}, {0x477b6000}, 
+    {0x477b8000}, {0x477ba000}, {0x477bc000}, {0x477be000}, 
+    {0x477c0000}, {0x477c2000}, {0x477c4000}, {0x477c6000}, 
+    {0x477c8000}, {0x477ca000}, {0x477cc000}, {0x477ce000}, 
+    {0x477d0000}, {0x477d2000}, {0x477d4000}, {0x477d6000}, 
+    {0x477d8000}, {0x477da000}, {0x477dc000}, {0x477de000}, 
+    {0x477e0000}, {0x477e2000}, {0x477e4000}, {0x477e6000}, 
+    {0x477e8000}, {0x477ea000}, {0x477ec000}, {0x477ee000}, 
+    {0x477f0000}, {0x477f2000}, {0x477f4000}, {0x477f6000}, 
+    {0x477f8000}, {0x477fa000}, {0x477fc000}, {0x477fe000}, 
+    {0x7f800000}, {0x7f802000}, {0x7f804000}, {0x7f806000}, 
+    {0x7f808000}, {0x7f80a000}, {0x7f80c000}, {0x7f80e000}, 
+    {0x7f810000}, {0x7f812000}, {0x7f814000}, {0x7f816000}, 
+    {0x7f818000}, {0x7f81a000}, {0x7f81c000}, {0x7f81e000}, 
+    {0x7f820000}, {0x7f822000}, {0x7f824000}, {0x7f826000}, 
+    {0x7f828000}, {0x7f82a000}, {0x7f82c000}, {0x7f82e000}, 
+    {0x7f830000}, {0x7f832000}, {0x7f834000}, {0x7f836000}, 
+    {0x7f838000}, {0x7f83a000}, {0x7f83c000}, {0x7f83e000}, 
+    {0x7f840000}, {0x7f842000}, {0x7f844000}, {0x7f846000}, 
+    {0x7f848000}, {0x7f84a000}, {0x7f84c000}, {0x7f84e000}, 
+    {0x7f850000}, {0x7f852000}, {0x7f854000}, {0x7f856000}, 
+    {0x7f858000}, {0x7f85a000}, {0x7f85c000}, {0x7f85e000}, 
+    {0x7f860000}, {0x7f862000}, {0x7f864000}, {0x7f866000}, 
+    {0x7f868000}, {0x7f86a000}, {0x7f86c000}, {0x7f86e000}, 
+    {0x7f870000}, {0x7f872000}, {0x7f874000}, {0x7f876000}, 
+    {0x7f878000}, {0x7f87a000}, {0x7f87c000}, {0x7f87e000}, 
+    {0x7f880000}, {0x7f882000}, {0x7f884000}, {0x7f886000}, 
+    {0x7f888000}, {0x7f88a000}, {0x7f88c000}, {0x7f88e000}, 
+    {0x7f890000}, {0x7f892000}, {0x7f894000}, {0x7f896000}, 
+    {0x7f898000}, {0x7f89a000}, {0x7f89c000}, {0x7f89e000}, 
+    {0x7f8a0000}, {0x7f8a2000}, {0x7f8a4000}, {0x7f8a6000}, 
+    {0x7f8a8000}, {0x7f8aa000}, {0x7f8ac000}, {0x7f8ae000}, 
+    {0x7f8b0000}, {0x7f8b2000}, {0x7f8b4000}, {0x7f8b6000}, 
+    {0x7f8b8000}, {0x7f8ba000}, {0x7f8bc000}, {0x7f8be000}, 
+    {0x7f8c0000}, {0x7f8c2000}, {0x7f8c4000}, {0x7f8c6000}, 
+    {0x7f8c8000}, {0x7f8ca000}, {0x7f8cc000}, {0x7f8ce000}, 
+    {0x7f8d0000}, {0x7f8d2000}, {0x7f8d4000}, {0x7f8d6000}, 
+    {0x7f8d8000}, {0x7f8da000}, {0x7f8dc000}, {0x7f8de000}, 
+    {0x7f8e0000}, {0x7f8e2000}, {0x7f8e4000}, {0x7f8e6000}, 
+    {0x7f8e8000}, {0x7f8ea000}, {0x7f8ec000}, {0x7f8ee000}, 
+    {0x7f8f0000}, {0x7f8f2000}, {0x7f8f4000}, {0x7f8f6000}, 
+    {0x7f8f8000}, {0x7f8fa000}, {0x7f8fc000}, {0x7f8fe000}, 
+    {0x7f900000}, {0x7f902000}, {0x7f904000}, {0x7f906000}, 
+    {0x7f908000}, {0x7f90a000}, {0x7f90c000}, {0x7f90e000}, 
+    {0x7f910000}, {0x7f912000}, {0x7f914000}, {0x7f916000}, 
+    {0x7f918000}, {0x7f91a000}, {0x7f91c000}, {0x7f91e000}, 
+    {0x7f920000}, {0x7f922000}, {0x7f924000}, {0x7f926000}, 
+    {0x7f928000}, {0x7f92a000}, {0x7f92c000}, {0x7f92e000}, 
+    {0x7f930000}, {0x7f932000}, {0x7f934000}, {0x7f936000}, 
+    {0x7f938000}, {0x7f93a000}, {0x7f93c000}, {0x7f93e000}, 
+    {0x7f940000}, {0x7f942000}, {0x7f944000}, {0x7f946000}, 
+    {0x7f948000}, {0x7f94a000}, {0x7f94c000}, {0x7f94e000}, 
+    {0x7f950000}, {0x7f952000}, {0x7f954000}, {0x7f956000}, 
+    {0x7f958000}, {0x7f95a000}, {0x7f95c000}, {0x7f95e000}, 
+    {0x7f960000}, {0x7f962000}, {0x7f964000}, {0x7f966000}, 
+    {0x7f968000}, {0x7f96a000}, {0x7f96c000}, {0x7f96e000}, 
+    {0x7f970000}, {0x7f972000}, {0x7f974000}, {0x7f976000}, 
+    {0x7f978000}, {0x7f97a000}, {0x7f97c000}, {0x7f97e000}, 
+    {0x7f980000}, {0x7f982000}, {0x7f984000}, {0x7f986000}, 
+    {0x7f988000}, {0x7f98a000}, {0x7f98c000}, {0x7f98e000}, 
+    {0x7f990000}, {0x7f992000}, {0x7f994000}, {0x7f996000}, 
+    {0x7f998000}, {0x7f99a000}, {0x7f99c000}, {0x7f99e000}, 
+    {0x7f9a0000}, {0x7f9a2000}, {0x7f9a4000}, {0x7f9a6000}, 
+    {0x7f9a8000}, {0x7f9aa000}, {0x7f9ac000}, {0x7f9ae000}, 
+    {0x7f9b0000}, {0x7f9b2000}, {0x7f9b4000}, {0x7f9b6000}, 
+    {0x7f9b8000}, {0x7f9ba000}, {0x7f9bc000}, {0x7f9be000}, 
+    {0x7f9c0000}, {0x7f9c2000}, {0x7f9c4000}, {0x7f9c6000}, 
+    {0x7f9c8000}, {0x7f9ca000}, {0x7f9cc000}, {0x7f9ce000}, 
+    {0x7f9d0000}, {0x7f9d2000}, {0x7f9d4000}, {0x7f9d6000}, 
+    {0x7f9d8000}, {0x7f9da000}, {0x7f9dc000}, {0x7f9de000}, 
+    {0x7f9e0000}, {0x7f9e2000}, {0x7f9e4000}, {0x7f9e6000}, 
+    {0x7f9e8000}, {0x7f9ea000}, {0x7f9ec000}, {0x7f9ee000}, 
+    {0x7f9f0000}, {0x7f9f2000}, {0x7f9f4000}, {0x7f9f6000}, 
+    {0x7f9f8000}, {0x7f9fa000}, {0x7f9fc000}, {0x7f9fe000}, 
+    {0x7fa00000}, {0x7fa02000}, {0x7fa04000}, {0x7fa06000}, 
+    {0x7fa08000}, {0x7fa0a000}, {0x7fa0c000}, {0x7fa0e000}, 
+    {0x7fa10000}, {0x7fa12000}, {0x7fa14000}, {0x7fa16000}, 
+    {0x7fa18000}, {0x7fa1a000}, {0x7fa1c000}, {0x7fa1e000}, 
+    {0x7fa20000}, {0x7fa22000}, {0x7fa24000}, {0x7fa26000}, 
+    {0x7fa28000}, {0x7fa2a000}, {0x7fa2c000}, {0x7fa2e000}, 
+    {0x7fa30000}, {0x7fa32000}, {0x7fa34000}, {0x7fa36000}, 
+    {0x7fa38000}, {0x7fa3a000}, {0x7fa3c000}, {0x7fa3e000}, 
+    {0x7fa40000}, {0x7fa42000}, {0x7fa44000}, {0x7fa46000}, 
+    {0x7fa48000}, {0x7fa4a000}, {0x7fa4c000}, {0x7fa4e000}, 
+    {0x7fa50000}, {0x7fa52000}, {0x7fa54000}, {0x7fa56000}, 
+    {0x7fa58000}, {0x7fa5a000}, {0x7fa5c000}, {0x7fa5e000}, 
+    {0x7fa60000}, {0x7fa62000}, {0x7fa64000}, {0x7fa66000}, 
+    {0x7fa68000}, {0x7fa6a000}, {0x7fa6c000}, {0x7fa6e000}, 
+    {0x7fa70000}, {0x7fa72000}, {0x7fa74000}, {0x7fa76000}, 
+    {0x7fa78000}, {0x7fa7a000}, {0x7fa7c000}, {0x7fa7e000}, 
+    {0x7fa80000}, {0x7fa82000}, {0x7fa84000}, {0x7fa86000}, 
+    {0x7fa88000}, {0x7fa8a000}, {0x7fa8c000}, {0x7fa8e000}, 
+    {0x7fa90000}, {0x7fa92000}, {0x7fa94000}, {0x7fa96000}, 
+    {0x7fa98000}, {0x7fa9a000}, {0x7fa9c000}, {0x7fa9e000}, 
+    {0x7faa0000}, {0x7faa2000}, {0x7faa4000}, {0x7faa6000}, 
+    {0x7faa8000}, {0x7faaa000}, {0x7faac000}, {0x7faae000}, 
+    {0x7fab0000}, {0x7fab2000}, {0x7fab4000}, {0x7fab6000}, 
+    {0x7fab8000}, {0x7faba000}, {0x7fabc000}, {0x7fabe000}, 
+    {0x7fac0000}, {0x7fac2000}, {0x7fac4000}, {0x7fac6000}, 
+    {0x7fac8000}, {0x7faca000}, {0x7facc000}, {0x7face000}, 
+    {0x7fad0000}, {0x7fad2000}, {0x7fad4000}, {0x7fad6000}, 
+    {0x7fad8000}, {0x7fada000}, {0x7fadc000}, {0x7fade000}, 
+    {0x7fae0000}, {0x7fae2000}, {0x7fae4000}, {0x7fae6000}, 
+    {0x7fae8000}, {0x7faea000}, {0x7faec000}, {0x7faee000}, 
+    {0x7faf0000}, {0x7faf2000}, {0x7faf4000}, {0x7faf6000}, 
+    {0x7faf8000}, {0x7fafa000}, {0x7fafc000}, {0x7fafe000}, 
+    {0x7fb00000}, {0x7fb02000}, {0x7fb04000}, {0x7fb06000}, 
+    {0x7fb08000}, {0x7fb0a000}, {0x7fb0c000}, {0x7fb0e000}, 
+    {0x7fb10000}, {0x7fb12000}, {0x7fb14000}, {0x7fb16000}, 
+    {0x7fb18000}, {0x7fb1a000}, {0x7fb1c000}, {0x7fb1e000}, 
+    {0x7fb20000}, {0x7fb22000}, {0x7fb24000}, {0x7fb26000}, 
+    {0x7fb28000}, {0x7fb2a000}, {0x7fb2c000}, {0x7fb2e000}, 
+    {0x7fb30000}, {0x7fb32000}, {0x7fb34000}, {0x7fb36000}, 
+    {0x7fb38000}, {0x7fb3a000}, {0x7fb3c000}, {0x7fb3e000}, 
+    {0x7fb40000}, {0x7fb42000}, {0x7fb44000}, {0x7fb46000}, 
+    {0x7fb48000}, {0x7fb4a000}, {0x7fb4c000}, {0x7fb4e000}, 
+    {0x7fb50000}, {0x7fb52000}, {0x7fb54000}, {0x7fb56000}, 
+    {0x7fb58000}, {0x7fb5a000}, {0x7fb5c000}, {0x7fb5e000}, 
+    {0x7fb60000}, {0x7fb62000}, {0x7fb64000}, {0x7fb66000}, 
+    {0x7fb68000}, {0x7fb6a000}, {0x7fb6c000}, {0x7fb6e000}, 
+    {0x7fb70000}, {0x7fb72000}, {0x7fb74000}, {0x7fb76000}, 
+    {0x7fb78000}, {0x7fb7a000}, {0x7fb7c000}, {0x7fb7e000}, 
+    {0x7fb80000}, {0x7fb82000}, {0x7fb84000}, {0x7fb86000}, 
+    {0x7fb88000}, {0x7fb8a000}, {0x7fb8c000}, {0x7fb8e000}, 
+    {0x7fb90000}, {0x7fb92000}, {0x7fb94000}, {0x7fb96000}, 
+    {0x7fb98000}, {0x7fb9a000}, {0x7fb9c000}, {0x7fb9e000}, 
+    {0x7fba0000}, {0x7fba2000}, {0x7fba4000}, {0x7fba6000}, 
+    {0x7fba8000}, {0x7fbaa000}, {0x7fbac000}, {0x7fbae000}, 
+    {0x7fbb0000}, {0x7fbb2000}, {0x7fbb4000}, {0x7fbb6000}, 
+    {0x7fbb8000}, {0x7fbba000}, {0x7fbbc000}, {0x7fbbe000}, 
+    {0x7fbc0000}, {0x7fbc2000}, {0x7fbc4000}, {0x7fbc6000}, 
+    {0x7fbc8000}, {0x7fbca000}, {0x7fbcc000}, {0x7fbce000}, 
+    {0x7fbd0000}, {0x7fbd2000}, {0x7fbd4000}, {0x7fbd6000}, 
+    {0x7fbd8000}, {0x7fbda000}, {0x7fbdc000}, {0x7fbde000}, 
+    {0x7fbe0000}, {0x7fbe2000}, {0x7fbe4000}, {0x7fbe6000}, 
+    {0x7fbe8000}, {0x7fbea000}, {0x7fbec000}, {0x7fbee000}, 
+    {0x7fbf0000}, {0x7fbf2000}, {0x7fbf4000}, {0x7fbf6000}, 
+    {0x7fbf8000}, {0x7fbfa000}, {0x7fbfc000}, {0x7fbfe000}, 
+    {0x7fc00000}, {0x7fc02000}, {0x7fc04000}, {0x7fc06000}, 
+    {0x7fc08000}, {0x7fc0a000}, {0x7fc0c000}, {0x7fc0e000}, 
+    {0x7fc10000}, {0x7fc12000}, {0x7fc14000}, {0x7fc16000}, 
+    {0x7fc18000}, {0x7fc1a000}, {0x7fc1c000}, {0x7fc1e000}, 
+    {0x7fc20000}, {0x7fc22000}, {0x7fc24000}, {0x7fc26000}, 
+    {0x7fc28000}, {0x7fc2a000}, {0x7fc2c000}, {0x7fc2e000}, 
+    {0x7fc30000}, {0x7fc32000}, {0x7fc34000}, {0x7fc36000}, 
+    {0x7fc38000}, {0x7fc3a000}, {0x7fc3c000}, {0x7fc3e000}, 
+    {0x7fc40000}, {0x7fc42000}, {0x7fc44000}, {0x7fc46000}, 
+    {0x7fc48000}, {0x7fc4a000}, {0x7fc4c000}, {0x7fc4e000}, 
+    {0x7fc50000}, {0x7fc52000}, {0x7fc54000}, {0x7fc56000}, 
+    {0x7fc58000}, {0x7fc5a000}, {0x7fc5c000}, {0x7fc5e000}, 
+    {0x7fc60000}, {0x7fc62000}, {0x7fc64000}, {0x7fc66000}, 
+    {0x7fc68000}, {0x7fc6a000}, {0x7fc6c000}, {0x7fc6e000}, 
+    {0x7fc70000}, {0x7fc72000}, {0x7fc74000}, {0x7fc76000}, 
+    {0x7fc78000}, {0x7fc7a000}, {0x7fc7c000}, {0x7fc7e000}, 
+    {0x7fc80000}, {0x7fc82000}, {0x7fc84000}, {0x7fc86000}, 
+    {0x7fc88000}, {0x7fc8a000}, {0x7fc8c000}, {0x7fc8e000}, 
+    {0x7fc90000}, {0x7fc92000}, {0x7fc94000}, {0x7fc96000}, 
+    {0x7fc98000}, {0x7fc9a000}, {0x7fc9c000}, {0x7fc9e000}, 
+    {0x7fca0000}, {0x7fca2000}, {0x7fca4000}, {0x7fca6000}, 
+    {0x7fca8000}, {0x7fcaa000}, {0x7fcac000}, {0x7fcae000}, 
+    {0x7fcb0000}, {0x7fcb2000}, {0x7fcb4000}, {0x7fcb6000}, 
+    {0x7fcb8000}, {0x7fcba000}, {0x7fcbc000}, {0x7fcbe000}, 
+    {0x7fcc0000}, {0x7fcc2000}, {0x7fcc4000}, {0x7fcc6000}, 
+    {0x7fcc8000}, {0x7fcca000}, {0x7fccc000}, {0x7fcce000}, 
+    {0x7fcd0000}, {0x7fcd2000}, {0x7fcd4000}, {0x7fcd6000}, 
+    {0x7fcd8000}, {0x7fcda000}, {0x7fcdc000}, {0x7fcde000}, 
+    {0x7fce0000}, {0x7fce2000}, {0x7fce4000}, {0x7fce6000}, 
+    {0x7fce8000}, {0x7fcea000}, {0x7fcec000}, {0x7fcee000}, 
+    {0x7fcf0000}, {0x7fcf2000}, {0x7fcf4000}, {0x7fcf6000}, 
+    {0x7fcf8000}, {0x7fcfa000}, {0x7fcfc000}, {0x7fcfe000}, 
+    {0x7fd00000}, {0x7fd02000}, {0x7fd04000}, {0x7fd06000}, 
+    {0x7fd08000}, {0x7fd0a000}, {0x7fd0c000}, {0x7fd0e000}, 
+    {0x7fd10000}, {0x7fd12000}, {0x7fd14000}, {0x7fd16000}, 
+    {0x7fd18000}, {0x7fd1a000}, {0x7fd1c000}, {0x7fd1e000}, 
+    {0x7fd20000}, {0x7fd22000}, {0x7fd24000}, {0x7fd26000}, 
+    {0x7fd28000}, {0x7fd2a000}, {0x7fd2c000}, {0x7fd2e000}, 
+    {0x7fd30000}, {0x7fd32000}, {0x7fd34000}, {0x7fd36000}, 
+    {0x7fd38000}, {0x7fd3a000}, {0x7fd3c000}, {0x7fd3e000}, 
+    {0x7fd40000}, {0x7fd42000}, {0x7fd44000}, {0x7fd46000}, 
+    {0x7fd48000}, {0x7fd4a000}, {0x7fd4c000}, {0x7fd4e000}, 
+    {0x7fd50000}, {0x7fd52000}, {0x7fd54000}, {0x7fd56000}, 
+    {0x7fd58000}, {0x7fd5a000}, {0x7fd5c000}, {0x7fd5e000}, 
+    {0x7fd60000}, {0x7fd62000}, {0x7fd64000}, {0x7fd66000}, 
+    {0x7fd68000}, {0x7fd6a000}, {0x7fd6c000}, {0x7fd6e000}, 
+    {0x7fd70000}, {0x7fd72000}, {0x7fd74000}, {0x7fd76000}, 
+    {0x7fd78000}, {0x7fd7a000}, {0x7fd7c000}, {0x7fd7e000}, 
+    {0x7fd80000}, {0x7fd82000}, {0x7fd84000}, {0x7fd86000}, 
+    {0x7fd88000}, {0x7fd8a000}, {0x7fd8c000}, {0x7fd8e000}, 
+    {0x7fd90000}, {0x7fd92000}, {0x7fd94000}, {0x7fd96000}, 
+    {0x7fd98000}, {0x7fd9a000}, {0x7fd9c000}, {0x7fd9e000}, 
+    {0x7fda0000}, {0x7fda2000}, {0x7fda4000}, {0x7fda6000}, 
+    {0x7fda8000}, {0x7fdaa000}, {0x7fdac000}, {0x7fdae000}, 
+    {0x7fdb0000}, {0x7fdb2000}, {0x7fdb4000}, {0x7fdb6000}, 
+    {0x7fdb8000}, {0x7fdba000}, {0x7fdbc000}, {0x7fdbe000}, 
+    {0x7fdc0000}, {0x7fdc2000}, {0x7fdc4000}, {0x7fdc6000}, 
+    {0x7fdc8000}, {0x7fdca000}, {0x7fdcc000}, {0x7fdce000}, 
+    {0x7fdd0000}, {0x7fdd2000}, {0x7fdd4000}, {0x7fdd6000}, 
+    {0x7fdd8000}, {0x7fdda000}, {0x7fddc000}, {0x7fdde000}, 
+    {0x7fde0000}, {0x7fde2000}, {0x7fde4000}, {0x7fde6000}, 
+    {0x7fde8000}, {0x7fdea000}, {0x7fdec000}, {0x7fdee000}, 
+    {0x7fdf0000}, {0x7fdf2000}, {0x7fdf4000}, {0x7fdf6000}, 
+    {0x7fdf8000}, {0x7fdfa000}, {0x7fdfc000}, {0x7fdfe000}, 
+    {0x7fe00000}, {0x7fe02000}, {0x7fe04000}, {0x7fe06000}, 
+    {0x7fe08000}, {0x7fe0a000}, {0x7fe0c000}, {0x7fe0e000}, 
+    {0x7fe10000}, {0x7fe12000}, {0x7fe14000}, {0x7fe16000}, 
+    {0x7fe18000}, {0x7fe1a000}, {0x7fe1c000}, {0x7fe1e000}, 
+    {0x7fe20000}, {0x7fe22000}, {0x7fe24000}, {0x7fe26000}, 
+    {0x7fe28000}, {0x7fe2a000}, {0x7fe2c000}, {0x7fe2e000}, 
+    {0x7fe30000}, {0x7fe32000}, {0x7fe34000}, {0x7fe36000}, 
+    {0x7fe38000}, {0x7fe3a000}, {0x7fe3c000}, {0x7fe3e000}, 
+    {0x7fe40000}, {0x7fe42000}, {0x7fe44000}, {0x7fe46000}, 
+    {0x7fe48000}, {0x7fe4a000}, {0x7fe4c000}, {0x7fe4e000}, 
+    {0x7fe50000}, {0x7fe52000}, {0x7fe54000}, {0x7fe56000}, 
+    {0x7fe58000}, {0x7fe5a000}, {0x7fe5c000}, {0x7fe5e000}, 
+    {0x7fe60000}, {0x7fe62000}, {0x7fe64000}, {0x7fe66000}, 
+    {0x7fe68000}, {0x7fe6a000}, {0x7fe6c000}, {0x7fe6e000}, 
+    {0x7fe70000}, {0x7fe72000}, {0x7fe74000}, {0x7fe76000}, 
+    {0x7fe78000}, {0x7fe7a000}, {0x7fe7c000}, {0x7fe7e000}, 
+    {0x7fe80000}, {0x7fe82000}, {0x7fe84000}, {0x7fe86000}, 
+    {0x7fe88000}, {0x7fe8a000}, {0x7fe8c000}, {0x7fe8e000}, 
+    {0x7fe90000}, {0x7fe92000}, {0x7fe94000}, {0x7fe96000}, 
+    {0x7fe98000}, {0x7fe9a000}, {0x7fe9c000}, {0x7fe9e000}, 
+    {0x7fea0000}, {0x7fea2000}, {0x7fea4000}, {0x7fea6000}, 
+    {0x7fea8000}, {0x7feaa000}, {0x7feac000}, {0x7feae000}, 
+    {0x7feb0000}, {0x7feb2000}, {0x7feb4000}, {0x7feb6000}, 
+    {0x7feb8000}, {0x7feba000}, {0x7febc000}, {0x7febe000}, 
+    {0x7fec0000}, {0x7fec2000}, {0x7fec4000}, {0x7fec6000}, 
+    {0x7fec8000}, {0x7feca000}, {0x7fecc000}, {0x7fece000}, 
+    {0x7fed0000}, {0x7fed2000}, {0x7fed4000}, {0x7fed6000}, 
+    {0x7fed8000}, {0x7feda000}, {0x7fedc000}, {0x7fede000}, 
+    {0x7fee0000}, {0x7fee2000}, {0x7fee4000}, {0x7fee6000}, 
+    {0x7fee8000}, {0x7feea000}, {0x7feec000}, {0x7feee000}, 
+    {0x7fef0000}, {0x7fef2000}, {0x7fef4000}, {0x7fef6000}, 
+    {0x7fef8000}, {0x7fefa000}, {0x7fefc000}, {0x7fefe000}, 
+    {0x7ff00000}, {0x7ff02000}, {0x7ff04000}, {0x7ff06000}, 
+    {0x7ff08000}, {0x7ff0a000}, {0x7ff0c000}, {0x7ff0e000}, 
+    {0x7ff10000}, {0x7ff12000}, {0x7ff14000}, {0x7ff16000}, 
+    {0x7ff18000}, {0x7ff1a000}, {0x7ff1c000}, {0x7ff1e000}, 
+    {0x7ff20000}, {0x7ff22000}, {0x7ff24000}, {0x7ff26000}, 
+    {0x7ff28000}, {0x7ff2a000}, {0x7ff2c000}, {0x7ff2e000}, 
+    {0x7ff30000}, {0x7ff32000}, {0x7ff34000}, {0x7ff36000}, 
+    {0x7ff38000}, {0x7ff3a000}, {0x7ff3c000}, {0x7ff3e000}, 
+    {0x7ff40000}, {0x7ff42000}, {0x7ff44000}, {0x7ff46000}, 
+    {0x7ff48000}, {0x7ff4a000}, {0x7ff4c000}, {0x7ff4e000}, 
+    {0x7ff50000}, {0x7ff52000}, {0x7ff54000}, {0x7ff56000}, 
+    {0x7ff58000}, {0x7ff5a000}, {0x7ff5c000}, {0x7ff5e000}, 
+    {0x7ff60000}, {0x7ff62000}, {0x7ff64000}, {0x7ff66000}, 
+    {0x7ff68000}, {0x7ff6a000}, {0x7ff6c000}, {0x7ff6e000}, 
+    {0x7ff70000}, {0x7ff72000}, {0x7ff74000}, {0x7ff76000}, 
+    {0x7ff78000}, {0x7ff7a000}, {0x7ff7c000}, {0x7ff7e000}, 
+    {0x7ff80000}, {0x7ff82000}, {0x7ff84000}, {0x7ff86000}, 
+    {0x7ff88000}, {0x7ff8a000}, {0x7ff8c000}, {0x7ff8e000}, 
+    {0x7ff90000}, {0x7ff92000}, {0x7ff94000}, {0x7ff96000}, 
+    {0x7ff98000}, {0x7ff9a000}, {0x7ff9c000}, {0x7ff9e000}, 
+    {0x7ffa0000}, {0x7ffa2000}, {0x7ffa4000}, {0x7ffa6000}, 
+    {0x7ffa8000}, {0x7ffaa000}, {0x7ffac000}, {0x7ffae000}, 
+    {0x7ffb0000}, {0x7ffb2000}, {0x7ffb4000}, {0x7ffb6000}, 
+    {0x7ffb8000}, {0x7ffba000}, {0x7ffbc000}, {0x7ffbe000}, 
+    {0x7ffc0000}, {0x7ffc2000}, {0x7ffc4000}, {0x7ffc6000}, 
+    {0x7ffc8000}, {0x7ffca000}, {0x7ffcc000}, {0x7ffce000}, 
+    {0x7ffd0000}, {0x7ffd2000}, {0x7ffd4000}, {0x7ffd6000}, 
+    {0x7ffd8000}, {0x7ffda000}, {0x7ffdc000}, {0x7ffde000}, 
+    {0x7ffe0000}, {0x7ffe2000}, {0x7ffe4000}, {0x7ffe6000}, 
+    {0x7ffe8000}, {0x7ffea000}, {0x7ffec000}, {0x7ffee000}, 
+    {0x7fff0000}, {0x7fff2000}, {0x7fff4000}, {0x7fff6000}, 
+    {0x7fff8000}, {0x7fffa000}, {0x7fffc000}, {0x7fffe000}, 
+    {0x80000000}, {0xb3800000}, {0xb4000000}, {0xb4400000}, 
+    {0xb4800000}, {0xb4a00000}, {0xb4c00000}, {0xb4e00000}, 
+    {0xb5000000}, {0xb5100000}, {0xb5200000}, {0xb5300000}, 
+    {0xb5400000}, {0xb5500000}, {0xb5600000}, {0xb5700000}, 
+    {0xb5800000}, {0xb5880000}, {0xb5900000}, {0xb5980000}, 
+    {0xb5a00000}, {0xb5a80000}, {0xb5b00000}, {0xb5b80000}, 
+    {0xb5c00000}, {0xb5c80000}, {0xb5d00000}, {0xb5d80000}, 
+    {0xb5e00000}, {0xb5e80000}, {0xb5f00000}, {0xb5f80000}, 
+    {0xb6000000}, {0xb6040000}, {0xb6080000}, {0xb60c0000}, 
+    {0xb6100000}, {0xb6140000}, {0xb6180000}, {0xb61c0000}, 
+    {0xb6200000}, {0xb6240000}, {0xb6280000}, {0xb62c0000}, 
+    {0xb6300000}, {0xb6340000}, {0xb6380000}, {0xb63c0000}, 
+    {0xb6400000}, {0xb6440000}, {0xb6480000}, {0xb64c0000}, 
+    {0xb6500000}, {0xb6540000}, {0xb6580000}, {0xb65c0000}, 
+    {0xb6600000}, {0xb6640000}, {0xb6680000}, {0xb66c0000}, 
+    {0xb6700000}, {0xb6740000}, {0xb6780000}, {0xb67c0000}, 
+    {0xb6800000}, {0xb6820000}, {0xb6840000}, {0xb6860000}, 
+    {0xb6880000}, {0xb68a0000}, {0xb68c0000}, {0xb68e0000}, 
+    {0xb6900000}, {0xb6920000}, {0xb6940000}, {0xb6960000}, 
+    {0xb6980000}, {0xb69a0000}, {0xb69c0000}, {0xb69e0000}, 
+    {0xb6a00000}, {0xb6a20000}, {0xb6a40000}, {0xb6a60000}, 
+    {0xb6a80000}, {0xb6aa0000}, {0xb6ac0000}, {0xb6ae0000}, 
+    {0xb6b00000}, {0xb6b20000}, {0xb6b40000}, {0xb6b60000}, 
+    {0xb6b80000}, {0xb6ba0000}, {0xb6bc0000}, {0xb6be0000}, 
+    {0xb6c00000}, {0xb6c20000}, {0xb6c40000}, {0xb6c60000}, 
+    {0xb6c80000}, {0xb6ca0000}, {0xb6cc0000}, {0xb6ce0000}, 
+    {0xb6d00000}, {0xb6d20000}, {0xb6d40000}, {0xb6d60000}, 
+    {0xb6d80000}, {0xb6da0000}, {0xb6dc0000}, {0xb6de0000}, 
+    {0xb6e00000}, {0xb6e20000}, {0xb6e40000}, {0xb6e60000}, 
+    {0xb6e80000}, {0xb6ea0000}, {0xb6ec0000}, {0xb6ee0000}, 
+    {0xb6f00000}, {0xb6f20000}, {0xb6f40000}, {0xb6f60000}, 
+    {0xb6f80000}, {0xb6fa0000}, {0xb6fc0000}, {0xb6fe0000}, 
+    {0xb7000000}, {0xb7010000}, {0xb7020000}, {0xb7030000}, 
+    {0xb7040000}, {0xb7050000}, {0xb7060000}, {0xb7070000}, 
+    {0xb7080000}, {0xb7090000}, {0xb70a0000}, {0xb70b0000}, 
+    {0xb70c0000}, {0xb70d0000}, {0xb70e0000}, {0xb70f0000}, 
+    {0xb7100000}, {0xb7110000}, {0xb7120000}, {0xb7130000}, 
+    {0xb7140000}, {0xb7150000}, {0xb7160000}, {0xb7170000}, 
+    {0xb7180000}, {0xb7190000}, {0xb71a0000}, {0xb71b0000}, 
+    {0xb71c0000}, {0xb71d0000}, {0xb71e0000}, {0xb71f0000}, 
+    {0xb7200000}, {0xb7210000}, {0xb7220000}, {0xb7230000}, 
+    {0xb7240000}, {0xb7250000}, {0xb7260000}, {0xb7270000}, 
+    {0xb7280000}, {0xb7290000}, {0xb72a0000}, {0xb72b0000}, 
+    {0xb72c0000}, {0xb72d0000}, {0xb72e0000}, {0xb72f0000}, 
+    {0xb7300000}, {0xb7310000}, {0xb7320000}, {0xb7330000}, 
+    {0xb7340000}, {0xb7350000}, {0xb7360000}, {0xb7370000}, 
+    {0xb7380000}, {0xb7390000}, {0xb73a0000}, {0xb73b0000}, 
+    {0xb73c0000}, {0xb73d0000}, {0xb73e0000}, {0xb73f0000}, 
+    {0xb7400000}, {0xb7410000}, {0xb7420000}, {0xb7430000}, 
+    {0xb7440000}, {0xb7450000}, {0xb7460000}, {0xb7470000}, 
+    {0xb7480000}, {0xb7490000}, {0xb74a0000}, {0xb74b0000}, 
+    {0xb74c0000}, {0xb74d0000}, {0xb74e0000}, {0xb74f0000}, 
+    {0xb7500000}, {0xb7510000}, {0xb7520000}, {0xb7530000}, 
+    {0xb7540000}, {0xb7550000}, {0xb7560000}, {0xb7570000}, 
+    {0xb7580000}, {0xb7590000}, {0xb75a0000}, {0xb75b0000}, 
+    {0xb75c0000}, {0xb75d0000}, {0xb75e0000}, {0xb75f0000}, 
+    {0xb7600000}, {0xb7610000}, {0xb7620000}, {0xb7630000}, 
+    {0xb7640000}, {0xb7650000}, {0xb7660000}, {0xb7670000}, 
+    {0xb7680000}, {0xb7690000}, {0xb76a0000}, {0xb76b0000}, 
+    {0xb76c0000}, {0xb76d0000}, {0xb76e0000}, {0xb76f0000}, 
+    {0xb7700000}, {0xb7710000}, {0xb7720000}, {0xb7730000}, 
+    {0xb7740000}, {0xb7750000}, {0xb7760000}, {0xb7770000}, 
+    {0xb7780000}, {0xb7790000}, {0xb77a0000}, {0xb77b0000}, 
+    {0xb77c0000}, {0xb77d0000}, {0xb77e0000}, {0xb77f0000}, 
+    {0xb7800000}, {0xb7808000}, {0xb7810000}, {0xb7818000}, 
+    {0xb7820000}, {0xb7828000}, {0xb7830000}, {0xb7838000}, 
+    {0xb7840000}, {0xb7848000}, {0xb7850000}, {0xb7858000}, 
+    {0xb7860000}, {0xb7868000}, {0xb7870000}, {0xb7878000}, 
+    {0xb7880000}, {0xb7888000}, {0xb7890000}, {0xb7898000}, 
+    {0xb78a0000}, {0xb78a8000}, {0xb78b0000}, {0xb78b8000}, 
+    {0xb78c0000}, {0xb78c8000}, {0xb78d0000}, {0xb78d8000}, 
+    {0xb78e0000}, {0xb78e8000}, {0xb78f0000}, {0xb78f8000}, 
+    {0xb7900000}, {0xb7908000}, {0xb7910000}, {0xb7918000}, 
+    {0xb7920000}, {0xb7928000}, {0xb7930000}, {0xb7938000}, 
+    {0xb7940000}, {0xb7948000}, {0xb7950000}, {0xb7958000}, 
+    {0xb7960000}, {0xb7968000}, {0xb7970000}, {0xb7978000}, 
+    {0xb7980000}, {0xb7988000}, {0xb7990000}, {0xb7998000}, 
+    {0xb79a0000}, {0xb79a8000}, {0xb79b0000}, {0xb79b8000}, 
+    {0xb79c0000}, {0xb79c8000}, {0xb79d0000}, {0xb79d8000}, 
+    {0xb79e0000}, {0xb79e8000}, {0xb79f0000}, {0xb79f8000}, 
+    {0xb7a00000}, {0xb7a08000}, {0xb7a10000}, {0xb7a18000}, 
+    {0xb7a20000}, {0xb7a28000}, {0xb7a30000}, {0xb7a38000}, 
+    {0xb7a40000}, {0xb7a48000}, {0xb7a50000}, {0xb7a58000}, 
+    {0xb7a60000}, {0xb7a68000}, {0xb7a70000}, {0xb7a78000}, 
+    {0xb7a80000}, {0xb7a88000}, {0xb7a90000}, {0xb7a98000}, 
+    {0xb7aa0000}, {0xb7aa8000}, {0xb7ab0000}, {0xb7ab8000}, 
+    {0xb7ac0000}, {0xb7ac8000}, {0xb7ad0000}, {0xb7ad8000}, 
+    {0xb7ae0000}, {0xb7ae8000}, {0xb7af0000}, {0xb7af8000}, 
+    {0xb7b00000}, {0xb7b08000}, {0xb7b10000}, {0xb7b18000}, 
+    {0xb7b20000}, {0xb7b28000}, {0xb7b30000}, {0xb7b38000}, 
+    {0xb7b40000}, {0xb7b48000}, {0xb7b50000}, {0xb7b58000}, 
+    {0xb7b60000}, {0xb7b68000}, {0xb7b70000}, {0xb7b78000}, 
+    {0xb7b80000}, {0xb7b88000}, {0xb7b90000}, {0xb7b98000}, 
+    {0xb7ba0000}, {0xb7ba8000}, {0xb7bb0000}, {0xb7bb8000}, 
+    {0xb7bc0000}, {0xb7bc8000}, {0xb7bd0000}, {0xb7bd8000}, 
+    {0xb7be0000}, {0xb7be8000}, {0xb7bf0000}, {0xb7bf8000}, 
+    {0xb7c00000}, {0xb7c08000}, {0xb7c10000}, {0xb7c18000}, 
+    {0xb7c20000}, {0xb7c28000}, {0xb7c30000}, {0xb7c38000}, 
+    {0xb7c40000}, {0xb7c48000}, {0xb7c50000}, {0xb7c58000}, 
+    {0xb7c60000}, {0xb7c68000}, {0xb7c70000}, {0xb7c78000}, 
+    {0xb7c80000}, {0xb7c88000}, {0xb7c90000}, {0xb7c98000}, 
+    {0xb7ca0000}, {0xb7ca8000}, {0xb7cb0000}, {0xb7cb8000}, 
+    {0xb7cc0000}, {0xb7cc8000}, {0xb7cd0000}, {0xb7cd8000}, 
+    {0xb7ce0000}, {0xb7ce8000}, {0xb7cf0000}, {0xb7cf8000}, 
+    {0xb7d00000}, {0xb7d08000}, {0xb7d10000}, {0xb7d18000}, 
+    {0xb7d20000}, {0xb7d28000}, {0xb7d30000}, {0xb7d38000}, 
+    {0xb7d40000}, {0xb7d48000}, {0xb7d50000}, {0xb7d58000}, 
+    {0xb7d60000}, {0xb7d68000}, {0xb7d70000}, {0xb7d78000}, 
+    {0xb7d80000}, {0xb7d88000}, {0xb7d90000}, {0xb7d98000}, 
+    {0xb7da0000}, {0xb7da8000}, {0xb7db0000}, {0xb7db8000}, 
+    {0xb7dc0000}, {0xb7dc8000}, {0xb7dd0000}, {0xb7dd8000}, 
+    {0xb7de0000}, {0xb7de8000}, {0xb7df0000}, {0xb7df8000}, 
+    {0xb7e00000}, {0xb7e08000}, {0xb7e10000}, {0xb7e18000}, 
+    {0xb7e20000}, {0xb7e28000}, {0xb7e30000}, {0xb7e38000}, 
+    {0xb7e40000}, {0xb7e48000}, {0xb7e50000}, {0xb7e58000}, 
+    {0xb7e60000}, {0xb7e68000}, {0xb7e70000}, {0xb7e78000}, 
+    {0xb7e80000}, {0xb7e88000}, {0xb7e90000}, {0xb7e98000}, 
+    {0xb7ea0000}, {0xb7ea8000}, {0xb7eb0000}, {0xb7eb8000}, 
+    {0xb7ec0000}, {0xb7ec8000}, {0xb7ed0000}, {0xb7ed8000}, 
+    {0xb7ee0000}, {0xb7ee8000}, {0xb7ef0000}, {0xb7ef8000}, 
+    {0xb7f00000}, {0xb7f08000}, {0xb7f10000}, {0xb7f18000}, 
+    {0xb7f20000}, {0xb7f28000}, {0xb7f30000}, {0xb7f38000}, 
+    {0xb7f40000}, {0xb7f48000}, {0xb7f50000}, {0xb7f58000}, 
+    {0xb7f60000}, {0xb7f68000}, {0xb7f70000}, {0xb7f78000}, 
+    {0xb7f80000}, {0xb7f88000}, {0xb7f90000}, {0xb7f98000}, 
+    {0xb7fa0000}, {0xb7fa8000}, {0xb7fb0000}, {0xb7fb8000}, 
+    {0xb7fc0000}, {0xb7fc8000}, {0xb7fd0000}, {0xb7fd8000}, 
+    {0xb7fe0000}, {0xb7fe8000}, {0xb7ff0000}, {0xb7ff8000}, 
+    {0xb8000000}, {0xb8004000}, {0xb8008000}, {0xb800c000}, 
+    {0xb8010000}, {0xb8014000}, {0xb8018000}, {0xb801c000}, 
+    {0xb8020000}, {0xb8024000}, {0xb8028000}, {0xb802c000}, 
+    {0xb8030000}, {0xb8034000}, {0xb8038000}, {0xb803c000}, 
+    {0xb8040000}, {0xb8044000}, {0xb8048000}, {0xb804c000}, 
+    {0xb8050000}, {0xb8054000}, {0xb8058000}, {0xb805c000}, 
+    {0xb8060000}, {0xb8064000}, {0xb8068000}, {0xb806c000}, 
+    {0xb8070000}, {0xb8074000}, {0xb8078000}, {0xb807c000}, 
+    {0xb8080000}, {0xb8084000}, {0xb8088000}, {0xb808c000}, 
+    {0xb8090000}, {0xb8094000}, {0xb8098000}, {0xb809c000}, 
+    {0xb80a0000}, {0xb80a4000}, {0xb80a8000}, {0xb80ac000}, 
+    {0xb80b0000}, {0xb80b4000}, {0xb80b8000}, {0xb80bc000}, 
+    {0xb80c0000}, {0xb80c4000}, {0xb80c8000}, {0xb80cc000}, 
+    {0xb80d0000}, {0xb80d4000}, {0xb80d8000}, {0xb80dc000}, 
+    {0xb80e0000}, {0xb80e4000}, {0xb80e8000}, {0xb80ec000}, 
+    {0xb80f0000}, {0xb80f4000}, {0xb80f8000}, {0xb80fc000}, 
+    {0xb8100000}, {0xb8104000}, {0xb8108000}, {0xb810c000}, 
+    {0xb8110000}, {0xb8114000}, {0xb8118000}, {0xb811c000}, 
+    {0xb8120000}, {0xb8124000}, {0xb8128000}, {0xb812c000}, 
+    {0xb8130000}, {0xb8134000}, {0xb8138000}, {0xb813c000}, 
+    {0xb8140000}, {0xb8144000}, {0xb8148000}, {0xb814c000}, 
+    {0xb8150000}, {0xb8154000}, {0xb8158000}, {0xb815c000}, 
+    {0xb8160000}, {0xb8164000}, {0xb8168000}, {0xb816c000}, 
+    {0xb8170000}, {0xb8174000}, {0xb8178000}, {0xb817c000}, 
+    {0xb8180000}, {0xb8184000}, {0xb8188000}, {0xb818c000}, 
+    {0xb8190000}, {0xb8194000}, {0xb8198000}, {0xb819c000}, 
+    {0xb81a0000}, {0xb81a4000}, {0xb81a8000}, {0xb81ac000}, 
+    {0xb81b0000}, {0xb81b4000}, {0xb81b8000}, {0xb81bc000}, 
+    {0xb81c0000}, {0xb81c4000}, {0xb81c8000}, {0xb81cc000}, 
+    {0xb81d0000}, {0xb81d4000}, {0xb81d8000}, {0xb81dc000}, 
+    {0xb81e0000}, {0xb81e4000}, {0xb81e8000}, {0xb81ec000}, 
+    {0xb81f0000}, {0xb81f4000}, {0xb81f8000}, {0xb81fc000}, 
+    {0xb8200000}, {0xb8204000}, {0xb8208000}, {0xb820c000}, 
+    {0xb8210000}, {0xb8214000}, {0xb8218000}, {0xb821c000}, 
+    {0xb8220000}, {0xb8224000}, {0xb8228000}, {0xb822c000}, 
+    {0xb8230000}, {0xb8234000}, {0xb8238000}, {0xb823c000}, 
+    {0xb8240000}, {0xb8244000}, {0xb8248000}, {0xb824c000}, 
+    {0xb8250000}, {0xb8254000}, {0xb8258000}, {0xb825c000}, 
+    {0xb8260000}, {0xb8264000}, {0xb8268000}, {0xb826c000}, 
+    {0xb8270000}, {0xb8274000}, {0xb8278000}, {0xb827c000}, 
+    {0xb8280000}, {0xb8284000}, {0xb8288000}, {0xb828c000}, 
+    {0xb8290000}, {0xb8294000}, {0xb8298000}, {0xb829c000}, 
+    {0xb82a0000}, {0xb82a4000}, {0xb82a8000}, {0xb82ac000}, 
+    {0xb82b0000}, {0xb82b4000}, {0xb82b8000}, {0xb82bc000}, 
+    {0xb82c0000}, {0xb82c4000}, {0xb82c8000}, {0xb82cc000}, 
+    {0xb82d0000}, {0xb82d4000}, {0xb82d8000}, {0xb82dc000}, 
+    {0xb82e0000}, {0xb82e4000}, {0xb82e8000}, {0xb82ec000}, 
+    {0xb82f0000}, {0xb82f4000}, {0xb82f8000}, {0xb82fc000}, 
+    {0xb8300000}, {0xb8304000}, {0xb8308000}, {0xb830c000}, 
+    {0xb8310000}, {0xb8314000}, {0xb8318000}, {0xb831c000}, 
+    {0xb8320000}, {0xb8324000}, {0xb8328000}, {0xb832c000}, 
+    {0xb8330000}, {0xb8334000}, {0xb8338000}, {0xb833c000}, 
+    {0xb8340000}, {0xb8344000}, {0xb8348000}, {0xb834c000}, 
+    {0xb8350000}, {0xb8354000}, {0xb8358000}, {0xb835c000}, 
+    {0xb8360000}, {0xb8364000}, {0xb8368000}, {0xb836c000}, 
+    {0xb8370000}, {0xb8374000}, {0xb8378000}, {0xb837c000}, 
+    {0xb8380000}, {0xb8384000}, {0xb8388000}, {0xb838c000}, 
+    {0xb8390000}, {0xb8394000}, {0xb8398000}, {0xb839c000}, 
+    {0xb83a0000}, {0xb83a4000}, {0xb83a8000}, {0xb83ac000}, 
+    {0xb83b0000}, {0xb83b4000}, {0xb83b8000}, {0xb83bc000}, 
+    {0xb83c0000}, {0xb83c4000}, {0xb83c8000}, {0xb83cc000}, 
+    {0xb83d0000}, {0xb83d4000}, {0xb83d8000}, {0xb83dc000}, 
+    {0xb83e0000}, {0xb83e4000}, {0xb83e8000}, {0xb83ec000}, 
+    {0xb83f0000}, {0xb83f4000}, {0xb83f8000}, {0xb83fc000}, 
+    {0xb8400000}, {0xb8404000}, {0xb8408000}, {0xb840c000}, 
+    {0xb8410000}, {0xb8414000}, {0xb8418000}, {0xb841c000}, 
+    {0xb8420000}, {0xb8424000}, {0xb8428000}, {0xb842c000}, 
+    {0xb8430000}, {0xb8434000}, {0xb8438000}, {0xb843c000}, 
+    {0xb8440000}, {0xb8444000}, {0xb8448000}, {0xb844c000}, 
+    {0xb8450000}, {0xb8454000}, {0xb8458000}, {0xb845c000}, 
+    {0xb8460000}, {0xb8464000}, {0xb8468000}, {0xb846c000}, 
+    {0xb8470000}, {0xb8474000}, {0xb8478000}, {0xb847c000}, 
+    {0xb8480000}, {0xb8484000}, {0xb8488000}, {0xb848c000}, 
+    {0xb8490000}, {0xb8494000}, {0xb8498000}, {0xb849c000}, 
+    {0xb84a0000}, {0xb84a4000}, {0xb84a8000}, {0xb84ac000}, 
+    {0xb84b0000}, {0xb84b4000}, {0xb84b8000}, {0xb84bc000}, 
+    {0xb84c0000}, {0xb84c4000}, {0xb84c8000}, {0xb84cc000}, 
+    {0xb84d0000}, {0xb84d4000}, {0xb84d8000}, {0xb84dc000}, 
+    {0xb84e0000}, {0xb84e4000}, {0xb84e8000}, {0xb84ec000}, 
+    {0xb84f0000}, {0xb84f4000}, {0xb84f8000}, {0xb84fc000}, 
+    {0xb8500000}, {0xb8504000}, {0xb8508000}, {0xb850c000}, 
+    {0xb8510000}, {0xb8514000}, {0xb8518000}, {0xb851c000}, 
+    {0xb8520000}, {0xb8524000}, {0xb8528000}, {0xb852c000}, 
+    {0xb8530000}, {0xb8534000}, {0xb8538000}, {0xb853c000}, 
+    {0xb8540000}, {0xb8544000}, {0xb8548000}, {0xb854c000}, 
+    {0xb8550000}, {0xb8554000}, {0xb8558000}, {0xb855c000}, 
+    {0xb8560000}, {0xb8564000}, {0xb8568000}, {0xb856c000}, 
+    {0xb8570000}, {0xb8574000}, {0xb8578000}, {0xb857c000}, 
+    {0xb8580000}, {0xb8584000}, {0xb8588000}, {0xb858c000}, 
+    {0xb8590000}, {0xb8594000}, {0xb8598000}, {0xb859c000}, 
+    {0xb85a0000}, {0xb85a4000}, {0xb85a8000}, {0xb85ac000}, 
+    {0xb85b0000}, {0xb85b4000}, {0xb85b8000}, {0xb85bc000}, 
+    {0xb85c0000}, {0xb85c4000}, {0xb85c8000}, {0xb85cc000}, 
+    {0xb85d0000}, {0xb85d4000}, {0xb85d8000}, {0xb85dc000}, 
+    {0xb85e0000}, {0xb85e4000}, {0xb85e8000}, {0xb85ec000}, 
+    {0xb85f0000}, {0xb85f4000}, {0xb85f8000}, {0xb85fc000}, 
+    {0xb8600000}, {0xb8604000}, {0xb8608000}, {0xb860c000}, 
+    {0xb8610000}, {0xb8614000}, {0xb8618000}, {0xb861c000}, 
+    {0xb8620000}, {0xb8624000}, {0xb8628000}, {0xb862c000}, 
+    {0xb8630000}, {0xb8634000}, {0xb8638000}, {0xb863c000}, 
+    {0xb8640000}, {0xb8644000}, {0xb8648000}, {0xb864c000}, 
+    {0xb8650000}, {0xb8654000}, {0xb8658000}, {0xb865c000}, 
+    {0xb8660000}, {0xb8664000}, {0xb8668000}, {0xb866c000}, 
+    {0xb8670000}, {0xb8674000}, {0xb8678000}, {0xb867c000}, 
+    {0xb8680000}, {0xb8684000}, {0xb8688000}, {0xb868c000}, 
+    {0xb8690000}, {0xb8694000}, {0xb8698000}, {0xb869c000}, 
+    {0xb86a0000}, {0xb86a4000}, {0xb86a8000}, {0xb86ac000}, 
+    {0xb86b0000}, {0xb86b4000}, {0xb86b8000}, {0xb86bc000}, 
+    {0xb86c0000}, {0xb86c4000}, {0xb86c8000}, {0xb86cc000}, 
+    {0xb86d0000}, {0xb86d4000}, {0xb86d8000}, {0xb86dc000}, 
+    {0xb86e0000}, {0xb86e4000}, {0xb86e8000}, {0xb86ec000}, 
+    {0xb86f0000}, {0xb86f4000}, {0xb86f8000}, {0xb86fc000}, 
+    {0xb8700000}, {0xb8704000}, {0xb8708000}, {0xb870c000}, 
+    {0xb8710000}, {0xb8714000}, {0xb8718000}, {0xb871c000}, 
+    {0xb8720000}, {0xb8724000}, {0xb8728000}, {0xb872c000}, 
+    {0xb8730000}, {0xb8734000}, {0xb8738000}, {0xb873c000}, 
+    {0xb8740000}, {0xb8744000}, {0xb8748000}, {0xb874c000}, 
+    {0xb8750000}, {0xb8754000}, {0xb8758000}, {0xb875c000}, 
+    {0xb8760000}, {0xb8764000}, {0xb8768000}, {0xb876c000}, 
+    {0xb8770000}, {0xb8774000}, {0xb8778000}, {0xb877c000}, 
+    {0xb8780000}, {0xb8784000}, {0xb8788000}, {0xb878c000}, 
+    {0xb8790000}, {0xb8794000}, {0xb8798000}, {0xb879c000}, 
+    {0xb87a0000}, {0xb87a4000}, {0xb87a8000}, {0xb87ac000}, 
+    {0xb87b0000}, {0xb87b4000}, {0xb87b8000}, {0xb87bc000}, 
+    {0xb87c0000}, {0xb87c4000}, {0xb87c8000}, {0xb87cc000}, 
+    {0xb87d0000}, {0xb87d4000}, {0xb87d8000}, {0xb87dc000}, 
+    {0xb87e0000}, {0xb87e4000}, {0xb87e8000}, {0xb87ec000}, 
+    {0xb87f0000}, {0xb87f4000}, {0xb87f8000}, {0xb87fc000}, 
+    {0xb8800000}, {0xb8802000}, {0xb8804000}, {0xb8806000}, 
+    {0xb8808000}, {0xb880a000}, {0xb880c000}, {0xb880e000}, 
+    {0xb8810000}, {0xb8812000}, {0xb8814000}, {0xb8816000}, 
+    {0xb8818000}, {0xb881a000}, {0xb881c000}, {0xb881e000}, 
+    {0xb8820000}, {0xb8822000}, {0xb8824000}, {0xb8826000}, 
+    {0xb8828000}, {0xb882a000}, {0xb882c000}, {0xb882e000}, 
+    {0xb8830000}, {0xb8832000}, {0xb8834000}, {0xb8836000}, 
+    {0xb8838000}, {0xb883a000}, {0xb883c000}, {0xb883e000}, 
+    {0xb8840000}, {0xb8842000}, {0xb8844000}, {0xb8846000}, 
+    {0xb8848000}, {0xb884a000}, {0xb884c000}, {0xb884e000}, 
+    {0xb8850000}, {0xb8852000}, {0xb8854000}, {0xb8856000}, 
+    {0xb8858000}, {0xb885a000}, {0xb885c000}, {0xb885e000}, 
+    {0xb8860000}, {0xb8862000}, {0xb8864000}, {0xb8866000}, 
+    {0xb8868000}, {0xb886a000}, {0xb886c000}, {0xb886e000}, 
+    {0xb8870000}, {0xb8872000}, {0xb8874000}, {0xb8876000}, 
+    {0xb8878000}, {0xb887a000}, {0xb887c000}, {0xb887e000}, 
+    {0xb8880000}, {0xb8882000}, {0xb8884000}, {0xb8886000}, 
+    {0xb8888000}, {0xb888a000}, {0xb888c000}, {0xb888e000}, 
+    {0xb8890000}, {0xb8892000}, {0xb8894000}, {0xb8896000}, 
+    {0xb8898000}, {0xb889a000}, {0xb889c000}, {0xb889e000}, 
+    {0xb88a0000}, {0xb88a2000}, {0xb88a4000}, {0xb88a6000}, 
+    {0xb88a8000}, {0xb88aa000}, {0xb88ac000}, {0xb88ae000}, 
+    {0xb88b0000}, {0xb88b2000}, {0xb88b4000}, {0xb88b6000}, 
+    {0xb88b8000}, {0xb88ba000}, {0xb88bc000}, {0xb88be000}, 
+    {0xb88c0000}, {0xb88c2000}, {0xb88c4000}, {0xb88c6000}, 
+    {0xb88c8000}, {0xb88ca000}, {0xb88cc000}, {0xb88ce000}, 
+    {0xb88d0000}, {0xb88d2000}, {0xb88d4000}, {0xb88d6000}, 
+    {0xb88d8000}, {0xb88da000}, {0xb88dc000}, {0xb88de000}, 
+    {0xb88e0000}, {0xb88e2000}, {0xb88e4000}, {0xb88e6000}, 
+    {0xb88e8000}, {0xb88ea000}, {0xb88ec000}, {0xb88ee000}, 
+    {0xb88f0000}, {0xb88f2000}, {0xb88f4000}, {0xb88f6000}, 
+    {0xb88f8000}, {0xb88fa000}, {0xb88fc000}, {0xb88fe000}, 
+    {0xb8900000}, {0xb8902000}, {0xb8904000}, {0xb8906000}, 
+    {0xb8908000}, {0xb890a000}, {0xb890c000}, {0xb890e000}, 
+    {0xb8910000}, {0xb8912000}, {0xb8914000}, {0xb8916000}, 
+    {0xb8918000}, {0xb891a000}, {0xb891c000}, {0xb891e000}, 
+    {0xb8920000}, {0xb8922000}, {0xb8924000}, {0xb8926000}, 
+    {0xb8928000}, {0xb892a000}, {0xb892c000}, {0xb892e000}, 
+    {0xb8930000}, {0xb8932000}, {0xb8934000}, {0xb8936000}, 
+    {0xb8938000}, {0xb893a000}, {0xb893c000}, {0xb893e000}, 
+    {0xb8940000}, {0xb8942000}, {0xb8944000}, {0xb8946000}, 
+    {0xb8948000}, {0xb894a000}, {0xb894c000}, {0xb894e000}, 
+    {0xb8950000}, {0xb8952000}, {0xb8954000}, {0xb8956000}, 
+    {0xb8958000}, {0xb895a000}, {0xb895c000}, {0xb895e000}, 
+    {0xb8960000}, {0xb8962000}, {0xb8964000}, {0xb8966000}, 
+    {0xb8968000}, {0xb896a000}, {0xb896c000}, {0xb896e000}, 
+    {0xb8970000}, {0xb8972000}, {0xb8974000}, {0xb8976000}, 
+    {0xb8978000}, {0xb897a000}, {0xb897c000}, {0xb897e000}, 
+    {0xb8980000}, {0xb8982000}, {0xb8984000}, {0xb8986000}, 
+    {0xb8988000}, {0xb898a000}, {0xb898c000}, {0xb898e000}, 
+    {0xb8990000}, {0xb8992000}, {0xb8994000}, {0xb8996000}, 
+    {0xb8998000}, {0xb899a000}, {0xb899c000}, {0xb899e000}, 
+    {0xb89a0000}, {0xb89a2000}, {0xb89a4000}, {0xb89a6000}, 
+    {0xb89a8000}, {0xb89aa000}, {0xb89ac000}, {0xb89ae000}, 
+    {0xb89b0000}, {0xb89b2000}, {0xb89b4000}, {0xb89b6000}, 
+    {0xb89b8000}, {0xb89ba000}, {0xb89bc000}, {0xb89be000}, 
+    {0xb89c0000}, {0xb89c2000}, {0xb89c4000}, {0xb89c6000}, 
+    {0xb89c8000}, {0xb89ca000}, {0xb89cc000}, {0xb89ce000}, 
+    {0xb89d0000}, {0xb89d2000}, {0xb89d4000}, {0xb89d6000}, 
+    {0xb89d8000}, {0xb89da000}, {0xb89dc000}, {0xb89de000}, 
+    {0xb89e0000}, {0xb89e2000}, {0xb89e4000}, {0xb89e6000}, 
+    {0xb89e8000}, {0xb89ea000}, {0xb89ec000}, {0xb89ee000}, 
+    {0xb89f0000}, {0xb89f2000}, {0xb89f4000}, {0xb89f6000}, 
+    {0xb89f8000}, {0xb89fa000}, {0xb89fc000}, {0xb89fe000}, 
+    {0xb8a00000}, {0xb8a02000}, {0xb8a04000}, {0xb8a06000}, 
+    {0xb8a08000}, {0xb8a0a000}, {0xb8a0c000}, {0xb8a0e000}, 
+    {0xb8a10000}, {0xb8a12000}, {0xb8a14000}, {0xb8a16000}, 
+    {0xb8a18000}, {0xb8a1a000}, {0xb8a1c000}, {0xb8a1e000}, 
+    {0xb8a20000}, {0xb8a22000}, {0xb8a24000}, {0xb8a26000}, 
+    {0xb8a28000}, {0xb8a2a000}, {0xb8a2c000}, {0xb8a2e000}, 
+    {0xb8a30000}, {0xb8a32000}, {0xb8a34000}, {0xb8a36000}, 
+    {0xb8a38000}, {0xb8a3a000}, {0xb8a3c000}, {0xb8a3e000}, 
+    {0xb8a40000}, {0xb8a42000}, {0xb8a44000}, {0xb8a46000}, 
+    {0xb8a48000}, {0xb8a4a000}, {0xb8a4c000}, {0xb8a4e000}, 
+    {0xb8a50000}, {0xb8a52000}, {0xb8a54000}, {0xb8a56000}, 
+    {0xb8a58000}, {0xb8a5a000}, {0xb8a5c000}, {0xb8a5e000}, 
+    {0xb8a60000}, {0xb8a62000}, {0xb8a64000}, {0xb8a66000}, 
+    {0xb8a68000}, {0xb8a6a000}, {0xb8a6c000}, {0xb8a6e000}, 
+    {0xb8a70000}, {0xb8a72000}, {0xb8a74000}, {0xb8a76000}, 
+    {0xb8a78000}, {0xb8a7a000}, {0xb8a7c000}, {0xb8a7e000}, 
+    {0xb8a80000}, {0xb8a82000}, {0xb8a84000}, {0xb8a86000}, 
+    {0xb8a88000}, {0xb8a8a000}, {0xb8a8c000}, {0xb8a8e000}, 
+    {0xb8a90000}, {0xb8a92000}, {0xb8a94000}, {0xb8a96000}, 
+    {0xb8a98000}, {0xb8a9a000}, {0xb8a9c000}, {0xb8a9e000}, 
+    {0xb8aa0000}, {0xb8aa2000}, {0xb8aa4000}, {0xb8aa6000}, 
+    {0xb8aa8000}, {0xb8aaa000}, {0xb8aac000}, {0xb8aae000}, 
+    {0xb8ab0000}, {0xb8ab2000}, {0xb8ab4000}, {0xb8ab6000}, 
+    {0xb8ab8000}, {0xb8aba000}, {0xb8abc000}, {0xb8abe000}, 
+    {0xb8ac0000}, {0xb8ac2000}, {0xb8ac4000}, {0xb8ac6000}, 
+    {0xb8ac8000}, {0xb8aca000}, {0xb8acc000}, {0xb8ace000}, 
+    {0xb8ad0000}, {0xb8ad2000}, {0xb8ad4000}, {0xb8ad6000}, 
+    {0xb8ad8000}, {0xb8ada000}, {0xb8adc000}, {0xb8ade000}, 
+    {0xb8ae0000}, {0xb8ae2000}, {0xb8ae4000}, {0xb8ae6000}, 
+    {0xb8ae8000}, {0xb8aea000}, {0xb8aec000}, {0xb8aee000}, 
+    {0xb8af0000}, {0xb8af2000}, {0xb8af4000}, {0xb8af6000}, 
+    {0xb8af8000}, {0xb8afa000}, {0xb8afc000}, {0xb8afe000}, 
+    {0xb8b00000}, {0xb8b02000}, {0xb8b04000}, {0xb8b06000}, 
+    {0xb8b08000}, {0xb8b0a000}, {0xb8b0c000}, {0xb8b0e000}, 
+    {0xb8b10000}, {0xb8b12000}, {0xb8b14000}, {0xb8b16000}, 
+    {0xb8b18000}, {0xb8b1a000}, {0xb8b1c000}, {0xb8b1e000}, 
+    {0xb8b20000}, {0xb8b22000}, {0xb8b24000}, {0xb8b26000}, 
+    {0xb8b28000}, {0xb8b2a000}, {0xb8b2c000}, {0xb8b2e000}, 
+    {0xb8b30000}, {0xb8b32000}, {0xb8b34000}, {0xb8b36000}, 
+    {0xb8b38000}, {0xb8b3a000}, {0xb8b3c000}, {0xb8b3e000}, 
+    {0xb8b40000}, {0xb8b42000}, {0xb8b44000}, {0xb8b46000}, 
+    {0xb8b48000}, {0xb8b4a000}, {0xb8b4c000}, {0xb8b4e000}, 
+    {0xb8b50000}, {0xb8b52000}, {0xb8b54000}, {0xb8b56000}, 
+    {0xb8b58000}, {0xb8b5a000}, {0xb8b5c000}, {0xb8b5e000}, 
+    {0xb8b60000}, {0xb8b62000}, {0xb8b64000}, {0xb8b66000}, 
+    {0xb8b68000}, {0xb8b6a000}, {0xb8b6c000}, {0xb8b6e000}, 
+    {0xb8b70000}, {0xb8b72000}, {0xb8b74000}, {0xb8b76000}, 
+    {0xb8b78000}, {0xb8b7a000}, {0xb8b7c000}, {0xb8b7e000}, 
+    {0xb8b80000}, {0xb8b82000}, {0xb8b84000}, {0xb8b86000}, 
+    {0xb8b88000}, {0xb8b8a000}, {0xb8b8c000}, {0xb8b8e000}, 
+    {0xb8b90000}, {0xb8b92000}, {0xb8b94000}, {0xb8b96000}, 
+    {0xb8b98000}, {0xb8b9a000}, {0xb8b9c000}, {0xb8b9e000}, 
+    {0xb8ba0000}, {0xb8ba2000}, {0xb8ba4000}, {0xb8ba6000}, 
+    {0xb8ba8000}, {0xb8baa000}, {0xb8bac000}, {0xb8bae000}, 
+    {0xb8bb0000}, {0xb8bb2000}, {0xb8bb4000}, {0xb8bb6000}, 
+    {0xb8bb8000}, {0xb8bba000}, {0xb8bbc000}, {0xb8bbe000}, 
+    {0xb8bc0000}, {0xb8bc2000}, {0xb8bc4000}, {0xb8bc6000}, 
+    {0xb8bc8000}, {0xb8bca000}, {0xb8bcc000}, {0xb8bce000}, 
+    {0xb8bd0000}, {0xb8bd2000}, {0xb8bd4000}, {0xb8bd6000}, 
+    {0xb8bd8000}, {0xb8bda000}, {0xb8bdc000}, {0xb8bde000}, 
+    {0xb8be0000}, {0xb8be2000}, {0xb8be4000}, {0xb8be6000}, 
+    {0xb8be8000}, {0xb8bea000}, {0xb8bec000}, {0xb8bee000}, 
+    {0xb8bf0000}, {0xb8bf2000}, {0xb8bf4000}, {0xb8bf6000}, 
+    {0xb8bf8000}, {0xb8bfa000}, {0xb8bfc000}, {0xb8bfe000}, 
+    {0xb8c00000}, {0xb8c02000}, {0xb8c04000}, {0xb8c06000}, 
+    {0xb8c08000}, {0xb8c0a000}, {0xb8c0c000}, {0xb8c0e000}, 
+    {0xb8c10000}, {0xb8c12000}, {0xb8c14000}, {0xb8c16000}, 
+    {0xb8c18000}, {0xb8c1a000}, {0xb8c1c000}, {0xb8c1e000}, 
+    {0xb8c20000}, {0xb8c22000}, {0xb8c24000}, {0xb8c26000}, 
+    {0xb8c28000}, {0xb8c2a000}, {0xb8c2c000}, {0xb8c2e000}, 
+    {0xb8c30000}, {0xb8c32000}, {0xb8c34000}, {0xb8c36000}, 
+    {0xb8c38000}, {0xb8c3a000}, {0xb8c3c000}, {0xb8c3e000}, 
+    {0xb8c40000}, {0xb8c42000}, {0xb8c44000}, {0xb8c46000}, 
+    {0xb8c48000}, {0xb8c4a000}, {0xb8c4c000}, {0xb8c4e000}, 
+    {0xb8c50000}, {0xb8c52000}, {0xb8c54000}, {0xb8c56000}, 
+    {0xb8c58000}, {0xb8c5a000}, {0xb8c5c000}, {0xb8c5e000}, 
+    {0xb8c60000}, {0xb8c62000}, {0xb8c64000}, {0xb8c66000}, 
+    {0xb8c68000}, {0xb8c6a000}, {0xb8c6c000}, {0xb8c6e000}, 
+    {0xb8c70000}, {0xb8c72000}, {0xb8c74000}, {0xb8c76000}, 
+    {0xb8c78000}, {0xb8c7a000}, {0xb8c7c000}, {0xb8c7e000}, 
+    {0xb8c80000}, {0xb8c82000}, {0xb8c84000}, {0xb8c86000}, 
+    {0xb8c88000}, {0xb8c8a000}, {0xb8c8c000}, {0xb8c8e000}, 
+    {0xb8c90000}, {0xb8c92000}, {0xb8c94000}, {0xb8c96000}, 
+    {0xb8c98000}, {0xb8c9a000}, {0xb8c9c000}, {0xb8c9e000}, 
+    {0xb8ca0000}, {0xb8ca2000}, {0xb8ca4000}, {0xb8ca6000}, 
+    {0xb8ca8000}, {0xb8caa000}, {0xb8cac000}, {0xb8cae000}, 
+    {0xb8cb0000}, {0xb8cb2000}, {0xb8cb4000}, {0xb8cb6000}, 
+    {0xb8cb8000}, {0xb8cba000}, {0xb8cbc000}, {0xb8cbe000}, 
+    {0xb8cc0000}, {0xb8cc2000}, {0xb8cc4000}, {0xb8cc6000}, 
+    {0xb8cc8000}, {0xb8cca000}, {0xb8ccc000}, {0xb8cce000}, 
+    {0xb8cd0000}, {0xb8cd2000}, {0xb8cd4000}, {0xb8cd6000}, 
+    {0xb8cd8000}, {0xb8cda000}, {0xb8cdc000}, {0xb8cde000}, 
+    {0xb8ce0000}, {0xb8ce2000}, {0xb8ce4000}, {0xb8ce6000}, 
+    {0xb8ce8000}, {0xb8cea000}, {0xb8cec000}, {0xb8cee000}, 
+    {0xb8cf0000}, {0xb8cf2000}, {0xb8cf4000}, {0xb8cf6000}, 
+    {0xb8cf8000}, {0xb8cfa000}, {0xb8cfc000}, {0xb8cfe000}, 
+    {0xb8d00000}, {0xb8d02000}, {0xb8d04000}, {0xb8d06000}, 
+    {0xb8d08000}, {0xb8d0a000}, {0xb8d0c000}, {0xb8d0e000}, 
+    {0xb8d10000}, {0xb8d12000}, {0xb8d14000}, {0xb8d16000}, 
+    {0xb8d18000}, {0xb8d1a000}, {0xb8d1c000}, {0xb8d1e000}, 
+    {0xb8d20000}, {0xb8d22000}, {0xb8d24000}, {0xb8d26000}, 
+    {0xb8d28000}, {0xb8d2a000}, {0xb8d2c000}, {0xb8d2e000}, 
+    {0xb8d30000}, {0xb8d32000}, {0xb8d34000}, {0xb8d36000}, 
+    {0xb8d38000}, {0xb8d3a000}, {0xb8d3c000}, {0xb8d3e000}, 
+    {0xb8d40000}, {0xb8d42000}, {0xb8d44000}, {0xb8d46000}, 
+    {0xb8d48000}, {0xb8d4a000}, {0xb8d4c000}, {0xb8d4e000}, 
+    {0xb8d50000}, {0xb8d52000}, {0xb8d54000}, {0xb8d56000}, 
+    {0xb8d58000}, {0xb8d5a000}, {0xb8d5c000}, {0xb8d5e000}, 
+    {0xb8d60000}, {0xb8d62000}, {0xb8d64000}, {0xb8d66000}, 
+    {0xb8d68000}, {0xb8d6a000}, {0xb8d6c000}, {0xb8d6e000}, 
+    {0xb8d70000}, {0xb8d72000}, {0xb8d74000}, {0xb8d76000}, 
+    {0xb8d78000}, {0xb8d7a000}, {0xb8d7c000}, {0xb8d7e000}, 
+    {0xb8d80000}, {0xb8d82000}, {0xb8d84000}, {0xb8d86000}, 
+    {0xb8d88000}, {0xb8d8a000}, {0xb8d8c000}, {0xb8d8e000}, 
+    {0xb8d90000}, {0xb8d92000}, {0xb8d94000}, {0xb8d96000}, 
+    {0xb8d98000}, {0xb8d9a000}, {0xb8d9c000}, {0xb8d9e000}, 
+    {0xb8da0000}, {0xb8da2000}, {0xb8da4000}, {0xb8da6000}, 
+    {0xb8da8000}, {0xb8daa000}, {0xb8dac000}, {0xb8dae000}, 
+    {0xb8db0000}, {0xb8db2000}, {0xb8db4000}, {0xb8db6000}, 
+    {0xb8db8000}, {0xb8dba000}, {0xb8dbc000}, {0xb8dbe000}, 
+    {0xb8dc0000}, {0xb8dc2000}, {0xb8dc4000}, {0xb8dc6000}, 
+    {0xb8dc8000}, {0xb8dca000}, {0xb8dcc000}, {0xb8dce000}, 
+    {0xb8dd0000}, {0xb8dd2000}, {0xb8dd4000}, {0xb8dd6000}, 
+    {0xb8dd8000}, {0xb8dda000}, {0xb8ddc000}, {0xb8dde000}, 
+    {0xb8de0000}, {0xb8de2000}, {0xb8de4000}, {0xb8de6000}, 
+    {0xb8de8000}, {0xb8dea000}, {0xb8dec000}, {0xb8dee000}, 
+    {0xb8df0000}, {0xb8df2000}, {0xb8df4000}, {0xb8df6000}, 
+    {0xb8df8000}, {0xb8dfa000}, {0xb8dfc000}, {0xb8dfe000}, 
+    {0xb8e00000}, {0xb8e02000}, {0xb8e04000}, {0xb8e06000}, 
+    {0xb8e08000}, {0xb8e0a000}, {0xb8e0c000}, {0xb8e0e000}, 
+    {0xb8e10000}, {0xb8e12000}, {0xb8e14000}, {0xb8e16000}, 
+    {0xb8e18000}, {0xb8e1a000}, {0xb8e1c000}, {0xb8e1e000}, 
+    {0xb8e20000}, {0xb8e22000}, {0xb8e24000}, {0xb8e26000}, 
+    {0xb8e28000}, {0xb8e2a000}, {0xb8e2c000}, {0xb8e2e000}, 
+    {0xb8e30000}, {0xb8e32000}, {0xb8e34000}, {0xb8e36000}, 
+    {0xb8e38000}, {0xb8e3a000}, {0xb8e3c000}, {0xb8e3e000}, 
+    {0xb8e40000}, {0xb8e42000}, {0xb8e44000}, {0xb8e46000}, 
+    {0xb8e48000}, {0xb8e4a000}, {0xb8e4c000}, {0xb8e4e000}, 
+    {0xb8e50000}, {0xb8e52000}, {0xb8e54000}, {0xb8e56000}, 
+    {0xb8e58000}, {0xb8e5a000}, {0xb8e5c000}, {0xb8e5e000}, 
+    {0xb8e60000}, {0xb8e62000}, {0xb8e64000}, {0xb8e66000}, 
+    {0xb8e68000}, {0xb8e6a000}, {0xb8e6c000}, {0xb8e6e000}, 
+    {0xb8e70000}, {0xb8e72000}, {0xb8e74000}, {0xb8e76000}, 
+    {0xb8e78000}, {0xb8e7a000}, {0xb8e7c000}, {0xb8e7e000}, 
+    {0xb8e80000}, {0xb8e82000}, {0xb8e84000}, {0xb8e86000}, 
+    {0xb8e88000}, {0xb8e8a000}, {0xb8e8c000}, {0xb8e8e000}, 
+    {0xb8e90000}, {0xb8e92000}, {0xb8e94000}, {0xb8e96000}, 
+    {0xb8e98000}, {0xb8e9a000}, {0xb8e9c000}, {0xb8e9e000}, 
+    {0xb8ea0000}, {0xb8ea2000}, {0xb8ea4000}, {0xb8ea6000}, 
+    {0xb8ea8000}, {0xb8eaa000}, {0xb8eac000}, {0xb8eae000}, 
+    {0xb8eb0000}, {0xb8eb2000}, {0xb8eb4000}, {0xb8eb6000}, 
+    {0xb8eb8000}, {0xb8eba000}, {0xb8ebc000}, {0xb8ebe000}, 
+    {0xb8ec0000}, {0xb8ec2000}, {0xb8ec4000}, {0xb8ec6000}, 
+    {0xb8ec8000}, {0xb8eca000}, {0xb8ecc000}, {0xb8ece000}, 
+    {0xb8ed0000}, {0xb8ed2000}, {0xb8ed4000}, {0xb8ed6000}, 
+    {0xb8ed8000}, {0xb8eda000}, {0xb8edc000}, {0xb8ede000}, 
+    {0xb8ee0000}, {0xb8ee2000}, {0xb8ee4000}, {0xb8ee6000}, 
+    {0xb8ee8000}, {0xb8eea000}, {0xb8eec000}, {0xb8eee000}, 
+    {0xb8ef0000}, {0xb8ef2000}, {0xb8ef4000}, {0xb8ef6000}, 
+    {0xb8ef8000}, {0xb8efa000}, {0xb8efc000}, {0xb8efe000}, 
+    {0xb8f00000}, {0xb8f02000}, {0xb8f04000}, {0xb8f06000}, 
+    {0xb8f08000}, {0xb8f0a000}, {0xb8f0c000}, {0xb8f0e000}, 
+    {0xb8f10000}, {0xb8f12000}, {0xb8f14000}, {0xb8f16000}, 
+    {0xb8f18000}, {0xb8f1a000}, {0xb8f1c000}, {0xb8f1e000}, 
+    {0xb8f20000}, {0xb8f22000}, {0xb8f24000}, {0xb8f26000}, 
+    {0xb8f28000}, {0xb8f2a000}, {0xb8f2c000}, {0xb8f2e000}, 
+    {0xb8f30000}, {0xb8f32000}, {0xb8f34000}, {0xb8f36000}, 
+    {0xb8f38000}, {0xb8f3a000}, {0xb8f3c000}, {0xb8f3e000}, 
+    {0xb8f40000}, {0xb8f42000}, {0xb8f44000}, {0xb8f46000}, 
+    {0xb8f48000}, {0xb8f4a000}, {0xb8f4c000}, {0xb8f4e000}, 
+    {0xb8f50000}, {0xb8f52000}, {0xb8f54000}, {0xb8f56000}, 
+    {0xb8f58000}, {0xb8f5a000}, {0xb8f5c000}, {0xb8f5e000}, 
+    {0xb8f60000}, {0xb8f62000}, {0xb8f64000}, {0xb8f66000}, 
+    {0xb8f68000}, {0xb8f6a000}, {0xb8f6c000}, {0xb8f6e000}, 
+    {0xb8f70000}, {0xb8f72000}, {0xb8f74000}, {0xb8f76000}, 
+    {0xb8f78000}, {0xb8f7a000}, {0xb8f7c000}, {0xb8f7e000}, 
+    {0xb8f80000}, {0xb8f82000}, {0xb8f84000}, {0xb8f86000}, 
+    {0xb8f88000}, {0xb8f8a000}, {0xb8f8c000}, {0xb8f8e000}, 
+    {0xb8f90000}, {0xb8f92000}, {0xb8f94000}, {0xb8f96000}, 
+    {0xb8f98000}, {0xb8f9a000}, {0xb8f9c000}, {0xb8f9e000}, 
+    {0xb8fa0000}, {0xb8fa2000}, {0xb8fa4000}, {0xb8fa6000}, 
+    {0xb8fa8000}, {0xb8faa000}, {0xb8fac000}, {0xb8fae000}, 
+    {0xb8fb0000}, {0xb8fb2000}, {0xb8fb4000}, {0xb8fb6000}, 
+    {0xb8fb8000}, {0xb8fba000}, {0xb8fbc000}, {0xb8fbe000}, 
+    {0xb8fc0000}, {0xb8fc2000}, {0xb8fc4000}, {0xb8fc6000}, 
+    {0xb8fc8000}, {0xb8fca000}, {0xb8fcc000}, {0xb8fce000}, 
+    {0xb8fd0000}, {0xb8fd2000}, {0xb8fd4000}, {0xb8fd6000}, 
+    {0xb8fd8000}, {0xb8fda000}, {0xb8fdc000}, {0xb8fde000}, 
+    {0xb8fe0000}, {0xb8fe2000}, {0xb8fe4000}, {0xb8fe6000}, 
+    {0xb8fe8000}, {0xb8fea000}, {0xb8fec000}, {0xb8fee000}, 
+    {0xb8ff0000}, {0xb8ff2000}, {0xb8ff4000}, {0xb8ff6000}, 
+    {0xb8ff8000}, {0xb8ffa000}, {0xb8ffc000}, {0xb8ffe000}, 
+    {0xb9000000}, {0xb9002000}, {0xb9004000}, {0xb9006000}, 
+    {0xb9008000}, {0xb900a000}, {0xb900c000}, {0xb900e000}, 
+    {0xb9010000}, {0xb9012000}, {0xb9014000}, {0xb9016000}, 
+    {0xb9018000}, {0xb901a000}, {0xb901c000}, {0xb901e000}, 
+    {0xb9020000}, {0xb9022000}, {0xb9024000}, {0xb9026000}, 
+    {0xb9028000}, {0xb902a000}, {0xb902c000}, {0xb902e000}, 
+    {0xb9030000}, {0xb9032000}, {0xb9034000}, {0xb9036000}, 
+    {0xb9038000}, {0xb903a000}, {0xb903c000}, {0xb903e000}, 
+    {0xb9040000}, {0xb9042000}, {0xb9044000}, {0xb9046000}, 
+    {0xb9048000}, {0xb904a000}, {0xb904c000}, {0xb904e000}, 
+    {0xb9050000}, {0xb9052000}, {0xb9054000}, {0xb9056000}, 
+    {0xb9058000}, {0xb905a000}, {0xb905c000}, {0xb905e000}, 
+    {0xb9060000}, {0xb9062000}, {0xb9064000}, {0xb9066000}, 
+    {0xb9068000}, {0xb906a000}, {0xb906c000}, {0xb906e000}, 
+    {0xb9070000}, {0xb9072000}, {0xb9074000}, {0xb9076000}, 
+    {0xb9078000}, {0xb907a000}, {0xb907c000}, {0xb907e000}, 
+    {0xb9080000}, {0xb9082000}, {0xb9084000}, {0xb9086000}, 
+    {0xb9088000}, {0xb908a000}, {0xb908c000}, {0xb908e000}, 
+    {0xb9090000}, {0xb9092000}, {0xb9094000}, {0xb9096000}, 
+    {0xb9098000}, {0xb909a000}, {0xb909c000}, {0xb909e000}, 
+    {0xb90a0000}, {0xb90a2000}, {0xb90a4000}, {0xb90a6000}, 
+    {0xb90a8000}, {0xb90aa000}, {0xb90ac000}, {0xb90ae000}, 
+    {0xb90b0000}, {0xb90b2000}, {0xb90b4000}, {0xb90b6000}, 
+    {0xb90b8000}, {0xb90ba000}, {0xb90bc000}, {0xb90be000}, 
+    {0xb90c0000}, {0xb90c2000}, {0xb90c4000}, {0xb90c6000}, 
+    {0xb90c8000}, {0xb90ca000}, {0xb90cc000}, {0xb90ce000}, 
+    {0xb90d0000}, {0xb90d2000}, {0xb90d4000}, {0xb90d6000}, 
+    {0xb90d8000}, {0xb90da000}, {0xb90dc000}, {0xb90de000}, 
+    {0xb90e0000}, {0xb90e2000}, {0xb90e4000}, {0xb90e6000}, 
+    {0xb90e8000}, {0xb90ea000}, {0xb90ec000}, {0xb90ee000}, 
+    {0xb90f0000}, {0xb90f2000}, {0xb90f4000}, {0xb90f6000}, 
+    {0xb90f8000}, {0xb90fa000}, {0xb90fc000}, {0xb90fe000}, 
+    {0xb9100000}, {0xb9102000}, {0xb9104000}, {0xb9106000}, 
+    {0xb9108000}, {0xb910a000}, {0xb910c000}, {0xb910e000}, 
+    {0xb9110000}, {0xb9112000}, {0xb9114000}, {0xb9116000}, 
+    {0xb9118000}, {0xb911a000}, {0xb911c000}, {0xb911e000}, 
+    {0xb9120000}, {0xb9122000}, {0xb9124000}, {0xb9126000}, 
+    {0xb9128000}, {0xb912a000}, {0xb912c000}, {0xb912e000}, 
+    {0xb9130000}, {0xb9132000}, {0xb9134000}, {0xb9136000}, 
+    {0xb9138000}, {0xb913a000}, {0xb913c000}, {0xb913e000}, 
+    {0xb9140000}, {0xb9142000}, {0xb9144000}, {0xb9146000}, 
+    {0xb9148000}, {0xb914a000}, {0xb914c000}, {0xb914e000}, 
+    {0xb9150000}, {0xb9152000}, {0xb9154000}, {0xb9156000}, 
+    {0xb9158000}, {0xb915a000}, {0xb915c000}, {0xb915e000}, 
+    {0xb9160000}, {0xb9162000}, {0xb9164000}, {0xb9166000}, 
+    {0xb9168000}, {0xb916a000}, {0xb916c000}, {0xb916e000}, 
+    {0xb9170000}, {0xb9172000}, {0xb9174000}, {0xb9176000}, 
+    {0xb9178000}, {0xb917a000}, {0xb917c000}, {0xb917e000}, 
+    {0xb9180000}, {0xb9182000}, {0xb9184000}, {0xb9186000}, 
+    {0xb9188000}, {0xb918a000}, {0xb918c000}, {0xb918e000}, 
+    {0xb9190000}, {0xb9192000}, {0xb9194000}, {0xb9196000}, 
+    {0xb9198000}, {0xb919a000}, {0xb919c000}, {0xb919e000}, 
+    {0xb91a0000}, {0xb91a2000}, {0xb91a4000}, {0xb91a6000}, 
+    {0xb91a8000}, {0xb91aa000}, {0xb91ac000}, {0xb91ae000}, 
+    {0xb91b0000}, {0xb91b2000}, {0xb91b4000}, {0xb91b6000}, 
+    {0xb91b8000}, {0xb91ba000}, {0xb91bc000}, {0xb91be000}, 
+    {0xb91c0000}, {0xb91c2000}, {0xb91c4000}, {0xb91c6000}, 
+    {0xb91c8000}, {0xb91ca000}, {0xb91cc000}, {0xb91ce000}, 
+    {0xb91d0000}, {0xb91d2000}, {0xb91d4000}, {0xb91d6000}, 
+    {0xb91d8000}, {0xb91da000}, {0xb91dc000}, {0xb91de000}, 
+    {0xb91e0000}, {0xb91e2000}, {0xb91e4000}, {0xb91e6000}, 
+    {0xb91e8000}, {0xb91ea000}, {0xb91ec000}, {0xb91ee000}, 
+    {0xb91f0000}, {0xb91f2000}, {0xb91f4000}, {0xb91f6000}, 
+    {0xb91f8000}, {0xb91fa000}, {0xb91fc000}, {0xb91fe000}, 
+    {0xb9200000}, {0xb9202000}, {0xb9204000}, {0xb9206000}, 
+    {0xb9208000}, {0xb920a000}, {0xb920c000}, {0xb920e000}, 
+    {0xb9210000}, {0xb9212000}, {0xb9214000}, {0xb9216000}, 
+    {0xb9218000}, {0xb921a000}, {0xb921c000}, {0xb921e000}, 
+    {0xb9220000}, {0xb9222000}, {0xb9224000}, {0xb9226000}, 
+    {0xb9228000}, {0xb922a000}, {0xb922c000}, {0xb922e000}, 
+    {0xb9230000}, {0xb9232000}, {0xb9234000}, {0xb9236000}, 
+    {0xb9238000}, {0xb923a000}, {0xb923c000}, {0xb923e000}, 
+    {0xb9240000}, {0xb9242000}, {0xb9244000}, {0xb9246000}, 
+    {0xb9248000}, {0xb924a000}, {0xb924c000}, {0xb924e000}, 
+    {0xb9250000}, {0xb9252000}, {0xb9254000}, {0xb9256000}, 
+    {0xb9258000}, {0xb925a000}, {0xb925c000}, {0xb925e000}, 
+    {0xb9260000}, {0xb9262000}, {0xb9264000}, {0xb9266000}, 
+    {0xb9268000}, {0xb926a000}, {0xb926c000}, {0xb926e000}, 
+    {0xb9270000}, {0xb9272000}, {0xb9274000}, {0xb9276000}, 
+    {0xb9278000}, {0xb927a000}, {0xb927c000}, {0xb927e000}, 
+    {0xb9280000}, {0xb9282000}, {0xb9284000}, {0xb9286000}, 
+    {0xb9288000}, {0xb928a000}, {0xb928c000}, {0xb928e000}, 
+    {0xb9290000}, {0xb9292000}, {0xb9294000}, {0xb9296000}, 
+    {0xb9298000}, {0xb929a000}, {0xb929c000}, {0xb929e000}, 
+    {0xb92a0000}, {0xb92a2000}, {0xb92a4000}, {0xb92a6000}, 
+    {0xb92a8000}, {0xb92aa000}, {0xb92ac000}, {0xb92ae000}, 
+    {0xb92b0000}, {0xb92b2000}, {0xb92b4000}, {0xb92b6000}, 
+    {0xb92b8000}, {0xb92ba000}, {0xb92bc000}, {0xb92be000}, 
+    {0xb92c0000}, {0xb92c2000}, {0xb92c4000}, {0xb92c6000}, 
+    {0xb92c8000}, {0xb92ca000}, {0xb92cc000}, {0xb92ce000}, 
+    {0xb92d0000}, {0xb92d2000}, {0xb92d4000}, {0xb92d6000}, 
+    {0xb92d8000}, {0xb92da000}, {0xb92dc000}, {0xb92de000}, 
+    {0xb92e0000}, {0xb92e2000}, {0xb92e4000}, {0xb92e6000}, 
+    {0xb92e8000}, {0xb92ea000}, {0xb92ec000}, {0xb92ee000}, 
+    {0xb92f0000}, {0xb92f2000}, {0xb92f4000}, {0xb92f6000}, 
+    {0xb92f8000}, {0xb92fa000}, {0xb92fc000}, {0xb92fe000}, 
+    {0xb9300000}, {0xb9302000}, {0xb9304000}, {0xb9306000}, 
+    {0xb9308000}, {0xb930a000}, {0xb930c000}, {0xb930e000}, 
+    {0xb9310000}, {0xb9312000}, {0xb9314000}, {0xb9316000}, 
+    {0xb9318000}, {0xb931a000}, {0xb931c000}, {0xb931e000}, 
+    {0xb9320000}, {0xb9322000}, {0xb9324000}, {0xb9326000}, 
+    {0xb9328000}, {0xb932a000}, {0xb932c000}, {0xb932e000}, 
+    {0xb9330000}, {0xb9332000}, {0xb9334000}, {0xb9336000}, 
+    {0xb9338000}, {0xb933a000}, {0xb933c000}, {0xb933e000}, 
+    {0xb9340000}, {0xb9342000}, {0xb9344000}, {0xb9346000}, 
+    {0xb9348000}, {0xb934a000}, {0xb934c000}, {0xb934e000}, 
+    {0xb9350000}, {0xb9352000}, {0xb9354000}, {0xb9356000}, 
+    {0xb9358000}, {0xb935a000}, {0xb935c000}, {0xb935e000}, 
+    {0xb9360000}, {0xb9362000}, {0xb9364000}, {0xb9366000}, 
+    {0xb9368000}, {0xb936a000}, {0xb936c000}, {0xb936e000}, 
+    {0xb9370000}, {0xb9372000}, {0xb9374000}, {0xb9376000}, 
+    {0xb9378000}, {0xb937a000}, {0xb937c000}, {0xb937e000}, 
+    {0xb9380000}, {0xb9382000}, {0xb9384000}, {0xb9386000}, 
+    {0xb9388000}, {0xb938a000}, {0xb938c000}, {0xb938e000}, 
+    {0xb9390000}, {0xb9392000}, {0xb9394000}, {0xb9396000}, 
+    {0xb9398000}, {0xb939a000}, {0xb939c000}, {0xb939e000}, 
+    {0xb93a0000}, {0xb93a2000}, {0xb93a4000}, {0xb93a6000}, 
+    {0xb93a8000}, {0xb93aa000}, {0xb93ac000}, {0xb93ae000}, 
+    {0xb93b0000}, {0xb93b2000}, {0xb93b4000}, {0xb93b6000}, 
+    {0xb93b8000}, {0xb93ba000}, {0xb93bc000}, {0xb93be000}, 
+    {0xb93c0000}, {0xb93c2000}, {0xb93c4000}, {0xb93c6000}, 
+    {0xb93c8000}, {0xb93ca000}, {0xb93cc000}, {0xb93ce000}, 
+    {0xb93d0000}, {0xb93d2000}, {0xb93d4000}, {0xb93d6000}, 
+    {0xb93d8000}, {0xb93da000}, {0xb93dc000}, {0xb93de000}, 
+    {0xb93e0000}, {0xb93e2000}, {0xb93e4000}, {0xb93e6000}, 
+    {0xb93e8000}, {0xb93ea000}, {0xb93ec000}, {0xb93ee000}, 
+    {0xb93f0000}, {0xb93f2000}, {0xb93f4000}, {0xb93f6000}, 
+    {0xb93f8000}, {0xb93fa000}, {0xb93fc000}, {0xb93fe000}, 
+    {0xb9400000}, {0xb9402000}, {0xb9404000}, {0xb9406000}, 
+    {0xb9408000}, {0xb940a000}, {0xb940c000}, {0xb940e000}, 
+    {0xb9410000}, {0xb9412000}, {0xb9414000}, {0xb9416000}, 
+    {0xb9418000}, {0xb941a000}, {0xb941c000}, {0xb941e000}, 
+    {0xb9420000}, {0xb9422000}, {0xb9424000}, {0xb9426000}, 
+    {0xb9428000}, {0xb942a000}, {0xb942c000}, {0xb942e000}, 
+    {0xb9430000}, {0xb9432000}, {0xb9434000}, {0xb9436000}, 
+    {0xb9438000}, {0xb943a000}, {0xb943c000}, {0xb943e000}, 
+    {0xb9440000}, {0xb9442000}, {0xb9444000}, {0xb9446000}, 
+    {0xb9448000}, {0xb944a000}, {0xb944c000}, {0xb944e000}, 
+    {0xb9450000}, {0xb9452000}, {0xb9454000}, {0xb9456000}, 
+    {0xb9458000}, {0xb945a000}, {0xb945c000}, {0xb945e000}, 
+    {0xb9460000}, {0xb9462000}, {0xb9464000}, {0xb9466000}, 
+    {0xb9468000}, {0xb946a000}, {0xb946c000}, {0xb946e000}, 
+    {0xb9470000}, {0xb9472000}, {0xb9474000}, {0xb9476000}, 
+    {0xb9478000}, {0xb947a000}, {0xb947c000}, {0xb947e000}, 
+    {0xb9480000}, {0xb9482000}, {0xb9484000}, {0xb9486000}, 
+    {0xb9488000}, {0xb948a000}, {0xb948c000}, {0xb948e000}, 
+    {0xb9490000}, {0xb9492000}, {0xb9494000}, {0xb9496000}, 
+    {0xb9498000}, {0xb949a000}, {0xb949c000}, {0xb949e000}, 
+    {0xb94a0000}, {0xb94a2000}, {0xb94a4000}, {0xb94a6000}, 
+    {0xb94a8000}, {0xb94aa000}, {0xb94ac000}, {0xb94ae000}, 
+    {0xb94b0000}, {0xb94b2000}, {0xb94b4000}, {0xb94b6000}, 
+    {0xb94b8000}, {0xb94ba000}, {0xb94bc000}, {0xb94be000}, 
+    {0xb94c0000}, {0xb94c2000}, {0xb94c4000}, {0xb94c6000}, 
+    {0xb94c8000}, {0xb94ca000}, {0xb94cc000}, {0xb94ce000}, 
+    {0xb94d0000}, {0xb94d2000}, {0xb94d4000}, {0xb94d6000}, 
+    {0xb94d8000}, {0xb94da000}, {0xb94dc000}, {0xb94de000}, 
+    {0xb94e0000}, {0xb94e2000}, {0xb94e4000}, {0xb94e6000}, 
+    {0xb94e8000}, {0xb94ea000}, {0xb94ec000}, {0xb94ee000}, 
+    {0xb94f0000}, {0xb94f2000}, {0xb94f4000}, {0xb94f6000}, 
+    {0xb94f8000}, {0xb94fa000}, {0xb94fc000}, {0xb94fe000}, 
+    {0xb9500000}, {0xb9502000}, {0xb9504000}, {0xb9506000}, 
+    {0xb9508000}, {0xb950a000}, {0xb950c000}, {0xb950e000}, 
+    {0xb9510000}, {0xb9512000}, {0xb9514000}, {0xb9516000}, 
+    {0xb9518000}, {0xb951a000}, {0xb951c000}, {0xb951e000}, 
+    {0xb9520000}, {0xb9522000}, {0xb9524000}, {0xb9526000}, 
+    {0xb9528000}, {0xb952a000}, {0xb952c000}, {0xb952e000}, 
+    {0xb9530000}, {0xb9532000}, {0xb9534000}, {0xb9536000}, 
+    {0xb9538000}, {0xb953a000}, {0xb953c000}, {0xb953e000}, 
+    {0xb9540000}, {0xb9542000}, {0xb9544000}, {0xb9546000}, 
+    {0xb9548000}, {0xb954a000}, {0xb954c000}, {0xb954e000}, 
+    {0xb9550000}, {0xb9552000}, {0xb9554000}, {0xb9556000}, 
+    {0xb9558000}, {0xb955a000}, {0xb955c000}, {0xb955e000}, 
+    {0xb9560000}, {0xb9562000}, {0xb9564000}, {0xb9566000}, 
+    {0xb9568000}, {0xb956a000}, {0xb956c000}, {0xb956e000}, 
+    {0xb9570000}, {0xb9572000}, {0xb9574000}, {0xb9576000}, 
+    {0xb9578000}, {0xb957a000}, {0xb957c000}, {0xb957e000}, 
+    {0xb9580000}, {0xb9582000}, {0xb9584000}, {0xb9586000}, 
+    {0xb9588000}, {0xb958a000}, {0xb958c000}, {0xb958e000}, 
+    {0xb9590000}, {0xb9592000}, {0xb9594000}, {0xb9596000}, 
+    {0xb9598000}, {0xb959a000}, {0xb959c000}, {0xb959e000}, 
+    {0xb95a0000}, {0xb95a2000}, {0xb95a4000}, {0xb95a6000}, 
+    {0xb95a8000}, {0xb95aa000}, {0xb95ac000}, {0xb95ae000}, 
+    {0xb95b0000}, {0xb95b2000}, {0xb95b4000}, {0xb95b6000}, 
+    {0xb95b8000}, {0xb95ba000}, {0xb95bc000}, {0xb95be000}, 
+    {0xb95c0000}, {0xb95c2000}, {0xb95c4000}, {0xb95c6000}, 
+    {0xb95c8000}, {0xb95ca000}, {0xb95cc000}, {0xb95ce000}, 
+    {0xb95d0000}, {0xb95d2000}, {0xb95d4000}, {0xb95d6000}, 
+    {0xb95d8000}, {0xb95da000}, {0xb95dc000}, {0xb95de000}, 
+    {0xb95e0000}, {0xb95e2000}, {0xb95e4000}, {0xb95e6000}, 
+    {0xb95e8000}, {0xb95ea000}, {0xb95ec000}, {0xb95ee000}, 
+    {0xb95f0000}, {0xb95f2000}, {0xb95f4000}, {0xb95f6000}, 
+    {0xb95f8000}, {0xb95fa000}, {0xb95fc000}, {0xb95fe000}, 
+    {0xb9600000}, {0xb9602000}, {0xb9604000}, {0xb9606000}, 
+    {0xb9608000}, {0xb960a000}, {0xb960c000}, {0xb960e000}, 
+    {0xb9610000}, {0xb9612000}, {0xb9614000}, {0xb9616000}, 
+    {0xb9618000}, {0xb961a000}, {0xb961c000}, {0xb961e000}, 
+    {0xb9620000}, {0xb9622000}, {0xb9624000}, {0xb9626000}, 
+    {0xb9628000}, {0xb962a000}, {0xb962c000}, {0xb962e000}, 
+    {0xb9630000}, {0xb9632000}, {0xb9634000}, {0xb9636000}, 
+    {0xb9638000}, {0xb963a000}, {0xb963c000}, {0xb963e000}, 
+    {0xb9640000}, {0xb9642000}, {0xb9644000}, {0xb9646000}, 
+    {0xb9648000}, {0xb964a000}, {0xb964c000}, {0xb964e000}, 
+    {0xb9650000}, {0xb9652000}, {0xb9654000}, {0xb9656000}, 
+    {0xb9658000}, {0xb965a000}, {0xb965c000}, {0xb965e000}, 
+    {0xb9660000}, {0xb9662000}, {0xb9664000}, {0xb9666000}, 
+    {0xb9668000}, {0xb966a000}, {0xb966c000}, {0xb966e000}, 
+    {0xb9670000}, {0xb9672000}, {0xb9674000}, {0xb9676000}, 
+    {0xb9678000}, {0xb967a000}, {0xb967c000}, {0xb967e000}, 
+    {0xb9680000}, {0xb9682000}, {0xb9684000}, {0xb9686000}, 
+    {0xb9688000}, {0xb968a000}, {0xb968c000}, {0xb968e000}, 
+    {0xb9690000}, {0xb9692000}, {0xb9694000}, {0xb9696000}, 
+    {0xb9698000}, {0xb969a000}, {0xb969c000}, {0xb969e000}, 
+    {0xb96a0000}, {0xb96a2000}, {0xb96a4000}, {0xb96a6000}, 
+    {0xb96a8000}, {0xb96aa000}, {0xb96ac000}, {0xb96ae000}, 
+    {0xb96b0000}, {0xb96b2000}, {0xb96b4000}, {0xb96b6000}, 
+    {0xb96b8000}, {0xb96ba000}, {0xb96bc000}, {0xb96be000}, 
+    {0xb96c0000}, {0xb96c2000}, {0xb96c4000}, {0xb96c6000}, 
+    {0xb96c8000}, {0xb96ca000}, {0xb96cc000}, {0xb96ce000}, 
+    {0xb96d0000}, {0xb96d2000}, {0xb96d4000}, {0xb96d6000}, 
+    {0xb96d8000}, {0xb96da000}, {0xb96dc000}, {0xb96de000}, 
+    {0xb96e0000}, {0xb96e2000}, {0xb96e4000}, {0xb96e6000}, 
+    {0xb96e8000}, {0xb96ea000}, {0xb96ec000}, {0xb96ee000}, 
+    {0xb96f0000}, {0xb96f2000}, {0xb96f4000}, {0xb96f6000}, 
+    {0xb96f8000}, {0xb96fa000}, {0xb96fc000}, {0xb96fe000}, 
+    {0xb9700000}, {0xb9702000}, {0xb9704000}, {0xb9706000}, 
+    {0xb9708000}, {0xb970a000}, {0xb970c000}, {0xb970e000}, 
+    {0xb9710000}, {0xb9712000}, {0xb9714000}, {0xb9716000}, 
+    {0xb9718000}, {0xb971a000}, {0xb971c000}, {0xb971e000}, 
+    {0xb9720000}, {0xb9722000}, {0xb9724000}, {0xb9726000}, 
+    {0xb9728000}, {0xb972a000}, {0xb972c000}, {0xb972e000}, 
+    {0xb9730000}, {0xb9732000}, {0xb9734000}, {0xb9736000}, 
+    {0xb9738000}, {0xb973a000}, {0xb973c000}, {0xb973e000}, 
+    {0xb9740000}, {0xb9742000}, {0xb9744000}, {0xb9746000}, 
+    {0xb9748000}, {0xb974a000}, {0xb974c000}, {0xb974e000}, 
+    {0xb9750000}, {0xb9752000}, {0xb9754000}, {0xb9756000}, 
+    {0xb9758000}, {0xb975a000}, {0xb975c000}, {0xb975e000}, 
+    {0xb9760000}, {0xb9762000}, {0xb9764000}, {0xb9766000}, 
+    {0xb9768000}, {0xb976a000}, {0xb976c000}, {0xb976e000}, 
+    {0xb9770000}, {0xb9772000}, {0xb9774000}, {0xb9776000}, 
+    {0xb9778000}, {0xb977a000}, {0xb977c000}, {0xb977e000}, 
+    {0xb9780000}, {0xb9782000}, {0xb9784000}, {0xb9786000}, 
+    {0xb9788000}, {0xb978a000}, {0xb978c000}, {0xb978e000}, 
+    {0xb9790000}, {0xb9792000}, {0xb9794000}, {0xb9796000}, 
+    {0xb9798000}, {0xb979a000}, {0xb979c000}, {0xb979e000}, 
+    {0xb97a0000}, {0xb97a2000}, {0xb97a4000}, {0xb97a6000}, 
+    {0xb97a8000}, {0xb97aa000}, {0xb97ac000}, {0xb97ae000}, 
+    {0xb97b0000}, {0xb97b2000}, {0xb97b4000}, {0xb97b6000}, 
+    {0xb97b8000}, {0xb97ba000}, {0xb97bc000}, {0xb97be000}, 
+    {0xb97c0000}, {0xb97c2000}, {0xb97c4000}, {0xb97c6000}, 
+    {0xb97c8000}, {0xb97ca000}, {0xb97cc000}, {0xb97ce000}, 
+    {0xb97d0000}, {0xb97d2000}, {0xb97d4000}, {0xb97d6000}, 
+    {0xb97d8000}, {0xb97da000}, {0xb97dc000}, {0xb97de000}, 
+    {0xb97e0000}, {0xb97e2000}, {0xb97e4000}, {0xb97e6000}, 
+    {0xb97e8000}, {0xb97ea000}, {0xb97ec000}, {0xb97ee000}, 
+    {0xb97f0000}, {0xb97f2000}, {0xb97f4000}, {0xb97f6000}, 
+    {0xb97f8000}, {0xb97fa000}, {0xb97fc000}, {0xb97fe000}, 
+    {0xb9800000}, {0xb9802000}, {0xb9804000}, {0xb9806000}, 
+    {0xb9808000}, {0xb980a000}, {0xb980c000}, {0xb980e000}, 
+    {0xb9810000}, {0xb9812000}, {0xb9814000}, {0xb9816000}, 
+    {0xb9818000}, {0xb981a000}, {0xb981c000}, {0xb981e000}, 
+    {0xb9820000}, {0xb9822000}, {0xb9824000}, {0xb9826000}, 
+    {0xb9828000}, {0xb982a000}, {0xb982c000}, {0xb982e000}, 
+    {0xb9830000}, {0xb9832000}, {0xb9834000}, {0xb9836000}, 
+    {0xb9838000}, {0xb983a000}, {0xb983c000}, {0xb983e000}, 
+    {0xb9840000}, {0xb9842000}, {0xb9844000}, {0xb9846000}, 
+    {0xb9848000}, {0xb984a000}, {0xb984c000}, {0xb984e000}, 
+    {0xb9850000}, {0xb9852000}, {0xb9854000}, {0xb9856000}, 
+    {0xb9858000}, {0xb985a000}, {0xb985c000}, {0xb985e000}, 
+    {0xb9860000}, {0xb9862000}, {0xb9864000}, {0xb9866000}, 
+    {0xb9868000}, {0xb986a000}, {0xb986c000}, {0xb986e000}, 
+    {0xb9870000}, {0xb9872000}, {0xb9874000}, {0xb9876000}, 
+    {0xb9878000}, {0xb987a000}, {0xb987c000}, {0xb987e000}, 
+    {0xb9880000}, {0xb9882000}, {0xb9884000}, {0xb9886000}, 
+    {0xb9888000}, {0xb988a000}, {0xb988c000}, {0xb988e000}, 
+    {0xb9890000}, {0xb9892000}, {0xb9894000}, {0xb9896000}, 
+    {0xb9898000}, {0xb989a000}, {0xb989c000}, {0xb989e000}, 
+    {0xb98a0000}, {0xb98a2000}, {0xb98a4000}, {0xb98a6000}, 
+    {0xb98a8000}, {0xb98aa000}, {0xb98ac000}, {0xb98ae000}, 
+    {0xb98b0000}, {0xb98b2000}, {0xb98b4000}, {0xb98b6000}, 
+    {0xb98b8000}, {0xb98ba000}, {0xb98bc000}, {0xb98be000}, 
+    {0xb98c0000}, {0xb98c2000}, {0xb98c4000}, {0xb98c6000}, 
+    {0xb98c8000}, {0xb98ca000}, {0xb98cc000}, {0xb98ce000}, 
+    {0xb98d0000}, {0xb98d2000}, {0xb98d4000}, {0xb98d6000}, 
+    {0xb98d8000}, {0xb98da000}, {0xb98dc000}, {0xb98de000}, 
+    {0xb98e0000}, {0xb98e2000}, {0xb98e4000}, {0xb98e6000}, 
+    {0xb98e8000}, {0xb98ea000}, {0xb98ec000}, {0xb98ee000}, 
+    {0xb98f0000}, {0xb98f2000}, {0xb98f4000}, {0xb98f6000}, 
+    {0xb98f8000}, {0xb98fa000}, {0xb98fc000}, {0xb98fe000}, 
+    {0xb9900000}, {0xb9902000}, {0xb9904000}, {0xb9906000}, 
+    {0xb9908000}, {0xb990a000}, {0xb990c000}, {0xb990e000}, 
+    {0xb9910000}, {0xb9912000}, {0xb9914000}, {0xb9916000}, 
+    {0xb9918000}, {0xb991a000}, {0xb991c000}, {0xb991e000}, 
+    {0xb9920000}, {0xb9922000}, {0xb9924000}, {0xb9926000}, 
+    {0xb9928000}, {0xb992a000}, {0xb992c000}, {0xb992e000}, 
+    {0xb9930000}, {0xb9932000}, {0xb9934000}, {0xb9936000}, 
+    {0xb9938000}, {0xb993a000}, {0xb993c000}, {0xb993e000}, 
+    {0xb9940000}, {0xb9942000}, {0xb9944000}, {0xb9946000}, 
+    {0xb9948000}, {0xb994a000}, {0xb994c000}, {0xb994e000}, 
+    {0xb9950000}, {0xb9952000}, {0xb9954000}, {0xb9956000}, 
+    {0xb9958000}, {0xb995a000}, {0xb995c000}, {0xb995e000}, 
+    {0xb9960000}, {0xb9962000}, {0xb9964000}, {0xb9966000}, 
+    {0xb9968000}, {0xb996a000}, {0xb996c000}, {0xb996e000}, 
+    {0xb9970000}, {0xb9972000}, {0xb9974000}, {0xb9976000}, 
+    {0xb9978000}, {0xb997a000}, {0xb997c000}, {0xb997e000}, 
+    {0xb9980000}, {0xb9982000}, {0xb9984000}, {0xb9986000}, 
+    {0xb9988000}, {0xb998a000}, {0xb998c000}, {0xb998e000}, 
+    {0xb9990000}, {0xb9992000}, {0xb9994000}, {0xb9996000}, 
+    {0xb9998000}, {0xb999a000}, {0xb999c000}, {0xb999e000}, 
+    {0xb99a0000}, {0xb99a2000}, {0xb99a4000}, {0xb99a6000}, 
+    {0xb99a8000}, {0xb99aa000}, {0xb99ac000}, {0xb99ae000}, 
+    {0xb99b0000}, {0xb99b2000}, {0xb99b4000}, {0xb99b6000}, 
+    {0xb99b8000}, {0xb99ba000}, {0xb99bc000}, {0xb99be000}, 
+    {0xb99c0000}, {0xb99c2000}, {0xb99c4000}, {0xb99c6000}, 
+    {0xb99c8000}, {0xb99ca000}, {0xb99cc000}, {0xb99ce000}, 
+    {0xb99d0000}, {0xb99d2000}, {0xb99d4000}, {0xb99d6000}, 
+    {0xb99d8000}, {0xb99da000}, {0xb99dc000}, {0xb99de000}, 
+    {0xb99e0000}, {0xb99e2000}, {0xb99e4000}, {0xb99e6000}, 
+    {0xb99e8000}, {0xb99ea000}, {0xb99ec000}, {0xb99ee000}, 
+    {0xb99f0000}, {0xb99f2000}, {0xb99f4000}, {0xb99f6000}, 
+    {0xb99f8000}, {0xb99fa000}, {0xb99fc000}, {0xb99fe000}, 
+    {0xb9a00000}, {0xb9a02000}, {0xb9a04000}, {0xb9a06000}, 
+    {0xb9a08000}, {0xb9a0a000}, {0xb9a0c000}, {0xb9a0e000}, 
+    {0xb9a10000}, {0xb9a12000}, {0xb9a14000}, {0xb9a16000}, 
+    {0xb9a18000}, {0xb9a1a000}, {0xb9a1c000}, {0xb9a1e000}, 
+    {0xb9a20000}, {0xb9a22000}, {0xb9a24000}, {0xb9a26000}, 
+    {0xb9a28000}, {0xb9a2a000}, {0xb9a2c000}, {0xb9a2e000}, 
+    {0xb9a30000}, {0xb9a32000}, {0xb9a34000}, {0xb9a36000}, 
+    {0xb9a38000}, {0xb9a3a000}, {0xb9a3c000}, {0xb9a3e000}, 
+    {0xb9a40000}, {0xb9a42000}, {0xb9a44000}, {0xb9a46000}, 
+    {0xb9a48000}, {0xb9a4a000}, {0xb9a4c000}, {0xb9a4e000}, 
+    {0xb9a50000}, {0xb9a52000}, {0xb9a54000}, {0xb9a56000}, 
+    {0xb9a58000}, {0xb9a5a000}, {0xb9a5c000}, {0xb9a5e000}, 
+    {0xb9a60000}, {0xb9a62000}, {0xb9a64000}, {0xb9a66000}, 
+    {0xb9a68000}, {0xb9a6a000}, {0xb9a6c000}, {0xb9a6e000}, 
+    {0xb9a70000}, {0xb9a72000}, {0xb9a74000}, {0xb9a76000}, 
+    {0xb9a78000}, {0xb9a7a000}, {0xb9a7c000}, {0xb9a7e000}, 
+    {0xb9a80000}, {0xb9a82000}, {0xb9a84000}, {0xb9a86000}, 
+    {0xb9a88000}, {0xb9a8a000}, {0xb9a8c000}, {0xb9a8e000}, 
+    {0xb9a90000}, {0xb9a92000}, {0xb9a94000}, {0xb9a96000}, 
+    {0xb9a98000}, {0xb9a9a000}, {0xb9a9c000}, {0xb9a9e000}, 
+    {0xb9aa0000}, {0xb9aa2000}, {0xb9aa4000}, {0xb9aa6000}, 
+    {0xb9aa8000}, {0xb9aaa000}, {0xb9aac000}, {0xb9aae000}, 
+    {0xb9ab0000}, {0xb9ab2000}, {0xb9ab4000}, {0xb9ab6000}, 
+    {0xb9ab8000}, {0xb9aba000}, {0xb9abc000}, {0xb9abe000}, 
+    {0xb9ac0000}, {0xb9ac2000}, {0xb9ac4000}, {0xb9ac6000}, 
+    {0xb9ac8000}, {0xb9aca000}, {0xb9acc000}, {0xb9ace000}, 
+    {0xb9ad0000}, {0xb9ad2000}, {0xb9ad4000}, {0xb9ad6000}, 
+    {0xb9ad8000}, {0xb9ada000}, {0xb9adc000}, {0xb9ade000}, 
+    {0xb9ae0000}, {0xb9ae2000}, {0xb9ae4000}, {0xb9ae6000}, 
+    {0xb9ae8000}, {0xb9aea000}, {0xb9aec000}, {0xb9aee000}, 
+    {0xb9af0000}, {0xb9af2000}, {0xb9af4000}, {0xb9af6000}, 
+    {0xb9af8000}, {0xb9afa000}, {0xb9afc000}, {0xb9afe000}, 
+    {0xb9b00000}, {0xb9b02000}, {0xb9b04000}, {0xb9b06000}, 
+    {0xb9b08000}, {0xb9b0a000}, {0xb9b0c000}, {0xb9b0e000}, 
+    {0xb9b10000}, {0xb9b12000}, {0xb9b14000}, {0xb9b16000}, 
+    {0xb9b18000}, {0xb9b1a000}, {0xb9b1c000}, {0xb9b1e000}, 
+    {0xb9b20000}, {0xb9b22000}, {0xb9b24000}, {0xb9b26000}, 
+    {0xb9b28000}, {0xb9b2a000}, {0xb9b2c000}, {0xb9b2e000}, 
+    {0xb9b30000}, {0xb9b32000}, {0xb9b34000}, {0xb9b36000}, 
+    {0xb9b38000}, {0xb9b3a000}, {0xb9b3c000}, {0xb9b3e000}, 
+    {0xb9b40000}, {0xb9b42000}, {0xb9b44000}, {0xb9b46000}, 
+    {0xb9b48000}, {0xb9b4a000}, {0xb9b4c000}, {0xb9b4e000}, 
+    {0xb9b50000}, {0xb9b52000}, {0xb9b54000}, {0xb9b56000}, 
+    {0xb9b58000}, {0xb9b5a000}, {0xb9b5c000}, {0xb9b5e000}, 
+    {0xb9b60000}, {0xb9b62000}, {0xb9b64000}, {0xb9b66000}, 
+    {0xb9b68000}, {0xb9b6a000}, {0xb9b6c000}, {0xb9b6e000}, 
+    {0xb9b70000}, {0xb9b72000}, {0xb9b74000}, {0xb9b76000}, 
+    {0xb9b78000}, {0xb9b7a000}, {0xb9b7c000}, {0xb9b7e000}, 
+    {0xb9b80000}, {0xb9b82000}, {0xb9b84000}, {0xb9b86000}, 
+    {0xb9b88000}, {0xb9b8a000}, {0xb9b8c000}, {0xb9b8e000}, 
+    {0xb9b90000}, {0xb9b92000}, {0xb9b94000}, {0xb9b96000}, 
+    {0xb9b98000}, {0xb9b9a000}, {0xb9b9c000}, {0xb9b9e000}, 
+    {0xb9ba0000}, {0xb9ba2000}, {0xb9ba4000}, {0xb9ba6000}, 
+    {0xb9ba8000}, {0xb9baa000}, {0xb9bac000}, {0xb9bae000}, 
+    {0xb9bb0000}, {0xb9bb2000}, {0xb9bb4000}, {0xb9bb6000}, 
+    {0xb9bb8000}, {0xb9bba000}, {0xb9bbc000}, {0xb9bbe000}, 
+    {0xb9bc0000}, {0xb9bc2000}, {0xb9bc4000}, {0xb9bc6000}, 
+    {0xb9bc8000}, {0xb9bca000}, {0xb9bcc000}, {0xb9bce000}, 
+    {0xb9bd0000}, {0xb9bd2000}, {0xb9bd4000}, {0xb9bd6000}, 
+    {0xb9bd8000}, {0xb9bda000}, {0xb9bdc000}, {0xb9bde000}, 
+    {0xb9be0000}, {0xb9be2000}, {0xb9be4000}, {0xb9be6000}, 
+    {0xb9be8000}, {0xb9bea000}, {0xb9bec000}, {0xb9bee000}, 
+    {0xb9bf0000}, {0xb9bf2000}, {0xb9bf4000}, {0xb9bf6000}, 
+    {0xb9bf8000}, {0xb9bfa000}, {0xb9bfc000}, {0xb9bfe000}, 
+    {0xb9c00000}, {0xb9c02000}, {0xb9c04000}, {0xb9c06000}, 
+    {0xb9c08000}, {0xb9c0a000}, {0xb9c0c000}, {0xb9c0e000}, 
+    {0xb9c10000}, {0xb9c12000}, {0xb9c14000}, {0xb9c16000}, 
+    {0xb9c18000}, {0xb9c1a000}, {0xb9c1c000}, {0xb9c1e000}, 
+    {0xb9c20000}, {0xb9c22000}, {0xb9c24000}, {0xb9c26000}, 
+    {0xb9c28000}, {0xb9c2a000}, {0xb9c2c000}, {0xb9c2e000}, 
+    {0xb9c30000}, {0xb9c32000}, {0xb9c34000}, {0xb9c36000}, 
+    {0xb9c38000}, {0xb9c3a000}, {0xb9c3c000}, {0xb9c3e000}, 
+    {0xb9c40000}, {0xb9c42000}, {0xb9c44000}, {0xb9c46000}, 
+    {0xb9c48000}, {0xb9c4a000}, {0xb9c4c000}, {0xb9c4e000}, 
+    {0xb9c50000}, {0xb9c52000}, {0xb9c54000}, {0xb9c56000}, 
+    {0xb9c58000}, {0xb9c5a000}, {0xb9c5c000}, {0xb9c5e000}, 
+    {0xb9c60000}, {0xb9c62000}, {0xb9c64000}, {0xb9c66000}, 
+    {0xb9c68000}, {0xb9c6a000}, {0xb9c6c000}, {0xb9c6e000}, 
+    {0xb9c70000}, {0xb9c72000}, {0xb9c74000}, {0xb9c76000}, 
+    {0xb9c78000}, {0xb9c7a000}, {0xb9c7c000}, {0xb9c7e000}, 
+    {0xb9c80000}, {0xb9c82000}, {0xb9c84000}, {0xb9c86000}, 
+    {0xb9c88000}, {0xb9c8a000}, {0xb9c8c000}, {0xb9c8e000}, 
+    {0xb9c90000}, {0xb9c92000}, {0xb9c94000}, {0xb9c96000}, 
+    {0xb9c98000}, {0xb9c9a000}, {0xb9c9c000}, {0xb9c9e000}, 
+    {0xb9ca0000}, {0xb9ca2000}, {0xb9ca4000}, {0xb9ca6000}, 
+    {0xb9ca8000}, {0xb9caa000}, {0xb9cac000}, {0xb9cae000}, 
+    {0xb9cb0000}, {0xb9cb2000}, {0xb9cb4000}, {0xb9cb6000}, 
+    {0xb9cb8000}, {0xb9cba000}, {0xb9cbc000}, {0xb9cbe000}, 
+    {0xb9cc0000}, {0xb9cc2000}, {0xb9cc4000}, {0xb9cc6000}, 
+    {0xb9cc8000}, {0xb9cca000}, {0xb9ccc000}, {0xb9cce000}, 
+    {0xb9cd0000}, {0xb9cd2000}, {0xb9cd4000}, {0xb9cd6000}, 
+    {0xb9cd8000}, {0xb9cda000}, {0xb9cdc000}, {0xb9cde000}, 
+    {0xb9ce0000}, {0xb9ce2000}, {0xb9ce4000}, {0xb9ce6000}, 
+    {0xb9ce8000}, {0xb9cea000}, {0xb9cec000}, {0xb9cee000}, 
+    {0xb9cf0000}, {0xb9cf2000}, {0xb9cf4000}, {0xb9cf6000}, 
+    {0xb9cf8000}, {0xb9cfa000}, {0xb9cfc000}, {0xb9cfe000}, 
+    {0xb9d00000}, {0xb9d02000}, {0xb9d04000}, {0xb9d06000}, 
+    {0xb9d08000}, {0xb9d0a000}, {0xb9d0c000}, {0xb9d0e000}, 
+    {0xb9d10000}, {0xb9d12000}, {0xb9d14000}, {0xb9d16000}, 
+    {0xb9d18000}, {0xb9d1a000}, {0xb9d1c000}, {0xb9d1e000}, 
+    {0xb9d20000}, {0xb9d22000}, {0xb9d24000}, {0xb9d26000}, 
+    {0xb9d28000}, {0xb9d2a000}, {0xb9d2c000}, {0xb9d2e000}, 
+    {0xb9d30000}, {0xb9d32000}, {0xb9d34000}, {0xb9d36000}, 
+    {0xb9d38000}, {0xb9d3a000}, {0xb9d3c000}, {0xb9d3e000}, 
+    {0xb9d40000}, {0xb9d42000}, {0xb9d44000}, {0xb9d46000}, 
+    {0xb9d48000}, {0xb9d4a000}, {0xb9d4c000}, {0xb9d4e000}, 
+    {0xb9d50000}, {0xb9d52000}, {0xb9d54000}, {0xb9d56000}, 
+    {0xb9d58000}, {0xb9d5a000}, {0xb9d5c000}, {0xb9d5e000}, 
+    {0xb9d60000}, {0xb9d62000}, {0xb9d64000}, {0xb9d66000}, 
+    {0xb9d68000}, {0xb9d6a000}, {0xb9d6c000}, {0xb9d6e000}, 
+    {0xb9d70000}, {0xb9d72000}, {0xb9d74000}, {0xb9d76000}, 
+    {0xb9d78000}, {0xb9d7a000}, {0xb9d7c000}, {0xb9d7e000}, 
+    {0xb9d80000}, {0xb9d82000}, {0xb9d84000}, {0xb9d86000}, 
+    {0xb9d88000}, {0xb9d8a000}, {0xb9d8c000}, {0xb9d8e000}, 
+    {0xb9d90000}, {0xb9d92000}, {0xb9d94000}, {0xb9d96000}, 
+    {0xb9d98000}, {0xb9d9a000}, {0xb9d9c000}, {0xb9d9e000}, 
+    {0xb9da0000}, {0xb9da2000}, {0xb9da4000}, {0xb9da6000}, 
+    {0xb9da8000}, {0xb9daa000}, {0xb9dac000}, {0xb9dae000}, 
+    {0xb9db0000}, {0xb9db2000}, {0xb9db4000}, {0xb9db6000}, 
+    {0xb9db8000}, {0xb9dba000}, {0xb9dbc000}, {0xb9dbe000}, 
+    {0xb9dc0000}, {0xb9dc2000}, {0xb9dc4000}, {0xb9dc6000}, 
+    {0xb9dc8000}, {0xb9dca000}, {0xb9dcc000}, {0xb9dce000}, 
+    {0xb9dd0000}, {0xb9dd2000}, {0xb9dd4000}, {0xb9dd6000}, 
+    {0xb9dd8000}, {0xb9dda000}, {0xb9ddc000}, {0xb9dde000}, 
+    {0xb9de0000}, {0xb9de2000}, {0xb9de4000}, {0xb9de6000}, 
+    {0xb9de8000}, {0xb9dea000}, {0xb9dec000}, {0xb9dee000}, 
+    {0xb9df0000}, {0xb9df2000}, {0xb9df4000}, {0xb9df6000}, 
+    {0xb9df8000}, {0xb9dfa000}, {0xb9dfc000}, {0xb9dfe000}, 
+    {0xb9e00000}, {0xb9e02000}, {0xb9e04000}, {0xb9e06000}, 
+    {0xb9e08000}, {0xb9e0a000}, {0xb9e0c000}, {0xb9e0e000}, 
+    {0xb9e10000}, {0xb9e12000}, {0xb9e14000}, {0xb9e16000}, 
+    {0xb9e18000}, {0xb9e1a000}, {0xb9e1c000}, {0xb9e1e000}, 
+    {0xb9e20000}, {0xb9e22000}, {0xb9e24000}, {0xb9e26000}, 
+    {0xb9e28000}, {0xb9e2a000}, {0xb9e2c000}, {0xb9e2e000}, 
+    {0xb9e30000}, {0xb9e32000}, {0xb9e34000}, {0xb9e36000}, 
+    {0xb9e38000}, {0xb9e3a000}, {0xb9e3c000}, {0xb9e3e000}, 
+    {0xb9e40000}, {0xb9e42000}, {0xb9e44000}, {0xb9e46000}, 
+    {0xb9e48000}, {0xb9e4a000}, {0xb9e4c000}, {0xb9e4e000}, 
+    {0xb9e50000}, {0xb9e52000}, {0xb9e54000}, {0xb9e56000}, 
+    {0xb9e58000}, {0xb9e5a000}, {0xb9e5c000}, {0xb9e5e000}, 
+    {0xb9e60000}, {0xb9e62000}, {0xb9e64000}, {0xb9e66000}, 
+    {0xb9e68000}, {0xb9e6a000}, {0xb9e6c000}, {0xb9e6e000}, 
+    {0xb9e70000}, {0xb9e72000}, {0xb9e74000}, {0xb9e76000}, 
+    {0xb9e78000}, {0xb9e7a000}, {0xb9e7c000}, {0xb9e7e000}, 
+    {0xb9e80000}, {0xb9e82000}, {0xb9e84000}, {0xb9e86000}, 
+    {0xb9e88000}, {0xb9e8a000}, {0xb9e8c000}, {0xb9e8e000}, 
+    {0xb9e90000}, {0xb9e92000}, {0xb9e94000}, {0xb9e96000}, 
+    {0xb9e98000}, {0xb9e9a000}, {0xb9e9c000}, {0xb9e9e000}, 
+    {0xb9ea0000}, {0xb9ea2000}, {0xb9ea4000}, {0xb9ea6000}, 
+    {0xb9ea8000}, {0xb9eaa000}, {0xb9eac000}, {0xb9eae000}, 
+    {0xb9eb0000}, {0xb9eb2000}, {0xb9eb4000}, {0xb9eb6000}, 
+    {0xb9eb8000}, {0xb9eba000}, {0xb9ebc000}, {0xb9ebe000}, 
+    {0xb9ec0000}, {0xb9ec2000}, {0xb9ec4000}, {0xb9ec6000}, 
+    {0xb9ec8000}, {0xb9eca000}, {0xb9ecc000}, {0xb9ece000}, 
+    {0xb9ed0000}, {0xb9ed2000}, {0xb9ed4000}, {0xb9ed6000}, 
+    {0xb9ed8000}, {0xb9eda000}, {0xb9edc000}, {0xb9ede000}, 
+    {0xb9ee0000}, {0xb9ee2000}, {0xb9ee4000}, {0xb9ee6000}, 
+    {0xb9ee8000}, {0xb9eea000}, {0xb9eec000}, {0xb9eee000}, 
+    {0xb9ef0000}, {0xb9ef2000}, {0xb9ef4000}, {0xb9ef6000}, 
+    {0xb9ef8000}, {0xb9efa000}, {0xb9efc000}, {0xb9efe000}, 
+    {0xb9f00000}, {0xb9f02000}, {0xb9f04000}, {0xb9f06000}, 
+    {0xb9f08000}, {0xb9f0a000}, {0xb9f0c000}, {0xb9f0e000}, 
+    {0xb9f10000}, {0xb9f12000}, {0xb9f14000}, {0xb9f16000}, 
+    {0xb9f18000}, {0xb9f1a000}, {0xb9f1c000}, {0xb9f1e000}, 
+    {0xb9f20000}, {0xb9f22000}, {0xb9f24000}, {0xb9f26000}, 
+    {0xb9f28000}, {0xb9f2a000}, {0xb9f2c000}, {0xb9f2e000}, 
+    {0xb9f30000}, {0xb9f32000}, {0xb9f34000}, {0xb9f36000}, 
+    {0xb9f38000}, {0xb9f3a000}, {0xb9f3c000}, {0xb9f3e000}, 
+    {0xb9f40000}, {0xb9f42000}, {0xb9f44000}, {0xb9f46000}, 
+    {0xb9f48000}, {0xb9f4a000}, {0xb9f4c000}, {0xb9f4e000}, 
+    {0xb9f50000}, {0xb9f52000}, {0xb9f54000}, {0xb9f56000}, 
+    {0xb9f58000}, {0xb9f5a000}, {0xb9f5c000}, {0xb9f5e000}, 
+    {0xb9f60000}, {0xb9f62000}, {0xb9f64000}, {0xb9f66000}, 
+    {0xb9f68000}, {0xb9f6a000}, {0xb9f6c000}, {0xb9f6e000}, 
+    {0xb9f70000}, {0xb9f72000}, {0xb9f74000}, {0xb9f76000}, 
+    {0xb9f78000}, {0xb9f7a000}, {0xb9f7c000}, {0xb9f7e000}, 
+    {0xb9f80000}, {0xb9f82000}, {0xb9f84000}, {0xb9f86000}, 
+    {0xb9f88000}, {0xb9f8a000}, {0xb9f8c000}, {0xb9f8e000}, 
+    {0xb9f90000}, {0xb9f92000}, {0xb9f94000}, {0xb9f96000}, 
+    {0xb9f98000}, {0xb9f9a000}, {0xb9f9c000}, {0xb9f9e000}, 
+    {0xb9fa0000}, {0xb9fa2000}, {0xb9fa4000}, {0xb9fa6000}, 
+    {0xb9fa8000}, {0xb9faa000}, {0xb9fac000}, {0xb9fae000}, 
+    {0xb9fb0000}, {0xb9fb2000}, {0xb9fb4000}, {0xb9fb6000}, 
+    {0xb9fb8000}, {0xb9fba000}, {0xb9fbc000}, {0xb9fbe000}, 
+    {0xb9fc0000}, {0xb9fc2000}, {0xb9fc4000}, {0xb9fc6000}, 
+    {0xb9fc8000}, {0xb9fca000}, {0xb9fcc000}, {0xb9fce000}, 
+    {0xb9fd0000}, {0xb9fd2000}, {0xb9fd4000}, {0xb9fd6000}, 
+    {0xb9fd8000}, {0xb9fda000}, {0xb9fdc000}, {0xb9fde000}, 
+    {0xb9fe0000}, {0xb9fe2000}, {0xb9fe4000}, {0xb9fe6000}, 
+    {0xb9fe8000}, {0xb9fea000}, {0xb9fec000}, {0xb9fee000}, 
+    {0xb9ff0000}, {0xb9ff2000}, {0xb9ff4000}, {0xb9ff6000}, 
+    {0xb9ff8000}, {0xb9ffa000}, {0xb9ffc000}, {0xb9ffe000}, 
+    {0xba000000}, {0xba002000}, {0xba004000}, {0xba006000}, 
+    {0xba008000}, {0xba00a000}, {0xba00c000}, {0xba00e000}, 
+    {0xba010000}, {0xba012000}, {0xba014000}, {0xba016000}, 
+    {0xba018000}, {0xba01a000}, {0xba01c000}, {0xba01e000}, 
+    {0xba020000}, {0xba022000}, {0xba024000}, {0xba026000}, 
+    {0xba028000}, {0xba02a000}, {0xba02c000}, {0xba02e000}, 
+    {0xba030000}, {0xba032000}, {0xba034000}, {0xba036000}, 
+    {0xba038000}, {0xba03a000}, {0xba03c000}, {0xba03e000}, 
+    {0xba040000}, {0xba042000}, {0xba044000}, {0xba046000}, 
+    {0xba048000}, {0xba04a000}, {0xba04c000}, {0xba04e000}, 
+    {0xba050000}, {0xba052000}, {0xba054000}, {0xba056000}, 
+    {0xba058000}, {0xba05a000}, {0xba05c000}, {0xba05e000}, 
+    {0xba060000}, {0xba062000}, {0xba064000}, {0xba066000}, 
+    {0xba068000}, {0xba06a000}, {0xba06c000}, {0xba06e000}, 
+    {0xba070000}, {0xba072000}, {0xba074000}, {0xba076000}, 
+    {0xba078000}, {0xba07a000}, {0xba07c000}, {0xba07e000}, 
+    {0xba080000}, {0xba082000}, {0xba084000}, {0xba086000}, 
+    {0xba088000}, {0xba08a000}, {0xba08c000}, {0xba08e000}, 
+    {0xba090000}, {0xba092000}, {0xba094000}, {0xba096000}, 
+    {0xba098000}, {0xba09a000}, {0xba09c000}, {0xba09e000}, 
+    {0xba0a0000}, {0xba0a2000}, {0xba0a4000}, {0xba0a6000}, 
+    {0xba0a8000}, {0xba0aa000}, {0xba0ac000}, {0xba0ae000}, 
+    {0xba0b0000}, {0xba0b2000}, {0xba0b4000}, {0xba0b6000}, 
+    {0xba0b8000}, {0xba0ba000}, {0xba0bc000}, {0xba0be000}, 
+    {0xba0c0000}, {0xba0c2000}, {0xba0c4000}, {0xba0c6000}, 
+    {0xba0c8000}, {0xba0ca000}, {0xba0cc000}, {0xba0ce000}, 
+    {0xba0d0000}, {0xba0d2000}, {0xba0d4000}, {0xba0d6000}, 
+    {0xba0d8000}, {0xba0da000}, {0xba0dc000}, {0xba0de000}, 
+    {0xba0e0000}, {0xba0e2000}, {0xba0e4000}, {0xba0e6000}, 
+    {0xba0e8000}, {0xba0ea000}, {0xba0ec000}, {0xba0ee000}, 
+    {0xba0f0000}, {0xba0f2000}, {0xba0f4000}, {0xba0f6000}, 
+    {0xba0f8000}, {0xba0fa000}, {0xba0fc000}, {0xba0fe000}, 
+    {0xba100000}, {0xba102000}, {0xba104000}, {0xba106000}, 
+    {0xba108000}, {0xba10a000}, {0xba10c000}, {0xba10e000}, 
+    {0xba110000}, {0xba112000}, {0xba114000}, {0xba116000}, 
+    {0xba118000}, {0xba11a000}, {0xba11c000}, {0xba11e000}, 
+    {0xba120000}, {0xba122000}, {0xba124000}, {0xba126000}, 
+    {0xba128000}, {0xba12a000}, {0xba12c000}, {0xba12e000}, 
+    {0xba130000}, {0xba132000}, {0xba134000}, {0xba136000}, 
+    {0xba138000}, {0xba13a000}, {0xba13c000}, {0xba13e000}, 
+    {0xba140000}, {0xba142000}, {0xba144000}, {0xba146000}, 
+    {0xba148000}, {0xba14a000}, {0xba14c000}, {0xba14e000}, 
+    {0xba150000}, {0xba152000}, {0xba154000}, {0xba156000}, 
+    {0xba158000}, {0xba15a000}, {0xba15c000}, {0xba15e000}, 
+    {0xba160000}, {0xba162000}, {0xba164000}, {0xba166000}, 
+    {0xba168000}, {0xba16a000}, {0xba16c000}, {0xba16e000}, 
+    {0xba170000}, {0xba172000}, {0xba174000}, {0xba176000}, 
+    {0xba178000}, {0xba17a000}, {0xba17c000}, {0xba17e000}, 
+    {0xba180000}, {0xba182000}, {0xba184000}, {0xba186000}, 
+    {0xba188000}, {0xba18a000}, {0xba18c000}, {0xba18e000}, 
+    {0xba190000}, {0xba192000}, {0xba194000}, {0xba196000}, 
+    {0xba198000}, {0xba19a000}, {0xba19c000}, {0xba19e000}, 
+    {0xba1a0000}, {0xba1a2000}, {0xba1a4000}, {0xba1a6000}, 
+    {0xba1a8000}, {0xba1aa000}, {0xba1ac000}, {0xba1ae000}, 
+    {0xba1b0000}, {0xba1b2000}, {0xba1b4000}, {0xba1b6000}, 
+    {0xba1b8000}, {0xba1ba000}, {0xba1bc000}, {0xba1be000}, 
+    {0xba1c0000}, {0xba1c2000}, {0xba1c4000}, {0xba1c6000}, 
+    {0xba1c8000}, {0xba1ca000}, {0xba1cc000}, {0xba1ce000}, 
+    {0xba1d0000}, {0xba1d2000}, {0xba1d4000}, {0xba1d6000}, 
+    {0xba1d8000}, {0xba1da000}, {0xba1dc000}, {0xba1de000}, 
+    {0xba1e0000}, {0xba1e2000}, {0xba1e4000}, {0xba1e6000}, 
+    {0xba1e8000}, {0xba1ea000}, {0xba1ec000}, {0xba1ee000}, 
+    {0xba1f0000}, {0xba1f2000}, {0xba1f4000}, {0xba1f6000}, 
+    {0xba1f8000}, {0xba1fa000}, {0xba1fc000}, {0xba1fe000}, 
+    {0xba200000}, {0xba202000}, {0xba204000}, {0xba206000}, 
+    {0xba208000}, {0xba20a000}, {0xba20c000}, {0xba20e000}, 
+    {0xba210000}, {0xba212000}, {0xba214000}, {0xba216000}, 
+    {0xba218000}, {0xba21a000}, {0xba21c000}, {0xba21e000}, 
+    {0xba220000}, {0xba222000}, {0xba224000}, {0xba226000}, 
+    {0xba228000}, {0xba22a000}, {0xba22c000}, {0xba22e000}, 
+    {0xba230000}, {0xba232000}, {0xba234000}, {0xba236000}, 
+    {0xba238000}, {0xba23a000}, {0xba23c000}, {0xba23e000}, 
+    {0xba240000}, {0xba242000}, {0xba244000}, {0xba246000}, 
+    {0xba248000}, {0xba24a000}, {0xba24c000}, {0xba24e000}, 
+    {0xba250000}, {0xba252000}, {0xba254000}, {0xba256000}, 
+    {0xba258000}, {0xba25a000}, {0xba25c000}, {0xba25e000}, 
+    {0xba260000}, {0xba262000}, {0xba264000}, {0xba266000}, 
+    {0xba268000}, {0xba26a000}, {0xba26c000}, {0xba26e000}, 
+    {0xba270000}, {0xba272000}, {0xba274000}, {0xba276000}, 
+    {0xba278000}, {0xba27a000}, {0xba27c000}, {0xba27e000}, 
+    {0xba280000}, {0xba282000}, {0xba284000}, {0xba286000}, 
+    {0xba288000}, {0xba28a000}, {0xba28c000}, {0xba28e000}, 
+    {0xba290000}, {0xba292000}, {0xba294000}, {0xba296000}, 
+    {0xba298000}, {0xba29a000}, {0xba29c000}, {0xba29e000}, 
+    {0xba2a0000}, {0xba2a2000}, {0xba2a4000}, {0xba2a6000}, 
+    {0xba2a8000}, {0xba2aa000}, {0xba2ac000}, {0xba2ae000}, 
+    {0xba2b0000}, {0xba2b2000}, {0xba2b4000}, {0xba2b6000}, 
+    {0xba2b8000}, {0xba2ba000}, {0xba2bc000}, {0xba2be000}, 
+    {0xba2c0000}, {0xba2c2000}, {0xba2c4000}, {0xba2c6000}, 
+    {0xba2c8000}, {0xba2ca000}, {0xba2cc000}, {0xba2ce000}, 
+    {0xba2d0000}, {0xba2d2000}, {0xba2d4000}, {0xba2d6000}, 
+    {0xba2d8000}, {0xba2da000}, {0xba2dc000}, {0xba2de000}, 
+    {0xba2e0000}, {0xba2e2000}, {0xba2e4000}, {0xba2e6000}, 
+    {0xba2e8000}, {0xba2ea000}, {0xba2ec000}, {0xba2ee000}, 
+    {0xba2f0000}, {0xba2f2000}, {0xba2f4000}, {0xba2f6000}, 
+    {0xba2f8000}, {0xba2fa000}, {0xba2fc000}, {0xba2fe000}, 
+    {0xba300000}, {0xba302000}, {0xba304000}, {0xba306000}, 
+    {0xba308000}, {0xba30a000}, {0xba30c000}, {0xba30e000}, 
+    {0xba310000}, {0xba312000}, {0xba314000}, {0xba316000}, 
+    {0xba318000}, {0xba31a000}, {0xba31c000}, {0xba31e000}, 
+    {0xba320000}, {0xba322000}, {0xba324000}, {0xba326000}, 
+    {0xba328000}, {0xba32a000}, {0xba32c000}, {0xba32e000}, 
+    {0xba330000}, {0xba332000}, {0xba334000}, {0xba336000}, 
+    {0xba338000}, {0xba33a000}, {0xba33c000}, {0xba33e000}, 
+    {0xba340000}, {0xba342000}, {0xba344000}, {0xba346000}, 
+    {0xba348000}, {0xba34a000}, {0xba34c000}, {0xba34e000}, 
+    {0xba350000}, {0xba352000}, {0xba354000}, {0xba356000}, 
+    {0xba358000}, {0xba35a000}, {0xba35c000}, {0xba35e000}, 
+    {0xba360000}, {0xba362000}, {0xba364000}, {0xba366000}, 
+    {0xba368000}, {0xba36a000}, {0xba36c000}, {0xba36e000}, 
+    {0xba370000}, {0xba372000}, {0xba374000}, {0xba376000}, 
+    {0xba378000}, {0xba37a000}, {0xba37c000}, {0xba37e000}, 
+    {0xba380000}, {0xba382000}, {0xba384000}, {0xba386000}, 
+    {0xba388000}, {0xba38a000}, {0xba38c000}, {0xba38e000}, 
+    {0xba390000}, {0xba392000}, {0xba394000}, {0xba396000}, 
+    {0xba398000}, {0xba39a000}, {0xba39c000}, {0xba39e000}, 
+    {0xba3a0000}, {0xba3a2000}, {0xba3a4000}, {0xba3a6000}, 
+    {0xba3a8000}, {0xba3aa000}, {0xba3ac000}, {0xba3ae000}, 
+    {0xba3b0000}, {0xba3b2000}, {0xba3b4000}, {0xba3b6000}, 
+    {0xba3b8000}, {0xba3ba000}, {0xba3bc000}, {0xba3be000}, 
+    {0xba3c0000}, {0xba3c2000}, {0xba3c4000}, {0xba3c6000}, 
+    {0xba3c8000}, {0xba3ca000}, {0xba3cc000}, {0xba3ce000}, 
+    {0xba3d0000}, {0xba3d2000}, {0xba3d4000}, {0xba3d6000}, 
+    {0xba3d8000}, {0xba3da000}, {0xba3dc000}, {0xba3de000}, 
+    {0xba3e0000}, {0xba3e2000}, {0xba3e4000}, {0xba3e6000}, 
+    {0xba3e8000}, {0xba3ea000}, {0xba3ec000}, {0xba3ee000}, 
+    {0xba3f0000}, {0xba3f2000}, {0xba3f4000}, {0xba3f6000}, 
+    {0xba3f8000}, {0xba3fa000}, {0xba3fc000}, {0xba3fe000}, 
+    {0xba400000}, {0xba402000}, {0xba404000}, {0xba406000}, 
+    {0xba408000}, {0xba40a000}, {0xba40c000}, {0xba40e000}, 
+    {0xba410000}, {0xba412000}, {0xba414000}, {0xba416000}, 
+    {0xba418000}, {0xba41a000}, {0xba41c000}, {0xba41e000}, 
+    {0xba420000}, {0xba422000}, {0xba424000}, {0xba426000}, 
+    {0xba428000}, {0xba42a000}, {0xba42c000}, {0xba42e000}, 
+    {0xba430000}, {0xba432000}, {0xba434000}, {0xba436000}, 
+    {0xba438000}, {0xba43a000}, {0xba43c000}, {0xba43e000}, 
+    {0xba440000}, {0xba442000}, {0xba444000}, {0xba446000}, 
+    {0xba448000}, {0xba44a000}, {0xba44c000}, {0xba44e000}, 
+    {0xba450000}, {0xba452000}, {0xba454000}, {0xba456000}, 
+    {0xba458000}, {0xba45a000}, {0xba45c000}, {0xba45e000}, 
+    {0xba460000}, {0xba462000}, {0xba464000}, {0xba466000}, 
+    {0xba468000}, {0xba46a000}, {0xba46c000}, {0xba46e000}, 
+    {0xba470000}, {0xba472000}, {0xba474000}, {0xba476000}, 
+    {0xba478000}, {0xba47a000}, {0xba47c000}, {0xba47e000}, 
+    {0xba480000}, {0xba482000}, {0xba484000}, {0xba486000}, 
+    {0xba488000}, {0xba48a000}, {0xba48c000}, {0xba48e000}, 
+    {0xba490000}, {0xba492000}, {0xba494000}, {0xba496000}, 
+    {0xba498000}, {0xba49a000}, {0xba49c000}, {0xba49e000}, 
+    {0xba4a0000}, {0xba4a2000}, {0xba4a4000}, {0xba4a6000}, 
+    {0xba4a8000}, {0xba4aa000}, {0xba4ac000}, {0xba4ae000}, 
+    {0xba4b0000}, {0xba4b2000}, {0xba4b4000}, {0xba4b6000}, 
+    {0xba4b8000}, {0xba4ba000}, {0xba4bc000}, {0xba4be000}, 
+    {0xba4c0000}, {0xba4c2000}, {0xba4c4000}, {0xba4c6000}, 
+    {0xba4c8000}, {0xba4ca000}, {0xba4cc000}, {0xba4ce000}, 
+    {0xba4d0000}, {0xba4d2000}, {0xba4d4000}, {0xba4d6000}, 
+    {0xba4d8000}, {0xba4da000}, {0xba4dc000}, {0xba4de000}, 
+    {0xba4e0000}, {0xba4e2000}, {0xba4e4000}, {0xba4e6000}, 
+    {0xba4e8000}, {0xba4ea000}, {0xba4ec000}, {0xba4ee000}, 
+    {0xba4f0000}, {0xba4f2000}, {0xba4f4000}, {0xba4f6000}, 
+    {0xba4f8000}, {0xba4fa000}, {0xba4fc000}, {0xba4fe000}, 
+    {0xba500000}, {0xba502000}, {0xba504000}, {0xba506000}, 
+    {0xba508000}, {0xba50a000}, {0xba50c000}, {0xba50e000}, 
+    {0xba510000}, {0xba512000}, {0xba514000}, {0xba516000}, 
+    {0xba518000}, {0xba51a000}, {0xba51c000}, {0xba51e000}, 
+    {0xba520000}, {0xba522000}, {0xba524000}, {0xba526000}, 
+    {0xba528000}, {0xba52a000}, {0xba52c000}, {0xba52e000}, 
+    {0xba530000}, {0xba532000}, {0xba534000}, {0xba536000}, 
+    {0xba538000}, {0xba53a000}, {0xba53c000}, {0xba53e000}, 
+    {0xba540000}, {0xba542000}, {0xba544000}, {0xba546000}, 
+    {0xba548000}, {0xba54a000}, {0xba54c000}, {0xba54e000}, 
+    {0xba550000}, {0xba552000}, {0xba554000}, {0xba556000}, 
+    {0xba558000}, {0xba55a000}, {0xba55c000}, {0xba55e000}, 
+    {0xba560000}, {0xba562000}, {0xba564000}, {0xba566000}, 
+    {0xba568000}, {0xba56a000}, {0xba56c000}, {0xba56e000}, 
+    {0xba570000}, {0xba572000}, {0xba574000}, {0xba576000}, 
+    {0xba578000}, {0xba57a000}, {0xba57c000}, {0xba57e000}, 
+    {0xba580000}, {0xba582000}, {0xba584000}, {0xba586000}, 
+    {0xba588000}, {0xba58a000}, {0xba58c000}, {0xba58e000}, 
+    {0xba590000}, {0xba592000}, {0xba594000}, {0xba596000}, 
+    {0xba598000}, {0xba59a000}, {0xba59c000}, {0xba59e000}, 
+    {0xba5a0000}, {0xba5a2000}, {0xba5a4000}, {0xba5a6000}, 
+    {0xba5a8000}, {0xba5aa000}, {0xba5ac000}, {0xba5ae000}, 
+    {0xba5b0000}, {0xba5b2000}, {0xba5b4000}, {0xba5b6000}, 
+    {0xba5b8000}, {0xba5ba000}, {0xba5bc000}, {0xba5be000}, 
+    {0xba5c0000}, {0xba5c2000}, {0xba5c4000}, {0xba5c6000}, 
+    {0xba5c8000}, {0xba5ca000}, {0xba5cc000}, {0xba5ce000}, 
+    {0xba5d0000}, {0xba5d2000}, {0xba5d4000}, {0xba5d6000}, 
+    {0xba5d8000}, {0xba5da000}, {0xba5dc000}, {0xba5de000}, 
+    {0xba5e0000}, {0xba5e2000}, {0xba5e4000}, {0xba5e6000}, 
+    {0xba5e8000}, {0xba5ea000}, {0xba5ec000}, {0xba5ee000}, 
+    {0xba5f0000}, {0xba5f2000}, {0xba5f4000}, {0xba5f6000}, 
+    {0xba5f8000}, {0xba5fa000}, {0xba5fc000}, {0xba5fe000}, 
+    {0xba600000}, {0xba602000}, {0xba604000}, {0xba606000}, 
+    {0xba608000}, {0xba60a000}, {0xba60c000}, {0xba60e000}, 
+    {0xba610000}, {0xba612000}, {0xba614000}, {0xba616000}, 
+    {0xba618000}, {0xba61a000}, {0xba61c000}, {0xba61e000}, 
+    {0xba620000}, {0xba622000}, {0xba624000}, {0xba626000}, 
+    {0xba628000}, {0xba62a000}, {0xba62c000}, {0xba62e000}, 
+    {0xba630000}, {0xba632000}, {0xba634000}, {0xba636000}, 
+    {0xba638000}, {0xba63a000}, {0xba63c000}, {0xba63e000}, 
+    {0xba640000}, {0xba642000}, {0xba644000}, {0xba646000}, 
+    {0xba648000}, {0xba64a000}, {0xba64c000}, {0xba64e000}, 
+    {0xba650000}, {0xba652000}, {0xba654000}, {0xba656000}, 
+    {0xba658000}, {0xba65a000}, {0xba65c000}, {0xba65e000}, 
+    {0xba660000}, {0xba662000}, {0xba664000}, {0xba666000}, 
+    {0xba668000}, {0xba66a000}, {0xba66c000}, {0xba66e000}, 
+    {0xba670000}, {0xba672000}, {0xba674000}, {0xba676000}, 
+    {0xba678000}, {0xba67a000}, {0xba67c000}, {0xba67e000}, 
+    {0xba680000}, {0xba682000}, {0xba684000}, {0xba686000}, 
+    {0xba688000}, {0xba68a000}, {0xba68c000}, {0xba68e000}, 
+    {0xba690000}, {0xba692000}, {0xba694000}, {0xba696000}, 
+    {0xba698000}, {0xba69a000}, {0xba69c000}, {0xba69e000}, 
+    {0xba6a0000}, {0xba6a2000}, {0xba6a4000}, {0xba6a6000}, 
+    {0xba6a8000}, {0xba6aa000}, {0xba6ac000}, {0xba6ae000}, 
+    {0xba6b0000}, {0xba6b2000}, {0xba6b4000}, {0xba6b6000}, 
+    {0xba6b8000}, {0xba6ba000}, {0xba6bc000}, {0xba6be000}, 
+    {0xba6c0000}, {0xba6c2000}, {0xba6c4000}, {0xba6c6000}, 
+    {0xba6c8000}, {0xba6ca000}, {0xba6cc000}, {0xba6ce000}, 
+    {0xba6d0000}, {0xba6d2000}, {0xba6d4000}, {0xba6d6000}, 
+    {0xba6d8000}, {0xba6da000}, {0xba6dc000}, {0xba6de000}, 
+    {0xba6e0000}, {0xba6e2000}, {0xba6e4000}, {0xba6e6000}, 
+    {0xba6e8000}, {0xba6ea000}, {0xba6ec000}, {0xba6ee000}, 
+    {0xba6f0000}, {0xba6f2000}, {0xba6f4000}, {0xba6f6000}, 
+    {0xba6f8000}, {0xba6fa000}, {0xba6fc000}, {0xba6fe000}, 
+    {0xba700000}, {0xba702000}, {0xba704000}, {0xba706000}, 
+    {0xba708000}, {0xba70a000}, {0xba70c000}, {0xba70e000}, 
+    {0xba710000}, {0xba712000}, {0xba714000}, {0xba716000}, 
+    {0xba718000}, {0xba71a000}, {0xba71c000}, {0xba71e000}, 
+    {0xba720000}, {0xba722000}, {0xba724000}, {0xba726000}, 
+    {0xba728000}, {0xba72a000}, {0xba72c000}, {0xba72e000}, 
+    {0xba730000}, {0xba732000}, {0xba734000}, {0xba736000}, 
+    {0xba738000}, {0xba73a000}, {0xba73c000}, {0xba73e000}, 
+    {0xba740000}, {0xba742000}, {0xba744000}, {0xba746000}, 
+    {0xba748000}, {0xba74a000}, {0xba74c000}, {0xba74e000}, 
+    {0xba750000}, {0xba752000}, {0xba754000}, {0xba756000}, 
+    {0xba758000}, {0xba75a000}, {0xba75c000}, {0xba75e000}, 
+    {0xba760000}, {0xba762000}, {0xba764000}, {0xba766000}, 
+    {0xba768000}, {0xba76a000}, {0xba76c000}, {0xba76e000}, 
+    {0xba770000}, {0xba772000}, {0xba774000}, {0xba776000}, 
+    {0xba778000}, {0xba77a000}, {0xba77c000}, {0xba77e000}, 
+    {0xba780000}, {0xba782000}, {0xba784000}, {0xba786000}, 
+    {0xba788000}, {0xba78a000}, {0xba78c000}, {0xba78e000}, 
+    {0xba790000}, {0xba792000}, {0xba794000}, {0xba796000}, 
+    {0xba798000}, {0xba79a000}, {0xba79c000}, {0xba79e000}, 
+    {0xba7a0000}, {0xba7a2000}, {0xba7a4000}, {0xba7a6000}, 
+    {0xba7a8000}, {0xba7aa000}, {0xba7ac000}, {0xba7ae000}, 
+    {0xba7b0000}, {0xba7b2000}, {0xba7b4000}, {0xba7b6000}, 
+    {0xba7b8000}, {0xba7ba000}, {0xba7bc000}, {0xba7be000}, 
+    {0xba7c0000}, {0xba7c2000}, {0xba7c4000}, {0xba7c6000}, 
+    {0xba7c8000}, {0xba7ca000}, {0xba7cc000}, {0xba7ce000}, 
+    {0xba7d0000}, {0xba7d2000}, {0xba7d4000}, {0xba7d6000}, 
+    {0xba7d8000}, {0xba7da000}, {0xba7dc000}, {0xba7de000}, 
+    {0xba7e0000}, {0xba7e2000}, {0xba7e4000}, {0xba7e6000}, 
+    {0xba7e8000}, {0xba7ea000}, {0xba7ec000}, {0xba7ee000}, 
+    {0xba7f0000}, {0xba7f2000}, {0xba7f4000}, {0xba7f6000}, 
+    {0xba7f8000}, {0xba7fa000}, {0xba7fc000}, {0xba7fe000}, 
+    {0xba800000}, {0xba802000}, {0xba804000}, {0xba806000}, 
+    {0xba808000}, {0xba80a000}, {0xba80c000}, {0xba80e000}, 
+    {0xba810000}, {0xba812000}, {0xba814000}, {0xba816000}, 
+    {0xba818000}, {0xba81a000}, {0xba81c000}, {0xba81e000}, 
+    {0xba820000}, {0xba822000}, {0xba824000}, {0xba826000}, 
+    {0xba828000}, {0xba82a000}, {0xba82c000}, {0xba82e000}, 
+    {0xba830000}, {0xba832000}, {0xba834000}, {0xba836000}, 
+    {0xba838000}, {0xba83a000}, {0xba83c000}, {0xba83e000}, 
+    {0xba840000}, {0xba842000}, {0xba844000}, {0xba846000}, 
+    {0xba848000}, {0xba84a000}, {0xba84c000}, {0xba84e000}, 
+    {0xba850000}, {0xba852000}, {0xba854000}, {0xba856000}, 
+    {0xba858000}, {0xba85a000}, {0xba85c000}, {0xba85e000}, 
+    {0xba860000}, {0xba862000}, {0xba864000}, {0xba866000}, 
+    {0xba868000}, {0xba86a000}, {0xba86c000}, {0xba86e000}, 
+    {0xba870000}, {0xba872000}, {0xba874000}, {0xba876000}, 
+    {0xba878000}, {0xba87a000}, {0xba87c000}, {0xba87e000}, 
+    {0xba880000}, {0xba882000}, {0xba884000}, {0xba886000}, 
+    {0xba888000}, {0xba88a000}, {0xba88c000}, {0xba88e000}, 
+    {0xba890000}, {0xba892000}, {0xba894000}, {0xba896000}, 
+    {0xba898000}, {0xba89a000}, {0xba89c000}, {0xba89e000}, 
+    {0xba8a0000}, {0xba8a2000}, {0xba8a4000}, {0xba8a6000}, 
+    {0xba8a8000}, {0xba8aa000}, {0xba8ac000}, {0xba8ae000}, 
+    {0xba8b0000}, {0xba8b2000}, {0xba8b4000}, {0xba8b6000}, 
+    {0xba8b8000}, {0xba8ba000}, {0xba8bc000}, {0xba8be000}, 
+    {0xba8c0000}, {0xba8c2000}, {0xba8c4000}, {0xba8c6000}, 
+    {0xba8c8000}, {0xba8ca000}, {0xba8cc000}, {0xba8ce000}, 
+    {0xba8d0000}, {0xba8d2000}, {0xba8d4000}, {0xba8d6000}, 
+    {0xba8d8000}, {0xba8da000}, {0xba8dc000}, {0xba8de000}, 
+    {0xba8e0000}, {0xba8e2000}, {0xba8e4000}, {0xba8e6000}, 
+    {0xba8e8000}, {0xba8ea000}, {0xba8ec000}, {0xba8ee000}, 
+    {0xba8f0000}, {0xba8f2000}, {0xba8f4000}, {0xba8f6000}, 
+    {0xba8f8000}, {0xba8fa000}, {0xba8fc000}, {0xba8fe000}, 
+    {0xba900000}, {0xba902000}, {0xba904000}, {0xba906000}, 
+    {0xba908000}, {0xba90a000}, {0xba90c000}, {0xba90e000}, 
+    {0xba910000}, {0xba912000}, {0xba914000}, {0xba916000}, 
+    {0xba918000}, {0xba91a000}, {0xba91c000}, {0xba91e000}, 
+    {0xba920000}, {0xba922000}, {0xba924000}, {0xba926000}, 
+    {0xba928000}, {0xba92a000}, {0xba92c000}, {0xba92e000}, 
+    {0xba930000}, {0xba932000}, {0xba934000}, {0xba936000}, 
+    {0xba938000}, {0xba93a000}, {0xba93c000}, {0xba93e000}, 
+    {0xba940000}, {0xba942000}, {0xba944000}, {0xba946000}, 
+    {0xba948000}, {0xba94a000}, {0xba94c000}, {0xba94e000}, 
+    {0xba950000}, {0xba952000}, {0xba954000}, {0xba956000}, 
+    {0xba958000}, {0xba95a000}, {0xba95c000}, {0xba95e000}, 
+    {0xba960000}, {0xba962000}, {0xba964000}, {0xba966000}, 
+    {0xba968000}, {0xba96a000}, {0xba96c000}, {0xba96e000}, 
+    {0xba970000}, {0xba972000}, {0xba974000}, {0xba976000}, 
+    {0xba978000}, {0xba97a000}, {0xba97c000}, {0xba97e000}, 
+    {0xba980000}, {0xba982000}, {0xba984000}, {0xba986000}, 
+    {0xba988000}, {0xba98a000}, {0xba98c000}, {0xba98e000}, 
+    {0xba990000}, {0xba992000}, {0xba994000}, {0xba996000}, 
+    {0xba998000}, {0xba99a000}, {0xba99c000}, {0xba99e000}, 
+    {0xba9a0000}, {0xba9a2000}, {0xba9a4000}, {0xba9a6000}, 
+    {0xba9a8000}, {0xba9aa000}, {0xba9ac000}, {0xba9ae000}, 
+    {0xba9b0000}, {0xba9b2000}, {0xba9b4000}, {0xba9b6000}, 
+    {0xba9b8000}, {0xba9ba000}, {0xba9bc000}, {0xba9be000}, 
+    {0xba9c0000}, {0xba9c2000}, {0xba9c4000}, {0xba9c6000}, 
+    {0xba9c8000}, {0xba9ca000}, {0xba9cc000}, {0xba9ce000}, 
+    {0xba9d0000}, {0xba9d2000}, {0xba9d4000}, {0xba9d6000}, 
+    {0xba9d8000}, {0xba9da000}, {0xba9dc000}, {0xba9de000}, 
+    {0xba9e0000}, {0xba9e2000}, {0xba9e4000}, {0xba9e6000}, 
+    {0xba9e8000}, {0xba9ea000}, {0xba9ec000}, {0xba9ee000}, 
+    {0xba9f0000}, {0xba9f2000}, {0xba9f4000}, {0xba9f6000}, 
+    {0xba9f8000}, {0xba9fa000}, {0xba9fc000}, {0xba9fe000}, 
+    {0xbaa00000}, {0xbaa02000}, {0xbaa04000}, {0xbaa06000}, 
+    {0xbaa08000}, {0xbaa0a000}, {0xbaa0c000}, {0xbaa0e000}, 
+    {0xbaa10000}, {0xbaa12000}, {0xbaa14000}, {0xbaa16000}, 
+    {0xbaa18000}, {0xbaa1a000}, {0xbaa1c000}, {0xbaa1e000}, 
+    {0xbaa20000}, {0xbaa22000}, {0xbaa24000}, {0xbaa26000}, 
+    {0xbaa28000}, {0xbaa2a000}, {0xbaa2c000}, {0xbaa2e000}, 
+    {0xbaa30000}, {0xbaa32000}, {0xbaa34000}, {0xbaa36000}, 
+    {0xbaa38000}, {0xbaa3a000}, {0xbaa3c000}, {0xbaa3e000}, 
+    {0xbaa40000}, {0xbaa42000}, {0xbaa44000}, {0xbaa46000}, 
+    {0xbaa48000}, {0xbaa4a000}, {0xbaa4c000}, {0xbaa4e000}, 
+    {0xbaa50000}, {0xbaa52000}, {0xbaa54000}, {0xbaa56000}, 
+    {0xbaa58000}, {0xbaa5a000}, {0xbaa5c000}, {0xbaa5e000}, 
+    {0xbaa60000}, {0xbaa62000}, {0xbaa64000}, {0xbaa66000}, 
+    {0xbaa68000}, {0xbaa6a000}, {0xbaa6c000}, {0xbaa6e000}, 
+    {0xbaa70000}, {0xbaa72000}, {0xbaa74000}, {0xbaa76000}, 
+    {0xbaa78000}, {0xbaa7a000}, {0xbaa7c000}, {0xbaa7e000}, 
+    {0xbaa80000}, {0xbaa82000}, {0xbaa84000}, {0xbaa86000}, 
+    {0xbaa88000}, {0xbaa8a000}, {0xbaa8c000}, {0xbaa8e000}, 
+    {0xbaa90000}, {0xbaa92000}, {0xbaa94000}, {0xbaa96000}, 
+    {0xbaa98000}, {0xbaa9a000}, {0xbaa9c000}, {0xbaa9e000}, 
+    {0xbaaa0000}, {0xbaaa2000}, {0xbaaa4000}, {0xbaaa6000}, 
+    {0xbaaa8000}, {0xbaaaa000}, {0xbaaac000}, {0xbaaae000}, 
+    {0xbaab0000}, {0xbaab2000}, {0xbaab4000}, {0xbaab6000}, 
+    {0xbaab8000}, {0xbaaba000}, {0xbaabc000}, {0xbaabe000}, 
+    {0xbaac0000}, {0xbaac2000}, {0xbaac4000}, {0xbaac6000}, 
+    {0xbaac8000}, {0xbaaca000}, {0xbaacc000}, {0xbaace000}, 
+    {0xbaad0000}, {0xbaad2000}, {0xbaad4000}, {0xbaad6000}, 
+    {0xbaad8000}, {0xbaada000}, {0xbaadc000}, {0xbaade000}, 
+    {0xbaae0000}, {0xbaae2000}, {0xbaae4000}, {0xbaae6000}, 
+    {0xbaae8000}, {0xbaaea000}, {0xbaaec000}, {0xbaaee000}, 
+    {0xbaaf0000}, {0xbaaf2000}, {0xbaaf4000}, {0xbaaf6000}, 
+    {0xbaaf8000}, {0xbaafa000}, {0xbaafc000}, {0xbaafe000}, 
+    {0xbab00000}, {0xbab02000}, {0xbab04000}, {0xbab06000}, 
+    {0xbab08000}, {0xbab0a000}, {0xbab0c000}, {0xbab0e000}, 
+    {0xbab10000}, {0xbab12000}, {0xbab14000}, {0xbab16000}, 
+    {0xbab18000}, {0xbab1a000}, {0xbab1c000}, {0xbab1e000}, 
+    {0xbab20000}, {0xbab22000}, {0xbab24000}, {0xbab26000}, 
+    {0xbab28000}, {0xbab2a000}, {0xbab2c000}, {0xbab2e000}, 
+    {0xbab30000}, {0xbab32000}, {0xbab34000}, {0xbab36000}, 
+    {0xbab38000}, {0xbab3a000}, {0xbab3c000}, {0xbab3e000}, 
+    {0xbab40000}, {0xbab42000}, {0xbab44000}, {0xbab46000}, 
+    {0xbab48000}, {0xbab4a000}, {0xbab4c000}, {0xbab4e000}, 
+    {0xbab50000}, {0xbab52000}, {0xbab54000}, {0xbab56000}, 
+    {0xbab58000}, {0xbab5a000}, {0xbab5c000}, {0xbab5e000}, 
+    {0xbab60000}, {0xbab62000}, {0xbab64000}, {0xbab66000}, 
+    {0xbab68000}, {0xbab6a000}, {0xbab6c000}, {0xbab6e000}, 
+    {0xbab70000}, {0xbab72000}, {0xbab74000}, {0xbab76000}, 
+    {0xbab78000}, {0xbab7a000}, {0xbab7c000}, {0xbab7e000}, 
+    {0xbab80000}, {0xbab82000}, {0xbab84000}, {0xbab86000}, 
+    {0xbab88000}, {0xbab8a000}, {0xbab8c000}, {0xbab8e000}, 
+    {0xbab90000}, {0xbab92000}, {0xbab94000}, {0xbab96000}, 
+    {0xbab98000}, {0xbab9a000}, {0xbab9c000}, {0xbab9e000}, 
+    {0xbaba0000}, {0xbaba2000}, {0xbaba4000}, {0xbaba6000}, 
+    {0xbaba8000}, {0xbabaa000}, {0xbabac000}, {0xbabae000}, 
+    {0xbabb0000}, {0xbabb2000}, {0xbabb4000}, {0xbabb6000}, 
+    {0xbabb8000}, {0xbabba000}, {0xbabbc000}, {0xbabbe000}, 
+    {0xbabc0000}, {0xbabc2000}, {0xbabc4000}, {0xbabc6000}, 
+    {0xbabc8000}, {0xbabca000}, {0xbabcc000}, {0xbabce000}, 
+    {0xbabd0000}, {0xbabd2000}, {0xbabd4000}, {0xbabd6000}, 
+    {0xbabd8000}, {0xbabda000}, {0xbabdc000}, {0xbabde000}, 
+    {0xbabe0000}, {0xbabe2000}, {0xbabe4000}, {0xbabe6000}, 
+    {0xbabe8000}, {0xbabea000}, {0xbabec000}, {0xbabee000}, 
+    {0xbabf0000}, {0xbabf2000}, {0xbabf4000}, {0xbabf6000}, 
+    {0xbabf8000}, {0xbabfa000}, {0xbabfc000}, {0xbabfe000}, 
+    {0xbac00000}, {0xbac02000}, {0xbac04000}, {0xbac06000}, 
+    {0xbac08000}, {0xbac0a000}, {0xbac0c000}, {0xbac0e000}, 
+    {0xbac10000}, {0xbac12000}, {0xbac14000}, {0xbac16000}, 
+    {0xbac18000}, {0xbac1a000}, {0xbac1c000}, {0xbac1e000}, 
+    {0xbac20000}, {0xbac22000}, {0xbac24000}, {0xbac26000}, 
+    {0xbac28000}, {0xbac2a000}, {0xbac2c000}, {0xbac2e000}, 
+    {0xbac30000}, {0xbac32000}, {0xbac34000}, {0xbac36000}, 
+    {0xbac38000}, {0xbac3a000}, {0xbac3c000}, {0xbac3e000}, 
+    {0xbac40000}, {0xbac42000}, {0xbac44000}, {0xbac46000}, 
+    {0xbac48000}, {0xbac4a000}, {0xbac4c000}, {0xbac4e000}, 
+    {0xbac50000}, {0xbac52000}, {0xbac54000}, {0xbac56000}, 
+    {0xbac58000}, {0xbac5a000}, {0xbac5c000}, {0xbac5e000}, 
+    {0xbac60000}, {0xbac62000}, {0xbac64000}, {0xbac66000}, 
+    {0xbac68000}, {0xbac6a000}, {0xbac6c000}, {0xbac6e000}, 
+    {0xbac70000}, {0xbac72000}, {0xbac74000}, {0xbac76000}, 
+    {0xbac78000}, {0xbac7a000}, {0xbac7c000}, {0xbac7e000}, 
+    {0xbac80000}, {0xbac82000}, {0xbac84000}, {0xbac86000}, 
+    {0xbac88000}, {0xbac8a000}, {0xbac8c000}, {0xbac8e000}, 
+    {0xbac90000}, {0xbac92000}, {0xbac94000}, {0xbac96000}, 
+    {0xbac98000}, {0xbac9a000}, {0xbac9c000}, {0xbac9e000}, 
+    {0xbaca0000}, {0xbaca2000}, {0xbaca4000}, {0xbaca6000}, 
+    {0xbaca8000}, {0xbacaa000}, {0xbacac000}, {0xbacae000}, 
+    {0xbacb0000}, {0xbacb2000}, {0xbacb4000}, {0xbacb6000}, 
+    {0xbacb8000}, {0xbacba000}, {0xbacbc000}, {0xbacbe000}, 
+    {0xbacc0000}, {0xbacc2000}, {0xbacc4000}, {0xbacc6000}, 
+    {0xbacc8000}, {0xbacca000}, {0xbaccc000}, {0xbacce000}, 
+    {0xbacd0000}, {0xbacd2000}, {0xbacd4000}, {0xbacd6000}, 
+    {0xbacd8000}, {0xbacda000}, {0xbacdc000}, {0xbacde000}, 
+    {0xbace0000}, {0xbace2000}, {0xbace4000}, {0xbace6000}, 
+    {0xbace8000}, {0xbacea000}, {0xbacec000}, {0xbacee000}, 
+    {0xbacf0000}, {0xbacf2000}, {0xbacf4000}, {0xbacf6000}, 
+    {0xbacf8000}, {0xbacfa000}, {0xbacfc000}, {0xbacfe000}, 
+    {0xbad00000}, {0xbad02000}, {0xbad04000}, {0xbad06000}, 
+    {0xbad08000}, {0xbad0a000}, {0xbad0c000}, {0xbad0e000}, 
+    {0xbad10000}, {0xbad12000}, {0xbad14000}, {0xbad16000}, 
+    {0xbad18000}, {0xbad1a000}, {0xbad1c000}, {0xbad1e000}, 
+    {0xbad20000}, {0xbad22000}, {0xbad24000}, {0xbad26000}, 
+    {0xbad28000}, {0xbad2a000}, {0xbad2c000}, {0xbad2e000}, 
+    {0xbad30000}, {0xbad32000}, {0xbad34000}, {0xbad36000}, 
+    {0xbad38000}, {0xbad3a000}, {0xbad3c000}, {0xbad3e000}, 
+    {0xbad40000}, {0xbad42000}, {0xbad44000}, {0xbad46000}, 
+    {0xbad48000}, {0xbad4a000}, {0xbad4c000}, {0xbad4e000}, 
+    {0xbad50000}, {0xbad52000}, {0xbad54000}, {0xbad56000}, 
+    {0xbad58000}, {0xbad5a000}, {0xbad5c000}, {0xbad5e000}, 
+    {0xbad60000}, {0xbad62000}, {0xbad64000}, {0xbad66000}, 
+    {0xbad68000}, {0xbad6a000}, {0xbad6c000}, {0xbad6e000}, 
+    {0xbad70000}, {0xbad72000}, {0xbad74000}, {0xbad76000}, 
+    {0xbad78000}, {0xbad7a000}, {0xbad7c000}, {0xbad7e000}, 
+    {0xbad80000}, {0xbad82000}, {0xbad84000}, {0xbad86000}, 
+    {0xbad88000}, {0xbad8a000}, {0xbad8c000}, {0xbad8e000}, 
+    {0xbad90000}, {0xbad92000}, {0xbad94000}, {0xbad96000}, 
+    {0xbad98000}, {0xbad9a000}, {0xbad9c000}, {0xbad9e000}, 
+    {0xbada0000}, {0xbada2000}, {0xbada4000}, {0xbada6000}, 
+    {0xbada8000}, {0xbadaa000}, {0xbadac000}, {0xbadae000}, 
+    {0xbadb0000}, {0xbadb2000}, {0xbadb4000}, {0xbadb6000}, 
+    {0xbadb8000}, {0xbadba000}, {0xbadbc000}, {0xbadbe000}, 
+    {0xbadc0000}, {0xbadc2000}, {0xbadc4000}, {0xbadc6000}, 
+    {0xbadc8000}, {0xbadca000}, {0xbadcc000}, {0xbadce000}, 
+    {0xbadd0000}, {0xbadd2000}, {0xbadd4000}, {0xbadd6000}, 
+    {0xbadd8000}, {0xbadda000}, {0xbaddc000}, {0xbadde000}, 
+    {0xbade0000}, {0xbade2000}, {0xbade4000}, {0xbade6000}, 
+    {0xbade8000}, {0xbadea000}, {0xbadec000}, {0xbadee000}, 
+    {0xbadf0000}, {0xbadf2000}, {0xbadf4000}, {0xbadf6000}, 
+    {0xbadf8000}, {0xbadfa000}, {0xbadfc000}, {0xbadfe000}, 
+    {0xbae00000}, {0xbae02000}, {0xbae04000}, {0xbae06000}, 
+    {0xbae08000}, {0xbae0a000}, {0xbae0c000}, {0xbae0e000}, 
+    {0xbae10000}, {0xbae12000}, {0xbae14000}, {0xbae16000}, 
+    {0xbae18000}, {0xbae1a000}, {0xbae1c000}, {0xbae1e000}, 
+    {0xbae20000}, {0xbae22000}, {0xbae24000}, {0xbae26000}, 
+    {0xbae28000}, {0xbae2a000}, {0xbae2c000}, {0xbae2e000}, 
+    {0xbae30000}, {0xbae32000}, {0xbae34000}, {0xbae36000}, 
+    {0xbae38000}, {0xbae3a000}, {0xbae3c000}, {0xbae3e000}, 
+    {0xbae40000}, {0xbae42000}, {0xbae44000}, {0xbae46000}, 
+    {0xbae48000}, {0xbae4a000}, {0xbae4c000}, {0xbae4e000}, 
+    {0xbae50000}, {0xbae52000}, {0xbae54000}, {0xbae56000}, 
+    {0xbae58000}, {0xbae5a000}, {0xbae5c000}, {0xbae5e000}, 
+    {0xbae60000}, {0xbae62000}, {0xbae64000}, {0xbae66000}, 
+    {0xbae68000}, {0xbae6a000}, {0xbae6c000}, {0xbae6e000}, 
+    {0xbae70000}, {0xbae72000}, {0xbae74000}, {0xbae76000}, 
+    {0xbae78000}, {0xbae7a000}, {0xbae7c000}, {0xbae7e000}, 
+    {0xbae80000}, {0xbae82000}, {0xbae84000}, {0xbae86000}, 
+    {0xbae88000}, {0xbae8a000}, {0xbae8c000}, {0xbae8e000}, 
+    {0xbae90000}, {0xbae92000}, {0xbae94000}, {0xbae96000}, 
+    {0xbae98000}, {0xbae9a000}, {0xbae9c000}, {0xbae9e000}, 
+    {0xbaea0000}, {0xbaea2000}, {0xbaea4000}, {0xbaea6000}, 
+    {0xbaea8000}, {0xbaeaa000}, {0xbaeac000}, {0xbaeae000}, 
+    {0xbaeb0000}, {0xbaeb2000}, {0xbaeb4000}, {0xbaeb6000}, 
+    {0xbaeb8000}, {0xbaeba000}, {0xbaebc000}, {0xbaebe000}, 
+    {0xbaec0000}, {0xbaec2000}, {0xbaec4000}, {0xbaec6000}, 
+    {0xbaec8000}, {0xbaeca000}, {0xbaecc000}, {0xbaece000}, 
+    {0xbaed0000}, {0xbaed2000}, {0xbaed4000}, {0xbaed6000}, 
+    {0xbaed8000}, {0xbaeda000}, {0xbaedc000}, {0xbaede000}, 
+    {0xbaee0000}, {0xbaee2000}, {0xbaee4000}, {0xbaee6000}, 
+    {0xbaee8000}, {0xbaeea000}, {0xbaeec000}, {0xbaeee000}, 
+    {0xbaef0000}, {0xbaef2000}, {0xbaef4000}, {0xbaef6000}, 
+    {0xbaef8000}, {0xbaefa000}, {0xbaefc000}, {0xbaefe000}, 
+    {0xbaf00000}, {0xbaf02000}, {0xbaf04000}, {0xbaf06000}, 
+    {0xbaf08000}, {0xbaf0a000}, {0xbaf0c000}, {0xbaf0e000}, 
+    {0xbaf10000}, {0xbaf12000}, {0xbaf14000}, {0xbaf16000}, 
+    {0xbaf18000}, {0xbaf1a000}, {0xbaf1c000}, {0xbaf1e000}, 
+    {0xbaf20000}, {0xbaf22000}, {0xbaf24000}, {0xbaf26000}, 
+    {0xbaf28000}, {0xbaf2a000}, {0xbaf2c000}, {0xbaf2e000}, 
+    {0xbaf30000}, {0xbaf32000}, {0xbaf34000}, {0xbaf36000}, 
+    {0xbaf38000}, {0xbaf3a000}, {0xbaf3c000}, {0xbaf3e000}, 
+    {0xbaf40000}, {0xbaf42000}, {0xbaf44000}, {0xbaf46000}, 
+    {0xbaf48000}, {0xbaf4a000}, {0xbaf4c000}, {0xbaf4e000}, 
+    {0xbaf50000}, {0xbaf52000}, {0xbaf54000}, {0xbaf56000}, 
+    {0xbaf58000}, {0xbaf5a000}, {0xbaf5c000}, {0xbaf5e000}, 
+    {0xbaf60000}, {0xbaf62000}, {0xbaf64000}, {0xbaf66000}, 
+    {0xbaf68000}, {0xbaf6a000}, {0xbaf6c000}, {0xbaf6e000}, 
+    {0xbaf70000}, {0xbaf72000}, {0xbaf74000}, {0xbaf76000}, 
+    {0xbaf78000}, {0xbaf7a000}, {0xbaf7c000}, {0xbaf7e000}, 
+    {0xbaf80000}, {0xbaf82000}, {0xbaf84000}, {0xbaf86000}, 
+    {0xbaf88000}, {0xbaf8a000}, {0xbaf8c000}, {0xbaf8e000}, 
+    {0xbaf90000}, {0xbaf92000}, {0xbaf94000}, {0xbaf96000}, 
+    {0xbaf98000}, {0xbaf9a000}, {0xbaf9c000}, {0xbaf9e000}, 
+    {0xbafa0000}, {0xbafa2000}, {0xbafa4000}, {0xbafa6000}, 
+    {0xbafa8000}, {0xbafaa000}, {0xbafac000}, {0xbafae000}, 
+    {0xbafb0000}, {0xbafb2000}, {0xbafb4000}, {0xbafb6000}, 
+    {0xbafb8000}, {0xbafba000}, {0xbafbc000}, {0xbafbe000}, 
+    {0xbafc0000}, {0xbafc2000}, {0xbafc4000}, {0xbafc6000}, 
+    {0xbafc8000}, {0xbafca000}, {0xbafcc000}, {0xbafce000}, 
+    {0xbafd0000}, {0xbafd2000}, {0xbafd4000}, {0xbafd6000}, 
+    {0xbafd8000}, {0xbafda000}, {0xbafdc000}, {0xbafde000}, 
+    {0xbafe0000}, {0xbafe2000}, {0xbafe4000}, {0xbafe6000}, 
+    {0xbafe8000}, {0xbafea000}, {0xbafec000}, {0xbafee000}, 
+    {0xbaff0000}, {0xbaff2000}, {0xbaff4000}, {0xbaff6000}, 
+    {0xbaff8000}, {0xbaffa000}, {0xbaffc000}, {0xbaffe000}, 
+    {0xbb000000}, {0xbb002000}, {0xbb004000}, {0xbb006000}, 
+    {0xbb008000}, {0xbb00a000}, {0xbb00c000}, {0xbb00e000}, 
+    {0xbb010000}, {0xbb012000}, {0xbb014000}, {0xbb016000}, 
+    {0xbb018000}, {0xbb01a000}, {0xbb01c000}, {0xbb01e000}, 
+    {0xbb020000}, {0xbb022000}, {0xbb024000}, {0xbb026000}, 
+    {0xbb028000}, {0xbb02a000}, {0xbb02c000}, {0xbb02e000}, 
+    {0xbb030000}, {0xbb032000}, {0xbb034000}, {0xbb036000}, 
+    {0xbb038000}, {0xbb03a000}, {0xbb03c000}, {0xbb03e000}, 
+    {0xbb040000}, {0xbb042000}, {0xbb044000}, {0xbb046000}, 
+    {0xbb048000}, {0xbb04a000}, {0xbb04c000}, {0xbb04e000}, 
+    {0xbb050000}, {0xbb052000}, {0xbb054000}, {0xbb056000}, 
+    {0xbb058000}, {0xbb05a000}, {0xbb05c000}, {0xbb05e000}, 
+    {0xbb060000}, {0xbb062000}, {0xbb064000}, {0xbb066000}, 
+    {0xbb068000}, {0xbb06a000}, {0xbb06c000}, {0xbb06e000}, 
+    {0xbb070000}, {0xbb072000}, {0xbb074000}, {0xbb076000}, 
+    {0xbb078000}, {0xbb07a000}, {0xbb07c000}, {0xbb07e000}, 
+    {0xbb080000}, {0xbb082000}, {0xbb084000}, {0xbb086000}, 
+    {0xbb088000}, {0xbb08a000}, {0xbb08c000}, {0xbb08e000}, 
+    {0xbb090000}, {0xbb092000}, {0xbb094000}, {0xbb096000}, 
+    {0xbb098000}, {0xbb09a000}, {0xbb09c000}, {0xbb09e000}, 
+    {0xbb0a0000}, {0xbb0a2000}, {0xbb0a4000}, {0xbb0a6000}, 
+    {0xbb0a8000}, {0xbb0aa000}, {0xbb0ac000}, {0xbb0ae000}, 
+    {0xbb0b0000}, {0xbb0b2000}, {0xbb0b4000}, {0xbb0b6000}, 
+    {0xbb0b8000}, {0xbb0ba000}, {0xbb0bc000}, {0xbb0be000}, 
+    {0xbb0c0000}, {0xbb0c2000}, {0xbb0c4000}, {0xbb0c6000}, 
+    {0xbb0c8000}, {0xbb0ca000}, {0xbb0cc000}, {0xbb0ce000}, 
+    {0xbb0d0000}, {0xbb0d2000}, {0xbb0d4000}, {0xbb0d6000}, 
+    {0xbb0d8000}, {0xbb0da000}, {0xbb0dc000}, {0xbb0de000}, 
+    {0xbb0e0000}, {0xbb0e2000}, {0xbb0e4000}, {0xbb0e6000}, 
+    {0xbb0e8000}, {0xbb0ea000}, {0xbb0ec000}, {0xbb0ee000}, 
+    {0xbb0f0000}, {0xbb0f2000}, {0xbb0f4000}, {0xbb0f6000}, 
+    {0xbb0f8000}, {0xbb0fa000}, {0xbb0fc000}, {0xbb0fe000}, 
+    {0xbb100000}, {0xbb102000}, {0xbb104000}, {0xbb106000}, 
+    {0xbb108000}, {0xbb10a000}, {0xbb10c000}, {0xbb10e000}, 
+    {0xbb110000}, {0xbb112000}, {0xbb114000}, {0xbb116000}, 
+    {0xbb118000}, {0xbb11a000}, {0xbb11c000}, {0xbb11e000}, 
+    {0xbb120000}, {0xbb122000}, {0xbb124000}, {0xbb126000}, 
+    {0xbb128000}, {0xbb12a000}, {0xbb12c000}, {0xbb12e000}, 
+    {0xbb130000}, {0xbb132000}, {0xbb134000}, {0xbb136000}, 
+    {0xbb138000}, {0xbb13a000}, {0xbb13c000}, {0xbb13e000}, 
+    {0xbb140000}, {0xbb142000}, {0xbb144000}, {0xbb146000}, 
+    {0xbb148000}, {0xbb14a000}, {0xbb14c000}, {0xbb14e000}, 
+    {0xbb150000}, {0xbb152000}, {0xbb154000}, {0xbb156000}, 
+    {0xbb158000}, {0xbb15a000}, {0xbb15c000}, {0xbb15e000}, 
+    {0xbb160000}, {0xbb162000}, {0xbb164000}, {0xbb166000}, 
+    {0xbb168000}, {0xbb16a000}, {0xbb16c000}, {0xbb16e000}, 
+    {0xbb170000}, {0xbb172000}, {0xbb174000}, {0xbb176000}, 
+    {0xbb178000}, {0xbb17a000}, {0xbb17c000}, {0xbb17e000}, 
+    {0xbb180000}, {0xbb182000}, {0xbb184000}, {0xbb186000}, 
+    {0xbb188000}, {0xbb18a000}, {0xbb18c000}, {0xbb18e000}, 
+    {0xbb190000}, {0xbb192000}, {0xbb194000}, {0xbb196000}, 
+    {0xbb198000}, {0xbb19a000}, {0xbb19c000}, {0xbb19e000}, 
+    {0xbb1a0000}, {0xbb1a2000}, {0xbb1a4000}, {0xbb1a6000}, 
+    {0xbb1a8000}, {0xbb1aa000}, {0xbb1ac000}, {0xbb1ae000}, 
+    {0xbb1b0000}, {0xbb1b2000}, {0xbb1b4000}, {0xbb1b6000}, 
+    {0xbb1b8000}, {0xbb1ba000}, {0xbb1bc000}, {0xbb1be000}, 
+    {0xbb1c0000}, {0xbb1c2000}, {0xbb1c4000}, {0xbb1c6000}, 
+    {0xbb1c8000}, {0xbb1ca000}, {0xbb1cc000}, {0xbb1ce000}, 
+    {0xbb1d0000}, {0xbb1d2000}, {0xbb1d4000}, {0xbb1d6000}, 
+    {0xbb1d8000}, {0xbb1da000}, {0xbb1dc000}, {0xbb1de000}, 
+    {0xbb1e0000}, {0xbb1e2000}, {0xbb1e4000}, {0xbb1e6000}, 
+    {0xbb1e8000}, {0xbb1ea000}, {0xbb1ec000}, {0xbb1ee000}, 
+    {0xbb1f0000}, {0xbb1f2000}, {0xbb1f4000}, {0xbb1f6000}, 
+    {0xbb1f8000}, {0xbb1fa000}, {0xbb1fc000}, {0xbb1fe000}, 
+    {0xbb200000}, {0xbb202000}, {0xbb204000}, {0xbb206000}, 
+    {0xbb208000}, {0xbb20a000}, {0xbb20c000}, {0xbb20e000}, 
+    {0xbb210000}, {0xbb212000}, {0xbb214000}, {0xbb216000}, 
+    {0xbb218000}, {0xbb21a000}, {0xbb21c000}, {0xbb21e000}, 
+    {0xbb220000}, {0xbb222000}, {0xbb224000}, {0xbb226000}, 
+    {0xbb228000}, {0xbb22a000}, {0xbb22c000}, {0xbb22e000}, 
+    {0xbb230000}, {0xbb232000}, {0xbb234000}, {0xbb236000}, 
+    {0xbb238000}, {0xbb23a000}, {0xbb23c000}, {0xbb23e000}, 
+    {0xbb240000}, {0xbb242000}, {0xbb244000}, {0xbb246000}, 
+    {0xbb248000}, {0xbb24a000}, {0xbb24c000}, {0xbb24e000}, 
+    {0xbb250000}, {0xbb252000}, {0xbb254000}, {0xbb256000}, 
+    {0xbb258000}, {0xbb25a000}, {0xbb25c000}, {0xbb25e000}, 
+    {0xbb260000}, {0xbb262000}, {0xbb264000}, {0xbb266000}, 
+    {0xbb268000}, {0xbb26a000}, {0xbb26c000}, {0xbb26e000}, 
+    {0xbb270000}, {0xbb272000}, {0xbb274000}, {0xbb276000}, 
+    {0xbb278000}, {0xbb27a000}, {0xbb27c000}, {0xbb27e000}, 
+    {0xbb280000}, {0xbb282000}, {0xbb284000}, {0xbb286000}, 
+    {0xbb288000}, {0xbb28a000}, {0xbb28c000}, {0xbb28e000}, 
+    {0xbb290000}, {0xbb292000}, {0xbb294000}, {0xbb296000}, 
+    {0xbb298000}, {0xbb29a000}, {0xbb29c000}, {0xbb29e000}, 
+    {0xbb2a0000}, {0xbb2a2000}, {0xbb2a4000}, {0xbb2a6000}, 
+    {0xbb2a8000}, {0xbb2aa000}, {0xbb2ac000}, {0xbb2ae000}, 
+    {0xbb2b0000}, {0xbb2b2000}, {0xbb2b4000}, {0xbb2b6000}, 
+    {0xbb2b8000}, {0xbb2ba000}, {0xbb2bc000}, {0xbb2be000}, 
+    {0xbb2c0000}, {0xbb2c2000}, {0xbb2c4000}, {0xbb2c6000}, 
+    {0xbb2c8000}, {0xbb2ca000}, {0xbb2cc000}, {0xbb2ce000}, 
+    {0xbb2d0000}, {0xbb2d2000}, {0xbb2d4000}, {0xbb2d6000}, 
+    {0xbb2d8000}, {0xbb2da000}, {0xbb2dc000}, {0xbb2de000}, 
+    {0xbb2e0000}, {0xbb2e2000}, {0xbb2e4000}, {0xbb2e6000}, 
+    {0xbb2e8000}, {0xbb2ea000}, {0xbb2ec000}, {0xbb2ee000}, 
+    {0xbb2f0000}, {0xbb2f2000}, {0xbb2f4000}, {0xbb2f6000}, 
+    {0xbb2f8000}, {0xbb2fa000}, {0xbb2fc000}, {0xbb2fe000}, 
+    {0xbb300000}, {0xbb302000}, {0xbb304000}, {0xbb306000}, 
+    {0xbb308000}, {0xbb30a000}, {0xbb30c000}, {0xbb30e000}, 
+    {0xbb310000}, {0xbb312000}, {0xbb314000}, {0xbb316000}, 
+    {0xbb318000}, {0xbb31a000}, {0xbb31c000}, {0xbb31e000}, 
+    {0xbb320000}, {0xbb322000}, {0xbb324000}, {0xbb326000}, 
+    {0xbb328000}, {0xbb32a000}, {0xbb32c000}, {0xbb32e000}, 
+    {0xbb330000}, {0xbb332000}, {0xbb334000}, {0xbb336000}, 
+    {0xbb338000}, {0xbb33a000}, {0xbb33c000}, {0xbb33e000}, 
+    {0xbb340000}, {0xbb342000}, {0xbb344000}, {0xbb346000}, 
+    {0xbb348000}, {0xbb34a000}, {0xbb34c000}, {0xbb34e000}, 
+    {0xbb350000}, {0xbb352000}, {0xbb354000}, {0xbb356000}, 
+    {0xbb358000}, {0xbb35a000}, {0xbb35c000}, {0xbb35e000}, 
+    {0xbb360000}, {0xbb362000}, {0xbb364000}, {0xbb366000}, 
+    {0xbb368000}, {0xbb36a000}, {0xbb36c000}, {0xbb36e000}, 
+    {0xbb370000}, {0xbb372000}, {0xbb374000}, {0xbb376000}, 
+    {0xbb378000}, {0xbb37a000}, {0xbb37c000}, {0xbb37e000}, 
+    {0xbb380000}, {0xbb382000}, {0xbb384000}, {0xbb386000}, 
+    {0xbb388000}, {0xbb38a000}, {0xbb38c000}, {0xbb38e000}, 
+    {0xbb390000}, {0xbb392000}, {0xbb394000}, {0xbb396000}, 
+    {0xbb398000}, {0xbb39a000}, {0xbb39c000}, {0xbb39e000}, 
+    {0xbb3a0000}, {0xbb3a2000}, {0xbb3a4000}, {0xbb3a6000}, 
+    {0xbb3a8000}, {0xbb3aa000}, {0xbb3ac000}, {0xbb3ae000}, 
+    {0xbb3b0000}, {0xbb3b2000}, {0xbb3b4000}, {0xbb3b6000}, 
+    {0xbb3b8000}, {0xbb3ba000}, {0xbb3bc000}, {0xbb3be000}, 
+    {0xbb3c0000}, {0xbb3c2000}, {0xbb3c4000}, {0xbb3c6000}, 
+    {0xbb3c8000}, {0xbb3ca000}, {0xbb3cc000}, {0xbb3ce000}, 
+    {0xbb3d0000}, {0xbb3d2000}, {0xbb3d4000}, {0xbb3d6000}, 
+    {0xbb3d8000}, {0xbb3da000}, {0xbb3dc000}, {0xbb3de000}, 
+    {0xbb3e0000}, {0xbb3e2000}, {0xbb3e4000}, {0xbb3e6000}, 
+    {0xbb3e8000}, {0xbb3ea000}, {0xbb3ec000}, {0xbb3ee000}, 
+    {0xbb3f0000}, {0xbb3f2000}, {0xbb3f4000}, {0xbb3f6000}, 
+    {0xbb3f8000}, {0xbb3fa000}, {0xbb3fc000}, {0xbb3fe000}, 
+    {0xbb400000}, {0xbb402000}, {0xbb404000}, {0xbb406000}, 
+    {0xbb408000}, {0xbb40a000}, {0xbb40c000}, {0xbb40e000}, 
+    {0xbb410000}, {0xbb412000}, {0xbb414000}, {0xbb416000}, 
+    {0xbb418000}, {0xbb41a000}, {0xbb41c000}, {0xbb41e000}, 
+    {0xbb420000}, {0xbb422000}, {0xbb424000}, {0xbb426000}, 
+    {0xbb428000}, {0xbb42a000}, {0xbb42c000}, {0xbb42e000}, 
+    {0xbb430000}, {0xbb432000}, {0xbb434000}, {0xbb436000}, 
+    {0xbb438000}, {0xbb43a000}, {0xbb43c000}, {0xbb43e000}, 
+    {0xbb440000}, {0xbb442000}, {0xbb444000}, {0xbb446000}, 
+    {0xbb448000}, {0xbb44a000}, {0xbb44c000}, {0xbb44e000}, 
+    {0xbb450000}, {0xbb452000}, {0xbb454000}, {0xbb456000}, 
+    {0xbb458000}, {0xbb45a000}, {0xbb45c000}, {0xbb45e000}, 
+    {0xbb460000}, {0xbb462000}, {0xbb464000}, {0xbb466000}, 
+    {0xbb468000}, {0xbb46a000}, {0xbb46c000}, {0xbb46e000}, 
+    {0xbb470000}, {0xbb472000}, {0xbb474000}, {0xbb476000}, 
+    {0xbb478000}, {0xbb47a000}, {0xbb47c000}, {0xbb47e000}, 
+    {0xbb480000}, {0xbb482000}, {0xbb484000}, {0xbb486000}, 
+    {0xbb488000}, {0xbb48a000}, {0xbb48c000}, {0xbb48e000}, 
+    {0xbb490000}, {0xbb492000}, {0xbb494000}, {0xbb496000}, 
+    {0xbb498000}, {0xbb49a000}, {0xbb49c000}, {0xbb49e000}, 
+    {0xbb4a0000}, {0xbb4a2000}, {0xbb4a4000}, {0xbb4a6000}, 
+    {0xbb4a8000}, {0xbb4aa000}, {0xbb4ac000}, {0xbb4ae000}, 
+    {0xbb4b0000}, {0xbb4b2000}, {0xbb4b4000}, {0xbb4b6000}, 
+    {0xbb4b8000}, {0xbb4ba000}, {0xbb4bc000}, {0xbb4be000}, 
+    {0xbb4c0000}, {0xbb4c2000}, {0xbb4c4000}, {0xbb4c6000}, 
+    {0xbb4c8000}, {0xbb4ca000}, {0xbb4cc000}, {0xbb4ce000}, 
+    {0xbb4d0000}, {0xbb4d2000}, {0xbb4d4000}, {0xbb4d6000}, 
+    {0xbb4d8000}, {0xbb4da000}, {0xbb4dc000}, {0xbb4de000}, 
+    {0xbb4e0000}, {0xbb4e2000}, {0xbb4e4000}, {0xbb4e6000}, 
+    {0xbb4e8000}, {0xbb4ea000}, {0xbb4ec000}, {0xbb4ee000}, 
+    {0xbb4f0000}, {0xbb4f2000}, {0xbb4f4000}, {0xbb4f6000}, 
+    {0xbb4f8000}, {0xbb4fa000}, {0xbb4fc000}, {0xbb4fe000}, 
+    {0xbb500000}, {0xbb502000}, {0xbb504000}, {0xbb506000}, 
+    {0xbb508000}, {0xbb50a000}, {0xbb50c000}, {0xbb50e000}, 
+    {0xbb510000}, {0xbb512000}, {0xbb514000}, {0xbb516000}, 
+    {0xbb518000}, {0xbb51a000}, {0xbb51c000}, {0xbb51e000}, 
+    {0xbb520000}, {0xbb522000}, {0xbb524000}, {0xbb526000}, 
+    {0xbb528000}, {0xbb52a000}, {0xbb52c000}, {0xbb52e000}, 
+    {0xbb530000}, {0xbb532000}, {0xbb534000}, {0xbb536000}, 
+    {0xbb538000}, {0xbb53a000}, {0xbb53c000}, {0xbb53e000}, 
+    {0xbb540000}, {0xbb542000}, {0xbb544000}, {0xbb546000}, 
+    {0xbb548000}, {0xbb54a000}, {0xbb54c000}, {0xbb54e000}, 
+    {0xbb550000}, {0xbb552000}, {0xbb554000}, {0xbb556000}, 
+    {0xbb558000}, {0xbb55a000}, {0xbb55c000}, {0xbb55e000}, 
+    {0xbb560000}, {0xbb562000}, {0xbb564000}, {0xbb566000}, 
+    {0xbb568000}, {0xbb56a000}, {0xbb56c000}, {0xbb56e000}, 
+    {0xbb570000}, {0xbb572000}, {0xbb574000}, {0xbb576000}, 
+    {0xbb578000}, {0xbb57a000}, {0xbb57c000}, {0xbb57e000}, 
+    {0xbb580000}, {0xbb582000}, {0xbb584000}, {0xbb586000}, 
+    {0xbb588000}, {0xbb58a000}, {0xbb58c000}, {0xbb58e000}, 
+    {0xbb590000}, {0xbb592000}, {0xbb594000}, {0xbb596000}, 
+    {0xbb598000}, {0xbb59a000}, {0xbb59c000}, {0xbb59e000}, 
+    {0xbb5a0000}, {0xbb5a2000}, {0xbb5a4000}, {0xbb5a6000}, 
+    {0xbb5a8000}, {0xbb5aa000}, {0xbb5ac000}, {0xbb5ae000}, 
+    {0xbb5b0000}, {0xbb5b2000}, {0xbb5b4000}, {0xbb5b6000}, 
+    {0xbb5b8000}, {0xbb5ba000}, {0xbb5bc000}, {0xbb5be000}, 
+    {0xbb5c0000}, {0xbb5c2000}, {0xbb5c4000}, {0xbb5c6000}, 
+    {0xbb5c8000}, {0xbb5ca000}, {0xbb5cc000}, {0xbb5ce000}, 
+    {0xbb5d0000}, {0xbb5d2000}, {0xbb5d4000}, {0xbb5d6000}, 
+    {0xbb5d8000}, {0xbb5da000}, {0xbb5dc000}, {0xbb5de000}, 
+    {0xbb5e0000}, {0xbb5e2000}, {0xbb5e4000}, {0xbb5e6000}, 
+    {0xbb5e8000}, {0xbb5ea000}, {0xbb5ec000}, {0xbb5ee000}, 
+    {0xbb5f0000}, {0xbb5f2000}, {0xbb5f4000}, {0xbb5f6000}, 
+    {0xbb5f8000}, {0xbb5fa000}, {0xbb5fc000}, {0xbb5fe000}, 
+    {0xbb600000}, {0xbb602000}, {0xbb604000}, {0xbb606000}, 
+    {0xbb608000}, {0xbb60a000}, {0xbb60c000}, {0xbb60e000}, 
+    {0xbb610000}, {0xbb612000}, {0xbb614000}, {0xbb616000}, 
+    {0xbb618000}, {0xbb61a000}, {0xbb61c000}, {0xbb61e000}, 
+    {0xbb620000}, {0xbb622000}, {0xbb624000}, {0xbb626000}, 
+    {0xbb628000}, {0xbb62a000}, {0xbb62c000}, {0xbb62e000}, 
+    {0xbb630000}, {0xbb632000}, {0xbb634000}, {0xbb636000}, 
+    {0xbb638000}, {0xbb63a000}, {0xbb63c000}, {0xbb63e000}, 
+    {0xbb640000}, {0xbb642000}, {0xbb644000}, {0xbb646000}, 
+    {0xbb648000}, {0xbb64a000}, {0xbb64c000}, {0xbb64e000}, 
+    {0xbb650000}, {0xbb652000}, {0xbb654000}, {0xbb656000}, 
+    {0xbb658000}, {0xbb65a000}, {0xbb65c000}, {0xbb65e000}, 
+    {0xbb660000}, {0xbb662000}, {0xbb664000}, {0xbb666000}, 
+    {0xbb668000}, {0xbb66a000}, {0xbb66c000}, {0xbb66e000}, 
+    {0xbb670000}, {0xbb672000}, {0xbb674000}, {0xbb676000}, 
+    {0xbb678000}, {0xbb67a000}, {0xbb67c000}, {0xbb67e000}, 
+    {0xbb680000}, {0xbb682000}, {0xbb684000}, {0xbb686000}, 
+    {0xbb688000}, {0xbb68a000}, {0xbb68c000}, {0xbb68e000}, 
+    {0xbb690000}, {0xbb692000}, {0xbb694000}, {0xbb696000}, 
+    {0xbb698000}, {0xbb69a000}, {0xbb69c000}, {0xbb69e000}, 
+    {0xbb6a0000}, {0xbb6a2000}, {0xbb6a4000}, {0xbb6a6000}, 
+    {0xbb6a8000}, {0xbb6aa000}, {0xbb6ac000}, {0xbb6ae000}, 
+    {0xbb6b0000}, {0xbb6b2000}, {0xbb6b4000}, {0xbb6b6000}, 
+    {0xbb6b8000}, {0xbb6ba000}, {0xbb6bc000}, {0xbb6be000}, 
+    {0xbb6c0000}, {0xbb6c2000}, {0xbb6c4000}, {0xbb6c6000}, 
+    {0xbb6c8000}, {0xbb6ca000}, {0xbb6cc000}, {0xbb6ce000}, 
+    {0xbb6d0000}, {0xbb6d2000}, {0xbb6d4000}, {0xbb6d6000}, 
+    {0xbb6d8000}, {0xbb6da000}, {0xbb6dc000}, {0xbb6de000}, 
+    {0xbb6e0000}, {0xbb6e2000}, {0xbb6e4000}, {0xbb6e6000}, 
+    {0xbb6e8000}, {0xbb6ea000}, {0xbb6ec000}, {0xbb6ee000}, 
+    {0xbb6f0000}, {0xbb6f2000}, {0xbb6f4000}, {0xbb6f6000}, 
+    {0xbb6f8000}, {0xbb6fa000}, {0xbb6fc000}, {0xbb6fe000}, 
+    {0xbb700000}, {0xbb702000}, {0xbb704000}, {0xbb706000}, 
+    {0xbb708000}, {0xbb70a000}, {0xbb70c000}, {0xbb70e000}, 
+    {0xbb710000}, {0xbb712000}, {0xbb714000}, {0xbb716000}, 
+    {0xbb718000}, {0xbb71a000}, {0xbb71c000}, {0xbb71e000}, 
+    {0xbb720000}, {0xbb722000}, {0xbb724000}, {0xbb726000}, 
+    {0xbb728000}, {0xbb72a000}, {0xbb72c000}, {0xbb72e000}, 
+    {0xbb730000}, {0xbb732000}, {0xbb734000}, {0xbb736000}, 
+    {0xbb738000}, {0xbb73a000}, {0xbb73c000}, {0xbb73e000}, 
+    {0xbb740000}, {0xbb742000}, {0xbb744000}, {0xbb746000}, 
+    {0xbb748000}, {0xbb74a000}, {0xbb74c000}, {0xbb74e000}, 
+    {0xbb750000}, {0xbb752000}, {0xbb754000}, {0xbb756000}, 
+    {0xbb758000}, {0xbb75a000}, {0xbb75c000}, {0xbb75e000}, 
+    {0xbb760000}, {0xbb762000}, {0xbb764000}, {0xbb766000}, 
+    {0xbb768000}, {0xbb76a000}, {0xbb76c000}, {0xbb76e000}, 
+    {0xbb770000}, {0xbb772000}, {0xbb774000}, {0xbb776000}, 
+    {0xbb778000}, {0xbb77a000}, {0xbb77c000}, {0xbb77e000}, 
+    {0xbb780000}, {0xbb782000}, {0xbb784000}, {0xbb786000}, 
+    {0xbb788000}, {0xbb78a000}, {0xbb78c000}, {0xbb78e000}, 
+    {0xbb790000}, {0xbb792000}, {0xbb794000}, {0xbb796000}, 
+    {0xbb798000}, {0xbb79a000}, {0xbb79c000}, {0xbb79e000}, 
+    {0xbb7a0000}, {0xbb7a2000}, {0xbb7a4000}, {0xbb7a6000}, 
+    {0xbb7a8000}, {0xbb7aa000}, {0xbb7ac000}, {0xbb7ae000}, 
+    {0xbb7b0000}, {0xbb7b2000}, {0xbb7b4000}, {0xbb7b6000}, 
+    {0xbb7b8000}, {0xbb7ba000}, {0xbb7bc000}, {0xbb7be000}, 
+    {0xbb7c0000}, {0xbb7c2000}, {0xbb7c4000}, {0xbb7c6000}, 
+    {0xbb7c8000}, {0xbb7ca000}, {0xbb7cc000}, {0xbb7ce000}, 
+    {0xbb7d0000}, {0xbb7d2000}, {0xbb7d4000}, {0xbb7d6000}, 
+    {0xbb7d8000}, {0xbb7da000}, {0xbb7dc000}, {0xbb7de000}, 
+    {0xbb7e0000}, {0xbb7e2000}, {0xbb7e4000}, {0xbb7e6000}, 
+    {0xbb7e8000}, {0xbb7ea000}, {0xbb7ec000}, {0xbb7ee000}, 
+    {0xbb7f0000}, {0xbb7f2000}, {0xbb7f4000}, {0xbb7f6000}, 
+    {0xbb7f8000}, {0xbb7fa000}, {0xbb7fc000}, {0xbb7fe000}, 
+    {0xbb800000}, {0xbb802000}, {0xbb804000}, {0xbb806000}, 
+    {0xbb808000}, {0xbb80a000}, {0xbb80c000}, {0xbb80e000}, 
+    {0xbb810000}, {0xbb812000}, {0xbb814000}, {0xbb816000}, 
+    {0xbb818000}, {0xbb81a000}, {0xbb81c000}, {0xbb81e000}, 
+    {0xbb820000}, {0xbb822000}, {0xbb824000}, {0xbb826000}, 
+    {0xbb828000}, {0xbb82a000}, {0xbb82c000}, {0xbb82e000}, 
+    {0xbb830000}, {0xbb832000}, {0xbb834000}, {0xbb836000}, 
+    {0xbb838000}, {0xbb83a000}, {0xbb83c000}, {0xbb83e000}, 
+    {0xbb840000}, {0xbb842000}, {0xbb844000}, {0xbb846000}, 
+    {0xbb848000}, {0xbb84a000}, {0xbb84c000}, {0xbb84e000}, 
+    {0xbb850000}, {0xbb852000}, {0xbb854000}, {0xbb856000}, 
+    {0xbb858000}, {0xbb85a000}, {0xbb85c000}, {0xbb85e000}, 
+    {0xbb860000}, {0xbb862000}, {0xbb864000}, {0xbb866000}, 
+    {0xbb868000}, {0xbb86a000}, {0xbb86c000}, {0xbb86e000}, 
+    {0xbb870000}, {0xbb872000}, {0xbb874000}, {0xbb876000}, 
+    {0xbb878000}, {0xbb87a000}, {0xbb87c000}, {0xbb87e000}, 
+    {0xbb880000}, {0xbb882000}, {0xbb884000}, {0xbb886000}, 
+    {0xbb888000}, {0xbb88a000}, {0xbb88c000}, {0xbb88e000}, 
+    {0xbb890000}, {0xbb892000}, {0xbb894000}, {0xbb896000}, 
+    {0xbb898000}, {0xbb89a000}, {0xbb89c000}, {0xbb89e000}, 
+    {0xbb8a0000}, {0xbb8a2000}, {0xbb8a4000}, {0xbb8a6000}, 
+    {0xbb8a8000}, {0xbb8aa000}, {0xbb8ac000}, {0xbb8ae000}, 
+    {0xbb8b0000}, {0xbb8b2000}, {0xbb8b4000}, {0xbb8b6000}, 
+    {0xbb8b8000}, {0xbb8ba000}, {0xbb8bc000}, {0xbb8be000}, 
+    {0xbb8c0000}, {0xbb8c2000}, {0xbb8c4000}, {0xbb8c6000}, 
+    {0xbb8c8000}, {0xbb8ca000}, {0xbb8cc000}, {0xbb8ce000}, 
+    {0xbb8d0000}, {0xbb8d2000}, {0xbb8d4000}, {0xbb8d6000}, 
+    {0xbb8d8000}, {0xbb8da000}, {0xbb8dc000}, {0xbb8de000}, 
+    {0xbb8e0000}, {0xbb8e2000}, {0xbb8e4000}, {0xbb8e6000}, 
+    {0xbb8e8000}, {0xbb8ea000}, {0xbb8ec000}, {0xbb8ee000}, 
+    {0xbb8f0000}, {0xbb8f2000}, {0xbb8f4000}, {0xbb8f6000}, 
+    {0xbb8f8000}, {0xbb8fa000}, {0xbb8fc000}, {0xbb8fe000}, 
+    {0xbb900000}, {0xbb902000}, {0xbb904000}, {0xbb906000}, 
+    {0xbb908000}, {0xbb90a000}, {0xbb90c000}, {0xbb90e000}, 
+    {0xbb910000}, {0xbb912000}, {0xbb914000}, {0xbb916000}, 
+    {0xbb918000}, {0xbb91a000}, {0xbb91c000}, {0xbb91e000}, 
+    {0xbb920000}, {0xbb922000}, {0xbb924000}, {0xbb926000}, 
+    {0xbb928000}, {0xbb92a000}, {0xbb92c000}, {0xbb92e000}, 
+    {0xbb930000}, {0xbb932000}, {0xbb934000}, {0xbb936000}, 
+    {0xbb938000}, {0xbb93a000}, {0xbb93c000}, {0xbb93e000}, 
+    {0xbb940000}, {0xbb942000}, {0xbb944000}, {0xbb946000}, 
+    {0xbb948000}, {0xbb94a000}, {0xbb94c000}, {0xbb94e000}, 
+    {0xbb950000}, {0xbb952000}, {0xbb954000}, {0xbb956000}, 
+    {0xbb958000}, {0xbb95a000}, {0xbb95c000}, {0xbb95e000}, 
+    {0xbb960000}, {0xbb962000}, {0xbb964000}, {0xbb966000}, 
+    {0xbb968000}, {0xbb96a000}, {0xbb96c000}, {0xbb96e000}, 
+    {0xbb970000}, {0xbb972000}, {0xbb974000}, {0xbb976000}, 
+    {0xbb978000}, {0xbb97a000}, {0xbb97c000}, {0xbb97e000}, 
+    {0xbb980000}, {0xbb982000}, {0xbb984000}, {0xbb986000}, 
+    {0xbb988000}, {0xbb98a000}, {0xbb98c000}, {0xbb98e000}, 
+    {0xbb990000}, {0xbb992000}, {0xbb994000}, {0xbb996000}, 
+    {0xbb998000}, {0xbb99a000}, {0xbb99c000}, {0xbb99e000}, 
+    {0xbb9a0000}, {0xbb9a2000}, {0xbb9a4000}, {0xbb9a6000}, 
+    {0xbb9a8000}, {0xbb9aa000}, {0xbb9ac000}, {0xbb9ae000}, 
+    {0xbb9b0000}, {0xbb9b2000}, {0xbb9b4000}, {0xbb9b6000}, 
+    {0xbb9b8000}, {0xbb9ba000}, {0xbb9bc000}, {0xbb9be000}, 
+    {0xbb9c0000}, {0xbb9c2000}, {0xbb9c4000}, {0xbb9c6000}, 
+    {0xbb9c8000}, {0xbb9ca000}, {0xbb9cc000}, {0xbb9ce000}, 
+    {0xbb9d0000}, {0xbb9d2000}, {0xbb9d4000}, {0xbb9d6000}, 
+    {0xbb9d8000}, {0xbb9da000}, {0xbb9dc000}, {0xbb9de000}, 
+    {0xbb9e0000}, {0xbb9e2000}, {0xbb9e4000}, {0xbb9e6000}, 
+    {0xbb9e8000}, {0xbb9ea000}, {0xbb9ec000}, {0xbb9ee000}, 
+    {0xbb9f0000}, {0xbb9f2000}, {0xbb9f4000}, {0xbb9f6000}, 
+    {0xbb9f8000}, {0xbb9fa000}, {0xbb9fc000}, {0xbb9fe000}, 
+    {0xbba00000}, {0xbba02000}, {0xbba04000}, {0xbba06000}, 
+    {0xbba08000}, {0xbba0a000}, {0xbba0c000}, {0xbba0e000}, 
+    {0xbba10000}, {0xbba12000}, {0xbba14000}, {0xbba16000}, 
+    {0xbba18000}, {0xbba1a000}, {0xbba1c000}, {0xbba1e000}, 
+    {0xbba20000}, {0xbba22000}, {0xbba24000}, {0xbba26000}, 
+    {0xbba28000}, {0xbba2a000}, {0xbba2c000}, {0xbba2e000}, 
+    {0xbba30000}, {0xbba32000}, {0xbba34000}, {0xbba36000}, 
+    {0xbba38000}, {0xbba3a000}, {0xbba3c000}, {0xbba3e000}, 
+    {0xbba40000}, {0xbba42000}, {0xbba44000}, {0xbba46000}, 
+    {0xbba48000}, {0xbba4a000}, {0xbba4c000}, {0xbba4e000}, 
+    {0xbba50000}, {0xbba52000}, {0xbba54000}, {0xbba56000}, 
+    {0xbba58000}, {0xbba5a000}, {0xbba5c000}, {0xbba5e000}, 
+    {0xbba60000}, {0xbba62000}, {0xbba64000}, {0xbba66000}, 
+    {0xbba68000}, {0xbba6a000}, {0xbba6c000}, {0xbba6e000}, 
+    {0xbba70000}, {0xbba72000}, {0xbba74000}, {0xbba76000}, 
+    {0xbba78000}, {0xbba7a000}, {0xbba7c000}, {0xbba7e000}, 
+    {0xbba80000}, {0xbba82000}, {0xbba84000}, {0xbba86000}, 
+    {0xbba88000}, {0xbba8a000}, {0xbba8c000}, {0xbba8e000}, 
+    {0xbba90000}, {0xbba92000}, {0xbba94000}, {0xbba96000}, 
+    {0xbba98000}, {0xbba9a000}, {0xbba9c000}, {0xbba9e000}, 
+    {0xbbaa0000}, {0xbbaa2000}, {0xbbaa4000}, {0xbbaa6000}, 
+    {0xbbaa8000}, {0xbbaaa000}, {0xbbaac000}, {0xbbaae000}, 
+    {0xbbab0000}, {0xbbab2000}, {0xbbab4000}, {0xbbab6000}, 
+    {0xbbab8000}, {0xbbaba000}, {0xbbabc000}, {0xbbabe000}, 
+    {0xbbac0000}, {0xbbac2000}, {0xbbac4000}, {0xbbac6000}, 
+    {0xbbac8000}, {0xbbaca000}, {0xbbacc000}, {0xbbace000}, 
+    {0xbbad0000}, {0xbbad2000}, {0xbbad4000}, {0xbbad6000}, 
+    {0xbbad8000}, {0xbbada000}, {0xbbadc000}, {0xbbade000}, 
+    {0xbbae0000}, {0xbbae2000}, {0xbbae4000}, {0xbbae6000}, 
+    {0xbbae8000}, {0xbbaea000}, {0xbbaec000}, {0xbbaee000}, 
+    {0xbbaf0000}, {0xbbaf2000}, {0xbbaf4000}, {0xbbaf6000}, 
+    {0xbbaf8000}, {0xbbafa000}, {0xbbafc000}, {0xbbafe000}, 
+    {0xbbb00000}, {0xbbb02000}, {0xbbb04000}, {0xbbb06000}, 
+    {0xbbb08000}, {0xbbb0a000}, {0xbbb0c000}, {0xbbb0e000}, 
+    {0xbbb10000}, {0xbbb12000}, {0xbbb14000}, {0xbbb16000}, 
+    {0xbbb18000}, {0xbbb1a000}, {0xbbb1c000}, {0xbbb1e000}, 
+    {0xbbb20000}, {0xbbb22000}, {0xbbb24000}, {0xbbb26000}, 
+    {0xbbb28000}, {0xbbb2a000}, {0xbbb2c000}, {0xbbb2e000}, 
+    {0xbbb30000}, {0xbbb32000}, {0xbbb34000}, {0xbbb36000}, 
+    {0xbbb38000}, {0xbbb3a000}, {0xbbb3c000}, {0xbbb3e000}, 
+    {0xbbb40000}, {0xbbb42000}, {0xbbb44000}, {0xbbb46000}, 
+    {0xbbb48000}, {0xbbb4a000}, {0xbbb4c000}, {0xbbb4e000}, 
+    {0xbbb50000}, {0xbbb52000}, {0xbbb54000}, {0xbbb56000}, 
+    {0xbbb58000}, {0xbbb5a000}, {0xbbb5c000}, {0xbbb5e000}, 
+    {0xbbb60000}, {0xbbb62000}, {0xbbb64000}, {0xbbb66000}, 
+    {0xbbb68000}, {0xbbb6a000}, {0xbbb6c000}, {0xbbb6e000}, 
+    {0xbbb70000}, {0xbbb72000}, {0xbbb74000}, {0xbbb76000}, 
+    {0xbbb78000}, {0xbbb7a000}, {0xbbb7c000}, {0xbbb7e000}, 
+    {0xbbb80000}, {0xbbb82000}, {0xbbb84000}, {0xbbb86000}, 
+    {0xbbb88000}, {0xbbb8a000}, {0xbbb8c000}, {0xbbb8e000}, 
+    {0xbbb90000}, {0xbbb92000}, {0xbbb94000}, {0xbbb96000}, 
+    {0xbbb98000}, {0xbbb9a000}, {0xbbb9c000}, {0xbbb9e000}, 
+    {0xbbba0000}, {0xbbba2000}, {0xbbba4000}, {0xbbba6000}, 
+    {0xbbba8000}, {0xbbbaa000}, {0xbbbac000}, {0xbbbae000}, 
+    {0xbbbb0000}, {0xbbbb2000}, {0xbbbb4000}, {0xbbbb6000}, 
+    {0xbbbb8000}, {0xbbbba000}, {0xbbbbc000}, {0xbbbbe000}, 
+    {0xbbbc0000}, {0xbbbc2000}, {0xbbbc4000}, {0xbbbc6000}, 
+    {0xbbbc8000}, {0xbbbca000}, {0xbbbcc000}, {0xbbbce000}, 
+    {0xbbbd0000}, {0xbbbd2000}, {0xbbbd4000}, {0xbbbd6000}, 
+    {0xbbbd8000}, {0xbbbda000}, {0xbbbdc000}, {0xbbbde000}, 
+    {0xbbbe0000}, {0xbbbe2000}, {0xbbbe4000}, {0xbbbe6000}, 
+    {0xbbbe8000}, {0xbbbea000}, {0xbbbec000}, {0xbbbee000}, 
+    {0xbbbf0000}, {0xbbbf2000}, {0xbbbf4000}, {0xbbbf6000}, 
+    {0xbbbf8000}, {0xbbbfa000}, {0xbbbfc000}, {0xbbbfe000}, 
+    {0xbbc00000}, {0xbbc02000}, {0xbbc04000}, {0xbbc06000}, 
+    {0xbbc08000}, {0xbbc0a000}, {0xbbc0c000}, {0xbbc0e000}, 
+    {0xbbc10000}, {0xbbc12000}, {0xbbc14000}, {0xbbc16000}, 
+    {0xbbc18000}, {0xbbc1a000}, {0xbbc1c000}, {0xbbc1e000}, 
+    {0xbbc20000}, {0xbbc22000}, {0xbbc24000}, {0xbbc26000}, 
+    {0xbbc28000}, {0xbbc2a000}, {0xbbc2c000}, {0xbbc2e000}, 
+    {0xbbc30000}, {0xbbc32000}, {0xbbc34000}, {0xbbc36000}, 
+    {0xbbc38000}, {0xbbc3a000}, {0xbbc3c000}, {0xbbc3e000}, 
+    {0xbbc40000}, {0xbbc42000}, {0xbbc44000}, {0xbbc46000}, 
+    {0xbbc48000}, {0xbbc4a000}, {0xbbc4c000}, {0xbbc4e000}, 
+    {0xbbc50000}, {0xbbc52000}, {0xbbc54000}, {0xbbc56000}, 
+    {0xbbc58000}, {0xbbc5a000}, {0xbbc5c000}, {0xbbc5e000}, 
+    {0xbbc60000}, {0xbbc62000}, {0xbbc64000}, {0xbbc66000}, 
+    {0xbbc68000}, {0xbbc6a000}, {0xbbc6c000}, {0xbbc6e000}, 
+    {0xbbc70000}, {0xbbc72000}, {0xbbc74000}, {0xbbc76000}, 
+    {0xbbc78000}, {0xbbc7a000}, {0xbbc7c000}, {0xbbc7e000}, 
+    {0xbbc80000}, {0xbbc82000}, {0xbbc84000}, {0xbbc86000}, 
+    {0xbbc88000}, {0xbbc8a000}, {0xbbc8c000}, {0xbbc8e000}, 
+    {0xbbc90000}, {0xbbc92000}, {0xbbc94000}, {0xbbc96000}, 
+    {0xbbc98000}, {0xbbc9a000}, {0xbbc9c000}, {0xbbc9e000}, 
+    {0xbbca0000}, {0xbbca2000}, {0xbbca4000}, {0xbbca6000}, 
+    {0xbbca8000}, {0xbbcaa000}, {0xbbcac000}, {0xbbcae000}, 
+    {0xbbcb0000}, {0xbbcb2000}, {0xbbcb4000}, {0xbbcb6000}, 
+    {0xbbcb8000}, {0xbbcba000}, {0xbbcbc000}, {0xbbcbe000}, 
+    {0xbbcc0000}, {0xbbcc2000}, {0xbbcc4000}, {0xbbcc6000}, 
+    {0xbbcc8000}, {0xbbcca000}, {0xbbccc000}, {0xbbcce000}, 
+    {0xbbcd0000}, {0xbbcd2000}, {0xbbcd4000}, {0xbbcd6000}, 
+    {0xbbcd8000}, {0xbbcda000}, {0xbbcdc000}, {0xbbcde000}, 
+    {0xbbce0000}, {0xbbce2000}, {0xbbce4000}, {0xbbce6000}, 
+    {0xbbce8000}, {0xbbcea000}, {0xbbcec000}, {0xbbcee000}, 
+    {0xbbcf0000}, {0xbbcf2000}, {0xbbcf4000}, {0xbbcf6000}, 
+    {0xbbcf8000}, {0xbbcfa000}, {0xbbcfc000}, {0xbbcfe000}, 
+    {0xbbd00000}, {0xbbd02000}, {0xbbd04000}, {0xbbd06000}, 
+    {0xbbd08000}, {0xbbd0a000}, {0xbbd0c000}, {0xbbd0e000}, 
+    {0xbbd10000}, {0xbbd12000}, {0xbbd14000}, {0xbbd16000}, 
+    {0xbbd18000}, {0xbbd1a000}, {0xbbd1c000}, {0xbbd1e000}, 
+    {0xbbd20000}, {0xbbd22000}, {0xbbd24000}, {0xbbd26000}, 
+    {0xbbd28000}, {0xbbd2a000}, {0xbbd2c000}, {0xbbd2e000}, 
+    {0xbbd30000}, {0xbbd32000}, {0xbbd34000}, {0xbbd36000}, 
+    {0xbbd38000}, {0xbbd3a000}, {0xbbd3c000}, {0xbbd3e000}, 
+    {0xbbd40000}, {0xbbd42000}, {0xbbd44000}, {0xbbd46000}, 
+    {0xbbd48000}, {0xbbd4a000}, {0xbbd4c000}, {0xbbd4e000}, 
+    {0xbbd50000}, {0xbbd52000}, {0xbbd54000}, {0xbbd56000}, 
+    {0xbbd58000}, {0xbbd5a000}, {0xbbd5c000}, {0xbbd5e000}, 
+    {0xbbd60000}, {0xbbd62000}, {0xbbd64000}, {0xbbd66000}, 
+    {0xbbd68000}, {0xbbd6a000}, {0xbbd6c000}, {0xbbd6e000}, 
+    {0xbbd70000}, {0xbbd72000}, {0xbbd74000}, {0xbbd76000}, 
+    {0xbbd78000}, {0xbbd7a000}, {0xbbd7c000}, {0xbbd7e000}, 
+    {0xbbd80000}, {0xbbd82000}, {0xbbd84000}, {0xbbd86000}, 
+    {0xbbd88000}, {0xbbd8a000}, {0xbbd8c000}, {0xbbd8e000}, 
+    {0xbbd90000}, {0xbbd92000}, {0xbbd94000}, {0xbbd96000}, 
+    {0xbbd98000}, {0xbbd9a000}, {0xbbd9c000}, {0xbbd9e000}, 
+    {0xbbda0000}, {0xbbda2000}, {0xbbda4000}, {0xbbda6000}, 
+    {0xbbda8000}, {0xbbdaa000}, {0xbbdac000}, {0xbbdae000}, 
+    {0xbbdb0000}, {0xbbdb2000}, {0xbbdb4000}, {0xbbdb6000}, 
+    {0xbbdb8000}, {0xbbdba000}, {0xbbdbc000}, {0xbbdbe000}, 
+    {0xbbdc0000}, {0xbbdc2000}, {0xbbdc4000}, {0xbbdc6000}, 
+    {0xbbdc8000}, {0xbbdca000}, {0xbbdcc000}, {0xbbdce000}, 
+    {0xbbdd0000}, {0xbbdd2000}, {0xbbdd4000}, {0xbbdd6000}, 
+    {0xbbdd8000}, {0xbbdda000}, {0xbbddc000}, {0xbbdde000}, 
+    {0xbbde0000}, {0xbbde2000}, {0xbbde4000}, {0xbbde6000}, 
+    {0xbbde8000}, {0xbbdea000}, {0xbbdec000}, {0xbbdee000}, 
+    {0xbbdf0000}, {0xbbdf2000}, {0xbbdf4000}, {0xbbdf6000}, 
+    {0xbbdf8000}, {0xbbdfa000}, {0xbbdfc000}, {0xbbdfe000}, 
+    {0xbbe00000}, {0xbbe02000}, {0xbbe04000}, {0xbbe06000}, 
+    {0xbbe08000}, {0xbbe0a000}, {0xbbe0c000}, {0xbbe0e000}, 
+    {0xbbe10000}, {0xbbe12000}, {0xbbe14000}, {0xbbe16000}, 
+    {0xbbe18000}, {0xbbe1a000}, {0xbbe1c000}, {0xbbe1e000}, 
+    {0xbbe20000}, {0xbbe22000}, {0xbbe24000}, {0xbbe26000}, 
+    {0xbbe28000}, {0xbbe2a000}, {0xbbe2c000}, {0xbbe2e000}, 
+    {0xbbe30000}, {0xbbe32000}, {0xbbe34000}, {0xbbe36000}, 
+    {0xbbe38000}, {0xbbe3a000}, {0xbbe3c000}, {0xbbe3e000}, 
+    {0xbbe40000}, {0xbbe42000}, {0xbbe44000}, {0xbbe46000}, 
+    {0xbbe48000}, {0xbbe4a000}, {0xbbe4c000}, {0xbbe4e000}, 
+    {0xbbe50000}, {0xbbe52000}, {0xbbe54000}, {0xbbe56000}, 
+    {0xbbe58000}, {0xbbe5a000}, {0xbbe5c000}, {0xbbe5e000}, 
+    {0xbbe60000}, {0xbbe62000}, {0xbbe64000}, {0xbbe66000}, 
+    {0xbbe68000}, {0xbbe6a000}, {0xbbe6c000}, {0xbbe6e000}, 
+    {0xbbe70000}, {0xbbe72000}, {0xbbe74000}, {0xbbe76000}, 
+    {0xbbe78000}, {0xbbe7a000}, {0xbbe7c000}, {0xbbe7e000}, 
+    {0xbbe80000}, {0xbbe82000}, {0xbbe84000}, {0xbbe86000}, 
+    {0xbbe88000}, {0xbbe8a000}, {0xbbe8c000}, {0xbbe8e000}, 
+    {0xbbe90000}, {0xbbe92000}, {0xbbe94000}, {0xbbe96000}, 
+    {0xbbe98000}, {0xbbe9a000}, {0xbbe9c000}, {0xbbe9e000}, 
+    {0xbbea0000}, {0xbbea2000}, {0xbbea4000}, {0xbbea6000}, 
+    {0xbbea8000}, {0xbbeaa000}, {0xbbeac000}, {0xbbeae000}, 
+    {0xbbeb0000}, {0xbbeb2000}, {0xbbeb4000}, {0xbbeb6000}, 
+    {0xbbeb8000}, {0xbbeba000}, {0xbbebc000}, {0xbbebe000}, 
+    {0xbbec0000}, {0xbbec2000}, {0xbbec4000}, {0xbbec6000}, 
+    {0xbbec8000}, {0xbbeca000}, {0xbbecc000}, {0xbbece000}, 
+    {0xbbed0000}, {0xbbed2000}, {0xbbed4000}, {0xbbed6000}, 
+    {0xbbed8000}, {0xbbeda000}, {0xbbedc000}, {0xbbede000}, 
+    {0xbbee0000}, {0xbbee2000}, {0xbbee4000}, {0xbbee6000}, 
+    {0xbbee8000}, {0xbbeea000}, {0xbbeec000}, {0xbbeee000}, 
+    {0xbbef0000}, {0xbbef2000}, {0xbbef4000}, {0xbbef6000}, 
+    {0xbbef8000}, {0xbbefa000}, {0xbbefc000}, {0xbbefe000}, 
+    {0xbbf00000}, {0xbbf02000}, {0xbbf04000}, {0xbbf06000}, 
+    {0xbbf08000}, {0xbbf0a000}, {0xbbf0c000}, {0xbbf0e000}, 
+    {0xbbf10000}, {0xbbf12000}, {0xbbf14000}, {0xbbf16000}, 
+    {0xbbf18000}, {0xbbf1a000}, {0xbbf1c000}, {0xbbf1e000}, 
+    {0xbbf20000}, {0xbbf22000}, {0xbbf24000}, {0xbbf26000}, 
+    {0xbbf28000}, {0xbbf2a000}, {0xbbf2c000}, {0xbbf2e000}, 
+    {0xbbf30000}, {0xbbf32000}, {0xbbf34000}, {0xbbf36000}, 
+    {0xbbf38000}, {0xbbf3a000}, {0xbbf3c000}, {0xbbf3e000}, 
+    {0xbbf40000}, {0xbbf42000}, {0xbbf44000}, {0xbbf46000}, 
+    {0xbbf48000}, {0xbbf4a000}, {0xbbf4c000}, {0xbbf4e000}, 
+    {0xbbf50000}, {0xbbf52000}, {0xbbf54000}, {0xbbf56000}, 
+    {0xbbf58000}, {0xbbf5a000}, {0xbbf5c000}, {0xbbf5e000}, 
+    {0xbbf60000}, {0xbbf62000}, {0xbbf64000}, {0xbbf66000}, 
+    {0xbbf68000}, {0xbbf6a000}, {0xbbf6c000}, {0xbbf6e000}, 
+    {0xbbf70000}, {0xbbf72000}, {0xbbf74000}, {0xbbf76000}, 
+    {0xbbf78000}, {0xbbf7a000}, {0xbbf7c000}, {0xbbf7e000}, 
+    {0xbbf80000}, {0xbbf82000}, {0xbbf84000}, {0xbbf86000}, 
+    {0xbbf88000}, {0xbbf8a000}, {0xbbf8c000}, {0xbbf8e000}, 
+    {0xbbf90000}, {0xbbf92000}, {0xbbf94000}, {0xbbf96000}, 
+    {0xbbf98000}, {0xbbf9a000}, {0xbbf9c000}, {0xbbf9e000}, 
+    {0xbbfa0000}, {0xbbfa2000}, {0xbbfa4000}, {0xbbfa6000}, 
+    {0xbbfa8000}, {0xbbfaa000}, {0xbbfac000}, {0xbbfae000}, 
+    {0xbbfb0000}, {0xbbfb2000}, {0xbbfb4000}, {0xbbfb6000}, 
+    {0xbbfb8000}, {0xbbfba000}, {0xbbfbc000}, {0xbbfbe000}, 
+    {0xbbfc0000}, {0xbbfc2000}, {0xbbfc4000}, {0xbbfc6000}, 
+    {0xbbfc8000}, {0xbbfca000}, {0xbbfcc000}, {0xbbfce000}, 
+    {0xbbfd0000}, {0xbbfd2000}, {0xbbfd4000}, {0xbbfd6000}, 
+    {0xbbfd8000}, {0xbbfda000}, {0xbbfdc000}, {0xbbfde000}, 
+    {0xbbfe0000}, {0xbbfe2000}, {0xbbfe4000}, {0xbbfe6000}, 
+    {0xbbfe8000}, {0xbbfea000}, {0xbbfec000}, {0xbbfee000}, 
+    {0xbbff0000}, {0xbbff2000}, {0xbbff4000}, {0xbbff6000}, 
+    {0xbbff8000}, {0xbbffa000}, {0xbbffc000}, {0xbbffe000}, 
+    {0xbc000000}, {0xbc002000}, {0xbc004000}, {0xbc006000}, 
+    {0xbc008000}, {0xbc00a000}, {0xbc00c000}, {0xbc00e000}, 
+    {0xbc010000}, {0xbc012000}, {0xbc014000}, {0xbc016000}, 
+    {0xbc018000}, {0xbc01a000}, {0xbc01c000}, {0xbc01e000}, 
+    {0xbc020000}, {0xbc022000}, {0xbc024000}, {0xbc026000}, 
+    {0xbc028000}, {0xbc02a000}, {0xbc02c000}, {0xbc02e000}, 
+    {0xbc030000}, {0xbc032000}, {0xbc034000}, {0xbc036000}, 
+    {0xbc038000}, {0xbc03a000}, {0xbc03c000}, {0xbc03e000}, 
+    {0xbc040000}, {0xbc042000}, {0xbc044000}, {0xbc046000}, 
+    {0xbc048000}, {0xbc04a000}, {0xbc04c000}, {0xbc04e000}, 
+    {0xbc050000}, {0xbc052000}, {0xbc054000}, {0xbc056000}, 
+    {0xbc058000}, {0xbc05a000}, {0xbc05c000}, {0xbc05e000}, 
+    {0xbc060000}, {0xbc062000}, {0xbc064000}, {0xbc066000}, 
+    {0xbc068000}, {0xbc06a000}, {0xbc06c000}, {0xbc06e000}, 
+    {0xbc070000}, {0xbc072000}, {0xbc074000}, {0xbc076000}, 
+    {0xbc078000}, {0xbc07a000}, {0xbc07c000}, {0xbc07e000}, 
+    {0xbc080000}, {0xbc082000}, {0xbc084000}, {0xbc086000}, 
+    {0xbc088000}, {0xbc08a000}, {0xbc08c000}, {0xbc08e000}, 
+    {0xbc090000}, {0xbc092000}, {0xbc094000}, {0xbc096000}, 
+    {0xbc098000}, {0xbc09a000}, {0xbc09c000}, {0xbc09e000}, 
+    {0xbc0a0000}, {0xbc0a2000}, {0xbc0a4000}, {0xbc0a6000}, 
+    {0xbc0a8000}, {0xbc0aa000}, {0xbc0ac000}, {0xbc0ae000}, 
+    {0xbc0b0000}, {0xbc0b2000}, {0xbc0b4000}, {0xbc0b6000}, 
+    {0xbc0b8000}, {0xbc0ba000}, {0xbc0bc000}, {0xbc0be000}, 
+    {0xbc0c0000}, {0xbc0c2000}, {0xbc0c4000}, {0xbc0c6000}, 
+    {0xbc0c8000}, {0xbc0ca000}, {0xbc0cc000}, {0xbc0ce000}, 
+    {0xbc0d0000}, {0xbc0d2000}, {0xbc0d4000}, {0xbc0d6000}, 
+    {0xbc0d8000}, {0xbc0da000}, {0xbc0dc000}, {0xbc0de000}, 
+    {0xbc0e0000}, {0xbc0e2000}, {0xbc0e4000}, {0xbc0e6000}, 
+    {0xbc0e8000}, {0xbc0ea000}, {0xbc0ec000}, {0xbc0ee000}, 
+    {0xbc0f0000}, {0xbc0f2000}, {0xbc0f4000}, {0xbc0f6000}, 
+    {0xbc0f8000}, {0xbc0fa000}, {0xbc0fc000}, {0xbc0fe000}, 
+    {0xbc100000}, {0xbc102000}, {0xbc104000}, {0xbc106000}, 
+    {0xbc108000}, {0xbc10a000}, {0xbc10c000}, {0xbc10e000}, 
+    {0xbc110000}, {0xbc112000}, {0xbc114000}, {0xbc116000}, 
+    {0xbc118000}, {0xbc11a000}, {0xbc11c000}, {0xbc11e000}, 
+    {0xbc120000}, {0xbc122000}, {0xbc124000}, {0xbc126000}, 
+    {0xbc128000}, {0xbc12a000}, {0xbc12c000}, {0xbc12e000}, 
+    {0xbc130000}, {0xbc132000}, {0xbc134000}, {0xbc136000}, 
+    {0xbc138000}, {0xbc13a000}, {0xbc13c000}, {0xbc13e000}, 
+    {0xbc140000}, {0xbc142000}, {0xbc144000}, {0xbc146000}, 
+    {0xbc148000}, {0xbc14a000}, {0xbc14c000}, {0xbc14e000}, 
+    {0xbc150000}, {0xbc152000}, {0xbc154000}, {0xbc156000}, 
+    {0xbc158000}, {0xbc15a000}, {0xbc15c000}, {0xbc15e000}, 
+    {0xbc160000}, {0xbc162000}, {0xbc164000}, {0xbc166000}, 
+    {0xbc168000}, {0xbc16a000}, {0xbc16c000}, {0xbc16e000}, 
+    {0xbc170000}, {0xbc172000}, {0xbc174000}, {0xbc176000}, 
+    {0xbc178000}, {0xbc17a000}, {0xbc17c000}, {0xbc17e000}, 
+    {0xbc180000}, {0xbc182000}, {0xbc184000}, {0xbc186000}, 
+    {0xbc188000}, {0xbc18a000}, {0xbc18c000}, {0xbc18e000}, 
+    {0xbc190000}, {0xbc192000}, {0xbc194000}, {0xbc196000}, 
+    {0xbc198000}, {0xbc19a000}, {0xbc19c000}, {0xbc19e000}, 
+    {0xbc1a0000}, {0xbc1a2000}, {0xbc1a4000}, {0xbc1a6000}, 
+    {0xbc1a8000}, {0xbc1aa000}, {0xbc1ac000}, {0xbc1ae000}, 
+    {0xbc1b0000}, {0xbc1b2000}, {0xbc1b4000}, {0xbc1b6000}, 
+    {0xbc1b8000}, {0xbc1ba000}, {0xbc1bc000}, {0xbc1be000}, 
+    {0xbc1c0000}, {0xbc1c2000}, {0xbc1c4000}, {0xbc1c6000}, 
+    {0xbc1c8000}, {0xbc1ca000}, {0xbc1cc000}, {0xbc1ce000}, 
+    {0xbc1d0000}, {0xbc1d2000}, {0xbc1d4000}, {0xbc1d6000}, 
+    {0xbc1d8000}, {0xbc1da000}, {0xbc1dc000}, {0xbc1de000}, 
+    {0xbc1e0000}, {0xbc1e2000}, {0xbc1e4000}, {0xbc1e6000}, 
+    {0xbc1e8000}, {0xbc1ea000}, {0xbc1ec000}, {0xbc1ee000}, 
+    {0xbc1f0000}, {0xbc1f2000}, {0xbc1f4000}, {0xbc1f6000}, 
+    {0xbc1f8000}, {0xbc1fa000}, {0xbc1fc000}, {0xbc1fe000}, 
+    {0xbc200000}, {0xbc202000}, {0xbc204000}, {0xbc206000}, 
+    {0xbc208000}, {0xbc20a000}, {0xbc20c000}, {0xbc20e000}, 
+    {0xbc210000}, {0xbc212000}, {0xbc214000}, {0xbc216000}, 
+    {0xbc218000}, {0xbc21a000}, {0xbc21c000}, {0xbc21e000}, 
+    {0xbc220000}, {0xbc222000}, {0xbc224000}, {0xbc226000}, 
+    {0xbc228000}, {0xbc22a000}, {0xbc22c000}, {0xbc22e000}, 
+    {0xbc230000}, {0xbc232000}, {0xbc234000}, {0xbc236000}, 
+    {0xbc238000}, {0xbc23a000}, {0xbc23c000}, {0xbc23e000}, 
+    {0xbc240000}, {0xbc242000}, {0xbc244000}, {0xbc246000}, 
+    {0xbc248000}, {0xbc24a000}, {0xbc24c000}, {0xbc24e000}, 
+    {0xbc250000}, {0xbc252000}, {0xbc254000}, {0xbc256000}, 
+    {0xbc258000}, {0xbc25a000}, {0xbc25c000}, {0xbc25e000}, 
+    {0xbc260000}, {0xbc262000}, {0xbc264000}, {0xbc266000}, 
+    {0xbc268000}, {0xbc26a000}, {0xbc26c000}, {0xbc26e000}, 
+    {0xbc270000}, {0xbc272000}, {0xbc274000}, {0xbc276000}, 
+    {0xbc278000}, {0xbc27a000}, {0xbc27c000}, {0xbc27e000}, 
+    {0xbc280000}, {0xbc282000}, {0xbc284000}, {0xbc286000}, 
+    {0xbc288000}, {0xbc28a000}, {0xbc28c000}, {0xbc28e000}, 
+    {0xbc290000}, {0xbc292000}, {0xbc294000}, {0xbc296000}, 
+    {0xbc298000}, {0xbc29a000}, {0xbc29c000}, {0xbc29e000}, 
+    {0xbc2a0000}, {0xbc2a2000}, {0xbc2a4000}, {0xbc2a6000}, 
+    {0xbc2a8000}, {0xbc2aa000}, {0xbc2ac000}, {0xbc2ae000}, 
+    {0xbc2b0000}, {0xbc2b2000}, {0xbc2b4000}, {0xbc2b6000}, 
+    {0xbc2b8000}, {0xbc2ba000}, {0xbc2bc000}, {0xbc2be000}, 
+    {0xbc2c0000}, {0xbc2c2000}, {0xbc2c4000}, {0xbc2c6000}, 
+    {0xbc2c8000}, {0xbc2ca000}, {0xbc2cc000}, {0xbc2ce000}, 
+    {0xbc2d0000}, {0xbc2d2000}, {0xbc2d4000}, {0xbc2d6000}, 
+    {0xbc2d8000}, {0xbc2da000}, {0xbc2dc000}, {0xbc2de000}, 
+    {0xbc2e0000}, {0xbc2e2000}, {0xbc2e4000}, {0xbc2e6000}, 
+    {0xbc2e8000}, {0xbc2ea000}, {0xbc2ec000}, {0xbc2ee000}, 
+    {0xbc2f0000}, {0xbc2f2000}, {0xbc2f4000}, {0xbc2f6000}, 
+    {0xbc2f8000}, {0xbc2fa000}, {0xbc2fc000}, {0xbc2fe000}, 
+    {0xbc300000}, {0xbc302000}, {0xbc304000}, {0xbc306000}, 
+    {0xbc308000}, {0xbc30a000}, {0xbc30c000}, {0xbc30e000}, 
+    {0xbc310000}, {0xbc312000}, {0xbc314000}, {0xbc316000}, 
+    {0xbc318000}, {0xbc31a000}, {0xbc31c000}, {0xbc31e000}, 
+    {0xbc320000}, {0xbc322000}, {0xbc324000}, {0xbc326000}, 
+    {0xbc328000}, {0xbc32a000}, {0xbc32c000}, {0xbc32e000}, 
+    {0xbc330000}, {0xbc332000}, {0xbc334000}, {0xbc336000}, 
+    {0xbc338000}, {0xbc33a000}, {0xbc33c000}, {0xbc33e000}, 
+    {0xbc340000}, {0xbc342000}, {0xbc344000}, {0xbc346000}, 
+    {0xbc348000}, {0xbc34a000}, {0xbc34c000}, {0xbc34e000}, 
+    {0xbc350000}, {0xbc352000}, {0xbc354000}, {0xbc356000}, 
+    {0xbc358000}, {0xbc35a000}, {0xbc35c000}, {0xbc35e000}, 
+    {0xbc360000}, {0xbc362000}, {0xbc364000}, {0xbc366000}, 
+    {0xbc368000}, {0xbc36a000}, {0xbc36c000}, {0xbc36e000}, 
+    {0xbc370000}, {0xbc372000}, {0xbc374000}, {0xbc376000}, 
+    {0xbc378000}, {0xbc37a000}, {0xbc37c000}, {0xbc37e000}, 
+    {0xbc380000}, {0xbc382000}, {0xbc384000}, {0xbc386000}, 
+    {0xbc388000}, {0xbc38a000}, {0xbc38c000}, {0xbc38e000}, 
+    {0xbc390000}, {0xbc392000}, {0xbc394000}, {0xbc396000}, 
+    {0xbc398000}, {0xbc39a000}, {0xbc39c000}, {0xbc39e000}, 
+    {0xbc3a0000}, {0xbc3a2000}, {0xbc3a4000}, {0xbc3a6000}, 
+    {0xbc3a8000}, {0xbc3aa000}, {0xbc3ac000}, {0xbc3ae000}, 
+    {0xbc3b0000}, {0xbc3b2000}, {0xbc3b4000}, {0xbc3b6000}, 
+    {0xbc3b8000}, {0xbc3ba000}, {0xbc3bc000}, {0xbc3be000}, 
+    {0xbc3c0000}, {0xbc3c2000}, {0xbc3c4000}, {0xbc3c6000}, 
+    {0xbc3c8000}, {0xbc3ca000}, {0xbc3cc000}, {0xbc3ce000}, 
+    {0xbc3d0000}, {0xbc3d2000}, {0xbc3d4000}, {0xbc3d6000}, 
+    {0xbc3d8000}, {0xbc3da000}, {0xbc3dc000}, {0xbc3de000}, 
+    {0xbc3e0000}, {0xbc3e2000}, {0xbc3e4000}, {0xbc3e6000}, 
+    {0xbc3e8000}, {0xbc3ea000}, {0xbc3ec000}, {0xbc3ee000}, 
+    {0xbc3f0000}, {0xbc3f2000}, {0xbc3f4000}, {0xbc3f6000}, 
+    {0xbc3f8000}, {0xbc3fa000}, {0xbc3fc000}, {0xbc3fe000}, 
+    {0xbc400000}, {0xbc402000}, {0xbc404000}, {0xbc406000}, 
+    {0xbc408000}, {0xbc40a000}, {0xbc40c000}, {0xbc40e000}, 
+    {0xbc410000}, {0xbc412000}, {0xbc414000}, {0xbc416000}, 
+    {0xbc418000}, {0xbc41a000}, {0xbc41c000}, {0xbc41e000}, 
+    {0xbc420000}, {0xbc422000}, {0xbc424000}, {0xbc426000}, 
+    {0xbc428000}, {0xbc42a000}, {0xbc42c000}, {0xbc42e000}, 
+    {0xbc430000}, {0xbc432000}, {0xbc434000}, {0xbc436000}, 
+    {0xbc438000}, {0xbc43a000}, {0xbc43c000}, {0xbc43e000}, 
+    {0xbc440000}, {0xbc442000}, {0xbc444000}, {0xbc446000}, 
+    {0xbc448000}, {0xbc44a000}, {0xbc44c000}, {0xbc44e000}, 
+    {0xbc450000}, {0xbc452000}, {0xbc454000}, {0xbc456000}, 
+    {0xbc458000}, {0xbc45a000}, {0xbc45c000}, {0xbc45e000}, 
+    {0xbc460000}, {0xbc462000}, {0xbc464000}, {0xbc466000}, 
+    {0xbc468000}, {0xbc46a000}, {0xbc46c000}, {0xbc46e000}, 
+    {0xbc470000}, {0xbc472000}, {0xbc474000}, {0xbc476000}, 
+    {0xbc478000}, {0xbc47a000}, {0xbc47c000}, {0xbc47e000}, 
+    {0xbc480000}, {0xbc482000}, {0xbc484000}, {0xbc486000}, 
+    {0xbc488000}, {0xbc48a000}, {0xbc48c000}, {0xbc48e000}, 
+    {0xbc490000}, {0xbc492000}, {0xbc494000}, {0xbc496000}, 
+    {0xbc498000}, {0xbc49a000}, {0xbc49c000}, {0xbc49e000}, 
+    {0xbc4a0000}, {0xbc4a2000}, {0xbc4a4000}, {0xbc4a6000}, 
+    {0xbc4a8000}, {0xbc4aa000}, {0xbc4ac000}, {0xbc4ae000}, 
+    {0xbc4b0000}, {0xbc4b2000}, {0xbc4b4000}, {0xbc4b6000}, 
+    {0xbc4b8000}, {0xbc4ba000}, {0xbc4bc000}, {0xbc4be000}, 
+    {0xbc4c0000}, {0xbc4c2000}, {0xbc4c4000}, {0xbc4c6000}, 
+    {0xbc4c8000}, {0xbc4ca000}, {0xbc4cc000}, {0xbc4ce000}, 
+    {0xbc4d0000}, {0xbc4d2000}, {0xbc4d4000}, {0xbc4d6000}, 
+    {0xbc4d8000}, {0xbc4da000}, {0xbc4dc000}, {0xbc4de000}, 
+    {0xbc4e0000}, {0xbc4e2000}, {0xbc4e4000}, {0xbc4e6000}, 
+    {0xbc4e8000}, {0xbc4ea000}, {0xbc4ec000}, {0xbc4ee000}, 
+    {0xbc4f0000}, {0xbc4f2000}, {0xbc4f4000}, {0xbc4f6000}, 
+    {0xbc4f8000}, {0xbc4fa000}, {0xbc4fc000}, {0xbc4fe000}, 
+    {0xbc500000}, {0xbc502000}, {0xbc504000}, {0xbc506000}, 
+    {0xbc508000}, {0xbc50a000}, {0xbc50c000}, {0xbc50e000}, 
+    {0xbc510000}, {0xbc512000}, {0xbc514000}, {0xbc516000}, 
+    {0xbc518000}, {0xbc51a000}, {0xbc51c000}, {0xbc51e000}, 
+    {0xbc520000}, {0xbc522000}, {0xbc524000}, {0xbc526000}, 
+    {0xbc528000}, {0xbc52a000}, {0xbc52c000}, {0xbc52e000}, 
+    {0xbc530000}, {0xbc532000}, {0xbc534000}, {0xbc536000}, 
+    {0xbc538000}, {0xbc53a000}, {0xbc53c000}, {0xbc53e000}, 
+    {0xbc540000}, {0xbc542000}, {0xbc544000}, {0xbc546000}, 
+    {0xbc548000}, {0xbc54a000}, {0xbc54c000}, {0xbc54e000}, 
+    {0xbc550000}, {0xbc552000}, {0xbc554000}, {0xbc556000}, 
+    {0xbc558000}, {0xbc55a000}, {0xbc55c000}, {0xbc55e000}, 
+    {0xbc560000}, {0xbc562000}, {0xbc564000}, {0xbc566000}, 
+    {0xbc568000}, {0xbc56a000}, {0xbc56c000}, {0xbc56e000}, 
+    {0xbc570000}, {0xbc572000}, {0xbc574000}, {0xbc576000}, 
+    {0xbc578000}, {0xbc57a000}, {0xbc57c000}, {0xbc57e000}, 
+    {0xbc580000}, {0xbc582000}, {0xbc584000}, {0xbc586000}, 
+    {0xbc588000}, {0xbc58a000}, {0xbc58c000}, {0xbc58e000}, 
+    {0xbc590000}, {0xbc592000}, {0xbc594000}, {0xbc596000}, 
+    {0xbc598000}, {0xbc59a000}, {0xbc59c000}, {0xbc59e000}, 
+    {0xbc5a0000}, {0xbc5a2000}, {0xbc5a4000}, {0xbc5a6000}, 
+    {0xbc5a8000}, {0xbc5aa000}, {0xbc5ac000}, {0xbc5ae000}, 
+    {0xbc5b0000}, {0xbc5b2000}, {0xbc5b4000}, {0xbc5b6000}, 
+    {0xbc5b8000}, {0xbc5ba000}, {0xbc5bc000}, {0xbc5be000}, 
+    {0xbc5c0000}, {0xbc5c2000}, {0xbc5c4000}, {0xbc5c6000}, 
+    {0xbc5c8000}, {0xbc5ca000}, {0xbc5cc000}, {0xbc5ce000}, 
+    {0xbc5d0000}, {0xbc5d2000}, {0xbc5d4000}, {0xbc5d6000}, 
+    {0xbc5d8000}, {0xbc5da000}, {0xbc5dc000}, {0xbc5de000}, 
+    {0xbc5e0000}, {0xbc5e2000}, {0xbc5e4000}, {0xbc5e6000}, 
+    {0xbc5e8000}, {0xbc5ea000}, {0xbc5ec000}, {0xbc5ee000}, 
+    {0xbc5f0000}, {0xbc5f2000}, {0xbc5f4000}, {0xbc5f6000}, 
+    {0xbc5f8000}, {0xbc5fa000}, {0xbc5fc000}, {0xbc5fe000}, 
+    {0xbc600000}, {0xbc602000}, {0xbc604000}, {0xbc606000}, 
+    {0xbc608000}, {0xbc60a000}, {0xbc60c000}, {0xbc60e000}, 
+    {0xbc610000}, {0xbc612000}, {0xbc614000}, {0xbc616000}, 
+    {0xbc618000}, {0xbc61a000}, {0xbc61c000}, {0xbc61e000}, 
+    {0xbc620000}, {0xbc622000}, {0xbc624000}, {0xbc626000}, 
+    {0xbc628000}, {0xbc62a000}, {0xbc62c000}, {0xbc62e000}, 
+    {0xbc630000}, {0xbc632000}, {0xbc634000}, {0xbc636000}, 
+    {0xbc638000}, {0xbc63a000}, {0xbc63c000}, {0xbc63e000}, 
+    {0xbc640000}, {0xbc642000}, {0xbc644000}, {0xbc646000}, 
+    {0xbc648000}, {0xbc64a000}, {0xbc64c000}, {0xbc64e000}, 
+    {0xbc650000}, {0xbc652000}, {0xbc654000}, {0xbc656000}, 
+    {0xbc658000}, {0xbc65a000}, {0xbc65c000}, {0xbc65e000}, 
+    {0xbc660000}, {0xbc662000}, {0xbc664000}, {0xbc666000}, 
+    {0xbc668000}, {0xbc66a000}, {0xbc66c000}, {0xbc66e000}, 
+    {0xbc670000}, {0xbc672000}, {0xbc674000}, {0xbc676000}, 
+    {0xbc678000}, {0xbc67a000}, {0xbc67c000}, {0xbc67e000}, 
+    {0xbc680000}, {0xbc682000}, {0xbc684000}, {0xbc686000}, 
+    {0xbc688000}, {0xbc68a000}, {0xbc68c000}, {0xbc68e000}, 
+    {0xbc690000}, {0xbc692000}, {0xbc694000}, {0xbc696000}, 
+    {0xbc698000}, {0xbc69a000}, {0xbc69c000}, {0xbc69e000}, 
+    {0xbc6a0000}, {0xbc6a2000}, {0xbc6a4000}, {0xbc6a6000}, 
+    {0xbc6a8000}, {0xbc6aa000}, {0xbc6ac000}, {0xbc6ae000}, 
+    {0xbc6b0000}, {0xbc6b2000}, {0xbc6b4000}, {0xbc6b6000}, 
+    {0xbc6b8000}, {0xbc6ba000}, {0xbc6bc000}, {0xbc6be000}, 
+    {0xbc6c0000}, {0xbc6c2000}, {0xbc6c4000}, {0xbc6c6000}, 
+    {0xbc6c8000}, {0xbc6ca000}, {0xbc6cc000}, {0xbc6ce000}, 
+    {0xbc6d0000}, {0xbc6d2000}, {0xbc6d4000}, {0xbc6d6000}, 
+    {0xbc6d8000}, {0xbc6da000}, {0xbc6dc000}, {0xbc6de000}, 
+    {0xbc6e0000}, {0xbc6e2000}, {0xbc6e4000}, {0xbc6e6000}, 
+    {0xbc6e8000}, {0xbc6ea000}, {0xbc6ec000}, {0xbc6ee000}, 
+    {0xbc6f0000}, {0xbc6f2000}, {0xbc6f4000}, {0xbc6f6000}, 
+    {0xbc6f8000}, {0xbc6fa000}, {0xbc6fc000}, {0xbc6fe000}, 
+    {0xbc700000}, {0xbc702000}, {0xbc704000}, {0xbc706000}, 
+    {0xbc708000}, {0xbc70a000}, {0xbc70c000}, {0xbc70e000}, 
+    {0xbc710000}, {0xbc712000}, {0xbc714000}, {0xbc716000}, 
+    {0xbc718000}, {0xbc71a000}, {0xbc71c000}, {0xbc71e000}, 
+    {0xbc720000}, {0xbc722000}, {0xbc724000}, {0xbc726000}, 
+    {0xbc728000}, {0xbc72a000}, {0xbc72c000}, {0xbc72e000}, 
+    {0xbc730000}, {0xbc732000}, {0xbc734000}, {0xbc736000}, 
+    {0xbc738000}, {0xbc73a000}, {0xbc73c000}, {0xbc73e000}, 
+    {0xbc740000}, {0xbc742000}, {0xbc744000}, {0xbc746000}, 
+    {0xbc748000}, {0xbc74a000}, {0xbc74c000}, {0xbc74e000}, 
+    {0xbc750000}, {0xbc752000}, {0xbc754000}, {0xbc756000}, 
+    {0xbc758000}, {0xbc75a000}, {0xbc75c000}, {0xbc75e000}, 
+    {0xbc760000}, {0xbc762000}, {0xbc764000}, {0xbc766000}, 
+    {0xbc768000}, {0xbc76a000}, {0xbc76c000}, {0xbc76e000}, 
+    {0xbc770000}, {0xbc772000}, {0xbc774000}, {0xbc776000}, 
+    {0xbc778000}, {0xbc77a000}, {0xbc77c000}, {0xbc77e000}, 
+    {0xbc780000}, {0xbc782000}, {0xbc784000}, {0xbc786000}, 
+    {0xbc788000}, {0xbc78a000}, {0xbc78c000}, {0xbc78e000}, 
+    {0xbc790000}, {0xbc792000}, {0xbc794000}, {0xbc796000}, 
+    {0xbc798000}, {0xbc79a000}, {0xbc79c000}, {0xbc79e000}, 
+    {0xbc7a0000}, {0xbc7a2000}, {0xbc7a4000}, {0xbc7a6000}, 
+    {0xbc7a8000}, {0xbc7aa000}, {0xbc7ac000}, {0xbc7ae000}, 
+    {0xbc7b0000}, {0xbc7b2000}, {0xbc7b4000}, {0xbc7b6000}, 
+    {0xbc7b8000}, {0xbc7ba000}, {0xbc7bc000}, {0xbc7be000}, 
+    {0xbc7c0000}, {0xbc7c2000}, {0xbc7c4000}, {0xbc7c6000}, 
+    {0xbc7c8000}, {0xbc7ca000}, {0xbc7cc000}, {0xbc7ce000}, 
+    {0xbc7d0000}, {0xbc7d2000}, {0xbc7d4000}, {0xbc7d6000}, 
+    {0xbc7d8000}, {0xbc7da000}, {0xbc7dc000}, {0xbc7de000}, 
+    {0xbc7e0000}, {0xbc7e2000}, {0xbc7e4000}, {0xbc7e6000}, 
+    {0xbc7e8000}, {0xbc7ea000}, {0xbc7ec000}, {0xbc7ee000}, 
+    {0xbc7f0000}, {0xbc7f2000}, {0xbc7f4000}, {0xbc7f6000}, 
+    {0xbc7f8000}, {0xbc7fa000}, {0xbc7fc000}, {0xbc7fe000}, 
+    {0xbc800000}, {0xbc802000}, {0xbc804000}, {0xbc806000}, 
+    {0xbc808000}, {0xbc80a000}, {0xbc80c000}, {0xbc80e000}, 
+    {0xbc810000}, {0xbc812000}, {0xbc814000}, {0xbc816000}, 
+    {0xbc818000}, {0xbc81a000}, {0xbc81c000}, {0xbc81e000}, 
+    {0xbc820000}, {0xbc822000}, {0xbc824000}, {0xbc826000}, 
+    {0xbc828000}, {0xbc82a000}, {0xbc82c000}, {0xbc82e000}, 
+    {0xbc830000}, {0xbc832000}, {0xbc834000}, {0xbc836000}, 
+    {0xbc838000}, {0xbc83a000}, {0xbc83c000}, {0xbc83e000}, 
+    {0xbc840000}, {0xbc842000}, {0xbc844000}, {0xbc846000}, 
+    {0xbc848000}, {0xbc84a000}, {0xbc84c000}, {0xbc84e000}, 
+    {0xbc850000}, {0xbc852000}, {0xbc854000}, {0xbc856000}, 
+    {0xbc858000}, {0xbc85a000}, {0xbc85c000}, {0xbc85e000}, 
+    {0xbc860000}, {0xbc862000}, {0xbc864000}, {0xbc866000}, 
+    {0xbc868000}, {0xbc86a000}, {0xbc86c000}, {0xbc86e000}, 
+    {0xbc870000}, {0xbc872000}, {0xbc874000}, {0xbc876000}, 
+    {0xbc878000}, {0xbc87a000}, {0xbc87c000}, {0xbc87e000}, 
+    {0xbc880000}, {0xbc882000}, {0xbc884000}, {0xbc886000}, 
+    {0xbc888000}, {0xbc88a000}, {0xbc88c000}, {0xbc88e000}, 
+    {0xbc890000}, {0xbc892000}, {0xbc894000}, {0xbc896000}, 
+    {0xbc898000}, {0xbc89a000}, {0xbc89c000}, {0xbc89e000}, 
+    {0xbc8a0000}, {0xbc8a2000}, {0xbc8a4000}, {0xbc8a6000}, 
+    {0xbc8a8000}, {0xbc8aa000}, {0xbc8ac000}, {0xbc8ae000}, 
+    {0xbc8b0000}, {0xbc8b2000}, {0xbc8b4000}, {0xbc8b6000}, 
+    {0xbc8b8000}, {0xbc8ba000}, {0xbc8bc000}, {0xbc8be000}, 
+    {0xbc8c0000}, {0xbc8c2000}, {0xbc8c4000}, {0xbc8c6000}, 
+    {0xbc8c8000}, {0xbc8ca000}, {0xbc8cc000}, {0xbc8ce000}, 
+    {0xbc8d0000}, {0xbc8d2000}, {0xbc8d4000}, {0xbc8d6000}, 
+    {0xbc8d8000}, {0xbc8da000}, {0xbc8dc000}, {0xbc8de000}, 
+    {0xbc8e0000}, {0xbc8e2000}, {0xbc8e4000}, {0xbc8e6000}, 
+    {0xbc8e8000}, {0xbc8ea000}, {0xbc8ec000}, {0xbc8ee000}, 
+    {0xbc8f0000}, {0xbc8f2000}, {0xbc8f4000}, {0xbc8f6000}, 
+    {0xbc8f8000}, {0xbc8fa000}, {0xbc8fc000}, {0xbc8fe000}, 
+    {0xbc900000}, {0xbc902000}, {0xbc904000}, {0xbc906000}, 
+    {0xbc908000}, {0xbc90a000}, {0xbc90c000}, {0xbc90e000}, 
+    {0xbc910000}, {0xbc912000}, {0xbc914000}, {0xbc916000}, 
+    {0xbc918000}, {0xbc91a000}, {0xbc91c000}, {0xbc91e000}, 
+    {0xbc920000}, {0xbc922000}, {0xbc924000}, {0xbc926000}, 
+    {0xbc928000}, {0xbc92a000}, {0xbc92c000}, {0xbc92e000}, 
+    {0xbc930000}, {0xbc932000}, {0xbc934000}, {0xbc936000}, 
+    {0xbc938000}, {0xbc93a000}, {0xbc93c000}, {0xbc93e000}, 
+    {0xbc940000}, {0xbc942000}, {0xbc944000}, {0xbc946000}, 
+    {0xbc948000}, {0xbc94a000}, {0xbc94c000}, {0xbc94e000}, 
+    {0xbc950000}, {0xbc952000}, {0xbc954000}, {0xbc956000}, 
+    {0xbc958000}, {0xbc95a000}, {0xbc95c000}, {0xbc95e000}, 
+    {0xbc960000}, {0xbc962000}, {0xbc964000}, {0xbc966000}, 
+    {0xbc968000}, {0xbc96a000}, {0xbc96c000}, {0xbc96e000}, 
+    {0xbc970000}, {0xbc972000}, {0xbc974000}, {0xbc976000}, 
+    {0xbc978000}, {0xbc97a000}, {0xbc97c000}, {0xbc97e000}, 
+    {0xbc980000}, {0xbc982000}, {0xbc984000}, {0xbc986000}, 
+    {0xbc988000}, {0xbc98a000}, {0xbc98c000}, {0xbc98e000}, 
+    {0xbc990000}, {0xbc992000}, {0xbc994000}, {0xbc996000}, 
+    {0xbc998000}, {0xbc99a000}, {0xbc99c000}, {0xbc99e000}, 
+    {0xbc9a0000}, {0xbc9a2000}, {0xbc9a4000}, {0xbc9a6000}, 
+    {0xbc9a8000}, {0xbc9aa000}, {0xbc9ac000}, {0xbc9ae000}, 
+    {0xbc9b0000}, {0xbc9b2000}, {0xbc9b4000}, {0xbc9b6000}, 
+    {0xbc9b8000}, {0xbc9ba000}, {0xbc9bc000}, {0xbc9be000}, 
+    {0xbc9c0000}, {0xbc9c2000}, {0xbc9c4000}, {0xbc9c6000}, 
+    {0xbc9c8000}, {0xbc9ca000}, {0xbc9cc000}, {0xbc9ce000}, 
+    {0xbc9d0000}, {0xbc9d2000}, {0xbc9d4000}, {0xbc9d6000}, 
+    {0xbc9d8000}, {0xbc9da000}, {0xbc9dc000}, {0xbc9de000}, 
+    {0xbc9e0000}, {0xbc9e2000}, {0xbc9e4000}, {0xbc9e6000}, 
+    {0xbc9e8000}, {0xbc9ea000}, {0xbc9ec000}, {0xbc9ee000}, 
+    {0xbc9f0000}, {0xbc9f2000}, {0xbc9f4000}, {0xbc9f6000}, 
+    {0xbc9f8000}, {0xbc9fa000}, {0xbc9fc000}, {0xbc9fe000}, 
+    {0xbca00000}, {0xbca02000}, {0xbca04000}, {0xbca06000}, 
+    {0xbca08000}, {0xbca0a000}, {0xbca0c000}, {0xbca0e000}, 
+    {0xbca10000}, {0xbca12000}, {0xbca14000}, {0xbca16000}, 
+    {0xbca18000}, {0xbca1a000}, {0xbca1c000}, {0xbca1e000}, 
+    {0xbca20000}, {0xbca22000}, {0xbca24000}, {0xbca26000}, 
+    {0xbca28000}, {0xbca2a000}, {0xbca2c000}, {0xbca2e000}, 
+    {0xbca30000}, {0xbca32000}, {0xbca34000}, {0xbca36000}, 
+    {0xbca38000}, {0xbca3a000}, {0xbca3c000}, {0xbca3e000}, 
+    {0xbca40000}, {0xbca42000}, {0xbca44000}, {0xbca46000}, 
+    {0xbca48000}, {0xbca4a000}, {0xbca4c000}, {0xbca4e000}, 
+    {0xbca50000}, {0xbca52000}, {0xbca54000}, {0xbca56000}, 
+    {0xbca58000}, {0xbca5a000}, {0xbca5c000}, {0xbca5e000}, 
+    {0xbca60000}, {0xbca62000}, {0xbca64000}, {0xbca66000}, 
+    {0xbca68000}, {0xbca6a000}, {0xbca6c000}, {0xbca6e000}, 
+    {0xbca70000}, {0xbca72000}, {0xbca74000}, {0xbca76000}, 
+    {0xbca78000}, {0xbca7a000}, {0xbca7c000}, {0xbca7e000}, 
+    {0xbca80000}, {0xbca82000}, {0xbca84000}, {0xbca86000}, 
+    {0xbca88000}, {0xbca8a000}, {0xbca8c000}, {0xbca8e000}, 
+    {0xbca90000}, {0xbca92000}, {0xbca94000}, {0xbca96000}, 
+    {0xbca98000}, {0xbca9a000}, {0xbca9c000}, {0xbca9e000}, 
+    {0xbcaa0000}, {0xbcaa2000}, {0xbcaa4000}, {0xbcaa6000}, 
+    {0xbcaa8000}, {0xbcaaa000}, {0xbcaac000}, {0xbcaae000}, 
+    {0xbcab0000}, {0xbcab2000}, {0xbcab4000}, {0xbcab6000}, 
+    {0xbcab8000}, {0xbcaba000}, {0xbcabc000}, {0xbcabe000}, 
+    {0xbcac0000}, {0xbcac2000}, {0xbcac4000}, {0xbcac6000}, 
+    {0xbcac8000}, {0xbcaca000}, {0xbcacc000}, {0xbcace000}, 
+    {0xbcad0000}, {0xbcad2000}, {0xbcad4000}, {0xbcad6000}, 
+    {0xbcad8000}, {0xbcada000}, {0xbcadc000}, {0xbcade000}, 
+    {0xbcae0000}, {0xbcae2000}, {0xbcae4000}, {0xbcae6000}, 
+    {0xbcae8000}, {0xbcaea000}, {0xbcaec000}, {0xbcaee000}, 
+    {0xbcaf0000}, {0xbcaf2000}, {0xbcaf4000}, {0xbcaf6000}, 
+    {0xbcaf8000}, {0xbcafa000}, {0xbcafc000}, {0xbcafe000}, 
+    {0xbcb00000}, {0xbcb02000}, {0xbcb04000}, {0xbcb06000}, 
+    {0xbcb08000}, {0xbcb0a000}, {0xbcb0c000}, {0xbcb0e000}, 
+    {0xbcb10000}, {0xbcb12000}, {0xbcb14000}, {0xbcb16000}, 
+    {0xbcb18000}, {0xbcb1a000}, {0xbcb1c000}, {0xbcb1e000}, 
+    {0xbcb20000}, {0xbcb22000}, {0xbcb24000}, {0xbcb26000}, 
+    {0xbcb28000}, {0xbcb2a000}, {0xbcb2c000}, {0xbcb2e000}, 
+    {0xbcb30000}, {0xbcb32000}, {0xbcb34000}, {0xbcb36000}, 
+    {0xbcb38000}, {0xbcb3a000}, {0xbcb3c000}, {0xbcb3e000}, 
+    {0xbcb40000}, {0xbcb42000}, {0xbcb44000}, {0xbcb46000}, 
+    {0xbcb48000}, {0xbcb4a000}, {0xbcb4c000}, {0xbcb4e000}, 
+    {0xbcb50000}, {0xbcb52000}, {0xbcb54000}, {0xbcb56000}, 
+    {0xbcb58000}, {0xbcb5a000}, {0xbcb5c000}, {0xbcb5e000}, 
+    {0xbcb60000}, {0xbcb62000}, {0xbcb64000}, {0xbcb66000}, 
+    {0xbcb68000}, {0xbcb6a000}, {0xbcb6c000}, {0xbcb6e000}, 
+    {0xbcb70000}, {0xbcb72000}, {0xbcb74000}, {0xbcb76000}, 
+    {0xbcb78000}, {0xbcb7a000}, {0xbcb7c000}, {0xbcb7e000}, 
+    {0xbcb80000}, {0xbcb82000}, {0xbcb84000}, {0xbcb86000}, 
+    {0xbcb88000}, {0xbcb8a000}, {0xbcb8c000}, {0xbcb8e000}, 
+    {0xbcb90000}, {0xbcb92000}, {0xbcb94000}, {0xbcb96000}, 
+    {0xbcb98000}, {0xbcb9a000}, {0xbcb9c000}, {0xbcb9e000}, 
+    {0xbcba0000}, {0xbcba2000}, {0xbcba4000}, {0xbcba6000}, 
+    {0xbcba8000}, {0xbcbaa000}, {0xbcbac000}, {0xbcbae000}, 
+    {0xbcbb0000}, {0xbcbb2000}, {0xbcbb4000}, {0xbcbb6000}, 
+    {0xbcbb8000}, {0xbcbba000}, {0xbcbbc000}, {0xbcbbe000}, 
+    {0xbcbc0000}, {0xbcbc2000}, {0xbcbc4000}, {0xbcbc6000}, 
+    {0xbcbc8000}, {0xbcbca000}, {0xbcbcc000}, {0xbcbce000}, 
+    {0xbcbd0000}, {0xbcbd2000}, {0xbcbd4000}, {0xbcbd6000}, 
+    {0xbcbd8000}, {0xbcbda000}, {0xbcbdc000}, {0xbcbde000}, 
+    {0xbcbe0000}, {0xbcbe2000}, {0xbcbe4000}, {0xbcbe6000}, 
+    {0xbcbe8000}, {0xbcbea000}, {0xbcbec000}, {0xbcbee000}, 
+    {0xbcbf0000}, {0xbcbf2000}, {0xbcbf4000}, {0xbcbf6000}, 
+    {0xbcbf8000}, {0xbcbfa000}, {0xbcbfc000}, {0xbcbfe000}, 
+    {0xbcc00000}, {0xbcc02000}, {0xbcc04000}, {0xbcc06000}, 
+    {0xbcc08000}, {0xbcc0a000}, {0xbcc0c000}, {0xbcc0e000}, 
+    {0xbcc10000}, {0xbcc12000}, {0xbcc14000}, {0xbcc16000}, 
+    {0xbcc18000}, {0xbcc1a000}, {0xbcc1c000}, {0xbcc1e000}, 
+    {0xbcc20000}, {0xbcc22000}, {0xbcc24000}, {0xbcc26000}, 
+    {0xbcc28000}, {0xbcc2a000}, {0xbcc2c000}, {0xbcc2e000}, 
+    {0xbcc30000}, {0xbcc32000}, {0xbcc34000}, {0xbcc36000}, 
+    {0xbcc38000}, {0xbcc3a000}, {0xbcc3c000}, {0xbcc3e000}, 
+    {0xbcc40000}, {0xbcc42000}, {0xbcc44000}, {0xbcc46000}, 
+    {0xbcc48000}, {0xbcc4a000}, {0xbcc4c000}, {0xbcc4e000}, 
+    {0xbcc50000}, {0xbcc52000}, {0xbcc54000}, {0xbcc56000}, 
+    {0xbcc58000}, {0xbcc5a000}, {0xbcc5c000}, {0xbcc5e000}, 
+    {0xbcc60000}, {0xbcc62000}, {0xbcc64000}, {0xbcc66000}, 
+    {0xbcc68000}, {0xbcc6a000}, {0xbcc6c000}, {0xbcc6e000}, 
+    {0xbcc70000}, {0xbcc72000}, {0xbcc74000}, {0xbcc76000}, 
+    {0xbcc78000}, {0xbcc7a000}, {0xbcc7c000}, {0xbcc7e000}, 
+    {0xbcc80000}, {0xbcc82000}, {0xbcc84000}, {0xbcc86000}, 
+    {0xbcc88000}, {0xbcc8a000}, {0xbcc8c000}, {0xbcc8e000}, 
+    {0xbcc90000}, {0xbcc92000}, {0xbcc94000}, {0xbcc96000}, 
+    {0xbcc98000}, {0xbcc9a000}, {0xbcc9c000}, {0xbcc9e000}, 
+    {0xbcca0000}, {0xbcca2000}, {0xbcca4000}, {0xbcca6000}, 
+    {0xbcca8000}, {0xbccaa000}, {0xbccac000}, {0xbccae000}, 
+    {0xbccb0000}, {0xbccb2000}, {0xbccb4000}, {0xbccb6000}, 
+    {0xbccb8000}, {0xbccba000}, {0xbccbc000}, {0xbccbe000}, 
+    {0xbccc0000}, {0xbccc2000}, {0xbccc4000}, {0xbccc6000}, 
+    {0xbccc8000}, {0xbccca000}, {0xbcccc000}, {0xbccce000}, 
+    {0xbccd0000}, {0xbccd2000}, {0xbccd4000}, {0xbccd6000}, 
+    {0xbccd8000}, {0xbccda000}, {0xbccdc000}, {0xbccde000}, 
+    {0xbcce0000}, {0xbcce2000}, {0xbcce4000}, {0xbcce6000}, 
+    {0xbcce8000}, {0xbccea000}, {0xbccec000}, {0xbccee000}, 
+    {0xbccf0000}, {0xbccf2000}, {0xbccf4000}, {0xbccf6000}, 
+    {0xbccf8000}, {0xbccfa000}, {0xbccfc000}, {0xbccfe000}, 
+    {0xbcd00000}, {0xbcd02000}, {0xbcd04000}, {0xbcd06000}, 
+    {0xbcd08000}, {0xbcd0a000}, {0xbcd0c000}, {0xbcd0e000}, 
+    {0xbcd10000}, {0xbcd12000}, {0xbcd14000}, {0xbcd16000}, 
+    {0xbcd18000}, {0xbcd1a000}, {0xbcd1c000}, {0xbcd1e000}, 
+    {0xbcd20000}, {0xbcd22000}, {0xbcd24000}, {0xbcd26000}, 
+    {0xbcd28000}, {0xbcd2a000}, {0xbcd2c000}, {0xbcd2e000}, 
+    {0xbcd30000}, {0xbcd32000}, {0xbcd34000}, {0xbcd36000}, 
+    {0xbcd38000}, {0xbcd3a000}, {0xbcd3c000}, {0xbcd3e000}, 
+    {0xbcd40000}, {0xbcd42000}, {0xbcd44000}, {0xbcd46000}, 
+    {0xbcd48000}, {0xbcd4a000}, {0xbcd4c000}, {0xbcd4e000}, 
+    {0xbcd50000}, {0xbcd52000}, {0xbcd54000}, {0xbcd56000}, 
+    {0xbcd58000}, {0xbcd5a000}, {0xbcd5c000}, {0xbcd5e000}, 
+    {0xbcd60000}, {0xbcd62000}, {0xbcd64000}, {0xbcd66000}, 
+    {0xbcd68000}, {0xbcd6a000}, {0xbcd6c000}, {0xbcd6e000}, 
+    {0xbcd70000}, {0xbcd72000}, {0xbcd74000}, {0xbcd76000}, 
+    {0xbcd78000}, {0xbcd7a000}, {0xbcd7c000}, {0xbcd7e000}, 
+    {0xbcd80000}, {0xbcd82000}, {0xbcd84000}, {0xbcd86000}, 
+    {0xbcd88000}, {0xbcd8a000}, {0xbcd8c000}, {0xbcd8e000}, 
+    {0xbcd90000}, {0xbcd92000}, {0xbcd94000}, {0xbcd96000}, 
+    {0xbcd98000}, {0xbcd9a000}, {0xbcd9c000}, {0xbcd9e000}, 
+    {0xbcda0000}, {0xbcda2000}, {0xbcda4000}, {0xbcda6000}, 
+    {0xbcda8000}, {0xbcdaa000}, {0xbcdac000}, {0xbcdae000}, 
+    {0xbcdb0000}, {0xbcdb2000}, {0xbcdb4000}, {0xbcdb6000}, 
+    {0xbcdb8000}, {0xbcdba000}, {0xbcdbc000}, {0xbcdbe000}, 
+    {0xbcdc0000}, {0xbcdc2000}, {0xbcdc4000}, {0xbcdc6000}, 
+    {0xbcdc8000}, {0xbcdca000}, {0xbcdcc000}, {0xbcdce000}, 
+    {0xbcdd0000}, {0xbcdd2000}, {0xbcdd4000}, {0xbcdd6000}, 
+    {0xbcdd8000}, {0xbcdda000}, {0xbcddc000}, {0xbcdde000}, 
+    {0xbcde0000}, {0xbcde2000}, {0xbcde4000}, {0xbcde6000}, 
+    {0xbcde8000}, {0xbcdea000}, {0xbcdec000}, {0xbcdee000}, 
+    {0xbcdf0000}, {0xbcdf2000}, {0xbcdf4000}, {0xbcdf6000}, 
+    {0xbcdf8000}, {0xbcdfa000}, {0xbcdfc000}, {0xbcdfe000}, 
+    {0xbce00000}, {0xbce02000}, {0xbce04000}, {0xbce06000}, 
+    {0xbce08000}, {0xbce0a000}, {0xbce0c000}, {0xbce0e000}, 
+    {0xbce10000}, {0xbce12000}, {0xbce14000}, {0xbce16000}, 
+    {0xbce18000}, {0xbce1a000}, {0xbce1c000}, {0xbce1e000}, 
+    {0xbce20000}, {0xbce22000}, {0xbce24000}, {0xbce26000}, 
+    {0xbce28000}, {0xbce2a000}, {0xbce2c000}, {0xbce2e000}, 
+    {0xbce30000}, {0xbce32000}, {0xbce34000}, {0xbce36000}, 
+    {0xbce38000}, {0xbce3a000}, {0xbce3c000}, {0xbce3e000}, 
+    {0xbce40000}, {0xbce42000}, {0xbce44000}, {0xbce46000}, 
+    {0xbce48000}, {0xbce4a000}, {0xbce4c000}, {0xbce4e000}, 
+    {0xbce50000}, {0xbce52000}, {0xbce54000}, {0xbce56000}, 
+    {0xbce58000}, {0xbce5a000}, {0xbce5c000}, {0xbce5e000}, 
+    {0xbce60000}, {0xbce62000}, {0xbce64000}, {0xbce66000}, 
+    {0xbce68000}, {0xbce6a000}, {0xbce6c000}, {0xbce6e000}, 
+    {0xbce70000}, {0xbce72000}, {0xbce74000}, {0xbce76000}, 
+    {0xbce78000}, {0xbce7a000}, {0xbce7c000}, {0xbce7e000}, 
+    {0xbce80000}, {0xbce82000}, {0xbce84000}, {0xbce86000}, 
+    {0xbce88000}, {0xbce8a000}, {0xbce8c000}, {0xbce8e000}, 
+    {0xbce90000}, {0xbce92000}, {0xbce94000}, {0xbce96000}, 
+    {0xbce98000}, {0xbce9a000}, {0xbce9c000}, {0xbce9e000}, 
+    {0xbcea0000}, {0xbcea2000}, {0xbcea4000}, {0xbcea6000}, 
+    {0xbcea8000}, {0xbceaa000}, {0xbceac000}, {0xbceae000}, 
+    {0xbceb0000}, {0xbceb2000}, {0xbceb4000}, {0xbceb6000}, 
+    {0xbceb8000}, {0xbceba000}, {0xbcebc000}, {0xbcebe000}, 
+    {0xbcec0000}, {0xbcec2000}, {0xbcec4000}, {0xbcec6000}, 
+    {0xbcec8000}, {0xbceca000}, {0xbcecc000}, {0xbcece000}, 
+    {0xbced0000}, {0xbced2000}, {0xbced4000}, {0xbced6000}, 
+    {0xbced8000}, {0xbceda000}, {0xbcedc000}, {0xbcede000}, 
+    {0xbcee0000}, {0xbcee2000}, {0xbcee4000}, {0xbcee6000}, 
+    {0xbcee8000}, {0xbceea000}, {0xbceec000}, {0xbceee000}, 
+    {0xbcef0000}, {0xbcef2000}, {0xbcef4000}, {0xbcef6000}, 
+    {0xbcef8000}, {0xbcefa000}, {0xbcefc000}, {0xbcefe000}, 
+    {0xbcf00000}, {0xbcf02000}, {0xbcf04000}, {0xbcf06000}, 
+    {0xbcf08000}, {0xbcf0a000}, {0xbcf0c000}, {0xbcf0e000}, 
+    {0xbcf10000}, {0xbcf12000}, {0xbcf14000}, {0xbcf16000}, 
+    {0xbcf18000}, {0xbcf1a000}, {0xbcf1c000}, {0xbcf1e000}, 
+    {0xbcf20000}, {0xbcf22000}, {0xbcf24000}, {0xbcf26000}, 
+    {0xbcf28000}, {0xbcf2a000}, {0xbcf2c000}, {0xbcf2e000}, 
+    {0xbcf30000}, {0xbcf32000}, {0xbcf34000}, {0xbcf36000}, 
+    {0xbcf38000}, {0xbcf3a000}, {0xbcf3c000}, {0xbcf3e000}, 
+    {0xbcf40000}, {0xbcf42000}, {0xbcf44000}, {0xbcf46000}, 
+    {0xbcf48000}, {0xbcf4a000}, {0xbcf4c000}, {0xbcf4e000}, 
+    {0xbcf50000}, {0xbcf52000}, {0xbcf54000}, {0xbcf56000}, 
+    {0xbcf58000}, {0xbcf5a000}, {0xbcf5c000}, {0xbcf5e000}, 
+    {0xbcf60000}, {0xbcf62000}, {0xbcf64000}, {0xbcf66000}, 
+    {0xbcf68000}, {0xbcf6a000}, {0xbcf6c000}, {0xbcf6e000}, 
+    {0xbcf70000}, {0xbcf72000}, {0xbcf74000}, {0xbcf76000}, 
+    {0xbcf78000}, {0xbcf7a000}, {0xbcf7c000}, {0xbcf7e000}, 
+    {0xbcf80000}, {0xbcf82000}, {0xbcf84000}, {0xbcf86000}, 
+    {0xbcf88000}, {0xbcf8a000}, {0xbcf8c000}, {0xbcf8e000}, 
+    {0xbcf90000}, {0xbcf92000}, {0xbcf94000}, {0xbcf96000}, 
+    {0xbcf98000}, {0xbcf9a000}, {0xbcf9c000}, {0xbcf9e000}, 
+    {0xbcfa0000}, {0xbcfa2000}, {0xbcfa4000}, {0xbcfa6000}, 
+    {0xbcfa8000}, {0xbcfaa000}, {0xbcfac000}, {0xbcfae000}, 
+    {0xbcfb0000}, {0xbcfb2000}, {0xbcfb4000}, {0xbcfb6000}, 
+    {0xbcfb8000}, {0xbcfba000}, {0xbcfbc000}, {0xbcfbe000}, 
+    {0xbcfc0000}, {0xbcfc2000}, {0xbcfc4000}, {0xbcfc6000}, 
+    {0xbcfc8000}, {0xbcfca000}, {0xbcfcc000}, {0xbcfce000}, 
+    {0xbcfd0000}, {0xbcfd2000}, {0xbcfd4000}, {0xbcfd6000}, 
+    {0xbcfd8000}, {0xbcfda000}, {0xbcfdc000}, {0xbcfde000}, 
+    {0xbcfe0000}, {0xbcfe2000}, {0xbcfe4000}, {0xbcfe6000}, 
+    {0xbcfe8000}, {0xbcfea000}, {0xbcfec000}, {0xbcfee000}, 
+    {0xbcff0000}, {0xbcff2000}, {0xbcff4000}, {0xbcff6000}, 
+    {0xbcff8000}, {0xbcffa000}, {0xbcffc000}, {0xbcffe000}, 
+    {0xbd000000}, {0xbd002000}, {0xbd004000}, {0xbd006000}, 
+    {0xbd008000}, {0xbd00a000}, {0xbd00c000}, {0xbd00e000}, 
+    {0xbd010000}, {0xbd012000}, {0xbd014000}, {0xbd016000}, 
+    {0xbd018000}, {0xbd01a000}, {0xbd01c000}, {0xbd01e000}, 
+    {0xbd020000}, {0xbd022000}, {0xbd024000}, {0xbd026000}, 
+    {0xbd028000}, {0xbd02a000}, {0xbd02c000}, {0xbd02e000}, 
+    {0xbd030000}, {0xbd032000}, {0xbd034000}, {0xbd036000}, 
+    {0xbd038000}, {0xbd03a000}, {0xbd03c000}, {0xbd03e000}, 
+    {0xbd040000}, {0xbd042000}, {0xbd044000}, {0xbd046000}, 
+    {0xbd048000}, {0xbd04a000}, {0xbd04c000}, {0xbd04e000}, 
+    {0xbd050000}, {0xbd052000}, {0xbd054000}, {0xbd056000}, 
+    {0xbd058000}, {0xbd05a000}, {0xbd05c000}, {0xbd05e000}, 
+    {0xbd060000}, {0xbd062000}, {0xbd064000}, {0xbd066000}, 
+    {0xbd068000}, {0xbd06a000}, {0xbd06c000}, {0xbd06e000}, 
+    {0xbd070000}, {0xbd072000}, {0xbd074000}, {0xbd076000}, 
+    {0xbd078000}, {0xbd07a000}, {0xbd07c000}, {0xbd07e000}, 
+    {0xbd080000}, {0xbd082000}, {0xbd084000}, {0xbd086000}, 
+    {0xbd088000}, {0xbd08a000}, {0xbd08c000}, {0xbd08e000}, 
+    {0xbd090000}, {0xbd092000}, {0xbd094000}, {0xbd096000}, 
+    {0xbd098000}, {0xbd09a000}, {0xbd09c000}, {0xbd09e000}, 
+    {0xbd0a0000}, {0xbd0a2000}, {0xbd0a4000}, {0xbd0a6000}, 
+    {0xbd0a8000}, {0xbd0aa000}, {0xbd0ac000}, {0xbd0ae000}, 
+    {0xbd0b0000}, {0xbd0b2000}, {0xbd0b4000}, {0xbd0b6000}, 
+    {0xbd0b8000}, {0xbd0ba000}, {0xbd0bc000}, {0xbd0be000}, 
+    {0xbd0c0000}, {0xbd0c2000}, {0xbd0c4000}, {0xbd0c6000}, 
+    {0xbd0c8000}, {0xbd0ca000}, {0xbd0cc000}, {0xbd0ce000}, 
+    {0xbd0d0000}, {0xbd0d2000}, {0xbd0d4000}, {0xbd0d6000}, 
+    {0xbd0d8000}, {0xbd0da000}, {0xbd0dc000}, {0xbd0de000}, 
+    {0xbd0e0000}, {0xbd0e2000}, {0xbd0e4000}, {0xbd0e6000}, 
+    {0xbd0e8000}, {0xbd0ea000}, {0xbd0ec000}, {0xbd0ee000}, 
+    {0xbd0f0000}, {0xbd0f2000}, {0xbd0f4000}, {0xbd0f6000}, 
+    {0xbd0f8000}, {0xbd0fa000}, {0xbd0fc000}, {0xbd0fe000}, 
+    {0xbd100000}, {0xbd102000}, {0xbd104000}, {0xbd106000}, 
+    {0xbd108000}, {0xbd10a000}, {0xbd10c000}, {0xbd10e000}, 
+    {0xbd110000}, {0xbd112000}, {0xbd114000}, {0xbd116000}, 
+    {0xbd118000}, {0xbd11a000}, {0xbd11c000}, {0xbd11e000}, 
+    {0xbd120000}, {0xbd122000}, {0xbd124000}, {0xbd126000}, 
+    {0xbd128000}, {0xbd12a000}, {0xbd12c000}, {0xbd12e000}, 
+    {0xbd130000}, {0xbd132000}, {0xbd134000}, {0xbd136000}, 
+    {0xbd138000}, {0xbd13a000}, {0xbd13c000}, {0xbd13e000}, 
+    {0xbd140000}, {0xbd142000}, {0xbd144000}, {0xbd146000}, 
+    {0xbd148000}, {0xbd14a000}, {0xbd14c000}, {0xbd14e000}, 
+    {0xbd150000}, {0xbd152000}, {0xbd154000}, {0xbd156000}, 
+    {0xbd158000}, {0xbd15a000}, {0xbd15c000}, {0xbd15e000}, 
+    {0xbd160000}, {0xbd162000}, {0xbd164000}, {0xbd166000}, 
+    {0xbd168000}, {0xbd16a000}, {0xbd16c000}, {0xbd16e000}, 
+    {0xbd170000}, {0xbd172000}, {0xbd174000}, {0xbd176000}, 
+    {0xbd178000}, {0xbd17a000}, {0xbd17c000}, {0xbd17e000}, 
+    {0xbd180000}, {0xbd182000}, {0xbd184000}, {0xbd186000}, 
+    {0xbd188000}, {0xbd18a000}, {0xbd18c000}, {0xbd18e000}, 
+    {0xbd190000}, {0xbd192000}, {0xbd194000}, {0xbd196000}, 
+    {0xbd198000}, {0xbd19a000}, {0xbd19c000}, {0xbd19e000}, 
+    {0xbd1a0000}, {0xbd1a2000}, {0xbd1a4000}, {0xbd1a6000}, 
+    {0xbd1a8000}, {0xbd1aa000}, {0xbd1ac000}, {0xbd1ae000}, 
+    {0xbd1b0000}, {0xbd1b2000}, {0xbd1b4000}, {0xbd1b6000}, 
+    {0xbd1b8000}, {0xbd1ba000}, {0xbd1bc000}, {0xbd1be000}, 
+    {0xbd1c0000}, {0xbd1c2000}, {0xbd1c4000}, {0xbd1c6000}, 
+    {0xbd1c8000}, {0xbd1ca000}, {0xbd1cc000}, {0xbd1ce000}, 
+    {0xbd1d0000}, {0xbd1d2000}, {0xbd1d4000}, {0xbd1d6000}, 
+    {0xbd1d8000}, {0xbd1da000}, {0xbd1dc000}, {0xbd1de000}, 
+    {0xbd1e0000}, {0xbd1e2000}, {0xbd1e4000}, {0xbd1e6000}, 
+    {0xbd1e8000}, {0xbd1ea000}, {0xbd1ec000}, {0xbd1ee000}, 
+    {0xbd1f0000}, {0xbd1f2000}, {0xbd1f4000}, {0xbd1f6000}, 
+    {0xbd1f8000}, {0xbd1fa000}, {0xbd1fc000}, {0xbd1fe000}, 
+    {0xbd200000}, {0xbd202000}, {0xbd204000}, {0xbd206000}, 
+    {0xbd208000}, {0xbd20a000}, {0xbd20c000}, {0xbd20e000}, 
+    {0xbd210000}, {0xbd212000}, {0xbd214000}, {0xbd216000}, 
+    {0xbd218000}, {0xbd21a000}, {0xbd21c000}, {0xbd21e000}, 
+    {0xbd220000}, {0xbd222000}, {0xbd224000}, {0xbd226000}, 
+    {0xbd228000}, {0xbd22a000}, {0xbd22c000}, {0xbd22e000}, 
+    {0xbd230000}, {0xbd232000}, {0xbd234000}, {0xbd236000}, 
+    {0xbd238000}, {0xbd23a000}, {0xbd23c000}, {0xbd23e000}, 
+    {0xbd240000}, {0xbd242000}, {0xbd244000}, {0xbd246000}, 
+    {0xbd248000}, {0xbd24a000}, {0xbd24c000}, {0xbd24e000}, 
+    {0xbd250000}, {0xbd252000}, {0xbd254000}, {0xbd256000}, 
+    {0xbd258000}, {0xbd25a000}, {0xbd25c000}, {0xbd25e000}, 
+    {0xbd260000}, {0xbd262000}, {0xbd264000}, {0xbd266000}, 
+    {0xbd268000}, {0xbd26a000}, {0xbd26c000}, {0xbd26e000}, 
+    {0xbd270000}, {0xbd272000}, {0xbd274000}, {0xbd276000}, 
+    {0xbd278000}, {0xbd27a000}, {0xbd27c000}, {0xbd27e000}, 
+    {0xbd280000}, {0xbd282000}, {0xbd284000}, {0xbd286000}, 
+    {0xbd288000}, {0xbd28a000}, {0xbd28c000}, {0xbd28e000}, 
+    {0xbd290000}, {0xbd292000}, {0xbd294000}, {0xbd296000}, 
+    {0xbd298000}, {0xbd29a000}, {0xbd29c000}, {0xbd29e000}, 
+    {0xbd2a0000}, {0xbd2a2000}, {0xbd2a4000}, {0xbd2a6000}, 
+    {0xbd2a8000}, {0xbd2aa000}, {0xbd2ac000}, {0xbd2ae000}, 
+    {0xbd2b0000}, {0xbd2b2000}, {0xbd2b4000}, {0xbd2b6000}, 
+    {0xbd2b8000}, {0xbd2ba000}, {0xbd2bc000}, {0xbd2be000}, 
+    {0xbd2c0000}, {0xbd2c2000}, {0xbd2c4000}, {0xbd2c6000}, 
+    {0xbd2c8000}, {0xbd2ca000}, {0xbd2cc000}, {0xbd2ce000}, 
+    {0xbd2d0000}, {0xbd2d2000}, {0xbd2d4000}, {0xbd2d6000}, 
+    {0xbd2d8000}, {0xbd2da000}, {0xbd2dc000}, {0xbd2de000}, 
+    {0xbd2e0000}, {0xbd2e2000}, {0xbd2e4000}, {0xbd2e6000}, 
+    {0xbd2e8000}, {0xbd2ea000}, {0xbd2ec000}, {0xbd2ee000}, 
+    {0xbd2f0000}, {0xbd2f2000}, {0xbd2f4000}, {0xbd2f6000}, 
+    {0xbd2f8000}, {0xbd2fa000}, {0xbd2fc000}, {0xbd2fe000}, 
+    {0xbd300000}, {0xbd302000}, {0xbd304000}, {0xbd306000}, 
+    {0xbd308000}, {0xbd30a000}, {0xbd30c000}, {0xbd30e000}, 
+    {0xbd310000}, {0xbd312000}, {0xbd314000}, {0xbd316000}, 
+    {0xbd318000}, {0xbd31a000}, {0xbd31c000}, {0xbd31e000}, 
+    {0xbd320000}, {0xbd322000}, {0xbd324000}, {0xbd326000}, 
+    {0xbd328000}, {0xbd32a000}, {0xbd32c000}, {0xbd32e000}, 
+    {0xbd330000}, {0xbd332000}, {0xbd334000}, {0xbd336000}, 
+    {0xbd338000}, {0xbd33a000}, {0xbd33c000}, {0xbd33e000}, 
+    {0xbd340000}, {0xbd342000}, {0xbd344000}, {0xbd346000}, 
+    {0xbd348000}, {0xbd34a000}, {0xbd34c000}, {0xbd34e000}, 
+    {0xbd350000}, {0xbd352000}, {0xbd354000}, {0xbd356000}, 
+    {0xbd358000}, {0xbd35a000}, {0xbd35c000}, {0xbd35e000}, 
+    {0xbd360000}, {0xbd362000}, {0xbd364000}, {0xbd366000}, 
+    {0xbd368000}, {0xbd36a000}, {0xbd36c000}, {0xbd36e000}, 
+    {0xbd370000}, {0xbd372000}, {0xbd374000}, {0xbd376000}, 
+    {0xbd378000}, {0xbd37a000}, {0xbd37c000}, {0xbd37e000}, 
+    {0xbd380000}, {0xbd382000}, {0xbd384000}, {0xbd386000}, 
+    {0xbd388000}, {0xbd38a000}, {0xbd38c000}, {0xbd38e000}, 
+    {0xbd390000}, {0xbd392000}, {0xbd394000}, {0xbd396000}, 
+    {0xbd398000}, {0xbd39a000}, {0xbd39c000}, {0xbd39e000}, 
+    {0xbd3a0000}, {0xbd3a2000}, {0xbd3a4000}, {0xbd3a6000}, 
+    {0xbd3a8000}, {0xbd3aa000}, {0xbd3ac000}, {0xbd3ae000}, 
+    {0xbd3b0000}, {0xbd3b2000}, {0xbd3b4000}, {0xbd3b6000}, 
+    {0xbd3b8000}, {0xbd3ba000}, {0xbd3bc000}, {0xbd3be000}, 
+    {0xbd3c0000}, {0xbd3c2000}, {0xbd3c4000}, {0xbd3c6000}, 
+    {0xbd3c8000}, {0xbd3ca000}, {0xbd3cc000}, {0xbd3ce000}, 
+    {0xbd3d0000}, {0xbd3d2000}, {0xbd3d4000}, {0xbd3d6000}, 
+    {0xbd3d8000}, {0xbd3da000}, {0xbd3dc000}, {0xbd3de000}, 
+    {0xbd3e0000}, {0xbd3e2000}, {0xbd3e4000}, {0xbd3e6000}, 
+    {0xbd3e8000}, {0xbd3ea000}, {0xbd3ec000}, {0xbd3ee000}, 
+    {0xbd3f0000}, {0xbd3f2000}, {0xbd3f4000}, {0xbd3f6000}, 
+    {0xbd3f8000}, {0xbd3fa000}, {0xbd3fc000}, {0xbd3fe000}, 
+    {0xbd400000}, {0xbd402000}, {0xbd404000}, {0xbd406000}, 
+    {0xbd408000}, {0xbd40a000}, {0xbd40c000}, {0xbd40e000}, 
+    {0xbd410000}, {0xbd412000}, {0xbd414000}, {0xbd416000}, 
+    {0xbd418000}, {0xbd41a000}, {0xbd41c000}, {0xbd41e000}, 
+    {0xbd420000}, {0xbd422000}, {0xbd424000}, {0xbd426000}, 
+    {0xbd428000}, {0xbd42a000}, {0xbd42c000}, {0xbd42e000}, 
+    {0xbd430000}, {0xbd432000}, {0xbd434000}, {0xbd436000}, 
+    {0xbd438000}, {0xbd43a000}, {0xbd43c000}, {0xbd43e000}, 
+    {0xbd440000}, {0xbd442000}, {0xbd444000}, {0xbd446000}, 
+    {0xbd448000}, {0xbd44a000}, {0xbd44c000}, {0xbd44e000}, 
+    {0xbd450000}, {0xbd452000}, {0xbd454000}, {0xbd456000}, 
+    {0xbd458000}, {0xbd45a000}, {0xbd45c000}, {0xbd45e000}, 
+    {0xbd460000}, {0xbd462000}, {0xbd464000}, {0xbd466000}, 
+    {0xbd468000}, {0xbd46a000}, {0xbd46c000}, {0xbd46e000}, 
+    {0xbd470000}, {0xbd472000}, {0xbd474000}, {0xbd476000}, 
+    {0xbd478000}, {0xbd47a000}, {0xbd47c000}, {0xbd47e000}, 
+    {0xbd480000}, {0xbd482000}, {0xbd484000}, {0xbd486000}, 
+    {0xbd488000}, {0xbd48a000}, {0xbd48c000}, {0xbd48e000}, 
+    {0xbd490000}, {0xbd492000}, {0xbd494000}, {0xbd496000}, 
+    {0xbd498000}, {0xbd49a000}, {0xbd49c000}, {0xbd49e000}, 
+    {0xbd4a0000}, {0xbd4a2000}, {0xbd4a4000}, {0xbd4a6000}, 
+    {0xbd4a8000}, {0xbd4aa000}, {0xbd4ac000}, {0xbd4ae000}, 
+    {0xbd4b0000}, {0xbd4b2000}, {0xbd4b4000}, {0xbd4b6000}, 
+    {0xbd4b8000}, {0xbd4ba000}, {0xbd4bc000}, {0xbd4be000}, 
+    {0xbd4c0000}, {0xbd4c2000}, {0xbd4c4000}, {0xbd4c6000}, 
+    {0xbd4c8000}, {0xbd4ca000}, {0xbd4cc000}, {0xbd4ce000}, 
+    {0xbd4d0000}, {0xbd4d2000}, {0xbd4d4000}, {0xbd4d6000}, 
+    {0xbd4d8000}, {0xbd4da000}, {0xbd4dc000}, {0xbd4de000}, 
+    {0xbd4e0000}, {0xbd4e2000}, {0xbd4e4000}, {0xbd4e6000}, 
+    {0xbd4e8000}, {0xbd4ea000}, {0xbd4ec000}, {0xbd4ee000}, 
+    {0xbd4f0000}, {0xbd4f2000}, {0xbd4f4000}, {0xbd4f6000}, 
+    {0xbd4f8000}, {0xbd4fa000}, {0xbd4fc000}, {0xbd4fe000}, 
+    {0xbd500000}, {0xbd502000}, {0xbd504000}, {0xbd506000}, 
+    {0xbd508000}, {0xbd50a000}, {0xbd50c000}, {0xbd50e000}, 
+    {0xbd510000}, {0xbd512000}, {0xbd514000}, {0xbd516000}, 
+    {0xbd518000}, {0xbd51a000}, {0xbd51c000}, {0xbd51e000}, 
+    {0xbd520000}, {0xbd522000}, {0xbd524000}, {0xbd526000}, 
+    {0xbd528000}, {0xbd52a000}, {0xbd52c000}, {0xbd52e000}, 
+    {0xbd530000}, {0xbd532000}, {0xbd534000}, {0xbd536000}, 
+    {0xbd538000}, {0xbd53a000}, {0xbd53c000}, {0xbd53e000}, 
+    {0xbd540000}, {0xbd542000}, {0xbd544000}, {0xbd546000}, 
+    {0xbd548000}, {0xbd54a000}, {0xbd54c000}, {0xbd54e000}, 
+    {0xbd550000}, {0xbd552000}, {0xbd554000}, {0xbd556000}, 
+    {0xbd558000}, {0xbd55a000}, {0xbd55c000}, {0xbd55e000}, 
+    {0xbd560000}, {0xbd562000}, {0xbd564000}, {0xbd566000}, 
+    {0xbd568000}, {0xbd56a000}, {0xbd56c000}, {0xbd56e000}, 
+    {0xbd570000}, {0xbd572000}, {0xbd574000}, {0xbd576000}, 
+    {0xbd578000}, {0xbd57a000}, {0xbd57c000}, {0xbd57e000}, 
+    {0xbd580000}, {0xbd582000}, {0xbd584000}, {0xbd586000}, 
+    {0xbd588000}, {0xbd58a000}, {0xbd58c000}, {0xbd58e000}, 
+    {0xbd590000}, {0xbd592000}, {0xbd594000}, {0xbd596000}, 
+    {0xbd598000}, {0xbd59a000}, {0xbd59c000}, {0xbd59e000}, 
+    {0xbd5a0000}, {0xbd5a2000}, {0xbd5a4000}, {0xbd5a6000}, 
+    {0xbd5a8000}, {0xbd5aa000}, {0xbd5ac000}, {0xbd5ae000}, 
+    {0xbd5b0000}, {0xbd5b2000}, {0xbd5b4000}, {0xbd5b6000}, 
+    {0xbd5b8000}, {0xbd5ba000}, {0xbd5bc000}, {0xbd5be000}, 
+    {0xbd5c0000}, {0xbd5c2000}, {0xbd5c4000}, {0xbd5c6000}, 
+    {0xbd5c8000}, {0xbd5ca000}, {0xbd5cc000}, {0xbd5ce000}, 
+    {0xbd5d0000}, {0xbd5d2000}, {0xbd5d4000}, {0xbd5d6000}, 
+    {0xbd5d8000}, {0xbd5da000}, {0xbd5dc000}, {0xbd5de000}, 
+    {0xbd5e0000}, {0xbd5e2000}, {0xbd5e4000}, {0xbd5e6000}, 
+    {0xbd5e8000}, {0xbd5ea000}, {0xbd5ec000}, {0xbd5ee000}, 
+    {0xbd5f0000}, {0xbd5f2000}, {0xbd5f4000}, {0xbd5f6000}, 
+    {0xbd5f8000}, {0xbd5fa000}, {0xbd5fc000}, {0xbd5fe000}, 
+    {0xbd600000}, {0xbd602000}, {0xbd604000}, {0xbd606000}, 
+    {0xbd608000}, {0xbd60a000}, {0xbd60c000}, {0xbd60e000}, 
+    {0xbd610000}, {0xbd612000}, {0xbd614000}, {0xbd616000}, 
+    {0xbd618000}, {0xbd61a000}, {0xbd61c000}, {0xbd61e000}, 
+    {0xbd620000}, {0xbd622000}, {0xbd624000}, {0xbd626000}, 
+    {0xbd628000}, {0xbd62a000}, {0xbd62c000}, {0xbd62e000}, 
+    {0xbd630000}, {0xbd632000}, {0xbd634000}, {0xbd636000}, 
+    {0xbd638000}, {0xbd63a000}, {0xbd63c000}, {0xbd63e000}, 
+    {0xbd640000}, {0xbd642000}, {0xbd644000}, {0xbd646000}, 
+    {0xbd648000}, {0xbd64a000}, {0xbd64c000}, {0xbd64e000}, 
+    {0xbd650000}, {0xbd652000}, {0xbd654000}, {0xbd656000}, 
+    {0xbd658000}, {0xbd65a000}, {0xbd65c000}, {0xbd65e000}, 
+    {0xbd660000}, {0xbd662000}, {0xbd664000}, {0xbd666000}, 
+    {0xbd668000}, {0xbd66a000}, {0xbd66c000}, {0xbd66e000}, 
+    {0xbd670000}, {0xbd672000}, {0xbd674000}, {0xbd676000}, 
+    {0xbd678000}, {0xbd67a000}, {0xbd67c000}, {0xbd67e000}, 
+    {0xbd680000}, {0xbd682000}, {0xbd684000}, {0xbd686000}, 
+    {0xbd688000}, {0xbd68a000}, {0xbd68c000}, {0xbd68e000}, 
+    {0xbd690000}, {0xbd692000}, {0xbd694000}, {0xbd696000}, 
+    {0xbd698000}, {0xbd69a000}, {0xbd69c000}, {0xbd69e000}, 
+    {0xbd6a0000}, {0xbd6a2000}, {0xbd6a4000}, {0xbd6a6000}, 
+    {0xbd6a8000}, {0xbd6aa000}, {0xbd6ac000}, {0xbd6ae000}, 
+    {0xbd6b0000}, {0xbd6b2000}, {0xbd6b4000}, {0xbd6b6000}, 
+    {0xbd6b8000}, {0xbd6ba000}, {0xbd6bc000}, {0xbd6be000}, 
+    {0xbd6c0000}, {0xbd6c2000}, {0xbd6c4000}, {0xbd6c6000}, 
+    {0xbd6c8000}, {0xbd6ca000}, {0xbd6cc000}, {0xbd6ce000}, 
+    {0xbd6d0000}, {0xbd6d2000}, {0xbd6d4000}, {0xbd6d6000}, 
+    {0xbd6d8000}, {0xbd6da000}, {0xbd6dc000}, {0xbd6de000}, 
+    {0xbd6e0000}, {0xbd6e2000}, {0xbd6e4000}, {0xbd6e6000}, 
+    {0xbd6e8000}, {0xbd6ea000}, {0xbd6ec000}, {0xbd6ee000}, 
+    {0xbd6f0000}, {0xbd6f2000}, {0xbd6f4000}, {0xbd6f6000}, 
+    {0xbd6f8000}, {0xbd6fa000}, {0xbd6fc000}, {0xbd6fe000}, 
+    {0xbd700000}, {0xbd702000}, {0xbd704000}, {0xbd706000}, 
+    {0xbd708000}, {0xbd70a000}, {0xbd70c000}, {0xbd70e000}, 
+    {0xbd710000}, {0xbd712000}, {0xbd714000}, {0xbd716000}, 
+    {0xbd718000}, {0xbd71a000}, {0xbd71c000}, {0xbd71e000}, 
+    {0xbd720000}, {0xbd722000}, {0xbd724000}, {0xbd726000}, 
+    {0xbd728000}, {0xbd72a000}, {0xbd72c000}, {0xbd72e000}, 
+    {0xbd730000}, {0xbd732000}, {0xbd734000}, {0xbd736000}, 
+    {0xbd738000}, {0xbd73a000}, {0xbd73c000}, {0xbd73e000}, 
+    {0xbd740000}, {0xbd742000}, {0xbd744000}, {0xbd746000}, 
+    {0xbd748000}, {0xbd74a000}, {0xbd74c000}, {0xbd74e000}, 
+    {0xbd750000}, {0xbd752000}, {0xbd754000}, {0xbd756000}, 
+    {0xbd758000}, {0xbd75a000}, {0xbd75c000}, {0xbd75e000}, 
+    {0xbd760000}, {0xbd762000}, {0xbd764000}, {0xbd766000}, 
+    {0xbd768000}, {0xbd76a000}, {0xbd76c000}, {0xbd76e000}, 
+    {0xbd770000}, {0xbd772000}, {0xbd774000}, {0xbd776000}, 
+    {0xbd778000}, {0xbd77a000}, {0xbd77c000}, {0xbd77e000}, 
+    {0xbd780000}, {0xbd782000}, {0xbd784000}, {0xbd786000}, 
+    {0xbd788000}, {0xbd78a000}, {0xbd78c000}, {0xbd78e000}, 
+    {0xbd790000}, {0xbd792000}, {0xbd794000}, {0xbd796000}, 
+    {0xbd798000}, {0xbd79a000}, {0xbd79c000}, {0xbd79e000}, 
+    {0xbd7a0000}, {0xbd7a2000}, {0xbd7a4000}, {0xbd7a6000}, 
+    {0xbd7a8000}, {0xbd7aa000}, {0xbd7ac000}, {0xbd7ae000}, 
+    {0xbd7b0000}, {0xbd7b2000}, {0xbd7b4000}, {0xbd7b6000}, 
+    {0xbd7b8000}, {0xbd7ba000}, {0xbd7bc000}, {0xbd7be000}, 
+    {0xbd7c0000}, {0xbd7c2000}, {0xbd7c4000}, {0xbd7c6000}, 
+    {0xbd7c8000}, {0xbd7ca000}, {0xbd7cc000}, {0xbd7ce000}, 
+    {0xbd7d0000}, {0xbd7d2000}, {0xbd7d4000}, {0xbd7d6000}, 
+    {0xbd7d8000}, {0xbd7da000}, {0xbd7dc000}, {0xbd7de000}, 
+    {0xbd7e0000}, {0xbd7e2000}, {0xbd7e4000}, {0xbd7e6000}, 
+    {0xbd7e8000}, {0xbd7ea000}, {0xbd7ec000}, {0xbd7ee000}, 
+    {0xbd7f0000}, {0xbd7f2000}, {0xbd7f4000}, {0xbd7f6000}, 
+    {0xbd7f8000}, {0xbd7fa000}, {0xbd7fc000}, {0xbd7fe000}, 
+    {0xbd800000}, {0xbd802000}, {0xbd804000}, {0xbd806000}, 
+    {0xbd808000}, {0xbd80a000}, {0xbd80c000}, {0xbd80e000}, 
+    {0xbd810000}, {0xbd812000}, {0xbd814000}, {0xbd816000}, 
+    {0xbd818000}, {0xbd81a000}, {0xbd81c000}, {0xbd81e000}, 
+    {0xbd820000}, {0xbd822000}, {0xbd824000}, {0xbd826000}, 
+    {0xbd828000}, {0xbd82a000}, {0xbd82c000}, {0xbd82e000}, 
+    {0xbd830000}, {0xbd832000}, {0xbd834000}, {0xbd836000}, 
+    {0xbd838000}, {0xbd83a000}, {0xbd83c000}, {0xbd83e000}, 
+    {0xbd840000}, {0xbd842000}, {0xbd844000}, {0xbd846000}, 
+    {0xbd848000}, {0xbd84a000}, {0xbd84c000}, {0xbd84e000}, 
+    {0xbd850000}, {0xbd852000}, {0xbd854000}, {0xbd856000}, 
+    {0xbd858000}, {0xbd85a000}, {0xbd85c000}, {0xbd85e000}, 
+    {0xbd860000}, {0xbd862000}, {0xbd864000}, {0xbd866000}, 
+    {0xbd868000}, {0xbd86a000}, {0xbd86c000}, {0xbd86e000}, 
+    {0xbd870000}, {0xbd872000}, {0xbd874000}, {0xbd876000}, 
+    {0xbd878000}, {0xbd87a000}, {0xbd87c000}, {0xbd87e000}, 
+    {0xbd880000}, {0xbd882000}, {0xbd884000}, {0xbd886000}, 
+    {0xbd888000}, {0xbd88a000}, {0xbd88c000}, {0xbd88e000}, 
+    {0xbd890000}, {0xbd892000}, {0xbd894000}, {0xbd896000}, 
+    {0xbd898000}, {0xbd89a000}, {0xbd89c000}, {0xbd89e000}, 
+    {0xbd8a0000}, {0xbd8a2000}, {0xbd8a4000}, {0xbd8a6000}, 
+    {0xbd8a8000}, {0xbd8aa000}, {0xbd8ac000}, {0xbd8ae000}, 
+    {0xbd8b0000}, {0xbd8b2000}, {0xbd8b4000}, {0xbd8b6000}, 
+    {0xbd8b8000}, {0xbd8ba000}, {0xbd8bc000}, {0xbd8be000}, 
+    {0xbd8c0000}, {0xbd8c2000}, {0xbd8c4000}, {0xbd8c6000}, 
+    {0xbd8c8000}, {0xbd8ca000}, {0xbd8cc000}, {0xbd8ce000}, 
+    {0xbd8d0000}, {0xbd8d2000}, {0xbd8d4000}, {0xbd8d6000}, 
+    {0xbd8d8000}, {0xbd8da000}, {0xbd8dc000}, {0xbd8de000}, 
+    {0xbd8e0000}, {0xbd8e2000}, {0xbd8e4000}, {0xbd8e6000}, 
+    {0xbd8e8000}, {0xbd8ea000}, {0xbd8ec000}, {0xbd8ee000}, 
+    {0xbd8f0000}, {0xbd8f2000}, {0xbd8f4000}, {0xbd8f6000}, 
+    {0xbd8f8000}, {0xbd8fa000}, {0xbd8fc000}, {0xbd8fe000}, 
+    {0xbd900000}, {0xbd902000}, {0xbd904000}, {0xbd906000}, 
+    {0xbd908000}, {0xbd90a000}, {0xbd90c000}, {0xbd90e000}, 
+    {0xbd910000}, {0xbd912000}, {0xbd914000}, {0xbd916000}, 
+    {0xbd918000}, {0xbd91a000}, {0xbd91c000}, {0xbd91e000}, 
+    {0xbd920000}, {0xbd922000}, {0xbd924000}, {0xbd926000}, 
+    {0xbd928000}, {0xbd92a000}, {0xbd92c000}, {0xbd92e000}, 
+    {0xbd930000}, {0xbd932000}, {0xbd934000}, {0xbd936000}, 
+    {0xbd938000}, {0xbd93a000}, {0xbd93c000}, {0xbd93e000}, 
+    {0xbd940000}, {0xbd942000}, {0xbd944000}, {0xbd946000}, 
+    {0xbd948000}, {0xbd94a000}, {0xbd94c000}, {0xbd94e000}, 
+    {0xbd950000}, {0xbd952000}, {0xbd954000}, {0xbd956000}, 
+    {0xbd958000}, {0xbd95a000}, {0xbd95c000}, {0xbd95e000}, 
+    {0xbd960000}, {0xbd962000}, {0xbd964000}, {0xbd966000}, 
+    {0xbd968000}, {0xbd96a000}, {0xbd96c000}, {0xbd96e000}, 
+    {0xbd970000}, {0xbd972000}, {0xbd974000}, {0xbd976000}, 
+    {0xbd978000}, {0xbd97a000}, {0xbd97c000}, {0xbd97e000}, 
+    {0xbd980000}, {0xbd982000}, {0xbd984000}, {0xbd986000}, 
+    {0xbd988000}, {0xbd98a000}, {0xbd98c000}, {0xbd98e000}, 
+    {0xbd990000}, {0xbd992000}, {0xbd994000}, {0xbd996000}, 
+    {0xbd998000}, {0xbd99a000}, {0xbd99c000}, {0xbd99e000}, 
+    {0xbd9a0000}, {0xbd9a2000}, {0xbd9a4000}, {0xbd9a6000}, 
+    {0xbd9a8000}, {0xbd9aa000}, {0xbd9ac000}, {0xbd9ae000}, 
+    {0xbd9b0000}, {0xbd9b2000}, {0xbd9b4000}, {0xbd9b6000}, 
+    {0xbd9b8000}, {0xbd9ba000}, {0xbd9bc000}, {0xbd9be000}, 
+    {0xbd9c0000}, {0xbd9c2000}, {0xbd9c4000}, {0xbd9c6000}, 
+    {0xbd9c8000}, {0xbd9ca000}, {0xbd9cc000}, {0xbd9ce000}, 
+    {0xbd9d0000}, {0xbd9d2000}, {0xbd9d4000}, {0xbd9d6000}, 
+    {0xbd9d8000}, {0xbd9da000}, {0xbd9dc000}, {0xbd9de000}, 
+    {0xbd9e0000}, {0xbd9e2000}, {0xbd9e4000}, {0xbd9e6000}, 
+    {0xbd9e8000}, {0xbd9ea000}, {0xbd9ec000}, {0xbd9ee000}, 
+    {0xbd9f0000}, {0xbd9f2000}, {0xbd9f4000}, {0xbd9f6000}, 
+    {0xbd9f8000}, {0xbd9fa000}, {0xbd9fc000}, {0xbd9fe000}, 
+    {0xbda00000}, {0xbda02000}, {0xbda04000}, {0xbda06000}, 
+    {0xbda08000}, {0xbda0a000}, {0xbda0c000}, {0xbda0e000}, 
+    {0xbda10000}, {0xbda12000}, {0xbda14000}, {0xbda16000}, 
+    {0xbda18000}, {0xbda1a000}, {0xbda1c000}, {0xbda1e000}, 
+    {0xbda20000}, {0xbda22000}, {0xbda24000}, {0xbda26000}, 
+    {0xbda28000}, {0xbda2a000}, {0xbda2c000}, {0xbda2e000}, 
+    {0xbda30000}, {0xbda32000}, {0xbda34000}, {0xbda36000}, 
+    {0xbda38000}, {0xbda3a000}, {0xbda3c000}, {0xbda3e000}, 
+    {0xbda40000}, {0xbda42000}, {0xbda44000}, {0xbda46000}, 
+    {0xbda48000}, {0xbda4a000}, {0xbda4c000}, {0xbda4e000}, 
+    {0xbda50000}, {0xbda52000}, {0xbda54000}, {0xbda56000}, 
+    {0xbda58000}, {0xbda5a000}, {0xbda5c000}, {0xbda5e000}, 
+    {0xbda60000}, {0xbda62000}, {0xbda64000}, {0xbda66000}, 
+    {0xbda68000}, {0xbda6a000}, {0xbda6c000}, {0xbda6e000}, 
+    {0xbda70000}, {0xbda72000}, {0xbda74000}, {0xbda76000}, 
+    {0xbda78000}, {0xbda7a000}, {0xbda7c000}, {0xbda7e000}, 
+    {0xbda80000}, {0xbda82000}, {0xbda84000}, {0xbda86000}, 
+    {0xbda88000}, {0xbda8a000}, {0xbda8c000}, {0xbda8e000}, 
+    {0xbda90000}, {0xbda92000}, {0xbda94000}, {0xbda96000}, 
+    {0xbda98000}, {0xbda9a000}, {0xbda9c000}, {0xbda9e000}, 
+    {0xbdaa0000}, {0xbdaa2000}, {0xbdaa4000}, {0xbdaa6000}, 
+    {0xbdaa8000}, {0xbdaaa000}, {0xbdaac000}, {0xbdaae000}, 
+    {0xbdab0000}, {0xbdab2000}, {0xbdab4000}, {0xbdab6000}, 
+    {0xbdab8000}, {0xbdaba000}, {0xbdabc000}, {0xbdabe000}, 
+    {0xbdac0000}, {0xbdac2000}, {0xbdac4000}, {0xbdac6000}, 
+    {0xbdac8000}, {0xbdaca000}, {0xbdacc000}, {0xbdace000}, 
+    {0xbdad0000}, {0xbdad2000}, {0xbdad4000}, {0xbdad6000}, 
+    {0xbdad8000}, {0xbdada000}, {0xbdadc000}, {0xbdade000}, 
+    {0xbdae0000}, {0xbdae2000}, {0xbdae4000}, {0xbdae6000}, 
+    {0xbdae8000}, {0xbdaea000}, {0xbdaec000}, {0xbdaee000}, 
+    {0xbdaf0000}, {0xbdaf2000}, {0xbdaf4000}, {0xbdaf6000}, 
+    {0xbdaf8000}, {0xbdafa000}, {0xbdafc000}, {0xbdafe000}, 
+    {0xbdb00000}, {0xbdb02000}, {0xbdb04000}, {0xbdb06000}, 
+    {0xbdb08000}, {0xbdb0a000}, {0xbdb0c000}, {0xbdb0e000}, 
+    {0xbdb10000}, {0xbdb12000}, {0xbdb14000}, {0xbdb16000}, 
+    {0xbdb18000}, {0xbdb1a000}, {0xbdb1c000}, {0xbdb1e000}, 
+    {0xbdb20000}, {0xbdb22000}, {0xbdb24000}, {0xbdb26000}, 
+    {0xbdb28000}, {0xbdb2a000}, {0xbdb2c000}, {0xbdb2e000}, 
+    {0xbdb30000}, {0xbdb32000}, {0xbdb34000}, {0xbdb36000}, 
+    {0xbdb38000}, {0xbdb3a000}, {0xbdb3c000}, {0xbdb3e000}, 
+    {0xbdb40000}, {0xbdb42000}, {0xbdb44000}, {0xbdb46000}, 
+    {0xbdb48000}, {0xbdb4a000}, {0xbdb4c000}, {0xbdb4e000}, 
+    {0xbdb50000}, {0xbdb52000}, {0xbdb54000}, {0xbdb56000}, 
+    {0xbdb58000}, {0xbdb5a000}, {0xbdb5c000}, {0xbdb5e000}, 
+    {0xbdb60000}, {0xbdb62000}, {0xbdb64000}, {0xbdb66000}, 
+    {0xbdb68000}, {0xbdb6a000}, {0xbdb6c000}, {0xbdb6e000}, 
+    {0xbdb70000}, {0xbdb72000}, {0xbdb74000}, {0xbdb76000}, 
+    {0xbdb78000}, {0xbdb7a000}, {0xbdb7c000}, {0xbdb7e000}, 
+    {0xbdb80000}, {0xbdb82000}, {0xbdb84000}, {0xbdb86000}, 
+    {0xbdb88000}, {0xbdb8a000}, {0xbdb8c000}, {0xbdb8e000}, 
+    {0xbdb90000}, {0xbdb92000}, {0xbdb94000}, {0xbdb96000}, 
+    {0xbdb98000}, {0xbdb9a000}, {0xbdb9c000}, {0xbdb9e000}, 
+    {0xbdba0000}, {0xbdba2000}, {0xbdba4000}, {0xbdba6000}, 
+    {0xbdba8000}, {0xbdbaa000}, {0xbdbac000}, {0xbdbae000}, 
+    {0xbdbb0000}, {0xbdbb2000}, {0xbdbb4000}, {0xbdbb6000}, 
+    {0xbdbb8000}, {0xbdbba000}, {0xbdbbc000}, {0xbdbbe000}, 
+    {0xbdbc0000}, {0xbdbc2000}, {0xbdbc4000}, {0xbdbc6000}, 
+    {0xbdbc8000}, {0xbdbca000}, {0xbdbcc000}, {0xbdbce000}, 
+    {0xbdbd0000}, {0xbdbd2000}, {0xbdbd4000}, {0xbdbd6000}, 
+    {0xbdbd8000}, {0xbdbda000}, {0xbdbdc000}, {0xbdbde000}, 
+    {0xbdbe0000}, {0xbdbe2000}, {0xbdbe4000}, {0xbdbe6000}, 
+    {0xbdbe8000}, {0xbdbea000}, {0xbdbec000}, {0xbdbee000}, 
+    {0xbdbf0000}, {0xbdbf2000}, {0xbdbf4000}, {0xbdbf6000}, 
+    {0xbdbf8000}, {0xbdbfa000}, {0xbdbfc000}, {0xbdbfe000}, 
+    {0xbdc00000}, {0xbdc02000}, {0xbdc04000}, {0xbdc06000}, 
+    {0xbdc08000}, {0xbdc0a000}, {0xbdc0c000}, {0xbdc0e000}, 
+    {0xbdc10000}, {0xbdc12000}, {0xbdc14000}, {0xbdc16000}, 
+    {0xbdc18000}, {0xbdc1a000}, {0xbdc1c000}, {0xbdc1e000}, 
+    {0xbdc20000}, {0xbdc22000}, {0xbdc24000}, {0xbdc26000}, 
+    {0xbdc28000}, {0xbdc2a000}, {0xbdc2c000}, {0xbdc2e000}, 
+    {0xbdc30000}, {0xbdc32000}, {0xbdc34000}, {0xbdc36000}, 
+    {0xbdc38000}, {0xbdc3a000}, {0xbdc3c000}, {0xbdc3e000}, 
+    {0xbdc40000}, {0xbdc42000}, {0xbdc44000}, {0xbdc46000}, 
+    {0xbdc48000}, {0xbdc4a000}, {0xbdc4c000}, {0xbdc4e000}, 
+    {0xbdc50000}, {0xbdc52000}, {0xbdc54000}, {0xbdc56000}, 
+    {0xbdc58000}, {0xbdc5a000}, {0xbdc5c000}, {0xbdc5e000}, 
+    {0xbdc60000}, {0xbdc62000}, {0xbdc64000}, {0xbdc66000}, 
+    {0xbdc68000}, {0xbdc6a000}, {0xbdc6c000}, {0xbdc6e000}, 
+    {0xbdc70000}, {0xbdc72000}, {0xbdc74000}, {0xbdc76000}, 
+    {0xbdc78000}, {0xbdc7a000}, {0xbdc7c000}, {0xbdc7e000}, 
+    {0xbdc80000}, {0xbdc82000}, {0xbdc84000}, {0xbdc86000}, 
+    {0xbdc88000}, {0xbdc8a000}, {0xbdc8c000}, {0xbdc8e000}, 
+    {0xbdc90000}, {0xbdc92000}, {0xbdc94000}, {0xbdc96000}, 
+    {0xbdc98000}, {0xbdc9a000}, {0xbdc9c000}, {0xbdc9e000}, 
+    {0xbdca0000}, {0xbdca2000}, {0xbdca4000}, {0xbdca6000}, 
+    {0xbdca8000}, {0xbdcaa000}, {0xbdcac000}, {0xbdcae000}, 
+    {0xbdcb0000}, {0xbdcb2000}, {0xbdcb4000}, {0xbdcb6000}, 
+    {0xbdcb8000}, {0xbdcba000}, {0xbdcbc000}, {0xbdcbe000}, 
+    {0xbdcc0000}, {0xbdcc2000}, {0xbdcc4000}, {0xbdcc6000}, 
+    {0xbdcc8000}, {0xbdcca000}, {0xbdccc000}, {0xbdcce000}, 
+    {0xbdcd0000}, {0xbdcd2000}, {0xbdcd4000}, {0xbdcd6000}, 
+    {0xbdcd8000}, {0xbdcda000}, {0xbdcdc000}, {0xbdcde000}, 
+    {0xbdce0000}, {0xbdce2000}, {0xbdce4000}, {0xbdce6000}, 
+    {0xbdce8000}, {0xbdcea000}, {0xbdcec000}, {0xbdcee000}, 
+    {0xbdcf0000}, {0xbdcf2000}, {0xbdcf4000}, {0xbdcf6000}, 
+    {0xbdcf8000}, {0xbdcfa000}, {0xbdcfc000}, {0xbdcfe000}, 
+    {0xbdd00000}, {0xbdd02000}, {0xbdd04000}, {0xbdd06000}, 
+    {0xbdd08000}, {0xbdd0a000}, {0xbdd0c000}, {0xbdd0e000}, 
+    {0xbdd10000}, {0xbdd12000}, {0xbdd14000}, {0xbdd16000}, 
+    {0xbdd18000}, {0xbdd1a000}, {0xbdd1c000}, {0xbdd1e000}, 
+    {0xbdd20000}, {0xbdd22000}, {0xbdd24000}, {0xbdd26000}, 
+    {0xbdd28000}, {0xbdd2a000}, {0xbdd2c000}, {0xbdd2e000}, 
+    {0xbdd30000}, {0xbdd32000}, {0xbdd34000}, {0xbdd36000}, 
+    {0xbdd38000}, {0xbdd3a000}, {0xbdd3c000}, {0xbdd3e000}, 
+    {0xbdd40000}, {0xbdd42000}, {0xbdd44000}, {0xbdd46000}, 
+    {0xbdd48000}, {0xbdd4a000}, {0xbdd4c000}, {0xbdd4e000}, 
+    {0xbdd50000}, {0xbdd52000}, {0xbdd54000}, {0xbdd56000}, 
+    {0xbdd58000}, {0xbdd5a000}, {0xbdd5c000}, {0xbdd5e000}, 
+    {0xbdd60000}, {0xbdd62000}, {0xbdd64000}, {0xbdd66000}, 
+    {0xbdd68000}, {0xbdd6a000}, {0xbdd6c000}, {0xbdd6e000}, 
+    {0xbdd70000}, {0xbdd72000}, {0xbdd74000}, {0xbdd76000}, 
+    {0xbdd78000}, {0xbdd7a000}, {0xbdd7c000}, {0xbdd7e000}, 
+    {0xbdd80000}, {0xbdd82000}, {0xbdd84000}, {0xbdd86000}, 
+    {0xbdd88000}, {0xbdd8a000}, {0xbdd8c000}, {0xbdd8e000}, 
+    {0xbdd90000}, {0xbdd92000}, {0xbdd94000}, {0xbdd96000}, 
+    {0xbdd98000}, {0xbdd9a000}, {0xbdd9c000}, {0xbdd9e000}, 
+    {0xbdda0000}, {0xbdda2000}, {0xbdda4000}, {0xbdda6000}, 
+    {0xbdda8000}, {0xbddaa000}, {0xbddac000}, {0xbddae000}, 
+    {0xbddb0000}, {0xbddb2000}, {0xbddb4000}, {0xbddb6000}, 
+    {0xbddb8000}, {0xbddba000}, {0xbddbc000}, {0xbddbe000}, 
+    {0xbddc0000}, {0xbddc2000}, {0xbddc4000}, {0xbddc6000}, 
+    {0xbddc8000}, {0xbddca000}, {0xbddcc000}, {0xbddce000}, 
+    {0xbddd0000}, {0xbddd2000}, {0xbddd4000}, {0xbddd6000}, 
+    {0xbddd8000}, {0xbddda000}, {0xbdddc000}, {0xbddde000}, 
+    {0xbdde0000}, {0xbdde2000}, {0xbdde4000}, {0xbdde6000}, 
+    {0xbdde8000}, {0xbddea000}, {0xbddec000}, {0xbddee000}, 
+    {0xbddf0000}, {0xbddf2000}, {0xbddf4000}, {0xbddf6000}, 
+    {0xbddf8000}, {0xbddfa000}, {0xbddfc000}, {0xbddfe000}, 
+    {0xbde00000}, {0xbde02000}, {0xbde04000}, {0xbde06000}, 
+    {0xbde08000}, {0xbde0a000}, {0xbde0c000}, {0xbde0e000}, 
+    {0xbde10000}, {0xbde12000}, {0xbde14000}, {0xbde16000}, 
+    {0xbde18000}, {0xbde1a000}, {0xbde1c000}, {0xbde1e000}, 
+    {0xbde20000}, {0xbde22000}, {0xbde24000}, {0xbde26000}, 
+    {0xbde28000}, {0xbde2a000}, {0xbde2c000}, {0xbde2e000}, 
+    {0xbde30000}, {0xbde32000}, {0xbde34000}, {0xbde36000}, 
+    {0xbde38000}, {0xbde3a000}, {0xbde3c000}, {0xbde3e000}, 
+    {0xbde40000}, {0xbde42000}, {0xbde44000}, {0xbde46000}, 
+    {0xbde48000}, {0xbde4a000}, {0xbde4c000}, {0xbde4e000}, 
+    {0xbde50000}, {0xbde52000}, {0xbde54000}, {0xbde56000}, 
+    {0xbde58000}, {0xbde5a000}, {0xbde5c000}, {0xbde5e000}, 
+    {0xbde60000}, {0xbde62000}, {0xbde64000}, {0xbde66000}, 
+    {0xbde68000}, {0xbde6a000}, {0xbde6c000}, {0xbde6e000}, 
+    {0xbde70000}, {0xbde72000}, {0xbde74000}, {0xbde76000}, 
+    {0xbde78000}, {0xbde7a000}, {0xbde7c000}, {0xbde7e000}, 
+    {0xbde80000}, {0xbde82000}, {0xbde84000}, {0xbde86000}, 
+    {0xbde88000}, {0xbde8a000}, {0xbde8c000}, {0xbde8e000}, 
+    {0xbde90000}, {0xbde92000}, {0xbde94000}, {0xbde96000}, 
+    {0xbde98000}, {0xbde9a000}, {0xbde9c000}, {0xbde9e000}, 
+    {0xbdea0000}, {0xbdea2000}, {0xbdea4000}, {0xbdea6000}, 
+    {0xbdea8000}, {0xbdeaa000}, {0xbdeac000}, {0xbdeae000}, 
+    {0xbdeb0000}, {0xbdeb2000}, {0xbdeb4000}, {0xbdeb6000}, 
+    {0xbdeb8000}, {0xbdeba000}, {0xbdebc000}, {0xbdebe000}, 
+    {0xbdec0000}, {0xbdec2000}, {0xbdec4000}, {0xbdec6000}, 
+    {0xbdec8000}, {0xbdeca000}, {0xbdecc000}, {0xbdece000}, 
+    {0xbded0000}, {0xbded2000}, {0xbded4000}, {0xbded6000}, 
+    {0xbded8000}, {0xbdeda000}, {0xbdedc000}, {0xbdede000}, 
+    {0xbdee0000}, {0xbdee2000}, {0xbdee4000}, {0xbdee6000}, 
+    {0xbdee8000}, {0xbdeea000}, {0xbdeec000}, {0xbdeee000}, 
+    {0xbdef0000}, {0xbdef2000}, {0xbdef4000}, {0xbdef6000}, 
+    {0xbdef8000}, {0xbdefa000}, {0xbdefc000}, {0xbdefe000}, 
+    {0xbdf00000}, {0xbdf02000}, {0xbdf04000}, {0xbdf06000}, 
+    {0xbdf08000}, {0xbdf0a000}, {0xbdf0c000}, {0xbdf0e000}, 
+    {0xbdf10000}, {0xbdf12000}, {0xbdf14000}, {0xbdf16000}, 
+    {0xbdf18000}, {0xbdf1a000}, {0xbdf1c000}, {0xbdf1e000}, 
+    {0xbdf20000}, {0xbdf22000}, {0xbdf24000}, {0xbdf26000}, 
+    {0xbdf28000}, {0xbdf2a000}, {0xbdf2c000}, {0xbdf2e000}, 
+    {0xbdf30000}, {0xbdf32000}, {0xbdf34000}, {0xbdf36000}, 
+    {0xbdf38000}, {0xbdf3a000}, {0xbdf3c000}, {0xbdf3e000}, 
+    {0xbdf40000}, {0xbdf42000}, {0xbdf44000}, {0xbdf46000}, 
+    {0xbdf48000}, {0xbdf4a000}, {0xbdf4c000}, {0xbdf4e000}, 
+    {0xbdf50000}, {0xbdf52000}, {0xbdf54000}, {0xbdf56000}, 
+    {0xbdf58000}, {0xbdf5a000}, {0xbdf5c000}, {0xbdf5e000}, 
+    {0xbdf60000}, {0xbdf62000}, {0xbdf64000}, {0xbdf66000}, 
+    {0xbdf68000}, {0xbdf6a000}, {0xbdf6c000}, {0xbdf6e000}, 
+    {0xbdf70000}, {0xbdf72000}, {0xbdf74000}, {0xbdf76000}, 
+    {0xbdf78000}, {0xbdf7a000}, {0xbdf7c000}, {0xbdf7e000}, 
+    {0xbdf80000}, {0xbdf82000}, {0xbdf84000}, {0xbdf86000}, 
+    {0xbdf88000}, {0xbdf8a000}, {0xbdf8c000}, {0xbdf8e000}, 
+    {0xbdf90000}, {0xbdf92000}, {0xbdf94000}, {0xbdf96000}, 
+    {0xbdf98000}, {0xbdf9a000}, {0xbdf9c000}, {0xbdf9e000}, 
+    {0xbdfa0000}, {0xbdfa2000}, {0xbdfa4000}, {0xbdfa6000}, 
+    {0xbdfa8000}, {0xbdfaa000}, {0xbdfac000}, {0xbdfae000}, 
+    {0xbdfb0000}, {0xbdfb2000}, {0xbdfb4000}, {0xbdfb6000}, 
+    {0xbdfb8000}, {0xbdfba000}, {0xbdfbc000}, {0xbdfbe000}, 
+    {0xbdfc0000}, {0xbdfc2000}, {0xbdfc4000}, {0xbdfc6000}, 
+    {0xbdfc8000}, {0xbdfca000}, {0xbdfcc000}, {0xbdfce000}, 
+    {0xbdfd0000}, {0xbdfd2000}, {0xbdfd4000}, {0xbdfd6000}, 
+    {0xbdfd8000}, {0xbdfda000}, {0xbdfdc000}, {0xbdfde000}, 
+    {0xbdfe0000}, {0xbdfe2000}, {0xbdfe4000}, {0xbdfe6000}, 
+    {0xbdfe8000}, {0xbdfea000}, {0xbdfec000}, {0xbdfee000}, 
+    {0xbdff0000}, {0xbdff2000}, {0xbdff4000}, {0xbdff6000}, 
+    {0xbdff8000}, {0xbdffa000}, {0xbdffc000}, {0xbdffe000}, 
+    {0xbe000000}, {0xbe002000}, {0xbe004000}, {0xbe006000}, 
+    {0xbe008000}, {0xbe00a000}, {0xbe00c000}, {0xbe00e000}, 
+    {0xbe010000}, {0xbe012000}, {0xbe014000}, {0xbe016000}, 
+    {0xbe018000}, {0xbe01a000}, {0xbe01c000}, {0xbe01e000}, 
+    {0xbe020000}, {0xbe022000}, {0xbe024000}, {0xbe026000}, 
+    {0xbe028000}, {0xbe02a000}, {0xbe02c000}, {0xbe02e000}, 
+    {0xbe030000}, {0xbe032000}, {0xbe034000}, {0xbe036000}, 
+    {0xbe038000}, {0xbe03a000}, {0xbe03c000}, {0xbe03e000}, 
+    {0xbe040000}, {0xbe042000}, {0xbe044000}, {0xbe046000}, 
+    {0xbe048000}, {0xbe04a000}, {0xbe04c000}, {0xbe04e000}, 
+    {0xbe050000}, {0xbe052000}, {0xbe054000}, {0xbe056000}, 
+    {0xbe058000}, {0xbe05a000}, {0xbe05c000}, {0xbe05e000}, 
+    {0xbe060000}, {0xbe062000}, {0xbe064000}, {0xbe066000}, 
+    {0xbe068000}, {0xbe06a000}, {0xbe06c000}, {0xbe06e000}, 
+    {0xbe070000}, {0xbe072000}, {0xbe074000}, {0xbe076000}, 
+    {0xbe078000}, {0xbe07a000}, {0xbe07c000}, {0xbe07e000}, 
+    {0xbe080000}, {0xbe082000}, {0xbe084000}, {0xbe086000}, 
+    {0xbe088000}, {0xbe08a000}, {0xbe08c000}, {0xbe08e000}, 
+    {0xbe090000}, {0xbe092000}, {0xbe094000}, {0xbe096000}, 
+    {0xbe098000}, {0xbe09a000}, {0xbe09c000}, {0xbe09e000}, 
+    {0xbe0a0000}, {0xbe0a2000}, {0xbe0a4000}, {0xbe0a6000}, 
+    {0xbe0a8000}, {0xbe0aa000}, {0xbe0ac000}, {0xbe0ae000}, 
+    {0xbe0b0000}, {0xbe0b2000}, {0xbe0b4000}, {0xbe0b6000}, 
+    {0xbe0b8000}, {0xbe0ba000}, {0xbe0bc000}, {0xbe0be000}, 
+    {0xbe0c0000}, {0xbe0c2000}, {0xbe0c4000}, {0xbe0c6000}, 
+    {0xbe0c8000}, {0xbe0ca000}, {0xbe0cc000}, {0xbe0ce000}, 
+    {0xbe0d0000}, {0xbe0d2000}, {0xbe0d4000}, {0xbe0d6000}, 
+    {0xbe0d8000}, {0xbe0da000}, {0xbe0dc000}, {0xbe0de000}, 
+    {0xbe0e0000}, {0xbe0e2000}, {0xbe0e4000}, {0xbe0e6000}, 
+    {0xbe0e8000}, {0xbe0ea000}, {0xbe0ec000}, {0xbe0ee000}, 
+    {0xbe0f0000}, {0xbe0f2000}, {0xbe0f4000}, {0xbe0f6000}, 
+    {0xbe0f8000}, {0xbe0fa000}, {0xbe0fc000}, {0xbe0fe000}, 
+    {0xbe100000}, {0xbe102000}, {0xbe104000}, {0xbe106000}, 
+    {0xbe108000}, {0xbe10a000}, {0xbe10c000}, {0xbe10e000}, 
+    {0xbe110000}, {0xbe112000}, {0xbe114000}, {0xbe116000}, 
+    {0xbe118000}, {0xbe11a000}, {0xbe11c000}, {0xbe11e000}, 
+    {0xbe120000}, {0xbe122000}, {0xbe124000}, {0xbe126000}, 
+    {0xbe128000}, {0xbe12a000}, {0xbe12c000}, {0xbe12e000}, 
+    {0xbe130000}, {0xbe132000}, {0xbe134000}, {0xbe136000}, 
+    {0xbe138000}, {0xbe13a000}, {0xbe13c000}, {0xbe13e000}, 
+    {0xbe140000}, {0xbe142000}, {0xbe144000}, {0xbe146000}, 
+    {0xbe148000}, {0xbe14a000}, {0xbe14c000}, {0xbe14e000}, 
+    {0xbe150000}, {0xbe152000}, {0xbe154000}, {0xbe156000}, 
+    {0xbe158000}, {0xbe15a000}, {0xbe15c000}, {0xbe15e000}, 
+    {0xbe160000}, {0xbe162000}, {0xbe164000}, {0xbe166000}, 
+    {0xbe168000}, {0xbe16a000}, {0xbe16c000}, {0xbe16e000}, 
+    {0xbe170000}, {0xbe172000}, {0xbe174000}, {0xbe176000}, 
+    {0xbe178000}, {0xbe17a000}, {0xbe17c000}, {0xbe17e000}, 
+    {0xbe180000}, {0xbe182000}, {0xbe184000}, {0xbe186000}, 
+    {0xbe188000}, {0xbe18a000}, {0xbe18c000}, {0xbe18e000}, 
+    {0xbe190000}, {0xbe192000}, {0xbe194000}, {0xbe196000}, 
+    {0xbe198000}, {0xbe19a000}, {0xbe19c000}, {0xbe19e000}, 
+    {0xbe1a0000}, {0xbe1a2000}, {0xbe1a4000}, {0xbe1a6000}, 
+    {0xbe1a8000}, {0xbe1aa000}, {0xbe1ac000}, {0xbe1ae000}, 
+    {0xbe1b0000}, {0xbe1b2000}, {0xbe1b4000}, {0xbe1b6000}, 
+    {0xbe1b8000}, {0xbe1ba000}, {0xbe1bc000}, {0xbe1be000}, 
+    {0xbe1c0000}, {0xbe1c2000}, {0xbe1c4000}, {0xbe1c6000}, 
+    {0xbe1c8000}, {0xbe1ca000}, {0xbe1cc000}, {0xbe1ce000}, 
+    {0xbe1d0000}, {0xbe1d2000}, {0xbe1d4000}, {0xbe1d6000}, 
+    {0xbe1d8000}, {0xbe1da000}, {0xbe1dc000}, {0xbe1de000}, 
+    {0xbe1e0000}, {0xbe1e2000}, {0xbe1e4000}, {0xbe1e6000}, 
+    {0xbe1e8000}, {0xbe1ea000}, {0xbe1ec000}, {0xbe1ee000}, 
+    {0xbe1f0000}, {0xbe1f2000}, {0xbe1f4000}, {0xbe1f6000}, 
+    {0xbe1f8000}, {0xbe1fa000}, {0xbe1fc000}, {0xbe1fe000}, 
+    {0xbe200000}, {0xbe202000}, {0xbe204000}, {0xbe206000}, 
+    {0xbe208000}, {0xbe20a000}, {0xbe20c000}, {0xbe20e000}, 
+    {0xbe210000}, {0xbe212000}, {0xbe214000}, {0xbe216000}, 
+    {0xbe218000}, {0xbe21a000}, {0xbe21c000}, {0xbe21e000}, 
+    {0xbe220000}, {0xbe222000}, {0xbe224000}, {0xbe226000}, 
+    {0xbe228000}, {0xbe22a000}, {0xbe22c000}, {0xbe22e000}, 
+    {0xbe230000}, {0xbe232000}, {0xbe234000}, {0xbe236000}, 
+    {0xbe238000}, {0xbe23a000}, {0xbe23c000}, {0xbe23e000}, 
+    {0xbe240000}, {0xbe242000}, {0xbe244000}, {0xbe246000}, 
+    {0xbe248000}, {0xbe24a000}, {0xbe24c000}, {0xbe24e000}, 
+    {0xbe250000}, {0xbe252000}, {0xbe254000}, {0xbe256000}, 
+    {0xbe258000}, {0xbe25a000}, {0xbe25c000}, {0xbe25e000}, 
+    {0xbe260000}, {0xbe262000}, {0xbe264000}, {0xbe266000}, 
+    {0xbe268000}, {0xbe26a000}, {0xbe26c000}, {0xbe26e000}, 
+    {0xbe270000}, {0xbe272000}, {0xbe274000}, {0xbe276000}, 
+    {0xbe278000}, {0xbe27a000}, {0xbe27c000}, {0xbe27e000}, 
+    {0xbe280000}, {0xbe282000}, {0xbe284000}, {0xbe286000}, 
+    {0xbe288000}, {0xbe28a000}, {0xbe28c000}, {0xbe28e000}, 
+    {0xbe290000}, {0xbe292000}, {0xbe294000}, {0xbe296000}, 
+    {0xbe298000}, {0xbe29a000}, {0xbe29c000}, {0xbe29e000}, 
+    {0xbe2a0000}, {0xbe2a2000}, {0xbe2a4000}, {0xbe2a6000}, 
+    {0xbe2a8000}, {0xbe2aa000}, {0xbe2ac000}, {0xbe2ae000}, 
+    {0xbe2b0000}, {0xbe2b2000}, {0xbe2b4000}, {0xbe2b6000}, 
+    {0xbe2b8000}, {0xbe2ba000}, {0xbe2bc000}, {0xbe2be000}, 
+    {0xbe2c0000}, {0xbe2c2000}, {0xbe2c4000}, {0xbe2c6000}, 
+    {0xbe2c8000}, {0xbe2ca000}, {0xbe2cc000}, {0xbe2ce000}, 
+    {0xbe2d0000}, {0xbe2d2000}, {0xbe2d4000}, {0xbe2d6000}, 
+    {0xbe2d8000}, {0xbe2da000}, {0xbe2dc000}, {0xbe2de000}, 
+    {0xbe2e0000}, {0xbe2e2000}, {0xbe2e4000}, {0xbe2e6000}, 
+    {0xbe2e8000}, {0xbe2ea000}, {0xbe2ec000}, {0xbe2ee000}, 
+    {0xbe2f0000}, {0xbe2f2000}, {0xbe2f4000}, {0xbe2f6000}, 
+    {0xbe2f8000}, {0xbe2fa000}, {0xbe2fc000}, {0xbe2fe000}, 
+    {0xbe300000}, {0xbe302000}, {0xbe304000}, {0xbe306000}, 
+    {0xbe308000}, {0xbe30a000}, {0xbe30c000}, {0xbe30e000}, 
+    {0xbe310000}, {0xbe312000}, {0xbe314000}, {0xbe316000}, 
+    {0xbe318000}, {0xbe31a000}, {0xbe31c000}, {0xbe31e000}, 
+    {0xbe320000}, {0xbe322000}, {0xbe324000}, {0xbe326000}, 
+    {0xbe328000}, {0xbe32a000}, {0xbe32c000}, {0xbe32e000}, 
+    {0xbe330000}, {0xbe332000}, {0xbe334000}, {0xbe336000}, 
+    {0xbe338000}, {0xbe33a000}, {0xbe33c000}, {0xbe33e000}, 
+    {0xbe340000}, {0xbe342000}, {0xbe344000}, {0xbe346000}, 
+    {0xbe348000}, {0xbe34a000}, {0xbe34c000}, {0xbe34e000}, 
+    {0xbe350000}, {0xbe352000}, {0xbe354000}, {0xbe356000}, 
+    {0xbe358000}, {0xbe35a000}, {0xbe35c000}, {0xbe35e000}, 
+    {0xbe360000}, {0xbe362000}, {0xbe364000}, {0xbe366000}, 
+    {0xbe368000}, {0xbe36a000}, {0xbe36c000}, {0xbe36e000}, 
+    {0xbe370000}, {0xbe372000}, {0xbe374000}, {0xbe376000}, 
+    {0xbe378000}, {0xbe37a000}, {0xbe37c000}, {0xbe37e000}, 
+    {0xbe380000}, {0xbe382000}, {0xbe384000}, {0xbe386000}, 
+    {0xbe388000}, {0xbe38a000}, {0xbe38c000}, {0xbe38e000}, 
+    {0xbe390000}, {0xbe392000}, {0xbe394000}, {0xbe396000}, 
+    {0xbe398000}, {0xbe39a000}, {0xbe39c000}, {0xbe39e000}, 
+    {0xbe3a0000}, {0xbe3a2000}, {0xbe3a4000}, {0xbe3a6000}, 
+    {0xbe3a8000}, {0xbe3aa000}, {0xbe3ac000}, {0xbe3ae000}, 
+    {0xbe3b0000}, {0xbe3b2000}, {0xbe3b4000}, {0xbe3b6000}, 
+    {0xbe3b8000}, {0xbe3ba000}, {0xbe3bc000}, {0xbe3be000}, 
+    {0xbe3c0000}, {0xbe3c2000}, {0xbe3c4000}, {0xbe3c6000}, 
+    {0xbe3c8000}, {0xbe3ca000}, {0xbe3cc000}, {0xbe3ce000}, 
+    {0xbe3d0000}, {0xbe3d2000}, {0xbe3d4000}, {0xbe3d6000}, 
+    {0xbe3d8000}, {0xbe3da000}, {0xbe3dc000}, {0xbe3de000}, 
+    {0xbe3e0000}, {0xbe3e2000}, {0xbe3e4000}, {0xbe3e6000}, 
+    {0xbe3e8000}, {0xbe3ea000}, {0xbe3ec000}, {0xbe3ee000}, 
+    {0xbe3f0000}, {0xbe3f2000}, {0xbe3f4000}, {0xbe3f6000}, 
+    {0xbe3f8000}, {0xbe3fa000}, {0xbe3fc000}, {0xbe3fe000}, 
+    {0xbe400000}, {0xbe402000}, {0xbe404000}, {0xbe406000}, 
+    {0xbe408000}, {0xbe40a000}, {0xbe40c000}, {0xbe40e000}, 
+    {0xbe410000}, {0xbe412000}, {0xbe414000}, {0xbe416000}, 
+    {0xbe418000}, {0xbe41a000}, {0xbe41c000}, {0xbe41e000}, 
+    {0xbe420000}, {0xbe422000}, {0xbe424000}, {0xbe426000}, 
+    {0xbe428000}, {0xbe42a000}, {0xbe42c000}, {0xbe42e000}, 
+    {0xbe430000}, {0xbe432000}, {0xbe434000}, {0xbe436000}, 
+    {0xbe438000}, {0xbe43a000}, {0xbe43c000}, {0xbe43e000}, 
+    {0xbe440000}, {0xbe442000}, {0xbe444000}, {0xbe446000}, 
+    {0xbe448000}, {0xbe44a000}, {0xbe44c000}, {0xbe44e000}, 
+    {0xbe450000}, {0xbe452000}, {0xbe454000}, {0xbe456000}, 
+    {0xbe458000}, {0xbe45a000}, {0xbe45c000}, {0xbe45e000}, 
+    {0xbe460000}, {0xbe462000}, {0xbe464000}, {0xbe466000}, 
+    {0xbe468000}, {0xbe46a000}, {0xbe46c000}, {0xbe46e000}, 
+    {0xbe470000}, {0xbe472000}, {0xbe474000}, {0xbe476000}, 
+    {0xbe478000}, {0xbe47a000}, {0xbe47c000}, {0xbe47e000}, 
+    {0xbe480000}, {0xbe482000}, {0xbe484000}, {0xbe486000}, 
+    {0xbe488000}, {0xbe48a000}, {0xbe48c000}, {0xbe48e000}, 
+    {0xbe490000}, {0xbe492000}, {0xbe494000}, {0xbe496000}, 
+    {0xbe498000}, {0xbe49a000}, {0xbe49c000}, {0xbe49e000}, 
+    {0xbe4a0000}, {0xbe4a2000}, {0xbe4a4000}, {0xbe4a6000}, 
+    {0xbe4a8000}, {0xbe4aa000}, {0xbe4ac000}, {0xbe4ae000}, 
+    {0xbe4b0000}, {0xbe4b2000}, {0xbe4b4000}, {0xbe4b6000}, 
+    {0xbe4b8000}, {0xbe4ba000}, {0xbe4bc000}, {0xbe4be000}, 
+    {0xbe4c0000}, {0xbe4c2000}, {0xbe4c4000}, {0xbe4c6000}, 
+    {0xbe4c8000}, {0xbe4ca000}, {0xbe4cc000}, {0xbe4ce000}, 
+    {0xbe4d0000}, {0xbe4d2000}, {0xbe4d4000}, {0xbe4d6000}, 
+    {0xbe4d8000}, {0xbe4da000}, {0xbe4dc000}, {0xbe4de000}, 
+    {0xbe4e0000}, {0xbe4e2000}, {0xbe4e4000}, {0xbe4e6000}, 
+    {0xbe4e8000}, {0xbe4ea000}, {0xbe4ec000}, {0xbe4ee000}, 
+    {0xbe4f0000}, {0xbe4f2000}, {0xbe4f4000}, {0xbe4f6000}, 
+    {0xbe4f8000}, {0xbe4fa000}, {0xbe4fc000}, {0xbe4fe000}, 
+    {0xbe500000}, {0xbe502000}, {0xbe504000}, {0xbe506000}, 
+    {0xbe508000}, {0xbe50a000}, {0xbe50c000}, {0xbe50e000}, 
+    {0xbe510000}, {0xbe512000}, {0xbe514000}, {0xbe516000}, 
+    {0xbe518000}, {0xbe51a000}, {0xbe51c000}, {0xbe51e000}, 
+    {0xbe520000}, {0xbe522000}, {0xbe524000}, {0xbe526000}, 
+    {0xbe528000}, {0xbe52a000}, {0xbe52c000}, {0xbe52e000}, 
+    {0xbe530000}, {0xbe532000}, {0xbe534000}, {0xbe536000}, 
+    {0xbe538000}, {0xbe53a000}, {0xbe53c000}, {0xbe53e000}, 
+    {0xbe540000}, {0xbe542000}, {0xbe544000}, {0xbe546000}, 
+    {0xbe548000}, {0xbe54a000}, {0xbe54c000}, {0xbe54e000}, 
+    {0xbe550000}, {0xbe552000}, {0xbe554000}, {0xbe556000}, 
+    {0xbe558000}, {0xbe55a000}, {0xbe55c000}, {0xbe55e000}, 
+    {0xbe560000}, {0xbe562000}, {0xbe564000}, {0xbe566000}, 
+    {0xbe568000}, {0xbe56a000}, {0xbe56c000}, {0xbe56e000}, 
+    {0xbe570000}, {0xbe572000}, {0xbe574000}, {0xbe576000}, 
+    {0xbe578000}, {0xbe57a000}, {0xbe57c000}, {0xbe57e000}, 
+    {0xbe580000}, {0xbe582000}, {0xbe584000}, {0xbe586000}, 
+    {0xbe588000}, {0xbe58a000}, {0xbe58c000}, {0xbe58e000}, 
+    {0xbe590000}, {0xbe592000}, {0xbe594000}, {0xbe596000}, 
+    {0xbe598000}, {0xbe59a000}, {0xbe59c000}, {0xbe59e000}, 
+    {0xbe5a0000}, {0xbe5a2000}, {0xbe5a4000}, {0xbe5a6000}, 
+    {0xbe5a8000}, {0xbe5aa000}, {0xbe5ac000}, {0xbe5ae000}, 
+    {0xbe5b0000}, {0xbe5b2000}, {0xbe5b4000}, {0xbe5b6000}, 
+    {0xbe5b8000}, {0xbe5ba000}, {0xbe5bc000}, {0xbe5be000}, 
+    {0xbe5c0000}, {0xbe5c2000}, {0xbe5c4000}, {0xbe5c6000}, 
+    {0xbe5c8000}, {0xbe5ca000}, {0xbe5cc000}, {0xbe5ce000}, 
+    {0xbe5d0000}, {0xbe5d2000}, {0xbe5d4000}, {0xbe5d6000}, 
+    {0xbe5d8000}, {0xbe5da000}, {0xbe5dc000}, {0xbe5de000}, 
+    {0xbe5e0000}, {0xbe5e2000}, {0xbe5e4000}, {0xbe5e6000}, 
+    {0xbe5e8000}, {0xbe5ea000}, {0xbe5ec000}, {0xbe5ee000}, 
+    {0xbe5f0000}, {0xbe5f2000}, {0xbe5f4000}, {0xbe5f6000}, 
+    {0xbe5f8000}, {0xbe5fa000}, {0xbe5fc000}, {0xbe5fe000}, 
+    {0xbe600000}, {0xbe602000}, {0xbe604000}, {0xbe606000}, 
+    {0xbe608000}, {0xbe60a000}, {0xbe60c000}, {0xbe60e000}, 
+    {0xbe610000}, {0xbe612000}, {0xbe614000}, {0xbe616000}, 
+    {0xbe618000}, {0xbe61a000}, {0xbe61c000}, {0xbe61e000}, 
+    {0xbe620000}, {0xbe622000}, {0xbe624000}, {0xbe626000}, 
+    {0xbe628000}, {0xbe62a000}, {0xbe62c000}, {0xbe62e000}, 
+    {0xbe630000}, {0xbe632000}, {0xbe634000}, {0xbe636000}, 
+    {0xbe638000}, {0xbe63a000}, {0xbe63c000}, {0xbe63e000}, 
+    {0xbe640000}, {0xbe642000}, {0xbe644000}, {0xbe646000}, 
+    {0xbe648000}, {0xbe64a000}, {0xbe64c000}, {0xbe64e000}, 
+    {0xbe650000}, {0xbe652000}, {0xbe654000}, {0xbe656000}, 
+    {0xbe658000}, {0xbe65a000}, {0xbe65c000}, {0xbe65e000}, 
+    {0xbe660000}, {0xbe662000}, {0xbe664000}, {0xbe666000}, 
+    {0xbe668000}, {0xbe66a000}, {0xbe66c000}, {0xbe66e000}, 
+    {0xbe670000}, {0xbe672000}, {0xbe674000}, {0xbe676000}, 
+    {0xbe678000}, {0xbe67a000}, {0xbe67c000}, {0xbe67e000}, 
+    {0xbe680000}, {0xbe682000}, {0xbe684000}, {0xbe686000}, 
+    {0xbe688000}, {0xbe68a000}, {0xbe68c000}, {0xbe68e000}, 
+    {0xbe690000}, {0xbe692000}, {0xbe694000}, {0xbe696000}, 
+    {0xbe698000}, {0xbe69a000}, {0xbe69c000}, {0xbe69e000}, 
+    {0xbe6a0000}, {0xbe6a2000}, {0xbe6a4000}, {0xbe6a6000}, 
+    {0xbe6a8000}, {0xbe6aa000}, {0xbe6ac000}, {0xbe6ae000}, 
+    {0xbe6b0000}, {0xbe6b2000}, {0xbe6b4000}, {0xbe6b6000}, 
+    {0xbe6b8000}, {0xbe6ba000}, {0xbe6bc000}, {0xbe6be000}, 
+    {0xbe6c0000}, {0xbe6c2000}, {0xbe6c4000}, {0xbe6c6000}, 
+    {0xbe6c8000}, {0xbe6ca000}, {0xbe6cc000}, {0xbe6ce000}, 
+    {0xbe6d0000}, {0xbe6d2000}, {0xbe6d4000}, {0xbe6d6000}, 
+    {0xbe6d8000}, {0xbe6da000}, {0xbe6dc000}, {0xbe6de000}, 
+    {0xbe6e0000}, {0xbe6e2000}, {0xbe6e4000}, {0xbe6e6000}, 
+    {0xbe6e8000}, {0xbe6ea000}, {0xbe6ec000}, {0xbe6ee000}, 
+    {0xbe6f0000}, {0xbe6f2000}, {0xbe6f4000}, {0xbe6f6000}, 
+    {0xbe6f8000}, {0xbe6fa000}, {0xbe6fc000}, {0xbe6fe000}, 
+    {0xbe700000}, {0xbe702000}, {0xbe704000}, {0xbe706000}, 
+    {0xbe708000}, {0xbe70a000}, {0xbe70c000}, {0xbe70e000}, 
+    {0xbe710000}, {0xbe712000}, {0xbe714000}, {0xbe716000}, 
+    {0xbe718000}, {0xbe71a000}, {0xbe71c000}, {0xbe71e000}, 
+    {0xbe720000}, {0xbe722000}, {0xbe724000}, {0xbe726000}, 
+    {0xbe728000}, {0xbe72a000}, {0xbe72c000}, {0xbe72e000}, 
+    {0xbe730000}, {0xbe732000}, {0xbe734000}, {0xbe736000}, 
+    {0xbe738000}, {0xbe73a000}, {0xbe73c000}, {0xbe73e000}, 
+    {0xbe740000}, {0xbe742000}, {0xbe744000}, {0xbe746000}, 
+    {0xbe748000}, {0xbe74a000}, {0xbe74c000}, {0xbe74e000}, 
+    {0xbe750000}, {0xbe752000}, {0xbe754000}, {0xbe756000}, 
+    {0xbe758000}, {0xbe75a000}, {0xbe75c000}, {0xbe75e000}, 
+    {0xbe760000}, {0xbe762000}, {0xbe764000}, {0xbe766000}, 
+    {0xbe768000}, {0xbe76a000}, {0xbe76c000}, {0xbe76e000}, 
+    {0xbe770000}, {0xbe772000}, {0xbe774000}, {0xbe776000}, 
+    {0xbe778000}, {0xbe77a000}, {0xbe77c000}, {0xbe77e000}, 
+    {0xbe780000}, {0xbe782000}, {0xbe784000}, {0xbe786000}, 
+    {0xbe788000}, {0xbe78a000}, {0xbe78c000}, {0xbe78e000}, 
+    {0xbe790000}, {0xbe792000}, {0xbe794000}, {0xbe796000}, 
+    {0xbe798000}, {0xbe79a000}, {0xbe79c000}, {0xbe79e000}, 
+    {0xbe7a0000}, {0xbe7a2000}, {0xbe7a4000}, {0xbe7a6000}, 
+    {0xbe7a8000}, {0xbe7aa000}, {0xbe7ac000}, {0xbe7ae000}, 
+    {0xbe7b0000}, {0xbe7b2000}, {0xbe7b4000}, {0xbe7b6000}, 
+    {0xbe7b8000}, {0xbe7ba000}, {0xbe7bc000}, {0xbe7be000}, 
+    {0xbe7c0000}, {0xbe7c2000}, {0xbe7c4000}, {0xbe7c6000}, 
+    {0xbe7c8000}, {0xbe7ca000}, {0xbe7cc000}, {0xbe7ce000}, 
+    {0xbe7d0000}, {0xbe7d2000}, {0xbe7d4000}, {0xbe7d6000}, 
+    {0xbe7d8000}, {0xbe7da000}, {0xbe7dc000}, {0xbe7de000}, 
+    {0xbe7e0000}, {0xbe7e2000}, {0xbe7e4000}, {0xbe7e6000}, 
+    {0xbe7e8000}, {0xbe7ea000}, {0xbe7ec000}, {0xbe7ee000}, 
+    {0xbe7f0000}, {0xbe7f2000}, {0xbe7f4000}, {0xbe7f6000}, 
+    {0xbe7f8000}, {0xbe7fa000}, {0xbe7fc000}, {0xbe7fe000}, 
+    {0xbe800000}, {0xbe802000}, {0xbe804000}, {0xbe806000}, 
+    {0xbe808000}, {0xbe80a000}, {0xbe80c000}, {0xbe80e000}, 
+    {0xbe810000}, {0xbe812000}, {0xbe814000}, {0xbe816000}, 
+    {0xbe818000}, {0xbe81a000}, {0xbe81c000}, {0xbe81e000}, 
+    {0xbe820000}, {0xbe822000}, {0xbe824000}, {0xbe826000}, 
+    {0xbe828000}, {0xbe82a000}, {0xbe82c000}, {0xbe82e000}, 
+    {0xbe830000}, {0xbe832000}, {0xbe834000}, {0xbe836000}, 
+    {0xbe838000}, {0xbe83a000}, {0xbe83c000}, {0xbe83e000}, 
+    {0xbe840000}, {0xbe842000}, {0xbe844000}, {0xbe846000}, 
+    {0xbe848000}, {0xbe84a000}, {0xbe84c000}, {0xbe84e000}, 
+    {0xbe850000}, {0xbe852000}, {0xbe854000}, {0xbe856000}, 
+    {0xbe858000}, {0xbe85a000}, {0xbe85c000}, {0xbe85e000}, 
+    {0xbe860000}, {0xbe862000}, {0xbe864000}, {0xbe866000}, 
+    {0xbe868000}, {0xbe86a000}, {0xbe86c000}, {0xbe86e000}, 
+    {0xbe870000}, {0xbe872000}, {0xbe874000}, {0xbe876000}, 
+    {0xbe878000}, {0xbe87a000}, {0xbe87c000}, {0xbe87e000}, 
+    {0xbe880000}, {0xbe882000}, {0xbe884000}, {0xbe886000}, 
+    {0xbe888000}, {0xbe88a000}, {0xbe88c000}, {0xbe88e000}, 
+    {0xbe890000}, {0xbe892000}, {0xbe894000}, {0xbe896000}, 
+    {0xbe898000}, {0xbe89a000}, {0xbe89c000}, {0xbe89e000}, 
+    {0xbe8a0000}, {0xbe8a2000}, {0xbe8a4000}, {0xbe8a6000}, 
+    {0xbe8a8000}, {0xbe8aa000}, {0xbe8ac000}, {0xbe8ae000}, 
+    {0xbe8b0000}, {0xbe8b2000}, {0xbe8b4000}, {0xbe8b6000}, 
+    {0xbe8b8000}, {0xbe8ba000}, {0xbe8bc000}, {0xbe8be000}, 
+    {0xbe8c0000}, {0xbe8c2000}, {0xbe8c4000}, {0xbe8c6000}, 
+    {0xbe8c8000}, {0xbe8ca000}, {0xbe8cc000}, {0xbe8ce000}, 
+    {0xbe8d0000}, {0xbe8d2000}, {0xbe8d4000}, {0xbe8d6000}, 
+    {0xbe8d8000}, {0xbe8da000}, {0xbe8dc000}, {0xbe8de000}, 
+    {0xbe8e0000}, {0xbe8e2000}, {0xbe8e4000}, {0xbe8e6000}, 
+    {0xbe8e8000}, {0xbe8ea000}, {0xbe8ec000}, {0xbe8ee000}, 
+    {0xbe8f0000}, {0xbe8f2000}, {0xbe8f4000}, {0xbe8f6000}, 
+    {0xbe8f8000}, {0xbe8fa000}, {0xbe8fc000}, {0xbe8fe000}, 
+    {0xbe900000}, {0xbe902000}, {0xbe904000}, {0xbe906000}, 
+    {0xbe908000}, {0xbe90a000}, {0xbe90c000}, {0xbe90e000}, 
+    {0xbe910000}, {0xbe912000}, {0xbe914000}, {0xbe916000}, 
+    {0xbe918000}, {0xbe91a000}, {0xbe91c000}, {0xbe91e000}, 
+    {0xbe920000}, {0xbe922000}, {0xbe924000}, {0xbe926000}, 
+    {0xbe928000}, {0xbe92a000}, {0xbe92c000}, {0xbe92e000}, 
+    {0xbe930000}, {0xbe932000}, {0xbe934000}, {0xbe936000}, 
+    {0xbe938000}, {0xbe93a000}, {0xbe93c000}, {0xbe93e000}, 
+    {0xbe940000}, {0xbe942000}, {0xbe944000}, {0xbe946000}, 
+    {0xbe948000}, {0xbe94a000}, {0xbe94c000}, {0xbe94e000}, 
+    {0xbe950000}, {0xbe952000}, {0xbe954000}, {0xbe956000}, 
+    {0xbe958000}, {0xbe95a000}, {0xbe95c000}, {0xbe95e000}, 
+    {0xbe960000}, {0xbe962000}, {0xbe964000}, {0xbe966000}, 
+    {0xbe968000}, {0xbe96a000}, {0xbe96c000}, {0xbe96e000}, 
+    {0xbe970000}, {0xbe972000}, {0xbe974000}, {0xbe976000}, 
+    {0xbe978000}, {0xbe97a000}, {0xbe97c000}, {0xbe97e000}, 
+    {0xbe980000}, {0xbe982000}, {0xbe984000}, {0xbe986000}, 
+    {0xbe988000}, {0xbe98a000}, {0xbe98c000}, {0xbe98e000}, 
+    {0xbe990000}, {0xbe992000}, {0xbe994000}, {0xbe996000}, 
+    {0xbe998000}, {0xbe99a000}, {0xbe99c000}, {0xbe99e000}, 
+    {0xbe9a0000}, {0xbe9a2000}, {0xbe9a4000}, {0xbe9a6000}, 
+    {0xbe9a8000}, {0xbe9aa000}, {0xbe9ac000}, {0xbe9ae000}, 
+    {0xbe9b0000}, {0xbe9b2000}, {0xbe9b4000}, {0xbe9b6000}, 
+    {0xbe9b8000}, {0xbe9ba000}, {0xbe9bc000}, {0xbe9be000}, 
+    {0xbe9c0000}, {0xbe9c2000}, {0xbe9c4000}, {0xbe9c6000}, 
+    {0xbe9c8000}, {0xbe9ca000}, {0xbe9cc000}, {0xbe9ce000}, 
+    {0xbe9d0000}, {0xbe9d2000}, {0xbe9d4000}, {0xbe9d6000}, 
+    {0xbe9d8000}, {0xbe9da000}, {0xbe9dc000}, {0xbe9de000}, 
+    {0xbe9e0000}, {0xbe9e2000}, {0xbe9e4000}, {0xbe9e6000}, 
+    {0xbe9e8000}, {0xbe9ea000}, {0xbe9ec000}, {0xbe9ee000}, 
+    {0xbe9f0000}, {0xbe9f2000}, {0xbe9f4000}, {0xbe9f6000}, 
+    {0xbe9f8000}, {0xbe9fa000}, {0xbe9fc000}, {0xbe9fe000}, 
+    {0xbea00000}, {0xbea02000}, {0xbea04000}, {0xbea06000}, 
+    {0xbea08000}, {0xbea0a000}, {0xbea0c000}, {0xbea0e000}, 
+    {0xbea10000}, {0xbea12000}, {0xbea14000}, {0xbea16000}, 
+    {0xbea18000}, {0xbea1a000}, {0xbea1c000}, {0xbea1e000}, 
+    {0xbea20000}, {0xbea22000}, {0xbea24000}, {0xbea26000}, 
+    {0xbea28000}, {0xbea2a000}, {0xbea2c000}, {0xbea2e000}, 
+    {0xbea30000}, {0xbea32000}, {0xbea34000}, {0xbea36000}, 
+    {0xbea38000}, {0xbea3a000}, {0xbea3c000}, {0xbea3e000}, 
+    {0xbea40000}, {0xbea42000}, {0xbea44000}, {0xbea46000}, 
+    {0xbea48000}, {0xbea4a000}, {0xbea4c000}, {0xbea4e000}, 
+    {0xbea50000}, {0xbea52000}, {0xbea54000}, {0xbea56000}, 
+    {0xbea58000}, {0xbea5a000}, {0xbea5c000}, {0xbea5e000}, 
+    {0xbea60000}, {0xbea62000}, {0xbea64000}, {0xbea66000}, 
+    {0xbea68000}, {0xbea6a000}, {0xbea6c000}, {0xbea6e000}, 
+    {0xbea70000}, {0xbea72000}, {0xbea74000}, {0xbea76000}, 
+    {0xbea78000}, {0xbea7a000}, {0xbea7c000}, {0xbea7e000}, 
+    {0xbea80000}, {0xbea82000}, {0xbea84000}, {0xbea86000}, 
+    {0xbea88000}, {0xbea8a000}, {0xbea8c000}, {0xbea8e000}, 
+    {0xbea90000}, {0xbea92000}, {0xbea94000}, {0xbea96000}, 
+    {0xbea98000}, {0xbea9a000}, {0xbea9c000}, {0xbea9e000}, 
+    {0xbeaa0000}, {0xbeaa2000}, {0xbeaa4000}, {0xbeaa6000}, 
+    {0xbeaa8000}, {0xbeaaa000}, {0xbeaac000}, {0xbeaae000}, 
+    {0xbeab0000}, {0xbeab2000}, {0xbeab4000}, {0xbeab6000}, 
+    {0xbeab8000}, {0xbeaba000}, {0xbeabc000}, {0xbeabe000}, 
+    {0xbeac0000}, {0xbeac2000}, {0xbeac4000}, {0xbeac6000}, 
+    {0xbeac8000}, {0xbeaca000}, {0xbeacc000}, {0xbeace000}, 
+    {0xbead0000}, {0xbead2000}, {0xbead4000}, {0xbead6000}, 
+    {0xbead8000}, {0xbeada000}, {0xbeadc000}, {0xbeade000}, 
+    {0xbeae0000}, {0xbeae2000}, {0xbeae4000}, {0xbeae6000}, 
+    {0xbeae8000}, {0xbeaea000}, {0xbeaec000}, {0xbeaee000}, 
+    {0xbeaf0000}, {0xbeaf2000}, {0xbeaf4000}, {0xbeaf6000}, 
+    {0xbeaf8000}, {0xbeafa000}, {0xbeafc000}, {0xbeafe000}, 
+    {0xbeb00000}, {0xbeb02000}, {0xbeb04000}, {0xbeb06000}, 
+    {0xbeb08000}, {0xbeb0a000}, {0xbeb0c000}, {0xbeb0e000}, 
+    {0xbeb10000}, {0xbeb12000}, {0xbeb14000}, {0xbeb16000}, 
+    {0xbeb18000}, {0xbeb1a000}, {0xbeb1c000}, {0xbeb1e000}, 
+    {0xbeb20000}, {0xbeb22000}, {0xbeb24000}, {0xbeb26000}, 
+    {0xbeb28000}, {0xbeb2a000}, {0xbeb2c000}, {0xbeb2e000}, 
+    {0xbeb30000}, {0xbeb32000}, {0xbeb34000}, {0xbeb36000}, 
+    {0xbeb38000}, {0xbeb3a000}, {0xbeb3c000}, {0xbeb3e000}, 
+    {0xbeb40000}, {0xbeb42000}, {0xbeb44000}, {0xbeb46000}, 
+    {0xbeb48000}, {0xbeb4a000}, {0xbeb4c000}, {0xbeb4e000}, 
+    {0xbeb50000}, {0xbeb52000}, {0xbeb54000}, {0xbeb56000}, 
+    {0xbeb58000}, {0xbeb5a000}, {0xbeb5c000}, {0xbeb5e000}, 
+    {0xbeb60000}, {0xbeb62000}, {0xbeb64000}, {0xbeb66000}, 
+    {0xbeb68000}, {0xbeb6a000}, {0xbeb6c000}, {0xbeb6e000}, 
+    {0xbeb70000}, {0xbeb72000}, {0xbeb74000}, {0xbeb76000}, 
+    {0xbeb78000}, {0xbeb7a000}, {0xbeb7c000}, {0xbeb7e000}, 
+    {0xbeb80000}, {0xbeb82000}, {0xbeb84000}, {0xbeb86000}, 
+    {0xbeb88000}, {0xbeb8a000}, {0xbeb8c000}, {0xbeb8e000}, 
+    {0xbeb90000}, {0xbeb92000}, {0xbeb94000}, {0xbeb96000}, 
+    {0xbeb98000}, {0xbeb9a000}, {0xbeb9c000}, {0xbeb9e000}, 
+    {0xbeba0000}, {0xbeba2000}, {0xbeba4000}, {0xbeba6000}, 
+    {0xbeba8000}, {0xbebaa000}, {0xbebac000}, {0xbebae000}, 
+    {0xbebb0000}, {0xbebb2000}, {0xbebb4000}, {0xbebb6000}, 
+    {0xbebb8000}, {0xbebba000}, {0xbebbc000}, {0xbebbe000}, 
+    {0xbebc0000}, {0xbebc2000}, {0xbebc4000}, {0xbebc6000}, 
+    {0xbebc8000}, {0xbebca000}, {0xbebcc000}, {0xbebce000}, 
+    {0xbebd0000}, {0xbebd2000}, {0xbebd4000}, {0xbebd6000}, 
+    {0xbebd8000}, {0xbebda000}, {0xbebdc000}, {0xbebde000}, 
+    {0xbebe0000}, {0xbebe2000}, {0xbebe4000}, {0xbebe6000}, 
+    {0xbebe8000}, {0xbebea000}, {0xbebec000}, {0xbebee000}, 
+    {0xbebf0000}, {0xbebf2000}, {0xbebf4000}, {0xbebf6000}, 
+    {0xbebf8000}, {0xbebfa000}, {0xbebfc000}, {0xbebfe000}, 
+    {0xbec00000}, {0xbec02000}, {0xbec04000}, {0xbec06000}, 
+    {0xbec08000}, {0xbec0a000}, {0xbec0c000}, {0xbec0e000}, 
+    {0xbec10000}, {0xbec12000}, {0xbec14000}, {0xbec16000}, 
+    {0xbec18000}, {0xbec1a000}, {0xbec1c000}, {0xbec1e000}, 
+    {0xbec20000}, {0xbec22000}, {0xbec24000}, {0xbec26000}, 
+    {0xbec28000}, {0xbec2a000}, {0xbec2c000}, {0xbec2e000}, 
+    {0xbec30000}, {0xbec32000}, {0xbec34000}, {0xbec36000}, 
+    {0xbec38000}, {0xbec3a000}, {0xbec3c000}, {0xbec3e000}, 
+    {0xbec40000}, {0xbec42000}, {0xbec44000}, {0xbec46000}, 
+    {0xbec48000}, {0xbec4a000}, {0xbec4c000}, {0xbec4e000}, 
+    {0xbec50000}, {0xbec52000}, {0xbec54000}, {0xbec56000}, 
+    {0xbec58000}, {0xbec5a000}, {0xbec5c000}, {0xbec5e000}, 
+    {0xbec60000}, {0xbec62000}, {0xbec64000}, {0xbec66000}, 
+    {0xbec68000}, {0xbec6a000}, {0xbec6c000}, {0xbec6e000}, 
+    {0xbec70000}, {0xbec72000}, {0xbec74000}, {0xbec76000}, 
+    {0xbec78000}, {0xbec7a000}, {0xbec7c000}, {0xbec7e000}, 
+    {0xbec80000}, {0xbec82000}, {0xbec84000}, {0xbec86000}, 
+    {0xbec88000}, {0xbec8a000}, {0xbec8c000}, {0xbec8e000}, 
+    {0xbec90000}, {0xbec92000}, {0xbec94000}, {0xbec96000}, 
+    {0xbec98000}, {0xbec9a000}, {0xbec9c000}, {0xbec9e000}, 
+    {0xbeca0000}, {0xbeca2000}, {0xbeca4000}, {0xbeca6000}, 
+    {0xbeca8000}, {0xbecaa000}, {0xbecac000}, {0xbecae000}, 
+    {0xbecb0000}, {0xbecb2000}, {0xbecb4000}, {0xbecb6000}, 
+    {0xbecb8000}, {0xbecba000}, {0xbecbc000}, {0xbecbe000}, 
+    {0xbecc0000}, {0xbecc2000}, {0xbecc4000}, {0xbecc6000}, 
+    {0xbecc8000}, {0xbecca000}, {0xbeccc000}, {0xbecce000}, 
+    {0xbecd0000}, {0xbecd2000}, {0xbecd4000}, {0xbecd6000}, 
+    {0xbecd8000}, {0xbecda000}, {0xbecdc000}, {0xbecde000}, 
+    {0xbece0000}, {0xbece2000}, {0xbece4000}, {0xbece6000}, 
+    {0xbece8000}, {0xbecea000}, {0xbecec000}, {0xbecee000}, 
+    {0xbecf0000}, {0xbecf2000}, {0xbecf4000}, {0xbecf6000}, 
+    {0xbecf8000}, {0xbecfa000}, {0xbecfc000}, {0xbecfe000}, 
+    {0xbed00000}, {0xbed02000}, {0xbed04000}, {0xbed06000}, 
+    {0xbed08000}, {0xbed0a000}, {0xbed0c000}, {0xbed0e000}, 
+    {0xbed10000}, {0xbed12000}, {0xbed14000}, {0xbed16000}, 
+    {0xbed18000}, {0xbed1a000}, {0xbed1c000}, {0xbed1e000}, 
+    {0xbed20000}, {0xbed22000}, {0xbed24000}, {0xbed26000}, 
+    {0xbed28000}, {0xbed2a000}, {0xbed2c000}, {0xbed2e000}, 
+    {0xbed30000}, {0xbed32000}, {0xbed34000}, {0xbed36000}, 
+    {0xbed38000}, {0xbed3a000}, {0xbed3c000}, {0xbed3e000}, 
+    {0xbed40000}, {0xbed42000}, {0xbed44000}, {0xbed46000}, 
+    {0xbed48000}, {0xbed4a000}, {0xbed4c000}, {0xbed4e000}, 
+    {0xbed50000}, {0xbed52000}, {0xbed54000}, {0xbed56000}, 
+    {0xbed58000}, {0xbed5a000}, {0xbed5c000}, {0xbed5e000}, 
+    {0xbed60000}, {0xbed62000}, {0xbed64000}, {0xbed66000}, 
+    {0xbed68000}, {0xbed6a000}, {0xbed6c000}, {0xbed6e000}, 
+    {0xbed70000}, {0xbed72000}, {0xbed74000}, {0xbed76000}, 
+    {0xbed78000}, {0xbed7a000}, {0xbed7c000}, {0xbed7e000}, 
+    {0xbed80000}, {0xbed82000}, {0xbed84000}, {0xbed86000}, 
+    {0xbed88000}, {0xbed8a000}, {0xbed8c000}, {0xbed8e000}, 
+    {0xbed90000}, {0xbed92000}, {0xbed94000}, {0xbed96000}, 
+    {0xbed98000}, {0xbed9a000}, {0xbed9c000}, {0xbed9e000}, 
+    {0xbeda0000}, {0xbeda2000}, {0xbeda4000}, {0xbeda6000}, 
+    {0xbeda8000}, {0xbedaa000}, {0xbedac000}, {0xbedae000}, 
+    {0xbedb0000}, {0xbedb2000}, {0xbedb4000}, {0xbedb6000}, 
+    {0xbedb8000}, {0xbedba000}, {0xbedbc000}, {0xbedbe000}, 
+    {0xbedc0000}, {0xbedc2000}, {0xbedc4000}, {0xbedc6000}, 
+    {0xbedc8000}, {0xbedca000}, {0xbedcc000}, {0xbedce000}, 
+    {0xbedd0000}, {0xbedd2000}, {0xbedd4000}, {0xbedd6000}, 
+    {0xbedd8000}, {0xbedda000}, {0xbeddc000}, {0xbedde000}, 
+    {0xbede0000}, {0xbede2000}, {0xbede4000}, {0xbede6000}, 
+    {0xbede8000}, {0xbedea000}, {0xbedec000}, {0xbedee000}, 
+    {0xbedf0000}, {0xbedf2000}, {0xbedf4000}, {0xbedf6000}, 
+    {0xbedf8000}, {0xbedfa000}, {0xbedfc000}, {0xbedfe000}, 
+    {0xbee00000}, {0xbee02000}, {0xbee04000}, {0xbee06000}, 
+    {0xbee08000}, {0xbee0a000}, {0xbee0c000}, {0xbee0e000}, 
+    {0xbee10000}, {0xbee12000}, {0xbee14000}, {0xbee16000}, 
+    {0xbee18000}, {0xbee1a000}, {0xbee1c000}, {0xbee1e000}, 
+    {0xbee20000}, {0xbee22000}, {0xbee24000}, {0xbee26000}, 
+    {0xbee28000}, {0xbee2a000}, {0xbee2c000}, {0xbee2e000}, 
+    {0xbee30000}, {0xbee32000}, {0xbee34000}, {0xbee36000}, 
+    {0xbee38000}, {0xbee3a000}, {0xbee3c000}, {0xbee3e000}, 
+    {0xbee40000}, {0xbee42000}, {0xbee44000}, {0xbee46000}, 
+    {0xbee48000}, {0xbee4a000}, {0xbee4c000}, {0xbee4e000}, 
+    {0xbee50000}, {0xbee52000}, {0xbee54000}, {0xbee56000}, 
+    {0xbee58000}, {0xbee5a000}, {0xbee5c000}, {0xbee5e000}, 
+    {0xbee60000}, {0xbee62000}, {0xbee64000}, {0xbee66000}, 
+    {0xbee68000}, {0xbee6a000}, {0xbee6c000}, {0xbee6e000}, 
+    {0xbee70000}, {0xbee72000}, {0xbee74000}, {0xbee76000}, 
+    {0xbee78000}, {0xbee7a000}, {0xbee7c000}, {0xbee7e000}, 
+    {0xbee80000}, {0xbee82000}, {0xbee84000}, {0xbee86000}, 
+    {0xbee88000}, {0xbee8a000}, {0xbee8c000}, {0xbee8e000}, 
+    {0xbee90000}, {0xbee92000}, {0xbee94000}, {0xbee96000}, 
+    {0xbee98000}, {0xbee9a000}, {0xbee9c000}, {0xbee9e000}, 
+    {0xbeea0000}, {0xbeea2000}, {0xbeea4000}, {0xbeea6000}, 
+    {0xbeea8000}, {0xbeeaa000}, {0xbeeac000}, {0xbeeae000}, 
+    {0xbeeb0000}, {0xbeeb2000}, {0xbeeb4000}, {0xbeeb6000}, 
+    {0xbeeb8000}, {0xbeeba000}, {0xbeebc000}, {0xbeebe000}, 
+    {0xbeec0000}, {0xbeec2000}, {0xbeec4000}, {0xbeec6000}, 
+    {0xbeec8000}, {0xbeeca000}, {0xbeecc000}, {0xbeece000}, 
+    {0xbeed0000}, {0xbeed2000}, {0xbeed4000}, {0xbeed6000}, 
+    {0xbeed8000}, {0xbeeda000}, {0xbeedc000}, {0xbeede000}, 
+    {0xbeee0000}, {0xbeee2000}, {0xbeee4000}, {0xbeee6000}, 
+    {0xbeee8000}, {0xbeeea000}, {0xbeeec000}, {0xbeeee000}, 
+    {0xbeef0000}, {0xbeef2000}, {0xbeef4000}, {0xbeef6000}, 
+    {0xbeef8000}, {0xbeefa000}, {0xbeefc000}, {0xbeefe000}, 
+    {0xbef00000}, {0xbef02000}, {0xbef04000}, {0xbef06000}, 
+    {0xbef08000}, {0xbef0a000}, {0xbef0c000}, {0xbef0e000}, 
+    {0xbef10000}, {0xbef12000}, {0xbef14000}, {0xbef16000}, 
+    {0xbef18000}, {0xbef1a000}, {0xbef1c000}, {0xbef1e000}, 
+    {0xbef20000}, {0xbef22000}, {0xbef24000}, {0xbef26000}, 
+    {0xbef28000}, {0xbef2a000}, {0xbef2c000}, {0xbef2e000}, 
+    {0xbef30000}, {0xbef32000}, {0xbef34000}, {0xbef36000}, 
+    {0xbef38000}, {0xbef3a000}, {0xbef3c000}, {0xbef3e000}, 
+    {0xbef40000}, {0xbef42000}, {0xbef44000}, {0xbef46000}, 
+    {0xbef48000}, {0xbef4a000}, {0xbef4c000}, {0xbef4e000}, 
+    {0xbef50000}, {0xbef52000}, {0xbef54000}, {0xbef56000}, 
+    {0xbef58000}, {0xbef5a000}, {0xbef5c000}, {0xbef5e000}, 
+    {0xbef60000}, {0xbef62000}, {0xbef64000}, {0xbef66000}, 
+    {0xbef68000}, {0xbef6a000}, {0xbef6c000}, {0xbef6e000}, 
+    {0xbef70000}, {0xbef72000}, {0xbef74000}, {0xbef76000}, 
+    {0xbef78000}, {0xbef7a000}, {0xbef7c000}, {0xbef7e000}, 
+    {0xbef80000}, {0xbef82000}, {0xbef84000}, {0xbef86000}, 
+    {0xbef88000}, {0xbef8a000}, {0xbef8c000}, {0xbef8e000}, 
+    {0xbef90000}, {0xbef92000}, {0xbef94000}, {0xbef96000}, 
+    {0xbef98000}, {0xbef9a000}, {0xbef9c000}, {0xbef9e000}, 
+    {0xbefa0000}, {0xbefa2000}, {0xbefa4000}, {0xbefa6000}, 
+    {0xbefa8000}, {0xbefaa000}, {0xbefac000}, {0xbefae000}, 
+    {0xbefb0000}, {0xbefb2000}, {0xbefb4000}, {0xbefb6000}, 
+    {0xbefb8000}, {0xbefba000}, {0xbefbc000}, {0xbefbe000}, 
+    {0xbefc0000}, {0xbefc2000}, {0xbefc4000}, {0xbefc6000}, 
+    {0xbefc8000}, {0xbefca000}, {0xbefcc000}, {0xbefce000}, 
+    {0xbefd0000}, {0xbefd2000}, {0xbefd4000}, {0xbefd6000}, 
+    {0xbefd8000}, {0xbefda000}, {0xbefdc000}, {0xbefde000}, 
+    {0xbefe0000}, {0xbefe2000}, {0xbefe4000}, {0xbefe6000}, 
+    {0xbefe8000}, {0xbefea000}, {0xbefec000}, {0xbefee000}, 
+    {0xbeff0000}, {0xbeff2000}, {0xbeff4000}, {0xbeff6000}, 
+    {0xbeff8000}, {0xbeffa000}, {0xbeffc000}, {0xbeffe000}, 
+    {0xbf000000}, {0xbf002000}, {0xbf004000}, {0xbf006000}, 
+    {0xbf008000}, {0xbf00a000}, {0xbf00c000}, {0xbf00e000}, 
+    {0xbf010000}, {0xbf012000}, {0xbf014000}, {0xbf016000}, 
+    {0xbf018000}, {0xbf01a000}, {0xbf01c000}, {0xbf01e000}, 
+    {0xbf020000}, {0xbf022000}, {0xbf024000}, {0xbf026000}, 
+    {0xbf028000}, {0xbf02a000}, {0xbf02c000}, {0xbf02e000}, 
+    {0xbf030000}, {0xbf032000}, {0xbf034000}, {0xbf036000}, 
+    {0xbf038000}, {0xbf03a000}, {0xbf03c000}, {0xbf03e000}, 
+    {0xbf040000}, {0xbf042000}, {0xbf044000}, {0xbf046000}, 
+    {0xbf048000}, {0xbf04a000}, {0xbf04c000}, {0xbf04e000}, 
+    {0xbf050000}, {0xbf052000}, {0xbf054000}, {0xbf056000}, 
+    {0xbf058000}, {0xbf05a000}, {0xbf05c000}, {0xbf05e000}, 
+    {0xbf060000}, {0xbf062000}, {0xbf064000}, {0xbf066000}, 
+    {0xbf068000}, {0xbf06a000}, {0xbf06c000}, {0xbf06e000}, 
+    {0xbf070000}, {0xbf072000}, {0xbf074000}, {0xbf076000}, 
+    {0xbf078000}, {0xbf07a000}, {0xbf07c000}, {0xbf07e000}, 
+    {0xbf080000}, {0xbf082000}, {0xbf084000}, {0xbf086000}, 
+    {0xbf088000}, {0xbf08a000}, {0xbf08c000}, {0xbf08e000}, 
+    {0xbf090000}, {0xbf092000}, {0xbf094000}, {0xbf096000}, 
+    {0xbf098000}, {0xbf09a000}, {0xbf09c000}, {0xbf09e000}, 
+    {0xbf0a0000}, {0xbf0a2000}, {0xbf0a4000}, {0xbf0a6000}, 
+    {0xbf0a8000}, {0xbf0aa000}, {0xbf0ac000}, {0xbf0ae000}, 
+    {0xbf0b0000}, {0xbf0b2000}, {0xbf0b4000}, {0xbf0b6000}, 
+    {0xbf0b8000}, {0xbf0ba000}, {0xbf0bc000}, {0xbf0be000}, 
+    {0xbf0c0000}, {0xbf0c2000}, {0xbf0c4000}, {0xbf0c6000}, 
+    {0xbf0c8000}, {0xbf0ca000}, {0xbf0cc000}, {0xbf0ce000}, 
+    {0xbf0d0000}, {0xbf0d2000}, {0xbf0d4000}, {0xbf0d6000}, 
+    {0xbf0d8000}, {0xbf0da000}, {0xbf0dc000}, {0xbf0de000}, 
+    {0xbf0e0000}, {0xbf0e2000}, {0xbf0e4000}, {0xbf0e6000}, 
+    {0xbf0e8000}, {0xbf0ea000}, {0xbf0ec000}, {0xbf0ee000}, 
+    {0xbf0f0000}, {0xbf0f2000}, {0xbf0f4000}, {0xbf0f6000}, 
+    {0xbf0f8000}, {0xbf0fa000}, {0xbf0fc000}, {0xbf0fe000}, 
+    {0xbf100000}, {0xbf102000}, {0xbf104000}, {0xbf106000}, 
+    {0xbf108000}, {0xbf10a000}, {0xbf10c000}, {0xbf10e000}, 
+    {0xbf110000}, {0xbf112000}, {0xbf114000}, {0xbf116000}, 
+    {0xbf118000}, {0xbf11a000}, {0xbf11c000}, {0xbf11e000}, 
+    {0xbf120000}, {0xbf122000}, {0xbf124000}, {0xbf126000}, 
+    {0xbf128000}, {0xbf12a000}, {0xbf12c000}, {0xbf12e000}, 
+    {0xbf130000}, {0xbf132000}, {0xbf134000}, {0xbf136000}, 
+    {0xbf138000}, {0xbf13a000}, {0xbf13c000}, {0xbf13e000}, 
+    {0xbf140000}, {0xbf142000}, {0xbf144000}, {0xbf146000}, 
+    {0xbf148000}, {0xbf14a000}, {0xbf14c000}, {0xbf14e000}, 
+    {0xbf150000}, {0xbf152000}, {0xbf154000}, {0xbf156000}, 
+    {0xbf158000}, {0xbf15a000}, {0xbf15c000}, {0xbf15e000}, 
+    {0xbf160000}, {0xbf162000}, {0xbf164000}, {0xbf166000}, 
+    {0xbf168000}, {0xbf16a000}, {0xbf16c000}, {0xbf16e000}, 
+    {0xbf170000}, {0xbf172000}, {0xbf174000}, {0xbf176000}, 
+    {0xbf178000}, {0xbf17a000}, {0xbf17c000}, {0xbf17e000}, 
+    {0xbf180000}, {0xbf182000}, {0xbf184000}, {0xbf186000}, 
+    {0xbf188000}, {0xbf18a000}, {0xbf18c000}, {0xbf18e000}, 
+    {0xbf190000}, {0xbf192000}, {0xbf194000}, {0xbf196000}, 
+    {0xbf198000}, {0xbf19a000}, {0xbf19c000}, {0xbf19e000}, 
+    {0xbf1a0000}, {0xbf1a2000}, {0xbf1a4000}, {0xbf1a6000}, 
+    {0xbf1a8000}, {0xbf1aa000}, {0xbf1ac000}, {0xbf1ae000}, 
+    {0xbf1b0000}, {0xbf1b2000}, {0xbf1b4000}, {0xbf1b6000}, 
+    {0xbf1b8000}, {0xbf1ba000}, {0xbf1bc000}, {0xbf1be000}, 
+    {0xbf1c0000}, {0xbf1c2000}, {0xbf1c4000}, {0xbf1c6000}, 
+    {0xbf1c8000}, {0xbf1ca000}, {0xbf1cc000}, {0xbf1ce000}, 
+    {0xbf1d0000}, {0xbf1d2000}, {0xbf1d4000}, {0xbf1d6000}, 
+    {0xbf1d8000}, {0xbf1da000}, {0xbf1dc000}, {0xbf1de000}, 
+    {0xbf1e0000}, {0xbf1e2000}, {0xbf1e4000}, {0xbf1e6000}, 
+    {0xbf1e8000}, {0xbf1ea000}, {0xbf1ec000}, {0xbf1ee000}, 
+    {0xbf1f0000}, {0xbf1f2000}, {0xbf1f4000}, {0xbf1f6000}, 
+    {0xbf1f8000}, {0xbf1fa000}, {0xbf1fc000}, {0xbf1fe000}, 
+    {0xbf200000}, {0xbf202000}, {0xbf204000}, {0xbf206000}, 
+    {0xbf208000}, {0xbf20a000}, {0xbf20c000}, {0xbf20e000}, 
+    {0xbf210000}, {0xbf212000}, {0xbf214000}, {0xbf216000}, 
+    {0xbf218000}, {0xbf21a000}, {0xbf21c000}, {0xbf21e000}, 
+    {0xbf220000}, {0xbf222000}, {0xbf224000}, {0xbf226000}, 
+    {0xbf228000}, {0xbf22a000}, {0xbf22c000}, {0xbf22e000}, 
+    {0xbf230000}, {0xbf232000}, {0xbf234000}, {0xbf236000}, 
+    {0xbf238000}, {0xbf23a000}, {0xbf23c000}, {0xbf23e000}, 
+    {0xbf240000}, {0xbf242000}, {0xbf244000}, {0xbf246000}, 
+    {0xbf248000}, {0xbf24a000}, {0xbf24c000}, {0xbf24e000}, 
+    {0xbf250000}, {0xbf252000}, {0xbf254000}, {0xbf256000}, 
+    {0xbf258000}, {0xbf25a000}, {0xbf25c000}, {0xbf25e000}, 
+    {0xbf260000}, {0xbf262000}, {0xbf264000}, {0xbf266000}, 
+    {0xbf268000}, {0xbf26a000}, {0xbf26c000}, {0xbf26e000}, 
+    {0xbf270000}, {0xbf272000}, {0xbf274000}, {0xbf276000}, 
+    {0xbf278000}, {0xbf27a000}, {0xbf27c000}, {0xbf27e000}, 
+    {0xbf280000}, {0xbf282000}, {0xbf284000}, {0xbf286000}, 
+    {0xbf288000}, {0xbf28a000}, {0xbf28c000}, {0xbf28e000}, 
+    {0xbf290000}, {0xbf292000}, {0xbf294000}, {0xbf296000}, 
+    {0xbf298000}, {0xbf29a000}, {0xbf29c000}, {0xbf29e000}, 
+    {0xbf2a0000}, {0xbf2a2000}, {0xbf2a4000}, {0xbf2a6000}, 
+    {0xbf2a8000}, {0xbf2aa000}, {0xbf2ac000}, {0xbf2ae000}, 
+    {0xbf2b0000}, {0xbf2b2000}, {0xbf2b4000}, {0xbf2b6000}, 
+    {0xbf2b8000}, {0xbf2ba000}, {0xbf2bc000}, {0xbf2be000}, 
+    {0xbf2c0000}, {0xbf2c2000}, {0xbf2c4000}, {0xbf2c6000}, 
+    {0xbf2c8000}, {0xbf2ca000}, {0xbf2cc000}, {0xbf2ce000}, 
+    {0xbf2d0000}, {0xbf2d2000}, {0xbf2d4000}, {0xbf2d6000}, 
+    {0xbf2d8000}, {0xbf2da000}, {0xbf2dc000}, {0xbf2de000}, 
+    {0xbf2e0000}, {0xbf2e2000}, {0xbf2e4000}, {0xbf2e6000}, 
+    {0xbf2e8000}, {0xbf2ea000}, {0xbf2ec000}, {0xbf2ee000}, 
+    {0xbf2f0000}, {0xbf2f2000}, {0xbf2f4000}, {0xbf2f6000}, 
+    {0xbf2f8000}, {0xbf2fa000}, {0xbf2fc000}, {0xbf2fe000}, 
+    {0xbf300000}, {0xbf302000}, {0xbf304000}, {0xbf306000}, 
+    {0xbf308000}, {0xbf30a000}, {0xbf30c000}, {0xbf30e000}, 
+    {0xbf310000}, {0xbf312000}, {0xbf314000}, {0xbf316000}, 
+    {0xbf318000}, {0xbf31a000}, {0xbf31c000}, {0xbf31e000}, 
+    {0xbf320000}, {0xbf322000}, {0xbf324000}, {0xbf326000}, 
+    {0xbf328000}, {0xbf32a000}, {0xbf32c000}, {0xbf32e000}, 
+    {0xbf330000}, {0xbf332000}, {0xbf334000}, {0xbf336000}, 
+    {0xbf338000}, {0xbf33a000}, {0xbf33c000}, {0xbf33e000}, 
+    {0xbf340000}, {0xbf342000}, {0xbf344000}, {0xbf346000}, 
+    {0xbf348000}, {0xbf34a000}, {0xbf34c000}, {0xbf34e000}, 
+    {0xbf350000}, {0xbf352000}, {0xbf354000}, {0xbf356000}, 
+    {0xbf358000}, {0xbf35a000}, {0xbf35c000}, {0xbf35e000}, 
+    {0xbf360000}, {0xbf362000}, {0xbf364000}, {0xbf366000}, 
+    {0xbf368000}, {0xbf36a000}, {0xbf36c000}, {0xbf36e000}, 
+    {0xbf370000}, {0xbf372000}, {0xbf374000}, {0xbf376000}, 
+    {0xbf378000}, {0xbf37a000}, {0xbf37c000}, {0xbf37e000}, 
+    {0xbf380000}, {0xbf382000}, {0xbf384000}, {0xbf386000}, 
+    {0xbf388000}, {0xbf38a000}, {0xbf38c000}, {0xbf38e000}, 
+    {0xbf390000}, {0xbf392000}, {0xbf394000}, {0xbf396000}, 
+    {0xbf398000}, {0xbf39a000}, {0xbf39c000}, {0xbf39e000}, 
+    {0xbf3a0000}, {0xbf3a2000}, {0xbf3a4000}, {0xbf3a6000}, 
+    {0xbf3a8000}, {0xbf3aa000}, {0xbf3ac000}, {0xbf3ae000}, 
+    {0xbf3b0000}, {0xbf3b2000}, {0xbf3b4000}, {0xbf3b6000}, 
+    {0xbf3b8000}, {0xbf3ba000}, {0xbf3bc000}, {0xbf3be000}, 
+    {0xbf3c0000}, {0xbf3c2000}, {0xbf3c4000}, {0xbf3c6000}, 
+    {0xbf3c8000}, {0xbf3ca000}, {0xbf3cc000}, {0xbf3ce000}, 
+    {0xbf3d0000}, {0xbf3d2000}, {0xbf3d4000}, {0xbf3d6000}, 
+    {0xbf3d8000}, {0xbf3da000}, {0xbf3dc000}, {0xbf3de000}, 
+    {0xbf3e0000}, {0xbf3e2000}, {0xbf3e4000}, {0xbf3e6000}, 
+    {0xbf3e8000}, {0xbf3ea000}, {0xbf3ec000}, {0xbf3ee000}, 
+    {0xbf3f0000}, {0xbf3f2000}, {0xbf3f4000}, {0xbf3f6000}, 
+    {0xbf3f8000}, {0xbf3fa000}, {0xbf3fc000}, {0xbf3fe000}, 
+    {0xbf400000}, {0xbf402000}, {0xbf404000}, {0xbf406000}, 
+    {0xbf408000}, {0xbf40a000}, {0xbf40c000}, {0xbf40e000}, 
+    {0xbf410000}, {0xbf412000}, {0xbf414000}, {0xbf416000}, 
+    {0xbf418000}, {0xbf41a000}, {0xbf41c000}, {0xbf41e000}, 
+    {0xbf420000}, {0xbf422000}, {0xbf424000}, {0xbf426000}, 
+    {0xbf428000}, {0xbf42a000}, {0xbf42c000}, {0xbf42e000}, 
+    {0xbf430000}, {0xbf432000}, {0xbf434000}, {0xbf436000}, 
+    {0xbf438000}, {0xbf43a000}, {0xbf43c000}, {0xbf43e000}, 
+    {0xbf440000}, {0xbf442000}, {0xbf444000}, {0xbf446000}, 
+    {0xbf448000}, {0xbf44a000}, {0xbf44c000}, {0xbf44e000}, 
+    {0xbf450000}, {0xbf452000}, {0xbf454000}, {0xbf456000}, 
+    {0xbf458000}, {0xbf45a000}, {0xbf45c000}, {0xbf45e000}, 
+    {0xbf460000}, {0xbf462000}, {0xbf464000}, {0xbf466000}, 
+    {0xbf468000}, {0xbf46a000}, {0xbf46c000}, {0xbf46e000}, 
+    {0xbf470000}, {0xbf472000}, {0xbf474000}, {0xbf476000}, 
+    {0xbf478000}, {0xbf47a000}, {0xbf47c000}, {0xbf47e000}, 
+    {0xbf480000}, {0xbf482000}, {0xbf484000}, {0xbf486000}, 
+    {0xbf488000}, {0xbf48a000}, {0xbf48c000}, {0xbf48e000}, 
+    {0xbf490000}, {0xbf492000}, {0xbf494000}, {0xbf496000}, 
+    {0xbf498000}, {0xbf49a000}, {0xbf49c000}, {0xbf49e000}, 
+    {0xbf4a0000}, {0xbf4a2000}, {0xbf4a4000}, {0xbf4a6000}, 
+    {0xbf4a8000}, {0xbf4aa000}, {0xbf4ac000}, {0xbf4ae000}, 
+    {0xbf4b0000}, {0xbf4b2000}, {0xbf4b4000}, {0xbf4b6000}, 
+    {0xbf4b8000}, {0xbf4ba000}, {0xbf4bc000}, {0xbf4be000}, 
+    {0xbf4c0000}, {0xbf4c2000}, {0xbf4c4000}, {0xbf4c6000}, 
+    {0xbf4c8000}, {0xbf4ca000}, {0xbf4cc000}, {0xbf4ce000}, 
+    {0xbf4d0000}, {0xbf4d2000}, {0xbf4d4000}, {0xbf4d6000}, 
+    {0xbf4d8000}, {0xbf4da000}, {0xbf4dc000}, {0xbf4de000}, 
+    {0xbf4e0000}, {0xbf4e2000}, {0xbf4e4000}, {0xbf4e6000}, 
+    {0xbf4e8000}, {0xbf4ea000}, {0xbf4ec000}, {0xbf4ee000}, 
+    {0xbf4f0000}, {0xbf4f2000}, {0xbf4f4000}, {0xbf4f6000}, 
+    {0xbf4f8000}, {0xbf4fa000}, {0xbf4fc000}, {0xbf4fe000}, 
+    {0xbf500000}, {0xbf502000}, {0xbf504000}, {0xbf506000}, 
+    {0xbf508000}, {0xbf50a000}, {0xbf50c000}, {0xbf50e000}, 
+    {0xbf510000}, {0xbf512000}, {0xbf514000}, {0xbf516000}, 
+    {0xbf518000}, {0xbf51a000}, {0xbf51c000}, {0xbf51e000}, 
+    {0xbf520000}, {0xbf522000}, {0xbf524000}, {0xbf526000}, 
+    {0xbf528000}, {0xbf52a000}, {0xbf52c000}, {0xbf52e000}, 
+    {0xbf530000}, {0xbf532000}, {0xbf534000}, {0xbf536000}, 
+    {0xbf538000}, {0xbf53a000}, {0xbf53c000}, {0xbf53e000}, 
+    {0xbf540000}, {0xbf542000}, {0xbf544000}, {0xbf546000}, 
+    {0xbf548000}, {0xbf54a000}, {0xbf54c000}, {0xbf54e000}, 
+    {0xbf550000}, {0xbf552000}, {0xbf554000}, {0xbf556000}, 
+    {0xbf558000}, {0xbf55a000}, {0xbf55c000}, {0xbf55e000}, 
+    {0xbf560000}, {0xbf562000}, {0xbf564000}, {0xbf566000}, 
+    {0xbf568000}, {0xbf56a000}, {0xbf56c000}, {0xbf56e000}, 
+    {0xbf570000}, {0xbf572000}, {0xbf574000}, {0xbf576000}, 
+    {0xbf578000}, {0xbf57a000}, {0xbf57c000}, {0xbf57e000}, 
+    {0xbf580000}, {0xbf582000}, {0xbf584000}, {0xbf586000}, 
+    {0xbf588000}, {0xbf58a000}, {0xbf58c000}, {0xbf58e000}, 
+    {0xbf590000}, {0xbf592000}, {0xbf594000}, {0xbf596000}, 
+    {0xbf598000}, {0xbf59a000}, {0xbf59c000}, {0xbf59e000}, 
+    {0xbf5a0000}, {0xbf5a2000}, {0xbf5a4000}, {0xbf5a6000}, 
+    {0xbf5a8000}, {0xbf5aa000}, {0xbf5ac000}, {0xbf5ae000}, 
+    {0xbf5b0000}, {0xbf5b2000}, {0xbf5b4000}, {0xbf5b6000}, 
+    {0xbf5b8000}, {0xbf5ba000}, {0xbf5bc000}, {0xbf5be000}, 
+    {0xbf5c0000}, {0xbf5c2000}, {0xbf5c4000}, {0xbf5c6000}, 
+    {0xbf5c8000}, {0xbf5ca000}, {0xbf5cc000}, {0xbf5ce000}, 
+    {0xbf5d0000}, {0xbf5d2000}, {0xbf5d4000}, {0xbf5d6000}, 
+    {0xbf5d8000}, {0xbf5da000}, {0xbf5dc000}, {0xbf5de000}, 
+    {0xbf5e0000}, {0xbf5e2000}, {0xbf5e4000}, {0xbf5e6000}, 
+    {0xbf5e8000}, {0xbf5ea000}, {0xbf5ec000}, {0xbf5ee000}, 
+    {0xbf5f0000}, {0xbf5f2000}, {0xbf5f4000}, {0xbf5f6000}, 
+    {0xbf5f8000}, {0xbf5fa000}, {0xbf5fc000}, {0xbf5fe000}, 
+    {0xbf600000}, {0xbf602000}, {0xbf604000}, {0xbf606000}, 
+    {0xbf608000}, {0xbf60a000}, {0xbf60c000}, {0xbf60e000}, 
+    {0xbf610000}, {0xbf612000}, {0xbf614000}, {0xbf616000}, 
+    {0xbf618000}, {0xbf61a000}, {0xbf61c000}, {0xbf61e000}, 
+    {0xbf620000}, {0xbf622000}, {0xbf624000}, {0xbf626000}, 
+    {0xbf628000}, {0xbf62a000}, {0xbf62c000}, {0xbf62e000}, 
+    {0xbf630000}, {0xbf632000}, {0xbf634000}, {0xbf636000}, 
+    {0xbf638000}, {0xbf63a000}, {0xbf63c000}, {0xbf63e000}, 
+    {0xbf640000}, {0xbf642000}, {0xbf644000}, {0xbf646000}, 
+    {0xbf648000}, {0xbf64a000}, {0xbf64c000}, {0xbf64e000}, 
+    {0xbf650000}, {0xbf652000}, {0xbf654000}, {0xbf656000}, 
+    {0xbf658000}, {0xbf65a000}, {0xbf65c000}, {0xbf65e000}, 
+    {0xbf660000}, {0xbf662000}, {0xbf664000}, {0xbf666000}, 
+    {0xbf668000}, {0xbf66a000}, {0xbf66c000}, {0xbf66e000}, 
+    {0xbf670000}, {0xbf672000}, {0xbf674000}, {0xbf676000}, 
+    {0xbf678000}, {0xbf67a000}, {0xbf67c000}, {0xbf67e000}, 
+    {0xbf680000}, {0xbf682000}, {0xbf684000}, {0xbf686000}, 
+    {0xbf688000}, {0xbf68a000}, {0xbf68c000}, {0xbf68e000}, 
+    {0xbf690000}, {0xbf692000}, {0xbf694000}, {0xbf696000}, 
+    {0xbf698000}, {0xbf69a000}, {0xbf69c000}, {0xbf69e000}, 
+    {0xbf6a0000}, {0xbf6a2000}, {0xbf6a4000}, {0xbf6a6000}, 
+    {0xbf6a8000}, {0xbf6aa000}, {0xbf6ac000}, {0xbf6ae000}, 
+    {0xbf6b0000}, {0xbf6b2000}, {0xbf6b4000}, {0xbf6b6000}, 
+    {0xbf6b8000}, {0xbf6ba000}, {0xbf6bc000}, {0xbf6be000}, 
+    {0xbf6c0000}, {0xbf6c2000}, {0xbf6c4000}, {0xbf6c6000}, 
+    {0xbf6c8000}, {0xbf6ca000}, {0xbf6cc000}, {0xbf6ce000}, 
+    {0xbf6d0000}, {0xbf6d2000}, {0xbf6d4000}, {0xbf6d6000}, 
+    {0xbf6d8000}, {0xbf6da000}, {0xbf6dc000}, {0xbf6de000}, 
+    {0xbf6e0000}, {0xbf6e2000}, {0xbf6e4000}, {0xbf6e6000}, 
+    {0xbf6e8000}, {0xbf6ea000}, {0xbf6ec000}, {0xbf6ee000}, 
+    {0xbf6f0000}, {0xbf6f2000}, {0xbf6f4000}, {0xbf6f6000}, 
+    {0xbf6f8000}, {0xbf6fa000}, {0xbf6fc000}, {0xbf6fe000}, 
+    {0xbf700000}, {0xbf702000}, {0xbf704000}, {0xbf706000}, 
+    {0xbf708000}, {0xbf70a000}, {0xbf70c000}, {0xbf70e000}, 
+    {0xbf710000}, {0xbf712000}, {0xbf714000}, {0xbf716000}, 
+    {0xbf718000}, {0xbf71a000}, {0xbf71c000}, {0xbf71e000}, 
+    {0xbf720000}, {0xbf722000}, {0xbf724000}, {0xbf726000}, 
+    {0xbf728000}, {0xbf72a000}, {0xbf72c000}, {0xbf72e000}, 
+    {0xbf730000}, {0xbf732000}, {0xbf734000}, {0xbf736000}, 
+    {0xbf738000}, {0xbf73a000}, {0xbf73c000}, {0xbf73e000}, 
+    {0xbf740000}, {0xbf742000}, {0xbf744000}, {0xbf746000}, 
+    {0xbf748000}, {0xbf74a000}, {0xbf74c000}, {0xbf74e000}, 
+    {0xbf750000}, {0xbf752000}, {0xbf754000}, {0xbf756000}, 
+    {0xbf758000}, {0xbf75a000}, {0xbf75c000}, {0xbf75e000}, 
+    {0xbf760000}, {0xbf762000}, {0xbf764000}, {0xbf766000}, 
+    {0xbf768000}, {0xbf76a000}, {0xbf76c000}, {0xbf76e000}, 
+    {0xbf770000}, {0xbf772000}, {0xbf774000}, {0xbf776000}, 
+    {0xbf778000}, {0xbf77a000}, {0xbf77c000}, {0xbf77e000}, 
+    {0xbf780000}, {0xbf782000}, {0xbf784000}, {0xbf786000}, 
+    {0xbf788000}, {0xbf78a000}, {0xbf78c000}, {0xbf78e000}, 
+    {0xbf790000}, {0xbf792000}, {0xbf794000}, {0xbf796000}, 
+    {0xbf798000}, {0xbf79a000}, {0xbf79c000}, {0xbf79e000}, 
+    {0xbf7a0000}, {0xbf7a2000}, {0xbf7a4000}, {0xbf7a6000}, 
+    {0xbf7a8000}, {0xbf7aa000}, {0xbf7ac000}, {0xbf7ae000}, 
+    {0xbf7b0000}, {0xbf7b2000}, {0xbf7b4000}, {0xbf7b6000}, 
+    {0xbf7b8000}, {0xbf7ba000}, {0xbf7bc000}, {0xbf7be000}, 
+    {0xbf7c0000}, {0xbf7c2000}, {0xbf7c4000}, {0xbf7c6000}, 
+    {0xbf7c8000}, {0xbf7ca000}, {0xbf7cc000}, {0xbf7ce000}, 
+    {0xbf7d0000}, {0xbf7d2000}, {0xbf7d4000}, {0xbf7d6000}, 
+    {0xbf7d8000}, {0xbf7da000}, {0xbf7dc000}, {0xbf7de000}, 
+    {0xbf7e0000}, {0xbf7e2000}, {0xbf7e4000}, {0xbf7e6000}, 
+    {0xbf7e8000}, {0xbf7ea000}, {0xbf7ec000}, {0xbf7ee000}, 
+    {0xbf7f0000}, {0xbf7f2000}, {0xbf7f4000}, {0xbf7f6000}, 
+    {0xbf7f8000}, {0xbf7fa000}, {0xbf7fc000}, {0xbf7fe000}, 
+    {0xbf800000}, {0xbf802000}, {0xbf804000}, {0xbf806000}, 
+    {0xbf808000}, {0xbf80a000}, {0xbf80c000}, {0xbf80e000}, 
+    {0xbf810000}, {0xbf812000}, {0xbf814000}, {0xbf816000}, 
+    {0xbf818000}, {0xbf81a000}, {0xbf81c000}, {0xbf81e000}, 
+    {0xbf820000}, {0xbf822000}, {0xbf824000}, {0xbf826000}, 
+    {0xbf828000}, {0xbf82a000}, {0xbf82c000}, {0xbf82e000}, 
+    {0xbf830000}, {0xbf832000}, {0xbf834000}, {0xbf836000}, 
+    {0xbf838000}, {0xbf83a000}, {0xbf83c000}, {0xbf83e000}, 
+    {0xbf840000}, {0xbf842000}, {0xbf844000}, {0xbf846000}, 
+    {0xbf848000}, {0xbf84a000}, {0xbf84c000}, {0xbf84e000}, 
+    {0xbf850000}, {0xbf852000}, {0xbf854000}, {0xbf856000}, 
+    {0xbf858000}, {0xbf85a000}, {0xbf85c000}, {0xbf85e000}, 
+    {0xbf860000}, {0xbf862000}, {0xbf864000}, {0xbf866000}, 
+    {0xbf868000}, {0xbf86a000}, {0xbf86c000}, {0xbf86e000}, 
+    {0xbf870000}, {0xbf872000}, {0xbf874000}, {0xbf876000}, 
+    {0xbf878000}, {0xbf87a000}, {0xbf87c000}, {0xbf87e000}, 
+    {0xbf880000}, {0xbf882000}, {0xbf884000}, {0xbf886000}, 
+    {0xbf888000}, {0xbf88a000}, {0xbf88c000}, {0xbf88e000}, 
+    {0xbf890000}, {0xbf892000}, {0xbf894000}, {0xbf896000}, 
+    {0xbf898000}, {0xbf89a000}, {0xbf89c000}, {0xbf89e000}, 
+    {0xbf8a0000}, {0xbf8a2000}, {0xbf8a4000}, {0xbf8a6000}, 
+    {0xbf8a8000}, {0xbf8aa000}, {0xbf8ac000}, {0xbf8ae000}, 
+    {0xbf8b0000}, {0xbf8b2000}, {0xbf8b4000}, {0xbf8b6000}, 
+    {0xbf8b8000}, {0xbf8ba000}, {0xbf8bc000}, {0xbf8be000}, 
+    {0xbf8c0000}, {0xbf8c2000}, {0xbf8c4000}, {0xbf8c6000}, 
+    {0xbf8c8000}, {0xbf8ca000}, {0xbf8cc000}, {0xbf8ce000}, 
+    {0xbf8d0000}, {0xbf8d2000}, {0xbf8d4000}, {0xbf8d6000}, 
+    {0xbf8d8000}, {0xbf8da000}, {0xbf8dc000}, {0xbf8de000}, 
+    {0xbf8e0000}, {0xbf8e2000}, {0xbf8e4000}, {0xbf8e6000}, 
+    {0xbf8e8000}, {0xbf8ea000}, {0xbf8ec000}, {0xbf8ee000}, 
+    {0xbf8f0000}, {0xbf8f2000}, {0xbf8f4000}, {0xbf8f6000}, 
+    {0xbf8f8000}, {0xbf8fa000}, {0xbf8fc000}, {0xbf8fe000}, 
+    {0xbf900000}, {0xbf902000}, {0xbf904000}, {0xbf906000}, 
+    {0xbf908000}, {0xbf90a000}, {0xbf90c000}, {0xbf90e000}, 
+    {0xbf910000}, {0xbf912000}, {0xbf914000}, {0xbf916000}, 
+    {0xbf918000}, {0xbf91a000}, {0xbf91c000}, {0xbf91e000}, 
+    {0xbf920000}, {0xbf922000}, {0xbf924000}, {0xbf926000}, 
+    {0xbf928000}, {0xbf92a000}, {0xbf92c000}, {0xbf92e000}, 
+    {0xbf930000}, {0xbf932000}, {0xbf934000}, {0xbf936000}, 
+    {0xbf938000}, {0xbf93a000}, {0xbf93c000}, {0xbf93e000}, 
+    {0xbf940000}, {0xbf942000}, {0xbf944000}, {0xbf946000}, 
+    {0xbf948000}, {0xbf94a000}, {0xbf94c000}, {0xbf94e000}, 
+    {0xbf950000}, {0xbf952000}, {0xbf954000}, {0xbf956000}, 
+    {0xbf958000}, {0xbf95a000}, {0xbf95c000}, {0xbf95e000}, 
+    {0xbf960000}, {0xbf962000}, {0xbf964000}, {0xbf966000}, 
+    {0xbf968000}, {0xbf96a000}, {0xbf96c000}, {0xbf96e000}, 
+    {0xbf970000}, {0xbf972000}, {0xbf974000}, {0xbf976000}, 
+    {0xbf978000}, {0xbf97a000}, {0xbf97c000}, {0xbf97e000}, 
+    {0xbf980000}, {0xbf982000}, {0xbf984000}, {0xbf986000}, 
+    {0xbf988000}, {0xbf98a000}, {0xbf98c000}, {0xbf98e000}, 
+    {0xbf990000}, {0xbf992000}, {0xbf994000}, {0xbf996000}, 
+    {0xbf998000}, {0xbf99a000}, {0xbf99c000}, {0xbf99e000}, 
+    {0xbf9a0000}, {0xbf9a2000}, {0xbf9a4000}, {0xbf9a6000}, 
+    {0xbf9a8000}, {0xbf9aa000}, {0xbf9ac000}, {0xbf9ae000}, 
+    {0xbf9b0000}, {0xbf9b2000}, {0xbf9b4000}, {0xbf9b6000}, 
+    {0xbf9b8000}, {0xbf9ba000}, {0xbf9bc000}, {0xbf9be000}, 
+    {0xbf9c0000}, {0xbf9c2000}, {0xbf9c4000}, {0xbf9c6000}, 
+    {0xbf9c8000}, {0xbf9ca000}, {0xbf9cc000}, {0xbf9ce000}, 
+    {0xbf9d0000}, {0xbf9d2000}, {0xbf9d4000}, {0xbf9d6000}, 
+    {0xbf9d8000}, {0xbf9da000}, {0xbf9dc000}, {0xbf9de000}, 
+    {0xbf9e0000}, {0xbf9e2000}, {0xbf9e4000}, {0xbf9e6000}, 
+    {0xbf9e8000}, {0xbf9ea000}, {0xbf9ec000}, {0xbf9ee000}, 
+    {0xbf9f0000}, {0xbf9f2000}, {0xbf9f4000}, {0xbf9f6000}, 
+    {0xbf9f8000}, {0xbf9fa000}, {0xbf9fc000}, {0xbf9fe000}, 
+    {0xbfa00000}, {0xbfa02000}, {0xbfa04000}, {0xbfa06000}, 
+    {0xbfa08000}, {0xbfa0a000}, {0xbfa0c000}, {0xbfa0e000}, 
+    {0xbfa10000}, {0xbfa12000}, {0xbfa14000}, {0xbfa16000}, 
+    {0xbfa18000}, {0xbfa1a000}, {0xbfa1c000}, {0xbfa1e000}, 
+    {0xbfa20000}, {0xbfa22000}, {0xbfa24000}, {0xbfa26000}, 
+    {0xbfa28000}, {0xbfa2a000}, {0xbfa2c000}, {0xbfa2e000}, 
+    {0xbfa30000}, {0xbfa32000}, {0xbfa34000}, {0xbfa36000}, 
+    {0xbfa38000}, {0xbfa3a000}, {0xbfa3c000}, {0xbfa3e000}, 
+    {0xbfa40000}, {0xbfa42000}, {0xbfa44000}, {0xbfa46000}, 
+    {0xbfa48000}, {0xbfa4a000}, {0xbfa4c000}, {0xbfa4e000}, 
+    {0xbfa50000}, {0xbfa52000}, {0xbfa54000}, {0xbfa56000}, 
+    {0xbfa58000}, {0xbfa5a000}, {0xbfa5c000}, {0xbfa5e000}, 
+    {0xbfa60000}, {0xbfa62000}, {0xbfa64000}, {0xbfa66000}, 
+    {0xbfa68000}, {0xbfa6a000}, {0xbfa6c000}, {0xbfa6e000}, 
+    {0xbfa70000}, {0xbfa72000}, {0xbfa74000}, {0xbfa76000}, 
+    {0xbfa78000}, {0xbfa7a000}, {0xbfa7c000}, {0xbfa7e000}, 
+    {0xbfa80000}, {0xbfa82000}, {0xbfa84000}, {0xbfa86000}, 
+    {0xbfa88000}, {0xbfa8a000}, {0xbfa8c000}, {0xbfa8e000}, 
+    {0xbfa90000}, {0xbfa92000}, {0xbfa94000}, {0xbfa96000}, 
+    {0xbfa98000}, {0xbfa9a000}, {0xbfa9c000}, {0xbfa9e000}, 
+    {0xbfaa0000}, {0xbfaa2000}, {0xbfaa4000}, {0xbfaa6000}, 
+    {0xbfaa8000}, {0xbfaaa000}, {0xbfaac000}, {0xbfaae000}, 
+    {0xbfab0000}, {0xbfab2000}, {0xbfab4000}, {0xbfab6000}, 
+    {0xbfab8000}, {0xbfaba000}, {0xbfabc000}, {0xbfabe000}, 
+    {0xbfac0000}, {0xbfac2000}, {0xbfac4000}, {0xbfac6000}, 
+    {0xbfac8000}, {0xbfaca000}, {0xbfacc000}, {0xbface000}, 
+    {0xbfad0000}, {0xbfad2000}, {0xbfad4000}, {0xbfad6000}, 
+    {0xbfad8000}, {0xbfada000}, {0xbfadc000}, {0xbfade000}, 
+    {0xbfae0000}, {0xbfae2000}, {0xbfae4000}, {0xbfae6000}, 
+    {0xbfae8000}, {0xbfaea000}, {0xbfaec000}, {0xbfaee000}, 
+    {0xbfaf0000}, {0xbfaf2000}, {0xbfaf4000}, {0xbfaf6000}, 
+    {0xbfaf8000}, {0xbfafa000}, {0xbfafc000}, {0xbfafe000}, 
+    {0xbfb00000}, {0xbfb02000}, {0xbfb04000}, {0xbfb06000}, 
+    {0xbfb08000}, {0xbfb0a000}, {0xbfb0c000}, {0xbfb0e000}, 
+    {0xbfb10000}, {0xbfb12000}, {0xbfb14000}, {0xbfb16000}, 
+    {0xbfb18000}, {0xbfb1a000}, {0xbfb1c000}, {0xbfb1e000}, 
+    {0xbfb20000}, {0xbfb22000}, {0xbfb24000}, {0xbfb26000}, 
+    {0xbfb28000}, {0xbfb2a000}, {0xbfb2c000}, {0xbfb2e000}, 
+    {0xbfb30000}, {0xbfb32000}, {0xbfb34000}, {0xbfb36000}, 
+    {0xbfb38000}, {0xbfb3a000}, {0xbfb3c000}, {0xbfb3e000}, 
+    {0xbfb40000}, {0xbfb42000}, {0xbfb44000}, {0xbfb46000}, 
+    {0xbfb48000}, {0xbfb4a000}, {0xbfb4c000}, {0xbfb4e000}, 
+    {0xbfb50000}, {0xbfb52000}, {0xbfb54000}, {0xbfb56000}, 
+    {0xbfb58000}, {0xbfb5a000}, {0xbfb5c000}, {0xbfb5e000}, 
+    {0xbfb60000}, {0xbfb62000}, {0xbfb64000}, {0xbfb66000}, 
+    {0xbfb68000}, {0xbfb6a000}, {0xbfb6c000}, {0xbfb6e000}, 
+    {0xbfb70000}, {0xbfb72000}, {0xbfb74000}, {0xbfb76000}, 
+    {0xbfb78000}, {0xbfb7a000}, {0xbfb7c000}, {0xbfb7e000}, 
+    {0xbfb80000}, {0xbfb82000}, {0xbfb84000}, {0xbfb86000}, 
+    {0xbfb88000}, {0xbfb8a000}, {0xbfb8c000}, {0xbfb8e000}, 
+    {0xbfb90000}, {0xbfb92000}, {0xbfb94000}, {0xbfb96000}, 
+    {0xbfb98000}, {0xbfb9a000}, {0xbfb9c000}, {0xbfb9e000}, 
+    {0xbfba0000}, {0xbfba2000}, {0xbfba4000}, {0xbfba6000}, 
+    {0xbfba8000}, {0xbfbaa000}, {0xbfbac000}, {0xbfbae000}, 
+    {0xbfbb0000}, {0xbfbb2000}, {0xbfbb4000}, {0xbfbb6000}, 
+    {0xbfbb8000}, {0xbfbba000}, {0xbfbbc000}, {0xbfbbe000}, 
+    {0xbfbc0000}, {0xbfbc2000}, {0xbfbc4000}, {0xbfbc6000}, 
+    {0xbfbc8000}, {0xbfbca000}, {0xbfbcc000}, {0xbfbce000}, 
+    {0xbfbd0000}, {0xbfbd2000}, {0xbfbd4000}, {0xbfbd6000}, 
+    {0xbfbd8000}, {0xbfbda000}, {0xbfbdc000}, {0xbfbde000}, 
+    {0xbfbe0000}, {0xbfbe2000}, {0xbfbe4000}, {0xbfbe6000}, 
+    {0xbfbe8000}, {0xbfbea000}, {0xbfbec000}, {0xbfbee000}, 
+    {0xbfbf0000}, {0xbfbf2000}, {0xbfbf4000}, {0xbfbf6000}, 
+    {0xbfbf8000}, {0xbfbfa000}, {0xbfbfc000}, {0xbfbfe000}, 
+    {0xbfc00000}, {0xbfc02000}, {0xbfc04000}, {0xbfc06000}, 
+    {0xbfc08000}, {0xbfc0a000}, {0xbfc0c000}, {0xbfc0e000}, 
+    {0xbfc10000}, {0xbfc12000}, {0xbfc14000}, {0xbfc16000}, 
+    {0xbfc18000}, {0xbfc1a000}, {0xbfc1c000}, {0xbfc1e000}, 
+    {0xbfc20000}, {0xbfc22000}, {0xbfc24000}, {0xbfc26000}, 
+    {0xbfc28000}, {0xbfc2a000}, {0xbfc2c000}, {0xbfc2e000}, 
+    {0xbfc30000}, {0xbfc32000}, {0xbfc34000}, {0xbfc36000}, 
+    {0xbfc38000}, {0xbfc3a000}, {0xbfc3c000}, {0xbfc3e000}, 
+    {0xbfc40000}, {0xbfc42000}, {0xbfc44000}, {0xbfc46000}, 
+    {0xbfc48000}, {0xbfc4a000}, {0xbfc4c000}, {0xbfc4e000}, 
+    {0xbfc50000}, {0xbfc52000}, {0xbfc54000}, {0xbfc56000}, 
+    {0xbfc58000}, {0xbfc5a000}, {0xbfc5c000}, {0xbfc5e000}, 
+    {0xbfc60000}, {0xbfc62000}, {0xbfc64000}, {0xbfc66000}, 
+    {0xbfc68000}, {0xbfc6a000}, {0xbfc6c000}, {0xbfc6e000}, 
+    {0xbfc70000}, {0xbfc72000}, {0xbfc74000}, {0xbfc76000}, 
+    {0xbfc78000}, {0xbfc7a000}, {0xbfc7c000}, {0xbfc7e000}, 
+    {0xbfc80000}, {0xbfc82000}, {0xbfc84000}, {0xbfc86000}, 
+    {0xbfc88000}, {0xbfc8a000}, {0xbfc8c000}, {0xbfc8e000}, 
+    {0xbfc90000}, {0xbfc92000}, {0xbfc94000}, {0xbfc96000}, 
+    {0xbfc98000}, {0xbfc9a000}, {0xbfc9c000}, {0xbfc9e000}, 
+    {0xbfca0000}, {0xbfca2000}, {0xbfca4000}, {0xbfca6000}, 
+    {0xbfca8000}, {0xbfcaa000}, {0xbfcac000}, {0xbfcae000}, 
+    {0xbfcb0000}, {0xbfcb2000}, {0xbfcb4000}, {0xbfcb6000}, 
+    {0xbfcb8000}, {0xbfcba000}, {0xbfcbc000}, {0xbfcbe000}, 
+    {0xbfcc0000}, {0xbfcc2000}, {0xbfcc4000}, {0xbfcc6000}, 
+    {0xbfcc8000}, {0xbfcca000}, {0xbfccc000}, {0xbfcce000}, 
+    {0xbfcd0000}, {0xbfcd2000}, {0xbfcd4000}, {0xbfcd6000}, 
+    {0xbfcd8000}, {0xbfcda000}, {0xbfcdc000}, {0xbfcde000}, 
+    {0xbfce0000}, {0xbfce2000}, {0xbfce4000}, {0xbfce6000}, 
+    {0xbfce8000}, {0xbfcea000}, {0xbfcec000}, {0xbfcee000}, 
+    {0xbfcf0000}, {0xbfcf2000}, {0xbfcf4000}, {0xbfcf6000}, 
+    {0xbfcf8000}, {0xbfcfa000}, {0xbfcfc000}, {0xbfcfe000}, 
+    {0xbfd00000}, {0xbfd02000}, {0xbfd04000}, {0xbfd06000}, 
+    {0xbfd08000}, {0xbfd0a000}, {0xbfd0c000}, {0xbfd0e000}, 
+    {0xbfd10000}, {0xbfd12000}, {0xbfd14000}, {0xbfd16000}, 
+    {0xbfd18000}, {0xbfd1a000}, {0xbfd1c000}, {0xbfd1e000}, 
+    {0xbfd20000}, {0xbfd22000}, {0xbfd24000}, {0xbfd26000}, 
+    {0xbfd28000}, {0xbfd2a000}, {0xbfd2c000}, {0xbfd2e000}, 
+    {0xbfd30000}, {0xbfd32000}, {0xbfd34000}, {0xbfd36000}, 
+    {0xbfd38000}, {0xbfd3a000}, {0xbfd3c000}, {0xbfd3e000}, 
+    {0xbfd40000}, {0xbfd42000}, {0xbfd44000}, {0xbfd46000}, 
+    {0xbfd48000}, {0xbfd4a000}, {0xbfd4c000}, {0xbfd4e000}, 
+    {0xbfd50000}, {0xbfd52000}, {0xbfd54000}, {0xbfd56000}, 
+    {0xbfd58000}, {0xbfd5a000}, {0xbfd5c000}, {0xbfd5e000}, 
+    {0xbfd60000}, {0xbfd62000}, {0xbfd64000}, {0xbfd66000}, 
+    {0xbfd68000}, {0xbfd6a000}, {0xbfd6c000}, {0xbfd6e000}, 
+    {0xbfd70000}, {0xbfd72000}, {0xbfd74000}, {0xbfd76000}, 
+    {0xbfd78000}, {0xbfd7a000}, {0xbfd7c000}, {0xbfd7e000}, 
+    {0xbfd80000}, {0xbfd82000}, {0xbfd84000}, {0xbfd86000}, 
+    {0xbfd88000}, {0xbfd8a000}, {0xbfd8c000}, {0xbfd8e000}, 
+    {0xbfd90000}, {0xbfd92000}, {0xbfd94000}, {0xbfd96000}, 
+    {0xbfd98000}, {0xbfd9a000}, {0xbfd9c000}, {0xbfd9e000}, 
+    {0xbfda0000}, {0xbfda2000}, {0xbfda4000}, {0xbfda6000}, 
+    {0xbfda8000}, {0xbfdaa000}, {0xbfdac000}, {0xbfdae000}, 
+    {0xbfdb0000}, {0xbfdb2000}, {0xbfdb4000}, {0xbfdb6000}, 
+    {0xbfdb8000}, {0xbfdba000}, {0xbfdbc000}, {0xbfdbe000}, 
+    {0xbfdc0000}, {0xbfdc2000}, {0xbfdc4000}, {0xbfdc6000}, 
+    {0xbfdc8000}, {0xbfdca000}, {0xbfdcc000}, {0xbfdce000}, 
+    {0xbfdd0000}, {0xbfdd2000}, {0xbfdd4000}, {0xbfdd6000}, 
+    {0xbfdd8000}, {0xbfdda000}, {0xbfddc000}, {0xbfdde000}, 
+    {0xbfde0000}, {0xbfde2000}, {0xbfde4000}, {0xbfde6000}, 
+    {0xbfde8000}, {0xbfdea000}, {0xbfdec000}, {0xbfdee000}, 
+    {0xbfdf0000}, {0xbfdf2000}, {0xbfdf4000}, {0xbfdf6000}, 
+    {0xbfdf8000}, {0xbfdfa000}, {0xbfdfc000}, {0xbfdfe000}, 
+    {0xbfe00000}, {0xbfe02000}, {0xbfe04000}, {0xbfe06000}, 
+    {0xbfe08000}, {0xbfe0a000}, {0xbfe0c000}, {0xbfe0e000}, 
+    {0xbfe10000}, {0xbfe12000}, {0xbfe14000}, {0xbfe16000}, 
+    {0xbfe18000}, {0xbfe1a000}, {0xbfe1c000}, {0xbfe1e000}, 
+    {0xbfe20000}, {0xbfe22000}, {0xbfe24000}, {0xbfe26000}, 
+    {0xbfe28000}, {0xbfe2a000}, {0xbfe2c000}, {0xbfe2e000}, 
+    {0xbfe30000}, {0xbfe32000}, {0xbfe34000}, {0xbfe36000}, 
+    {0xbfe38000}, {0xbfe3a000}, {0xbfe3c000}, {0xbfe3e000}, 
+    {0xbfe40000}, {0xbfe42000}, {0xbfe44000}, {0xbfe46000}, 
+    {0xbfe48000}, {0xbfe4a000}, {0xbfe4c000}, {0xbfe4e000}, 
+    {0xbfe50000}, {0xbfe52000}, {0xbfe54000}, {0xbfe56000}, 
+    {0xbfe58000}, {0xbfe5a000}, {0xbfe5c000}, {0xbfe5e000}, 
+    {0xbfe60000}, {0xbfe62000}, {0xbfe64000}, {0xbfe66000}, 
+    {0xbfe68000}, {0xbfe6a000}, {0xbfe6c000}, {0xbfe6e000}, 
+    {0xbfe70000}, {0xbfe72000}, {0xbfe74000}, {0xbfe76000}, 
+    {0xbfe78000}, {0xbfe7a000}, {0xbfe7c000}, {0xbfe7e000}, 
+    {0xbfe80000}, {0xbfe82000}, {0xbfe84000}, {0xbfe86000}, 
+    {0xbfe88000}, {0xbfe8a000}, {0xbfe8c000}, {0xbfe8e000}, 
+    {0xbfe90000}, {0xbfe92000}, {0xbfe94000}, {0xbfe96000}, 
+    {0xbfe98000}, {0xbfe9a000}, {0xbfe9c000}, {0xbfe9e000}, 
+    {0xbfea0000}, {0xbfea2000}, {0xbfea4000}, {0xbfea6000}, 
+    {0xbfea8000}, {0xbfeaa000}, {0xbfeac000}, {0xbfeae000}, 
+    {0xbfeb0000}, {0xbfeb2000}, {0xbfeb4000}, {0xbfeb6000}, 
+    {0xbfeb8000}, {0xbfeba000}, {0xbfebc000}, {0xbfebe000}, 
+    {0xbfec0000}, {0xbfec2000}, {0xbfec4000}, {0xbfec6000}, 
+    {0xbfec8000}, {0xbfeca000}, {0xbfecc000}, {0xbfece000}, 
+    {0xbfed0000}, {0xbfed2000}, {0xbfed4000}, {0xbfed6000}, 
+    {0xbfed8000}, {0xbfeda000}, {0xbfedc000}, {0xbfede000}, 
+    {0xbfee0000}, {0xbfee2000}, {0xbfee4000}, {0xbfee6000}, 
+    {0xbfee8000}, {0xbfeea000}, {0xbfeec000}, {0xbfeee000}, 
+    {0xbfef0000}, {0xbfef2000}, {0xbfef4000}, {0xbfef6000}, 
+    {0xbfef8000}, {0xbfefa000}, {0xbfefc000}, {0xbfefe000}, 
+    {0xbff00000}, {0xbff02000}, {0xbff04000}, {0xbff06000}, 
+    {0xbff08000}, {0xbff0a000}, {0xbff0c000}, {0xbff0e000}, 
+    {0xbff10000}, {0xbff12000}, {0xbff14000}, {0xbff16000}, 
+    {0xbff18000}, {0xbff1a000}, {0xbff1c000}, {0xbff1e000}, 
+    {0xbff20000}, {0xbff22000}, {0xbff24000}, {0xbff26000}, 
+    {0xbff28000}, {0xbff2a000}, {0xbff2c000}, {0xbff2e000}, 
+    {0xbff30000}, {0xbff32000}, {0xbff34000}, {0xbff36000}, 
+    {0xbff38000}, {0xbff3a000}, {0xbff3c000}, {0xbff3e000}, 
+    {0xbff40000}, {0xbff42000}, {0xbff44000}, {0xbff46000}, 
+    {0xbff48000}, {0xbff4a000}, {0xbff4c000}, {0xbff4e000}, 
+    {0xbff50000}, {0xbff52000}, {0xbff54000}, {0xbff56000}, 
+    {0xbff58000}, {0xbff5a000}, {0xbff5c000}, {0xbff5e000}, 
+    {0xbff60000}, {0xbff62000}, {0xbff64000}, {0xbff66000}, 
+    {0xbff68000}, {0xbff6a000}, {0xbff6c000}, {0xbff6e000}, 
+    {0xbff70000}, {0xbff72000}, {0xbff74000}, {0xbff76000}, 
+    {0xbff78000}, {0xbff7a000}, {0xbff7c000}, {0xbff7e000}, 
+    {0xbff80000}, {0xbff82000}, {0xbff84000}, {0xbff86000}, 
+    {0xbff88000}, {0xbff8a000}, {0xbff8c000}, {0xbff8e000}, 
+    {0xbff90000}, {0xbff92000}, {0xbff94000}, {0xbff96000}, 
+    {0xbff98000}, {0xbff9a000}, {0xbff9c000}, {0xbff9e000}, 
+    {0xbffa0000}, {0xbffa2000}, {0xbffa4000}, {0xbffa6000}, 
+    {0xbffa8000}, {0xbffaa000}, {0xbffac000}, {0xbffae000}, 
+    {0xbffb0000}, {0xbffb2000}, {0xbffb4000}, {0xbffb6000}, 
+    {0xbffb8000}, {0xbffba000}, {0xbffbc000}, {0xbffbe000}, 
+    {0xbffc0000}, {0xbffc2000}, {0xbffc4000}, {0xbffc6000}, 
+    {0xbffc8000}, {0xbffca000}, {0xbffcc000}, {0xbffce000}, 
+    {0xbffd0000}, {0xbffd2000}, {0xbffd4000}, {0xbffd6000}, 
+    {0xbffd8000}, {0xbffda000}, {0xbffdc000}, {0xbffde000}, 
+    {0xbffe0000}, {0xbffe2000}, {0xbffe4000}, {0xbffe6000}, 
+    {0xbffe8000}, {0xbffea000}, {0xbffec000}, {0xbffee000}, 
+    {0xbfff0000}, {0xbfff2000}, {0xbfff4000}, {0xbfff6000}, 
+    {0xbfff8000}, {0xbfffa000}, {0xbfffc000}, {0xbfffe000}, 
+    {0xc0000000}, {0xc0002000}, {0xc0004000}, {0xc0006000}, 
+    {0xc0008000}, {0xc000a000}, {0xc000c000}, {0xc000e000}, 
+    {0xc0010000}, {0xc0012000}, {0xc0014000}, {0xc0016000}, 
+    {0xc0018000}, {0xc001a000}, {0xc001c000}, {0xc001e000}, 
+    {0xc0020000}, {0xc0022000}, {0xc0024000}, {0xc0026000}, 
+    {0xc0028000}, {0xc002a000}, {0xc002c000}, {0xc002e000}, 
+    {0xc0030000}, {0xc0032000}, {0xc0034000}, {0xc0036000}, 
+    {0xc0038000}, {0xc003a000}, {0xc003c000}, {0xc003e000}, 
+    {0xc0040000}, {0xc0042000}, {0xc0044000}, {0xc0046000}, 
+    {0xc0048000}, {0xc004a000}, {0xc004c000}, {0xc004e000}, 
+    {0xc0050000}, {0xc0052000}, {0xc0054000}, {0xc0056000}, 
+    {0xc0058000}, {0xc005a000}, {0xc005c000}, {0xc005e000}, 
+    {0xc0060000}, {0xc0062000}, {0xc0064000}, {0xc0066000}, 
+    {0xc0068000}, {0xc006a000}, {0xc006c000}, {0xc006e000}, 
+    {0xc0070000}, {0xc0072000}, {0xc0074000}, {0xc0076000}, 
+    {0xc0078000}, {0xc007a000}, {0xc007c000}, {0xc007e000}, 
+    {0xc0080000}, {0xc0082000}, {0xc0084000}, {0xc0086000}, 
+    {0xc0088000}, {0xc008a000}, {0xc008c000}, {0xc008e000}, 
+    {0xc0090000}, {0xc0092000}, {0xc0094000}, {0xc0096000}, 
+    {0xc0098000}, {0xc009a000}, {0xc009c000}, {0xc009e000}, 
+    {0xc00a0000}, {0xc00a2000}, {0xc00a4000}, {0xc00a6000}, 
+    {0xc00a8000}, {0xc00aa000}, {0xc00ac000}, {0xc00ae000}, 
+    {0xc00b0000}, {0xc00b2000}, {0xc00b4000}, {0xc00b6000}, 
+    {0xc00b8000}, {0xc00ba000}, {0xc00bc000}, {0xc00be000}, 
+    {0xc00c0000}, {0xc00c2000}, {0xc00c4000}, {0xc00c6000}, 
+    {0xc00c8000}, {0xc00ca000}, {0xc00cc000}, {0xc00ce000}, 
+    {0xc00d0000}, {0xc00d2000}, {0xc00d4000}, {0xc00d6000}, 
+    {0xc00d8000}, {0xc00da000}, {0xc00dc000}, {0xc00de000}, 
+    {0xc00e0000}, {0xc00e2000}, {0xc00e4000}, {0xc00e6000}, 
+    {0xc00e8000}, {0xc00ea000}, {0xc00ec000}, {0xc00ee000}, 
+    {0xc00f0000}, {0xc00f2000}, {0xc00f4000}, {0xc00f6000}, 
+    {0xc00f8000}, {0xc00fa000}, {0xc00fc000}, {0xc00fe000}, 
+    {0xc0100000}, {0xc0102000}, {0xc0104000}, {0xc0106000}, 
+    {0xc0108000}, {0xc010a000}, {0xc010c000}, {0xc010e000}, 
+    {0xc0110000}, {0xc0112000}, {0xc0114000}, {0xc0116000}, 
+    {0xc0118000}, {0xc011a000}, {0xc011c000}, {0xc011e000}, 
+    {0xc0120000}, {0xc0122000}, {0xc0124000}, {0xc0126000}, 
+    {0xc0128000}, {0xc012a000}, {0xc012c000}, {0xc012e000}, 
+    {0xc0130000}, {0xc0132000}, {0xc0134000}, {0xc0136000}, 
+    {0xc0138000}, {0xc013a000}, {0xc013c000}, {0xc013e000}, 
+    {0xc0140000}, {0xc0142000}, {0xc0144000}, {0xc0146000}, 
+    {0xc0148000}, {0xc014a000}, {0xc014c000}, {0xc014e000}, 
+    {0xc0150000}, {0xc0152000}, {0xc0154000}, {0xc0156000}, 
+    {0xc0158000}, {0xc015a000}, {0xc015c000}, {0xc015e000}, 
+    {0xc0160000}, {0xc0162000}, {0xc0164000}, {0xc0166000}, 
+    {0xc0168000}, {0xc016a000}, {0xc016c000}, {0xc016e000}, 
+    {0xc0170000}, {0xc0172000}, {0xc0174000}, {0xc0176000}, 
+    {0xc0178000}, {0xc017a000}, {0xc017c000}, {0xc017e000}, 
+    {0xc0180000}, {0xc0182000}, {0xc0184000}, {0xc0186000}, 
+    {0xc0188000}, {0xc018a000}, {0xc018c000}, {0xc018e000}, 
+    {0xc0190000}, {0xc0192000}, {0xc0194000}, {0xc0196000}, 
+    {0xc0198000}, {0xc019a000}, {0xc019c000}, {0xc019e000}, 
+    {0xc01a0000}, {0xc01a2000}, {0xc01a4000}, {0xc01a6000}, 
+    {0xc01a8000}, {0xc01aa000}, {0xc01ac000}, {0xc01ae000}, 
+    {0xc01b0000}, {0xc01b2000}, {0xc01b4000}, {0xc01b6000}, 
+    {0xc01b8000}, {0xc01ba000}, {0xc01bc000}, {0xc01be000}, 
+    {0xc01c0000}, {0xc01c2000}, {0xc01c4000}, {0xc01c6000}, 
+    {0xc01c8000}, {0xc01ca000}, {0xc01cc000}, {0xc01ce000}, 
+    {0xc01d0000}, {0xc01d2000}, {0xc01d4000}, {0xc01d6000}, 
+    {0xc01d8000}, {0xc01da000}, {0xc01dc000}, {0xc01de000}, 
+    {0xc01e0000}, {0xc01e2000}, {0xc01e4000}, {0xc01e6000}, 
+    {0xc01e8000}, {0xc01ea000}, {0xc01ec000}, {0xc01ee000}, 
+    {0xc01f0000}, {0xc01f2000}, {0xc01f4000}, {0xc01f6000}, 
+    {0xc01f8000}, {0xc01fa000}, {0xc01fc000}, {0xc01fe000}, 
+    {0xc0200000}, {0xc0202000}, {0xc0204000}, {0xc0206000}, 
+    {0xc0208000}, {0xc020a000}, {0xc020c000}, {0xc020e000}, 
+    {0xc0210000}, {0xc0212000}, {0xc0214000}, {0xc0216000}, 
+    {0xc0218000}, {0xc021a000}, {0xc021c000}, {0xc021e000}, 
+    {0xc0220000}, {0xc0222000}, {0xc0224000}, {0xc0226000}, 
+    {0xc0228000}, {0xc022a000}, {0xc022c000}, {0xc022e000}, 
+    {0xc0230000}, {0xc0232000}, {0xc0234000}, {0xc0236000}, 
+    {0xc0238000}, {0xc023a000}, {0xc023c000}, {0xc023e000}, 
+    {0xc0240000}, {0xc0242000}, {0xc0244000}, {0xc0246000}, 
+    {0xc0248000}, {0xc024a000}, {0xc024c000}, {0xc024e000}, 
+    {0xc0250000}, {0xc0252000}, {0xc0254000}, {0xc0256000}, 
+    {0xc0258000}, {0xc025a000}, {0xc025c000}, {0xc025e000}, 
+    {0xc0260000}, {0xc0262000}, {0xc0264000}, {0xc0266000}, 
+    {0xc0268000}, {0xc026a000}, {0xc026c000}, {0xc026e000}, 
+    {0xc0270000}, {0xc0272000}, {0xc0274000}, {0xc0276000}, 
+    {0xc0278000}, {0xc027a000}, {0xc027c000}, {0xc027e000}, 
+    {0xc0280000}, {0xc0282000}, {0xc0284000}, {0xc0286000}, 
+    {0xc0288000}, {0xc028a000}, {0xc028c000}, {0xc028e000}, 
+    {0xc0290000}, {0xc0292000}, {0xc0294000}, {0xc0296000}, 
+    {0xc0298000}, {0xc029a000}, {0xc029c000}, {0xc029e000}, 
+    {0xc02a0000}, {0xc02a2000}, {0xc02a4000}, {0xc02a6000}, 
+    {0xc02a8000}, {0xc02aa000}, {0xc02ac000}, {0xc02ae000}, 
+    {0xc02b0000}, {0xc02b2000}, {0xc02b4000}, {0xc02b6000}, 
+    {0xc02b8000}, {0xc02ba000}, {0xc02bc000}, {0xc02be000}, 
+    {0xc02c0000}, {0xc02c2000}, {0xc02c4000}, {0xc02c6000}, 
+    {0xc02c8000}, {0xc02ca000}, {0xc02cc000}, {0xc02ce000}, 
+    {0xc02d0000}, {0xc02d2000}, {0xc02d4000}, {0xc02d6000}, 
+    {0xc02d8000}, {0xc02da000}, {0xc02dc000}, {0xc02de000}, 
+    {0xc02e0000}, {0xc02e2000}, {0xc02e4000}, {0xc02e6000}, 
+    {0xc02e8000}, {0xc02ea000}, {0xc02ec000}, {0xc02ee000}, 
+    {0xc02f0000}, {0xc02f2000}, {0xc02f4000}, {0xc02f6000}, 
+    {0xc02f8000}, {0xc02fa000}, {0xc02fc000}, {0xc02fe000}, 
+    {0xc0300000}, {0xc0302000}, {0xc0304000}, {0xc0306000}, 
+    {0xc0308000}, {0xc030a000}, {0xc030c000}, {0xc030e000}, 
+    {0xc0310000}, {0xc0312000}, {0xc0314000}, {0xc0316000}, 
+    {0xc0318000}, {0xc031a000}, {0xc031c000}, {0xc031e000}, 
+    {0xc0320000}, {0xc0322000}, {0xc0324000}, {0xc0326000}, 
+    {0xc0328000}, {0xc032a000}, {0xc032c000}, {0xc032e000}, 
+    {0xc0330000}, {0xc0332000}, {0xc0334000}, {0xc0336000}, 
+    {0xc0338000}, {0xc033a000}, {0xc033c000}, {0xc033e000}, 
+    {0xc0340000}, {0xc0342000}, {0xc0344000}, {0xc0346000}, 
+    {0xc0348000}, {0xc034a000}, {0xc034c000}, {0xc034e000}, 
+    {0xc0350000}, {0xc0352000}, {0xc0354000}, {0xc0356000}, 
+    {0xc0358000}, {0xc035a000}, {0xc035c000}, {0xc035e000}, 
+    {0xc0360000}, {0xc0362000}, {0xc0364000}, {0xc0366000}, 
+    {0xc0368000}, {0xc036a000}, {0xc036c000}, {0xc036e000}, 
+    {0xc0370000}, {0xc0372000}, {0xc0374000}, {0xc0376000}, 
+    {0xc0378000}, {0xc037a000}, {0xc037c000}, {0xc037e000}, 
+    {0xc0380000}, {0xc0382000}, {0xc0384000}, {0xc0386000}, 
+    {0xc0388000}, {0xc038a000}, {0xc038c000}, {0xc038e000}, 
+    {0xc0390000}, {0xc0392000}, {0xc0394000}, {0xc0396000}, 
+    {0xc0398000}, {0xc039a000}, {0xc039c000}, {0xc039e000}, 
+    {0xc03a0000}, {0xc03a2000}, {0xc03a4000}, {0xc03a6000}, 
+    {0xc03a8000}, {0xc03aa000}, {0xc03ac000}, {0xc03ae000}, 
+    {0xc03b0000}, {0xc03b2000}, {0xc03b4000}, {0xc03b6000}, 
+    {0xc03b8000}, {0xc03ba000}, {0xc03bc000}, {0xc03be000}, 
+    {0xc03c0000}, {0xc03c2000}, {0xc03c4000}, {0xc03c6000}, 
+    {0xc03c8000}, {0xc03ca000}, {0xc03cc000}, {0xc03ce000}, 
+    {0xc03d0000}, {0xc03d2000}, {0xc03d4000}, {0xc03d6000}, 
+    {0xc03d8000}, {0xc03da000}, {0xc03dc000}, {0xc03de000}, 
+    {0xc03e0000}, {0xc03e2000}, {0xc03e4000}, {0xc03e6000}, 
+    {0xc03e8000}, {0xc03ea000}, {0xc03ec000}, {0xc03ee000}, 
+    {0xc03f0000}, {0xc03f2000}, {0xc03f4000}, {0xc03f6000}, 
+    {0xc03f8000}, {0xc03fa000}, {0xc03fc000}, {0xc03fe000}, 
+    {0xc0400000}, {0xc0402000}, {0xc0404000}, {0xc0406000}, 
+    {0xc0408000}, {0xc040a000}, {0xc040c000}, {0xc040e000}, 
+    {0xc0410000}, {0xc0412000}, {0xc0414000}, {0xc0416000}, 
+    {0xc0418000}, {0xc041a000}, {0xc041c000}, {0xc041e000}, 
+    {0xc0420000}, {0xc0422000}, {0xc0424000}, {0xc0426000}, 
+    {0xc0428000}, {0xc042a000}, {0xc042c000}, {0xc042e000}, 
+    {0xc0430000}, {0xc0432000}, {0xc0434000}, {0xc0436000}, 
+    {0xc0438000}, {0xc043a000}, {0xc043c000}, {0xc043e000}, 
+    {0xc0440000}, {0xc0442000}, {0xc0444000}, {0xc0446000}, 
+    {0xc0448000}, {0xc044a000}, {0xc044c000}, {0xc044e000}, 
+    {0xc0450000}, {0xc0452000}, {0xc0454000}, {0xc0456000}, 
+    {0xc0458000}, {0xc045a000}, {0xc045c000}, {0xc045e000}, 
+    {0xc0460000}, {0xc0462000}, {0xc0464000}, {0xc0466000}, 
+    {0xc0468000}, {0xc046a000}, {0xc046c000}, {0xc046e000}, 
+    {0xc0470000}, {0xc0472000}, {0xc0474000}, {0xc0476000}, 
+    {0xc0478000}, {0xc047a000}, {0xc047c000}, {0xc047e000}, 
+    {0xc0480000}, {0xc0482000}, {0xc0484000}, {0xc0486000}, 
+    {0xc0488000}, {0xc048a000}, {0xc048c000}, {0xc048e000}, 
+    {0xc0490000}, {0xc0492000}, {0xc0494000}, {0xc0496000}, 
+    {0xc0498000}, {0xc049a000}, {0xc049c000}, {0xc049e000}, 
+    {0xc04a0000}, {0xc04a2000}, {0xc04a4000}, {0xc04a6000}, 
+    {0xc04a8000}, {0xc04aa000}, {0xc04ac000}, {0xc04ae000}, 
+    {0xc04b0000}, {0xc04b2000}, {0xc04b4000}, {0xc04b6000}, 
+    {0xc04b8000}, {0xc04ba000}, {0xc04bc000}, {0xc04be000}, 
+    {0xc04c0000}, {0xc04c2000}, {0xc04c4000}, {0xc04c6000}, 
+    {0xc04c8000}, {0xc04ca000}, {0xc04cc000}, {0xc04ce000}, 
+    {0xc04d0000}, {0xc04d2000}, {0xc04d4000}, {0xc04d6000}, 
+    {0xc04d8000}, {0xc04da000}, {0xc04dc000}, {0xc04de000}, 
+    {0xc04e0000}, {0xc04e2000}, {0xc04e4000}, {0xc04e6000}, 
+    {0xc04e8000}, {0xc04ea000}, {0xc04ec000}, {0xc04ee000}, 
+    {0xc04f0000}, {0xc04f2000}, {0xc04f4000}, {0xc04f6000}, 
+    {0xc04f8000}, {0xc04fa000}, {0xc04fc000}, {0xc04fe000}, 
+    {0xc0500000}, {0xc0502000}, {0xc0504000}, {0xc0506000}, 
+    {0xc0508000}, {0xc050a000}, {0xc050c000}, {0xc050e000}, 
+    {0xc0510000}, {0xc0512000}, {0xc0514000}, {0xc0516000}, 
+    {0xc0518000}, {0xc051a000}, {0xc051c000}, {0xc051e000}, 
+    {0xc0520000}, {0xc0522000}, {0xc0524000}, {0xc0526000}, 
+    {0xc0528000}, {0xc052a000}, {0xc052c000}, {0xc052e000}, 
+    {0xc0530000}, {0xc0532000}, {0xc0534000}, {0xc0536000}, 
+    {0xc0538000}, {0xc053a000}, {0xc053c000}, {0xc053e000}, 
+    {0xc0540000}, {0xc0542000}, {0xc0544000}, {0xc0546000}, 
+    {0xc0548000}, {0xc054a000}, {0xc054c000}, {0xc054e000}, 
+    {0xc0550000}, {0xc0552000}, {0xc0554000}, {0xc0556000}, 
+    {0xc0558000}, {0xc055a000}, {0xc055c000}, {0xc055e000}, 
+    {0xc0560000}, {0xc0562000}, {0xc0564000}, {0xc0566000}, 
+    {0xc0568000}, {0xc056a000}, {0xc056c000}, {0xc056e000}, 
+    {0xc0570000}, {0xc0572000}, {0xc0574000}, {0xc0576000}, 
+    {0xc0578000}, {0xc057a000}, {0xc057c000}, {0xc057e000}, 
+    {0xc0580000}, {0xc0582000}, {0xc0584000}, {0xc0586000}, 
+    {0xc0588000}, {0xc058a000}, {0xc058c000}, {0xc058e000}, 
+    {0xc0590000}, {0xc0592000}, {0xc0594000}, {0xc0596000}, 
+    {0xc0598000}, {0xc059a000}, {0xc059c000}, {0xc059e000}, 
+    {0xc05a0000}, {0xc05a2000}, {0xc05a4000}, {0xc05a6000}, 
+    {0xc05a8000}, {0xc05aa000}, {0xc05ac000}, {0xc05ae000}, 
+    {0xc05b0000}, {0xc05b2000}, {0xc05b4000}, {0xc05b6000}, 
+    {0xc05b8000}, {0xc05ba000}, {0xc05bc000}, {0xc05be000}, 
+    {0xc05c0000}, {0xc05c2000}, {0xc05c4000}, {0xc05c6000}, 
+    {0xc05c8000}, {0xc05ca000}, {0xc05cc000}, {0xc05ce000}, 
+    {0xc05d0000}, {0xc05d2000}, {0xc05d4000}, {0xc05d6000}, 
+    {0xc05d8000}, {0xc05da000}, {0xc05dc000}, {0xc05de000}, 
+    {0xc05e0000}, {0xc05e2000}, {0xc05e4000}, {0xc05e6000}, 
+    {0xc05e8000}, {0xc05ea000}, {0xc05ec000}, {0xc05ee000}, 
+    {0xc05f0000}, {0xc05f2000}, {0xc05f4000}, {0xc05f6000}, 
+    {0xc05f8000}, {0xc05fa000}, {0xc05fc000}, {0xc05fe000}, 
+    {0xc0600000}, {0xc0602000}, {0xc0604000}, {0xc0606000}, 
+    {0xc0608000}, {0xc060a000}, {0xc060c000}, {0xc060e000}, 
+    {0xc0610000}, {0xc0612000}, {0xc0614000}, {0xc0616000}, 
+    {0xc0618000}, {0xc061a000}, {0xc061c000}, {0xc061e000}, 
+    {0xc0620000}, {0xc0622000}, {0xc0624000}, {0xc0626000}, 
+    {0xc0628000}, {0xc062a000}, {0xc062c000}, {0xc062e000}, 
+    {0xc0630000}, {0xc0632000}, {0xc0634000}, {0xc0636000}, 
+    {0xc0638000}, {0xc063a000}, {0xc063c000}, {0xc063e000}, 
+    {0xc0640000}, {0xc0642000}, {0xc0644000}, {0xc0646000}, 
+    {0xc0648000}, {0xc064a000}, {0xc064c000}, {0xc064e000}, 
+    {0xc0650000}, {0xc0652000}, {0xc0654000}, {0xc0656000}, 
+    {0xc0658000}, {0xc065a000}, {0xc065c000}, {0xc065e000}, 
+    {0xc0660000}, {0xc0662000}, {0xc0664000}, {0xc0666000}, 
+    {0xc0668000}, {0xc066a000}, {0xc066c000}, {0xc066e000}, 
+    {0xc0670000}, {0xc0672000}, {0xc0674000}, {0xc0676000}, 
+    {0xc0678000}, {0xc067a000}, {0xc067c000}, {0xc067e000}, 
+    {0xc0680000}, {0xc0682000}, {0xc0684000}, {0xc0686000}, 
+    {0xc0688000}, {0xc068a000}, {0xc068c000}, {0xc068e000}, 
+    {0xc0690000}, {0xc0692000}, {0xc0694000}, {0xc0696000}, 
+    {0xc0698000}, {0xc069a000}, {0xc069c000}, {0xc069e000}, 
+    {0xc06a0000}, {0xc06a2000}, {0xc06a4000}, {0xc06a6000}, 
+    {0xc06a8000}, {0xc06aa000}, {0xc06ac000}, {0xc06ae000}, 
+    {0xc06b0000}, {0xc06b2000}, {0xc06b4000}, {0xc06b6000}, 
+    {0xc06b8000}, {0xc06ba000}, {0xc06bc000}, {0xc06be000}, 
+    {0xc06c0000}, {0xc06c2000}, {0xc06c4000}, {0xc06c6000}, 
+    {0xc06c8000}, {0xc06ca000}, {0xc06cc000}, {0xc06ce000}, 
+    {0xc06d0000}, {0xc06d2000}, {0xc06d4000}, {0xc06d6000}, 
+    {0xc06d8000}, {0xc06da000}, {0xc06dc000}, {0xc06de000}, 
+    {0xc06e0000}, {0xc06e2000}, {0xc06e4000}, {0xc06e6000}, 
+    {0xc06e8000}, {0xc06ea000}, {0xc06ec000}, {0xc06ee000}, 
+    {0xc06f0000}, {0xc06f2000}, {0xc06f4000}, {0xc06f6000}, 
+    {0xc06f8000}, {0xc06fa000}, {0xc06fc000}, {0xc06fe000}, 
+    {0xc0700000}, {0xc0702000}, {0xc0704000}, {0xc0706000}, 
+    {0xc0708000}, {0xc070a000}, {0xc070c000}, {0xc070e000}, 
+    {0xc0710000}, {0xc0712000}, {0xc0714000}, {0xc0716000}, 
+    {0xc0718000}, {0xc071a000}, {0xc071c000}, {0xc071e000}, 
+    {0xc0720000}, {0xc0722000}, {0xc0724000}, {0xc0726000}, 
+    {0xc0728000}, {0xc072a000}, {0xc072c000}, {0xc072e000}, 
+    {0xc0730000}, {0xc0732000}, {0xc0734000}, {0xc0736000}, 
+    {0xc0738000}, {0xc073a000}, {0xc073c000}, {0xc073e000}, 
+    {0xc0740000}, {0xc0742000}, {0xc0744000}, {0xc0746000}, 
+    {0xc0748000}, {0xc074a000}, {0xc074c000}, {0xc074e000}, 
+    {0xc0750000}, {0xc0752000}, {0xc0754000}, {0xc0756000}, 
+    {0xc0758000}, {0xc075a000}, {0xc075c000}, {0xc075e000}, 
+    {0xc0760000}, {0xc0762000}, {0xc0764000}, {0xc0766000}, 
+    {0xc0768000}, {0xc076a000}, {0xc076c000}, {0xc076e000}, 
+    {0xc0770000}, {0xc0772000}, {0xc0774000}, {0xc0776000}, 
+    {0xc0778000}, {0xc077a000}, {0xc077c000}, {0xc077e000}, 
+    {0xc0780000}, {0xc0782000}, {0xc0784000}, {0xc0786000}, 
+    {0xc0788000}, {0xc078a000}, {0xc078c000}, {0xc078e000}, 
+    {0xc0790000}, {0xc0792000}, {0xc0794000}, {0xc0796000}, 
+    {0xc0798000}, {0xc079a000}, {0xc079c000}, {0xc079e000}, 
+    {0xc07a0000}, {0xc07a2000}, {0xc07a4000}, {0xc07a6000}, 
+    {0xc07a8000}, {0xc07aa000}, {0xc07ac000}, {0xc07ae000}, 
+    {0xc07b0000}, {0xc07b2000}, {0xc07b4000}, {0xc07b6000}, 
+    {0xc07b8000}, {0xc07ba000}, {0xc07bc000}, {0xc07be000}, 
+    {0xc07c0000}, {0xc07c2000}, {0xc07c4000}, {0xc07c6000}, 
+    {0xc07c8000}, {0xc07ca000}, {0xc07cc000}, {0xc07ce000}, 
+    {0xc07d0000}, {0xc07d2000}, {0xc07d4000}, {0xc07d6000}, 
+    {0xc07d8000}, {0xc07da000}, {0xc07dc000}, {0xc07de000}, 
+    {0xc07e0000}, {0xc07e2000}, {0xc07e4000}, {0xc07e6000}, 
+    {0xc07e8000}, {0xc07ea000}, {0xc07ec000}, {0xc07ee000}, 
+    {0xc07f0000}, {0xc07f2000}, {0xc07f4000}, {0xc07f6000}, 
+    {0xc07f8000}, {0xc07fa000}, {0xc07fc000}, {0xc07fe000}, 
+    {0xc0800000}, {0xc0802000}, {0xc0804000}, {0xc0806000}, 
+    {0xc0808000}, {0xc080a000}, {0xc080c000}, {0xc080e000}, 
+    {0xc0810000}, {0xc0812000}, {0xc0814000}, {0xc0816000}, 
+    {0xc0818000}, {0xc081a000}, {0xc081c000}, {0xc081e000}, 
+    {0xc0820000}, {0xc0822000}, {0xc0824000}, {0xc0826000}, 
+    {0xc0828000}, {0xc082a000}, {0xc082c000}, {0xc082e000}, 
+    {0xc0830000}, {0xc0832000}, {0xc0834000}, {0xc0836000}, 
+    {0xc0838000}, {0xc083a000}, {0xc083c000}, {0xc083e000}, 
+    {0xc0840000}, {0xc0842000}, {0xc0844000}, {0xc0846000}, 
+    {0xc0848000}, {0xc084a000}, {0xc084c000}, {0xc084e000}, 
+    {0xc0850000}, {0xc0852000}, {0xc0854000}, {0xc0856000}, 
+    {0xc0858000}, {0xc085a000}, {0xc085c000}, {0xc085e000}, 
+    {0xc0860000}, {0xc0862000}, {0xc0864000}, {0xc0866000}, 
+    {0xc0868000}, {0xc086a000}, {0xc086c000}, {0xc086e000}, 
+    {0xc0870000}, {0xc0872000}, {0xc0874000}, {0xc0876000}, 
+    {0xc0878000}, {0xc087a000}, {0xc087c000}, {0xc087e000}, 
+    {0xc0880000}, {0xc0882000}, {0xc0884000}, {0xc0886000}, 
+    {0xc0888000}, {0xc088a000}, {0xc088c000}, {0xc088e000}, 
+    {0xc0890000}, {0xc0892000}, {0xc0894000}, {0xc0896000}, 
+    {0xc0898000}, {0xc089a000}, {0xc089c000}, {0xc089e000}, 
+    {0xc08a0000}, {0xc08a2000}, {0xc08a4000}, {0xc08a6000}, 
+    {0xc08a8000}, {0xc08aa000}, {0xc08ac000}, {0xc08ae000}, 
+    {0xc08b0000}, {0xc08b2000}, {0xc08b4000}, {0xc08b6000}, 
+    {0xc08b8000}, {0xc08ba000}, {0xc08bc000}, {0xc08be000}, 
+    {0xc08c0000}, {0xc08c2000}, {0xc08c4000}, {0xc08c6000}, 
+    {0xc08c8000}, {0xc08ca000}, {0xc08cc000}, {0xc08ce000}, 
+    {0xc08d0000}, {0xc08d2000}, {0xc08d4000}, {0xc08d6000}, 
+    {0xc08d8000}, {0xc08da000}, {0xc08dc000}, {0xc08de000}, 
+    {0xc08e0000}, {0xc08e2000}, {0xc08e4000}, {0xc08e6000}, 
+    {0xc08e8000}, {0xc08ea000}, {0xc08ec000}, {0xc08ee000}, 
+    {0xc08f0000}, {0xc08f2000}, {0xc08f4000}, {0xc08f6000}, 
+    {0xc08f8000}, {0xc08fa000}, {0xc08fc000}, {0xc08fe000}, 
+    {0xc0900000}, {0xc0902000}, {0xc0904000}, {0xc0906000}, 
+    {0xc0908000}, {0xc090a000}, {0xc090c000}, {0xc090e000}, 
+    {0xc0910000}, {0xc0912000}, {0xc0914000}, {0xc0916000}, 
+    {0xc0918000}, {0xc091a000}, {0xc091c000}, {0xc091e000}, 
+    {0xc0920000}, {0xc0922000}, {0xc0924000}, {0xc0926000}, 
+    {0xc0928000}, {0xc092a000}, {0xc092c000}, {0xc092e000}, 
+    {0xc0930000}, {0xc0932000}, {0xc0934000}, {0xc0936000}, 
+    {0xc0938000}, {0xc093a000}, {0xc093c000}, {0xc093e000}, 
+    {0xc0940000}, {0xc0942000}, {0xc0944000}, {0xc0946000}, 
+    {0xc0948000}, {0xc094a000}, {0xc094c000}, {0xc094e000}, 
+    {0xc0950000}, {0xc0952000}, {0xc0954000}, {0xc0956000}, 
+    {0xc0958000}, {0xc095a000}, {0xc095c000}, {0xc095e000}, 
+    {0xc0960000}, {0xc0962000}, {0xc0964000}, {0xc0966000}, 
+    {0xc0968000}, {0xc096a000}, {0xc096c000}, {0xc096e000}, 
+    {0xc0970000}, {0xc0972000}, {0xc0974000}, {0xc0976000}, 
+    {0xc0978000}, {0xc097a000}, {0xc097c000}, {0xc097e000}, 
+    {0xc0980000}, {0xc0982000}, {0xc0984000}, {0xc0986000}, 
+    {0xc0988000}, {0xc098a000}, {0xc098c000}, {0xc098e000}, 
+    {0xc0990000}, {0xc0992000}, {0xc0994000}, {0xc0996000}, 
+    {0xc0998000}, {0xc099a000}, {0xc099c000}, {0xc099e000}, 
+    {0xc09a0000}, {0xc09a2000}, {0xc09a4000}, {0xc09a6000}, 
+    {0xc09a8000}, {0xc09aa000}, {0xc09ac000}, {0xc09ae000}, 
+    {0xc09b0000}, {0xc09b2000}, {0xc09b4000}, {0xc09b6000}, 
+    {0xc09b8000}, {0xc09ba000}, {0xc09bc000}, {0xc09be000}, 
+    {0xc09c0000}, {0xc09c2000}, {0xc09c4000}, {0xc09c6000}, 
+    {0xc09c8000}, {0xc09ca000}, {0xc09cc000}, {0xc09ce000}, 
+    {0xc09d0000}, {0xc09d2000}, {0xc09d4000}, {0xc09d6000}, 
+    {0xc09d8000}, {0xc09da000}, {0xc09dc000}, {0xc09de000}, 
+    {0xc09e0000}, {0xc09e2000}, {0xc09e4000}, {0xc09e6000}, 
+    {0xc09e8000}, {0xc09ea000}, {0xc09ec000}, {0xc09ee000}, 
+    {0xc09f0000}, {0xc09f2000}, {0xc09f4000}, {0xc09f6000}, 
+    {0xc09f8000}, {0xc09fa000}, {0xc09fc000}, {0xc09fe000}, 
+    {0xc0a00000}, {0xc0a02000}, {0xc0a04000}, {0xc0a06000}, 
+    {0xc0a08000}, {0xc0a0a000}, {0xc0a0c000}, {0xc0a0e000}, 
+    {0xc0a10000}, {0xc0a12000}, {0xc0a14000}, {0xc0a16000}, 
+    {0xc0a18000}, {0xc0a1a000}, {0xc0a1c000}, {0xc0a1e000}, 
+    {0xc0a20000}, {0xc0a22000}, {0xc0a24000}, {0xc0a26000}, 
+    {0xc0a28000}, {0xc0a2a000}, {0xc0a2c000}, {0xc0a2e000}, 
+    {0xc0a30000}, {0xc0a32000}, {0xc0a34000}, {0xc0a36000}, 
+    {0xc0a38000}, {0xc0a3a000}, {0xc0a3c000}, {0xc0a3e000}, 
+    {0xc0a40000}, {0xc0a42000}, {0xc0a44000}, {0xc0a46000}, 
+    {0xc0a48000}, {0xc0a4a000}, {0xc0a4c000}, {0xc0a4e000}, 
+    {0xc0a50000}, {0xc0a52000}, {0xc0a54000}, {0xc0a56000}, 
+    {0xc0a58000}, {0xc0a5a000}, {0xc0a5c000}, {0xc0a5e000}, 
+    {0xc0a60000}, {0xc0a62000}, {0xc0a64000}, {0xc0a66000}, 
+    {0xc0a68000}, {0xc0a6a000}, {0xc0a6c000}, {0xc0a6e000}, 
+    {0xc0a70000}, {0xc0a72000}, {0xc0a74000}, {0xc0a76000}, 
+    {0xc0a78000}, {0xc0a7a000}, {0xc0a7c000}, {0xc0a7e000}, 
+    {0xc0a80000}, {0xc0a82000}, {0xc0a84000}, {0xc0a86000}, 
+    {0xc0a88000}, {0xc0a8a000}, {0xc0a8c000}, {0xc0a8e000}, 
+    {0xc0a90000}, {0xc0a92000}, {0xc0a94000}, {0xc0a96000}, 
+    {0xc0a98000}, {0xc0a9a000}, {0xc0a9c000}, {0xc0a9e000}, 
+    {0xc0aa0000}, {0xc0aa2000}, {0xc0aa4000}, {0xc0aa6000}, 
+    {0xc0aa8000}, {0xc0aaa000}, {0xc0aac000}, {0xc0aae000}, 
+    {0xc0ab0000}, {0xc0ab2000}, {0xc0ab4000}, {0xc0ab6000}, 
+    {0xc0ab8000}, {0xc0aba000}, {0xc0abc000}, {0xc0abe000}, 
+    {0xc0ac0000}, {0xc0ac2000}, {0xc0ac4000}, {0xc0ac6000}, 
+    {0xc0ac8000}, {0xc0aca000}, {0xc0acc000}, {0xc0ace000}, 
+    {0xc0ad0000}, {0xc0ad2000}, {0xc0ad4000}, {0xc0ad6000}, 
+    {0xc0ad8000}, {0xc0ada000}, {0xc0adc000}, {0xc0ade000}, 
+    {0xc0ae0000}, {0xc0ae2000}, {0xc0ae4000}, {0xc0ae6000}, 
+    {0xc0ae8000}, {0xc0aea000}, {0xc0aec000}, {0xc0aee000}, 
+    {0xc0af0000}, {0xc0af2000}, {0xc0af4000}, {0xc0af6000}, 
+    {0xc0af8000}, {0xc0afa000}, {0xc0afc000}, {0xc0afe000}, 
+    {0xc0b00000}, {0xc0b02000}, {0xc0b04000}, {0xc0b06000}, 
+    {0xc0b08000}, {0xc0b0a000}, {0xc0b0c000}, {0xc0b0e000}, 
+    {0xc0b10000}, {0xc0b12000}, {0xc0b14000}, {0xc0b16000}, 
+    {0xc0b18000}, {0xc0b1a000}, {0xc0b1c000}, {0xc0b1e000}, 
+    {0xc0b20000}, {0xc0b22000}, {0xc0b24000}, {0xc0b26000}, 
+    {0xc0b28000}, {0xc0b2a000}, {0xc0b2c000}, {0xc0b2e000}, 
+    {0xc0b30000}, {0xc0b32000}, {0xc0b34000}, {0xc0b36000}, 
+    {0xc0b38000}, {0xc0b3a000}, {0xc0b3c000}, {0xc0b3e000}, 
+    {0xc0b40000}, {0xc0b42000}, {0xc0b44000}, {0xc0b46000}, 
+    {0xc0b48000}, {0xc0b4a000}, {0xc0b4c000}, {0xc0b4e000}, 
+    {0xc0b50000}, {0xc0b52000}, {0xc0b54000}, {0xc0b56000}, 
+    {0xc0b58000}, {0xc0b5a000}, {0xc0b5c000}, {0xc0b5e000}, 
+    {0xc0b60000}, {0xc0b62000}, {0xc0b64000}, {0xc0b66000}, 
+    {0xc0b68000}, {0xc0b6a000}, {0xc0b6c000}, {0xc0b6e000}, 
+    {0xc0b70000}, {0xc0b72000}, {0xc0b74000}, {0xc0b76000}, 
+    {0xc0b78000}, {0xc0b7a000}, {0xc0b7c000}, {0xc0b7e000}, 
+    {0xc0b80000}, {0xc0b82000}, {0xc0b84000}, {0xc0b86000}, 
+    {0xc0b88000}, {0xc0b8a000}, {0xc0b8c000}, {0xc0b8e000}, 
+    {0xc0b90000}, {0xc0b92000}, {0xc0b94000}, {0xc0b96000}, 
+    {0xc0b98000}, {0xc0b9a000}, {0xc0b9c000}, {0xc0b9e000}, 
+    {0xc0ba0000}, {0xc0ba2000}, {0xc0ba4000}, {0xc0ba6000}, 
+    {0xc0ba8000}, {0xc0baa000}, {0xc0bac000}, {0xc0bae000}, 
+    {0xc0bb0000}, {0xc0bb2000}, {0xc0bb4000}, {0xc0bb6000}, 
+    {0xc0bb8000}, {0xc0bba000}, {0xc0bbc000}, {0xc0bbe000}, 
+    {0xc0bc0000}, {0xc0bc2000}, {0xc0bc4000}, {0xc0bc6000}, 
+    {0xc0bc8000}, {0xc0bca000}, {0xc0bcc000}, {0xc0bce000}, 
+    {0xc0bd0000}, {0xc0bd2000}, {0xc0bd4000}, {0xc0bd6000}, 
+    {0xc0bd8000}, {0xc0bda000}, {0xc0bdc000}, {0xc0bde000}, 
+    {0xc0be0000}, {0xc0be2000}, {0xc0be4000}, {0xc0be6000}, 
+    {0xc0be8000}, {0xc0bea000}, {0xc0bec000}, {0xc0bee000}, 
+    {0xc0bf0000}, {0xc0bf2000}, {0xc0bf4000}, {0xc0bf6000}, 
+    {0xc0bf8000}, {0xc0bfa000}, {0xc0bfc000}, {0xc0bfe000}, 
+    {0xc0c00000}, {0xc0c02000}, {0xc0c04000}, {0xc0c06000}, 
+    {0xc0c08000}, {0xc0c0a000}, {0xc0c0c000}, {0xc0c0e000}, 
+    {0xc0c10000}, {0xc0c12000}, {0xc0c14000}, {0xc0c16000}, 
+    {0xc0c18000}, {0xc0c1a000}, {0xc0c1c000}, {0xc0c1e000}, 
+    {0xc0c20000}, {0xc0c22000}, {0xc0c24000}, {0xc0c26000}, 
+    {0xc0c28000}, {0xc0c2a000}, {0xc0c2c000}, {0xc0c2e000}, 
+    {0xc0c30000}, {0xc0c32000}, {0xc0c34000}, {0xc0c36000}, 
+    {0xc0c38000}, {0xc0c3a000}, {0xc0c3c000}, {0xc0c3e000}, 
+    {0xc0c40000}, {0xc0c42000}, {0xc0c44000}, {0xc0c46000}, 
+    {0xc0c48000}, {0xc0c4a000}, {0xc0c4c000}, {0xc0c4e000}, 
+    {0xc0c50000}, {0xc0c52000}, {0xc0c54000}, {0xc0c56000}, 
+    {0xc0c58000}, {0xc0c5a000}, {0xc0c5c000}, {0xc0c5e000}, 
+    {0xc0c60000}, {0xc0c62000}, {0xc0c64000}, {0xc0c66000}, 
+    {0xc0c68000}, {0xc0c6a000}, {0xc0c6c000}, {0xc0c6e000}, 
+    {0xc0c70000}, {0xc0c72000}, {0xc0c74000}, {0xc0c76000}, 
+    {0xc0c78000}, {0xc0c7a000}, {0xc0c7c000}, {0xc0c7e000}, 
+    {0xc0c80000}, {0xc0c82000}, {0xc0c84000}, {0xc0c86000}, 
+    {0xc0c88000}, {0xc0c8a000}, {0xc0c8c000}, {0xc0c8e000}, 
+    {0xc0c90000}, {0xc0c92000}, {0xc0c94000}, {0xc0c96000}, 
+    {0xc0c98000}, {0xc0c9a000}, {0xc0c9c000}, {0xc0c9e000}, 
+    {0xc0ca0000}, {0xc0ca2000}, {0xc0ca4000}, {0xc0ca6000}, 
+    {0xc0ca8000}, {0xc0caa000}, {0xc0cac000}, {0xc0cae000}, 
+    {0xc0cb0000}, {0xc0cb2000}, {0xc0cb4000}, {0xc0cb6000}, 
+    {0xc0cb8000}, {0xc0cba000}, {0xc0cbc000}, {0xc0cbe000}, 
+    {0xc0cc0000}, {0xc0cc2000}, {0xc0cc4000}, {0xc0cc6000}, 
+    {0xc0cc8000}, {0xc0cca000}, {0xc0ccc000}, {0xc0cce000}, 
+    {0xc0cd0000}, {0xc0cd2000}, {0xc0cd4000}, {0xc0cd6000}, 
+    {0xc0cd8000}, {0xc0cda000}, {0xc0cdc000}, {0xc0cde000}, 
+    {0xc0ce0000}, {0xc0ce2000}, {0xc0ce4000}, {0xc0ce6000}, 
+    {0xc0ce8000}, {0xc0cea000}, {0xc0cec000}, {0xc0cee000}, 
+    {0xc0cf0000}, {0xc0cf2000}, {0xc0cf4000}, {0xc0cf6000}, 
+    {0xc0cf8000}, {0xc0cfa000}, {0xc0cfc000}, {0xc0cfe000}, 
+    {0xc0d00000}, {0xc0d02000}, {0xc0d04000}, {0xc0d06000}, 
+    {0xc0d08000}, {0xc0d0a000}, {0xc0d0c000}, {0xc0d0e000}, 
+    {0xc0d10000}, {0xc0d12000}, {0xc0d14000}, {0xc0d16000}, 
+    {0xc0d18000}, {0xc0d1a000}, {0xc0d1c000}, {0xc0d1e000}, 
+    {0xc0d20000}, {0xc0d22000}, {0xc0d24000}, {0xc0d26000}, 
+    {0xc0d28000}, {0xc0d2a000}, {0xc0d2c000}, {0xc0d2e000}, 
+    {0xc0d30000}, {0xc0d32000}, {0xc0d34000}, {0xc0d36000}, 
+    {0xc0d38000}, {0xc0d3a000}, {0xc0d3c000}, {0xc0d3e000}, 
+    {0xc0d40000}, {0xc0d42000}, {0xc0d44000}, {0xc0d46000}, 
+    {0xc0d48000}, {0xc0d4a000}, {0xc0d4c000}, {0xc0d4e000}, 
+    {0xc0d50000}, {0xc0d52000}, {0xc0d54000}, {0xc0d56000}, 
+    {0xc0d58000}, {0xc0d5a000}, {0xc0d5c000}, {0xc0d5e000}, 
+    {0xc0d60000}, {0xc0d62000}, {0xc0d64000}, {0xc0d66000}, 
+    {0xc0d68000}, {0xc0d6a000}, {0xc0d6c000}, {0xc0d6e000}, 
+    {0xc0d70000}, {0xc0d72000}, {0xc0d74000}, {0xc0d76000}, 
+    {0xc0d78000}, {0xc0d7a000}, {0xc0d7c000}, {0xc0d7e000}, 
+    {0xc0d80000}, {0xc0d82000}, {0xc0d84000}, {0xc0d86000}, 
+    {0xc0d88000}, {0xc0d8a000}, {0xc0d8c000}, {0xc0d8e000}, 
+    {0xc0d90000}, {0xc0d92000}, {0xc0d94000}, {0xc0d96000}, 
+    {0xc0d98000}, {0xc0d9a000}, {0xc0d9c000}, {0xc0d9e000}, 
+    {0xc0da0000}, {0xc0da2000}, {0xc0da4000}, {0xc0da6000}, 
+    {0xc0da8000}, {0xc0daa000}, {0xc0dac000}, {0xc0dae000}, 
+    {0xc0db0000}, {0xc0db2000}, {0xc0db4000}, {0xc0db6000}, 
+    {0xc0db8000}, {0xc0dba000}, {0xc0dbc000}, {0xc0dbe000}, 
+    {0xc0dc0000}, {0xc0dc2000}, {0xc0dc4000}, {0xc0dc6000}, 
+    {0xc0dc8000}, {0xc0dca000}, {0xc0dcc000}, {0xc0dce000}, 
+    {0xc0dd0000}, {0xc0dd2000}, {0xc0dd4000}, {0xc0dd6000}, 
+    {0xc0dd8000}, {0xc0dda000}, {0xc0ddc000}, {0xc0dde000}, 
+    {0xc0de0000}, {0xc0de2000}, {0xc0de4000}, {0xc0de6000}, 
+    {0xc0de8000}, {0xc0dea000}, {0xc0dec000}, {0xc0dee000}, 
+    {0xc0df0000}, {0xc0df2000}, {0xc0df4000}, {0xc0df6000}, 
+    {0xc0df8000}, {0xc0dfa000}, {0xc0dfc000}, {0xc0dfe000}, 
+    {0xc0e00000}, {0xc0e02000}, {0xc0e04000}, {0xc0e06000}, 
+    {0xc0e08000}, {0xc0e0a000}, {0xc0e0c000}, {0xc0e0e000}, 
+    {0xc0e10000}, {0xc0e12000}, {0xc0e14000}, {0xc0e16000}, 
+    {0xc0e18000}, {0xc0e1a000}, {0xc0e1c000}, {0xc0e1e000}, 
+    {0xc0e20000}, {0xc0e22000}, {0xc0e24000}, {0xc0e26000}, 
+    {0xc0e28000}, {0xc0e2a000}, {0xc0e2c000}, {0xc0e2e000}, 
+    {0xc0e30000}, {0xc0e32000}, {0xc0e34000}, {0xc0e36000}, 
+    {0xc0e38000}, {0xc0e3a000}, {0xc0e3c000}, {0xc0e3e000}, 
+    {0xc0e40000}, {0xc0e42000}, {0xc0e44000}, {0xc0e46000}, 
+    {0xc0e48000}, {0xc0e4a000}, {0xc0e4c000}, {0xc0e4e000}, 
+    {0xc0e50000}, {0xc0e52000}, {0xc0e54000}, {0xc0e56000}, 
+    {0xc0e58000}, {0xc0e5a000}, {0xc0e5c000}, {0xc0e5e000}, 
+    {0xc0e60000}, {0xc0e62000}, {0xc0e64000}, {0xc0e66000}, 
+    {0xc0e68000}, {0xc0e6a000}, {0xc0e6c000}, {0xc0e6e000}, 
+    {0xc0e70000}, {0xc0e72000}, {0xc0e74000}, {0xc0e76000}, 
+    {0xc0e78000}, {0xc0e7a000}, {0xc0e7c000}, {0xc0e7e000}, 
+    {0xc0e80000}, {0xc0e82000}, {0xc0e84000}, {0xc0e86000}, 
+    {0xc0e88000}, {0xc0e8a000}, {0xc0e8c000}, {0xc0e8e000}, 
+    {0xc0e90000}, {0xc0e92000}, {0xc0e94000}, {0xc0e96000}, 
+    {0xc0e98000}, {0xc0e9a000}, {0xc0e9c000}, {0xc0e9e000}, 
+    {0xc0ea0000}, {0xc0ea2000}, {0xc0ea4000}, {0xc0ea6000}, 
+    {0xc0ea8000}, {0xc0eaa000}, {0xc0eac000}, {0xc0eae000}, 
+    {0xc0eb0000}, {0xc0eb2000}, {0xc0eb4000}, {0xc0eb6000}, 
+    {0xc0eb8000}, {0xc0eba000}, {0xc0ebc000}, {0xc0ebe000}, 
+    {0xc0ec0000}, {0xc0ec2000}, {0xc0ec4000}, {0xc0ec6000}, 
+    {0xc0ec8000}, {0xc0eca000}, {0xc0ecc000}, {0xc0ece000}, 
+    {0xc0ed0000}, {0xc0ed2000}, {0xc0ed4000}, {0xc0ed6000}, 
+    {0xc0ed8000}, {0xc0eda000}, {0xc0edc000}, {0xc0ede000}, 
+    {0xc0ee0000}, {0xc0ee2000}, {0xc0ee4000}, {0xc0ee6000}, 
+    {0xc0ee8000}, {0xc0eea000}, {0xc0eec000}, {0xc0eee000}, 
+    {0xc0ef0000}, {0xc0ef2000}, {0xc0ef4000}, {0xc0ef6000}, 
+    {0xc0ef8000}, {0xc0efa000}, {0xc0efc000}, {0xc0efe000}, 
+    {0xc0f00000}, {0xc0f02000}, {0xc0f04000}, {0xc0f06000}, 
+    {0xc0f08000}, {0xc0f0a000}, {0xc0f0c000}, {0xc0f0e000}, 
+    {0xc0f10000}, {0xc0f12000}, {0xc0f14000}, {0xc0f16000}, 
+    {0xc0f18000}, {0xc0f1a000}, {0xc0f1c000}, {0xc0f1e000}, 
+    {0xc0f20000}, {0xc0f22000}, {0xc0f24000}, {0xc0f26000}, 
+    {0xc0f28000}, {0xc0f2a000}, {0xc0f2c000}, {0xc0f2e000}, 
+    {0xc0f30000}, {0xc0f32000}, {0xc0f34000}, {0xc0f36000}, 
+    {0xc0f38000}, {0xc0f3a000}, {0xc0f3c000}, {0xc0f3e000}, 
+    {0xc0f40000}, {0xc0f42000}, {0xc0f44000}, {0xc0f46000}, 
+    {0xc0f48000}, {0xc0f4a000}, {0xc0f4c000}, {0xc0f4e000}, 
+    {0xc0f50000}, {0xc0f52000}, {0xc0f54000}, {0xc0f56000}, 
+    {0xc0f58000}, {0xc0f5a000}, {0xc0f5c000}, {0xc0f5e000}, 
+    {0xc0f60000}, {0xc0f62000}, {0xc0f64000}, {0xc0f66000}, 
+    {0xc0f68000}, {0xc0f6a000}, {0xc0f6c000}, {0xc0f6e000}, 
+    {0xc0f70000}, {0xc0f72000}, {0xc0f74000}, {0xc0f76000}, 
+    {0xc0f78000}, {0xc0f7a000}, {0xc0f7c000}, {0xc0f7e000}, 
+    {0xc0f80000}, {0xc0f82000}, {0xc0f84000}, {0xc0f86000}, 
+    {0xc0f88000}, {0xc0f8a000}, {0xc0f8c000}, {0xc0f8e000}, 
+    {0xc0f90000}, {0xc0f92000}, {0xc0f94000}, {0xc0f96000}, 
+    {0xc0f98000}, {0xc0f9a000}, {0xc0f9c000}, {0xc0f9e000}, 
+    {0xc0fa0000}, {0xc0fa2000}, {0xc0fa4000}, {0xc0fa6000}, 
+    {0xc0fa8000}, {0xc0faa000}, {0xc0fac000}, {0xc0fae000}, 
+    {0xc0fb0000}, {0xc0fb2000}, {0xc0fb4000}, {0xc0fb6000}, 
+    {0xc0fb8000}, {0xc0fba000}, {0xc0fbc000}, {0xc0fbe000}, 
+    {0xc0fc0000}, {0xc0fc2000}, {0xc0fc4000}, {0xc0fc6000}, 
+    {0xc0fc8000}, {0xc0fca000}, {0xc0fcc000}, {0xc0fce000}, 
+    {0xc0fd0000}, {0xc0fd2000}, {0xc0fd4000}, {0xc0fd6000}, 
+    {0xc0fd8000}, {0xc0fda000}, {0xc0fdc000}, {0xc0fde000}, 
+    {0xc0fe0000}, {0xc0fe2000}, {0xc0fe4000}, {0xc0fe6000}, 
+    {0xc0fe8000}, {0xc0fea000}, {0xc0fec000}, {0xc0fee000}, 
+    {0xc0ff0000}, {0xc0ff2000}, {0xc0ff4000}, {0xc0ff6000}, 
+    {0xc0ff8000}, {0xc0ffa000}, {0xc0ffc000}, {0xc0ffe000}, 
+    {0xc1000000}, {0xc1002000}, {0xc1004000}, {0xc1006000}, 
+    {0xc1008000}, {0xc100a000}, {0xc100c000}, {0xc100e000}, 
+    {0xc1010000}, {0xc1012000}, {0xc1014000}, {0xc1016000}, 
+    {0xc1018000}, {0xc101a000}, {0xc101c000}, {0xc101e000}, 
+    {0xc1020000}, {0xc1022000}, {0xc1024000}, {0xc1026000}, 
+    {0xc1028000}, {0xc102a000}, {0xc102c000}, {0xc102e000}, 
+    {0xc1030000}, {0xc1032000}, {0xc1034000}, {0xc1036000}, 
+    {0xc1038000}, {0xc103a000}, {0xc103c000}, {0xc103e000}, 
+    {0xc1040000}, {0xc1042000}, {0xc1044000}, {0xc1046000}, 
+    {0xc1048000}, {0xc104a000}, {0xc104c000}, {0xc104e000}, 
+    {0xc1050000}, {0xc1052000}, {0xc1054000}, {0xc1056000}, 
+    {0xc1058000}, {0xc105a000}, {0xc105c000}, {0xc105e000}, 
+    {0xc1060000}, {0xc1062000}, {0xc1064000}, {0xc1066000}, 
+    {0xc1068000}, {0xc106a000}, {0xc106c000}, {0xc106e000}, 
+    {0xc1070000}, {0xc1072000}, {0xc1074000}, {0xc1076000}, 
+    {0xc1078000}, {0xc107a000}, {0xc107c000}, {0xc107e000}, 
+    {0xc1080000}, {0xc1082000}, {0xc1084000}, {0xc1086000}, 
+    {0xc1088000}, {0xc108a000}, {0xc108c000}, {0xc108e000}, 
+    {0xc1090000}, {0xc1092000}, {0xc1094000}, {0xc1096000}, 
+    {0xc1098000}, {0xc109a000}, {0xc109c000}, {0xc109e000}, 
+    {0xc10a0000}, {0xc10a2000}, {0xc10a4000}, {0xc10a6000}, 
+    {0xc10a8000}, {0xc10aa000}, {0xc10ac000}, {0xc10ae000}, 
+    {0xc10b0000}, {0xc10b2000}, {0xc10b4000}, {0xc10b6000}, 
+    {0xc10b8000}, {0xc10ba000}, {0xc10bc000}, {0xc10be000}, 
+    {0xc10c0000}, {0xc10c2000}, {0xc10c4000}, {0xc10c6000}, 
+    {0xc10c8000}, {0xc10ca000}, {0xc10cc000}, {0xc10ce000}, 
+    {0xc10d0000}, {0xc10d2000}, {0xc10d4000}, {0xc10d6000}, 
+    {0xc10d8000}, {0xc10da000}, {0xc10dc000}, {0xc10de000}, 
+    {0xc10e0000}, {0xc10e2000}, {0xc10e4000}, {0xc10e6000}, 
+    {0xc10e8000}, {0xc10ea000}, {0xc10ec000}, {0xc10ee000}, 
+    {0xc10f0000}, {0xc10f2000}, {0xc10f4000}, {0xc10f6000}, 
+    {0xc10f8000}, {0xc10fa000}, {0xc10fc000}, {0xc10fe000}, 
+    {0xc1100000}, {0xc1102000}, {0xc1104000}, {0xc1106000}, 
+    {0xc1108000}, {0xc110a000}, {0xc110c000}, {0xc110e000}, 
+    {0xc1110000}, {0xc1112000}, {0xc1114000}, {0xc1116000}, 
+    {0xc1118000}, {0xc111a000}, {0xc111c000}, {0xc111e000}, 
+    {0xc1120000}, {0xc1122000}, {0xc1124000}, {0xc1126000}, 
+    {0xc1128000}, {0xc112a000}, {0xc112c000}, {0xc112e000}, 
+    {0xc1130000}, {0xc1132000}, {0xc1134000}, {0xc1136000}, 
+    {0xc1138000}, {0xc113a000}, {0xc113c000}, {0xc113e000}, 
+    {0xc1140000}, {0xc1142000}, {0xc1144000}, {0xc1146000}, 
+    {0xc1148000}, {0xc114a000}, {0xc114c000}, {0xc114e000}, 
+    {0xc1150000}, {0xc1152000}, {0xc1154000}, {0xc1156000}, 
+    {0xc1158000}, {0xc115a000}, {0xc115c000}, {0xc115e000}, 
+    {0xc1160000}, {0xc1162000}, {0xc1164000}, {0xc1166000}, 
+    {0xc1168000}, {0xc116a000}, {0xc116c000}, {0xc116e000}, 
+    {0xc1170000}, {0xc1172000}, {0xc1174000}, {0xc1176000}, 
+    {0xc1178000}, {0xc117a000}, {0xc117c000}, {0xc117e000}, 
+    {0xc1180000}, {0xc1182000}, {0xc1184000}, {0xc1186000}, 
+    {0xc1188000}, {0xc118a000}, {0xc118c000}, {0xc118e000}, 
+    {0xc1190000}, {0xc1192000}, {0xc1194000}, {0xc1196000}, 
+    {0xc1198000}, {0xc119a000}, {0xc119c000}, {0xc119e000}, 
+    {0xc11a0000}, {0xc11a2000}, {0xc11a4000}, {0xc11a6000}, 
+    {0xc11a8000}, {0xc11aa000}, {0xc11ac000}, {0xc11ae000}, 
+    {0xc11b0000}, {0xc11b2000}, {0xc11b4000}, {0xc11b6000}, 
+    {0xc11b8000}, {0xc11ba000}, {0xc11bc000}, {0xc11be000}, 
+    {0xc11c0000}, {0xc11c2000}, {0xc11c4000}, {0xc11c6000}, 
+    {0xc11c8000}, {0xc11ca000}, {0xc11cc000}, {0xc11ce000}, 
+    {0xc11d0000}, {0xc11d2000}, {0xc11d4000}, {0xc11d6000}, 
+    {0xc11d8000}, {0xc11da000}, {0xc11dc000}, {0xc11de000}, 
+    {0xc11e0000}, {0xc11e2000}, {0xc11e4000}, {0xc11e6000}, 
+    {0xc11e8000}, {0xc11ea000}, {0xc11ec000}, {0xc11ee000}, 
+    {0xc11f0000}, {0xc11f2000}, {0xc11f4000}, {0xc11f6000}, 
+    {0xc11f8000}, {0xc11fa000}, {0xc11fc000}, {0xc11fe000}, 
+    {0xc1200000}, {0xc1202000}, {0xc1204000}, {0xc1206000}, 
+    {0xc1208000}, {0xc120a000}, {0xc120c000}, {0xc120e000}, 
+    {0xc1210000}, {0xc1212000}, {0xc1214000}, {0xc1216000}, 
+    {0xc1218000}, {0xc121a000}, {0xc121c000}, {0xc121e000}, 
+    {0xc1220000}, {0xc1222000}, {0xc1224000}, {0xc1226000}, 
+    {0xc1228000}, {0xc122a000}, {0xc122c000}, {0xc122e000}, 
+    {0xc1230000}, {0xc1232000}, {0xc1234000}, {0xc1236000}, 
+    {0xc1238000}, {0xc123a000}, {0xc123c000}, {0xc123e000}, 
+    {0xc1240000}, {0xc1242000}, {0xc1244000}, {0xc1246000}, 
+    {0xc1248000}, {0xc124a000}, {0xc124c000}, {0xc124e000}, 
+    {0xc1250000}, {0xc1252000}, {0xc1254000}, {0xc1256000}, 
+    {0xc1258000}, {0xc125a000}, {0xc125c000}, {0xc125e000}, 
+    {0xc1260000}, {0xc1262000}, {0xc1264000}, {0xc1266000}, 
+    {0xc1268000}, {0xc126a000}, {0xc126c000}, {0xc126e000}, 
+    {0xc1270000}, {0xc1272000}, {0xc1274000}, {0xc1276000}, 
+    {0xc1278000}, {0xc127a000}, {0xc127c000}, {0xc127e000}, 
+    {0xc1280000}, {0xc1282000}, {0xc1284000}, {0xc1286000}, 
+    {0xc1288000}, {0xc128a000}, {0xc128c000}, {0xc128e000}, 
+    {0xc1290000}, {0xc1292000}, {0xc1294000}, {0xc1296000}, 
+    {0xc1298000}, {0xc129a000}, {0xc129c000}, {0xc129e000}, 
+    {0xc12a0000}, {0xc12a2000}, {0xc12a4000}, {0xc12a6000}, 
+    {0xc12a8000}, {0xc12aa000}, {0xc12ac000}, {0xc12ae000}, 
+    {0xc12b0000}, {0xc12b2000}, {0xc12b4000}, {0xc12b6000}, 
+    {0xc12b8000}, {0xc12ba000}, {0xc12bc000}, {0xc12be000}, 
+    {0xc12c0000}, {0xc12c2000}, {0xc12c4000}, {0xc12c6000}, 
+    {0xc12c8000}, {0xc12ca000}, {0xc12cc000}, {0xc12ce000}, 
+    {0xc12d0000}, {0xc12d2000}, {0xc12d4000}, {0xc12d6000}, 
+    {0xc12d8000}, {0xc12da000}, {0xc12dc000}, {0xc12de000}, 
+    {0xc12e0000}, {0xc12e2000}, {0xc12e4000}, {0xc12e6000}, 
+    {0xc12e8000}, {0xc12ea000}, {0xc12ec000}, {0xc12ee000}, 
+    {0xc12f0000}, {0xc12f2000}, {0xc12f4000}, {0xc12f6000}, 
+    {0xc12f8000}, {0xc12fa000}, {0xc12fc000}, {0xc12fe000}, 
+    {0xc1300000}, {0xc1302000}, {0xc1304000}, {0xc1306000}, 
+    {0xc1308000}, {0xc130a000}, {0xc130c000}, {0xc130e000}, 
+    {0xc1310000}, {0xc1312000}, {0xc1314000}, {0xc1316000}, 
+    {0xc1318000}, {0xc131a000}, {0xc131c000}, {0xc131e000}, 
+    {0xc1320000}, {0xc1322000}, {0xc1324000}, {0xc1326000}, 
+    {0xc1328000}, {0xc132a000}, {0xc132c000}, {0xc132e000}, 
+    {0xc1330000}, {0xc1332000}, {0xc1334000}, {0xc1336000}, 
+    {0xc1338000}, {0xc133a000}, {0xc133c000}, {0xc133e000}, 
+    {0xc1340000}, {0xc1342000}, {0xc1344000}, {0xc1346000}, 
+    {0xc1348000}, {0xc134a000}, {0xc134c000}, {0xc134e000}, 
+    {0xc1350000}, {0xc1352000}, {0xc1354000}, {0xc1356000}, 
+    {0xc1358000}, {0xc135a000}, {0xc135c000}, {0xc135e000}, 
+    {0xc1360000}, {0xc1362000}, {0xc1364000}, {0xc1366000}, 
+    {0xc1368000}, {0xc136a000}, {0xc136c000}, {0xc136e000}, 
+    {0xc1370000}, {0xc1372000}, {0xc1374000}, {0xc1376000}, 
+    {0xc1378000}, {0xc137a000}, {0xc137c000}, {0xc137e000}, 
+    {0xc1380000}, {0xc1382000}, {0xc1384000}, {0xc1386000}, 
+    {0xc1388000}, {0xc138a000}, {0xc138c000}, {0xc138e000}, 
+    {0xc1390000}, {0xc1392000}, {0xc1394000}, {0xc1396000}, 
+    {0xc1398000}, {0xc139a000}, {0xc139c000}, {0xc139e000}, 
+    {0xc13a0000}, {0xc13a2000}, {0xc13a4000}, {0xc13a6000}, 
+    {0xc13a8000}, {0xc13aa000}, {0xc13ac000}, {0xc13ae000}, 
+    {0xc13b0000}, {0xc13b2000}, {0xc13b4000}, {0xc13b6000}, 
+    {0xc13b8000}, {0xc13ba000}, {0xc13bc000}, {0xc13be000}, 
+    {0xc13c0000}, {0xc13c2000}, {0xc13c4000}, {0xc13c6000}, 
+    {0xc13c8000}, {0xc13ca000}, {0xc13cc000}, {0xc13ce000}, 
+    {0xc13d0000}, {0xc13d2000}, {0xc13d4000}, {0xc13d6000}, 
+    {0xc13d8000}, {0xc13da000}, {0xc13dc000}, {0xc13de000}, 
+    {0xc13e0000}, {0xc13e2000}, {0xc13e4000}, {0xc13e6000}, 
+    {0xc13e8000}, {0xc13ea000}, {0xc13ec000}, {0xc13ee000}, 
+    {0xc13f0000}, {0xc13f2000}, {0xc13f4000}, {0xc13f6000}, 
+    {0xc13f8000}, {0xc13fa000}, {0xc13fc000}, {0xc13fe000}, 
+    {0xc1400000}, {0xc1402000}, {0xc1404000}, {0xc1406000}, 
+    {0xc1408000}, {0xc140a000}, {0xc140c000}, {0xc140e000}, 
+    {0xc1410000}, {0xc1412000}, {0xc1414000}, {0xc1416000}, 
+    {0xc1418000}, {0xc141a000}, {0xc141c000}, {0xc141e000}, 
+    {0xc1420000}, {0xc1422000}, {0xc1424000}, {0xc1426000}, 
+    {0xc1428000}, {0xc142a000}, {0xc142c000}, {0xc142e000}, 
+    {0xc1430000}, {0xc1432000}, {0xc1434000}, {0xc1436000}, 
+    {0xc1438000}, {0xc143a000}, {0xc143c000}, {0xc143e000}, 
+    {0xc1440000}, {0xc1442000}, {0xc1444000}, {0xc1446000}, 
+    {0xc1448000}, {0xc144a000}, {0xc144c000}, {0xc144e000}, 
+    {0xc1450000}, {0xc1452000}, {0xc1454000}, {0xc1456000}, 
+    {0xc1458000}, {0xc145a000}, {0xc145c000}, {0xc145e000}, 
+    {0xc1460000}, {0xc1462000}, {0xc1464000}, {0xc1466000}, 
+    {0xc1468000}, {0xc146a000}, {0xc146c000}, {0xc146e000}, 
+    {0xc1470000}, {0xc1472000}, {0xc1474000}, {0xc1476000}, 
+    {0xc1478000}, {0xc147a000}, {0xc147c000}, {0xc147e000}, 
+    {0xc1480000}, {0xc1482000}, {0xc1484000}, {0xc1486000}, 
+    {0xc1488000}, {0xc148a000}, {0xc148c000}, {0xc148e000}, 
+    {0xc1490000}, {0xc1492000}, {0xc1494000}, {0xc1496000}, 
+    {0xc1498000}, {0xc149a000}, {0xc149c000}, {0xc149e000}, 
+    {0xc14a0000}, {0xc14a2000}, {0xc14a4000}, {0xc14a6000}, 
+    {0xc14a8000}, {0xc14aa000}, {0xc14ac000}, {0xc14ae000}, 
+    {0xc14b0000}, {0xc14b2000}, {0xc14b4000}, {0xc14b6000}, 
+    {0xc14b8000}, {0xc14ba000}, {0xc14bc000}, {0xc14be000}, 
+    {0xc14c0000}, {0xc14c2000}, {0xc14c4000}, {0xc14c6000}, 
+    {0xc14c8000}, {0xc14ca000}, {0xc14cc000}, {0xc14ce000}, 
+    {0xc14d0000}, {0xc14d2000}, {0xc14d4000}, {0xc14d6000}, 
+    {0xc14d8000}, {0xc14da000}, {0xc14dc000}, {0xc14de000}, 
+    {0xc14e0000}, {0xc14e2000}, {0xc14e4000}, {0xc14e6000}, 
+    {0xc14e8000}, {0xc14ea000}, {0xc14ec000}, {0xc14ee000}, 
+    {0xc14f0000}, {0xc14f2000}, {0xc14f4000}, {0xc14f6000}, 
+    {0xc14f8000}, {0xc14fa000}, {0xc14fc000}, {0xc14fe000}, 
+    {0xc1500000}, {0xc1502000}, {0xc1504000}, {0xc1506000}, 
+    {0xc1508000}, {0xc150a000}, {0xc150c000}, {0xc150e000}, 
+    {0xc1510000}, {0xc1512000}, {0xc1514000}, {0xc1516000}, 
+    {0xc1518000}, {0xc151a000}, {0xc151c000}, {0xc151e000}, 
+    {0xc1520000}, {0xc1522000}, {0xc1524000}, {0xc1526000}, 
+    {0xc1528000}, {0xc152a000}, {0xc152c000}, {0xc152e000}, 
+    {0xc1530000}, {0xc1532000}, {0xc1534000}, {0xc1536000}, 
+    {0xc1538000}, {0xc153a000}, {0xc153c000}, {0xc153e000}, 
+    {0xc1540000}, {0xc1542000}, {0xc1544000}, {0xc1546000}, 
+    {0xc1548000}, {0xc154a000}, {0xc154c000}, {0xc154e000}, 
+    {0xc1550000}, {0xc1552000}, {0xc1554000}, {0xc1556000}, 
+    {0xc1558000}, {0xc155a000}, {0xc155c000}, {0xc155e000}, 
+    {0xc1560000}, {0xc1562000}, {0xc1564000}, {0xc1566000}, 
+    {0xc1568000}, {0xc156a000}, {0xc156c000}, {0xc156e000}, 
+    {0xc1570000}, {0xc1572000}, {0xc1574000}, {0xc1576000}, 
+    {0xc1578000}, {0xc157a000}, {0xc157c000}, {0xc157e000}, 
+    {0xc1580000}, {0xc1582000}, {0xc1584000}, {0xc1586000}, 
+    {0xc1588000}, {0xc158a000}, {0xc158c000}, {0xc158e000}, 
+    {0xc1590000}, {0xc1592000}, {0xc1594000}, {0xc1596000}, 
+    {0xc1598000}, {0xc159a000}, {0xc159c000}, {0xc159e000}, 
+    {0xc15a0000}, {0xc15a2000}, {0xc15a4000}, {0xc15a6000}, 
+    {0xc15a8000}, {0xc15aa000}, {0xc15ac000}, {0xc15ae000}, 
+    {0xc15b0000}, {0xc15b2000}, {0xc15b4000}, {0xc15b6000}, 
+    {0xc15b8000}, {0xc15ba000}, {0xc15bc000}, {0xc15be000}, 
+    {0xc15c0000}, {0xc15c2000}, {0xc15c4000}, {0xc15c6000}, 
+    {0xc15c8000}, {0xc15ca000}, {0xc15cc000}, {0xc15ce000}, 
+    {0xc15d0000}, {0xc15d2000}, {0xc15d4000}, {0xc15d6000}, 
+    {0xc15d8000}, {0xc15da000}, {0xc15dc000}, {0xc15de000}, 
+    {0xc15e0000}, {0xc15e2000}, {0xc15e4000}, {0xc15e6000}, 
+    {0xc15e8000}, {0xc15ea000}, {0xc15ec000}, {0xc15ee000}, 
+    {0xc15f0000}, {0xc15f2000}, {0xc15f4000}, {0xc15f6000}, 
+    {0xc15f8000}, {0xc15fa000}, {0xc15fc000}, {0xc15fe000}, 
+    {0xc1600000}, {0xc1602000}, {0xc1604000}, {0xc1606000}, 
+    {0xc1608000}, {0xc160a000}, {0xc160c000}, {0xc160e000}, 
+    {0xc1610000}, {0xc1612000}, {0xc1614000}, {0xc1616000}, 
+    {0xc1618000}, {0xc161a000}, {0xc161c000}, {0xc161e000}, 
+    {0xc1620000}, {0xc1622000}, {0xc1624000}, {0xc1626000}, 
+    {0xc1628000}, {0xc162a000}, {0xc162c000}, {0xc162e000}, 
+    {0xc1630000}, {0xc1632000}, {0xc1634000}, {0xc1636000}, 
+    {0xc1638000}, {0xc163a000}, {0xc163c000}, {0xc163e000}, 
+    {0xc1640000}, {0xc1642000}, {0xc1644000}, {0xc1646000}, 
+    {0xc1648000}, {0xc164a000}, {0xc164c000}, {0xc164e000}, 
+    {0xc1650000}, {0xc1652000}, {0xc1654000}, {0xc1656000}, 
+    {0xc1658000}, {0xc165a000}, {0xc165c000}, {0xc165e000}, 
+    {0xc1660000}, {0xc1662000}, {0xc1664000}, {0xc1666000}, 
+    {0xc1668000}, {0xc166a000}, {0xc166c000}, {0xc166e000}, 
+    {0xc1670000}, {0xc1672000}, {0xc1674000}, {0xc1676000}, 
+    {0xc1678000}, {0xc167a000}, {0xc167c000}, {0xc167e000}, 
+    {0xc1680000}, {0xc1682000}, {0xc1684000}, {0xc1686000}, 
+    {0xc1688000}, {0xc168a000}, {0xc168c000}, {0xc168e000}, 
+    {0xc1690000}, {0xc1692000}, {0xc1694000}, {0xc1696000}, 
+    {0xc1698000}, {0xc169a000}, {0xc169c000}, {0xc169e000}, 
+    {0xc16a0000}, {0xc16a2000}, {0xc16a4000}, {0xc16a6000}, 
+    {0xc16a8000}, {0xc16aa000}, {0xc16ac000}, {0xc16ae000}, 
+    {0xc16b0000}, {0xc16b2000}, {0xc16b4000}, {0xc16b6000}, 
+    {0xc16b8000}, {0xc16ba000}, {0xc16bc000}, {0xc16be000}, 
+    {0xc16c0000}, {0xc16c2000}, {0xc16c4000}, {0xc16c6000}, 
+    {0xc16c8000}, {0xc16ca000}, {0xc16cc000}, {0xc16ce000}, 
+    {0xc16d0000}, {0xc16d2000}, {0xc16d4000}, {0xc16d6000}, 
+    {0xc16d8000}, {0xc16da000}, {0xc16dc000}, {0xc16de000}, 
+    {0xc16e0000}, {0xc16e2000}, {0xc16e4000}, {0xc16e6000}, 
+    {0xc16e8000}, {0xc16ea000}, {0xc16ec000}, {0xc16ee000}, 
+    {0xc16f0000}, {0xc16f2000}, {0xc16f4000}, {0xc16f6000}, 
+    {0xc16f8000}, {0xc16fa000}, {0xc16fc000}, {0xc16fe000}, 
+    {0xc1700000}, {0xc1702000}, {0xc1704000}, {0xc1706000}, 
+    {0xc1708000}, {0xc170a000}, {0xc170c000}, {0xc170e000}, 
+    {0xc1710000}, {0xc1712000}, {0xc1714000}, {0xc1716000}, 
+    {0xc1718000}, {0xc171a000}, {0xc171c000}, {0xc171e000}, 
+    {0xc1720000}, {0xc1722000}, {0xc1724000}, {0xc1726000}, 
+    {0xc1728000}, {0xc172a000}, {0xc172c000}, {0xc172e000}, 
+    {0xc1730000}, {0xc1732000}, {0xc1734000}, {0xc1736000}, 
+    {0xc1738000}, {0xc173a000}, {0xc173c000}, {0xc173e000}, 
+    {0xc1740000}, {0xc1742000}, {0xc1744000}, {0xc1746000}, 
+    {0xc1748000}, {0xc174a000}, {0xc174c000}, {0xc174e000}, 
+    {0xc1750000}, {0xc1752000}, {0xc1754000}, {0xc1756000}, 
+    {0xc1758000}, {0xc175a000}, {0xc175c000}, {0xc175e000}, 
+    {0xc1760000}, {0xc1762000}, {0xc1764000}, {0xc1766000}, 
+    {0xc1768000}, {0xc176a000}, {0xc176c000}, {0xc176e000}, 
+    {0xc1770000}, {0xc1772000}, {0xc1774000}, {0xc1776000}, 
+    {0xc1778000}, {0xc177a000}, {0xc177c000}, {0xc177e000}, 
+    {0xc1780000}, {0xc1782000}, {0xc1784000}, {0xc1786000}, 
+    {0xc1788000}, {0xc178a000}, {0xc178c000}, {0xc178e000}, 
+    {0xc1790000}, {0xc1792000}, {0xc1794000}, {0xc1796000}, 
+    {0xc1798000}, {0xc179a000}, {0xc179c000}, {0xc179e000}, 
+    {0xc17a0000}, {0xc17a2000}, {0xc17a4000}, {0xc17a6000}, 
+    {0xc17a8000}, {0xc17aa000}, {0xc17ac000}, {0xc17ae000}, 
+    {0xc17b0000}, {0xc17b2000}, {0xc17b4000}, {0xc17b6000}, 
+    {0xc17b8000}, {0xc17ba000}, {0xc17bc000}, {0xc17be000}, 
+    {0xc17c0000}, {0xc17c2000}, {0xc17c4000}, {0xc17c6000}, 
+    {0xc17c8000}, {0xc17ca000}, {0xc17cc000}, {0xc17ce000}, 
+    {0xc17d0000}, {0xc17d2000}, {0xc17d4000}, {0xc17d6000}, 
+    {0xc17d8000}, {0xc17da000}, {0xc17dc000}, {0xc17de000}, 
+    {0xc17e0000}, {0xc17e2000}, {0xc17e4000}, {0xc17e6000}, 
+    {0xc17e8000}, {0xc17ea000}, {0xc17ec000}, {0xc17ee000}, 
+    {0xc17f0000}, {0xc17f2000}, {0xc17f4000}, {0xc17f6000}, 
+    {0xc17f8000}, {0xc17fa000}, {0xc17fc000}, {0xc17fe000}, 
+    {0xc1800000}, {0xc1802000}, {0xc1804000}, {0xc1806000}, 
+    {0xc1808000}, {0xc180a000}, {0xc180c000}, {0xc180e000}, 
+    {0xc1810000}, {0xc1812000}, {0xc1814000}, {0xc1816000}, 
+    {0xc1818000}, {0xc181a000}, {0xc181c000}, {0xc181e000}, 
+    {0xc1820000}, {0xc1822000}, {0xc1824000}, {0xc1826000}, 
+    {0xc1828000}, {0xc182a000}, {0xc182c000}, {0xc182e000}, 
+    {0xc1830000}, {0xc1832000}, {0xc1834000}, {0xc1836000}, 
+    {0xc1838000}, {0xc183a000}, {0xc183c000}, {0xc183e000}, 
+    {0xc1840000}, {0xc1842000}, {0xc1844000}, {0xc1846000}, 
+    {0xc1848000}, {0xc184a000}, {0xc184c000}, {0xc184e000}, 
+    {0xc1850000}, {0xc1852000}, {0xc1854000}, {0xc1856000}, 
+    {0xc1858000}, {0xc185a000}, {0xc185c000}, {0xc185e000}, 
+    {0xc1860000}, {0xc1862000}, {0xc1864000}, {0xc1866000}, 
+    {0xc1868000}, {0xc186a000}, {0xc186c000}, {0xc186e000}, 
+    {0xc1870000}, {0xc1872000}, {0xc1874000}, {0xc1876000}, 
+    {0xc1878000}, {0xc187a000}, {0xc187c000}, {0xc187e000}, 
+    {0xc1880000}, {0xc1882000}, {0xc1884000}, {0xc1886000}, 
+    {0xc1888000}, {0xc188a000}, {0xc188c000}, {0xc188e000}, 
+    {0xc1890000}, {0xc1892000}, {0xc1894000}, {0xc1896000}, 
+    {0xc1898000}, {0xc189a000}, {0xc189c000}, {0xc189e000}, 
+    {0xc18a0000}, {0xc18a2000}, {0xc18a4000}, {0xc18a6000}, 
+    {0xc18a8000}, {0xc18aa000}, {0xc18ac000}, {0xc18ae000}, 
+    {0xc18b0000}, {0xc18b2000}, {0xc18b4000}, {0xc18b6000}, 
+    {0xc18b8000}, {0xc18ba000}, {0xc18bc000}, {0xc18be000}, 
+    {0xc18c0000}, {0xc18c2000}, {0xc18c4000}, {0xc18c6000}, 
+    {0xc18c8000}, {0xc18ca000}, {0xc18cc000}, {0xc18ce000}, 
+    {0xc18d0000}, {0xc18d2000}, {0xc18d4000}, {0xc18d6000}, 
+    {0xc18d8000}, {0xc18da000}, {0xc18dc000}, {0xc18de000}, 
+    {0xc18e0000}, {0xc18e2000}, {0xc18e4000}, {0xc18e6000}, 
+    {0xc18e8000}, {0xc18ea000}, {0xc18ec000}, {0xc18ee000}, 
+    {0xc18f0000}, {0xc18f2000}, {0xc18f4000}, {0xc18f6000}, 
+    {0xc18f8000}, {0xc18fa000}, {0xc18fc000}, {0xc18fe000}, 
+    {0xc1900000}, {0xc1902000}, {0xc1904000}, {0xc1906000}, 
+    {0xc1908000}, {0xc190a000}, {0xc190c000}, {0xc190e000}, 
+    {0xc1910000}, {0xc1912000}, {0xc1914000}, {0xc1916000}, 
+    {0xc1918000}, {0xc191a000}, {0xc191c000}, {0xc191e000}, 
+    {0xc1920000}, {0xc1922000}, {0xc1924000}, {0xc1926000}, 
+    {0xc1928000}, {0xc192a000}, {0xc192c000}, {0xc192e000}, 
+    {0xc1930000}, {0xc1932000}, {0xc1934000}, {0xc1936000}, 
+    {0xc1938000}, {0xc193a000}, {0xc193c000}, {0xc193e000}, 
+    {0xc1940000}, {0xc1942000}, {0xc1944000}, {0xc1946000}, 
+    {0xc1948000}, {0xc194a000}, {0xc194c000}, {0xc194e000}, 
+    {0xc1950000}, {0xc1952000}, {0xc1954000}, {0xc1956000}, 
+    {0xc1958000}, {0xc195a000}, {0xc195c000}, {0xc195e000}, 
+    {0xc1960000}, {0xc1962000}, {0xc1964000}, {0xc1966000}, 
+    {0xc1968000}, {0xc196a000}, {0xc196c000}, {0xc196e000}, 
+    {0xc1970000}, {0xc1972000}, {0xc1974000}, {0xc1976000}, 
+    {0xc1978000}, {0xc197a000}, {0xc197c000}, {0xc197e000}, 
+    {0xc1980000}, {0xc1982000}, {0xc1984000}, {0xc1986000}, 
+    {0xc1988000}, {0xc198a000}, {0xc198c000}, {0xc198e000}, 
+    {0xc1990000}, {0xc1992000}, {0xc1994000}, {0xc1996000}, 
+    {0xc1998000}, {0xc199a000}, {0xc199c000}, {0xc199e000}, 
+    {0xc19a0000}, {0xc19a2000}, {0xc19a4000}, {0xc19a6000}, 
+    {0xc19a8000}, {0xc19aa000}, {0xc19ac000}, {0xc19ae000}, 
+    {0xc19b0000}, {0xc19b2000}, {0xc19b4000}, {0xc19b6000}, 
+    {0xc19b8000}, {0xc19ba000}, {0xc19bc000}, {0xc19be000}, 
+    {0xc19c0000}, {0xc19c2000}, {0xc19c4000}, {0xc19c6000}, 
+    {0xc19c8000}, {0xc19ca000}, {0xc19cc000}, {0xc19ce000}, 
+    {0xc19d0000}, {0xc19d2000}, {0xc19d4000}, {0xc19d6000}, 
+    {0xc19d8000}, {0xc19da000}, {0xc19dc000}, {0xc19de000}, 
+    {0xc19e0000}, {0xc19e2000}, {0xc19e4000}, {0xc19e6000}, 
+    {0xc19e8000}, {0xc19ea000}, {0xc19ec000}, {0xc19ee000}, 
+    {0xc19f0000}, {0xc19f2000}, {0xc19f4000}, {0xc19f6000}, 
+    {0xc19f8000}, {0xc19fa000}, {0xc19fc000}, {0xc19fe000}, 
+    {0xc1a00000}, {0xc1a02000}, {0xc1a04000}, {0xc1a06000}, 
+    {0xc1a08000}, {0xc1a0a000}, {0xc1a0c000}, {0xc1a0e000}, 
+    {0xc1a10000}, {0xc1a12000}, {0xc1a14000}, {0xc1a16000}, 
+    {0xc1a18000}, {0xc1a1a000}, {0xc1a1c000}, {0xc1a1e000}, 
+    {0xc1a20000}, {0xc1a22000}, {0xc1a24000}, {0xc1a26000}, 
+    {0xc1a28000}, {0xc1a2a000}, {0xc1a2c000}, {0xc1a2e000}, 
+    {0xc1a30000}, {0xc1a32000}, {0xc1a34000}, {0xc1a36000}, 
+    {0xc1a38000}, {0xc1a3a000}, {0xc1a3c000}, {0xc1a3e000}, 
+    {0xc1a40000}, {0xc1a42000}, {0xc1a44000}, {0xc1a46000}, 
+    {0xc1a48000}, {0xc1a4a000}, {0xc1a4c000}, {0xc1a4e000}, 
+    {0xc1a50000}, {0xc1a52000}, {0xc1a54000}, {0xc1a56000}, 
+    {0xc1a58000}, {0xc1a5a000}, {0xc1a5c000}, {0xc1a5e000}, 
+    {0xc1a60000}, {0xc1a62000}, {0xc1a64000}, {0xc1a66000}, 
+    {0xc1a68000}, {0xc1a6a000}, {0xc1a6c000}, {0xc1a6e000}, 
+    {0xc1a70000}, {0xc1a72000}, {0xc1a74000}, {0xc1a76000}, 
+    {0xc1a78000}, {0xc1a7a000}, {0xc1a7c000}, {0xc1a7e000}, 
+    {0xc1a80000}, {0xc1a82000}, {0xc1a84000}, {0xc1a86000}, 
+    {0xc1a88000}, {0xc1a8a000}, {0xc1a8c000}, {0xc1a8e000}, 
+    {0xc1a90000}, {0xc1a92000}, {0xc1a94000}, {0xc1a96000}, 
+    {0xc1a98000}, {0xc1a9a000}, {0xc1a9c000}, {0xc1a9e000}, 
+    {0xc1aa0000}, {0xc1aa2000}, {0xc1aa4000}, {0xc1aa6000}, 
+    {0xc1aa8000}, {0xc1aaa000}, {0xc1aac000}, {0xc1aae000}, 
+    {0xc1ab0000}, {0xc1ab2000}, {0xc1ab4000}, {0xc1ab6000}, 
+    {0xc1ab8000}, {0xc1aba000}, {0xc1abc000}, {0xc1abe000}, 
+    {0xc1ac0000}, {0xc1ac2000}, {0xc1ac4000}, {0xc1ac6000}, 
+    {0xc1ac8000}, {0xc1aca000}, {0xc1acc000}, {0xc1ace000}, 
+    {0xc1ad0000}, {0xc1ad2000}, {0xc1ad4000}, {0xc1ad6000}, 
+    {0xc1ad8000}, {0xc1ada000}, {0xc1adc000}, {0xc1ade000}, 
+    {0xc1ae0000}, {0xc1ae2000}, {0xc1ae4000}, {0xc1ae6000}, 
+    {0xc1ae8000}, {0xc1aea000}, {0xc1aec000}, {0xc1aee000}, 
+    {0xc1af0000}, {0xc1af2000}, {0xc1af4000}, {0xc1af6000}, 
+    {0xc1af8000}, {0xc1afa000}, {0xc1afc000}, {0xc1afe000}, 
+    {0xc1b00000}, {0xc1b02000}, {0xc1b04000}, {0xc1b06000}, 
+    {0xc1b08000}, {0xc1b0a000}, {0xc1b0c000}, {0xc1b0e000}, 
+    {0xc1b10000}, {0xc1b12000}, {0xc1b14000}, {0xc1b16000}, 
+    {0xc1b18000}, {0xc1b1a000}, {0xc1b1c000}, {0xc1b1e000}, 
+    {0xc1b20000}, {0xc1b22000}, {0xc1b24000}, {0xc1b26000}, 
+    {0xc1b28000}, {0xc1b2a000}, {0xc1b2c000}, {0xc1b2e000}, 
+    {0xc1b30000}, {0xc1b32000}, {0xc1b34000}, {0xc1b36000}, 
+    {0xc1b38000}, {0xc1b3a000}, {0xc1b3c000}, {0xc1b3e000}, 
+    {0xc1b40000}, {0xc1b42000}, {0xc1b44000}, {0xc1b46000}, 
+    {0xc1b48000}, {0xc1b4a000}, {0xc1b4c000}, {0xc1b4e000}, 
+    {0xc1b50000}, {0xc1b52000}, {0xc1b54000}, {0xc1b56000}, 
+    {0xc1b58000}, {0xc1b5a000}, {0xc1b5c000}, {0xc1b5e000}, 
+    {0xc1b60000}, {0xc1b62000}, {0xc1b64000}, {0xc1b66000}, 
+    {0xc1b68000}, {0xc1b6a000}, {0xc1b6c000}, {0xc1b6e000}, 
+    {0xc1b70000}, {0xc1b72000}, {0xc1b74000}, {0xc1b76000}, 
+    {0xc1b78000}, {0xc1b7a000}, {0xc1b7c000}, {0xc1b7e000}, 
+    {0xc1b80000}, {0xc1b82000}, {0xc1b84000}, {0xc1b86000}, 
+    {0xc1b88000}, {0xc1b8a000}, {0xc1b8c000}, {0xc1b8e000}, 
+    {0xc1b90000}, {0xc1b92000}, {0xc1b94000}, {0xc1b96000}, 
+    {0xc1b98000}, {0xc1b9a000}, {0xc1b9c000}, {0xc1b9e000}, 
+    {0xc1ba0000}, {0xc1ba2000}, {0xc1ba4000}, {0xc1ba6000}, 
+    {0xc1ba8000}, {0xc1baa000}, {0xc1bac000}, {0xc1bae000}, 
+    {0xc1bb0000}, {0xc1bb2000}, {0xc1bb4000}, {0xc1bb6000}, 
+    {0xc1bb8000}, {0xc1bba000}, {0xc1bbc000}, {0xc1bbe000}, 
+    {0xc1bc0000}, {0xc1bc2000}, {0xc1bc4000}, {0xc1bc6000}, 
+    {0xc1bc8000}, {0xc1bca000}, {0xc1bcc000}, {0xc1bce000}, 
+    {0xc1bd0000}, {0xc1bd2000}, {0xc1bd4000}, {0xc1bd6000}, 
+    {0xc1bd8000}, {0xc1bda000}, {0xc1bdc000}, {0xc1bde000}, 
+    {0xc1be0000}, {0xc1be2000}, {0xc1be4000}, {0xc1be6000}, 
+    {0xc1be8000}, {0xc1bea000}, {0xc1bec000}, {0xc1bee000}, 
+    {0xc1bf0000}, {0xc1bf2000}, {0xc1bf4000}, {0xc1bf6000}, 
+    {0xc1bf8000}, {0xc1bfa000}, {0xc1bfc000}, {0xc1bfe000}, 
+    {0xc1c00000}, {0xc1c02000}, {0xc1c04000}, {0xc1c06000}, 
+    {0xc1c08000}, {0xc1c0a000}, {0xc1c0c000}, {0xc1c0e000}, 
+    {0xc1c10000}, {0xc1c12000}, {0xc1c14000}, {0xc1c16000}, 
+    {0xc1c18000}, {0xc1c1a000}, {0xc1c1c000}, {0xc1c1e000}, 
+    {0xc1c20000}, {0xc1c22000}, {0xc1c24000}, {0xc1c26000}, 
+    {0xc1c28000}, {0xc1c2a000}, {0xc1c2c000}, {0xc1c2e000}, 
+    {0xc1c30000}, {0xc1c32000}, {0xc1c34000}, {0xc1c36000}, 
+    {0xc1c38000}, {0xc1c3a000}, {0xc1c3c000}, {0xc1c3e000}, 
+    {0xc1c40000}, {0xc1c42000}, {0xc1c44000}, {0xc1c46000}, 
+    {0xc1c48000}, {0xc1c4a000}, {0xc1c4c000}, {0xc1c4e000}, 
+    {0xc1c50000}, {0xc1c52000}, {0xc1c54000}, {0xc1c56000}, 
+    {0xc1c58000}, {0xc1c5a000}, {0xc1c5c000}, {0xc1c5e000}, 
+    {0xc1c60000}, {0xc1c62000}, {0xc1c64000}, {0xc1c66000}, 
+    {0xc1c68000}, {0xc1c6a000}, {0xc1c6c000}, {0xc1c6e000}, 
+    {0xc1c70000}, {0xc1c72000}, {0xc1c74000}, {0xc1c76000}, 
+    {0xc1c78000}, {0xc1c7a000}, {0xc1c7c000}, {0xc1c7e000}, 
+    {0xc1c80000}, {0xc1c82000}, {0xc1c84000}, {0xc1c86000}, 
+    {0xc1c88000}, {0xc1c8a000}, {0xc1c8c000}, {0xc1c8e000}, 
+    {0xc1c90000}, {0xc1c92000}, {0xc1c94000}, {0xc1c96000}, 
+    {0xc1c98000}, {0xc1c9a000}, {0xc1c9c000}, {0xc1c9e000}, 
+    {0xc1ca0000}, {0xc1ca2000}, {0xc1ca4000}, {0xc1ca6000}, 
+    {0xc1ca8000}, {0xc1caa000}, {0xc1cac000}, {0xc1cae000}, 
+    {0xc1cb0000}, {0xc1cb2000}, {0xc1cb4000}, {0xc1cb6000}, 
+    {0xc1cb8000}, {0xc1cba000}, {0xc1cbc000}, {0xc1cbe000}, 
+    {0xc1cc0000}, {0xc1cc2000}, {0xc1cc4000}, {0xc1cc6000}, 
+    {0xc1cc8000}, {0xc1cca000}, {0xc1ccc000}, {0xc1cce000}, 
+    {0xc1cd0000}, {0xc1cd2000}, {0xc1cd4000}, {0xc1cd6000}, 
+    {0xc1cd8000}, {0xc1cda000}, {0xc1cdc000}, {0xc1cde000}, 
+    {0xc1ce0000}, {0xc1ce2000}, {0xc1ce4000}, {0xc1ce6000}, 
+    {0xc1ce8000}, {0xc1cea000}, {0xc1cec000}, {0xc1cee000}, 
+    {0xc1cf0000}, {0xc1cf2000}, {0xc1cf4000}, {0xc1cf6000}, 
+    {0xc1cf8000}, {0xc1cfa000}, {0xc1cfc000}, {0xc1cfe000}, 
+    {0xc1d00000}, {0xc1d02000}, {0xc1d04000}, {0xc1d06000}, 
+    {0xc1d08000}, {0xc1d0a000}, {0xc1d0c000}, {0xc1d0e000}, 
+    {0xc1d10000}, {0xc1d12000}, {0xc1d14000}, {0xc1d16000}, 
+    {0xc1d18000}, {0xc1d1a000}, {0xc1d1c000}, {0xc1d1e000}, 
+    {0xc1d20000}, {0xc1d22000}, {0xc1d24000}, {0xc1d26000}, 
+    {0xc1d28000}, {0xc1d2a000}, {0xc1d2c000}, {0xc1d2e000}, 
+    {0xc1d30000}, {0xc1d32000}, {0xc1d34000}, {0xc1d36000}, 
+    {0xc1d38000}, {0xc1d3a000}, {0xc1d3c000}, {0xc1d3e000}, 
+    {0xc1d40000}, {0xc1d42000}, {0xc1d44000}, {0xc1d46000}, 
+    {0xc1d48000}, {0xc1d4a000}, {0xc1d4c000}, {0xc1d4e000}, 
+    {0xc1d50000}, {0xc1d52000}, {0xc1d54000}, {0xc1d56000}, 
+    {0xc1d58000}, {0xc1d5a000}, {0xc1d5c000}, {0xc1d5e000}, 
+    {0xc1d60000}, {0xc1d62000}, {0xc1d64000}, {0xc1d66000}, 
+    {0xc1d68000}, {0xc1d6a000}, {0xc1d6c000}, {0xc1d6e000}, 
+    {0xc1d70000}, {0xc1d72000}, {0xc1d74000}, {0xc1d76000}, 
+    {0xc1d78000}, {0xc1d7a000}, {0xc1d7c000}, {0xc1d7e000}, 
+    {0xc1d80000}, {0xc1d82000}, {0xc1d84000}, {0xc1d86000}, 
+    {0xc1d88000}, {0xc1d8a000}, {0xc1d8c000}, {0xc1d8e000}, 
+    {0xc1d90000}, {0xc1d92000}, {0xc1d94000}, {0xc1d96000}, 
+    {0xc1d98000}, {0xc1d9a000}, {0xc1d9c000}, {0xc1d9e000}, 
+    {0xc1da0000}, {0xc1da2000}, {0xc1da4000}, {0xc1da6000}, 
+    {0xc1da8000}, {0xc1daa000}, {0xc1dac000}, {0xc1dae000}, 
+    {0xc1db0000}, {0xc1db2000}, {0xc1db4000}, {0xc1db6000}, 
+    {0xc1db8000}, {0xc1dba000}, {0xc1dbc000}, {0xc1dbe000}, 
+    {0xc1dc0000}, {0xc1dc2000}, {0xc1dc4000}, {0xc1dc6000}, 
+    {0xc1dc8000}, {0xc1dca000}, {0xc1dcc000}, {0xc1dce000}, 
+    {0xc1dd0000}, {0xc1dd2000}, {0xc1dd4000}, {0xc1dd6000}, 
+    {0xc1dd8000}, {0xc1dda000}, {0xc1ddc000}, {0xc1dde000}, 
+    {0xc1de0000}, {0xc1de2000}, {0xc1de4000}, {0xc1de6000}, 
+    {0xc1de8000}, {0xc1dea000}, {0xc1dec000}, {0xc1dee000}, 
+    {0xc1df0000}, {0xc1df2000}, {0xc1df4000}, {0xc1df6000}, 
+    {0xc1df8000}, {0xc1dfa000}, {0xc1dfc000}, {0xc1dfe000}, 
+    {0xc1e00000}, {0xc1e02000}, {0xc1e04000}, {0xc1e06000}, 
+    {0xc1e08000}, {0xc1e0a000}, {0xc1e0c000}, {0xc1e0e000}, 
+    {0xc1e10000}, {0xc1e12000}, {0xc1e14000}, {0xc1e16000}, 
+    {0xc1e18000}, {0xc1e1a000}, {0xc1e1c000}, {0xc1e1e000}, 
+    {0xc1e20000}, {0xc1e22000}, {0xc1e24000}, {0xc1e26000}, 
+    {0xc1e28000}, {0xc1e2a000}, {0xc1e2c000}, {0xc1e2e000}, 
+    {0xc1e30000}, {0xc1e32000}, {0xc1e34000}, {0xc1e36000}, 
+    {0xc1e38000}, {0xc1e3a000}, {0xc1e3c000}, {0xc1e3e000}, 
+    {0xc1e40000}, {0xc1e42000}, {0xc1e44000}, {0xc1e46000}, 
+    {0xc1e48000}, {0xc1e4a000}, {0xc1e4c000}, {0xc1e4e000}, 
+    {0xc1e50000}, {0xc1e52000}, {0xc1e54000}, {0xc1e56000}, 
+    {0xc1e58000}, {0xc1e5a000}, {0xc1e5c000}, {0xc1e5e000}, 
+    {0xc1e60000}, {0xc1e62000}, {0xc1e64000}, {0xc1e66000}, 
+    {0xc1e68000}, {0xc1e6a000}, {0xc1e6c000}, {0xc1e6e000}, 
+    {0xc1e70000}, {0xc1e72000}, {0xc1e74000}, {0xc1e76000}, 
+    {0xc1e78000}, {0xc1e7a000}, {0xc1e7c000}, {0xc1e7e000}, 
+    {0xc1e80000}, {0xc1e82000}, {0xc1e84000}, {0xc1e86000}, 
+    {0xc1e88000}, {0xc1e8a000}, {0xc1e8c000}, {0xc1e8e000}, 
+    {0xc1e90000}, {0xc1e92000}, {0xc1e94000}, {0xc1e96000}, 
+    {0xc1e98000}, {0xc1e9a000}, {0xc1e9c000}, {0xc1e9e000}, 
+    {0xc1ea0000}, {0xc1ea2000}, {0xc1ea4000}, {0xc1ea6000}, 
+    {0xc1ea8000}, {0xc1eaa000}, {0xc1eac000}, {0xc1eae000}, 
+    {0xc1eb0000}, {0xc1eb2000}, {0xc1eb4000}, {0xc1eb6000}, 
+    {0xc1eb8000}, {0xc1eba000}, {0xc1ebc000}, {0xc1ebe000}, 
+    {0xc1ec0000}, {0xc1ec2000}, {0xc1ec4000}, {0xc1ec6000}, 
+    {0xc1ec8000}, {0xc1eca000}, {0xc1ecc000}, {0xc1ece000}, 
+    {0xc1ed0000}, {0xc1ed2000}, {0xc1ed4000}, {0xc1ed6000}, 
+    {0xc1ed8000}, {0xc1eda000}, {0xc1edc000}, {0xc1ede000}, 
+    {0xc1ee0000}, {0xc1ee2000}, {0xc1ee4000}, {0xc1ee6000}, 
+    {0xc1ee8000}, {0xc1eea000}, {0xc1eec000}, {0xc1eee000}, 
+    {0xc1ef0000}, {0xc1ef2000}, {0xc1ef4000}, {0xc1ef6000}, 
+    {0xc1ef8000}, {0xc1efa000}, {0xc1efc000}, {0xc1efe000}, 
+    {0xc1f00000}, {0xc1f02000}, {0xc1f04000}, {0xc1f06000}, 
+    {0xc1f08000}, {0xc1f0a000}, {0xc1f0c000}, {0xc1f0e000}, 
+    {0xc1f10000}, {0xc1f12000}, {0xc1f14000}, {0xc1f16000}, 
+    {0xc1f18000}, {0xc1f1a000}, {0xc1f1c000}, {0xc1f1e000}, 
+    {0xc1f20000}, {0xc1f22000}, {0xc1f24000}, {0xc1f26000}, 
+    {0xc1f28000}, {0xc1f2a000}, {0xc1f2c000}, {0xc1f2e000}, 
+    {0xc1f30000}, {0xc1f32000}, {0xc1f34000}, {0xc1f36000}, 
+    {0xc1f38000}, {0xc1f3a000}, {0xc1f3c000}, {0xc1f3e000}, 
+    {0xc1f40000}, {0xc1f42000}, {0xc1f44000}, {0xc1f46000}, 
+    {0xc1f48000}, {0xc1f4a000}, {0xc1f4c000}, {0xc1f4e000}, 
+    {0xc1f50000}, {0xc1f52000}, {0xc1f54000}, {0xc1f56000}, 
+    {0xc1f58000}, {0xc1f5a000}, {0xc1f5c000}, {0xc1f5e000}, 
+    {0xc1f60000}, {0xc1f62000}, {0xc1f64000}, {0xc1f66000}, 
+    {0xc1f68000}, {0xc1f6a000}, {0xc1f6c000}, {0xc1f6e000}, 
+    {0xc1f70000}, {0xc1f72000}, {0xc1f74000}, {0xc1f76000}, 
+    {0xc1f78000}, {0xc1f7a000}, {0xc1f7c000}, {0xc1f7e000}, 
+    {0xc1f80000}, {0xc1f82000}, {0xc1f84000}, {0xc1f86000}, 
+    {0xc1f88000}, {0xc1f8a000}, {0xc1f8c000}, {0xc1f8e000}, 
+    {0xc1f90000}, {0xc1f92000}, {0xc1f94000}, {0xc1f96000}, 
+    {0xc1f98000}, {0xc1f9a000}, {0xc1f9c000}, {0xc1f9e000}, 
+    {0xc1fa0000}, {0xc1fa2000}, {0xc1fa4000}, {0xc1fa6000}, 
+    {0xc1fa8000}, {0xc1faa000}, {0xc1fac000}, {0xc1fae000}, 
+    {0xc1fb0000}, {0xc1fb2000}, {0xc1fb4000}, {0xc1fb6000}, 
+    {0xc1fb8000}, {0xc1fba000}, {0xc1fbc000}, {0xc1fbe000}, 
+    {0xc1fc0000}, {0xc1fc2000}, {0xc1fc4000}, {0xc1fc6000}, 
+    {0xc1fc8000}, {0xc1fca000}, {0xc1fcc000}, {0xc1fce000}, 
+    {0xc1fd0000}, {0xc1fd2000}, {0xc1fd4000}, {0xc1fd6000}, 
+    {0xc1fd8000}, {0xc1fda000}, {0xc1fdc000}, {0xc1fde000}, 
+    {0xc1fe0000}, {0xc1fe2000}, {0xc1fe4000}, {0xc1fe6000}, 
+    {0xc1fe8000}, {0xc1fea000}, {0xc1fec000}, {0xc1fee000}, 
+    {0xc1ff0000}, {0xc1ff2000}, {0xc1ff4000}, {0xc1ff6000}, 
+    {0xc1ff8000}, {0xc1ffa000}, {0xc1ffc000}, {0xc1ffe000}, 
+    {0xc2000000}, {0xc2002000}, {0xc2004000}, {0xc2006000}, 
+    {0xc2008000}, {0xc200a000}, {0xc200c000}, {0xc200e000}, 
+    {0xc2010000}, {0xc2012000}, {0xc2014000}, {0xc2016000}, 
+    {0xc2018000}, {0xc201a000}, {0xc201c000}, {0xc201e000}, 
+    {0xc2020000}, {0xc2022000}, {0xc2024000}, {0xc2026000}, 
+    {0xc2028000}, {0xc202a000}, {0xc202c000}, {0xc202e000}, 
+    {0xc2030000}, {0xc2032000}, {0xc2034000}, {0xc2036000}, 
+    {0xc2038000}, {0xc203a000}, {0xc203c000}, {0xc203e000}, 
+    {0xc2040000}, {0xc2042000}, {0xc2044000}, {0xc2046000}, 
+    {0xc2048000}, {0xc204a000}, {0xc204c000}, {0xc204e000}, 
+    {0xc2050000}, {0xc2052000}, {0xc2054000}, {0xc2056000}, 
+    {0xc2058000}, {0xc205a000}, {0xc205c000}, {0xc205e000}, 
+    {0xc2060000}, {0xc2062000}, {0xc2064000}, {0xc2066000}, 
+    {0xc2068000}, {0xc206a000}, {0xc206c000}, {0xc206e000}, 
+    {0xc2070000}, {0xc2072000}, {0xc2074000}, {0xc2076000}, 
+    {0xc2078000}, {0xc207a000}, {0xc207c000}, {0xc207e000}, 
+    {0xc2080000}, {0xc2082000}, {0xc2084000}, {0xc2086000}, 
+    {0xc2088000}, {0xc208a000}, {0xc208c000}, {0xc208e000}, 
+    {0xc2090000}, {0xc2092000}, {0xc2094000}, {0xc2096000}, 
+    {0xc2098000}, {0xc209a000}, {0xc209c000}, {0xc209e000}, 
+    {0xc20a0000}, {0xc20a2000}, {0xc20a4000}, {0xc20a6000}, 
+    {0xc20a8000}, {0xc20aa000}, {0xc20ac000}, {0xc20ae000}, 
+    {0xc20b0000}, {0xc20b2000}, {0xc20b4000}, {0xc20b6000}, 
+    {0xc20b8000}, {0xc20ba000}, {0xc20bc000}, {0xc20be000}, 
+    {0xc20c0000}, {0xc20c2000}, {0xc20c4000}, {0xc20c6000}, 
+    {0xc20c8000}, {0xc20ca000}, {0xc20cc000}, {0xc20ce000}, 
+    {0xc20d0000}, {0xc20d2000}, {0xc20d4000}, {0xc20d6000}, 
+    {0xc20d8000}, {0xc20da000}, {0xc20dc000}, {0xc20de000}, 
+    {0xc20e0000}, {0xc20e2000}, {0xc20e4000}, {0xc20e6000}, 
+    {0xc20e8000}, {0xc20ea000}, {0xc20ec000}, {0xc20ee000}, 
+    {0xc20f0000}, {0xc20f2000}, {0xc20f4000}, {0xc20f6000}, 
+    {0xc20f8000}, {0xc20fa000}, {0xc20fc000}, {0xc20fe000}, 
+    {0xc2100000}, {0xc2102000}, {0xc2104000}, {0xc2106000}, 
+    {0xc2108000}, {0xc210a000}, {0xc210c000}, {0xc210e000}, 
+    {0xc2110000}, {0xc2112000}, {0xc2114000}, {0xc2116000}, 
+    {0xc2118000}, {0xc211a000}, {0xc211c000}, {0xc211e000}, 
+    {0xc2120000}, {0xc2122000}, {0xc2124000}, {0xc2126000}, 
+    {0xc2128000}, {0xc212a000}, {0xc212c000}, {0xc212e000}, 
+    {0xc2130000}, {0xc2132000}, {0xc2134000}, {0xc2136000}, 
+    {0xc2138000}, {0xc213a000}, {0xc213c000}, {0xc213e000}, 
+    {0xc2140000}, {0xc2142000}, {0xc2144000}, {0xc2146000}, 
+    {0xc2148000}, {0xc214a000}, {0xc214c000}, {0xc214e000}, 
+    {0xc2150000}, {0xc2152000}, {0xc2154000}, {0xc2156000}, 
+    {0xc2158000}, {0xc215a000}, {0xc215c000}, {0xc215e000}, 
+    {0xc2160000}, {0xc2162000}, {0xc2164000}, {0xc2166000}, 
+    {0xc2168000}, {0xc216a000}, {0xc216c000}, {0xc216e000}, 
+    {0xc2170000}, {0xc2172000}, {0xc2174000}, {0xc2176000}, 
+    {0xc2178000}, {0xc217a000}, {0xc217c000}, {0xc217e000}, 
+    {0xc2180000}, {0xc2182000}, {0xc2184000}, {0xc2186000}, 
+    {0xc2188000}, {0xc218a000}, {0xc218c000}, {0xc218e000}, 
+    {0xc2190000}, {0xc2192000}, {0xc2194000}, {0xc2196000}, 
+    {0xc2198000}, {0xc219a000}, {0xc219c000}, {0xc219e000}, 
+    {0xc21a0000}, {0xc21a2000}, {0xc21a4000}, {0xc21a6000}, 
+    {0xc21a8000}, {0xc21aa000}, {0xc21ac000}, {0xc21ae000}, 
+    {0xc21b0000}, {0xc21b2000}, {0xc21b4000}, {0xc21b6000}, 
+    {0xc21b8000}, {0xc21ba000}, {0xc21bc000}, {0xc21be000}, 
+    {0xc21c0000}, {0xc21c2000}, {0xc21c4000}, {0xc21c6000}, 
+    {0xc21c8000}, {0xc21ca000}, {0xc21cc000}, {0xc21ce000}, 
+    {0xc21d0000}, {0xc21d2000}, {0xc21d4000}, {0xc21d6000}, 
+    {0xc21d8000}, {0xc21da000}, {0xc21dc000}, {0xc21de000}, 
+    {0xc21e0000}, {0xc21e2000}, {0xc21e4000}, {0xc21e6000}, 
+    {0xc21e8000}, {0xc21ea000}, {0xc21ec000}, {0xc21ee000}, 
+    {0xc21f0000}, {0xc21f2000}, {0xc21f4000}, {0xc21f6000}, 
+    {0xc21f8000}, {0xc21fa000}, {0xc21fc000}, {0xc21fe000}, 
+    {0xc2200000}, {0xc2202000}, {0xc2204000}, {0xc2206000}, 
+    {0xc2208000}, {0xc220a000}, {0xc220c000}, {0xc220e000}, 
+    {0xc2210000}, {0xc2212000}, {0xc2214000}, {0xc2216000}, 
+    {0xc2218000}, {0xc221a000}, {0xc221c000}, {0xc221e000}, 
+    {0xc2220000}, {0xc2222000}, {0xc2224000}, {0xc2226000}, 
+    {0xc2228000}, {0xc222a000}, {0xc222c000}, {0xc222e000}, 
+    {0xc2230000}, {0xc2232000}, {0xc2234000}, {0xc2236000}, 
+    {0xc2238000}, {0xc223a000}, {0xc223c000}, {0xc223e000}, 
+    {0xc2240000}, {0xc2242000}, {0xc2244000}, {0xc2246000}, 
+    {0xc2248000}, {0xc224a000}, {0xc224c000}, {0xc224e000}, 
+    {0xc2250000}, {0xc2252000}, {0xc2254000}, {0xc2256000}, 
+    {0xc2258000}, {0xc225a000}, {0xc225c000}, {0xc225e000}, 
+    {0xc2260000}, {0xc2262000}, {0xc2264000}, {0xc2266000}, 
+    {0xc2268000}, {0xc226a000}, {0xc226c000}, {0xc226e000}, 
+    {0xc2270000}, {0xc2272000}, {0xc2274000}, {0xc2276000}, 
+    {0xc2278000}, {0xc227a000}, {0xc227c000}, {0xc227e000}, 
+    {0xc2280000}, {0xc2282000}, {0xc2284000}, {0xc2286000}, 
+    {0xc2288000}, {0xc228a000}, {0xc228c000}, {0xc228e000}, 
+    {0xc2290000}, {0xc2292000}, {0xc2294000}, {0xc2296000}, 
+    {0xc2298000}, {0xc229a000}, {0xc229c000}, {0xc229e000}, 
+    {0xc22a0000}, {0xc22a2000}, {0xc22a4000}, {0xc22a6000}, 
+    {0xc22a8000}, {0xc22aa000}, {0xc22ac000}, {0xc22ae000}, 
+    {0xc22b0000}, {0xc22b2000}, {0xc22b4000}, {0xc22b6000}, 
+    {0xc22b8000}, {0xc22ba000}, {0xc22bc000}, {0xc22be000}, 
+    {0xc22c0000}, {0xc22c2000}, {0xc22c4000}, {0xc22c6000}, 
+    {0xc22c8000}, {0xc22ca000}, {0xc22cc000}, {0xc22ce000}, 
+    {0xc22d0000}, {0xc22d2000}, {0xc22d4000}, {0xc22d6000}, 
+    {0xc22d8000}, {0xc22da000}, {0xc22dc000}, {0xc22de000}, 
+    {0xc22e0000}, {0xc22e2000}, {0xc22e4000}, {0xc22e6000}, 
+    {0xc22e8000}, {0xc22ea000}, {0xc22ec000}, {0xc22ee000}, 
+    {0xc22f0000}, {0xc22f2000}, {0xc22f4000}, {0xc22f6000}, 
+    {0xc22f8000}, {0xc22fa000}, {0xc22fc000}, {0xc22fe000}, 
+    {0xc2300000}, {0xc2302000}, {0xc2304000}, {0xc2306000}, 
+    {0xc2308000}, {0xc230a000}, {0xc230c000}, {0xc230e000}, 
+    {0xc2310000}, {0xc2312000}, {0xc2314000}, {0xc2316000}, 
+    {0xc2318000}, {0xc231a000}, {0xc231c000}, {0xc231e000}, 
+    {0xc2320000}, {0xc2322000}, {0xc2324000}, {0xc2326000}, 
+    {0xc2328000}, {0xc232a000}, {0xc232c000}, {0xc232e000}, 
+    {0xc2330000}, {0xc2332000}, {0xc2334000}, {0xc2336000}, 
+    {0xc2338000}, {0xc233a000}, {0xc233c000}, {0xc233e000}, 
+    {0xc2340000}, {0xc2342000}, {0xc2344000}, {0xc2346000}, 
+    {0xc2348000}, {0xc234a000}, {0xc234c000}, {0xc234e000}, 
+    {0xc2350000}, {0xc2352000}, {0xc2354000}, {0xc2356000}, 
+    {0xc2358000}, {0xc235a000}, {0xc235c000}, {0xc235e000}, 
+    {0xc2360000}, {0xc2362000}, {0xc2364000}, {0xc2366000}, 
+    {0xc2368000}, {0xc236a000}, {0xc236c000}, {0xc236e000}, 
+    {0xc2370000}, {0xc2372000}, {0xc2374000}, {0xc2376000}, 
+    {0xc2378000}, {0xc237a000}, {0xc237c000}, {0xc237e000}, 
+    {0xc2380000}, {0xc2382000}, {0xc2384000}, {0xc2386000}, 
+    {0xc2388000}, {0xc238a000}, {0xc238c000}, {0xc238e000}, 
+    {0xc2390000}, {0xc2392000}, {0xc2394000}, {0xc2396000}, 
+    {0xc2398000}, {0xc239a000}, {0xc239c000}, {0xc239e000}, 
+    {0xc23a0000}, {0xc23a2000}, {0xc23a4000}, {0xc23a6000}, 
+    {0xc23a8000}, {0xc23aa000}, {0xc23ac000}, {0xc23ae000}, 
+    {0xc23b0000}, {0xc23b2000}, {0xc23b4000}, {0xc23b6000}, 
+    {0xc23b8000}, {0xc23ba000}, {0xc23bc000}, {0xc23be000}, 
+    {0xc23c0000}, {0xc23c2000}, {0xc23c4000}, {0xc23c6000}, 
+    {0xc23c8000}, {0xc23ca000}, {0xc23cc000}, {0xc23ce000}, 
+    {0xc23d0000}, {0xc23d2000}, {0xc23d4000}, {0xc23d6000}, 
+    {0xc23d8000}, {0xc23da000}, {0xc23dc000}, {0xc23de000}, 
+    {0xc23e0000}, {0xc23e2000}, {0xc23e4000}, {0xc23e6000}, 
+    {0xc23e8000}, {0xc23ea000}, {0xc23ec000}, {0xc23ee000}, 
+    {0xc23f0000}, {0xc23f2000}, {0xc23f4000}, {0xc23f6000}, 
+    {0xc23f8000}, {0xc23fa000}, {0xc23fc000}, {0xc23fe000}, 
+    {0xc2400000}, {0xc2402000}, {0xc2404000}, {0xc2406000}, 
+    {0xc2408000}, {0xc240a000}, {0xc240c000}, {0xc240e000}, 
+    {0xc2410000}, {0xc2412000}, {0xc2414000}, {0xc2416000}, 
+    {0xc2418000}, {0xc241a000}, {0xc241c000}, {0xc241e000}, 
+    {0xc2420000}, {0xc2422000}, {0xc2424000}, {0xc2426000}, 
+    {0xc2428000}, {0xc242a000}, {0xc242c000}, {0xc242e000}, 
+    {0xc2430000}, {0xc2432000}, {0xc2434000}, {0xc2436000}, 
+    {0xc2438000}, {0xc243a000}, {0xc243c000}, {0xc243e000}, 
+    {0xc2440000}, {0xc2442000}, {0xc2444000}, {0xc2446000}, 
+    {0xc2448000}, {0xc244a000}, {0xc244c000}, {0xc244e000}, 
+    {0xc2450000}, {0xc2452000}, {0xc2454000}, {0xc2456000}, 
+    {0xc2458000}, {0xc245a000}, {0xc245c000}, {0xc245e000}, 
+    {0xc2460000}, {0xc2462000}, {0xc2464000}, {0xc2466000}, 
+    {0xc2468000}, {0xc246a000}, {0xc246c000}, {0xc246e000}, 
+    {0xc2470000}, {0xc2472000}, {0xc2474000}, {0xc2476000}, 
+    {0xc2478000}, {0xc247a000}, {0xc247c000}, {0xc247e000}, 
+    {0xc2480000}, {0xc2482000}, {0xc2484000}, {0xc2486000}, 
+    {0xc2488000}, {0xc248a000}, {0xc248c000}, {0xc248e000}, 
+    {0xc2490000}, {0xc2492000}, {0xc2494000}, {0xc2496000}, 
+    {0xc2498000}, {0xc249a000}, {0xc249c000}, {0xc249e000}, 
+    {0xc24a0000}, {0xc24a2000}, {0xc24a4000}, {0xc24a6000}, 
+    {0xc24a8000}, {0xc24aa000}, {0xc24ac000}, {0xc24ae000}, 
+    {0xc24b0000}, {0xc24b2000}, {0xc24b4000}, {0xc24b6000}, 
+    {0xc24b8000}, {0xc24ba000}, {0xc24bc000}, {0xc24be000}, 
+    {0xc24c0000}, {0xc24c2000}, {0xc24c4000}, {0xc24c6000}, 
+    {0xc24c8000}, {0xc24ca000}, {0xc24cc000}, {0xc24ce000}, 
+    {0xc24d0000}, {0xc24d2000}, {0xc24d4000}, {0xc24d6000}, 
+    {0xc24d8000}, {0xc24da000}, {0xc24dc000}, {0xc24de000}, 
+    {0xc24e0000}, {0xc24e2000}, {0xc24e4000}, {0xc24e6000}, 
+    {0xc24e8000}, {0xc24ea000}, {0xc24ec000}, {0xc24ee000}, 
+    {0xc24f0000}, {0xc24f2000}, {0xc24f4000}, {0xc24f6000}, 
+    {0xc24f8000}, {0xc24fa000}, {0xc24fc000}, {0xc24fe000}, 
+    {0xc2500000}, {0xc2502000}, {0xc2504000}, {0xc2506000}, 
+    {0xc2508000}, {0xc250a000}, {0xc250c000}, {0xc250e000}, 
+    {0xc2510000}, {0xc2512000}, {0xc2514000}, {0xc2516000}, 
+    {0xc2518000}, {0xc251a000}, {0xc251c000}, {0xc251e000}, 
+    {0xc2520000}, {0xc2522000}, {0xc2524000}, {0xc2526000}, 
+    {0xc2528000}, {0xc252a000}, {0xc252c000}, {0xc252e000}, 
+    {0xc2530000}, {0xc2532000}, {0xc2534000}, {0xc2536000}, 
+    {0xc2538000}, {0xc253a000}, {0xc253c000}, {0xc253e000}, 
+    {0xc2540000}, {0xc2542000}, {0xc2544000}, {0xc2546000}, 
+    {0xc2548000}, {0xc254a000}, {0xc254c000}, {0xc254e000}, 
+    {0xc2550000}, {0xc2552000}, {0xc2554000}, {0xc2556000}, 
+    {0xc2558000}, {0xc255a000}, {0xc255c000}, {0xc255e000}, 
+    {0xc2560000}, {0xc2562000}, {0xc2564000}, {0xc2566000}, 
+    {0xc2568000}, {0xc256a000}, {0xc256c000}, {0xc256e000}, 
+    {0xc2570000}, {0xc2572000}, {0xc2574000}, {0xc2576000}, 
+    {0xc2578000}, {0xc257a000}, {0xc257c000}, {0xc257e000}, 
+    {0xc2580000}, {0xc2582000}, {0xc2584000}, {0xc2586000}, 
+    {0xc2588000}, {0xc258a000}, {0xc258c000}, {0xc258e000}, 
+    {0xc2590000}, {0xc2592000}, {0xc2594000}, {0xc2596000}, 
+    {0xc2598000}, {0xc259a000}, {0xc259c000}, {0xc259e000}, 
+    {0xc25a0000}, {0xc25a2000}, {0xc25a4000}, {0xc25a6000}, 
+    {0xc25a8000}, {0xc25aa000}, {0xc25ac000}, {0xc25ae000}, 
+    {0xc25b0000}, {0xc25b2000}, {0xc25b4000}, {0xc25b6000}, 
+    {0xc25b8000}, {0xc25ba000}, {0xc25bc000}, {0xc25be000}, 
+    {0xc25c0000}, {0xc25c2000}, {0xc25c4000}, {0xc25c6000}, 
+    {0xc25c8000}, {0xc25ca000}, {0xc25cc000}, {0xc25ce000}, 
+    {0xc25d0000}, {0xc25d2000}, {0xc25d4000}, {0xc25d6000}, 
+    {0xc25d8000}, {0xc25da000}, {0xc25dc000}, {0xc25de000}, 
+    {0xc25e0000}, {0xc25e2000}, {0xc25e4000}, {0xc25e6000}, 
+    {0xc25e8000}, {0xc25ea000}, {0xc25ec000}, {0xc25ee000}, 
+    {0xc25f0000}, {0xc25f2000}, {0xc25f4000}, {0xc25f6000}, 
+    {0xc25f8000}, {0xc25fa000}, {0xc25fc000}, {0xc25fe000}, 
+    {0xc2600000}, {0xc2602000}, {0xc2604000}, {0xc2606000}, 
+    {0xc2608000}, {0xc260a000}, {0xc260c000}, {0xc260e000}, 
+    {0xc2610000}, {0xc2612000}, {0xc2614000}, {0xc2616000}, 
+    {0xc2618000}, {0xc261a000}, {0xc261c000}, {0xc261e000}, 
+    {0xc2620000}, {0xc2622000}, {0xc2624000}, {0xc2626000}, 
+    {0xc2628000}, {0xc262a000}, {0xc262c000}, {0xc262e000}, 
+    {0xc2630000}, {0xc2632000}, {0xc2634000}, {0xc2636000}, 
+    {0xc2638000}, {0xc263a000}, {0xc263c000}, {0xc263e000}, 
+    {0xc2640000}, {0xc2642000}, {0xc2644000}, {0xc2646000}, 
+    {0xc2648000}, {0xc264a000}, {0xc264c000}, {0xc264e000}, 
+    {0xc2650000}, {0xc2652000}, {0xc2654000}, {0xc2656000}, 
+    {0xc2658000}, {0xc265a000}, {0xc265c000}, {0xc265e000}, 
+    {0xc2660000}, {0xc2662000}, {0xc2664000}, {0xc2666000}, 
+    {0xc2668000}, {0xc266a000}, {0xc266c000}, {0xc266e000}, 
+    {0xc2670000}, {0xc2672000}, {0xc2674000}, {0xc2676000}, 
+    {0xc2678000}, {0xc267a000}, {0xc267c000}, {0xc267e000}, 
+    {0xc2680000}, {0xc2682000}, {0xc2684000}, {0xc2686000}, 
+    {0xc2688000}, {0xc268a000}, {0xc268c000}, {0xc268e000}, 
+    {0xc2690000}, {0xc2692000}, {0xc2694000}, {0xc2696000}, 
+    {0xc2698000}, {0xc269a000}, {0xc269c000}, {0xc269e000}, 
+    {0xc26a0000}, {0xc26a2000}, {0xc26a4000}, {0xc26a6000}, 
+    {0xc26a8000}, {0xc26aa000}, {0xc26ac000}, {0xc26ae000}, 
+    {0xc26b0000}, {0xc26b2000}, {0xc26b4000}, {0xc26b6000}, 
+    {0xc26b8000}, {0xc26ba000}, {0xc26bc000}, {0xc26be000}, 
+    {0xc26c0000}, {0xc26c2000}, {0xc26c4000}, {0xc26c6000}, 
+    {0xc26c8000}, {0xc26ca000}, {0xc26cc000}, {0xc26ce000}, 
+    {0xc26d0000}, {0xc26d2000}, {0xc26d4000}, {0xc26d6000}, 
+    {0xc26d8000}, {0xc26da000}, {0xc26dc000}, {0xc26de000}, 
+    {0xc26e0000}, {0xc26e2000}, {0xc26e4000}, {0xc26e6000}, 
+    {0xc26e8000}, {0xc26ea000}, {0xc26ec000}, {0xc26ee000}, 
+    {0xc26f0000}, {0xc26f2000}, {0xc26f4000}, {0xc26f6000}, 
+    {0xc26f8000}, {0xc26fa000}, {0xc26fc000}, {0xc26fe000}, 
+    {0xc2700000}, {0xc2702000}, {0xc2704000}, {0xc2706000}, 
+    {0xc2708000}, {0xc270a000}, {0xc270c000}, {0xc270e000}, 
+    {0xc2710000}, {0xc2712000}, {0xc2714000}, {0xc2716000}, 
+    {0xc2718000}, {0xc271a000}, {0xc271c000}, {0xc271e000}, 
+    {0xc2720000}, {0xc2722000}, {0xc2724000}, {0xc2726000}, 
+    {0xc2728000}, {0xc272a000}, {0xc272c000}, {0xc272e000}, 
+    {0xc2730000}, {0xc2732000}, {0xc2734000}, {0xc2736000}, 
+    {0xc2738000}, {0xc273a000}, {0xc273c000}, {0xc273e000}, 
+    {0xc2740000}, {0xc2742000}, {0xc2744000}, {0xc2746000}, 
+    {0xc2748000}, {0xc274a000}, {0xc274c000}, {0xc274e000}, 
+    {0xc2750000}, {0xc2752000}, {0xc2754000}, {0xc2756000}, 
+    {0xc2758000}, {0xc275a000}, {0xc275c000}, {0xc275e000}, 
+    {0xc2760000}, {0xc2762000}, {0xc2764000}, {0xc2766000}, 
+    {0xc2768000}, {0xc276a000}, {0xc276c000}, {0xc276e000}, 
+    {0xc2770000}, {0xc2772000}, {0xc2774000}, {0xc2776000}, 
+    {0xc2778000}, {0xc277a000}, {0xc277c000}, {0xc277e000}, 
+    {0xc2780000}, {0xc2782000}, {0xc2784000}, {0xc2786000}, 
+    {0xc2788000}, {0xc278a000}, {0xc278c000}, {0xc278e000}, 
+    {0xc2790000}, {0xc2792000}, {0xc2794000}, {0xc2796000}, 
+    {0xc2798000}, {0xc279a000}, {0xc279c000}, {0xc279e000}, 
+    {0xc27a0000}, {0xc27a2000}, {0xc27a4000}, {0xc27a6000}, 
+    {0xc27a8000}, {0xc27aa000}, {0xc27ac000}, {0xc27ae000}, 
+    {0xc27b0000}, {0xc27b2000}, {0xc27b4000}, {0xc27b6000}, 
+    {0xc27b8000}, {0xc27ba000}, {0xc27bc000}, {0xc27be000}, 
+    {0xc27c0000}, {0xc27c2000}, {0xc27c4000}, {0xc27c6000}, 
+    {0xc27c8000}, {0xc27ca000}, {0xc27cc000}, {0xc27ce000}, 
+    {0xc27d0000}, {0xc27d2000}, {0xc27d4000}, {0xc27d6000}, 
+    {0xc27d8000}, {0xc27da000}, {0xc27dc000}, {0xc27de000}, 
+    {0xc27e0000}, {0xc27e2000}, {0xc27e4000}, {0xc27e6000}, 
+    {0xc27e8000}, {0xc27ea000}, {0xc27ec000}, {0xc27ee000}, 
+    {0xc27f0000}, {0xc27f2000}, {0xc27f4000}, {0xc27f6000}, 
+    {0xc27f8000}, {0xc27fa000}, {0xc27fc000}, {0xc27fe000}, 
+    {0xc2800000}, {0xc2802000}, {0xc2804000}, {0xc2806000}, 
+    {0xc2808000}, {0xc280a000}, {0xc280c000}, {0xc280e000}, 
+    {0xc2810000}, {0xc2812000}, {0xc2814000}, {0xc2816000}, 
+    {0xc2818000}, {0xc281a000}, {0xc281c000}, {0xc281e000}, 
+    {0xc2820000}, {0xc2822000}, {0xc2824000}, {0xc2826000}, 
+    {0xc2828000}, {0xc282a000}, {0xc282c000}, {0xc282e000}, 
+    {0xc2830000}, {0xc2832000}, {0xc2834000}, {0xc2836000}, 
+    {0xc2838000}, {0xc283a000}, {0xc283c000}, {0xc283e000}, 
+    {0xc2840000}, {0xc2842000}, {0xc2844000}, {0xc2846000}, 
+    {0xc2848000}, {0xc284a000}, {0xc284c000}, {0xc284e000}, 
+    {0xc2850000}, {0xc2852000}, {0xc2854000}, {0xc2856000}, 
+    {0xc2858000}, {0xc285a000}, {0xc285c000}, {0xc285e000}, 
+    {0xc2860000}, {0xc2862000}, {0xc2864000}, {0xc2866000}, 
+    {0xc2868000}, {0xc286a000}, {0xc286c000}, {0xc286e000}, 
+    {0xc2870000}, {0xc2872000}, {0xc2874000}, {0xc2876000}, 
+    {0xc2878000}, {0xc287a000}, {0xc287c000}, {0xc287e000}, 
+    {0xc2880000}, {0xc2882000}, {0xc2884000}, {0xc2886000}, 
+    {0xc2888000}, {0xc288a000}, {0xc288c000}, {0xc288e000}, 
+    {0xc2890000}, {0xc2892000}, {0xc2894000}, {0xc2896000}, 
+    {0xc2898000}, {0xc289a000}, {0xc289c000}, {0xc289e000}, 
+    {0xc28a0000}, {0xc28a2000}, {0xc28a4000}, {0xc28a6000}, 
+    {0xc28a8000}, {0xc28aa000}, {0xc28ac000}, {0xc28ae000}, 
+    {0xc28b0000}, {0xc28b2000}, {0xc28b4000}, {0xc28b6000}, 
+    {0xc28b8000}, {0xc28ba000}, {0xc28bc000}, {0xc28be000}, 
+    {0xc28c0000}, {0xc28c2000}, {0xc28c4000}, {0xc28c6000}, 
+    {0xc28c8000}, {0xc28ca000}, {0xc28cc000}, {0xc28ce000}, 
+    {0xc28d0000}, {0xc28d2000}, {0xc28d4000}, {0xc28d6000}, 
+    {0xc28d8000}, {0xc28da000}, {0xc28dc000}, {0xc28de000}, 
+    {0xc28e0000}, {0xc28e2000}, {0xc28e4000}, {0xc28e6000}, 
+    {0xc28e8000}, {0xc28ea000}, {0xc28ec000}, {0xc28ee000}, 
+    {0xc28f0000}, {0xc28f2000}, {0xc28f4000}, {0xc28f6000}, 
+    {0xc28f8000}, {0xc28fa000}, {0xc28fc000}, {0xc28fe000}, 
+    {0xc2900000}, {0xc2902000}, {0xc2904000}, {0xc2906000}, 
+    {0xc2908000}, {0xc290a000}, {0xc290c000}, {0xc290e000}, 
+    {0xc2910000}, {0xc2912000}, {0xc2914000}, {0xc2916000}, 
+    {0xc2918000}, {0xc291a000}, {0xc291c000}, {0xc291e000}, 
+    {0xc2920000}, {0xc2922000}, {0xc2924000}, {0xc2926000}, 
+    {0xc2928000}, {0xc292a000}, {0xc292c000}, {0xc292e000}, 
+    {0xc2930000}, {0xc2932000}, {0xc2934000}, {0xc2936000}, 
+    {0xc2938000}, {0xc293a000}, {0xc293c000}, {0xc293e000}, 
+    {0xc2940000}, {0xc2942000}, {0xc2944000}, {0xc2946000}, 
+    {0xc2948000}, {0xc294a000}, {0xc294c000}, {0xc294e000}, 
+    {0xc2950000}, {0xc2952000}, {0xc2954000}, {0xc2956000}, 
+    {0xc2958000}, {0xc295a000}, {0xc295c000}, {0xc295e000}, 
+    {0xc2960000}, {0xc2962000}, {0xc2964000}, {0xc2966000}, 
+    {0xc2968000}, {0xc296a000}, {0xc296c000}, {0xc296e000}, 
+    {0xc2970000}, {0xc2972000}, {0xc2974000}, {0xc2976000}, 
+    {0xc2978000}, {0xc297a000}, {0xc297c000}, {0xc297e000}, 
+    {0xc2980000}, {0xc2982000}, {0xc2984000}, {0xc2986000}, 
+    {0xc2988000}, {0xc298a000}, {0xc298c000}, {0xc298e000}, 
+    {0xc2990000}, {0xc2992000}, {0xc2994000}, {0xc2996000}, 
+    {0xc2998000}, {0xc299a000}, {0xc299c000}, {0xc299e000}, 
+    {0xc29a0000}, {0xc29a2000}, {0xc29a4000}, {0xc29a6000}, 
+    {0xc29a8000}, {0xc29aa000}, {0xc29ac000}, {0xc29ae000}, 
+    {0xc29b0000}, {0xc29b2000}, {0xc29b4000}, {0xc29b6000}, 
+    {0xc29b8000}, {0xc29ba000}, {0xc29bc000}, {0xc29be000}, 
+    {0xc29c0000}, {0xc29c2000}, {0xc29c4000}, {0xc29c6000}, 
+    {0xc29c8000}, {0xc29ca000}, {0xc29cc000}, {0xc29ce000}, 
+    {0xc29d0000}, {0xc29d2000}, {0xc29d4000}, {0xc29d6000}, 
+    {0xc29d8000}, {0xc29da000}, {0xc29dc000}, {0xc29de000}, 
+    {0xc29e0000}, {0xc29e2000}, {0xc29e4000}, {0xc29e6000}, 
+    {0xc29e8000}, {0xc29ea000}, {0xc29ec000}, {0xc29ee000}, 
+    {0xc29f0000}, {0xc29f2000}, {0xc29f4000}, {0xc29f6000}, 
+    {0xc29f8000}, {0xc29fa000}, {0xc29fc000}, {0xc29fe000}, 
+    {0xc2a00000}, {0xc2a02000}, {0xc2a04000}, {0xc2a06000}, 
+    {0xc2a08000}, {0xc2a0a000}, {0xc2a0c000}, {0xc2a0e000}, 
+    {0xc2a10000}, {0xc2a12000}, {0xc2a14000}, {0xc2a16000}, 
+    {0xc2a18000}, {0xc2a1a000}, {0xc2a1c000}, {0xc2a1e000}, 
+    {0xc2a20000}, {0xc2a22000}, {0xc2a24000}, {0xc2a26000}, 
+    {0xc2a28000}, {0xc2a2a000}, {0xc2a2c000}, {0xc2a2e000}, 
+    {0xc2a30000}, {0xc2a32000}, {0xc2a34000}, {0xc2a36000}, 
+    {0xc2a38000}, {0xc2a3a000}, {0xc2a3c000}, {0xc2a3e000}, 
+    {0xc2a40000}, {0xc2a42000}, {0xc2a44000}, {0xc2a46000}, 
+    {0xc2a48000}, {0xc2a4a000}, {0xc2a4c000}, {0xc2a4e000}, 
+    {0xc2a50000}, {0xc2a52000}, {0xc2a54000}, {0xc2a56000}, 
+    {0xc2a58000}, {0xc2a5a000}, {0xc2a5c000}, {0xc2a5e000}, 
+    {0xc2a60000}, {0xc2a62000}, {0xc2a64000}, {0xc2a66000}, 
+    {0xc2a68000}, {0xc2a6a000}, {0xc2a6c000}, {0xc2a6e000}, 
+    {0xc2a70000}, {0xc2a72000}, {0xc2a74000}, {0xc2a76000}, 
+    {0xc2a78000}, {0xc2a7a000}, {0xc2a7c000}, {0xc2a7e000}, 
+    {0xc2a80000}, {0xc2a82000}, {0xc2a84000}, {0xc2a86000}, 
+    {0xc2a88000}, {0xc2a8a000}, {0xc2a8c000}, {0xc2a8e000}, 
+    {0xc2a90000}, {0xc2a92000}, {0xc2a94000}, {0xc2a96000}, 
+    {0xc2a98000}, {0xc2a9a000}, {0xc2a9c000}, {0xc2a9e000}, 
+    {0xc2aa0000}, {0xc2aa2000}, {0xc2aa4000}, {0xc2aa6000}, 
+    {0xc2aa8000}, {0xc2aaa000}, {0xc2aac000}, {0xc2aae000}, 
+    {0xc2ab0000}, {0xc2ab2000}, {0xc2ab4000}, {0xc2ab6000}, 
+    {0xc2ab8000}, {0xc2aba000}, {0xc2abc000}, {0xc2abe000}, 
+    {0xc2ac0000}, {0xc2ac2000}, {0xc2ac4000}, {0xc2ac6000}, 
+    {0xc2ac8000}, {0xc2aca000}, {0xc2acc000}, {0xc2ace000}, 
+    {0xc2ad0000}, {0xc2ad2000}, {0xc2ad4000}, {0xc2ad6000}, 
+    {0xc2ad8000}, {0xc2ada000}, {0xc2adc000}, {0xc2ade000}, 
+    {0xc2ae0000}, {0xc2ae2000}, {0xc2ae4000}, {0xc2ae6000}, 
+    {0xc2ae8000}, {0xc2aea000}, {0xc2aec000}, {0xc2aee000}, 
+    {0xc2af0000}, {0xc2af2000}, {0xc2af4000}, {0xc2af6000}, 
+    {0xc2af8000}, {0xc2afa000}, {0xc2afc000}, {0xc2afe000}, 
+    {0xc2b00000}, {0xc2b02000}, {0xc2b04000}, {0xc2b06000}, 
+    {0xc2b08000}, {0xc2b0a000}, {0xc2b0c000}, {0xc2b0e000}, 
+    {0xc2b10000}, {0xc2b12000}, {0xc2b14000}, {0xc2b16000}, 
+    {0xc2b18000}, {0xc2b1a000}, {0xc2b1c000}, {0xc2b1e000}, 
+    {0xc2b20000}, {0xc2b22000}, {0xc2b24000}, {0xc2b26000}, 
+    {0xc2b28000}, {0xc2b2a000}, {0xc2b2c000}, {0xc2b2e000}, 
+    {0xc2b30000}, {0xc2b32000}, {0xc2b34000}, {0xc2b36000}, 
+    {0xc2b38000}, {0xc2b3a000}, {0xc2b3c000}, {0xc2b3e000}, 
+    {0xc2b40000}, {0xc2b42000}, {0xc2b44000}, {0xc2b46000}, 
+    {0xc2b48000}, {0xc2b4a000}, {0xc2b4c000}, {0xc2b4e000}, 
+    {0xc2b50000}, {0xc2b52000}, {0xc2b54000}, {0xc2b56000}, 
+    {0xc2b58000}, {0xc2b5a000}, {0xc2b5c000}, {0xc2b5e000}, 
+    {0xc2b60000}, {0xc2b62000}, {0xc2b64000}, {0xc2b66000}, 
+    {0xc2b68000}, {0xc2b6a000}, {0xc2b6c000}, {0xc2b6e000}, 
+    {0xc2b70000}, {0xc2b72000}, {0xc2b74000}, {0xc2b76000}, 
+    {0xc2b78000}, {0xc2b7a000}, {0xc2b7c000}, {0xc2b7e000}, 
+    {0xc2b80000}, {0xc2b82000}, {0xc2b84000}, {0xc2b86000}, 
+    {0xc2b88000}, {0xc2b8a000}, {0xc2b8c000}, {0xc2b8e000}, 
+    {0xc2b90000}, {0xc2b92000}, {0xc2b94000}, {0xc2b96000}, 
+    {0xc2b98000}, {0xc2b9a000}, {0xc2b9c000}, {0xc2b9e000}, 
+    {0xc2ba0000}, {0xc2ba2000}, {0xc2ba4000}, {0xc2ba6000}, 
+    {0xc2ba8000}, {0xc2baa000}, {0xc2bac000}, {0xc2bae000}, 
+    {0xc2bb0000}, {0xc2bb2000}, {0xc2bb4000}, {0xc2bb6000}, 
+    {0xc2bb8000}, {0xc2bba000}, {0xc2bbc000}, {0xc2bbe000}, 
+    {0xc2bc0000}, {0xc2bc2000}, {0xc2bc4000}, {0xc2bc6000}, 
+    {0xc2bc8000}, {0xc2bca000}, {0xc2bcc000}, {0xc2bce000}, 
+    {0xc2bd0000}, {0xc2bd2000}, {0xc2bd4000}, {0xc2bd6000}, 
+    {0xc2bd8000}, {0xc2bda000}, {0xc2bdc000}, {0xc2bde000}, 
+    {0xc2be0000}, {0xc2be2000}, {0xc2be4000}, {0xc2be6000}, 
+    {0xc2be8000}, {0xc2bea000}, {0xc2bec000}, {0xc2bee000}, 
+    {0xc2bf0000}, {0xc2bf2000}, {0xc2bf4000}, {0xc2bf6000}, 
+    {0xc2bf8000}, {0xc2bfa000}, {0xc2bfc000}, {0xc2bfe000}, 
+    {0xc2c00000}, {0xc2c02000}, {0xc2c04000}, {0xc2c06000}, 
+    {0xc2c08000}, {0xc2c0a000}, {0xc2c0c000}, {0xc2c0e000}, 
+    {0xc2c10000}, {0xc2c12000}, {0xc2c14000}, {0xc2c16000}, 
+    {0xc2c18000}, {0xc2c1a000}, {0xc2c1c000}, {0xc2c1e000}, 
+    {0xc2c20000}, {0xc2c22000}, {0xc2c24000}, {0xc2c26000}, 
+    {0xc2c28000}, {0xc2c2a000}, {0xc2c2c000}, {0xc2c2e000}, 
+    {0xc2c30000}, {0xc2c32000}, {0xc2c34000}, {0xc2c36000}, 
+    {0xc2c38000}, {0xc2c3a000}, {0xc2c3c000}, {0xc2c3e000}, 
+    {0xc2c40000}, {0xc2c42000}, {0xc2c44000}, {0xc2c46000}, 
+    {0xc2c48000}, {0xc2c4a000}, {0xc2c4c000}, {0xc2c4e000}, 
+    {0xc2c50000}, {0xc2c52000}, {0xc2c54000}, {0xc2c56000}, 
+    {0xc2c58000}, {0xc2c5a000}, {0xc2c5c000}, {0xc2c5e000}, 
+    {0xc2c60000}, {0xc2c62000}, {0xc2c64000}, {0xc2c66000}, 
+    {0xc2c68000}, {0xc2c6a000}, {0xc2c6c000}, {0xc2c6e000}, 
+    {0xc2c70000}, {0xc2c72000}, {0xc2c74000}, {0xc2c76000}, 
+    {0xc2c78000}, {0xc2c7a000}, {0xc2c7c000}, {0xc2c7e000}, 
+    {0xc2c80000}, {0xc2c82000}, {0xc2c84000}, {0xc2c86000}, 
+    {0xc2c88000}, {0xc2c8a000}, {0xc2c8c000}, {0xc2c8e000}, 
+    {0xc2c90000}, {0xc2c92000}, {0xc2c94000}, {0xc2c96000}, 
+    {0xc2c98000}, {0xc2c9a000}, {0xc2c9c000}, {0xc2c9e000}, 
+    {0xc2ca0000}, {0xc2ca2000}, {0xc2ca4000}, {0xc2ca6000}, 
+    {0xc2ca8000}, {0xc2caa000}, {0xc2cac000}, {0xc2cae000}, 
+    {0xc2cb0000}, {0xc2cb2000}, {0xc2cb4000}, {0xc2cb6000}, 
+    {0xc2cb8000}, {0xc2cba000}, {0xc2cbc000}, {0xc2cbe000}, 
+    {0xc2cc0000}, {0xc2cc2000}, {0xc2cc4000}, {0xc2cc6000}, 
+    {0xc2cc8000}, {0xc2cca000}, {0xc2ccc000}, {0xc2cce000}, 
+    {0xc2cd0000}, {0xc2cd2000}, {0xc2cd4000}, {0xc2cd6000}, 
+    {0xc2cd8000}, {0xc2cda000}, {0xc2cdc000}, {0xc2cde000}, 
+    {0xc2ce0000}, {0xc2ce2000}, {0xc2ce4000}, {0xc2ce6000}, 
+    {0xc2ce8000}, {0xc2cea000}, {0xc2cec000}, {0xc2cee000}, 
+    {0xc2cf0000}, {0xc2cf2000}, {0xc2cf4000}, {0xc2cf6000}, 
+    {0xc2cf8000}, {0xc2cfa000}, {0xc2cfc000}, {0xc2cfe000}, 
+    {0xc2d00000}, {0xc2d02000}, {0xc2d04000}, {0xc2d06000}, 
+    {0xc2d08000}, {0xc2d0a000}, {0xc2d0c000}, {0xc2d0e000}, 
+    {0xc2d10000}, {0xc2d12000}, {0xc2d14000}, {0xc2d16000}, 
+    {0xc2d18000}, {0xc2d1a000}, {0xc2d1c000}, {0xc2d1e000}, 
+    {0xc2d20000}, {0xc2d22000}, {0xc2d24000}, {0xc2d26000}, 
+    {0xc2d28000}, {0xc2d2a000}, {0xc2d2c000}, {0xc2d2e000}, 
+    {0xc2d30000}, {0xc2d32000}, {0xc2d34000}, {0xc2d36000}, 
+    {0xc2d38000}, {0xc2d3a000}, {0xc2d3c000}, {0xc2d3e000}, 
+    {0xc2d40000}, {0xc2d42000}, {0xc2d44000}, {0xc2d46000}, 
+    {0xc2d48000}, {0xc2d4a000}, {0xc2d4c000}, {0xc2d4e000}, 
+    {0xc2d50000}, {0xc2d52000}, {0xc2d54000}, {0xc2d56000}, 
+    {0xc2d58000}, {0xc2d5a000}, {0xc2d5c000}, {0xc2d5e000}, 
+    {0xc2d60000}, {0xc2d62000}, {0xc2d64000}, {0xc2d66000}, 
+    {0xc2d68000}, {0xc2d6a000}, {0xc2d6c000}, {0xc2d6e000}, 
+    {0xc2d70000}, {0xc2d72000}, {0xc2d74000}, {0xc2d76000}, 
+    {0xc2d78000}, {0xc2d7a000}, {0xc2d7c000}, {0xc2d7e000}, 
+    {0xc2d80000}, {0xc2d82000}, {0xc2d84000}, {0xc2d86000}, 
+    {0xc2d88000}, {0xc2d8a000}, {0xc2d8c000}, {0xc2d8e000}, 
+    {0xc2d90000}, {0xc2d92000}, {0xc2d94000}, {0xc2d96000}, 
+    {0xc2d98000}, {0xc2d9a000}, {0xc2d9c000}, {0xc2d9e000}, 
+    {0xc2da0000}, {0xc2da2000}, {0xc2da4000}, {0xc2da6000}, 
+    {0xc2da8000}, {0xc2daa000}, {0xc2dac000}, {0xc2dae000}, 
+    {0xc2db0000}, {0xc2db2000}, {0xc2db4000}, {0xc2db6000}, 
+    {0xc2db8000}, {0xc2dba000}, {0xc2dbc000}, {0xc2dbe000}, 
+    {0xc2dc0000}, {0xc2dc2000}, {0xc2dc4000}, {0xc2dc6000}, 
+    {0xc2dc8000}, {0xc2dca000}, {0xc2dcc000}, {0xc2dce000}, 
+    {0xc2dd0000}, {0xc2dd2000}, {0xc2dd4000}, {0xc2dd6000}, 
+    {0xc2dd8000}, {0xc2dda000}, {0xc2ddc000}, {0xc2dde000}, 
+    {0xc2de0000}, {0xc2de2000}, {0xc2de4000}, {0xc2de6000}, 
+    {0xc2de8000}, {0xc2dea000}, {0xc2dec000}, {0xc2dee000}, 
+    {0xc2df0000}, {0xc2df2000}, {0xc2df4000}, {0xc2df6000}, 
+    {0xc2df8000}, {0xc2dfa000}, {0xc2dfc000}, {0xc2dfe000}, 
+    {0xc2e00000}, {0xc2e02000}, {0xc2e04000}, {0xc2e06000}, 
+    {0xc2e08000}, {0xc2e0a000}, {0xc2e0c000}, {0xc2e0e000}, 
+    {0xc2e10000}, {0xc2e12000}, {0xc2e14000}, {0xc2e16000}, 
+    {0xc2e18000}, {0xc2e1a000}, {0xc2e1c000}, {0xc2e1e000}, 
+    {0xc2e20000}, {0xc2e22000}, {0xc2e24000}, {0xc2e26000}, 
+    {0xc2e28000}, {0xc2e2a000}, {0xc2e2c000}, {0xc2e2e000}, 
+    {0xc2e30000}, {0xc2e32000}, {0xc2e34000}, {0xc2e36000}, 
+    {0xc2e38000}, {0xc2e3a000}, {0xc2e3c000}, {0xc2e3e000}, 
+    {0xc2e40000}, {0xc2e42000}, {0xc2e44000}, {0xc2e46000}, 
+    {0xc2e48000}, {0xc2e4a000}, {0xc2e4c000}, {0xc2e4e000}, 
+    {0xc2e50000}, {0xc2e52000}, {0xc2e54000}, {0xc2e56000}, 
+    {0xc2e58000}, {0xc2e5a000}, {0xc2e5c000}, {0xc2e5e000}, 
+    {0xc2e60000}, {0xc2e62000}, {0xc2e64000}, {0xc2e66000}, 
+    {0xc2e68000}, {0xc2e6a000}, {0xc2e6c000}, {0xc2e6e000}, 
+    {0xc2e70000}, {0xc2e72000}, {0xc2e74000}, {0xc2e76000}, 
+    {0xc2e78000}, {0xc2e7a000}, {0xc2e7c000}, {0xc2e7e000}, 
+    {0xc2e80000}, {0xc2e82000}, {0xc2e84000}, {0xc2e86000}, 
+    {0xc2e88000}, {0xc2e8a000}, {0xc2e8c000}, {0xc2e8e000}, 
+    {0xc2e90000}, {0xc2e92000}, {0xc2e94000}, {0xc2e96000}, 
+    {0xc2e98000}, {0xc2e9a000}, {0xc2e9c000}, {0xc2e9e000}, 
+    {0xc2ea0000}, {0xc2ea2000}, {0xc2ea4000}, {0xc2ea6000}, 
+    {0xc2ea8000}, {0xc2eaa000}, {0xc2eac000}, {0xc2eae000}, 
+    {0xc2eb0000}, {0xc2eb2000}, {0xc2eb4000}, {0xc2eb6000}, 
+    {0xc2eb8000}, {0xc2eba000}, {0xc2ebc000}, {0xc2ebe000}, 
+    {0xc2ec0000}, {0xc2ec2000}, {0xc2ec4000}, {0xc2ec6000}, 
+    {0xc2ec8000}, {0xc2eca000}, {0xc2ecc000}, {0xc2ece000}, 
+    {0xc2ed0000}, {0xc2ed2000}, {0xc2ed4000}, {0xc2ed6000}, 
+    {0xc2ed8000}, {0xc2eda000}, {0xc2edc000}, {0xc2ede000}, 
+    {0xc2ee0000}, {0xc2ee2000}, {0xc2ee4000}, {0xc2ee6000}, 
+    {0xc2ee8000}, {0xc2eea000}, {0xc2eec000}, {0xc2eee000}, 
+    {0xc2ef0000}, {0xc2ef2000}, {0xc2ef4000}, {0xc2ef6000}, 
+    {0xc2ef8000}, {0xc2efa000}, {0xc2efc000}, {0xc2efe000}, 
+    {0xc2f00000}, {0xc2f02000}, {0xc2f04000}, {0xc2f06000}, 
+    {0xc2f08000}, {0xc2f0a000}, {0xc2f0c000}, {0xc2f0e000}, 
+    {0xc2f10000}, {0xc2f12000}, {0xc2f14000}, {0xc2f16000}, 
+    {0xc2f18000}, {0xc2f1a000}, {0xc2f1c000}, {0xc2f1e000}, 
+    {0xc2f20000}, {0xc2f22000}, {0xc2f24000}, {0xc2f26000}, 
+    {0xc2f28000}, {0xc2f2a000}, {0xc2f2c000}, {0xc2f2e000}, 
+    {0xc2f30000}, {0xc2f32000}, {0xc2f34000}, {0xc2f36000}, 
+    {0xc2f38000}, {0xc2f3a000}, {0xc2f3c000}, {0xc2f3e000}, 
+    {0xc2f40000}, {0xc2f42000}, {0xc2f44000}, {0xc2f46000}, 
+    {0xc2f48000}, {0xc2f4a000}, {0xc2f4c000}, {0xc2f4e000}, 
+    {0xc2f50000}, {0xc2f52000}, {0xc2f54000}, {0xc2f56000}, 
+    {0xc2f58000}, {0xc2f5a000}, {0xc2f5c000}, {0xc2f5e000}, 
+    {0xc2f60000}, {0xc2f62000}, {0xc2f64000}, {0xc2f66000}, 
+    {0xc2f68000}, {0xc2f6a000}, {0xc2f6c000}, {0xc2f6e000}, 
+    {0xc2f70000}, {0xc2f72000}, {0xc2f74000}, {0xc2f76000}, 
+    {0xc2f78000}, {0xc2f7a000}, {0xc2f7c000}, {0xc2f7e000}, 
+    {0xc2f80000}, {0xc2f82000}, {0xc2f84000}, {0xc2f86000}, 
+    {0xc2f88000}, {0xc2f8a000}, {0xc2f8c000}, {0xc2f8e000}, 
+    {0xc2f90000}, {0xc2f92000}, {0xc2f94000}, {0xc2f96000}, 
+    {0xc2f98000}, {0xc2f9a000}, {0xc2f9c000}, {0xc2f9e000}, 
+    {0xc2fa0000}, {0xc2fa2000}, {0xc2fa4000}, {0xc2fa6000}, 
+    {0xc2fa8000}, {0xc2faa000}, {0xc2fac000}, {0xc2fae000}, 
+    {0xc2fb0000}, {0xc2fb2000}, {0xc2fb4000}, {0xc2fb6000}, 
+    {0xc2fb8000}, {0xc2fba000}, {0xc2fbc000}, {0xc2fbe000}, 
+    {0xc2fc0000}, {0xc2fc2000}, {0xc2fc4000}, {0xc2fc6000}, 
+    {0xc2fc8000}, {0xc2fca000}, {0xc2fcc000}, {0xc2fce000}, 
+    {0xc2fd0000}, {0xc2fd2000}, {0xc2fd4000}, {0xc2fd6000}, 
+    {0xc2fd8000}, {0xc2fda000}, {0xc2fdc000}, {0xc2fde000}, 
+    {0xc2fe0000}, {0xc2fe2000}, {0xc2fe4000}, {0xc2fe6000}, 
+    {0xc2fe8000}, {0xc2fea000}, {0xc2fec000}, {0xc2fee000}, 
+    {0xc2ff0000}, {0xc2ff2000}, {0xc2ff4000}, {0xc2ff6000}, 
+    {0xc2ff8000}, {0xc2ffa000}, {0xc2ffc000}, {0xc2ffe000}, 
+    {0xc3000000}, {0xc3002000}, {0xc3004000}, {0xc3006000}, 
+    {0xc3008000}, {0xc300a000}, {0xc300c000}, {0xc300e000}, 
+    {0xc3010000}, {0xc3012000}, {0xc3014000}, {0xc3016000}, 
+    {0xc3018000}, {0xc301a000}, {0xc301c000}, {0xc301e000}, 
+    {0xc3020000}, {0xc3022000}, {0xc3024000}, {0xc3026000}, 
+    {0xc3028000}, {0xc302a000}, {0xc302c000}, {0xc302e000}, 
+    {0xc3030000}, {0xc3032000}, {0xc3034000}, {0xc3036000}, 
+    {0xc3038000}, {0xc303a000}, {0xc303c000}, {0xc303e000}, 
+    {0xc3040000}, {0xc3042000}, {0xc3044000}, {0xc3046000}, 
+    {0xc3048000}, {0xc304a000}, {0xc304c000}, {0xc304e000}, 
+    {0xc3050000}, {0xc3052000}, {0xc3054000}, {0xc3056000}, 
+    {0xc3058000}, {0xc305a000}, {0xc305c000}, {0xc305e000}, 
+    {0xc3060000}, {0xc3062000}, {0xc3064000}, {0xc3066000}, 
+    {0xc3068000}, {0xc306a000}, {0xc306c000}, {0xc306e000}, 
+    {0xc3070000}, {0xc3072000}, {0xc3074000}, {0xc3076000}, 
+    {0xc3078000}, {0xc307a000}, {0xc307c000}, {0xc307e000}, 
+    {0xc3080000}, {0xc3082000}, {0xc3084000}, {0xc3086000}, 
+    {0xc3088000}, {0xc308a000}, {0xc308c000}, {0xc308e000}, 
+    {0xc3090000}, {0xc3092000}, {0xc3094000}, {0xc3096000}, 
+    {0xc3098000}, {0xc309a000}, {0xc309c000}, {0xc309e000}, 
+    {0xc30a0000}, {0xc30a2000}, {0xc30a4000}, {0xc30a6000}, 
+    {0xc30a8000}, {0xc30aa000}, {0xc30ac000}, {0xc30ae000}, 
+    {0xc30b0000}, {0xc30b2000}, {0xc30b4000}, {0xc30b6000}, 
+    {0xc30b8000}, {0xc30ba000}, {0xc30bc000}, {0xc30be000}, 
+    {0xc30c0000}, {0xc30c2000}, {0xc30c4000}, {0xc30c6000}, 
+    {0xc30c8000}, {0xc30ca000}, {0xc30cc000}, {0xc30ce000}, 
+    {0xc30d0000}, {0xc30d2000}, {0xc30d4000}, {0xc30d6000}, 
+    {0xc30d8000}, {0xc30da000}, {0xc30dc000}, {0xc30de000}, 
+    {0xc30e0000}, {0xc30e2000}, {0xc30e4000}, {0xc30e6000}, 
+    {0xc30e8000}, {0xc30ea000}, {0xc30ec000}, {0xc30ee000}, 
+    {0xc30f0000}, {0xc30f2000}, {0xc30f4000}, {0xc30f6000}, 
+    {0xc30f8000}, {0xc30fa000}, {0xc30fc000}, {0xc30fe000}, 
+    {0xc3100000}, {0xc3102000}, {0xc3104000}, {0xc3106000}, 
+    {0xc3108000}, {0xc310a000}, {0xc310c000}, {0xc310e000}, 
+    {0xc3110000}, {0xc3112000}, {0xc3114000}, {0xc3116000}, 
+    {0xc3118000}, {0xc311a000}, {0xc311c000}, {0xc311e000}, 
+    {0xc3120000}, {0xc3122000}, {0xc3124000}, {0xc3126000}, 
+    {0xc3128000}, {0xc312a000}, {0xc312c000}, {0xc312e000}, 
+    {0xc3130000}, {0xc3132000}, {0xc3134000}, {0xc3136000}, 
+    {0xc3138000}, {0xc313a000}, {0xc313c000}, {0xc313e000}, 
+    {0xc3140000}, {0xc3142000}, {0xc3144000}, {0xc3146000}, 
+    {0xc3148000}, {0xc314a000}, {0xc314c000}, {0xc314e000}, 
+    {0xc3150000}, {0xc3152000}, {0xc3154000}, {0xc3156000}, 
+    {0xc3158000}, {0xc315a000}, {0xc315c000}, {0xc315e000}, 
+    {0xc3160000}, {0xc3162000}, {0xc3164000}, {0xc3166000}, 
+    {0xc3168000}, {0xc316a000}, {0xc316c000}, {0xc316e000}, 
+    {0xc3170000}, {0xc3172000}, {0xc3174000}, {0xc3176000}, 
+    {0xc3178000}, {0xc317a000}, {0xc317c000}, {0xc317e000}, 
+    {0xc3180000}, {0xc3182000}, {0xc3184000}, {0xc3186000}, 
+    {0xc3188000}, {0xc318a000}, {0xc318c000}, {0xc318e000}, 
+    {0xc3190000}, {0xc3192000}, {0xc3194000}, {0xc3196000}, 
+    {0xc3198000}, {0xc319a000}, {0xc319c000}, {0xc319e000}, 
+    {0xc31a0000}, {0xc31a2000}, {0xc31a4000}, {0xc31a6000}, 
+    {0xc31a8000}, {0xc31aa000}, {0xc31ac000}, {0xc31ae000}, 
+    {0xc31b0000}, {0xc31b2000}, {0xc31b4000}, {0xc31b6000}, 
+    {0xc31b8000}, {0xc31ba000}, {0xc31bc000}, {0xc31be000}, 
+    {0xc31c0000}, {0xc31c2000}, {0xc31c4000}, {0xc31c6000}, 
+    {0xc31c8000}, {0xc31ca000}, {0xc31cc000}, {0xc31ce000}, 
+    {0xc31d0000}, {0xc31d2000}, {0xc31d4000}, {0xc31d6000}, 
+    {0xc31d8000}, {0xc31da000}, {0xc31dc000}, {0xc31de000}, 
+    {0xc31e0000}, {0xc31e2000}, {0xc31e4000}, {0xc31e6000}, 
+    {0xc31e8000}, {0xc31ea000}, {0xc31ec000}, {0xc31ee000}, 
+    {0xc31f0000}, {0xc31f2000}, {0xc31f4000}, {0xc31f6000}, 
+    {0xc31f8000}, {0xc31fa000}, {0xc31fc000}, {0xc31fe000}, 
+    {0xc3200000}, {0xc3202000}, {0xc3204000}, {0xc3206000}, 
+    {0xc3208000}, {0xc320a000}, {0xc320c000}, {0xc320e000}, 
+    {0xc3210000}, {0xc3212000}, {0xc3214000}, {0xc3216000}, 
+    {0xc3218000}, {0xc321a000}, {0xc321c000}, {0xc321e000}, 
+    {0xc3220000}, {0xc3222000}, {0xc3224000}, {0xc3226000}, 
+    {0xc3228000}, {0xc322a000}, {0xc322c000}, {0xc322e000}, 
+    {0xc3230000}, {0xc3232000}, {0xc3234000}, {0xc3236000}, 
+    {0xc3238000}, {0xc323a000}, {0xc323c000}, {0xc323e000}, 
+    {0xc3240000}, {0xc3242000}, {0xc3244000}, {0xc3246000}, 
+    {0xc3248000}, {0xc324a000}, {0xc324c000}, {0xc324e000}, 
+    {0xc3250000}, {0xc3252000}, {0xc3254000}, {0xc3256000}, 
+    {0xc3258000}, {0xc325a000}, {0xc325c000}, {0xc325e000}, 
+    {0xc3260000}, {0xc3262000}, {0xc3264000}, {0xc3266000}, 
+    {0xc3268000}, {0xc326a000}, {0xc326c000}, {0xc326e000}, 
+    {0xc3270000}, {0xc3272000}, {0xc3274000}, {0xc3276000}, 
+    {0xc3278000}, {0xc327a000}, {0xc327c000}, {0xc327e000}, 
+    {0xc3280000}, {0xc3282000}, {0xc3284000}, {0xc3286000}, 
+    {0xc3288000}, {0xc328a000}, {0xc328c000}, {0xc328e000}, 
+    {0xc3290000}, {0xc3292000}, {0xc3294000}, {0xc3296000}, 
+    {0xc3298000}, {0xc329a000}, {0xc329c000}, {0xc329e000}, 
+    {0xc32a0000}, {0xc32a2000}, {0xc32a4000}, {0xc32a6000}, 
+    {0xc32a8000}, {0xc32aa000}, {0xc32ac000}, {0xc32ae000}, 
+    {0xc32b0000}, {0xc32b2000}, {0xc32b4000}, {0xc32b6000}, 
+    {0xc32b8000}, {0xc32ba000}, {0xc32bc000}, {0xc32be000}, 
+    {0xc32c0000}, {0xc32c2000}, {0xc32c4000}, {0xc32c6000}, 
+    {0xc32c8000}, {0xc32ca000}, {0xc32cc000}, {0xc32ce000}, 
+    {0xc32d0000}, {0xc32d2000}, {0xc32d4000}, {0xc32d6000}, 
+    {0xc32d8000}, {0xc32da000}, {0xc32dc000}, {0xc32de000}, 
+    {0xc32e0000}, {0xc32e2000}, {0xc32e4000}, {0xc32e6000}, 
+    {0xc32e8000}, {0xc32ea000}, {0xc32ec000}, {0xc32ee000}, 
+    {0xc32f0000}, {0xc32f2000}, {0xc32f4000}, {0xc32f6000}, 
+    {0xc32f8000}, {0xc32fa000}, {0xc32fc000}, {0xc32fe000}, 
+    {0xc3300000}, {0xc3302000}, {0xc3304000}, {0xc3306000}, 
+    {0xc3308000}, {0xc330a000}, {0xc330c000}, {0xc330e000}, 
+    {0xc3310000}, {0xc3312000}, {0xc3314000}, {0xc3316000}, 
+    {0xc3318000}, {0xc331a000}, {0xc331c000}, {0xc331e000}, 
+    {0xc3320000}, {0xc3322000}, {0xc3324000}, {0xc3326000}, 
+    {0xc3328000}, {0xc332a000}, {0xc332c000}, {0xc332e000}, 
+    {0xc3330000}, {0xc3332000}, {0xc3334000}, {0xc3336000}, 
+    {0xc3338000}, {0xc333a000}, {0xc333c000}, {0xc333e000}, 
+    {0xc3340000}, {0xc3342000}, {0xc3344000}, {0xc3346000}, 
+    {0xc3348000}, {0xc334a000}, {0xc334c000}, {0xc334e000}, 
+    {0xc3350000}, {0xc3352000}, {0xc3354000}, {0xc3356000}, 
+    {0xc3358000}, {0xc335a000}, {0xc335c000}, {0xc335e000}, 
+    {0xc3360000}, {0xc3362000}, {0xc3364000}, {0xc3366000}, 
+    {0xc3368000}, {0xc336a000}, {0xc336c000}, {0xc336e000}, 
+    {0xc3370000}, {0xc3372000}, {0xc3374000}, {0xc3376000}, 
+    {0xc3378000}, {0xc337a000}, {0xc337c000}, {0xc337e000}, 
+    {0xc3380000}, {0xc3382000}, {0xc3384000}, {0xc3386000}, 
+    {0xc3388000}, {0xc338a000}, {0xc338c000}, {0xc338e000}, 
+    {0xc3390000}, {0xc3392000}, {0xc3394000}, {0xc3396000}, 
+    {0xc3398000}, {0xc339a000}, {0xc339c000}, {0xc339e000}, 
+    {0xc33a0000}, {0xc33a2000}, {0xc33a4000}, {0xc33a6000}, 
+    {0xc33a8000}, {0xc33aa000}, {0xc33ac000}, {0xc33ae000}, 
+    {0xc33b0000}, {0xc33b2000}, {0xc33b4000}, {0xc33b6000}, 
+    {0xc33b8000}, {0xc33ba000}, {0xc33bc000}, {0xc33be000}, 
+    {0xc33c0000}, {0xc33c2000}, {0xc33c4000}, {0xc33c6000}, 
+    {0xc33c8000}, {0xc33ca000}, {0xc33cc000}, {0xc33ce000}, 
+    {0xc33d0000}, {0xc33d2000}, {0xc33d4000}, {0xc33d6000}, 
+    {0xc33d8000}, {0xc33da000}, {0xc33dc000}, {0xc33de000}, 
+    {0xc33e0000}, {0xc33e2000}, {0xc33e4000}, {0xc33e6000}, 
+    {0xc33e8000}, {0xc33ea000}, {0xc33ec000}, {0xc33ee000}, 
+    {0xc33f0000}, {0xc33f2000}, {0xc33f4000}, {0xc33f6000}, 
+    {0xc33f8000}, {0xc33fa000}, {0xc33fc000}, {0xc33fe000}, 
+    {0xc3400000}, {0xc3402000}, {0xc3404000}, {0xc3406000}, 
+    {0xc3408000}, {0xc340a000}, {0xc340c000}, {0xc340e000}, 
+    {0xc3410000}, {0xc3412000}, {0xc3414000}, {0xc3416000}, 
+    {0xc3418000}, {0xc341a000}, {0xc341c000}, {0xc341e000}, 
+    {0xc3420000}, {0xc3422000}, {0xc3424000}, {0xc3426000}, 
+    {0xc3428000}, {0xc342a000}, {0xc342c000}, {0xc342e000}, 
+    {0xc3430000}, {0xc3432000}, {0xc3434000}, {0xc3436000}, 
+    {0xc3438000}, {0xc343a000}, {0xc343c000}, {0xc343e000}, 
+    {0xc3440000}, {0xc3442000}, {0xc3444000}, {0xc3446000}, 
+    {0xc3448000}, {0xc344a000}, {0xc344c000}, {0xc344e000}, 
+    {0xc3450000}, {0xc3452000}, {0xc3454000}, {0xc3456000}, 
+    {0xc3458000}, {0xc345a000}, {0xc345c000}, {0xc345e000}, 
+    {0xc3460000}, {0xc3462000}, {0xc3464000}, {0xc3466000}, 
+    {0xc3468000}, {0xc346a000}, {0xc346c000}, {0xc346e000}, 
+    {0xc3470000}, {0xc3472000}, {0xc3474000}, {0xc3476000}, 
+    {0xc3478000}, {0xc347a000}, {0xc347c000}, {0xc347e000}, 
+    {0xc3480000}, {0xc3482000}, {0xc3484000}, {0xc3486000}, 
+    {0xc3488000}, {0xc348a000}, {0xc348c000}, {0xc348e000}, 
+    {0xc3490000}, {0xc3492000}, {0xc3494000}, {0xc3496000}, 
+    {0xc3498000}, {0xc349a000}, {0xc349c000}, {0xc349e000}, 
+    {0xc34a0000}, {0xc34a2000}, {0xc34a4000}, {0xc34a6000}, 
+    {0xc34a8000}, {0xc34aa000}, {0xc34ac000}, {0xc34ae000}, 
+    {0xc34b0000}, {0xc34b2000}, {0xc34b4000}, {0xc34b6000}, 
+    {0xc34b8000}, {0xc34ba000}, {0xc34bc000}, {0xc34be000}, 
+    {0xc34c0000}, {0xc34c2000}, {0xc34c4000}, {0xc34c6000}, 
+    {0xc34c8000}, {0xc34ca000}, {0xc34cc000}, {0xc34ce000}, 
+    {0xc34d0000}, {0xc34d2000}, {0xc34d4000}, {0xc34d6000}, 
+    {0xc34d8000}, {0xc34da000}, {0xc34dc000}, {0xc34de000}, 
+    {0xc34e0000}, {0xc34e2000}, {0xc34e4000}, {0xc34e6000}, 
+    {0xc34e8000}, {0xc34ea000}, {0xc34ec000}, {0xc34ee000}, 
+    {0xc34f0000}, {0xc34f2000}, {0xc34f4000}, {0xc34f6000}, 
+    {0xc34f8000}, {0xc34fa000}, {0xc34fc000}, {0xc34fe000}, 
+    {0xc3500000}, {0xc3502000}, {0xc3504000}, {0xc3506000}, 
+    {0xc3508000}, {0xc350a000}, {0xc350c000}, {0xc350e000}, 
+    {0xc3510000}, {0xc3512000}, {0xc3514000}, {0xc3516000}, 
+    {0xc3518000}, {0xc351a000}, {0xc351c000}, {0xc351e000}, 
+    {0xc3520000}, {0xc3522000}, {0xc3524000}, {0xc3526000}, 
+    {0xc3528000}, {0xc352a000}, {0xc352c000}, {0xc352e000}, 
+    {0xc3530000}, {0xc3532000}, {0xc3534000}, {0xc3536000}, 
+    {0xc3538000}, {0xc353a000}, {0xc353c000}, {0xc353e000}, 
+    {0xc3540000}, {0xc3542000}, {0xc3544000}, {0xc3546000}, 
+    {0xc3548000}, {0xc354a000}, {0xc354c000}, {0xc354e000}, 
+    {0xc3550000}, {0xc3552000}, {0xc3554000}, {0xc3556000}, 
+    {0xc3558000}, {0xc355a000}, {0xc355c000}, {0xc355e000}, 
+    {0xc3560000}, {0xc3562000}, {0xc3564000}, {0xc3566000}, 
+    {0xc3568000}, {0xc356a000}, {0xc356c000}, {0xc356e000}, 
+    {0xc3570000}, {0xc3572000}, {0xc3574000}, {0xc3576000}, 
+    {0xc3578000}, {0xc357a000}, {0xc357c000}, {0xc357e000}, 
+    {0xc3580000}, {0xc3582000}, {0xc3584000}, {0xc3586000}, 
+    {0xc3588000}, {0xc358a000}, {0xc358c000}, {0xc358e000}, 
+    {0xc3590000}, {0xc3592000}, {0xc3594000}, {0xc3596000}, 
+    {0xc3598000}, {0xc359a000}, {0xc359c000}, {0xc359e000}, 
+    {0xc35a0000}, {0xc35a2000}, {0xc35a4000}, {0xc35a6000}, 
+    {0xc35a8000}, {0xc35aa000}, {0xc35ac000}, {0xc35ae000}, 
+    {0xc35b0000}, {0xc35b2000}, {0xc35b4000}, {0xc35b6000}, 
+    {0xc35b8000}, {0xc35ba000}, {0xc35bc000}, {0xc35be000}, 
+    {0xc35c0000}, {0xc35c2000}, {0xc35c4000}, {0xc35c6000}, 
+    {0xc35c8000}, {0xc35ca000}, {0xc35cc000}, {0xc35ce000}, 
+    {0xc35d0000}, {0xc35d2000}, {0xc35d4000}, {0xc35d6000}, 
+    {0xc35d8000}, {0xc35da000}, {0xc35dc000}, {0xc35de000}, 
+    {0xc35e0000}, {0xc35e2000}, {0xc35e4000}, {0xc35e6000}, 
+    {0xc35e8000}, {0xc35ea000}, {0xc35ec000}, {0xc35ee000}, 
+    {0xc35f0000}, {0xc35f2000}, {0xc35f4000}, {0xc35f6000}, 
+    {0xc35f8000}, {0xc35fa000}, {0xc35fc000}, {0xc35fe000}, 
+    {0xc3600000}, {0xc3602000}, {0xc3604000}, {0xc3606000}, 
+    {0xc3608000}, {0xc360a000}, {0xc360c000}, {0xc360e000}, 
+    {0xc3610000}, {0xc3612000}, {0xc3614000}, {0xc3616000}, 
+    {0xc3618000}, {0xc361a000}, {0xc361c000}, {0xc361e000}, 
+    {0xc3620000}, {0xc3622000}, {0xc3624000}, {0xc3626000}, 
+    {0xc3628000}, {0xc362a000}, {0xc362c000}, {0xc362e000}, 
+    {0xc3630000}, {0xc3632000}, {0xc3634000}, {0xc3636000}, 
+    {0xc3638000}, {0xc363a000}, {0xc363c000}, {0xc363e000}, 
+    {0xc3640000}, {0xc3642000}, {0xc3644000}, {0xc3646000}, 
+    {0xc3648000}, {0xc364a000}, {0xc364c000}, {0xc364e000}, 
+    {0xc3650000}, {0xc3652000}, {0xc3654000}, {0xc3656000}, 
+    {0xc3658000}, {0xc365a000}, {0xc365c000}, {0xc365e000}, 
+    {0xc3660000}, {0xc3662000}, {0xc3664000}, {0xc3666000}, 
+    {0xc3668000}, {0xc366a000}, {0xc366c000}, {0xc366e000}, 
+    {0xc3670000}, {0xc3672000}, {0xc3674000}, {0xc3676000}, 
+    {0xc3678000}, {0xc367a000}, {0xc367c000}, {0xc367e000}, 
+    {0xc3680000}, {0xc3682000}, {0xc3684000}, {0xc3686000}, 
+    {0xc3688000}, {0xc368a000}, {0xc368c000}, {0xc368e000}, 
+    {0xc3690000}, {0xc3692000}, {0xc3694000}, {0xc3696000}, 
+    {0xc3698000}, {0xc369a000}, {0xc369c000}, {0xc369e000}, 
+    {0xc36a0000}, {0xc36a2000}, {0xc36a4000}, {0xc36a6000}, 
+    {0xc36a8000}, {0xc36aa000}, {0xc36ac000}, {0xc36ae000}, 
+    {0xc36b0000}, {0xc36b2000}, {0xc36b4000}, {0xc36b6000}, 
+    {0xc36b8000}, {0xc36ba000}, {0xc36bc000}, {0xc36be000}, 
+    {0xc36c0000}, {0xc36c2000}, {0xc36c4000}, {0xc36c6000}, 
+    {0xc36c8000}, {0xc36ca000}, {0xc36cc000}, {0xc36ce000}, 
+    {0xc36d0000}, {0xc36d2000}, {0xc36d4000}, {0xc36d6000}, 
+    {0xc36d8000}, {0xc36da000}, {0xc36dc000}, {0xc36de000}, 
+    {0xc36e0000}, {0xc36e2000}, {0xc36e4000}, {0xc36e6000}, 
+    {0xc36e8000}, {0xc36ea000}, {0xc36ec000}, {0xc36ee000}, 
+    {0xc36f0000}, {0xc36f2000}, {0xc36f4000}, {0xc36f6000}, 
+    {0xc36f8000}, {0xc36fa000}, {0xc36fc000}, {0xc36fe000}, 
+    {0xc3700000}, {0xc3702000}, {0xc3704000}, {0xc3706000}, 
+    {0xc3708000}, {0xc370a000}, {0xc370c000}, {0xc370e000}, 
+    {0xc3710000}, {0xc3712000}, {0xc3714000}, {0xc3716000}, 
+    {0xc3718000}, {0xc371a000}, {0xc371c000}, {0xc371e000}, 
+    {0xc3720000}, {0xc3722000}, {0xc3724000}, {0xc3726000}, 
+    {0xc3728000}, {0xc372a000}, {0xc372c000}, {0xc372e000}, 
+    {0xc3730000}, {0xc3732000}, {0xc3734000}, {0xc3736000}, 
+    {0xc3738000}, {0xc373a000}, {0xc373c000}, {0xc373e000}, 
+    {0xc3740000}, {0xc3742000}, {0xc3744000}, {0xc3746000}, 
+    {0xc3748000}, {0xc374a000}, {0xc374c000}, {0xc374e000}, 
+    {0xc3750000}, {0xc3752000}, {0xc3754000}, {0xc3756000}, 
+    {0xc3758000}, {0xc375a000}, {0xc375c000}, {0xc375e000}, 
+    {0xc3760000}, {0xc3762000}, {0xc3764000}, {0xc3766000}, 
+    {0xc3768000}, {0xc376a000}, {0xc376c000}, {0xc376e000}, 
+    {0xc3770000}, {0xc3772000}, {0xc3774000}, {0xc3776000}, 
+    {0xc3778000}, {0xc377a000}, {0xc377c000}, {0xc377e000}, 
+    {0xc3780000}, {0xc3782000}, {0xc3784000}, {0xc3786000}, 
+    {0xc3788000}, {0xc378a000}, {0xc378c000}, {0xc378e000}, 
+    {0xc3790000}, {0xc3792000}, {0xc3794000}, {0xc3796000}, 
+    {0xc3798000}, {0xc379a000}, {0xc379c000}, {0xc379e000}, 
+    {0xc37a0000}, {0xc37a2000}, {0xc37a4000}, {0xc37a6000}, 
+    {0xc37a8000}, {0xc37aa000}, {0xc37ac000}, {0xc37ae000}, 
+    {0xc37b0000}, {0xc37b2000}, {0xc37b4000}, {0xc37b6000}, 
+    {0xc37b8000}, {0xc37ba000}, {0xc37bc000}, {0xc37be000}, 
+    {0xc37c0000}, {0xc37c2000}, {0xc37c4000}, {0xc37c6000}, 
+    {0xc37c8000}, {0xc37ca000}, {0xc37cc000}, {0xc37ce000}, 
+    {0xc37d0000}, {0xc37d2000}, {0xc37d4000}, {0xc37d6000}, 
+    {0xc37d8000}, {0xc37da000}, {0xc37dc000}, {0xc37de000}, 
+    {0xc37e0000}, {0xc37e2000}, {0xc37e4000}, {0xc37e6000}, 
+    {0xc37e8000}, {0xc37ea000}, {0xc37ec000}, {0xc37ee000}, 
+    {0xc37f0000}, {0xc37f2000}, {0xc37f4000}, {0xc37f6000}, 
+    {0xc37f8000}, {0xc37fa000}, {0xc37fc000}, {0xc37fe000}, 
+    {0xc3800000}, {0xc3802000}, {0xc3804000}, {0xc3806000}, 
+    {0xc3808000}, {0xc380a000}, {0xc380c000}, {0xc380e000}, 
+    {0xc3810000}, {0xc3812000}, {0xc3814000}, {0xc3816000}, 
+    {0xc3818000}, {0xc381a000}, {0xc381c000}, {0xc381e000}, 
+    {0xc3820000}, {0xc3822000}, {0xc3824000}, {0xc3826000}, 
+    {0xc3828000}, {0xc382a000}, {0xc382c000}, {0xc382e000}, 
+    {0xc3830000}, {0xc3832000}, {0xc3834000}, {0xc3836000}, 
+    {0xc3838000}, {0xc383a000}, {0xc383c000}, {0xc383e000}, 
+    {0xc3840000}, {0xc3842000}, {0xc3844000}, {0xc3846000}, 
+    {0xc3848000}, {0xc384a000}, {0xc384c000}, {0xc384e000}, 
+    {0xc3850000}, {0xc3852000}, {0xc3854000}, {0xc3856000}, 
+    {0xc3858000}, {0xc385a000}, {0xc385c000}, {0xc385e000}, 
+    {0xc3860000}, {0xc3862000}, {0xc3864000}, {0xc3866000}, 
+    {0xc3868000}, {0xc386a000}, {0xc386c000}, {0xc386e000}, 
+    {0xc3870000}, {0xc3872000}, {0xc3874000}, {0xc3876000}, 
+    {0xc3878000}, {0xc387a000}, {0xc387c000}, {0xc387e000}, 
+    {0xc3880000}, {0xc3882000}, {0xc3884000}, {0xc3886000}, 
+    {0xc3888000}, {0xc388a000}, {0xc388c000}, {0xc388e000}, 
+    {0xc3890000}, {0xc3892000}, {0xc3894000}, {0xc3896000}, 
+    {0xc3898000}, {0xc389a000}, {0xc389c000}, {0xc389e000}, 
+    {0xc38a0000}, {0xc38a2000}, {0xc38a4000}, {0xc38a6000}, 
+    {0xc38a8000}, {0xc38aa000}, {0xc38ac000}, {0xc38ae000}, 
+    {0xc38b0000}, {0xc38b2000}, {0xc38b4000}, {0xc38b6000}, 
+    {0xc38b8000}, {0xc38ba000}, {0xc38bc000}, {0xc38be000}, 
+    {0xc38c0000}, {0xc38c2000}, {0xc38c4000}, {0xc38c6000}, 
+    {0xc38c8000}, {0xc38ca000}, {0xc38cc000}, {0xc38ce000}, 
+    {0xc38d0000}, {0xc38d2000}, {0xc38d4000}, {0xc38d6000}, 
+    {0xc38d8000}, {0xc38da000}, {0xc38dc000}, {0xc38de000}, 
+    {0xc38e0000}, {0xc38e2000}, {0xc38e4000}, {0xc38e6000}, 
+    {0xc38e8000}, {0xc38ea000}, {0xc38ec000}, {0xc38ee000}, 
+    {0xc38f0000}, {0xc38f2000}, {0xc38f4000}, {0xc38f6000}, 
+    {0xc38f8000}, {0xc38fa000}, {0xc38fc000}, {0xc38fe000}, 
+    {0xc3900000}, {0xc3902000}, {0xc3904000}, {0xc3906000}, 
+    {0xc3908000}, {0xc390a000}, {0xc390c000}, {0xc390e000}, 
+    {0xc3910000}, {0xc3912000}, {0xc3914000}, {0xc3916000}, 
+    {0xc3918000}, {0xc391a000}, {0xc391c000}, {0xc391e000}, 
+    {0xc3920000}, {0xc3922000}, {0xc3924000}, {0xc3926000}, 
+    {0xc3928000}, {0xc392a000}, {0xc392c000}, {0xc392e000}, 
+    {0xc3930000}, {0xc3932000}, {0xc3934000}, {0xc3936000}, 
+    {0xc3938000}, {0xc393a000}, {0xc393c000}, {0xc393e000}, 
+    {0xc3940000}, {0xc3942000}, {0xc3944000}, {0xc3946000}, 
+    {0xc3948000}, {0xc394a000}, {0xc394c000}, {0xc394e000}, 
+    {0xc3950000}, {0xc3952000}, {0xc3954000}, {0xc3956000}, 
+    {0xc3958000}, {0xc395a000}, {0xc395c000}, {0xc395e000}, 
+    {0xc3960000}, {0xc3962000}, {0xc3964000}, {0xc3966000}, 
+    {0xc3968000}, {0xc396a000}, {0xc396c000}, {0xc396e000}, 
+    {0xc3970000}, {0xc3972000}, {0xc3974000}, {0xc3976000}, 
+    {0xc3978000}, {0xc397a000}, {0xc397c000}, {0xc397e000}, 
+    {0xc3980000}, {0xc3982000}, {0xc3984000}, {0xc3986000}, 
+    {0xc3988000}, {0xc398a000}, {0xc398c000}, {0xc398e000}, 
+    {0xc3990000}, {0xc3992000}, {0xc3994000}, {0xc3996000}, 
+    {0xc3998000}, {0xc399a000}, {0xc399c000}, {0xc399e000}, 
+    {0xc39a0000}, {0xc39a2000}, {0xc39a4000}, {0xc39a6000}, 
+    {0xc39a8000}, {0xc39aa000}, {0xc39ac000}, {0xc39ae000}, 
+    {0xc39b0000}, {0xc39b2000}, {0xc39b4000}, {0xc39b6000}, 
+    {0xc39b8000}, {0xc39ba000}, {0xc39bc000}, {0xc39be000}, 
+    {0xc39c0000}, {0xc39c2000}, {0xc39c4000}, {0xc39c6000}, 
+    {0xc39c8000}, {0xc39ca000}, {0xc39cc000}, {0xc39ce000}, 
+    {0xc39d0000}, {0xc39d2000}, {0xc39d4000}, {0xc39d6000}, 
+    {0xc39d8000}, {0xc39da000}, {0xc39dc000}, {0xc39de000}, 
+    {0xc39e0000}, {0xc39e2000}, {0xc39e4000}, {0xc39e6000}, 
+    {0xc39e8000}, {0xc39ea000}, {0xc39ec000}, {0xc39ee000}, 
+    {0xc39f0000}, {0xc39f2000}, {0xc39f4000}, {0xc39f6000}, 
+    {0xc39f8000}, {0xc39fa000}, {0xc39fc000}, {0xc39fe000}, 
+    {0xc3a00000}, {0xc3a02000}, {0xc3a04000}, {0xc3a06000}, 
+    {0xc3a08000}, {0xc3a0a000}, {0xc3a0c000}, {0xc3a0e000}, 
+    {0xc3a10000}, {0xc3a12000}, {0xc3a14000}, {0xc3a16000}, 
+    {0xc3a18000}, {0xc3a1a000}, {0xc3a1c000}, {0xc3a1e000}, 
+    {0xc3a20000}, {0xc3a22000}, {0xc3a24000}, {0xc3a26000}, 
+    {0xc3a28000}, {0xc3a2a000}, {0xc3a2c000}, {0xc3a2e000}, 
+    {0xc3a30000}, {0xc3a32000}, {0xc3a34000}, {0xc3a36000}, 
+    {0xc3a38000}, {0xc3a3a000}, {0xc3a3c000}, {0xc3a3e000}, 
+    {0xc3a40000}, {0xc3a42000}, {0xc3a44000}, {0xc3a46000}, 
+    {0xc3a48000}, {0xc3a4a000}, {0xc3a4c000}, {0xc3a4e000}, 
+    {0xc3a50000}, {0xc3a52000}, {0xc3a54000}, {0xc3a56000}, 
+    {0xc3a58000}, {0xc3a5a000}, {0xc3a5c000}, {0xc3a5e000}, 
+    {0xc3a60000}, {0xc3a62000}, {0xc3a64000}, {0xc3a66000}, 
+    {0xc3a68000}, {0xc3a6a000}, {0xc3a6c000}, {0xc3a6e000}, 
+    {0xc3a70000}, {0xc3a72000}, {0xc3a74000}, {0xc3a76000}, 
+    {0xc3a78000}, {0xc3a7a000}, {0xc3a7c000}, {0xc3a7e000}, 
+    {0xc3a80000}, {0xc3a82000}, {0xc3a84000}, {0xc3a86000}, 
+    {0xc3a88000}, {0xc3a8a000}, {0xc3a8c000}, {0xc3a8e000}, 
+    {0xc3a90000}, {0xc3a92000}, {0xc3a94000}, {0xc3a96000}, 
+    {0xc3a98000}, {0xc3a9a000}, {0xc3a9c000}, {0xc3a9e000}, 
+    {0xc3aa0000}, {0xc3aa2000}, {0xc3aa4000}, {0xc3aa6000}, 
+    {0xc3aa8000}, {0xc3aaa000}, {0xc3aac000}, {0xc3aae000}, 
+    {0xc3ab0000}, {0xc3ab2000}, {0xc3ab4000}, {0xc3ab6000}, 
+    {0xc3ab8000}, {0xc3aba000}, {0xc3abc000}, {0xc3abe000}, 
+    {0xc3ac0000}, {0xc3ac2000}, {0xc3ac4000}, {0xc3ac6000}, 
+    {0xc3ac8000}, {0xc3aca000}, {0xc3acc000}, {0xc3ace000}, 
+    {0xc3ad0000}, {0xc3ad2000}, {0xc3ad4000}, {0xc3ad6000}, 
+    {0xc3ad8000}, {0xc3ada000}, {0xc3adc000}, {0xc3ade000}, 
+    {0xc3ae0000}, {0xc3ae2000}, {0xc3ae4000}, {0xc3ae6000}, 
+    {0xc3ae8000}, {0xc3aea000}, {0xc3aec000}, {0xc3aee000}, 
+    {0xc3af0000}, {0xc3af2000}, {0xc3af4000}, {0xc3af6000}, 
+    {0xc3af8000}, {0xc3afa000}, {0xc3afc000}, {0xc3afe000}, 
+    {0xc3b00000}, {0xc3b02000}, {0xc3b04000}, {0xc3b06000}, 
+    {0xc3b08000}, {0xc3b0a000}, {0xc3b0c000}, {0xc3b0e000}, 
+    {0xc3b10000}, {0xc3b12000}, {0xc3b14000}, {0xc3b16000}, 
+    {0xc3b18000}, {0xc3b1a000}, {0xc3b1c000}, {0xc3b1e000}, 
+    {0xc3b20000}, {0xc3b22000}, {0xc3b24000}, {0xc3b26000}, 
+    {0xc3b28000}, {0xc3b2a000}, {0xc3b2c000}, {0xc3b2e000}, 
+    {0xc3b30000}, {0xc3b32000}, {0xc3b34000}, {0xc3b36000}, 
+    {0xc3b38000}, {0xc3b3a000}, {0xc3b3c000}, {0xc3b3e000}, 
+    {0xc3b40000}, {0xc3b42000}, {0xc3b44000}, {0xc3b46000}, 
+    {0xc3b48000}, {0xc3b4a000}, {0xc3b4c000}, {0xc3b4e000}, 
+    {0xc3b50000}, {0xc3b52000}, {0xc3b54000}, {0xc3b56000}, 
+    {0xc3b58000}, {0xc3b5a000}, {0xc3b5c000}, {0xc3b5e000}, 
+    {0xc3b60000}, {0xc3b62000}, {0xc3b64000}, {0xc3b66000}, 
+    {0xc3b68000}, {0xc3b6a000}, {0xc3b6c000}, {0xc3b6e000}, 
+    {0xc3b70000}, {0xc3b72000}, {0xc3b74000}, {0xc3b76000}, 
+    {0xc3b78000}, {0xc3b7a000}, {0xc3b7c000}, {0xc3b7e000}, 
+    {0xc3b80000}, {0xc3b82000}, {0xc3b84000}, {0xc3b86000}, 
+    {0xc3b88000}, {0xc3b8a000}, {0xc3b8c000}, {0xc3b8e000}, 
+    {0xc3b90000}, {0xc3b92000}, {0xc3b94000}, {0xc3b96000}, 
+    {0xc3b98000}, {0xc3b9a000}, {0xc3b9c000}, {0xc3b9e000}, 
+    {0xc3ba0000}, {0xc3ba2000}, {0xc3ba4000}, {0xc3ba6000}, 
+    {0xc3ba8000}, {0xc3baa000}, {0xc3bac000}, {0xc3bae000}, 
+    {0xc3bb0000}, {0xc3bb2000}, {0xc3bb4000}, {0xc3bb6000}, 
+    {0xc3bb8000}, {0xc3bba000}, {0xc3bbc000}, {0xc3bbe000}, 
+    {0xc3bc0000}, {0xc3bc2000}, {0xc3bc4000}, {0xc3bc6000}, 
+    {0xc3bc8000}, {0xc3bca000}, {0xc3bcc000}, {0xc3bce000}, 
+    {0xc3bd0000}, {0xc3bd2000}, {0xc3bd4000}, {0xc3bd6000}, 
+    {0xc3bd8000}, {0xc3bda000}, {0xc3bdc000}, {0xc3bde000}, 
+    {0xc3be0000}, {0xc3be2000}, {0xc3be4000}, {0xc3be6000}, 
+    {0xc3be8000}, {0xc3bea000}, {0xc3bec000}, {0xc3bee000}, 
+    {0xc3bf0000}, {0xc3bf2000}, {0xc3bf4000}, {0xc3bf6000}, 
+    {0xc3bf8000}, {0xc3bfa000}, {0xc3bfc000}, {0xc3bfe000}, 
+    {0xc3c00000}, {0xc3c02000}, {0xc3c04000}, {0xc3c06000}, 
+    {0xc3c08000}, {0xc3c0a000}, {0xc3c0c000}, {0xc3c0e000}, 
+    {0xc3c10000}, {0xc3c12000}, {0xc3c14000}, {0xc3c16000}, 
+    {0xc3c18000}, {0xc3c1a000}, {0xc3c1c000}, {0xc3c1e000}, 
+    {0xc3c20000}, {0xc3c22000}, {0xc3c24000}, {0xc3c26000}, 
+    {0xc3c28000}, {0xc3c2a000}, {0xc3c2c000}, {0xc3c2e000}, 
+    {0xc3c30000}, {0xc3c32000}, {0xc3c34000}, {0xc3c36000}, 
+    {0xc3c38000}, {0xc3c3a000}, {0xc3c3c000}, {0xc3c3e000}, 
+    {0xc3c40000}, {0xc3c42000}, {0xc3c44000}, {0xc3c46000}, 
+    {0xc3c48000}, {0xc3c4a000}, {0xc3c4c000}, {0xc3c4e000}, 
+    {0xc3c50000}, {0xc3c52000}, {0xc3c54000}, {0xc3c56000}, 
+    {0xc3c58000}, {0xc3c5a000}, {0xc3c5c000}, {0xc3c5e000}, 
+    {0xc3c60000}, {0xc3c62000}, {0xc3c64000}, {0xc3c66000}, 
+    {0xc3c68000}, {0xc3c6a000}, {0xc3c6c000}, {0xc3c6e000}, 
+    {0xc3c70000}, {0xc3c72000}, {0xc3c74000}, {0xc3c76000}, 
+    {0xc3c78000}, {0xc3c7a000}, {0xc3c7c000}, {0xc3c7e000}, 
+    {0xc3c80000}, {0xc3c82000}, {0xc3c84000}, {0xc3c86000}, 
+    {0xc3c88000}, {0xc3c8a000}, {0xc3c8c000}, {0xc3c8e000}, 
+    {0xc3c90000}, {0xc3c92000}, {0xc3c94000}, {0xc3c96000}, 
+    {0xc3c98000}, {0xc3c9a000}, {0xc3c9c000}, {0xc3c9e000}, 
+    {0xc3ca0000}, {0xc3ca2000}, {0xc3ca4000}, {0xc3ca6000}, 
+    {0xc3ca8000}, {0xc3caa000}, {0xc3cac000}, {0xc3cae000}, 
+    {0xc3cb0000}, {0xc3cb2000}, {0xc3cb4000}, {0xc3cb6000}, 
+    {0xc3cb8000}, {0xc3cba000}, {0xc3cbc000}, {0xc3cbe000}, 
+    {0xc3cc0000}, {0xc3cc2000}, {0xc3cc4000}, {0xc3cc6000}, 
+    {0xc3cc8000}, {0xc3cca000}, {0xc3ccc000}, {0xc3cce000}, 
+    {0xc3cd0000}, {0xc3cd2000}, {0xc3cd4000}, {0xc3cd6000}, 
+    {0xc3cd8000}, {0xc3cda000}, {0xc3cdc000}, {0xc3cde000}, 
+    {0xc3ce0000}, {0xc3ce2000}, {0xc3ce4000}, {0xc3ce6000}, 
+    {0xc3ce8000}, {0xc3cea000}, {0xc3cec000}, {0xc3cee000}, 
+    {0xc3cf0000}, {0xc3cf2000}, {0xc3cf4000}, {0xc3cf6000}, 
+    {0xc3cf8000}, {0xc3cfa000}, {0xc3cfc000}, {0xc3cfe000}, 
+    {0xc3d00000}, {0xc3d02000}, {0xc3d04000}, {0xc3d06000}, 
+    {0xc3d08000}, {0xc3d0a000}, {0xc3d0c000}, {0xc3d0e000}, 
+    {0xc3d10000}, {0xc3d12000}, {0xc3d14000}, {0xc3d16000}, 
+    {0xc3d18000}, {0xc3d1a000}, {0xc3d1c000}, {0xc3d1e000}, 
+    {0xc3d20000}, {0xc3d22000}, {0xc3d24000}, {0xc3d26000}, 
+    {0xc3d28000}, {0xc3d2a000}, {0xc3d2c000}, {0xc3d2e000}, 
+    {0xc3d30000}, {0xc3d32000}, {0xc3d34000}, {0xc3d36000}, 
+    {0xc3d38000}, {0xc3d3a000}, {0xc3d3c000}, {0xc3d3e000}, 
+    {0xc3d40000}, {0xc3d42000}, {0xc3d44000}, {0xc3d46000}, 
+    {0xc3d48000}, {0xc3d4a000}, {0xc3d4c000}, {0xc3d4e000}, 
+    {0xc3d50000}, {0xc3d52000}, {0xc3d54000}, {0xc3d56000}, 
+    {0xc3d58000}, {0xc3d5a000}, {0xc3d5c000}, {0xc3d5e000}, 
+    {0xc3d60000}, {0xc3d62000}, {0xc3d64000}, {0xc3d66000}, 
+    {0xc3d68000}, {0xc3d6a000}, {0xc3d6c000}, {0xc3d6e000}, 
+    {0xc3d70000}, {0xc3d72000}, {0xc3d74000}, {0xc3d76000}, 
+    {0xc3d78000}, {0xc3d7a000}, {0xc3d7c000}, {0xc3d7e000}, 
+    {0xc3d80000}, {0xc3d82000}, {0xc3d84000}, {0xc3d86000}, 
+    {0xc3d88000}, {0xc3d8a000}, {0xc3d8c000}, {0xc3d8e000}, 
+    {0xc3d90000}, {0xc3d92000}, {0xc3d94000}, {0xc3d96000}, 
+    {0xc3d98000}, {0xc3d9a000}, {0xc3d9c000}, {0xc3d9e000}, 
+    {0xc3da0000}, {0xc3da2000}, {0xc3da4000}, {0xc3da6000}, 
+    {0xc3da8000}, {0xc3daa000}, {0xc3dac000}, {0xc3dae000}, 
+    {0xc3db0000}, {0xc3db2000}, {0xc3db4000}, {0xc3db6000}, 
+    {0xc3db8000}, {0xc3dba000}, {0xc3dbc000}, {0xc3dbe000}, 
+    {0xc3dc0000}, {0xc3dc2000}, {0xc3dc4000}, {0xc3dc6000}, 
+    {0xc3dc8000}, {0xc3dca000}, {0xc3dcc000}, {0xc3dce000}, 
+    {0xc3dd0000}, {0xc3dd2000}, {0xc3dd4000}, {0xc3dd6000}, 
+    {0xc3dd8000}, {0xc3dda000}, {0xc3ddc000}, {0xc3dde000}, 
+    {0xc3de0000}, {0xc3de2000}, {0xc3de4000}, {0xc3de6000}, 
+    {0xc3de8000}, {0xc3dea000}, {0xc3dec000}, {0xc3dee000}, 
+    {0xc3df0000}, {0xc3df2000}, {0xc3df4000}, {0xc3df6000}, 
+    {0xc3df8000}, {0xc3dfa000}, {0xc3dfc000}, {0xc3dfe000}, 
+    {0xc3e00000}, {0xc3e02000}, {0xc3e04000}, {0xc3e06000}, 
+    {0xc3e08000}, {0xc3e0a000}, {0xc3e0c000}, {0xc3e0e000}, 
+    {0xc3e10000}, {0xc3e12000}, {0xc3e14000}, {0xc3e16000}, 
+    {0xc3e18000}, {0xc3e1a000}, {0xc3e1c000}, {0xc3e1e000}, 
+    {0xc3e20000}, {0xc3e22000}, {0xc3e24000}, {0xc3e26000}, 
+    {0xc3e28000}, {0xc3e2a000}, {0xc3e2c000}, {0xc3e2e000}, 
+    {0xc3e30000}, {0xc3e32000}, {0xc3e34000}, {0xc3e36000}, 
+    {0xc3e38000}, {0xc3e3a000}, {0xc3e3c000}, {0xc3e3e000}, 
+    {0xc3e40000}, {0xc3e42000}, {0xc3e44000}, {0xc3e46000}, 
+    {0xc3e48000}, {0xc3e4a000}, {0xc3e4c000}, {0xc3e4e000}, 
+    {0xc3e50000}, {0xc3e52000}, {0xc3e54000}, {0xc3e56000}, 
+    {0xc3e58000}, {0xc3e5a000}, {0xc3e5c000}, {0xc3e5e000}, 
+    {0xc3e60000}, {0xc3e62000}, {0xc3e64000}, {0xc3e66000}, 
+    {0xc3e68000}, {0xc3e6a000}, {0xc3e6c000}, {0xc3e6e000}, 
+    {0xc3e70000}, {0xc3e72000}, {0xc3e74000}, {0xc3e76000}, 
+    {0xc3e78000}, {0xc3e7a000}, {0xc3e7c000}, {0xc3e7e000}, 
+    {0xc3e80000}, {0xc3e82000}, {0xc3e84000}, {0xc3e86000}, 
+    {0xc3e88000}, {0xc3e8a000}, {0xc3e8c000}, {0xc3e8e000}, 
+    {0xc3e90000}, {0xc3e92000}, {0xc3e94000}, {0xc3e96000}, 
+    {0xc3e98000}, {0xc3e9a000}, {0xc3e9c000}, {0xc3e9e000}, 
+    {0xc3ea0000}, {0xc3ea2000}, {0xc3ea4000}, {0xc3ea6000}, 
+    {0xc3ea8000}, {0xc3eaa000}, {0xc3eac000}, {0xc3eae000}, 
+    {0xc3eb0000}, {0xc3eb2000}, {0xc3eb4000}, {0xc3eb6000}, 
+    {0xc3eb8000}, {0xc3eba000}, {0xc3ebc000}, {0xc3ebe000}, 
+    {0xc3ec0000}, {0xc3ec2000}, {0xc3ec4000}, {0xc3ec6000}, 
+    {0xc3ec8000}, {0xc3eca000}, {0xc3ecc000}, {0xc3ece000}, 
+    {0xc3ed0000}, {0xc3ed2000}, {0xc3ed4000}, {0xc3ed6000}, 
+    {0xc3ed8000}, {0xc3eda000}, {0xc3edc000}, {0xc3ede000}, 
+    {0xc3ee0000}, {0xc3ee2000}, {0xc3ee4000}, {0xc3ee6000}, 
+    {0xc3ee8000}, {0xc3eea000}, {0xc3eec000}, {0xc3eee000}, 
+    {0xc3ef0000}, {0xc3ef2000}, {0xc3ef4000}, {0xc3ef6000}, 
+    {0xc3ef8000}, {0xc3efa000}, {0xc3efc000}, {0xc3efe000}, 
+    {0xc3f00000}, {0xc3f02000}, {0xc3f04000}, {0xc3f06000}, 
+    {0xc3f08000}, {0xc3f0a000}, {0xc3f0c000}, {0xc3f0e000}, 
+    {0xc3f10000}, {0xc3f12000}, {0xc3f14000}, {0xc3f16000}, 
+    {0xc3f18000}, {0xc3f1a000}, {0xc3f1c000}, {0xc3f1e000}, 
+    {0xc3f20000}, {0xc3f22000}, {0xc3f24000}, {0xc3f26000}, 
+    {0xc3f28000}, {0xc3f2a000}, {0xc3f2c000}, {0xc3f2e000}, 
+    {0xc3f30000}, {0xc3f32000}, {0xc3f34000}, {0xc3f36000}, 
+    {0xc3f38000}, {0xc3f3a000}, {0xc3f3c000}, {0xc3f3e000}, 
+    {0xc3f40000}, {0xc3f42000}, {0xc3f44000}, {0xc3f46000}, 
+    {0xc3f48000}, {0xc3f4a000}, {0xc3f4c000}, {0xc3f4e000}, 
+    {0xc3f50000}, {0xc3f52000}, {0xc3f54000}, {0xc3f56000}, 
+    {0xc3f58000}, {0xc3f5a000}, {0xc3f5c000}, {0xc3f5e000}, 
+    {0xc3f60000}, {0xc3f62000}, {0xc3f64000}, {0xc3f66000}, 
+    {0xc3f68000}, {0xc3f6a000}, {0xc3f6c000}, {0xc3f6e000}, 
+    {0xc3f70000}, {0xc3f72000}, {0xc3f74000}, {0xc3f76000}, 
+    {0xc3f78000}, {0xc3f7a000}, {0xc3f7c000}, {0xc3f7e000}, 
+    {0xc3f80000}, {0xc3f82000}, {0xc3f84000}, {0xc3f86000}, 
+    {0xc3f88000}, {0xc3f8a000}, {0xc3f8c000}, {0xc3f8e000}, 
+    {0xc3f90000}, {0xc3f92000}, {0xc3f94000}, {0xc3f96000}, 
+    {0xc3f98000}, {0xc3f9a000}, {0xc3f9c000}, {0xc3f9e000}, 
+    {0xc3fa0000}, {0xc3fa2000}, {0xc3fa4000}, {0xc3fa6000}, 
+    {0xc3fa8000}, {0xc3faa000}, {0xc3fac000}, {0xc3fae000}, 
+    {0xc3fb0000}, {0xc3fb2000}, {0xc3fb4000}, {0xc3fb6000}, 
+    {0xc3fb8000}, {0xc3fba000}, {0xc3fbc000}, {0xc3fbe000}, 
+    {0xc3fc0000}, {0xc3fc2000}, {0xc3fc4000}, {0xc3fc6000}, 
+    {0xc3fc8000}, {0xc3fca000}, {0xc3fcc000}, {0xc3fce000}, 
+    {0xc3fd0000}, {0xc3fd2000}, {0xc3fd4000}, {0xc3fd6000}, 
+    {0xc3fd8000}, {0xc3fda000}, {0xc3fdc000}, {0xc3fde000}, 
+    {0xc3fe0000}, {0xc3fe2000}, {0xc3fe4000}, {0xc3fe6000}, 
+    {0xc3fe8000}, {0xc3fea000}, {0xc3fec000}, {0xc3fee000}, 
+    {0xc3ff0000}, {0xc3ff2000}, {0xc3ff4000}, {0xc3ff6000}, 
+    {0xc3ff8000}, {0xc3ffa000}, {0xc3ffc000}, {0xc3ffe000}, 
+    {0xc4000000}, {0xc4002000}, {0xc4004000}, {0xc4006000}, 
+    {0xc4008000}, {0xc400a000}, {0xc400c000}, {0xc400e000}, 
+    {0xc4010000}, {0xc4012000}, {0xc4014000}, {0xc4016000}, 
+    {0xc4018000}, {0xc401a000}, {0xc401c000}, {0xc401e000}, 
+    {0xc4020000}, {0xc4022000}, {0xc4024000}, {0xc4026000}, 
+    {0xc4028000}, {0xc402a000}, {0xc402c000}, {0xc402e000}, 
+    {0xc4030000}, {0xc4032000}, {0xc4034000}, {0xc4036000}, 
+    {0xc4038000}, {0xc403a000}, {0xc403c000}, {0xc403e000}, 
+    {0xc4040000}, {0xc4042000}, {0xc4044000}, {0xc4046000}, 
+    {0xc4048000}, {0xc404a000}, {0xc404c000}, {0xc404e000}, 
+    {0xc4050000}, {0xc4052000}, {0xc4054000}, {0xc4056000}, 
+    {0xc4058000}, {0xc405a000}, {0xc405c000}, {0xc405e000}, 
+    {0xc4060000}, {0xc4062000}, {0xc4064000}, {0xc4066000}, 
+    {0xc4068000}, {0xc406a000}, {0xc406c000}, {0xc406e000}, 
+    {0xc4070000}, {0xc4072000}, {0xc4074000}, {0xc4076000}, 
+    {0xc4078000}, {0xc407a000}, {0xc407c000}, {0xc407e000}, 
+    {0xc4080000}, {0xc4082000}, {0xc4084000}, {0xc4086000}, 
+    {0xc4088000}, {0xc408a000}, {0xc408c000}, {0xc408e000}, 
+    {0xc4090000}, {0xc4092000}, {0xc4094000}, {0xc4096000}, 
+    {0xc4098000}, {0xc409a000}, {0xc409c000}, {0xc409e000}, 
+    {0xc40a0000}, {0xc40a2000}, {0xc40a4000}, {0xc40a6000}, 
+    {0xc40a8000}, {0xc40aa000}, {0xc40ac000}, {0xc40ae000}, 
+    {0xc40b0000}, {0xc40b2000}, {0xc40b4000}, {0xc40b6000}, 
+    {0xc40b8000}, {0xc40ba000}, {0xc40bc000}, {0xc40be000}, 
+    {0xc40c0000}, {0xc40c2000}, {0xc40c4000}, {0xc40c6000}, 
+    {0xc40c8000}, {0xc40ca000}, {0xc40cc000}, {0xc40ce000}, 
+    {0xc40d0000}, {0xc40d2000}, {0xc40d4000}, {0xc40d6000}, 
+    {0xc40d8000}, {0xc40da000}, {0xc40dc000}, {0xc40de000}, 
+    {0xc40e0000}, {0xc40e2000}, {0xc40e4000}, {0xc40e6000}, 
+    {0xc40e8000}, {0xc40ea000}, {0xc40ec000}, {0xc40ee000}, 
+    {0xc40f0000}, {0xc40f2000}, {0xc40f4000}, {0xc40f6000}, 
+    {0xc40f8000}, {0xc40fa000}, {0xc40fc000}, {0xc40fe000}, 
+    {0xc4100000}, {0xc4102000}, {0xc4104000}, {0xc4106000}, 
+    {0xc4108000}, {0xc410a000}, {0xc410c000}, {0xc410e000}, 
+    {0xc4110000}, {0xc4112000}, {0xc4114000}, {0xc4116000}, 
+    {0xc4118000}, {0xc411a000}, {0xc411c000}, {0xc411e000}, 
+    {0xc4120000}, {0xc4122000}, {0xc4124000}, {0xc4126000}, 
+    {0xc4128000}, {0xc412a000}, {0xc412c000}, {0xc412e000}, 
+    {0xc4130000}, {0xc4132000}, {0xc4134000}, {0xc4136000}, 
+    {0xc4138000}, {0xc413a000}, {0xc413c000}, {0xc413e000}, 
+    {0xc4140000}, {0xc4142000}, {0xc4144000}, {0xc4146000}, 
+    {0xc4148000}, {0xc414a000}, {0xc414c000}, {0xc414e000}, 
+    {0xc4150000}, {0xc4152000}, {0xc4154000}, {0xc4156000}, 
+    {0xc4158000}, {0xc415a000}, {0xc415c000}, {0xc415e000}, 
+    {0xc4160000}, {0xc4162000}, {0xc4164000}, {0xc4166000}, 
+    {0xc4168000}, {0xc416a000}, {0xc416c000}, {0xc416e000}, 
+    {0xc4170000}, {0xc4172000}, {0xc4174000}, {0xc4176000}, 
+    {0xc4178000}, {0xc417a000}, {0xc417c000}, {0xc417e000}, 
+    {0xc4180000}, {0xc4182000}, {0xc4184000}, {0xc4186000}, 
+    {0xc4188000}, {0xc418a000}, {0xc418c000}, {0xc418e000}, 
+    {0xc4190000}, {0xc4192000}, {0xc4194000}, {0xc4196000}, 
+    {0xc4198000}, {0xc419a000}, {0xc419c000}, {0xc419e000}, 
+    {0xc41a0000}, {0xc41a2000}, {0xc41a4000}, {0xc41a6000}, 
+    {0xc41a8000}, {0xc41aa000}, {0xc41ac000}, {0xc41ae000}, 
+    {0xc41b0000}, {0xc41b2000}, {0xc41b4000}, {0xc41b6000}, 
+    {0xc41b8000}, {0xc41ba000}, {0xc41bc000}, {0xc41be000}, 
+    {0xc41c0000}, {0xc41c2000}, {0xc41c4000}, {0xc41c6000}, 
+    {0xc41c8000}, {0xc41ca000}, {0xc41cc000}, {0xc41ce000}, 
+    {0xc41d0000}, {0xc41d2000}, {0xc41d4000}, {0xc41d6000}, 
+    {0xc41d8000}, {0xc41da000}, {0xc41dc000}, {0xc41de000}, 
+    {0xc41e0000}, {0xc41e2000}, {0xc41e4000}, {0xc41e6000}, 
+    {0xc41e8000}, {0xc41ea000}, {0xc41ec000}, {0xc41ee000}, 
+    {0xc41f0000}, {0xc41f2000}, {0xc41f4000}, {0xc41f6000}, 
+    {0xc41f8000}, {0xc41fa000}, {0xc41fc000}, {0xc41fe000}, 
+    {0xc4200000}, {0xc4202000}, {0xc4204000}, {0xc4206000}, 
+    {0xc4208000}, {0xc420a000}, {0xc420c000}, {0xc420e000}, 
+    {0xc4210000}, {0xc4212000}, {0xc4214000}, {0xc4216000}, 
+    {0xc4218000}, {0xc421a000}, {0xc421c000}, {0xc421e000}, 
+    {0xc4220000}, {0xc4222000}, {0xc4224000}, {0xc4226000}, 
+    {0xc4228000}, {0xc422a000}, {0xc422c000}, {0xc422e000}, 
+    {0xc4230000}, {0xc4232000}, {0xc4234000}, {0xc4236000}, 
+    {0xc4238000}, {0xc423a000}, {0xc423c000}, {0xc423e000}, 
+    {0xc4240000}, {0xc4242000}, {0xc4244000}, {0xc4246000}, 
+    {0xc4248000}, {0xc424a000}, {0xc424c000}, {0xc424e000}, 
+    {0xc4250000}, {0xc4252000}, {0xc4254000}, {0xc4256000}, 
+    {0xc4258000}, {0xc425a000}, {0xc425c000}, {0xc425e000}, 
+    {0xc4260000}, {0xc4262000}, {0xc4264000}, {0xc4266000}, 
+    {0xc4268000}, {0xc426a000}, {0xc426c000}, {0xc426e000}, 
+    {0xc4270000}, {0xc4272000}, {0xc4274000}, {0xc4276000}, 
+    {0xc4278000}, {0xc427a000}, {0xc427c000}, {0xc427e000}, 
+    {0xc4280000}, {0xc4282000}, {0xc4284000}, {0xc4286000}, 
+    {0xc4288000}, {0xc428a000}, {0xc428c000}, {0xc428e000}, 
+    {0xc4290000}, {0xc4292000}, {0xc4294000}, {0xc4296000}, 
+    {0xc4298000}, {0xc429a000}, {0xc429c000}, {0xc429e000}, 
+    {0xc42a0000}, {0xc42a2000}, {0xc42a4000}, {0xc42a6000}, 
+    {0xc42a8000}, {0xc42aa000}, {0xc42ac000}, {0xc42ae000}, 
+    {0xc42b0000}, {0xc42b2000}, {0xc42b4000}, {0xc42b6000}, 
+    {0xc42b8000}, {0xc42ba000}, {0xc42bc000}, {0xc42be000}, 
+    {0xc42c0000}, {0xc42c2000}, {0xc42c4000}, {0xc42c6000}, 
+    {0xc42c8000}, {0xc42ca000}, {0xc42cc000}, {0xc42ce000}, 
+    {0xc42d0000}, {0xc42d2000}, {0xc42d4000}, {0xc42d6000}, 
+    {0xc42d8000}, {0xc42da000}, {0xc42dc000}, {0xc42de000}, 
+    {0xc42e0000}, {0xc42e2000}, {0xc42e4000}, {0xc42e6000}, 
+    {0xc42e8000}, {0xc42ea000}, {0xc42ec000}, {0xc42ee000}, 
+    {0xc42f0000}, {0xc42f2000}, {0xc42f4000}, {0xc42f6000}, 
+    {0xc42f8000}, {0xc42fa000}, {0xc42fc000}, {0xc42fe000}, 
+    {0xc4300000}, {0xc4302000}, {0xc4304000}, {0xc4306000}, 
+    {0xc4308000}, {0xc430a000}, {0xc430c000}, {0xc430e000}, 
+    {0xc4310000}, {0xc4312000}, {0xc4314000}, {0xc4316000}, 
+    {0xc4318000}, {0xc431a000}, {0xc431c000}, {0xc431e000}, 
+    {0xc4320000}, {0xc4322000}, {0xc4324000}, {0xc4326000}, 
+    {0xc4328000}, {0xc432a000}, {0xc432c000}, {0xc432e000}, 
+    {0xc4330000}, {0xc4332000}, {0xc4334000}, {0xc4336000}, 
+    {0xc4338000}, {0xc433a000}, {0xc433c000}, {0xc433e000}, 
+    {0xc4340000}, {0xc4342000}, {0xc4344000}, {0xc4346000}, 
+    {0xc4348000}, {0xc434a000}, {0xc434c000}, {0xc434e000}, 
+    {0xc4350000}, {0xc4352000}, {0xc4354000}, {0xc4356000}, 
+    {0xc4358000}, {0xc435a000}, {0xc435c000}, {0xc435e000}, 
+    {0xc4360000}, {0xc4362000}, {0xc4364000}, {0xc4366000}, 
+    {0xc4368000}, {0xc436a000}, {0xc436c000}, {0xc436e000}, 
+    {0xc4370000}, {0xc4372000}, {0xc4374000}, {0xc4376000}, 
+    {0xc4378000}, {0xc437a000}, {0xc437c000}, {0xc437e000}, 
+    {0xc4380000}, {0xc4382000}, {0xc4384000}, {0xc4386000}, 
+    {0xc4388000}, {0xc438a000}, {0xc438c000}, {0xc438e000}, 
+    {0xc4390000}, {0xc4392000}, {0xc4394000}, {0xc4396000}, 
+    {0xc4398000}, {0xc439a000}, {0xc439c000}, {0xc439e000}, 
+    {0xc43a0000}, {0xc43a2000}, {0xc43a4000}, {0xc43a6000}, 
+    {0xc43a8000}, {0xc43aa000}, {0xc43ac000}, {0xc43ae000}, 
+    {0xc43b0000}, {0xc43b2000}, {0xc43b4000}, {0xc43b6000}, 
+    {0xc43b8000}, {0xc43ba000}, {0xc43bc000}, {0xc43be000}, 
+    {0xc43c0000}, {0xc43c2000}, {0xc43c4000}, {0xc43c6000}, 
+    {0xc43c8000}, {0xc43ca000}, {0xc43cc000}, {0xc43ce000}, 
+    {0xc43d0000}, {0xc43d2000}, {0xc43d4000}, {0xc43d6000}, 
+    {0xc43d8000}, {0xc43da000}, {0xc43dc000}, {0xc43de000}, 
+    {0xc43e0000}, {0xc43e2000}, {0xc43e4000}, {0xc43e6000}, 
+    {0xc43e8000}, {0xc43ea000}, {0xc43ec000}, {0xc43ee000}, 
+    {0xc43f0000}, {0xc43f2000}, {0xc43f4000}, {0xc43f6000}, 
+    {0xc43f8000}, {0xc43fa000}, {0xc43fc000}, {0xc43fe000}, 
+    {0xc4400000}, {0xc4402000}, {0xc4404000}, {0xc4406000}, 
+    {0xc4408000}, {0xc440a000}, {0xc440c000}, {0xc440e000}, 
+    {0xc4410000}, {0xc4412000}, {0xc4414000}, {0xc4416000}, 
+    {0xc4418000}, {0xc441a000}, {0xc441c000}, {0xc441e000}, 
+    {0xc4420000}, {0xc4422000}, {0xc4424000}, {0xc4426000}, 
+    {0xc4428000}, {0xc442a000}, {0xc442c000}, {0xc442e000}, 
+    {0xc4430000}, {0xc4432000}, {0xc4434000}, {0xc4436000}, 
+    {0xc4438000}, {0xc443a000}, {0xc443c000}, {0xc443e000}, 
+    {0xc4440000}, {0xc4442000}, {0xc4444000}, {0xc4446000}, 
+    {0xc4448000}, {0xc444a000}, {0xc444c000}, {0xc444e000}, 
+    {0xc4450000}, {0xc4452000}, {0xc4454000}, {0xc4456000}, 
+    {0xc4458000}, {0xc445a000}, {0xc445c000}, {0xc445e000}, 
+    {0xc4460000}, {0xc4462000}, {0xc4464000}, {0xc4466000}, 
+    {0xc4468000}, {0xc446a000}, {0xc446c000}, {0xc446e000}, 
+    {0xc4470000}, {0xc4472000}, {0xc4474000}, {0xc4476000}, 
+    {0xc4478000}, {0xc447a000}, {0xc447c000}, {0xc447e000}, 
+    {0xc4480000}, {0xc4482000}, {0xc4484000}, {0xc4486000}, 
+    {0xc4488000}, {0xc448a000}, {0xc448c000}, {0xc448e000}, 
+    {0xc4490000}, {0xc4492000}, {0xc4494000}, {0xc4496000}, 
+    {0xc4498000}, {0xc449a000}, {0xc449c000}, {0xc449e000}, 
+    {0xc44a0000}, {0xc44a2000}, {0xc44a4000}, {0xc44a6000}, 
+    {0xc44a8000}, {0xc44aa000}, {0xc44ac000}, {0xc44ae000}, 
+    {0xc44b0000}, {0xc44b2000}, {0xc44b4000}, {0xc44b6000}, 
+    {0xc44b8000}, {0xc44ba000}, {0xc44bc000}, {0xc44be000}, 
+    {0xc44c0000}, {0xc44c2000}, {0xc44c4000}, {0xc44c6000}, 
+    {0xc44c8000}, {0xc44ca000}, {0xc44cc000}, {0xc44ce000}, 
+    {0xc44d0000}, {0xc44d2000}, {0xc44d4000}, {0xc44d6000}, 
+    {0xc44d8000}, {0xc44da000}, {0xc44dc000}, {0xc44de000}, 
+    {0xc44e0000}, {0xc44e2000}, {0xc44e4000}, {0xc44e6000}, 
+    {0xc44e8000}, {0xc44ea000}, {0xc44ec000}, {0xc44ee000}, 
+    {0xc44f0000}, {0xc44f2000}, {0xc44f4000}, {0xc44f6000}, 
+    {0xc44f8000}, {0xc44fa000}, {0xc44fc000}, {0xc44fe000}, 
+    {0xc4500000}, {0xc4502000}, {0xc4504000}, {0xc4506000}, 
+    {0xc4508000}, {0xc450a000}, {0xc450c000}, {0xc450e000}, 
+    {0xc4510000}, {0xc4512000}, {0xc4514000}, {0xc4516000}, 
+    {0xc4518000}, {0xc451a000}, {0xc451c000}, {0xc451e000}, 
+    {0xc4520000}, {0xc4522000}, {0xc4524000}, {0xc4526000}, 
+    {0xc4528000}, {0xc452a000}, {0xc452c000}, {0xc452e000}, 
+    {0xc4530000}, {0xc4532000}, {0xc4534000}, {0xc4536000}, 
+    {0xc4538000}, {0xc453a000}, {0xc453c000}, {0xc453e000}, 
+    {0xc4540000}, {0xc4542000}, {0xc4544000}, {0xc4546000}, 
+    {0xc4548000}, {0xc454a000}, {0xc454c000}, {0xc454e000}, 
+    {0xc4550000}, {0xc4552000}, {0xc4554000}, {0xc4556000}, 
+    {0xc4558000}, {0xc455a000}, {0xc455c000}, {0xc455e000}, 
+    {0xc4560000}, {0xc4562000}, {0xc4564000}, {0xc4566000}, 
+    {0xc4568000}, {0xc456a000}, {0xc456c000}, {0xc456e000}, 
+    {0xc4570000}, {0xc4572000}, {0xc4574000}, {0xc4576000}, 
+    {0xc4578000}, {0xc457a000}, {0xc457c000}, {0xc457e000}, 
+    {0xc4580000}, {0xc4582000}, {0xc4584000}, {0xc4586000}, 
+    {0xc4588000}, {0xc458a000}, {0xc458c000}, {0xc458e000}, 
+    {0xc4590000}, {0xc4592000}, {0xc4594000}, {0xc4596000}, 
+    {0xc4598000}, {0xc459a000}, {0xc459c000}, {0xc459e000}, 
+    {0xc45a0000}, {0xc45a2000}, {0xc45a4000}, {0xc45a6000}, 
+    {0xc45a8000}, {0xc45aa000}, {0xc45ac000}, {0xc45ae000}, 
+    {0xc45b0000}, {0xc45b2000}, {0xc45b4000}, {0xc45b6000}, 
+    {0xc45b8000}, {0xc45ba000}, {0xc45bc000}, {0xc45be000}, 
+    {0xc45c0000}, {0xc45c2000}, {0xc45c4000}, {0xc45c6000}, 
+    {0xc45c8000}, {0xc45ca000}, {0xc45cc000}, {0xc45ce000}, 
+    {0xc45d0000}, {0xc45d2000}, {0xc45d4000}, {0xc45d6000}, 
+    {0xc45d8000}, {0xc45da000}, {0xc45dc000}, {0xc45de000}, 
+    {0xc45e0000}, {0xc45e2000}, {0xc45e4000}, {0xc45e6000}, 
+    {0xc45e8000}, {0xc45ea000}, {0xc45ec000}, {0xc45ee000}, 
+    {0xc45f0000}, {0xc45f2000}, {0xc45f4000}, {0xc45f6000}, 
+    {0xc45f8000}, {0xc45fa000}, {0xc45fc000}, {0xc45fe000}, 
+    {0xc4600000}, {0xc4602000}, {0xc4604000}, {0xc4606000}, 
+    {0xc4608000}, {0xc460a000}, {0xc460c000}, {0xc460e000}, 
+    {0xc4610000}, {0xc4612000}, {0xc4614000}, {0xc4616000}, 
+    {0xc4618000}, {0xc461a000}, {0xc461c000}, {0xc461e000}, 
+    {0xc4620000}, {0xc4622000}, {0xc4624000}, {0xc4626000}, 
+    {0xc4628000}, {0xc462a000}, {0xc462c000}, {0xc462e000}, 
+    {0xc4630000}, {0xc4632000}, {0xc4634000}, {0xc4636000}, 
+    {0xc4638000}, {0xc463a000}, {0xc463c000}, {0xc463e000}, 
+    {0xc4640000}, {0xc4642000}, {0xc4644000}, {0xc4646000}, 
+    {0xc4648000}, {0xc464a000}, {0xc464c000}, {0xc464e000}, 
+    {0xc4650000}, {0xc4652000}, {0xc4654000}, {0xc4656000}, 
+    {0xc4658000}, {0xc465a000}, {0xc465c000}, {0xc465e000}, 
+    {0xc4660000}, {0xc4662000}, {0xc4664000}, {0xc4666000}, 
+    {0xc4668000}, {0xc466a000}, {0xc466c000}, {0xc466e000}, 
+    {0xc4670000}, {0xc4672000}, {0xc4674000}, {0xc4676000}, 
+    {0xc4678000}, {0xc467a000}, {0xc467c000}, {0xc467e000}, 
+    {0xc4680000}, {0xc4682000}, {0xc4684000}, {0xc4686000}, 
+    {0xc4688000}, {0xc468a000}, {0xc468c000}, {0xc468e000}, 
+    {0xc4690000}, {0xc4692000}, {0xc4694000}, {0xc4696000}, 
+    {0xc4698000}, {0xc469a000}, {0xc469c000}, {0xc469e000}, 
+    {0xc46a0000}, {0xc46a2000}, {0xc46a4000}, {0xc46a6000}, 
+    {0xc46a8000}, {0xc46aa000}, {0xc46ac000}, {0xc46ae000}, 
+    {0xc46b0000}, {0xc46b2000}, {0xc46b4000}, {0xc46b6000}, 
+    {0xc46b8000}, {0xc46ba000}, {0xc46bc000}, {0xc46be000}, 
+    {0xc46c0000}, {0xc46c2000}, {0xc46c4000}, {0xc46c6000}, 
+    {0xc46c8000}, {0xc46ca000}, {0xc46cc000}, {0xc46ce000}, 
+    {0xc46d0000}, {0xc46d2000}, {0xc46d4000}, {0xc46d6000}, 
+    {0xc46d8000}, {0xc46da000}, {0xc46dc000}, {0xc46de000}, 
+    {0xc46e0000}, {0xc46e2000}, {0xc46e4000}, {0xc46e6000}, 
+    {0xc46e8000}, {0xc46ea000}, {0xc46ec000}, {0xc46ee000}, 
+    {0xc46f0000}, {0xc46f2000}, {0xc46f4000}, {0xc46f6000}, 
+    {0xc46f8000}, {0xc46fa000}, {0xc46fc000}, {0xc46fe000}, 
+    {0xc4700000}, {0xc4702000}, {0xc4704000}, {0xc4706000}, 
+    {0xc4708000}, {0xc470a000}, {0xc470c000}, {0xc470e000}, 
+    {0xc4710000}, {0xc4712000}, {0xc4714000}, {0xc4716000}, 
+    {0xc4718000}, {0xc471a000}, {0xc471c000}, {0xc471e000}, 
+    {0xc4720000}, {0xc4722000}, {0xc4724000}, {0xc4726000}, 
+    {0xc4728000}, {0xc472a000}, {0xc472c000}, {0xc472e000}, 
+    {0xc4730000}, {0xc4732000}, {0xc4734000}, {0xc4736000}, 
+    {0xc4738000}, {0xc473a000}, {0xc473c000}, {0xc473e000}, 
+    {0xc4740000}, {0xc4742000}, {0xc4744000}, {0xc4746000}, 
+    {0xc4748000}, {0xc474a000}, {0xc474c000}, {0xc474e000}, 
+    {0xc4750000}, {0xc4752000}, {0xc4754000}, {0xc4756000}, 
+    {0xc4758000}, {0xc475a000}, {0xc475c000}, {0xc475e000}, 
+    {0xc4760000}, {0xc4762000}, {0xc4764000}, {0xc4766000}, 
+    {0xc4768000}, {0xc476a000}, {0xc476c000}, {0xc476e000}, 
+    {0xc4770000}, {0xc4772000}, {0xc4774000}, {0xc4776000}, 
+    {0xc4778000}, {0xc477a000}, {0xc477c000}, {0xc477e000}, 
+    {0xc4780000}, {0xc4782000}, {0xc4784000}, {0xc4786000}, 
+    {0xc4788000}, {0xc478a000}, {0xc478c000}, {0xc478e000}, 
+    {0xc4790000}, {0xc4792000}, {0xc4794000}, {0xc4796000}, 
+    {0xc4798000}, {0xc479a000}, {0xc479c000}, {0xc479e000}, 
+    {0xc47a0000}, {0xc47a2000}, {0xc47a4000}, {0xc47a6000}, 
+    {0xc47a8000}, {0xc47aa000}, {0xc47ac000}, {0xc47ae000}, 
+    {0xc47b0000}, {0xc47b2000}, {0xc47b4000}, {0xc47b6000}, 
+    {0xc47b8000}, {0xc47ba000}, {0xc47bc000}, {0xc47be000}, 
+    {0xc47c0000}, {0xc47c2000}, {0xc47c4000}, {0xc47c6000}, 
+    {0xc47c8000}, {0xc47ca000}, {0xc47cc000}, {0xc47ce000}, 
+    {0xc47d0000}, {0xc47d2000}, {0xc47d4000}, {0xc47d6000}, 
+    {0xc47d8000}, {0xc47da000}, {0xc47dc000}, {0xc47de000}, 
+    {0xc47e0000}, {0xc47e2000}, {0xc47e4000}, {0xc47e6000}, 
+    {0xc47e8000}, {0xc47ea000}, {0xc47ec000}, {0xc47ee000}, 
+    {0xc47f0000}, {0xc47f2000}, {0xc47f4000}, {0xc47f6000}, 
+    {0xc47f8000}, {0xc47fa000}, {0xc47fc000}, {0xc47fe000}, 
+    {0xc4800000}, {0xc4802000}, {0xc4804000}, {0xc4806000}, 
+    {0xc4808000}, {0xc480a000}, {0xc480c000}, {0xc480e000}, 
+    {0xc4810000}, {0xc4812000}, {0xc4814000}, {0xc4816000}, 
+    {0xc4818000}, {0xc481a000}, {0xc481c000}, {0xc481e000}, 
+    {0xc4820000}, {0xc4822000}, {0xc4824000}, {0xc4826000}, 
+    {0xc4828000}, {0xc482a000}, {0xc482c000}, {0xc482e000}, 
+    {0xc4830000}, {0xc4832000}, {0xc4834000}, {0xc4836000}, 
+    {0xc4838000}, {0xc483a000}, {0xc483c000}, {0xc483e000}, 
+    {0xc4840000}, {0xc4842000}, {0xc4844000}, {0xc4846000}, 
+    {0xc4848000}, {0xc484a000}, {0xc484c000}, {0xc484e000}, 
+    {0xc4850000}, {0xc4852000}, {0xc4854000}, {0xc4856000}, 
+    {0xc4858000}, {0xc485a000}, {0xc485c000}, {0xc485e000}, 
+    {0xc4860000}, {0xc4862000}, {0xc4864000}, {0xc4866000}, 
+    {0xc4868000}, {0xc486a000}, {0xc486c000}, {0xc486e000}, 
+    {0xc4870000}, {0xc4872000}, {0xc4874000}, {0xc4876000}, 
+    {0xc4878000}, {0xc487a000}, {0xc487c000}, {0xc487e000}, 
+    {0xc4880000}, {0xc4882000}, {0xc4884000}, {0xc4886000}, 
+    {0xc4888000}, {0xc488a000}, {0xc488c000}, {0xc488e000}, 
+    {0xc4890000}, {0xc4892000}, {0xc4894000}, {0xc4896000}, 
+    {0xc4898000}, {0xc489a000}, {0xc489c000}, {0xc489e000}, 
+    {0xc48a0000}, {0xc48a2000}, {0xc48a4000}, {0xc48a6000}, 
+    {0xc48a8000}, {0xc48aa000}, {0xc48ac000}, {0xc48ae000}, 
+    {0xc48b0000}, {0xc48b2000}, {0xc48b4000}, {0xc48b6000}, 
+    {0xc48b8000}, {0xc48ba000}, {0xc48bc000}, {0xc48be000}, 
+    {0xc48c0000}, {0xc48c2000}, {0xc48c4000}, {0xc48c6000}, 
+    {0xc48c8000}, {0xc48ca000}, {0xc48cc000}, {0xc48ce000}, 
+    {0xc48d0000}, {0xc48d2000}, {0xc48d4000}, {0xc48d6000}, 
+    {0xc48d8000}, {0xc48da000}, {0xc48dc000}, {0xc48de000}, 
+    {0xc48e0000}, {0xc48e2000}, {0xc48e4000}, {0xc48e6000}, 
+    {0xc48e8000}, {0xc48ea000}, {0xc48ec000}, {0xc48ee000}, 
+    {0xc48f0000}, {0xc48f2000}, {0xc48f4000}, {0xc48f6000}, 
+    {0xc48f8000}, {0xc48fa000}, {0xc48fc000}, {0xc48fe000}, 
+    {0xc4900000}, {0xc4902000}, {0xc4904000}, {0xc4906000}, 
+    {0xc4908000}, {0xc490a000}, {0xc490c000}, {0xc490e000}, 
+    {0xc4910000}, {0xc4912000}, {0xc4914000}, {0xc4916000}, 
+    {0xc4918000}, {0xc491a000}, {0xc491c000}, {0xc491e000}, 
+    {0xc4920000}, {0xc4922000}, {0xc4924000}, {0xc4926000}, 
+    {0xc4928000}, {0xc492a000}, {0xc492c000}, {0xc492e000}, 
+    {0xc4930000}, {0xc4932000}, {0xc4934000}, {0xc4936000}, 
+    {0xc4938000}, {0xc493a000}, {0xc493c000}, {0xc493e000}, 
+    {0xc4940000}, {0xc4942000}, {0xc4944000}, {0xc4946000}, 
+    {0xc4948000}, {0xc494a000}, {0xc494c000}, {0xc494e000}, 
+    {0xc4950000}, {0xc4952000}, {0xc4954000}, {0xc4956000}, 
+    {0xc4958000}, {0xc495a000}, {0xc495c000}, {0xc495e000}, 
+    {0xc4960000}, {0xc4962000}, {0xc4964000}, {0xc4966000}, 
+    {0xc4968000}, {0xc496a000}, {0xc496c000}, {0xc496e000}, 
+    {0xc4970000}, {0xc4972000}, {0xc4974000}, {0xc4976000}, 
+    {0xc4978000}, {0xc497a000}, {0xc497c000}, {0xc497e000}, 
+    {0xc4980000}, {0xc4982000}, {0xc4984000}, {0xc4986000}, 
+    {0xc4988000}, {0xc498a000}, {0xc498c000}, {0xc498e000}, 
+    {0xc4990000}, {0xc4992000}, {0xc4994000}, {0xc4996000}, 
+    {0xc4998000}, {0xc499a000}, {0xc499c000}, {0xc499e000}, 
+    {0xc49a0000}, {0xc49a2000}, {0xc49a4000}, {0xc49a6000}, 
+    {0xc49a8000}, {0xc49aa000}, {0xc49ac000}, {0xc49ae000}, 
+    {0xc49b0000}, {0xc49b2000}, {0xc49b4000}, {0xc49b6000}, 
+    {0xc49b8000}, {0xc49ba000}, {0xc49bc000}, {0xc49be000}, 
+    {0xc49c0000}, {0xc49c2000}, {0xc49c4000}, {0xc49c6000}, 
+    {0xc49c8000}, {0xc49ca000}, {0xc49cc000}, {0xc49ce000}, 
+    {0xc49d0000}, {0xc49d2000}, {0xc49d4000}, {0xc49d6000}, 
+    {0xc49d8000}, {0xc49da000}, {0xc49dc000}, {0xc49de000}, 
+    {0xc49e0000}, {0xc49e2000}, {0xc49e4000}, {0xc49e6000}, 
+    {0xc49e8000}, {0xc49ea000}, {0xc49ec000}, {0xc49ee000}, 
+    {0xc49f0000}, {0xc49f2000}, {0xc49f4000}, {0xc49f6000}, 
+    {0xc49f8000}, {0xc49fa000}, {0xc49fc000}, {0xc49fe000}, 
+    {0xc4a00000}, {0xc4a02000}, {0xc4a04000}, {0xc4a06000}, 
+    {0xc4a08000}, {0xc4a0a000}, {0xc4a0c000}, {0xc4a0e000}, 
+    {0xc4a10000}, {0xc4a12000}, {0xc4a14000}, {0xc4a16000}, 
+    {0xc4a18000}, {0xc4a1a000}, {0xc4a1c000}, {0xc4a1e000}, 
+    {0xc4a20000}, {0xc4a22000}, {0xc4a24000}, {0xc4a26000}, 
+    {0xc4a28000}, {0xc4a2a000}, {0xc4a2c000}, {0xc4a2e000}, 
+    {0xc4a30000}, {0xc4a32000}, {0xc4a34000}, {0xc4a36000}, 
+    {0xc4a38000}, {0xc4a3a000}, {0xc4a3c000}, {0xc4a3e000}, 
+    {0xc4a40000}, {0xc4a42000}, {0xc4a44000}, {0xc4a46000}, 
+    {0xc4a48000}, {0xc4a4a000}, {0xc4a4c000}, {0xc4a4e000}, 
+    {0xc4a50000}, {0xc4a52000}, {0xc4a54000}, {0xc4a56000}, 
+    {0xc4a58000}, {0xc4a5a000}, {0xc4a5c000}, {0xc4a5e000}, 
+    {0xc4a60000}, {0xc4a62000}, {0xc4a64000}, {0xc4a66000}, 
+    {0xc4a68000}, {0xc4a6a000}, {0xc4a6c000}, {0xc4a6e000}, 
+    {0xc4a70000}, {0xc4a72000}, {0xc4a74000}, {0xc4a76000}, 
+    {0xc4a78000}, {0xc4a7a000}, {0xc4a7c000}, {0xc4a7e000}, 
+    {0xc4a80000}, {0xc4a82000}, {0xc4a84000}, {0xc4a86000}, 
+    {0xc4a88000}, {0xc4a8a000}, {0xc4a8c000}, {0xc4a8e000}, 
+    {0xc4a90000}, {0xc4a92000}, {0xc4a94000}, {0xc4a96000}, 
+    {0xc4a98000}, {0xc4a9a000}, {0xc4a9c000}, {0xc4a9e000}, 
+    {0xc4aa0000}, {0xc4aa2000}, {0xc4aa4000}, {0xc4aa6000}, 
+    {0xc4aa8000}, {0xc4aaa000}, {0xc4aac000}, {0xc4aae000}, 
+    {0xc4ab0000}, {0xc4ab2000}, {0xc4ab4000}, {0xc4ab6000}, 
+    {0xc4ab8000}, {0xc4aba000}, {0xc4abc000}, {0xc4abe000}, 
+    {0xc4ac0000}, {0xc4ac2000}, {0xc4ac4000}, {0xc4ac6000}, 
+    {0xc4ac8000}, {0xc4aca000}, {0xc4acc000}, {0xc4ace000}, 
+    {0xc4ad0000}, {0xc4ad2000}, {0xc4ad4000}, {0xc4ad6000}, 
+    {0xc4ad8000}, {0xc4ada000}, {0xc4adc000}, {0xc4ade000}, 
+    {0xc4ae0000}, {0xc4ae2000}, {0xc4ae4000}, {0xc4ae6000}, 
+    {0xc4ae8000}, {0xc4aea000}, {0xc4aec000}, {0xc4aee000}, 
+    {0xc4af0000}, {0xc4af2000}, {0xc4af4000}, {0xc4af6000}, 
+    {0xc4af8000}, {0xc4afa000}, {0xc4afc000}, {0xc4afe000}, 
+    {0xc4b00000}, {0xc4b02000}, {0xc4b04000}, {0xc4b06000}, 
+    {0xc4b08000}, {0xc4b0a000}, {0xc4b0c000}, {0xc4b0e000}, 
+    {0xc4b10000}, {0xc4b12000}, {0xc4b14000}, {0xc4b16000}, 
+    {0xc4b18000}, {0xc4b1a000}, {0xc4b1c000}, {0xc4b1e000}, 
+    {0xc4b20000}, {0xc4b22000}, {0xc4b24000}, {0xc4b26000}, 
+    {0xc4b28000}, {0xc4b2a000}, {0xc4b2c000}, {0xc4b2e000}, 
+    {0xc4b30000}, {0xc4b32000}, {0xc4b34000}, {0xc4b36000}, 
+    {0xc4b38000}, {0xc4b3a000}, {0xc4b3c000}, {0xc4b3e000}, 
+    {0xc4b40000}, {0xc4b42000}, {0xc4b44000}, {0xc4b46000}, 
+    {0xc4b48000}, {0xc4b4a000}, {0xc4b4c000}, {0xc4b4e000}, 
+    {0xc4b50000}, {0xc4b52000}, {0xc4b54000}, {0xc4b56000}, 
+    {0xc4b58000}, {0xc4b5a000}, {0xc4b5c000}, {0xc4b5e000}, 
+    {0xc4b60000}, {0xc4b62000}, {0xc4b64000}, {0xc4b66000}, 
+    {0xc4b68000}, {0xc4b6a000}, {0xc4b6c000}, {0xc4b6e000}, 
+    {0xc4b70000}, {0xc4b72000}, {0xc4b74000}, {0xc4b76000}, 
+    {0xc4b78000}, {0xc4b7a000}, {0xc4b7c000}, {0xc4b7e000}, 
+    {0xc4b80000}, {0xc4b82000}, {0xc4b84000}, {0xc4b86000}, 
+    {0xc4b88000}, {0xc4b8a000}, {0xc4b8c000}, {0xc4b8e000}, 
+    {0xc4b90000}, {0xc4b92000}, {0xc4b94000}, {0xc4b96000}, 
+    {0xc4b98000}, {0xc4b9a000}, {0xc4b9c000}, {0xc4b9e000}, 
+    {0xc4ba0000}, {0xc4ba2000}, {0xc4ba4000}, {0xc4ba6000}, 
+    {0xc4ba8000}, {0xc4baa000}, {0xc4bac000}, {0xc4bae000}, 
+    {0xc4bb0000}, {0xc4bb2000}, {0xc4bb4000}, {0xc4bb6000}, 
+    {0xc4bb8000}, {0xc4bba000}, {0xc4bbc000}, {0xc4bbe000}, 
+    {0xc4bc0000}, {0xc4bc2000}, {0xc4bc4000}, {0xc4bc6000}, 
+    {0xc4bc8000}, {0xc4bca000}, {0xc4bcc000}, {0xc4bce000}, 
+    {0xc4bd0000}, {0xc4bd2000}, {0xc4bd4000}, {0xc4bd6000}, 
+    {0xc4bd8000}, {0xc4bda000}, {0xc4bdc000}, {0xc4bde000}, 
+    {0xc4be0000}, {0xc4be2000}, {0xc4be4000}, {0xc4be6000}, 
+    {0xc4be8000}, {0xc4bea000}, {0xc4bec000}, {0xc4bee000}, 
+    {0xc4bf0000}, {0xc4bf2000}, {0xc4bf4000}, {0xc4bf6000}, 
+    {0xc4bf8000}, {0xc4bfa000}, {0xc4bfc000}, {0xc4bfe000}, 
+    {0xc4c00000}, {0xc4c02000}, {0xc4c04000}, {0xc4c06000}, 
+    {0xc4c08000}, {0xc4c0a000}, {0xc4c0c000}, {0xc4c0e000}, 
+    {0xc4c10000}, {0xc4c12000}, {0xc4c14000}, {0xc4c16000}, 
+    {0xc4c18000}, {0xc4c1a000}, {0xc4c1c000}, {0xc4c1e000}, 
+    {0xc4c20000}, {0xc4c22000}, {0xc4c24000}, {0xc4c26000}, 
+    {0xc4c28000}, {0xc4c2a000}, {0xc4c2c000}, {0xc4c2e000}, 
+    {0xc4c30000}, {0xc4c32000}, {0xc4c34000}, {0xc4c36000}, 
+    {0xc4c38000}, {0xc4c3a000}, {0xc4c3c000}, {0xc4c3e000}, 
+    {0xc4c40000}, {0xc4c42000}, {0xc4c44000}, {0xc4c46000}, 
+    {0xc4c48000}, {0xc4c4a000}, {0xc4c4c000}, {0xc4c4e000}, 
+    {0xc4c50000}, {0xc4c52000}, {0xc4c54000}, {0xc4c56000}, 
+    {0xc4c58000}, {0xc4c5a000}, {0xc4c5c000}, {0xc4c5e000}, 
+    {0xc4c60000}, {0xc4c62000}, {0xc4c64000}, {0xc4c66000}, 
+    {0xc4c68000}, {0xc4c6a000}, {0xc4c6c000}, {0xc4c6e000}, 
+    {0xc4c70000}, {0xc4c72000}, {0xc4c74000}, {0xc4c76000}, 
+    {0xc4c78000}, {0xc4c7a000}, {0xc4c7c000}, {0xc4c7e000}, 
+    {0xc4c80000}, {0xc4c82000}, {0xc4c84000}, {0xc4c86000}, 
+    {0xc4c88000}, {0xc4c8a000}, {0xc4c8c000}, {0xc4c8e000}, 
+    {0xc4c90000}, {0xc4c92000}, {0xc4c94000}, {0xc4c96000}, 
+    {0xc4c98000}, {0xc4c9a000}, {0xc4c9c000}, {0xc4c9e000}, 
+    {0xc4ca0000}, {0xc4ca2000}, {0xc4ca4000}, {0xc4ca6000}, 
+    {0xc4ca8000}, {0xc4caa000}, {0xc4cac000}, {0xc4cae000}, 
+    {0xc4cb0000}, {0xc4cb2000}, {0xc4cb4000}, {0xc4cb6000}, 
+    {0xc4cb8000}, {0xc4cba000}, {0xc4cbc000}, {0xc4cbe000}, 
+    {0xc4cc0000}, {0xc4cc2000}, {0xc4cc4000}, {0xc4cc6000}, 
+    {0xc4cc8000}, {0xc4cca000}, {0xc4ccc000}, {0xc4cce000}, 
+    {0xc4cd0000}, {0xc4cd2000}, {0xc4cd4000}, {0xc4cd6000}, 
+    {0xc4cd8000}, {0xc4cda000}, {0xc4cdc000}, {0xc4cde000}, 
+    {0xc4ce0000}, {0xc4ce2000}, {0xc4ce4000}, {0xc4ce6000}, 
+    {0xc4ce8000}, {0xc4cea000}, {0xc4cec000}, {0xc4cee000}, 
+    {0xc4cf0000}, {0xc4cf2000}, {0xc4cf4000}, {0xc4cf6000}, 
+    {0xc4cf8000}, {0xc4cfa000}, {0xc4cfc000}, {0xc4cfe000}, 
+    {0xc4d00000}, {0xc4d02000}, {0xc4d04000}, {0xc4d06000}, 
+    {0xc4d08000}, {0xc4d0a000}, {0xc4d0c000}, {0xc4d0e000}, 
+    {0xc4d10000}, {0xc4d12000}, {0xc4d14000}, {0xc4d16000}, 
+    {0xc4d18000}, {0xc4d1a000}, {0xc4d1c000}, {0xc4d1e000}, 
+    {0xc4d20000}, {0xc4d22000}, {0xc4d24000}, {0xc4d26000}, 
+    {0xc4d28000}, {0xc4d2a000}, {0xc4d2c000}, {0xc4d2e000}, 
+    {0xc4d30000}, {0xc4d32000}, {0xc4d34000}, {0xc4d36000}, 
+    {0xc4d38000}, {0xc4d3a000}, {0xc4d3c000}, {0xc4d3e000}, 
+    {0xc4d40000}, {0xc4d42000}, {0xc4d44000}, {0xc4d46000}, 
+    {0xc4d48000}, {0xc4d4a000}, {0xc4d4c000}, {0xc4d4e000}, 
+    {0xc4d50000}, {0xc4d52000}, {0xc4d54000}, {0xc4d56000}, 
+    {0xc4d58000}, {0xc4d5a000}, {0xc4d5c000}, {0xc4d5e000}, 
+    {0xc4d60000}, {0xc4d62000}, {0xc4d64000}, {0xc4d66000}, 
+    {0xc4d68000}, {0xc4d6a000}, {0xc4d6c000}, {0xc4d6e000}, 
+    {0xc4d70000}, {0xc4d72000}, {0xc4d74000}, {0xc4d76000}, 
+    {0xc4d78000}, {0xc4d7a000}, {0xc4d7c000}, {0xc4d7e000}, 
+    {0xc4d80000}, {0xc4d82000}, {0xc4d84000}, {0xc4d86000}, 
+    {0xc4d88000}, {0xc4d8a000}, {0xc4d8c000}, {0xc4d8e000}, 
+    {0xc4d90000}, {0xc4d92000}, {0xc4d94000}, {0xc4d96000}, 
+    {0xc4d98000}, {0xc4d9a000}, {0xc4d9c000}, {0xc4d9e000}, 
+    {0xc4da0000}, {0xc4da2000}, {0xc4da4000}, {0xc4da6000}, 
+    {0xc4da8000}, {0xc4daa000}, {0xc4dac000}, {0xc4dae000}, 
+    {0xc4db0000}, {0xc4db2000}, {0xc4db4000}, {0xc4db6000}, 
+    {0xc4db8000}, {0xc4dba000}, {0xc4dbc000}, {0xc4dbe000}, 
+    {0xc4dc0000}, {0xc4dc2000}, {0xc4dc4000}, {0xc4dc6000}, 
+    {0xc4dc8000}, {0xc4dca000}, {0xc4dcc000}, {0xc4dce000}, 
+    {0xc4dd0000}, {0xc4dd2000}, {0xc4dd4000}, {0xc4dd6000}, 
+    {0xc4dd8000}, {0xc4dda000}, {0xc4ddc000}, {0xc4dde000}, 
+    {0xc4de0000}, {0xc4de2000}, {0xc4de4000}, {0xc4de6000}, 
+    {0xc4de8000}, {0xc4dea000}, {0xc4dec000}, {0xc4dee000}, 
+    {0xc4df0000}, {0xc4df2000}, {0xc4df4000}, {0xc4df6000}, 
+    {0xc4df8000}, {0xc4dfa000}, {0xc4dfc000}, {0xc4dfe000}, 
+    {0xc4e00000}, {0xc4e02000}, {0xc4e04000}, {0xc4e06000}, 
+    {0xc4e08000}, {0xc4e0a000}, {0xc4e0c000}, {0xc4e0e000}, 
+    {0xc4e10000}, {0xc4e12000}, {0xc4e14000}, {0xc4e16000}, 
+    {0xc4e18000}, {0xc4e1a000}, {0xc4e1c000}, {0xc4e1e000}, 
+    {0xc4e20000}, {0xc4e22000}, {0xc4e24000}, {0xc4e26000}, 
+    {0xc4e28000}, {0xc4e2a000}, {0xc4e2c000}, {0xc4e2e000}, 
+    {0xc4e30000}, {0xc4e32000}, {0xc4e34000}, {0xc4e36000}, 
+    {0xc4e38000}, {0xc4e3a000}, {0xc4e3c000}, {0xc4e3e000}, 
+    {0xc4e40000}, {0xc4e42000}, {0xc4e44000}, {0xc4e46000}, 
+    {0xc4e48000}, {0xc4e4a000}, {0xc4e4c000}, {0xc4e4e000}, 
+    {0xc4e50000}, {0xc4e52000}, {0xc4e54000}, {0xc4e56000}, 
+    {0xc4e58000}, {0xc4e5a000}, {0xc4e5c000}, {0xc4e5e000}, 
+    {0xc4e60000}, {0xc4e62000}, {0xc4e64000}, {0xc4e66000}, 
+    {0xc4e68000}, {0xc4e6a000}, {0xc4e6c000}, {0xc4e6e000}, 
+    {0xc4e70000}, {0xc4e72000}, {0xc4e74000}, {0xc4e76000}, 
+    {0xc4e78000}, {0xc4e7a000}, {0xc4e7c000}, {0xc4e7e000}, 
+    {0xc4e80000}, {0xc4e82000}, {0xc4e84000}, {0xc4e86000}, 
+    {0xc4e88000}, {0xc4e8a000}, {0xc4e8c000}, {0xc4e8e000}, 
+    {0xc4e90000}, {0xc4e92000}, {0xc4e94000}, {0xc4e96000}, 
+    {0xc4e98000}, {0xc4e9a000}, {0xc4e9c000}, {0xc4e9e000}, 
+    {0xc4ea0000}, {0xc4ea2000}, {0xc4ea4000}, {0xc4ea6000}, 
+    {0xc4ea8000}, {0xc4eaa000}, {0xc4eac000}, {0xc4eae000}, 
+    {0xc4eb0000}, {0xc4eb2000}, {0xc4eb4000}, {0xc4eb6000}, 
+    {0xc4eb8000}, {0xc4eba000}, {0xc4ebc000}, {0xc4ebe000}, 
+    {0xc4ec0000}, {0xc4ec2000}, {0xc4ec4000}, {0xc4ec6000}, 
+    {0xc4ec8000}, {0xc4eca000}, {0xc4ecc000}, {0xc4ece000}, 
+    {0xc4ed0000}, {0xc4ed2000}, {0xc4ed4000}, {0xc4ed6000}, 
+    {0xc4ed8000}, {0xc4eda000}, {0xc4edc000}, {0xc4ede000}, 
+    {0xc4ee0000}, {0xc4ee2000}, {0xc4ee4000}, {0xc4ee6000}, 
+    {0xc4ee8000}, {0xc4eea000}, {0xc4eec000}, {0xc4eee000}, 
+    {0xc4ef0000}, {0xc4ef2000}, {0xc4ef4000}, {0xc4ef6000}, 
+    {0xc4ef8000}, {0xc4efa000}, {0xc4efc000}, {0xc4efe000}, 
+    {0xc4f00000}, {0xc4f02000}, {0xc4f04000}, {0xc4f06000}, 
+    {0xc4f08000}, {0xc4f0a000}, {0xc4f0c000}, {0xc4f0e000}, 
+    {0xc4f10000}, {0xc4f12000}, {0xc4f14000}, {0xc4f16000}, 
+    {0xc4f18000}, {0xc4f1a000}, {0xc4f1c000}, {0xc4f1e000}, 
+    {0xc4f20000}, {0xc4f22000}, {0xc4f24000}, {0xc4f26000}, 
+    {0xc4f28000}, {0xc4f2a000}, {0xc4f2c000}, {0xc4f2e000}, 
+    {0xc4f30000}, {0xc4f32000}, {0xc4f34000}, {0xc4f36000}, 
+    {0xc4f38000}, {0xc4f3a000}, {0xc4f3c000}, {0xc4f3e000}, 
+    {0xc4f40000}, {0xc4f42000}, {0xc4f44000}, {0xc4f46000}, 
+    {0xc4f48000}, {0xc4f4a000}, {0xc4f4c000}, {0xc4f4e000}, 
+    {0xc4f50000}, {0xc4f52000}, {0xc4f54000}, {0xc4f56000}, 
+    {0xc4f58000}, {0xc4f5a000}, {0xc4f5c000}, {0xc4f5e000}, 
+    {0xc4f60000}, {0xc4f62000}, {0xc4f64000}, {0xc4f66000}, 
+    {0xc4f68000}, {0xc4f6a000}, {0xc4f6c000}, {0xc4f6e000}, 
+    {0xc4f70000}, {0xc4f72000}, {0xc4f74000}, {0xc4f76000}, 
+    {0xc4f78000}, {0xc4f7a000}, {0xc4f7c000}, {0xc4f7e000}, 
+    {0xc4f80000}, {0xc4f82000}, {0xc4f84000}, {0xc4f86000}, 
+    {0xc4f88000}, {0xc4f8a000}, {0xc4f8c000}, {0xc4f8e000}, 
+    {0xc4f90000}, {0xc4f92000}, {0xc4f94000}, {0xc4f96000}, 
+    {0xc4f98000}, {0xc4f9a000}, {0xc4f9c000}, {0xc4f9e000}, 
+    {0xc4fa0000}, {0xc4fa2000}, {0xc4fa4000}, {0xc4fa6000}, 
+    {0xc4fa8000}, {0xc4faa000}, {0xc4fac000}, {0xc4fae000}, 
+    {0xc4fb0000}, {0xc4fb2000}, {0xc4fb4000}, {0xc4fb6000}, 
+    {0xc4fb8000}, {0xc4fba000}, {0xc4fbc000}, {0xc4fbe000}, 
+    {0xc4fc0000}, {0xc4fc2000}, {0xc4fc4000}, {0xc4fc6000}, 
+    {0xc4fc8000}, {0xc4fca000}, {0xc4fcc000}, {0xc4fce000}, 
+    {0xc4fd0000}, {0xc4fd2000}, {0xc4fd4000}, {0xc4fd6000}, 
+    {0xc4fd8000}, {0xc4fda000}, {0xc4fdc000}, {0xc4fde000}, 
+    {0xc4fe0000}, {0xc4fe2000}, {0xc4fe4000}, {0xc4fe6000}, 
+    {0xc4fe8000}, {0xc4fea000}, {0xc4fec000}, {0xc4fee000}, 
+    {0xc4ff0000}, {0xc4ff2000}, {0xc4ff4000}, {0xc4ff6000}, 
+    {0xc4ff8000}, {0xc4ffa000}, {0xc4ffc000}, {0xc4ffe000}, 
+    {0xc5000000}, {0xc5002000}, {0xc5004000}, {0xc5006000}, 
+    {0xc5008000}, {0xc500a000}, {0xc500c000}, {0xc500e000}, 
+    {0xc5010000}, {0xc5012000}, {0xc5014000}, {0xc5016000}, 
+    {0xc5018000}, {0xc501a000}, {0xc501c000}, {0xc501e000}, 
+    {0xc5020000}, {0xc5022000}, {0xc5024000}, {0xc5026000}, 
+    {0xc5028000}, {0xc502a000}, {0xc502c000}, {0xc502e000}, 
+    {0xc5030000}, {0xc5032000}, {0xc5034000}, {0xc5036000}, 
+    {0xc5038000}, {0xc503a000}, {0xc503c000}, {0xc503e000}, 
+    {0xc5040000}, {0xc5042000}, {0xc5044000}, {0xc5046000}, 
+    {0xc5048000}, {0xc504a000}, {0xc504c000}, {0xc504e000}, 
+    {0xc5050000}, {0xc5052000}, {0xc5054000}, {0xc5056000}, 
+    {0xc5058000}, {0xc505a000}, {0xc505c000}, {0xc505e000}, 
+    {0xc5060000}, {0xc5062000}, {0xc5064000}, {0xc5066000}, 
+    {0xc5068000}, {0xc506a000}, {0xc506c000}, {0xc506e000}, 
+    {0xc5070000}, {0xc5072000}, {0xc5074000}, {0xc5076000}, 
+    {0xc5078000}, {0xc507a000}, {0xc507c000}, {0xc507e000}, 
+    {0xc5080000}, {0xc5082000}, {0xc5084000}, {0xc5086000}, 
+    {0xc5088000}, {0xc508a000}, {0xc508c000}, {0xc508e000}, 
+    {0xc5090000}, {0xc5092000}, {0xc5094000}, {0xc5096000}, 
+    {0xc5098000}, {0xc509a000}, {0xc509c000}, {0xc509e000}, 
+    {0xc50a0000}, {0xc50a2000}, {0xc50a4000}, {0xc50a6000}, 
+    {0xc50a8000}, {0xc50aa000}, {0xc50ac000}, {0xc50ae000}, 
+    {0xc50b0000}, {0xc50b2000}, {0xc50b4000}, {0xc50b6000}, 
+    {0xc50b8000}, {0xc50ba000}, {0xc50bc000}, {0xc50be000}, 
+    {0xc50c0000}, {0xc50c2000}, {0xc50c4000}, {0xc50c6000}, 
+    {0xc50c8000}, {0xc50ca000}, {0xc50cc000}, {0xc50ce000}, 
+    {0xc50d0000}, {0xc50d2000}, {0xc50d4000}, {0xc50d6000}, 
+    {0xc50d8000}, {0xc50da000}, {0xc50dc000}, {0xc50de000}, 
+    {0xc50e0000}, {0xc50e2000}, {0xc50e4000}, {0xc50e6000}, 
+    {0xc50e8000}, {0xc50ea000}, {0xc50ec000}, {0xc50ee000}, 
+    {0xc50f0000}, {0xc50f2000}, {0xc50f4000}, {0xc50f6000}, 
+    {0xc50f8000}, {0xc50fa000}, {0xc50fc000}, {0xc50fe000}, 
+    {0xc5100000}, {0xc5102000}, {0xc5104000}, {0xc5106000}, 
+    {0xc5108000}, {0xc510a000}, {0xc510c000}, {0xc510e000}, 
+    {0xc5110000}, {0xc5112000}, {0xc5114000}, {0xc5116000}, 
+    {0xc5118000}, {0xc511a000}, {0xc511c000}, {0xc511e000}, 
+    {0xc5120000}, {0xc5122000}, {0xc5124000}, {0xc5126000}, 
+    {0xc5128000}, {0xc512a000}, {0xc512c000}, {0xc512e000}, 
+    {0xc5130000}, {0xc5132000}, {0xc5134000}, {0xc5136000}, 
+    {0xc5138000}, {0xc513a000}, {0xc513c000}, {0xc513e000}, 
+    {0xc5140000}, {0xc5142000}, {0xc5144000}, {0xc5146000}, 
+    {0xc5148000}, {0xc514a000}, {0xc514c000}, {0xc514e000}, 
+    {0xc5150000}, {0xc5152000}, {0xc5154000}, {0xc5156000}, 
+    {0xc5158000}, {0xc515a000}, {0xc515c000}, {0xc515e000}, 
+    {0xc5160000}, {0xc5162000}, {0xc5164000}, {0xc5166000}, 
+    {0xc5168000}, {0xc516a000}, {0xc516c000}, {0xc516e000}, 
+    {0xc5170000}, {0xc5172000}, {0xc5174000}, {0xc5176000}, 
+    {0xc5178000}, {0xc517a000}, {0xc517c000}, {0xc517e000}, 
+    {0xc5180000}, {0xc5182000}, {0xc5184000}, {0xc5186000}, 
+    {0xc5188000}, {0xc518a000}, {0xc518c000}, {0xc518e000}, 
+    {0xc5190000}, {0xc5192000}, {0xc5194000}, {0xc5196000}, 
+    {0xc5198000}, {0xc519a000}, {0xc519c000}, {0xc519e000}, 
+    {0xc51a0000}, {0xc51a2000}, {0xc51a4000}, {0xc51a6000}, 
+    {0xc51a8000}, {0xc51aa000}, {0xc51ac000}, {0xc51ae000}, 
+    {0xc51b0000}, {0xc51b2000}, {0xc51b4000}, {0xc51b6000}, 
+    {0xc51b8000}, {0xc51ba000}, {0xc51bc000}, {0xc51be000}, 
+    {0xc51c0000}, {0xc51c2000}, {0xc51c4000}, {0xc51c6000}, 
+    {0xc51c8000}, {0xc51ca000}, {0xc51cc000}, {0xc51ce000}, 
+    {0xc51d0000}, {0xc51d2000}, {0xc51d4000}, {0xc51d6000}, 
+    {0xc51d8000}, {0xc51da000}, {0xc51dc000}, {0xc51de000}, 
+    {0xc51e0000}, {0xc51e2000}, {0xc51e4000}, {0xc51e6000}, 
+    {0xc51e8000}, {0xc51ea000}, {0xc51ec000}, {0xc51ee000}, 
+    {0xc51f0000}, {0xc51f2000}, {0xc51f4000}, {0xc51f6000}, 
+    {0xc51f8000}, {0xc51fa000}, {0xc51fc000}, {0xc51fe000}, 
+    {0xc5200000}, {0xc5202000}, {0xc5204000}, {0xc5206000}, 
+    {0xc5208000}, {0xc520a000}, {0xc520c000}, {0xc520e000}, 
+    {0xc5210000}, {0xc5212000}, {0xc5214000}, {0xc5216000}, 
+    {0xc5218000}, {0xc521a000}, {0xc521c000}, {0xc521e000}, 
+    {0xc5220000}, {0xc5222000}, {0xc5224000}, {0xc5226000}, 
+    {0xc5228000}, {0xc522a000}, {0xc522c000}, {0xc522e000}, 
+    {0xc5230000}, {0xc5232000}, {0xc5234000}, {0xc5236000}, 
+    {0xc5238000}, {0xc523a000}, {0xc523c000}, {0xc523e000}, 
+    {0xc5240000}, {0xc5242000}, {0xc5244000}, {0xc5246000}, 
+    {0xc5248000}, {0xc524a000}, {0xc524c000}, {0xc524e000}, 
+    {0xc5250000}, {0xc5252000}, {0xc5254000}, {0xc5256000}, 
+    {0xc5258000}, {0xc525a000}, {0xc525c000}, {0xc525e000}, 
+    {0xc5260000}, {0xc5262000}, {0xc5264000}, {0xc5266000}, 
+    {0xc5268000}, {0xc526a000}, {0xc526c000}, {0xc526e000}, 
+    {0xc5270000}, {0xc5272000}, {0xc5274000}, {0xc5276000}, 
+    {0xc5278000}, {0xc527a000}, {0xc527c000}, {0xc527e000}, 
+    {0xc5280000}, {0xc5282000}, {0xc5284000}, {0xc5286000}, 
+    {0xc5288000}, {0xc528a000}, {0xc528c000}, {0xc528e000}, 
+    {0xc5290000}, {0xc5292000}, {0xc5294000}, {0xc5296000}, 
+    {0xc5298000}, {0xc529a000}, {0xc529c000}, {0xc529e000}, 
+    {0xc52a0000}, {0xc52a2000}, {0xc52a4000}, {0xc52a6000}, 
+    {0xc52a8000}, {0xc52aa000}, {0xc52ac000}, {0xc52ae000}, 
+    {0xc52b0000}, {0xc52b2000}, {0xc52b4000}, {0xc52b6000}, 
+    {0xc52b8000}, {0xc52ba000}, {0xc52bc000}, {0xc52be000}, 
+    {0xc52c0000}, {0xc52c2000}, {0xc52c4000}, {0xc52c6000}, 
+    {0xc52c8000}, {0xc52ca000}, {0xc52cc000}, {0xc52ce000}, 
+    {0xc52d0000}, {0xc52d2000}, {0xc52d4000}, {0xc52d6000}, 
+    {0xc52d8000}, {0xc52da000}, {0xc52dc000}, {0xc52de000}, 
+    {0xc52e0000}, {0xc52e2000}, {0xc52e4000}, {0xc52e6000}, 
+    {0xc52e8000}, {0xc52ea000}, {0xc52ec000}, {0xc52ee000}, 
+    {0xc52f0000}, {0xc52f2000}, {0xc52f4000}, {0xc52f6000}, 
+    {0xc52f8000}, {0xc52fa000}, {0xc52fc000}, {0xc52fe000}, 
+    {0xc5300000}, {0xc5302000}, {0xc5304000}, {0xc5306000}, 
+    {0xc5308000}, {0xc530a000}, {0xc530c000}, {0xc530e000}, 
+    {0xc5310000}, {0xc5312000}, {0xc5314000}, {0xc5316000}, 
+    {0xc5318000}, {0xc531a000}, {0xc531c000}, {0xc531e000}, 
+    {0xc5320000}, {0xc5322000}, {0xc5324000}, {0xc5326000}, 
+    {0xc5328000}, {0xc532a000}, {0xc532c000}, {0xc532e000}, 
+    {0xc5330000}, {0xc5332000}, {0xc5334000}, {0xc5336000}, 
+    {0xc5338000}, {0xc533a000}, {0xc533c000}, {0xc533e000}, 
+    {0xc5340000}, {0xc5342000}, {0xc5344000}, {0xc5346000}, 
+    {0xc5348000}, {0xc534a000}, {0xc534c000}, {0xc534e000}, 
+    {0xc5350000}, {0xc5352000}, {0xc5354000}, {0xc5356000}, 
+    {0xc5358000}, {0xc535a000}, {0xc535c000}, {0xc535e000}, 
+    {0xc5360000}, {0xc5362000}, {0xc5364000}, {0xc5366000}, 
+    {0xc5368000}, {0xc536a000}, {0xc536c000}, {0xc536e000}, 
+    {0xc5370000}, {0xc5372000}, {0xc5374000}, {0xc5376000}, 
+    {0xc5378000}, {0xc537a000}, {0xc537c000}, {0xc537e000}, 
+    {0xc5380000}, {0xc5382000}, {0xc5384000}, {0xc5386000}, 
+    {0xc5388000}, {0xc538a000}, {0xc538c000}, {0xc538e000}, 
+    {0xc5390000}, {0xc5392000}, {0xc5394000}, {0xc5396000}, 
+    {0xc5398000}, {0xc539a000}, {0xc539c000}, {0xc539e000}, 
+    {0xc53a0000}, {0xc53a2000}, {0xc53a4000}, {0xc53a6000}, 
+    {0xc53a8000}, {0xc53aa000}, {0xc53ac000}, {0xc53ae000}, 
+    {0xc53b0000}, {0xc53b2000}, {0xc53b4000}, {0xc53b6000}, 
+    {0xc53b8000}, {0xc53ba000}, {0xc53bc000}, {0xc53be000}, 
+    {0xc53c0000}, {0xc53c2000}, {0xc53c4000}, {0xc53c6000}, 
+    {0xc53c8000}, {0xc53ca000}, {0xc53cc000}, {0xc53ce000}, 
+    {0xc53d0000}, {0xc53d2000}, {0xc53d4000}, {0xc53d6000}, 
+    {0xc53d8000}, {0xc53da000}, {0xc53dc000}, {0xc53de000}, 
+    {0xc53e0000}, {0xc53e2000}, {0xc53e4000}, {0xc53e6000}, 
+    {0xc53e8000}, {0xc53ea000}, {0xc53ec000}, {0xc53ee000}, 
+    {0xc53f0000}, {0xc53f2000}, {0xc53f4000}, {0xc53f6000}, 
+    {0xc53f8000}, {0xc53fa000}, {0xc53fc000}, {0xc53fe000}, 
+    {0xc5400000}, {0xc5402000}, {0xc5404000}, {0xc5406000}, 
+    {0xc5408000}, {0xc540a000}, {0xc540c000}, {0xc540e000}, 
+    {0xc5410000}, {0xc5412000}, {0xc5414000}, {0xc5416000}, 
+    {0xc5418000}, {0xc541a000}, {0xc541c000}, {0xc541e000}, 
+    {0xc5420000}, {0xc5422000}, {0xc5424000}, {0xc5426000}, 
+    {0xc5428000}, {0xc542a000}, {0xc542c000}, {0xc542e000}, 
+    {0xc5430000}, {0xc5432000}, {0xc5434000}, {0xc5436000}, 
+    {0xc5438000}, {0xc543a000}, {0xc543c000}, {0xc543e000}, 
+    {0xc5440000}, {0xc5442000}, {0xc5444000}, {0xc5446000}, 
+    {0xc5448000}, {0xc544a000}, {0xc544c000}, {0xc544e000}, 
+    {0xc5450000}, {0xc5452000}, {0xc5454000}, {0xc5456000}, 
+    {0xc5458000}, {0xc545a000}, {0xc545c000}, {0xc545e000}, 
+    {0xc5460000}, {0xc5462000}, {0xc5464000}, {0xc5466000}, 
+    {0xc5468000}, {0xc546a000}, {0xc546c000}, {0xc546e000}, 
+    {0xc5470000}, {0xc5472000}, {0xc5474000}, {0xc5476000}, 
+    {0xc5478000}, {0xc547a000}, {0xc547c000}, {0xc547e000}, 
+    {0xc5480000}, {0xc5482000}, {0xc5484000}, {0xc5486000}, 
+    {0xc5488000}, {0xc548a000}, {0xc548c000}, {0xc548e000}, 
+    {0xc5490000}, {0xc5492000}, {0xc5494000}, {0xc5496000}, 
+    {0xc5498000}, {0xc549a000}, {0xc549c000}, {0xc549e000}, 
+    {0xc54a0000}, {0xc54a2000}, {0xc54a4000}, {0xc54a6000}, 
+    {0xc54a8000}, {0xc54aa000}, {0xc54ac000}, {0xc54ae000}, 
+    {0xc54b0000}, {0xc54b2000}, {0xc54b4000}, {0xc54b6000}, 
+    {0xc54b8000}, {0xc54ba000}, {0xc54bc000}, {0xc54be000}, 
+    {0xc54c0000}, {0xc54c2000}, {0xc54c4000}, {0xc54c6000}, 
+    {0xc54c8000}, {0xc54ca000}, {0xc54cc000}, {0xc54ce000}, 
+    {0xc54d0000}, {0xc54d2000}, {0xc54d4000}, {0xc54d6000}, 
+    {0xc54d8000}, {0xc54da000}, {0xc54dc000}, {0xc54de000}, 
+    {0xc54e0000}, {0xc54e2000}, {0xc54e4000}, {0xc54e6000}, 
+    {0xc54e8000}, {0xc54ea000}, {0xc54ec000}, {0xc54ee000}, 
+    {0xc54f0000}, {0xc54f2000}, {0xc54f4000}, {0xc54f6000}, 
+    {0xc54f8000}, {0xc54fa000}, {0xc54fc000}, {0xc54fe000}, 
+    {0xc5500000}, {0xc5502000}, {0xc5504000}, {0xc5506000}, 
+    {0xc5508000}, {0xc550a000}, {0xc550c000}, {0xc550e000}, 
+    {0xc5510000}, {0xc5512000}, {0xc5514000}, {0xc5516000}, 
+    {0xc5518000}, {0xc551a000}, {0xc551c000}, {0xc551e000}, 
+    {0xc5520000}, {0xc5522000}, {0xc5524000}, {0xc5526000}, 
+    {0xc5528000}, {0xc552a000}, {0xc552c000}, {0xc552e000}, 
+    {0xc5530000}, {0xc5532000}, {0xc5534000}, {0xc5536000}, 
+    {0xc5538000}, {0xc553a000}, {0xc553c000}, {0xc553e000}, 
+    {0xc5540000}, {0xc5542000}, {0xc5544000}, {0xc5546000}, 
+    {0xc5548000}, {0xc554a000}, {0xc554c000}, {0xc554e000}, 
+    {0xc5550000}, {0xc5552000}, {0xc5554000}, {0xc5556000}, 
+    {0xc5558000}, {0xc555a000}, {0xc555c000}, {0xc555e000}, 
+    {0xc5560000}, {0xc5562000}, {0xc5564000}, {0xc5566000}, 
+    {0xc5568000}, {0xc556a000}, {0xc556c000}, {0xc556e000}, 
+    {0xc5570000}, {0xc5572000}, {0xc5574000}, {0xc5576000}, 
+    {0xc5578000}, {0xc557a000}, {0xc557c000}, {0xc557e000}, 
+    {0xc5580000}, {0xc5582000}, {0xc5584000}, {0xc5586000}, 
+    {0xc5588000}, {0xc558a000}, {0xc558c000}, {0xc558e000}, 
+    {0xc5590000}, {0xc5592000}, {0xc5594000}, {0xc5596000}, 
+    {0xc5598000}, {0xc559a000}, {0xc559c000}, {0xc559e000}, 
+    {0xc55a0000}, {0xc55a2000}, {0xc55a4000}, {0xc55a6000}, 
+    {0xc55a8000}, {0xc55aa000}, {0xc55ac000}, {0xc55ae000}, 
+    {0xc55b0000}, {0xc55b2000}, {0xc55b4000}, {0xc55b6000}, 
+    {0xc55b8000}, {0xc55ba000}, {0xc55bc000}, {0xc55be000}, 
+    {0xc55c0000}, {0xc55c2000}, {0xc55c4000}, {0xc55c6000}, 
+    {0xc55c8000}, {0xc55ca000}, {0xc55cc000}, {0xc55ce000}, 
+    {0xc55d0000}, {0xc55d2000}, {0xc55d4000}, {0xc55d6000}, 
+    {0xc55d8000}, {0xc55da000}, {0xc55dc000}, {0xc55de000}, 
+    {0xc55e0000}, {0xc55e2000}, {0xc55e4000}, {0xc55e6000}, 
+    {0xc55e8000}, {0xc55ea000}, {0xc55ec000}, {0xc55ee000}, 
+    {0xc55f0000}, {0xc55f2000}, {0xc55f4000}, {0xc55f6000}, 
+    {0xc55f8000}, {0xc55fa000}, {0xc55fc000}, {0xc55fe000}, 
+    {0xc5600000}, {0xc5602000}, {0xc5604000}, {0xc5606000}, 
+    {0xc5608000}, {0xc560a000}, {0xc560c000}, {0xc560e000}, 
+    {0xc5610000}, {0xc5612000}, {0xc5614000}, {0xc5616000}, 
+    {0xc5618000}, {0xc561a000}, {0xc561c000}, {0xc561e000}, 
+    {0xc5620000}, {0xc5622000}, {0xc5624000}, {0xc5626000}, 
+    {0xc5628000}, {0xc562a000}, {0xc562c000}, {0xc562e000}, 
+    {0xc5630000}, {0xc5632000}, {0xc5634000}, {0xc5636000}, 
+    {0xc5638000}, {0xc563a000}, {0xc563c000}, {0xc563e000}, 
+    {0xc5640000}, {0xc5642000}, {0xc5644000}, {0xc5646000}, 
+    {0xc5648000}, {0xc564a000}, {0xc564c000}, {0xc564e000}, 
+    {0xc5650000}, {0xc5652000}, {0xc5654000}, {0xc5656000}, 
+    {0xc5658000}, {0xc565a000}, {0xc565c000}, {0xc565e000}, 
+    {0xc5660000}, {0xc5662000}, {0xc5664000}, {0xc5666000}, 
+    {0xc5668000}, {0xc566a000}, {0xc566c000}, {0xc566e000}, 
+    {0xc5670000}, {0xc5672000}, {0xc5674000}, {0xc5676000}, 
+    {0xc5678000}, {0xc567a000}, {0xc567c000}, {0xc567e000}, 
+    {0xc5680000}, {0xc5682000}, {0xc5684000}, {0xc5686000}, 
+    {0xc5688000}, {0xc568a000}, {0xc568c000}, {0xc568e000}, 
+    {0xc5690000}, {0xc5692000}, {0xc5694000}, {0xc5696000}, 
+    {0xc5698000}, {0xc569a000}, {0xc569c000}, {0xc569e000}, 
+    {0xc56a0000}, {0xc56a2000}, {0xc56a4000}, {0xc56a6000}, 
+    {0xc56a8000}, {0xc56aa000}, {0xc56ac000}, {0xc56ae000}, 
+    {0xc56b0000}, {0xc56b2000}, {0xc56b4000}, {0xc56b6000}, 
+    {0xc56b8000}, {0xc56ba000}, {0xc56bc000}, {0xc56be000}, 
+    {0xc56c0000}, {0xc56c2000}, {0xc56c4000}, {0xc56c6000}, 
+    {0xc56c8000}, {0xc56ca000}, {0xc56cc000}, {0xc56ce000}, 
+    {0xc56d0000}, {0xc56d2000}, {0xc56d4000}, {0xc56d6000}, 
+    {0xc56d8000}, {0xc56da000}, {0xc56dc000}, {0xc56de000}, 
+    {0xc56e0000}, {0xc56e2000}, {0xc56e4000}, {0xc56e6000}, 
+    {0xc56e8000}, {0xc56ea000}, {0xc56ec000}, {0xc56ee000}, 
+    {0xc56f0000}, {0xc56f2000}, {0xc56f4000}, {0xc56f6000}, 
+    {0xc56f8000}, {0xc56fa000}, {0xc56fc000}, {0xc56fe000}, 
+    {0xc5700000}, {0xc5702000}, {0xc5704000}, {0xc5706000}, 
+    {0xc5708000}, {0xc570a000}, {0xc570c000}, {0xc570e000}, 
+    {0xc5710000}, {0xc5712000}, {0xc5714000}, {0xc5716000}, 
+    {0xc5718000}, {0xc571a000}, {0xc571c000}, {0xc571e000}, 
+    {0xc5720000}, {0xc5722000}, {0xc5724000}, {0xc5726000}, 
+    {0xc5728000}, {0xc572a000}, {0xc572c000}, {0xc572e000}, 
+    {0xc5730000}, {0xc5732000}, {0xc5734000}, {0xc5736000}, 
+    {0xc5738000}, {0xc573a000}, {0xc573c000}, {0xc573e000}, 
+    {0xc5740000}, {0xc5742000}, {0xc5744000}, {0xc5746000}, 
+    {0xc5748000}, {0xc574a000}, {0xc574c000}, {0xc574e000}, 
+    {0xc5750000}, {0xc5752000}, {0xc5754000}, {0xc5756000}, 
+    {0xc5758000}, {0xc575a000}, {0xc575c000}, {0xc575e000}, 
+    {0xc5760000}, {0xc5762000}, {0xc5764000}, {0xc5766000}, 
+    {0xc5768000}, {0xc576a000}, {0xc576c000}, {0xc576e000}, 
+    {0xc5770000}, {0xc5772000}, {0xc5774000}, {0xc5776000}, 
+    {0xc5778000}, {0xc577a000}, {0xc577c000}, {0xc577e000}, 
+    {0xc5780000}, {0xc5782000}, {0xc5784000}, {0xc5786000}, 
+    {0xc5788000}, {0xc578a000}, {0xc578c000}, {0xc578e000}, 
+    {0xc5790000}, {0xc5792000}, {0xc5794000}, {0xc5796000}, 
+    {0xc5798000}, {0xc579a000}, {0xc579c000}, {0xc579e000}, 
+    {0xc57a0000}, {0xc57a2000}, {0xc57a4000}, {0xc57a6000}, 
+    {0xc57a8000}, {0xc57aa000}, {0xc57ac000}, {0xc57ae000}, 
+    {0xc57b0000}, {0xc57b2000}, {0xc57b4000}, {0xc57b6000}, 
+    {0xc57b8000}, {0xc57ba000}, {0xc57bc000}, {0xc57be000}, 
+    {0xc57c0000}, {0xc57c2000}, {0xc57c4000}, {0xc57c6000}, 
+    {0xc57c8000}, {0xc57ca000}, {0xc57cc000}, {0xc57ce000}, 
+    {0xc57d0000}, {0xc57d2000}, {0xc57d4000}, {0xc57d6000}, 
+    {0xc57d8000}, {0xc57da000}, {0xc57dc000}, {0xc57de000}, 
+    {0xc57e0000}, {0xc57e2000}, {0xc57e4000}, {0xc57e6000}, 
+    {0xc57e8000}, {0xc57ea000}, {0xc57ec000}, {0xc57ee000}, 
+    {0xc57f0000}, {0xc57f2000}, {0xc57f4000}, {0xc57f6000}, 
+    {0xc57f8000}, {0xc57fa000}, {0xc57fc000}, {0xc57fe000}, 
+    {0xc5800000}, {0xc5802000}, {0xc5804000}, {0xc5806000}, 
+    {0xc5808000}, {0xc580a000}, {0xc580c000}, {0xc580e000}, 
+    {0xc5810000}, {0xc5812000}, {0xc5814000}, {0xc5816000}, 
+    {0xc5818000}, {0xc581a000}, {0xc581c000}, {0xc581e000}, 
+    {0xc5820000}, {0xc5822000}, {0xc5824000}, {0xc5826000}, 
+    {0xc5828000}, {0xc582a000}, {0xc582c000}, {0xc582e000}, 
+    {0xc5830000}, {0xc5832000}, {0xc5834000}, {0xc5836000}, 
+    {0xc5838000}, {0xc583a000}, {0xc583c000}, {0xc583e000}, 
+    {0xc5840000}, {0xc5842000}, {0xc5844000}, {0xc5846000}, 
+    {0xc5848000}, {0xc584a000}, {0xc584c000}, {0xc584e000}, 
+    {0xc5850000}, {0xc5852000}, {0xc5854000}, {0xc5856000}, 
+    {0xc5858000}, {0xc585a000}, {0xc585c000}, {0xc585e000}, 
+    {0xc5860000}, {0xc5862000}, {0xc5864000}, {0xc5866000}, 
+    {0xc5868000}, {0xc586a000}, {0xc586c000}, {0xc586e000}, 
+    {0xc5870000}, {0xc5872000}, {0xc5874000}, {0xc5876000}, 
+    {0xc5878000}, {0xc587a000}, {0xc587c000}, {0xc587e000}, 
+    {0xc5880000}, {0xc5882000}, {0xc5884000}, {0xc5886000}, 
+    {0xc5888000}, {0xc588a000}, {0xc588c000}, {0xc588e000}, 
+    {0xc5890000}, {0xc5892000}, {0xc5894000}, {0xc5896000}, 
+    {0xc5898000}, {0xc589a000}, {0xc589c000}, {0xc589e000}, 
+    {0xc58a0000}, {0xc58a2000}, {0xc58a4000}, {0xc58a6000}, 
+    {0xc58a8000}, {0xc58aa000}, {0xc58ac000}, {0xc58ae000}, 
+    {0xc58b0000}, {0xc58b2000}, {0xc58b4000}, {0xc58b6000}, 
+    {0xc58b8000}, {0xc58ba000}, {0xc58bc000}, {0xc58be000}, 
+    {0xc58c0000}, {0xc58c2000}, {0xc58c4000}, {0xc58c6000}, 
+    {0xc58c8000}, {0xc58ca000}, {0xc58cc000}, {0xc58ce000}, 
+    {0xc58d0000}, {0xc58d2000}, {0xc58d4000}, {0xc58d6000}, 
+    {0xc58d8000}, {0xc58da000}, {0xc58dc000}, {0xc58de000}, 
+    {0xc58e0000}, {0xc58e2000}, {0xc58e4000}, {0xc58e6000}, 
+    {0xc58e8000}, {0xc58ea000}, {0xc58ec000}, {0xc58ee000}, 
+    {0xc58f0000}, {0xc58f2000}, {0xc58f4000}, {0xc58f6000}, 
+    {0xc58f8000}, {0xc58fa000}, {0xc58fc000}, {0xc58fe000}, 
+    {0xc5900000}, {0xc5902000}, {0xc5904000}, {0xc5906000}, 
+    {0xc5908000}, {0xc590a000}, {0xc590c000}, {0xc590e000}, 
+    {0xc5910000}, {0xc5912000}, {0xc5914000}, {0xc5916000}, 
+    {0xc5918000}, {0xc591a000}, {0xc591c000}, {0xc591e000}, 
+    {0xc5920000}, {0xc5922000}, {0xc5924000}, {0xc5926000}, 
+    {0xc5928000}, {0xc592a000}, {0xc592c000}, {0xc592e000}, 
+    {0xc5930000}, {0xc5932000}, {0xc5934000}, {0xc5936000}, 
+    {0xc5938000}, {0xc593a000}, {0xc593c000}, {0xc593e000}, 
+    {0xc5940000}, {0xc5942000}, {0xc5944000}, {0xc5946000}, 
+    {0xc5948000}, {0xc594a000}, {0xc594c000}, {0xc594e000}, 
+    {0xc5950000}, {0xc5952000}, {0xc5954000}, {0xc5956000}, 
+    {0xc5958000}, {0xc595a000}, {0xc595c000}, {0xc595e000}, 
+    {0xc5960000}, {0xc5962000}, {0xc5964000}, {0xc5966000}, 
+    {0xc5968000}, {0xc596a000}, {0xc596c000}, {0xc596e000}, 
+    {0xc5970000}, {0xc5972000}, {0xc5974000}, {0xc5976000}, 
+    {0xc5978000}, {0xc597a000}, {0xc597c000}, {0xc597e000}, 
+    {0xc5980000}, {0xc5982000}, {0xc5984000}, {0xc5986000}, 
+    {0xc5988000}, {0xc598a000}, {0xc598c000}, {0xc598e000}, 
+    {0xc5990000}, {0xc5992000}, {0xc5994000}, {0xc5996000}, 
+    {0xc5998000}, {0xc599a000}, {0xc599c000}, {0xc599e000}, 
+    {0xc59a0000}, {0xc59a2000}, {0xc59a4000}, {0xc59a6000}, 
+    {0xc59a8000}, {0xc59aa000}, {0xc59ac000}, {0xc59ae000}, 
+    {0xc59b0000}, {0xc59b2000}, {0xc59b4000}, {0xc59b6000}, 
+    {0xc59b8000}, {0xc59ba000}, {0xc59bc000}, {0xc59be000}, 
+    {0xc59c0000}, {0xc59c2000}, {0xc59c4000}, {0xc59c6000}, 
+    {0xc59c8000}, {0xc59ca000}, {0xc59cc000}, {0xc59ce000}, 
+    {0xc59d0000}, {0xc59d2000}, {0xc59d4000}, {0xc59d6000}, 
+    {0xc59d8000}, {0xc59da000}, {0xc59dc000}, {0xc59de000}, 
+    {0xc59e0000}, {0xc59e2000}, {0xc59e4000}, {0xc59e6000}, 
+    {0xc59e8000}, {0xc59ea000}, {0xc59ec000}, {0xc59ee000}, 
+    {0xc59f0000}, {0xc59f2000}, {0xc59f4000}, {0xc59f6000}, 
+    {0xc59f8000}, {0xc59fa000}, {0xc59fc000}, {0xc59fe000}, 
+    {0xc5a00000}, {0xc5a02000}, {0xc5a04000}, {0xc5a06000}, 
+    {0xc5a08000}, {0xc5a0a000}, {0xc5a0c000}, {0xc5a0e000}, 
+    {0xc5a10000}, {0xc5a12000}, {0xc5a14000}, {0xc5a16000}, 
+    {0xc5a18000}, {0xc5a1a000}, {0xc5a1c000}, {0xc5a1e000}, 
+    {0xc5a20000}, {0xc5a22000}, {0xc5a24000}, {0xc5a26000}, 
+    {0xc5a28000}, {0xc5a2a000}, {0xc5a2c000}, {0xc5a2e000}, 
+    {0xc5a30000}, {0xc5a32000}, {0xc5a34000}, {0xc5a36000}, 
+    {0xc5a38000}, {0xc5a3a000}, {0xc5a3c000}, {0xc5a3e000}, 
+    {0xc5a40000}, {0xc5a42000}, {0xc5a44000}, {0xc5a46000}, 
+    {0xc5a48000}, {0xc5a4a000}, {0xc5a4c000}, {0xc5a4e000}, 
+    {0xc5a50000}, {0xc5a52000}, {0xc5a54000}, {0xc5a56000}, 
+    {0xc5a58000}, {0xc5a5a000}, {0xc5a5c000}, {0xc5a5e000}, 
+    {0xc5a60000}, {0xc5a62000}, {0xc5a64000}, {0xc5a66000}, 
+    {0xc5a68000}, {0xc5a6a000}, {0xc5a6c000}, {0xc5a6e000}, 
+    {0xc5a70000}, {0xc5a72000}, {0xc5a74000}, {0xc5a76000}, 
+    {0xc5a78000}, {0xc5a7a000}, {0xc5a7c000}, {0xc5a7e000}, 
+    {0xc5a80000}, {0xc5a82000}, {0xc5a84000}, {0xc5a86000}, 
+    {0xc5a88000}, {0xc5a8a000}, {0xc5a8c000}, {0xc5a8e000}, 
+    {0xc5a90000}, {0xc5a92000}, {0xc5a94000}, {0xc5a96000}, 
+    {0xc5a98000}, {0xc5a9a000}, {0xc5a9c000}, {0xc5a9e000}, 
+    {0xc5aa0000}, {0xc5aa2000}, {0xc5aa4000}, {0xc5aa6000}, 
+    {0xc5aa8000}, {0xc5aaa000}, {0xc5aac000}, {0xc5aae000}, 
+    {0xc5ab0000}, {0xc5ab2000}, {0xc5ab4000}, {0xc5ab6000}, 
+    {0xc5ab8000}, {0xc5aba000}, {0xc5abc000}, {0xc5abe000}, 
+    {0xc5ac0000}, {0xc5ac2000}, {0xc5ac4000}, {0xc5ac6000}, 
+    {0xc5ac8000}, {0xc5aca000}, {0xc5acc000}, {0xc5ace000}, 
+    {0xc5ad0000}, {0xc5ad2000}, {0xc5ad4000}, {0xc5ad6000}, 
+    {0xc5ad8000}, {0xc5ada000}, {0xc5adc000}, {0xc5ade000}, 
+    {0xc5ae0000}, {0xc5ae2000}, {0xc5ae4000}, {0xc5ae6000}, 
+    {0xc5ae8000}, {0xc5aea000}, {0xc5aec000}, {0xc5aee000}, 
+    {0xc5af0000}, {0xc5af2000}, {0xc5af4000}, {0xc5af6000}, 
+    {0xc5af8000}, {0xc5afa000}, {0xc5afc000}, {0xc5afe000}, 
+    {0xc5b00000}, {0xc5b02000}, {0xc5b04000}, {0xc5b06000}, 
+    {0xc5b08000}, {0xc5b0a000}, {0xc5b0c000}, {0xc5b0e000}, 
+    {0xc5b10000}, {0xc5b12000}, {0xc5b14000}, {0xc5b16000}, 
+    {0xc5b18000}, {0xc5b1a000}, {0xc5b1c000}, {0xc5b1e000}, 
+    {0xc5b20000}, {0xc5b22000}, {0xc5b24000}, {0xc5b26000}, 
+    {0xc5b28000}, {0xc5b2a000}, {0xc5b2c000}, {0xc5b2e000}, 
+    {0xc5b30000}, {0xc5b32000}, {0xc5b34000}, {0xc5b36000}, 
+    {0xc5b38000}, {0xc5b3a000}, {0xc5b3c000}, {0xc5b3e000}, 
+    {0xc5b40000}, {0xc5b42000}, {0xc5b44000}, {0xc5b46000}, 
+    {0xc5b48000}, {0xc5b4a000}, {0xc5b4c000}, {0xc5b4e000}, 
+    {0xc5b50000}, {0xc5b52000}, {0xc5b54000}, {0xc5b56000}, 
+    {0xc5b58000}, {0xc5b5a000}, {0xc5b5c000}, {0xc5b5e000}, 
+    {0xc5b60000}, {0xc5b62000}, {0xc5b64000}, {0xc5b66000}, 
+    {0xc5b68000}, {0xc5b6a000}, {0xc5b6c000}, {0xc5b6e000}, 
+    {0xc5b70000}, {0xc5b72000}, {0xc5b74000}, {0xc5b76000}, 
+    {0xc5b78000}, {0xc5b7a000}, {0xc5b7c000}, {0xc5b7e000}, 
+    {0xc5b80000}, {0xc5b82000}, {0xc5b84000}, {0xc5b86000}, 
+    {0xc5b88000}, {0xc5b8a000}, {0xc5b8c000}, {0xc5b8e000}, 
+    {0xc5b90000}, {0xc5b92000}, {0xc5b94000}, {0xc5b96000}, 
+    {0xc5b98000}, {0xc5b9a000}, {0xc5b9c000}, {0xc5b9e000}, 
+    {0xc5ba0000}, {0xc5ba2000}, {0xc5ba4000}, {0xc5ba6000}, 
+    {0xc5ba8000}, {0xc5baa000}, {0xc5bac000}, {0xc5bae000}, 
+    {0xc5bb0000}, {0xc5bb2000}, {0xc5bb4000}, {0xc5bb6000}, 
+    {0xc5bb8000}, {0xc5bba000}, {0xc5bbc000}, {0xc5bbe000}, 
+    {0xc5bc0000}, {0xc5bc2000}, {0xc5bc4000}, {0xc5bc6000}, 
+    {0xc5bc8000}, {0xc5bca000}, {0xc5bcc000}, {0xc5bce000}, 
+    {0xc5bd0000}, {0xc5bd2000}, {0xc5bd4000}, {0xc5bd6000}, 
+    {0xc5bd8000}, {0xc5bda000}, {0xc5bdc000}, {0xc5bde000}, 
+    {0xc5be0000}, {0xc5be2000}, {0xc5be4000}, {0xc5be6000}, 
+    {0xc5be8000}, {0xc5bea000}, {0xc5bec000}, {0xc5bee000}, 
+    {0xc5bf0000}, {0xc5bf2000}, {0xc5bf4000}, {0xc5bf6000}, 
+    {0xc5bf8000}, {0xc5bfa000}, {0xc5bfc000}, {0xc5bfe000}, 
+    {0xc5c00000}, {0xc5c02000}, {0xc5c04000}, {0xc5c06000}, 
+    {0xc5c08000}, {0xc5c0a000}, {0xc5c0c000}, {0xc5c0e000}, 
+    {0xc5c10000}, {0xc5c12000}, {0xc5c14000}, {0xc5c16000}, 
+    {0xc5c18000}, {0xc5c1a000}, {0xc5c1c000}, {0xc5c1e000}, 
+    {0xc5c20000}, {0xc5c22000}, {0xc5c24000}, {0xc5c26000}, 
+    {0xc5c28000}, {0xc5c2a000}, {0xc5c2c000}, {0xc5c2e000}, 
+    {0xc5c30000}, {0xc5c32000}, {0xc5c34000}, {0xc5c36000}, 
+    {0xc5c38000}, {0xc5c3a000}, {0xc5c3c000}, {0xc5c3e000}, 
+    {0xc5c40000}, {0xc5c42000}, {0xc5c44000}, {0xc5c46000}, 
+    {0xc5c48000}, {0xc5c4a000}, {0xc5c4c000}, {0xc5c4e000}, 
+    {0xc5c50000}, {0xc5c52000}, {0xc5c54000}, {0xc5c56000}, 
+    {0xc5c58000}, {0xc5c5a000}, {0xc5c5c000}, {0xc5c5e000}, 
+    {0xc5c60000}, {0xc5c62000}, {0xc5c64000}, {0xc5c66000}, 
+    {0xc5c68000}, {0xc5c6a000}, {0xc5c6c000}, {0xc5c6e000}, 
+    {0xc5c70000}, {0xc5c72000}, {0xc5c74000}, {0xc5c76000}, 
+    {0xc5c78000}, {0xc5c7a000}, {0xc5c7c000}, {0xc5c7e000}, 
+    {0xc5c80000}, {0xc5c82000}, {0xc5c84000}, {0xc5c86000}, 
+    {0xc5c88000}, {0xc5c8a000}, {0xc5c8c000}, {0xc5c8e000}, 
+    {0xc5c90000}, {0xc5c92000}, {0xc5c94000}, {0xc5c96000}, 
+    {0xc5c98000}, {0xc5c9a000}, {0xc5c9c000}, {0xc5c9e000}, 
+    {0xc5ca0000}, {0xc5ca2000}, {0xc5ca4000}, {0xc5ca6000}, 
+    {0xc5ca8000}, {0xc5caa000}, {0xc5cac000}, {0xc5cae000}, 
+    {0xc5cb0000}, {0xc5cb2000}, {0xc5cb4000}, {0xc5cb6000}, 
+    {0xc5cb8000}, {0xc5cba000}, {0xc5cbc000}, {0xc5cbe000}, 
+    {0xc5cc0000}, {0xc5cc2000}, {0xc5cc4000}, {0xc5cc6000}, 
+    {0xc5cc8000}, {0xc5cca000}, {0xc5ccc000}, {0xc5cce000}, 
+    {0xc5cd0000}, {0xc5cd2000}, {0xc5cd4000}, {0xc5cd6000}, 
+    {0xc5cd8000}, {0xc5cda000}, {0xc5cdc000}, {0xc5cde000}, 
+    {0xc5ce0000}, {0xc5ce2000}, {0xc5ce4000}, {0xc5ce6000}, 
+    {0xc5ce8000}, {0xc5cea000}, {0xc5cec000}, {0xc5cee000}, 
+    {0xc5cf0000}, {0xc5cf2000}, {0xc5cf4000}, {0xc5cf6000}, 
+    {0xc5cf8000}, {0xc5cfa000}, {0xc5cfc000}, {0xc5cfe000}, 
+    {0xc5d00000}, {0xc5d02000}, {0xc5d04000}, {0xc5d06000}, 
+    {0xc5d08000}, {0xc5d0a000}, {0xc5d0c000}, {0xc5d0e000}, 
+    {0xc5d10000}, {0xc5d12000}, {0xc5d14000}, {0xc5d16000}, 
+    {0xc5d18000}, {0xc5d1a000}, {0xc5d1c000}, {0xc5d1e000}, 
+    {0xc5d20000}, {0xc5d22000}, {0xc5d24000}, {0xc5d26000}, 
+    {0xc5d28000}, {0xc5d2a000}, {0xc5d2c000}, {0xc5d2e000}, 
+    {0xc5d30000}, {0xc5d32000}, {0xc5d34000}, {0xc5d36000}, 
+    {0xc5d38000}, {0xc5d3a000}, {0xc5d3c000}, {0xc5d3e000}, 
+    {0xc5d40000}, {0xc5d42000}, {0xc5d44000}, {0xc5d46000}, 
+    {0xc5d48000}, {0xc5d4a000}, {0xc5d4c000}, {0xc5d4e000}, 
+    {0xc5d50000}, {0xc5d52000}, {0xc5d54000}, {0xc5d56000}, 
+    {0xc5d58000}, {0xc5d5a000}, {0xc5d5c000}, {0xc5d5e000}, 
+    {0xc5d60000}, {0xc5d62000}, {0xc5d64000}, {0xc5d66000}, 
+    {0xc5d68000}, {0xc5d6a000}, {0xc5d6c000}, {0xc5d6e000}, 
+    {0xc5d70000}, {0xc5d72000}, {0xc5d74000}, {0xc5d76000}, 
+    {0xc5d78000}, {0xc5d7a000}, {0xc5d7c000}, {0xc5d7e000}, 
+    {0xc5d80000}, {0xc5d82000}, {0xc5d84000}, {0xc5d86000}, 
+    {0xc5d88000}, {0xc5d8a000}, {0xc5d8c000}, {0xc5d8e000}, 
+    {0xc5d90000}, {0xc5d92000}, {0xc5d94000}, {0xc5d96000}, 
+    {0xc5d98000}, {0xc5d9a000}, {0xc5d9c000}, {0xc5d9e000}, 
+    {0xc5da0000}, {0xc5da2000}, {0xc5da4000}, {0xc5da6000}, 
+    {0xc5da8000}, {0xc5daa000}, {0xc5dac000}, {0xc5dae000}, 
+    {0xc5db0000}, {0xc5db2000}, {0xc5db4000}, {0xc5db6000}, 
+    {0xc5db8000}, {0xc5dba000}, {0xc5dbc000}, {0xc5dbe000}, 
+    {0xc5dc0000}, {0xc5dc2000}, {0xc5dc4000}, {0xc5dc6000}, 
+    {0xc5dc8000}, {0xc5dca000}, {0xc5dcc000}, {0xc5dce000}, 
+    {0xc5dd0000}, {0xc5dd2000}, {0xc5dd4000}, {0xc5dd6000}, 
+    {0xc5dd8000}, {0xc5dda000}, {0xc5ddc000}, {0xc5dde000}, 
+    {0xc5de0000}, {0xc5de2000}, {0xc5de4000}, {0xc5de6000}, 
+    {0xc5de8000}, {0xc5dea000}, {0xc5dec000}, {0xc5dee000}, 
+    {0xc5df0000}, {0xc5df2000}, {0xc5df4000}, {0xc5df6000}, 
+    {0xc5df8000}, {0xc5dfa000}, {0xc5dfc000}, {0xc5dfe000}, 
+    {0xc5e00000}, {0xc5e02000}, {0xc5e04000}, {0xc5e06000}, 
+    {0xc5e08000}, {0xc5e0a000}, {0xc5e0c000}, {0xc5e0e000}, 
+    {0xc5e10000}, {0xc5e12000}, {0xc5e14000}, {0xc5e16000}, 
+    {0xc5e18000}, {0xc5e1a000}, {0xc5e1c000}, {0xc5e1e000}, 
+    {0xc5e20000}, {0xc5e22000}, {0xc5e24000}, {0xc5e26000}, 
+    {0xc5e28000}, {0xc5e2a000}, {0xc5e2c000}, {0xc5e2e000}, 
+    {0xc5e30000}, {0xc5e32000}, {0xc5e34000}, {0xc5e36000}, 
+    {0xc5e38000}, {0xc5e3a000}, {0xc5e3c000}, {0xc5e3e000}, 
+    {0xc5e40000}, {0xc5e42000}, {0xc5e44000}, {0xc5e46000}, 
+    {0xc5e48000}, {0xc5e4a000}, {0xc5e4c000}, {0xc5e4e000}, 
+    {0xc5e50000}, {0xc5e52000}, {0xc5e54000}, {0xc5e56000}, 
+    {0xc5e58000}, {0xc5e5a000}, {0xc5e5c000}, {0xc5e5e000}, 
+    {0xc5e60000}, {0xc5e62000}, {0xc5e64000}, {0xc5e66000}, 
+    {0xc5e68000}, {0xc5e6a000}, {0xc5e6c000}, {0xc5e6e000}, 
+    {0xc5e70000}, {0xc5e72000}, {0xc5e74000}, {0xc5e76000}, 
+    {0xc5e78000}, {0xc5e7a000}, {0xc5e7c000}, {0xc5e7e000}, 
+    {0xc5e80000}, {0xc5e82000}, {0xc5e84000}, {0xc5e86000}, 
+    {0xc5e88000}, {0xc5e8a000}, {0xc5e8c000}, {0xc5e8e000}, 
+    {0xc5e90000}, {0xc5e92000}, {0xc5e94000}, {0xc5e96000}, 
+    {0xc5e98000}, {0xc5e9a000}, {0xc5e9c000}, {0xc5e9e000}, 
+    {0xc5ea0000}, {0xc5ea2000}, {0xc5ea4000}, {0xc5ea6000}, 
+    {0xc5ea8000}, {0xc5eaa000}, {0xc5eac000}, {0xc5eae000}, 
+    {0xc5eb0000}, {0xc5eb2000}, {0xc5eb4000}, {0xc5eb6000}, 
+    {0xc5eb8000}, {0xc5eba000}, {0xc5ebc000}, {0xc5ebe000}, 
+    {0xc5ec0000}, {0xc5ec2000}, {0xc5ec4000}, {0xc5ec6000}, 
+    {0xc5ec8000}, {0xc5eca000}, {0xc5ecc000}, {0xc5ece000}, 
+    {0xc5ed0000}, {0xc5ed2000}, {0xc5ed4000}, {0xc5ed6000}, 
+    {0xc5ed8000}, {0xc5eda000}, {0xc5edc000}, {0xc5ede000}, 
+    {0xc5ee0000}, {0xc5ee2000}, {0xc5ee4000}, {0xc5ee6000}, 
+    {0xc5ee8000}, {0xc5eea000}, {0xc5eec000}, {0xc5eee000}, 
+    {0xc5ef0000}, {0xc5ef2000}, {0xc5ef4000}, {0xc5ef6000}, 
+    {0xc5ef8000}, {0xc5efa000}, {0xc5efc000}, {0xc5efe000}, 
+    {0xc5f00000}, {0xc5f02000}, {0xc5f04000}, {0xc5f06000}, 
+    {0xc5f08000}, {0xc5f0a000}, {0xc5f0c000}, {0xc5f0e000}, 
+    {0xc5f10000}, {0xc5f12000}, {0xc5f14000}, {0xc5f16000}, 
+    {0xc5f18000}, {0xc5f1a000}, {0xc5f1c000}, {0xc5f1e000}, 
+    {0xc5f20000}, {0xc5f22000}, {0xc5f24000}, {0xc5f26000}, 
+    {0xc5f28000}, {0xc5f2a000}, {0xc5f2c000}, {0xc5f2e000}, 
+    {0xc5f30000}, {0xc5f32000}, {0xc5f34000}, {0xc5f36000}, 
+    {0xc5f38000}, {0xc5f3a000}, {0xc5f3c000}, {0xc5f3e000}, 
+    {0xc5f40000}, {0xc5f42000}, {0xc5f44000}, {0xc5f46000}, 
+    {0xc5f48000}, {0xc5f4a000}, {0xc5f4c000}, {0xc5f4e000}, 
+    {0xc5f50000}, {0xc5f52000}, {0xc5f54000}, {0xc5f56000}, 
+    {0xc5f58000}, {0xc5f5a000}, {0xc5f5c000}, {0xc5f5e000}, 
+    {0xc5f60000}, {0xc5f62000}, {0xc5f64000}, {0xc5f66000}, 
+    {0xc5f68000}, {0xc5f6a000}, {0xc5f6c000}, {0xc5f6e000}, 
+    {0xc5f70000}, {0xc5f72000}, {0xc5f74000}, {0xc5f76000}, 
+    {0xc5f78000}, {0xc5f7a000}, {0xc5f7c000}, {0xc5f7e000}, 
+    {0xc5f80000}, {0xc5f82000}, {0xc5f84000}, {0xc5f86000}, 
+    {0xc5f88000}, {0xc5f8a000}, {0xc5f8c000}, {0xc5f8e000}, 
+    {0xc5f90000}, {0xc5f92000}, {0xc5f94000}, {0xc5f96000}, 
+    {0xc5f98000}, {0xc5f9a000}, {0xc5f9c000}, {0xc5f9e000}, 
+    {0xc5fa0000}, {0xc5fa2000}, {0xc5fa4000}, {0xc5fa6000}, 
+    {0xc5fa8000}, {0xc5faa000}, {0xc5fac000}, {0xc5fae000}, 
+    {0xc5fb0000}, {0xc5fb2000}, {0xc5fb4000}, {0xc5fb6000}, 
+    {0xc5fb8000}, {0xc5fba000}, {0xc5fbc000}, {0xc5fbe000}, 
+    {0xc5fc0000}, {0xc5fc2000}, {0xc5fc4000}, {0xc5fc6000}, 
+    {0xc5fc8000}, {0xc5fca000}, {0xc5fcc000}, {0xc5fce000}, 
+    {0xc5fd0000}, {0xc5fd2000}, {0xc5fd4000}, {0xc5fd6000}, 
+    {0xc5fd8000}, {0xc5fda000}, {0xc5fdc000}, {0xc5fde000}, 
+    {0xc5fe0000}, {0xc5fe2000}, {0xc5fe4000}, {0xc5fe6000}, 
+    {0xc5fe8000}, {0xc5fea000}, {0xc5fec000}, {0xc5fee000}, 
+    {0xc5ff0000}, {0xc5ff2000}, {0xc5ff4000}, {0xc5ff6000}, 
+    {0xc5ff8000}, {0xc5ffa000}, {0xc5ffc000}, {0xc5ffe000}, 
+    {0xc6000000}, {0xc6002000}, {0xc6004000}, {0xc6006000}, 
+    {0xc6008000}, {0xc600a000}, {0xc600c000}, {0xc600e000}, 
+    {0xc6010000}, {0xc6012000}, {0xc6014000}, {0xc6016000}, 
+    {0xc6018000}, {0xc601a000}, {0xc601c000}, {0xc601e000}, 
+    {0xc6020000}, {0xc6022000}, {0xc6024000}, {0xc6026000}, 
+    {0xc6028000}, {0xc602a000}, {0xc602c000}, {0xc602e000}, 
+    {0xc6030000}, {0xc6032000}, {0xc6034000}, {0xc6036000}, 
+    {0xc6038000}, {0xc603a000}, {0xc603c000}, {0xc603e000}, 
+    {0xc6040000}, {0xc6042000}, {0xc6044000}, {0xc6046000}, 
+    {0xc6048000}, {0xc604a000}, {0xc604c000}, {0xc604e000}, 
+    {0xc6050000}, {0xc6052000}, {0xc6054000}, {0xc6056000}, 
+    {0xc6058000}, {0xc605a000}, {0xc605c000}, {0xc605e000}, 
+    {0xc6060000}, {0xc6062000}, {0xc6064000}, {0xc6066000}, 
+    {0xc6068000}, {0xc606a000}, {0xc606c000}, {0xc606e000}, 
+    {0xc6070000}, {0xc6072000}, {0xc6074000}, {0xc6076000}, 
+    {0xc6078000}, {0xc607a000}, {0xc607c000}, {0xc607e000}, 
+    {0xc6080000}, {0xc6082000}, {0xc6084000}, {0xc6086000}, 
+    {0xc6088000}, {0xc608a000}, {0xc608c000}, {0xc608e000}, 
+    {0xc6090000}, {0xc6092000}, {0xc6094000}, {0xc6096000}, 
+    {0xc6098000}, {0xc609a000}, {0xc609c000}, {0xc609e000}, 
+    {0xc60a0000}, {0xc60a2000}, {0xc60a4000}, {0xc60a6000}, 
+    {0xc60a8000}, {0xc60aa000}, {0xc60ac000}, {0xc60ae000}, 
+    {0xc60b0000}, {0xc60b2000}, {0xc60b4000}, {0xc60b6000}, 
+    {0xc60b8000}, {0xc60ba000}, {0xc60bc000}, {0xc60be000}, 
+    {0xc60c0000}, {0xc60c2000}, {0xc60c4000}, {0xc60c6000}, 
+    {0xc60c8000}, {0xc60ca000}, {0xc60cc000}, {0xc60ce000}, 
+    {0xc60d0000}, {0xc60d2000}, {0xc60d4000}, {0xc60d6000}, 
+    {0xc60d8000}, {0xc60da000}, {0xc60dc000}, {0xc60de000}, 
+    {0xc60e0000}, {0xc60e2000}, {0xc60e4000}, {0xc60e6000}, 
+    {0xc60e8000}, {0xc60ea000}, {0xc60ec000}, {0xc60ee000}, 
+    {0xc60f0000}, {0xc60f2000}, {0xc60f4000}, {0xc60f6000}, 
+    {0xc60f8000}, {0xc60fa000}, {0xc60fc000}, {0xc60fe000}, 
+    {0xc6100000}, {0xc6102000}, {0xc6104000}, {0xc6106000}, 
+    {0xc6108000}, {0xc610a000}, {0xc610c000}, {0xc610e000}, 
+    {0xc6110000}, {0xc6112000}, {0xc6114000}, {0xc6116000}, 
+    {0xc6118000}, {0xc611a000}, {0xc611c000}, {0xc611e000}, 
+    {0xc6120000}, {0xc6122000}, {0xc6124000}, {0xc6126000}, 
+    {0xc6128000}, {0xc612a000}, {0xc612c000}, {0xc612e000}, 
+    {0xc6130000}, {0xc6132000}, {0xc6134000}, {0xc6136000}, 
+    {0xc6138000}, {0xc613a000}, {0xc613c000}, {0xc613e000}, 
+    {0xc6140000}, {0xc6142000}, {0xc6144000}, {0xc6146000}, 
+    {0xc6148000}, {0xc614a000}, {0xc614c000}, {0xc614e000}, 
+    {0xc6150000}, {0xc6152000}, {0xc6154000}, {0xc6156000}, 
+    {0xc6158000}, {0xc615a000}, {0xc615c000}, {0xc615e000}, 
+    {0xc6160000}, {0xc6162000}, {0xc6164000}, {0xc6166000}, 
+    {0xc6168000}, {0xc616a000}, {0xc616c000}, {0xc616e000}, 
+    {0xc6170000}, {0xc6172000}, {0xc6174000}, {0xc6176000}, 
+    {0xc6178000}, {0xc617a000}, {0xc617c000}, {0xc617e000}, 
+    {0xc6180000}, {0xc6182000}, {0xc6184000}, {0xc6186000}, 
+    {0xc6188000}, {0xc618a000}, {0xc618c000}, {0xc618e000}, 
+    {0xc6190000}, {0xc6192000}, {0xc6194000}, {0xc6196000}, 
+    {0xc6198000}, {0xc619a000}, {0xc619c000}, {0xc619e000}, 
+    {0xc61a0000}, {0xc61a2000}, {0xc61a4000}, {0xc61a6000}, 
+    {0xc61a8000}, {0xc61aa000}, {0xc61ac000}, {0xc61ae000}, 
+    {0xc61b0000}, {0xc61b2000}, {0xc61b4000}, {0xc61b6000}, 
+    {0xc61b8000}, {0xc61ba000}, {0xc61bc000}, {0xc61be000}, 
+    {0xc61c0000}, {0xc61c2000}, {0xc61c4000}, {0xc61c6000}, 
+    {0xc61c8000}, {0xc61ca000}, {0xc61cc000}, {0xc61ce000}, 
+    {0xc61d0000}, {0xc61d2000}, {0xc61d4000}, {0xc61d6000}, 
+    {0xc61d8000}, {0xc61da000}, {0xc61dc000}, {0xc61de000}, 
+    {0xc61e0000}, {0xc61e2000}, {0xc61e4000}, {0xc61e6000}, 
+    {0xc61e8000}, {0xc61ea000}, {0xc61ec000}, {0xc61ee000}, 
+    {0xc61f0000}, {0xc61f2000}, {0xc61f4000}, {0xc61f6000}, 
+    {0xc61f8000}, {0xc61fa000}, {0xc61fc000}, {0xc61fe000}, 
+    {0xc6200000}, {0xc6202000}, {0xc6204000}, {0xc6206000}, 
+    {0xc6208000}, {0xc620a000}, {0xc620c000}, {0xc620e000}, 
+    {0xc6210000}, {0xc6212000}, {0xc6214000}, {0xc6216000}, 
+    {0xc6218000}, {0xc621a000}, {0xc621c000}, {0xc621e000}, 
+    {0xc6220000}, {0xc6222000}, {0xc6224000}, {0xc6226000}, 
+    {0xc6228000}, {0xc622a000}, {0xc622c000}, {0xc622e000}, 
+    {0xc6230000}, {0xc6232000}, {0xc6234000}, {0xc6236000}, 
+    {0xc6238000}, {0xc623a000}, {0xc623c000}, {0xc623e000}, 
+    {0xc6240000}, {0xc6242000}, {0xc6244000}, {0xc6246000}, 
+    {0xc6248000}, {0xc624a000}, {0xc624c000}, {0xc624e000}, 
+    {0xc6250000}, {0xc6252000}, {0xc6254000}, {0xc6256000}, 
+    {0xc6258000}, {0xc625a000}, {0xc625c000}, {0xc625e000}, 
+    {0xc6260000}, {0xc6262000}, {0xc6264000}, {0xc6266000}, 
+    {0xc6268000}, {0xc626a000}, {0xc626c000}, {0xc626e000}, 
+    {0xc6270000}, {0xc6272000}, {0xc6274000}, {0xc6276000}, 
+    {0xc6278000}, {0xc627a000}, {0xc627c000}, {0xc627e000}, 
+    {0xc6280000}, {0xc6282000}, {0xc6284000}, {0xc6286000}, 
+    {0xc6288000}, {0xc628a000}, {0xc628c000}, {0xc628e000}, 
+    {0xc6290000}, {0xc6292000}, {0xc6294000}, {0xc6296000}, 
+    {0xc6298000}, {0xc629a000}, {0xc629c000}, {0xc629e000}, 
+    {0xc62a0000}, {0xc62a2000}, {0xc62a4000}, {0xc62a6000}, 
+    {0xc62a8000}, {0xc62aa000}, {0xc62ac000}, {0xc62ae000}, 
+    {0xc62b0000}, {0xc62b2000}, {0xc62b4000}, {0xc62b6000}, 
+    {0xc62b8000}, {0xc62ba000}, {0xc62bc000}, {0xc62be000}, 
+    {0xc62c0000}, {0xc62c2000}, {0xc62c4000}, {0xc62c6000}, 
+    {0xc62c8000}, {0xc62ca000}, {0xc62cc000}, {0xc62ce000}, 
+    {0xc62d0000}, {0xc62d2000}, {0xc62d4000}, {0xc62d6000}, 
+    {0xc62d8000}, {0xc62da000}, {0xc62dc000}, {0xc62de000}, 
+    {0xc62e0000}, {0xc62e2000}, {0xc62e4000}, {0xc62e6000}, 
+    {0xc62e8000}, {0xc62ea000}, {0xc62ec000}, {0xc62ee000}, 
+    {0xc62f0000}, {0xc62f2000}, {0xc62f4000}, {0xc62f6000}, 
+    {0xc62f8000}, {0xc62fa000}, {0xc62fc000}, {0xc62fe000}, 
+    {0xc6300000}, {0xc6302000}, {0xc6304000}, {0xc6306000}, 
+    {0xc6308000}, {0xc630a000}, {0xc630c000}, {0xc630e000}, 
+    {0xc6310000}, {0xc6312000}, {0xc6314000}, {0xc6316000}, 
+    {0xc6318000}, {0xc631a000}, {0xc631c000}, {0xc631e000}, 
+    {0xc6320000}, {0xc6322000}, {0xc6324000}, {0xc6326000}, 
+    {0xc6328000}, {0xc632a000}, {0xc632c000}, {0xc632e000}, 
+    {0xc6330000}, {0xc6332000}, {0xc6334000}, {0xc6336000}, 
+    {0xc6338000}, {0xc633a000}, {0xc633c000}, {0xc633e000}, 
+    {0xc6340000}, {0xc6342000}, {0xc6344000}, {0xc6346000}, 
+    {0xc6348000}, {0xc634a000}, {0xc634c000}, {0xc634e000}, 
+    {0xc6350000}, {0xc6352000}, {0xc6354000}, {0xc6356000}, 
+    {0xc6358000}, {0xc635a000}, {0xc635c000}, {0xc635e000}, 
+    {0xc6360000}, {0xc6362000}, {0xc6364000}, {0xc6366000}, 
+    {0xc6368000}, {0xc636a000}, {0xc636c000}, {0xc636e000}, 
+    {0xc6370000}, {0xc6372000}, {0xc6374000}, {0xc6376000}, 
+    {0xc6378000}, {0xc637a000}, {0xc637c000}, {0xc637e000}, 
+    {0xc6380000}, {0xc6382000}, {0xc6384000}, {0xc6386000}, 
+    {0xc6388000}, {0xc638a000}, {0xc638c000}, {0xc638e000}, 
+    {0xc6390000}, {0xc6392000}, {0xc6394000}, {0xc6396000}, 
+    {0xc6398000}, {0xc639a000}, {0xc639c000}, {0xc639e000}, 
+    {0xc63a0000}, {0xc63a2000}, {0xc63a4000}, {0xc63a6000}, 
+    {0xc63a8000}, {0xc63aa000}, {0xc63ac000}, {0xc63ae000}, 
+    {0xc63b0000}, {0xc63b2000}, {0xc63b4000}, {0xc63b6000}, 
+    {0xc63b8000}, {0xc63ba000}, {0xc63bc000}, {0xc63be000}, 
+    {0xc63c0000}, {0xc63c2000}, {0xc63c4000}, {0xc63c6000}, 
+    {0xc63c8000}, {0xc63ca000}, {0xc63cc000}, {0xc63ce000}, 
+    {0xc63d0000}, {0xc63d2000}, {0xc63d4000}, {0xc63d6000}, 
+    {0xc63d8000}, {0xc63da000}, {0xc63dc000}, {0xc63de000}, 
+    {0xc63e0000}, {0xc63e2000}, {0xc63e4000}, {0xc63e6000}, 
+    {0xc63e8000}, {0xc63ea000}, {0xc63ec000}, {0xc63ee000}, 
+    {0xc63f0000}, {0xc63f2000}, {0xc63f4000}, {0xc63f6000}, 
+    {0xc63f8000}, {0xc63fa000}, {0xc63fc000}, {0xc63fe000}, 
+    {0xc6400000}, {0xc6402000}, {0xc6404000}, {0xc6406000}, 
+    {0xc6408000}, {0xc640a000}, {0xc640c000}, {0xc640e000}, 
+    {0xc6410000}, {0xc6412000}, {0xc6414000}, {0xc6416000}, 
+    {0xc6418000}, {0xc641a000}, {0xc641c000}, {0xc641e000}, 
+    {0xc6420000}, {0xc6422000}, {0xc6424000}, {0xc6426000}, 
+    {0xc6428000}, {0xc642a000}, {0xc642c000}, {0xc642e000}, 
+    {0xc6430000}, {0xc6432000}, {0xc6434000}, {0xc6436000}, 
+    {0xc6438000}, {0xc643a000}, {0xc643c000}, {0xc643e000}, 
+    {0xc6440000}, {0xc6442000}, {0xc6444000}, {0xc6446000}, 
+    {0xc6448000}, {0xc644a000}, {0xc644c000}, {0xc644e000}, 
+    {0xc6450000}, {0xc6452000}, {0xc6454000}, {0xc6456000}, 
+    {0xc6458000}, {0xc645a000}, {0xc645c000}, {0xc645e000}, 
+    {0xc6460000}, {0xc6462000}, {0xc6464000}, {0xc6466000}, 
+    {0xc6468000}, {0xc646a000}, {0xc646c000}, {0xc646e000}, 
+    {0xc6470000}, {0xc6472000}, {0xc6474000}, {0xc6476000}, 
+    {0xc6478000}, {0xc647a000}, {0xc647c000}, {0xc647e000}, 
+    {0xc6480000}, {0xc6482000}, {0xc6484000}, {0xc6486000}, 
+    {0xc6488000}, {0xc648a000}, {0xc648c000}, {0xc648e000}, 
+    {0xc6490000}, {0xc6492000}, {0xc6494000}, {0xc6496000}, 
+    {0xc6498000}, {0xc649a000}, {0xc649c000}, {0xc649e000}, 
+    {0xc64a0000}, {0xc64a2000}, {0xc64a4000}, {0xc64a6000}, 
+    {0xc64a8000}, {0xc64aa000}, {0xc64ac000}, {0xc64ae000}, 
+    {0xc64b0000}, {0xc64b2000}, {0xc64b4000}, {0xc64b6000}, 
+    {0xc64b8000}, {0xc64ba000}, {0xc64bc000}, {0xc64be000}, 
+    {0xc64c0000}, {0xc64c2000}, {0xc64c4000}, {0xc64c6000}, 
+    {0xc64c8000}, {0xc64ca000}, {0xc64cc000}, {0xc64ce000}, 
+    {0xc64d0000}, {0xc64d2000}, {0xc64d4000}, {0xc64d6000}, 
+    {0xc64d8000}, {0xc64da000}, {0xc64dc000}, {0xc64de000}, 
+    {0xc64e0000}, {0xc64e2000}, {0xc64e4000}, {0xc64e6000}, 
+    {0xc64e8000}, {0xc64ea000}, {0xc64ec000}, {0xc64ee000}, 
+    {0xc64f0000}, {0xc64f2000}, {0xc64f4000}, {0xc64f6000}, 
+    {0xc64f8000}, {0xc64fa000}, {0xc64fc000}, {0xc64fe000}, 
+    {0xc6500000}, {0xc6502000}, {0xc6504000}, {0xc6506000}, 
+    {0xc6508000}, {0xc650a000}, {0xc650c000}, {0xc650e000}, 
+    {0xc6510000}, {0xc6512000}, {0xc6514000}, {0xc6516000}, 
+    {0xc6518000}, {0xc651a000}, {0xc651c000}, {0xc651e000}, 
+    {0xc6520000}, {0xc6522000}, {0xc6524000}, {0xc6526000}, 
+    {0xc6528000}, {0xc652a000}, {0xc652c000}, {0xc652e000}, 
+    {0xc6530000}, {0xc6532000}, {0xc6534000}, {0xc6536000}, 
+    {0xc6538000}, {0xc653a000}, {0xc653c000}, {0xc653e000}, 
+    {0xc6540000}, {0xc6542000}, {0xc6544000}, {0xc6546000}, 
+    {0xc6548000}, {0xc654a000}, {0xc654c000}, {0xc654e000}, 
+    {0xc6550000}, {0xc6552000}, {0xc6554000}, {0xc6556000}, 
+    {0xc6558000}, {0xc655a000}, {0xc655c000}, {0xc655e000}, 
+    {0xc6560000}, {0xc6562000}, {0xc6564000}, {0xc6566000}, 
+    {0xc6568000}, {0xc656a000}, {0xc656c000}, {0xc656e000}, 
+    {0xc6570000}, {0xc6572000}, {0xc6574000}, {0xc6576000}, 
+    {0xc6578000}, {0xc657a000}, {0xc657c000}, {0xc657e000}, 
+    {0xc6580000}, {0xc6582000}, {0xc6584000}, {0xc6586000}, 
+    {0xc6588000}, {0xc658a000}, {0xc658c000}, {0xc658e000}, 
+    {0xc6590000}, {0xc6592000}, {0xc6594000}, {0xc6596000}, 
+    {0xc6598000}, {0xc659a000}, {0xc659c000}, {0xc659e000}, 
+    {0xc65a0000}, {0xc65a2000}, {0xc65a4000}, {0xc65a6000}, 
+    {0xc65a8000}, {0xc65aa000}, {0xc65ac000}, {0xc65ae000}, 
+    {0xc65b0000}, {0xc65b2000}, {0xc65b4000}, {0xc65b6000}, 
+    {0xc65b8000}, {0xc65ba000}, {0xc65bc000}, {0xc65be000}, 
+    {0xc65c0000}, {0xc65c2000}, {0xc65c4000}, {0xc65c6000}, 
+    {0xc65c8000}, {0xc65ca000}, {0xc65cc000}, {0xc65ce000}, 
+    {0xc65d0000}, {0xc65d2000}, {0xc65d4000}, {0xc65d6000}, 
+    {0xc65d8000}, {0xc65da000}, {0xc65dc000}, {0xc65de000}, 
+    {0xc65e0000}, {0xc65e2000}, {0xc65e4000}, {0xc65e6000}, 
+    {0xc65e8000}, {0xc65ea000}, {0xc65ec000}, {0xc65ee000}, 
+    {0xc65f0000}, {0xc65f2000}, {0xc65f4000}, {0xc65f6000}, 
+    {0xc65f8000}, {0xc65fa000}, {0xc65fc000}, {0xc65fe000}, 
+    {0xc6600000}, {0xc6602000}, {0xc6604000}, {0xc6606000}, 
+    {0xc6608000}, {0xc660a000}, {0xc660c000}, {0xc660e000}, 
+    {0xc6610000}, {0xc6612000}, {0xc6614000}, {0xc6616000}, 
+    {0xc6618000}, {0xc661a000}, {0xc661c000}, {0xc661e000}, 
+    {0xc6620000}, {0xc6622000}, {0xc6624000}, {0xc6626000}, 
+    {0xc6628000}, {0xc662a000}, {0xc662c000}, {0xc662e000}, 
+    {0xc6630000}, {0xc6632000}, {0xc6634000}, {0xc6636000}, 
+    {0xc6638000}, {0xc663a000}, {0xc663c000}, {0xc663e000}, 
+    {0xc6640000}, {0xc6642000}, {0xc6644000}, {0xc6646000}, 
+    {0xc6648000}, {0xc664a000}, {0xc664c000}, {0xc664e000}, 
+    {0xc6650000}, {0xc6652000}, {0xc6654000}, {0xc6656000}, 
+    {0xc6658000}, {0xc665a000}, {0xc665c000}, {0xc665e000}, 
+    {0xc6660000}, {0xc6662000}, {0xc6664000}, {0xc6666000}, 
+    {0xc6668000}, {0xc666a000}, {0xc666c000}, {0xc666e000}, 
+    {0xc6670000}, {0xc6672000}, {0xc6674000}, {0xc6676000}, 
+    {0xc6678000}, {0xc667a000}, {0xc667c000}, {0xc667e000}, 
+    {0xc6680000}, {0xc6682000}, {0xc6684000}, {0xc6686000}, 
+    {0xc6688000}, {0xc668a000}, {0xc668c000}, {0xc668e000}, 
+    {0xc6690000}, {0xc6692000}, {0xc6694000}, {0xc6696000}, 
+    {0xc6698000}, {0xc669a000}, {0xc669c000}, {0xc669e000}, 
+    {0xc66a0000}, {0xc66a2000}, {0xc66a4000}, {0xc66a6000}, 
+    {0xc66a8000}, {0xc66aa000}, {0xc66ac000}, {0xc66ae000}, 
+    {0xc66b0000}, {0xc66b2000}, {0xc66b4000}, {0xc66b6000}, 
+    {0xc66b8000}, {0xc66ba000}, {0xc66bc000}, {0xc66be000}, 
+    {0xc66c0000}, {0xc66c2000}, {0xc66c4000}, {0xc66c6000}, 
+    {0xc66c8000}, {0xc66ca000}, {0xc66cc000}, {0xc66ce000}, 
+    {0xc66d0000}, {0xc66d2000}, {0xc66d4000}, {0xc66d6000}, 
+    {0xc66d8000}, {0xc66da000}, {0xc66dc000}, {0xc66de000}, 
+    {0xc66e0000}, {0xc66e2000}, {0xc66e4000}, {0xc66e6000}, 
+    {0xc66e8000}, {0xc66ea000}, {0xc66ec000}, {0xc66ee000}, 
+    {0xc66f0000}, {0xc66f2000}, {0xc66f4000}, {0xc66f6000}, 
+    {0xc66f8000}, {0xc66fa000}, {0xc66fc000}, {0xc66fe000}, 
+    {0xc6700000}, {0xc6702000}, {0xc6704000}, {0xc6706000}, 
+    {0xc6708000}, {0xc670a000}, {0xc670c000}, {0xc670e000}, 
+    {0xc6710000}, {0xc6712000}, {0xc6714000}, {0xc6716000}, 
+    {0xc6718000}, {0xc671a000}, {0xc671c000}, {0xc671e000}, 
+    {0xc6720000}, {0xc6722000}, {0xc6724000}, {0xc6726000}, 
+    {0xc6728000}, {0xc672a000}, {0xc672c000}, {0xc672e000}, 
+    {0xc6730000}, {0xc6732000}, {0xc6734000}, {0xc6736000}, 
+    {0xc6738000}, {0xc673a000}, {0xc673c000}, {0xc673e000}, 
+    {0xc6740000}, {0xc6742000}, {0xc6744000}, {0xc6746000}, 
+    {0xc6748000}, {0xc674a000}, {0xc674c000}, {0xc674e000}, 
+    {0xc6750000}, {0xc6752000}, {0xc6754000}, {0xc6756000}, 
+    {0xc6758000}, {0xc675a000}, {0xc675c000}, {0xc675e000}, 
+    {0xc6760000}, {0xc6762000}, {0xc6764000}, {0xc6766000}, 
+    {0xc6768000}, {0xc676a000}, {0xc676c000}, {0xc676e000}, 
+    {0xc6770000}, {0xc6772000}, {0xc6774000}, {0xc6776000}, 
+    {0xc6778000}, {0xc677a000}, {0xc677c000}, {0xc677e000}, 
+    {0xc6780000}, {0xc6782000}, {0xc6784000}, {0xc6786000}, 
+    {0xc6788000}, {0xc678a000}, {0xc678c000}, {0xc678e000}, 
+    {0xc6790000}, {0xc6792000}, {0xc6794000}, {0xc6796000}, 
+    {0xc6798000}, {0xc679a000}, {0xc679c000}, {0xc679e000}, 
+    {0xc67a0000}, {0xc67a2000}, {0xc67a4000}, {0xc67a6000}, 
+    {0xc67a8000}, {0xc67aa000}, {0xc67ac000}, {0xc67ae000}, 
+    {0xc67b0000}, {0xc67b2000}, {0xc67b4000}, {0xc67b6000}, 
+    {0xc67b8000}, {0xc67ba000}, {0xc67bc000}, {0xc67be000}, 
+    {0xc67c0000}, {0xc67c2000}, {0xc67c4000}, {0xc67c6000}, 
+    {0xc67c8000}, {0xc67ca000}, {0xc67cc000}, {0xc67ce000}, 
+    {0xc67d0000}, {0xc67d2000}, {0xc67d4000}, {0xc67d6000}, 
+    {0xc67d8000}, {0xc67da000}, {0xc67dc000}, {0xc67de000}, 
+    {0xc67e0000}, {0xc67e2000}, {0xc67e4000}, {0xc67e6000}, 
+    {0xc67e8000}, {0xc67ea000}, {0xc67ec000}, {0xc67ee000}, 
+    {0xc67f0000}, {0xc67f2000}, {0xc67f4000}, {0xc67f6000}, 
+    {0xc67f8000}, {0xc67fa000}, {0xc67fc000}, {0xc67fe000}, 
+    {0xc6800000}, {0xc6802000}, {0xc6804000}, {0xc6806000}, 
+    {0xc6808000}, {0xc680a000}, {0xc680c000}, {0xc680e000}, 
+    {0xc6810000}, {0xc6812000}, {0xc6814000}, {0xc6816000}, 
+    {0xc6818000}, {0xc681a000}, {0xc681c000}, {0xc681e000}, 
+    {0xc6820000}, {0xc6822000}, {0xc6824000}, {0xc6826000}, 
+    {0xc6828000}, {0xc682a000}, {0xc682c000}, {0xc682e000}, 
+    {0xc6830000}, {0xc6832000}, {0xc6834000}, {0xc6836000}, 
+    {0xc6838000}, {0xc683a000}, {0xc683c000}, {0xc683e000}, 
+    {0xc6840000}, {0xc6842000}, {0xc6844000}, {0xc6846000}, 
+    {0xc6848000}, {0xc684a000}, {0xc684c000}, {0xc684e000}, 
+    {0xc6850000}, {0xc6852000}, {0xc6854000}, {0xc6856000}, 
+    {0xc6858000}, {0xc685a000}, {0xc685c000}, {0xc685e000}, 
+    {0xc6860000}, {0xc6862000}, {0xc6864000}, {0xc6866000}, 
+    {0xc6868000}, {0xc686a000}, {0xc686c000}, {0xc686e000}, 
+    {0xc6870000}, {0xc6872000}, {0xc6874000}, {0xc6876000}, 
+    {0xc6878000}, {0xc687a000}, {0xc687c000}, {0xc687e000}, 
+    {0xc6880000}, {0xc6882000}, {0xc6884000}, {0xc6886000}, 
+    {0xc6888000}, {0xc688a000}, {0xc688c000}, {0xc688e000}, 
+    {0xc6890000}, {0xc6892000}, {0xc6894000}, {0xc6896000}, 
+    {0xc6898000}, {0xc689a000}, {0xc689c000}, {0xc689e000}, 
+    {0xc68a0000}, {0xc68a2000}, {0xc68a4000}, {0xc68a6000}, 
+    {0xc68a8000}, {0xc68aa000}, {0xc68ac000}, {0xc68ae000}, 
+    {0xc68b0000}, {0xc68b2000}, {0xc68b4000}, {0xc68b6000}, 
+    {0xc68b8000}, {0xc68ba000}, {0xc68bc000}, {0xc68be000}, 
+    {0xc68c0000}, {0xc68c2000}, {0xc68c4000}, {0xc68c6000}, 
+    {0xc68c8000}, {0xc68ca000}, {0xc68cc000}, {0xc68ce000}, 
+    {0xc68d0000}, {0xc68d2000}, {0xc68d4000}, {0xc68d6000}, 
+    {0xc68d8000}, {0xc68da000}, {0xc68dc000}, {0xc68de000}, 
+    {0xc68e0000}, {0xc68e2000}, {0xc68e4000}, {0xc68e6000}, 
+    {0xc68e8000}, {0xc68ea000}, {0xc68ec000}, {0xc68ee000}, 
+    {0xc68f0000}, {0xc68f2000}, {0xc68f4000}, {0xc68f6000}, 
+    {0xc68f8000}, {0xc68fa000}, {0xc68fc000}, {0xc68fe000}, 
+    {0xc6900000}, {0xc6902000}, {0xc6904000}, {0xc6906000}, 
+    {0xc6908000}, {0xc690a000}, {0xc690c000}, {0xc690e000}, 
+    {0xc6910000}, {0xc6912000}, {0xc6914000}, {0xc6916000}, 
+    {0xc6918000}, {0xc691a000}, {0xc691c000}, {0xc691e000}, 
+    {0xc6920000}, {0xc6922000}, {0xc6924000}, {0xc6926000}, 
+    {0xc6928000}, {0xc692a000}, {0xc692c000}, {0xc692e000}, 
+    {0xc6930000}, {0xc6932000}, {0xc6934000}, {0xc6936000}, 
+    {0xc6938000}, {0xc693a000}, {0xc693c000}, {0xc693e000}, 
+    {0xc6940000}, {0xc6942000}, {0xc6944000}, {0xc6946000}, 
+    {0xc6948000}, {0xc694a000}, {0xc694c000}, {0xc694e000}, 
+    {0xc6950000}, {0xc6952000}, {0xc6954000}, {0xc6956000}, 
+    {0xc6958000}, {0xc695a000}, {0xc695c000}, {0xc695e000}, 
+    {0xc6960000}, {0xc6962000}, {0xc6964000}, {0xc6966000}, 
+    {0xc6968000}, {0xc696a000}, {0xc696c000}, {0xc696e000}, 
+    {0xc6970000}, {0xc6972000}, {0xc6974000}, {0xc6976000}, 
+    {0xc6978000}, {0xc697a000}, {0xc697c000}, {0xc697e000}, 
+    {0xc6980000}, {0xc6982000}, {0xc6984000}, {0xc6986000}, 
+    {0xc6988000}, {0xc698a000}, {0xc698c000}, {0xc698e000}, 
+    {0xc6990000}, {0xc6992000}, {0xc6994000}, {0xc6996000}, 
+    {0xc6998000}, {0xc699a000}, {0xc699c000}, {0xc699e000}, 
+    {0xc69a0000}, {0xc69a2000}, {0xc69a4000}, {0xc69a6000}, 
+    {0xc69a8000}, {0xc69aa000}, {0xc69ac000}, {0xc69ae000}, 
+    {0xc69b0000}, {0xc69b2000}, {0xc69b4000}, {0xc69b6000}, 
+    {0xc69b8000}, {0xc69ba000}, {0xc69bc000}, {0xc69be000}, 
+    {0xc69c0000}, {0xc69c2000}, {0xc69c4000}, {0xc69c6000}, 
+    {0xc69c8000}, {0xc69ca000}, {0xc69cc000}, {0xc69ce000}, 
+    {0xc69d0000}, {0xc69d2000}, {0xc69d4000}, {0xc69d6000}, 
+    {0xc69d8000}, {0xc69da000}, {0xc69dc000}, {0xc69de000}, 
+    {0xc69e0000}, {0xc69e2000}, {0xc69e4000}, {0xc69e6000}, 
+    {0xc69e8000}, {0xc69ea000}, {0xc69ec000}, {0xc69ee000}, 
+    {0xc69f0000}, {0xc69f2000}, {0xc69f4000}, {0xc69f6000}, 
+    {0xc69f8000}, {0xc69fa000}, {0xc69fc000}, {0xc69fe000}, 
+    {0xc6a00000}, {0xc6a02000}, {0xc6a04000}, {0xc6a06000}, 
+    {0xc6a08000}, {0xc6a0a000}, {0xc6a0c000}, {0xc6a0e000}, 
+    {0xc6a10000}, {0xc6a12000}, {0xc6a14000}, {0xc6a16000}, 
+    {0xc6a18000}, {0xc6a1a000}, {0xc6a1c000}, {0xc6a1e000}, 
+    {0xc6a20000}, {0xc6a22000}, {0xc6a24000}, {0xc6a26000}, 
+    {0xc6a28000}, {0xc6a2a000}, {0xc6a2c000}, {0xc6a2e000}, 
+    {0xc6a30000}, {0xc6a32000}, {0xc6a34000}, {0xc6a36000}, 
+    {0xc6a38000}, {0xc6a3a000}, {0xc6a3c000}, {0xc6a3e000}, 
+    {0xc6a40000}, {0xc6a42000}, {0xc6a44000}, {0xc6a46000}, 
+    {0xc6a48000}, {0xc6a4a000}, {0xc6a4c000}, {0xc6a4e000}, 
+    {0xc6a50000}, {0xc6a52000}, {0xc6a54000}, {0xc6a56000}, 
+    {0xc6a58000}, {0xc6a5a000}, {0xc6a5c000}, {0xc6a5e000}, 
+    {0xc6a60000}, {0xc6a62000}, {0xc6a64000}, {0xc6a66000}, 
+    {0xc6a68000}, {0xc6a6a000}, {0xc6a6c000}, {0xc6a6e000}, 
+    {0xc6a70000}, {0xc6a72000}, {0xc6a74000}, {0xc6a76000}, 
+    {0xc6a78000}, {0xc6a7a000}, {0xc6a7c000}, {0xc6a7e000}, 
+    {0xc6a80000}, {0xc6a82000}, {0xc6a84000}, {0xc6a86000}, 
+    {0xc6a88000}, {0xc6a8a000}, {0xc6a8c000}, {0xc6a8e000}, 
+    {0xc6a90000}, {0xc6a92000}, {0xc6a94000}, {0xc6a96000}, 
+    {0xc6a98000}, {0xc6a9a000}, {0xc6a9c000}, {0xc6a9e000}, 
+    {0xc6aa0000}, {0xc6aa2000}, {0xc6aa4000}, {0xc6aa6000}, 
+    {0xc6aa8000}, {0xc6aaa000}, {0xc6aac000}, {0xc6aae000}, 
+    {0xc6ab0000}, {0xc6ab2000}, {0xc6ab4000}, {0xc6ab6000}, 
+    {0xc6ab8000}, {0xc6aba000}, {0xc6abc000}, {0xc6abe000}, 
+    {0xc6ac0000}, {0xc6ac2000}, {0xc6ac4000}, {0xc6ac6000}, 
+    {0xc6ac8000}, {0xc6aca000}, {0xc6acc000}, {0xc6ace000}, 
+    {0xc6ad0000}, {0xc6ad2000}, {0xc6ad4000}, {0xc6ad6000}, 
+    {0xc6ad8000}, {0xc6ada000}, {0xc6adc000}, {0xc6ade000}, 
+    {0xc6ae0000}, {0xc6ae2000}, {0xc6ae4000}, {0xc6ae6000}, 
+    {0xc6ae8000}, {0xc6aea000}, {0xc6aec000}, {0xc6aee000}, 
+    {0xc6af0000}, {0xc6af2000}, {0xc6af4000}, {0xc6af6000}, 
+    {0xc6af8000}, {0xc6afa000}, {0xc6afc000}, {0xc6afe000}, 
+    {0xc6b00000}, {0xc6b02000}, {0xc6b04000}, {0xc6b06000}, 
+    {0xc6b08000}, {0xc6b0a000}, {0xc6b0c000}, {0xc6b0e000}, 
+    {0xc6b10000}, {0xc6b12000}, {0xc6b14000}, {0xc6b16000}, 
+    {0xc6b18000}, {0xc6b1a000}, {0xc6b1c000}, {0xc6b1e000}, 
+    {0xc6b20000}, {0xc6b22000}, {0xc6b24000}, {0xc6b26000}, 
+    {0xc6b28000}, {0xc6b2a000}, {0xc6b2c000}, {0xc6b2e000}, 
+    {0xc6b30000}, {0xc6b32000}, {0xc6b34000}, {0xc6b36000}, 
+    {0xc6b38000}, {0xc6b3a000}, {0xc6b3c000}, {0xc6b3e000}, 
+    {0xc6b40000}, {0xc6b42000}, {0xc6b44000}, {0xc6b46000}, 
+    {0xc6b48000}, {0xc6b4a000}, {0xc6b4c000}, {0xc6b4e000}, 
+    {0xc6b50000}, {0xc6b52000}, {0xc6b54000}, {0xc6b56000}, 
+    {0xc6b58000}, {0xc6b5a000}, {0xc6b5c000}, {0xc6b5e000}, 
+    {0xc6b60000}, {0xc6b62000}, {0xc6b64000}, {0xc6b66000}, 
+    {0xc6b68000}, {0xc6b6a000}, {0xc6b6c000}, {0xc6b6e000}, 
+    {0xc6b70000}, {0xc6b72000}, {0xc6b74000}, {0xc6b76000}, 
+    {0xc6b78000}, {0xc6b7a000}, {0xc6b7c000}, {0xc6b7e000}, 
+    {0xc6b80000}, {0xc6b82000}, {0xc6b84000}, {0xc6b86000}, 
+    {0xc6b88000}, {0xc6b8a000}, {0xc6b8c000}, {0xc6b8e000}, 
+    {0xc6b90000}, {0xc6b92000}, {0xc6b94000}, {0xc6b96000}, 
+    {0xc6b98000}, {0xc6b9a000}, {0xc6b9c000}, {0xc6b9e000}, 
+    {0xc6ba0000}, {0xc6ba2000}, {0xc6ba4000}, {0xc6ba6000}, 
+    {0xc6ba8000}, {0xc6baa000}, {0xc6bac000}, {0xc6bae000}, 
+    {0xc6bb0000}, {0xc6bb2000}, {0xc6bb4000}, {0xc6bb6000}, 
+    {0xc6bb8000}, {0xc6bba000}, {0xc6bbc000}, {0xc6bbe000}, 
+    {0xc6bc0000}, {0xc6bc2000}, {0xc6bc4000}, {0xc6bc6000}, 
+    {0xc6bc8000}, {0xc6bca000}, {0xc6bcc000}, {0xc6bce000}, 
+    {0xc6bd0000}, {0xc6bd2000}, {0xc6bd4000}, {0xc6bd6000}, 
+    {0xc6bd8000}, {0xc6bda000}, {0xc6bdc000}, {0xc6bde000}, 
+    {0xc6be0000}, {0xc6be2000}, {0xc6be4000}, {0xc6be6000}, 
+    {0xc6be8000}, {0xc6bea000}, {0xc6bec000}, {0xc6bee000}, 
+    {0xc6bf0000}, {0xc6bf2000}, {0xc6bf4000}, {0xc6bf6000}, 
+    {0xc6bf8000}, {0xc6bfa000}, {0xc6bfc000}, {0xc6bfe000}, 
+    {0xc6c00000}, {0xc6c02000}, {0xc6c04000}, {0xc6c06000}, 
+    {0xc6c08000}, {0xc6c0a000}, {0xc6c0c000}, {0xc6c0e000}, 
+    {0xc6c10000}, {0xc6c12000}, {0xc6c14000}, {0xc6c16000}, 
+    {0xc6c18000}, {0xc6c1a000}, {0xc6c1c000}, {0xc6c1e000}, 
+    {0xc6c20000}, {0xc6c22000}, {0xc6c24000}, {0xc6c26000}, 
+    {0xc6c28000}, {0xc6c2a000}, {0xc6c2c000}, {0xc6c2e000}, 
+    {0xc6c30000}, {0xc6c32000}, {0xc6c34000}, {0xc6c36000}, 
+    {0xc6c38000}, {0xc6c3a000}, {0xc6c3c000}, {0xc6c3e000}, 
+    {0xc6c40000}, {0xc6c42000}, {0xc6c44000}, {0xc6c46000}, 
+    {0xc6c48000}, {0xc6c4a000}, {0xc6c4c000}, {0xc6c4e000}, 
+    {0xc6c50000}, {0xc6c52000}, {0xc6c54000}, {0xc6c56000}, 
+    {0xc6c58000}, {0xc6c5a000}, {0xc6c5c000}, {0xc6c5e000}, 
+    {0xc6c60000}, {0xc6c62000}, {0xc6c64000}, {0xc6c66000}, 
+    {0xc6c68000}, {0xc6c6a000}, {0xc6c6c000}, {0xc6c6e000}, 
+    {0xc6c70000}, {0xc6c72000}, {0xc6c74000}, {0xc6c76000}, 
+    {0xc6c78000}, {0xc6c7a000}, {0xc6c7c000}, {0xc6c7e000}, 
+    {0xc6c80000}, {0xc6c82000}, {0xc6c84000}, {0xc6c86000}, 
+    {0xc6c88000}, {0xc6c8a000}, {0xc6c8c000}, {0xc6c8e000}, 
+    {0xc6c90000}, {0xc6c92000}, {0xc6c94000}, {0xc6c96000}, 
+    {0xc6c98000}, {0xc6c9a000}, {0xc6c9c000}, {0xc6c9e000}, 
+    {0xc6ca0000}, {0xc6ca2000}, {0xc6ca4000}, {0xc6ca6000}, 
+    {0xc6ca8000}, {0xc6caa000}, {0xc6cac000}, {0xc6cae000}, 
+    {0xc6cb0000}, {0xc6cb2000}, {0xc6cb4000}, {0xc6cb6000}, 
+    {0xc6cb8000}, {0xc6cba000}, {0xc6cbc000}, {0xc6cbe000}, 
+    {0xc6cc0000}, {0xc6cc2000}, {0xc6cc4000}, {0xc6cc6000}, 
+    {0xc6cc8000}, {0xc6cca000}, {0xc6ccc000}, {0xc6cce000}, 
+    {0xc6cd0000}, {0xc6cd2000}, {0xc6cd4000}, {0xc6cd6000}, 
+    {0xc6cd8000}, {0xc6cda000}, {0xc6cdc000}, {0xc6cde000}, 
+    {0xc6ce0000}, {0xc6ce2000}, {0xc6ce4000}, {0xc6ce6000}, 
+    {0xc6ce8000}, {0xc6cea000}, {0xc6cec000}, {0xc6cee000}, 
+    {0xc6cf0000}, {0xc6cf2000}, {0xc6cf4000}, {0xc6cf6000}, 
+    {0xc6cf8000}, {0xc6cfa000}, {0xc6cfc000}, {0xc6cfe000}, 
+    {0xc6d00000}, {0xc6d02000}, {0xc6d04000}, {0xc6d06000}, 
+    {0xc6d08000}, {0xc6d0a000}, {0xc6d0c000}, {0xc6d0e000}, 
+    {0xc6d10000}, {0xc6d12000}, {0xc6d14000}, {0xc6d16000}, 
+    {0xc6d18000}, {0xc6d1a000}, {0xc6d1c000}, {0xc6d1e000}, 
+    {0xc6d20000}, {0xc6d22000}, {0xc6d24000}, {0xc6d26000}, 
+    {0xc6d28000}, {0xc6d2a000}, {0xc6d2c000}, {0xc6d2e000}, 
+    {0xc6d30000}, {0xc6d32000}, {0xc6d34000}, {0xc6d36000}, 
+    {0xc6d38000}, {0xc6d3a000}, {0xc6d3c000}, {0xc6d3e000}, 
+    {0xc6d40000}, {0xc6d42000}, {0xc6d44000}, {0xc6d46000}, 
+    {0xc6d48000}, {0xc6d4a000}, {0xc6d4c000}, {0xc6d4e000}, 
+    {0xc6d50000}, {0xc6d52000}, {0xc6d54000}, {0xc6d56000}, 
+    {0xc6d58000}, {0xc6d5a000}, {0xc6d5c000}, {0xc6d5e000}, 
+    {0xc6d60000}, {0xc6d62000}, {0xc6d64000}, {0xc6d66000}, 
+    {0xc6d68000}, {0xc6d6a000}, {0xc6d6c000}, {0xc6d6e000}, 
+    {0xc6d70000}, {0xc6d72000}, {0xc6d74000}, {0xc6d76000}, 
+    {0xc6d78000}, {0xc6d7a000}, {0xc6d7c000}, {0xc6d7e000}, 
+    {0xc6d80000}, {0xc6d82000}, {0xc6d84000}, {0xc6d86000}, 
+    {0xc6d88000}, {0xc6d8a000}, {0xc6d8c000}, {0xc6d8e000}, 
+    {0xc6d90000}, {0xc6d92000}, {0xc6d94000}, {0xc6d96000}, 
+    {0xc6d98000}, {0xc6d9a000}, {0xc6d9c000}, {0xc6d9e000}, 
+    {0xc6da0000}, {0xc6da2000}, {0xc6da4000}, {0xc6da6000}, 
+    {0xc6da8000}, {0xc6daa000}, {0xc6dac000}, {0xc6dae000}, 
+    {0xc6db0000}, {0xc6db2000}, {0xc6db4000}, {0xc6db6000}, 
+    {0xc6db8000}, {0xc6dba000}, {0xc6dbc000}, {0xc6dbe000}, 
+    {0xc6dc0000}, {0xc6dc2000}, {0xc6dc4000}, {0xc6dc6000}, 
+    {0xc6dc8000}, {0xc6dca000}, {0xc6dcc000}, {0xc6dce000}, 
+    {0xc6dd0000}, {0xc6dd2000}, {0xc6dd4000}, {0xc6dd6000}, 
+    {0xc6dd8000}, {0xc6dda000}, {0xc6ddc000}, {0xc6dde000}, 
+    {0xc6de0000}, {0xc6de2000}, {0xc6de4000}, {0xc6de6000}, 
+    {0xc6de8000}, {0xc6dea000}, {0xc6dec000}, {0xc6dee000}, 
+    {0xc6df0000}, {0xc6df2000}, {0xc6df4000}, {0xc6df6000}, 
+    {0xc6df8000}, {0xc6dfa000}, {0xc6dfc000}, {0xc6dfe000}, 
+    {0xc6e00000}, {0xc6e02000}, {0xc6e04000}, {0xc6e06000}, 
+    {0xc6e08000}, {0xc6e0a000}, {0xc6e0c000}, {0xc6e0e000}, 
+    {0xc6e10000}, {0xc6e12000}, {0xc6e14000}, {0xc6e16000}, 
+    {0xc6e18000}, {0xc6e1a000}, {0xc6e1c000}, {0xc6e1e000}, 
+    {0xc6e20000}, {0xc6e22000}, {0xc6e24000}, {0xc6e26000}, 
+    {0xc6e28000}, {0xc6e2a000}, {0xc6e2c000}, {0xc6e2e000}, 
+    {0xc6e30000}, {0xc6e32000}, {0xc6e34000}, {0xc6e36000}, 
+    {0xc6e38000}, {0xc6e3a000}, {0xc6e3c000}, {0xc6e3e000}, 
+    {0xc6e40000}, {0xc6e42000}, {0xc6e44000}, {0xc6e46000}, 
+    {0xc6e48000}, {0xc6e4a000}, {0xc6e4c000}, {0xc6e4e000}, 
+    {0xc6e50000}, {0xc6e52000}, {0xc6e54000}, {0xc6e56000}, 
+    {0xc6e58000}, {0xc6e5a000}, {0xc6e5c000}, {0xc6e5e000}, 
+    {0xc6e60000}, {0xc6e62000}, {0xc6e64000}, {0xc6e66000}, 
+    {0xc6e68000}, {0xc6e6a000}, {0xc6e6c000}, {0xc6e6e000}, 
+    {0xc6e70000}, {0xc6e72000}, {0xc6e74000}, {0xc6e76000}, 
+    {0xc6e78000}, {0xc6e7a000}, {0xc6e7c000}, {0xc6e7e000}, 
+    {0xc6e80000}, {0xc6e82000}, {0xc6e84000}, {0xc6e86000}, 
+    {0xc6e88000}, {0xc6e8a000}, {0xc6e8c000}, {0xc6e8e000}, 
+    {0xc6e90000}, {0xc6e92000}, {0xc6e94000}, {0xc6e96000}, 
+    {0xc6e98000}, {0xc6e9a000}, {0xc6e9c000}, {0xc6e9e000}, 
+    {0xc6ea0000}, {0xc6ea2000}, {0xc6ea4000}, {0xc6ea6000}, 
+    {0xc6ea8000}, {0xc6eaa000}, {0xc6eac000}, {0xc6eae000}, 
+    {0xc6eb0000}, {0xc6eb2000}, {0xc6eb4000}, {0xc6eb6000}, 
+    {0xc6eb8000}, {0xc6eba000}, {0xc6ebc000}, {0xc6ebe000}, 
+    {0xc6ec0000}, {0xc6ec2000}, {0xc6ec4000}, {0xc6ec6000}, 
+    {0xc6ec8000}, {0xc6eca000}, {0xc6ecc000}, {0xc6ece000}, 
+    {0xc6ed0000}, {0xc6ed2000}, {0xc6ed4000}, {0xc6ed6000}, 
+    {0xc6ed8000}, {0xc6eda000}, {0xc6edc000}, {0xc6ede000}, 
+    {0xc6ee0000}, {0xc6ee2000}, {0xc6ee4000}, {0xc6ee6000}, 
+    {0xc6ee8000}, {0xc6eea000}, {0xc6eec000}, {0xc6eee000}, 
+    {0xc6ef0000}, {0xc6ef2000}, {0xc6ef4000}, {0xc6ef6000}, 
+    {0xc6ef8000}, {0xc6efa000}, {0xc6efc000}, {0xc6efe000}, 
+    {0xc6f00000}, {0xc6f02000}, {0xc6f04000}, {0xc6f06000}, 
+    {0xc6f08000}, {0xc6f0a000}, {0xc6f0c000}, {0xc6f0e000}, 
+    {0xc6f10000}, {0xc6f12000}, {0xc6f14000}, {0xc6f16000}, 
+    {0xc6f18000}, {0xc6f1a000}, {0xc6f1c000}, {0xc6f1e000}, 
+    {0xc6f20000}, {0xc6f22000}, {0xc6f24000}, {0xc6f26000}, 
+    {0xc6f28000}, {0xc6f2a000}, {0xc6f2c000}, {0xc6f2e000}, 
+    {0xc6f30000}, {0xc6f32000}, {0xc6f34000}, {0xc6f36000}, 
+    {0xc6f38000}, {0xc6f3a000}, {0xc6f3c000}, {0xc6f3e000}, 
+    {0xc6f40000}, {0xc6f42000}, {0xc6f44000}, {0xc6f46000}, 
+    {0xc6f48000}, {0xc6f4a000}, {0xc6f4c000}, {0xc6f4e000}, 
+    {0xc6f50000}, {0xc6f52000}, {0xc6f54000}, {0xc6f56000}, 
+    {0xc6f58000}, {0xc6f5a000}, {0xc6f5c000}, {0xc6f5e000}, 
+    {0xc6f60000}, {0xc6f62000}, {0xc6f64000}, {0xc6f66000}, 
+    {0xc6f68000}, {0xc6f6a000}, {0xc6f6c000}, {0xc6f6e000}, 
+    {0xc6f70000}, {0xc6f72000}, {0xc6f74000}, {0xc6f76000}, 
+    {0xc6f78000}, {0xc6f7a000}, {0xc6f7c000}, {0xc6f7e000}, 
+    {0xc6f80000}, {0xc6f82000}, {0xc6f84000}, {0xc6f86000}, 
+    {0xc6f88000}, {0xc6f8a000}, {0xc6f8c000}, {0xc6f8e000}, 
+    {0xc6f90000}, {0xc6f92000}, {0xc6f94000}, {0xc6f96000}, 
+    {0xc6f98000}, {0xc6f9a000}, {0xc6f9c000}, {0xc6f9e000}, 
+    {0xc6fa0000}, {0xc6fa2000}, {0xc6fa4000}, {0xc6fa6000}, 
+    {0xc6fa8000}, {0xc6faa000}, {0xc6fac000}, {0xc6fae000}, 
+    {0xc6fb0000}, {0xc6fb2000}, {0xc6fb4000}, {0xc6fb6000}, 
+    {0xc6fb8000}, {0xc6fba000}, {0xc6fbc000}, {0xc6fbe000}, 
+    {0xc6fc0000}, {0xc6fc2000}, {0xc6fc4000}, {0xc6fc6000}, 
+    {0xc6fc8000}, {0xc6fca000}, {0xc6fcc000}, {0xc6fce000}, 
+    {0xc6fd0000}, {0xc6fd2000}, {0xc6fd4000}, {0xc6fd6000}, 
+    {0xc6fd8000}, {0xc6fda000}, {0xc6fdc000}, {0xc6fde000}, 
+    {0xc6fe0000}, {0xc6fe2000}, {0xc6fe4000}, {0xc6fe6000}, 
+    {0xc6fe8000}, {0xc6fea000}, {0xc6fec000}, {0xc6fee000}, 
+    {0xc6ff0000}, {0xc6ff2000}, {0xc6ff4000}, {0xc6ff6000}, 
+    {0xc6ff8000}, {0xc6ffa000}, {0xc6ffc000}, {0xc6ffe000}, 
+    {0xc7000000}, {0xc7002000}, {0xc7004000}, {0xc7006000}, 
+    {0xc7008000}, {0xc700a000}, {0xc700c000}, {0xc700e000}, 
+    {0xc7010000}, {0xc7012000}, {0xc7014000}, {0xc7016000}, 
+    {0xc7018000}, {0xc701a000}, {0xc701c000}, {0xc701e000}, 
+    {0xc7020000}, {0xc7022000}, {0xc7024000}, {0xc7026000}, 
+    {0xc7028000}, {0xc702a000}, {0xc702c000}, {0xc702e000}, 
+    {0xc7030000}, {0xc7032000}, {0xc7034000}, {0xc7036000}, 
+    {0xc7038000}, {0xc703a000}, {0xc703c000}, {0xc703e000}, 
+    {0xc7040000}, {0xc7042000}, {0xc7044000}, {0xc7046000}, 
+    {0xc7048000}, {0xc704a000}, {0xc704c000}, {0xc704e000}, 
+    {0xc7050000}, {0xc7052000}, {0xc7054000}, {0xc7056000}, 
+    {0xc7058000}, {0xc705a000}, {0xc705c000}, {0xc705e000}, 
+    {0xc7060000}, {0xc7062000}, {0xc7064000}, {0xc7066000}, 
+    {0xc7068000}, {0xc706a000}, {0xc706c000}, {0xc706e000}, 
+    {0xc7070000}, {0xc7072000}, {0xc7074000}, {0xc7076000}, 
+    {0xc7078000}, {0xc707a000}, {0xc707c000}, {0xc707e000}, 
+    {0xc7080000}, {0xc7082000}, {0xc7084000}, {0xc7086000}, 
+    {0xc7088000}, {0xc708a000}, {0xc708c000}, {0xc708e000}, 
+    {0xc7090000}, {0xc7092000}, {0xc7094000}, {0xc7096000}, 
+    {0xc7098000}, {0xc709a000}, {0xc709c000}, {0xc709e000}, 
+    {0xc70a0000}, {0xc70a2000}, {0xc70a4000}, {0xc70a6000}, 
+    {0xc70a8000}, {0xc70aa000}, {0xc70ac000}, {0xc70ae000}, 
+    {0xc70b0000}, {0xc70b2000}, {0xc70b4000}, {0xc70b6000}, 
+    {0xc70b8000}, {0xc70ba000}, {0xc70bc000}, {0xc70be000}, 
+    {0xc70c0000}, {0xc70c2000}, {0xc70c4000}, {0xc70c6000}, 
+    {0xc70c8000}, {0xc70ca000}, {0xc70cc000}, {0xc70ce000}, 
+    {0xc70d0000}, {0xc70d2000}, {0xc70d4000}, {0xc70d6000}, 
+    {0xc70d8000}, {0xc70da000}, {0xc70dc000}, {0xc70de000}, 
+    {0xc70e0000}, {0xc70e2000}, {0xc70e4000}, {0xc70e6000}, 
+    {0xc70e8000}, {0xc70ea000}, {0xc70ec000}, {0xc70ee000}, 
+    {0xc70f0000}, {0xc70f2000}, {0xc70f4000}, {0xc70f6000}, 
+    {0xc70f8000}, {0xc70fa000}, {0xc70fc000}, {0xc70fe000}, 
+    {0xc7100000}, {0xc7102000}, {0xc7104000}, {0xc7106000}, 
+    {0xc7108000}, {0xc710a000}, {0xc710c000}, {0xc710e000}, 
+    {0xc7110000}, {0xc7112000}, {0xc7114000}, {0xc7116000}, 
+    {0xc7118000}, {0xc711a000}, {0xc711c000}, {0xc711e000}, 
+    {0xc7120000}, {0xc7122000}, {0xc7124000}, {0xc7126000}, 
+    {0xc7128000}, {0xc712a000}, {0xc712c000}, {0xc712e000}, 
+    {0xc7130000}, {0xc7132000}, {0xc7134000}, {0xc7136000}, 
+    {0xc7138000}, {0xc713a000}, {0xc713c000}, {0xc713e000}, 
+    {0xc7140000}, {0xc7142000}, {0xc7144000}, {0xc7146000}, 
+    {0xc7148000}, {0xc714a000}, {0xc714c000}, {0xc714e000}, 
+    {0xc7150000}, {0xc7152000}, {0xc7154000}, {0xc7156000}, 
+    {0xc7158000}, {0xc715a000}, {0xc715c000}, {0xc715e000}, 
+    {0xc7160000}, {0xc7162000}, {0xc7164000}, {0xc7166000}, 
+    {0xc7168000}, {0xc716a000}, {0xc716c000}, {0xc716e000}, 
+    {0xc7170000}, {0xc7172000}, {0xc7174000}, {0xc7176000}, 
+    {0xc7178000}, {0xc717a000}, {0xc717c000}, {0xc717e000}, 
+    {0xc7180000}, {0xc7182000}, {0xc7184000}, {0xc7186000}, 
+    {0xc7188000}, {0xc718a000}, {0xc718c000}, {0xc718e000}, 
+    {0xc7190000}, {0xc7192000}, {0xc7194000}, {0xc7196000}, 
+    {0xc7198000}, {0xc719a000}, {0xc719c000}, {0xc719e000}, 
+    {0xc71a0000}, {0xc71a2000}, {0xc71a4000}, {0xc71a6000}, 
+    {0xc71a8000}, {0xc71aa000}, {0xc71ac000}, {0xc71ae000}, 
+    {0xc71b0000}, {0xc71b2000}, {0xc71b4000}, {0xc71b6000}, 
+    {0xc71b8000}, {0xc71ba000}, {0xc71bc000}, {0xc71be000}, 
+    {0xc71c0000}, {0xc71c2000}, {0xc71c4000}, {0xc71c6000}, 
+    {0xc71c8000}, {0xc71ca000}, {0xc71cc000}, {0xc71ce000}, 
+    {0xc71d0000}, {0xc71d2000}, {0xc71d4000}, {0xc71d6000}, 
+    {0xc71d8000}, {0xc71da000}, {0xc71dc000}, {0xc71de000}, 
+    {0xc71e0000}, {0xc71e2000}, {0xc71e4000}, {0xc71e6000}, 
+    {0xc71e8000}, {0xc71ea000}, {0xc71ec000}, {0xc71ee000}, 
+    {0xc71f0000}, {0xc71f2000}, {0xc71f4000}, {0xc71f6000}, 
+    {0xc71f8000}, {0xc71fa000}, {0xc71fc000}, {0xc71fe000}, 
+    {0xc7200000}, {0xc7202000}, {0xc7204000}, {0xc7206000}, 
+    {0xc7208000}, {0xc720a000}, {0xc720c000}, {0xc720e000}, 
+    {0xc7210000}, {0xc7212000}, {0xc7214000}, {0xc7216000}, 
+    {0xc7218000}, {0xc721a000}, {0xc721c000}, {0xc721e000}, 
+    {0xc7220000}, {0xc7222000}, {0xc7224000}, {0xc7226000}, 
+    {0xc7228000}, {0xc722a000}, {0xc722c000}, {0xc722e000}, 
+    {0xc7230000}, {0xc7232000}, {0xc7234000}, {0xc7236000}, 
+    {0xc7238000}, {0xc723a000}, {0xc723c000}, {0xc723e000}, 
+    {0xc7240000}, {0xc7242000}, {0xc7244000}, {0xc7246000}, 
+    {0xc7248000}, {0xc724a000}, {0xc724c000}, {0xc724e000}, 
+    {0xc7250000}, {0xc7252000}, {0xc7254000}, {0xc7256000}, 
+    {0xc7258000}, {0xc725a000}, {0xc725c000}, {0xc725e000}, 
+    {0xc7260000}, {0xc7262000}, {0xc7264000}, {0xc7266000}, 
+    {0xc7268000}, {0xc726a000}, {0xc726c000}, {0xc726e000}, 
+    {0xc7270000}, {0xc7272000}, {0xc7274000}, {0xc7276000}, 
+    {0xc7278000}, {0xc727a000}, {0xc727c000}, {0xc727e000}, 
+    {0xc7280000}, {0xc7282000}, {0xc7284000}, {0xc7286000}, 
+    {0xc7288000}, {0xc728a000}, {0xc728c000}, {0xc728e000}, 
+    {0xc7290000}, {0xc7292000}, {0xc7294000}, {0xc7296000}, 
+    {0xc7298000}, {0xc729a000}, {0xc729c000}, {0xc729e000}, 
+    {0xc72a0000}, {0xc72a2000}, {0xc72a4000}, {0xc72a6000}, 
+    {0xc72a8000}, {0xc72aa000}, {0xc72ac000}, {0xc72ae000}, 
+    {0xc72b0000}, {0xc72b2000}, {0xc72b4000}, {0xc72b6000}, 
+    {0xc72b8000}, {0xc72ba000}, {0xc72bc000}, {0xc72be000}, 
+    {0xc72c0000}, {0xc72c2000}, {0xc72c4000}, {0xc72c6000}, 
+    {0xc72c8000}, {0xc72ca000}, {0xc72cc000}, {0xc72ce000}, 
+    {0xc72d0000}, {0xc72d2000}, {0xc72d4000}, {0xc72d6000}, 
+    {0xc72d8000}, {0xc72da000}, {0xc72dc000}, {0xc72de000}, 
+    {0xc72e0000}, {0xc72e2000}, {0xc72e4000}, {0xc72e6000}, 
+    {0xc72e8000}, {0xc72ea000}, {0xc72ec000}, {0xc72ee000}, 
+    {0xc72f0000}, {0xc72f2000}, {0xc72f4000}, {0xc72f6000}, 
+    {0xc72f8000}, {0xc72fa000}, {0xc72fc000}, {0xc72fe000}, 
+    {0xc7300000}, {0xc7302000}, {0xc7304000}, {0xc7306000}, 
+    {0xc7308000}, {0xc730a000}, {0xc730c000}, {0xc730e000}, 
+    {0xc7310000}, {0xc7312000}, {0xc7314000}, {0xc7316000}, 
+    {0xc7318000}, {0xc731a000}, {0xc731c000}, {0xc731e000}, 
+    {0xc7320000}, {0xc7322000}, {0xc7324000}, {0xc7326000}, 
+    {0xc7328000}, {0xc732a000}, {0xc732c000}, {0xc732e000}, 
+    {0xc7330000}, {0xc7332000}, {0xc7334000}, {0xc7336000}, 
+    {0xc7338000}, {0xc733a000}, {0xc733c000}, {0xc733e000}, 
+    {0xc7340000}, {0xc7342000}, {0xc7344000}, {0xc7346000}, 
+    {0xc7348000}, {0xc734a000}, {0xc734c000}, {0xc734e000}, 
+    {0xc7350000}, {0xc7352000}, {0xc7354000}, {0xc7356000}, 
+    {0xc7358000}, {0xc735a000}, {0xc735c000}, {0xc735e000}, 
+    {0xc7360000}, {0xc7362000}, {0xc7364000}, {0xc7366000}, 
+    {0xc7368000}, {0xc736a000}, {0xc736c000}, {0xc736e000}, 
+    {0xc7370000}, {0xc7372000}, {0xc7374000}, {0xc7376000}, 
+    {0xc7378000}, {0xc737a000}, {0xc737c000}, {0xc737e000}, 
+    {0xc7380000}, {0xc7382000}, {0xc7384000}, {0xc7386000}, 
+    {0xc7388000}, {0xc738a000}, {0xc738c000}, {0xc738e000}, 
+    {0xc7390000}, {0xc7392000}, {0xc7394000}, {0xc7396000}, 
+    {0xc7398000}, {0xc739a000}, {0xc739c000}, {0xc739e000}, 
+    {0xc73a0000}, {0xc73a2000}, {0xc73a4000}, {0xc73a6000}, 
+    {0xc73a8000}, {0xc73aa000}, {0xc73ac000}, {0xc73ae000}, 
+    {0xc73b0000}, {0xc73b2000}, {0xc73b4000}, {0xc73b6000}, 
+    {0xc73b8000}, {0xc73ba000}, {0xc73bc000}, {0xc73be000}, 
+    {0xc73c0000}, {0xc73c2000}, {0xc73c4000}, {0xc73c6000}, 
+    {0xc73c8000}, {0xc73ca000}, {0xc73cc000}, {0xc73ce000}, 
+    {0xc73d0000}, {0xc73d2000}, {0xc73d4000}, {0xc73d6000}, 
+    {0xc73d8000}, {0xc73da000}, {0xc73dc000}, {0xc73de000}, 
+    {0xc73e0000}, {0xc73e2000}, {0xc73e4000}, {0xc73e6000}, 
+    {0xc73e8000}, {0xc73ea000}, {0xc73ec000}, {0xc73ee000}, 
+    {0xc73f0000}, {0xc73f2000}, {0xc73f4000}, {0xc73f6000}, 
+    {0xc73f8000}, {0xc73fa000}, {0xc73fc000}, {0xc73fe000}, 
+    {0xc7400000}, {0xc7402000}, {0xc7404000}, {0xc7406000}, 
+    {0xc7408000}, {0xc740a000}, {0xc740c000}, {0xc740e000}, 
+    {0xc7410000}, {0xc7412000}, {0xc7414000}, {0xc7416000}, 
+    {0xc7418000}, {0xc741a000}, {0xc741c000}, {0xc741e000}, 
+    {0xc7420000}, {0xc7422000}, {0xc7424000}, {0xc7426000}, 
+    {0xc7428000}, {0xc742a000}, {0xc742c000}, {0xc742e000}, 
+    {0xc7430000}, {0xc7432000}, {0xc7434000}, {0xc7436000}, 
+    {0xc7438000}, {0xc743a000}, {0xc743c000}, {0xc743e000}, 
+    {0xc7440000}, {0xc7442000}, {0xc7444000}, {0xc7446000}, 
+    {0xc7448000}, {0xc744a000}, {0xc744c000}, {0xc744e000}, 
+    {0xc7450000}, {0xc7452000}, {0xc7454000}, {0xc7456000}, 
+    {0xc7458000}, {0xc745a000}, {0xc745c000}, {0xc745e000}, 
+    {0xc7460000}, {0xc7462000}, {0xc7464000}, {0xc7466000}, 
+    {0xc7468000}, {0xc746a000}, {0xc746c000}, {0xc746e000}, 
+    {0xc7470000}, {0xc7472000}, {0xc7474000}, {0xc7476000}, 
+    {0xc7478000}, {0xc747a000}, {0xc747c000}, {0xc747e000}, 
+    {0xc7480000}, {0xc7482000}, {0xc7484000}, {0xc7486000}, 
+    {0xc7488000}, {0xc748a000}, {0xc748c000}, {0xc748e000}, 
+    {0xc7490000}, {0xc7492000}, {0xc7494000}, {0xc7496000}, 
+    {0xc7498000}, {0xc749a000}, {0xc749c000}, {0xc749e000}, 
+    {0xc74a0000}, {0xc74a2000}, {0xc74a4000}, {0xc74a6000}, 
+    {0xc74a8000}, {0xc74aa000}, {0xc74ac000}, {0xc74ae000}, 
+    {0xc74b0000}, {0xc74b2000}, {0xc74b4000}, {0xc74b6000}, 
+    {0xc74b8000}, {0xc74ba000}, {0xc74bc000}, {0xc74be000}, 
+    {0xc74c0000}, {0xc74c2000}, {0xc74c4000}, {0xc74c6000}, 
+    {0xc74c8000}, {0xc74ca000}, {0xc74cc000}, {0xc74ce000}, 
+    {0xc74d0000}, {0xc74d2000}, {0xc74d4000}, {0xc74d6000}, 
+    {0xc74d8000}, {0xc74da000}, {0xc74dc000}, {0xc74de000}, 
+    {0xc74e0000}, {0xc74e2000}, {0xc74e4000}, {0xc74e6000}, 
+    {0xc74e8000}, {0xc74ea000}, {0xc74ec000}, {0xc74ee000}, 
+    {0xc74f0000}, {0xc74f2000}, {0xc74f4000}, {0xc74f6000}, 
+    {0xc74f8000}, {0xc74fa000}, {0xc74fc000}, {0xc74fe000}, 
+    {0xc7500000}, {0xc7502000}, {0xc7504000}, {0xc7506000}, 
+    {0xc7508000}, {0xc750a000}, {0xc750c000}, {0xc750e000}, 
+    {0xc7510000}, {0xc7512000}, {0xc7514000}, {0xc7516000}, 
+    {0xc7518000}, {0xc751a000}, {0xc751c000}, {0xc751e000}, 
+    {0xc7520000}, {0xc7522000}, {0xc7524000}, {0xc7526000}, 
+    {0xc7528000}, {0xc752a000}, {0xc752c000}, {0xc752e000}, 
+    {0xc7530000}, {0xc7532000}, {0xc7534000}, {0xc7536000}, 
+    {0xc7538000}, {0xc753a000}, {0xc753c000}, {0xc753e000}, 
+    {0xc7540000}, {0xc7542000}, {0xc7544000}, {0xc7546000}, 
+    {0xc7548000}, {0xc754a000}, {0xc754c000}, {0xc754e000}, 
+    {0xc7550000}, {0xc7552000}, {0xc7554000}, {0xc7556000}, 
+    {0xc7558000}, {0xc755a000}, {0xc755c000}, {0xc755e000}, 
+    {0xc7560000}, {0xc7562000}, {0xc7564000}, {0xc7566000}, 
+    {0xc7568000}, {0xc756a000}, {0xc756c000}, {0xc756e000}, 
+    {0xc7570000}, {0xc7572000}, {0xc7574000}, {0xc7576000}, 
+    {0xc7578000}, {0xc757a000}, {0xc757c000}, {0xc757e000}, 
+    {0xc7580000}, {0xc7582000}, {0xc7584000}, {0xc7586000}, 
+    {0xc7588000}, {0xc758a000}, {0xc758c000}, {0xc758e000}, 
+    {0xc7590000}, {0xc7592000}, {0xc7594000}, {0xc7596000}, 
+    {0xc7598000}, {0xc759a000}, {0xc759c000}, {0xc759e000}, 
+    {0xc75a0000}, {0xc75a2000}, {0xc75a4000}, {0xc75a6000}, 
+    {0xc75a8000}, {0xc75aa000}, {0xc75ac000}, {0xc75ae000}, 
+    {0xc75b0000}, {0xc75b2000}, {0xc75b4000}, {0xc75b6000}, 
+    {0xc75b8000}, {0xc75ba000}, {0xc75bc000}, {0xc75be000}, 
+    {0xc75c0000}, {0xc75c2000}, {0xc75c4000}, {0xc75c6000}, 
+    {0xc75c8000}, {0xc75ca000}, {0xc75cc000}, {0xc75ce000}, 
+    {0xc75d0000}, {0xc75d2000}, {0xc75d4000}, {0xc75d6000}, 
+    {0xc75d8000}, {0xc75da000}, {0xc75dc000}, {0xc75de000}, 
+    {0xc75e0000}, {0xc75e2000}, {0xc75e4000}, {0xc75e6000}, 
+    {0xc75e8000}, {0xc75ea000}, {0xc75ec000}, {0xc75ee000}, 
+    {0xc75f0000}, {0xc75f2000}, {0xc75f4000}, {0xc75f6000}, 
+    {0xc75f8000}, {0xc75fa000}, {0xc75fc000}, {0xc75fe000}, 
+    {0xc7600000}, {0xc7602000}, {0xc7604000}, {0xc7606000}, 
+    {0xc7608000}, {0xc760a000}, {0xc760c000}, {0xc760e000}, 
+    {0xc7610000}, {0xc7612000}, {0xc7614000}, {0xc7616000}, 
+    {0xc7618000}, {0xc761a000}, {0xc761c000}, {0xc761e000}, 
+    {0xc7620000}, {0xc7622000}, {0xc7624000}, {0xc7626000}, 
+    {0xc7628000}, {0xc762a000}, {0xc762c000}, {0xc762e000}, 
+    {0xc7630000}, {0xc7632000}, {0xc7634000}, {0xc7636000}, 
+    {0xc7638000}, {0xc763a000}, {0xc763c000}, {0xc763e000}, 
+    {0xc7640000}, {0xc7642000}, {0xc7644000}, {0xc7646000}, 
+    {0xc7648000}, {0xc764a000}, {0xc764c000}, {0xc764e000}, 
+    {0xc7650000}, {0xc7652000}, {0xc7654000}, {0xc7656000}, 
+    {0xc7658000}, {0xc765a000}, {0xc765c000}, {0xc765e000}, 
+    {0xc7660000}, {0xc7662000}, {0xc7664000}, {0xc7666000}, 
+    {0xc7668000}, {0xc766a000}, {0xc766c000}, {0xc766e000}, 
+    {0xc7670000}, {0xc7672000}, {0xc7674000}, {0xc7676000}, 
+    {0xc7678000}, {0xc767a000}, {0xc767c000}, {0xc767e000}, 
+    {0xc7680000}, {0xc7682000}, {0xc7684000}, {0xc7686000}, 
+    {0xc7688000}, {0xc768a000}, {0xc768c000}, {0xc768e000}, 
+    {0xc7690000}, {0xc7692000}, {0xc7694000}, {0xc7696000}, 
+    {0xc7698000}, {0xc769a000}, {0xc769c000}, {0xc769e000}, 
+    {0xc76a0000}, {0xc76a2000}, {0xc76a4000}, {0xc76a6000}, 
+    {0xc76a8000}, {0xc76aa000}, {0xc76ac000}, {0xc76ae000}, 
+    {0xc76b0000}, {0xc76b2000}, {0xc76b4000}, {0xc76b6000}, 
+    {0xc76b8000}, {0xc76ba000}, {0xc76bc000}, {0xc76be000}, 
+    {0xc76c0000}, {0xc76c2000}, {0xc76c4000}, {0xc76c6000}, 
+    {0xc76c8000}, {0xc76ca000}, {0xc76cc000}, {0xc76ce000}, 
+    {0xc76d0000}, {0xc76d2000}, {0xc76d4000}, {0xc76d6000}, 
+    {0xc76d8000}, {0xc76da000}, {0xc76dc000}, {0xc76de000}, 
+    {0xc76e0000}, {0xc76e2000}, {0xc76e4000}, {0xc76e6000}, 
+    {0xc76e8000}, {0xc76ea000}, {0xc76ec000}, {0xc76ee000}, 
+    {0xc76f0000}, {0xc76f2000}, {0xc76f4000}, {0xc76f6000}, 
+    {0xc76f8000}, {0xc76fa000}, {0xc76fc000}, {0xc76fe000}, 
+    {0xc7700000}, {0xc7702000}, {0xc7704000}, {0xc7706000}, 
+    {0xc7708000}, {0xc770a000}, {0xc770c000}, {0xc770e000}, 
+    {0xc7710000}, {0xc7712000}, {0xc7714000}, {0xc7716000}, 
+    {0xc7718000}, {0xc771a000}, {0xc771c000}, {0xc771e000}, 
+    {0xc7720000}, {0xc7722000}, {0xc7724000}, {0xc7726000}, 
+    {0xc7728000}, {0xc772a000}, {0xc772c000}, {0xc772e000}, 
+    {0xc7730000}, {0xc7732000}, {0xc7734000}, {0xc7736000}, 
+    {0xc7738000}, {0xc773a000}, {0xc773c000}, {0xc773e000}, 
+    {0xc7740000}, {0xc7742000}, {0xc7744000}, {0xc7746000}, 
+    {0xc7748000}, {0xc774a000}, {0xc774c000}, {0xc774e000}, 
+    {0xc7750000}, {0xc7752000}, {0xc7754000}, {0xc7756000}, 
+    {0xc7758000}, {0xc775a000}, {0xc775c000}, {0xc775e000}, 
+    {0xc7760000}, {0xc7762000}, {0xc7764000}, {0xc7766000}, 
+    {0xc7768000}, {0xc776a000}, {0xc776c000}, {0xc776e000}, 
+    {0xc7770000}, {0xc7772000}, {0xc7774000}, {0xc7776000}, 
+    {0xc7778000}, {0xc777a000}, {0xc777c000}, {0xc777e000}, 
+    {0xc7780000}, {0xc7782000}, {0xc7784000}, {0xc7786000}, 
+    {0xc7788000}, {0xc778a000}, {0xc778c000}, {0xc778e000}, 
+    {0xc7790000}, {0xc7792000}, {0xc7794000}, {0xc7796000}, 
+    {0xc7798000}, {0xc779a000}, {0xc779c000}, {0xc779e000}, 
+    {0xc77a0000}, {0xc77a2000}, {0xc77a4000}, {0xc77a6000}, 
+    {0xc77a8000}, {0xc77aa000}, {0xc77ac000}, {0xc77ae000}, 
+    {0xc77b0000}, {0xc77b2000}, {0xc77b4000}, {0xc77b6000}, 
+    {0xc77b8000}, {0xc77ba000}, {0xc77bc000}, {0xc77be000}, 
+    {0xc77c0000}, {0xc77c2000}, {0xc77c4000}, {0xc77c6000}, 
+    {0xc77c8000}, {0xc77ca000}, {0xc77cc000}, {0xc77ce000}, 
+    {0xc77d0000}, {0xc77d2000}, {0xc77d4000}, {0xc77d6000}, 
+    {0xc77d8000}, {0xc77da000}, {0xc77dc000}, {0xc77de000}, 
+    {0xc77e0000}, {0xc77e2000}, {0xc77e4000}, {0xc77e6000}, 
+    {0xc77e8000}, {0xc77ea000}, {0xc77ec000}, {0xc77ee000}, 
+    {0xc77f0000}, {0xc77f2000}, {0xc77f4000}, {0xc77f6000}, 
+    {0xc77f8000}, {0xc77fa000}, {0xc77fc000}, {0xc77fe000}, 
+    {0xff800000}, {0xff802000}, {0xff804000}, {0xff806000}, 
+    {0xff808000}, {0xff80a000}, {0xff80c000}, {0xff80e000}, 
+    {0xff810000}, {0xff812000}, {0xff814000}, {0xff816000}, 
+    {0xff818000}, {0xff81a000}, {0xff81c000}, {0xff81e000}, 
+    {0xff820000}, {0xff822000}, {0xff824000}, {0xff826000}, 
+    {0xff828000}, {0xff82a000}, {0xff82c000}, {0xff82e000}, 
+    {0xff830000}, {0xff832000}, {0xff834000}, {0xff836000}, 
+    {0xff838000}, {0xff83a000}, {0xff83c000}, {0xff83e000}, 
+    {0xff840000}, {0xff842000}, {0xff844000}, {0xff846000}, 
+    {0xff848000}, {0xff84a000}, {0xff84c000}, {0xff84e000}, 
+    {0xff850000}, {0xff852000}, {0xff854000}, {0xff856000}, 
+    {0xff858000}, {0xff85a000}, {0xff85c000}, {0xff85e000}, 
+    {0xff860000}, {0xff862000}, {0xff864000}, {0xff866000}, 
+    {0xff868000}, {0xff86a000}, {0xff86c000}, {0xff86e000}, 
+    {0xff870000}, {0xff872000}, {0xff874000}, {0xff876000}, 
+    {0xff878000}, {0xff87a000}, {0xff87c000}, {0xff87e000}, 
+    {0xff880000}, {0xff882000}, {0xff884000}, {0xff886000}, 
+    {0xff888000}, {0xff88a000}, {0xff88c000}, {0xff88e000}, 
+    {0xff890000}, {0xff892000}, {0xff894000}, {0xff896000}, 
+    {0xff898000}, {0xff89a000}, {0xff89c000}, {0xff89e000}, 
+    {0xff8a0000}, {0xff8a2000}, {0xff8a4000}, {0xff8a6000}, 
+    {0xff8a8000}, {0xff8aa000}, {0xff8ac000}, {0xff8ae000}, 
+    {0xff8b0000}, {0xff8b2000}, {0xff8b4000}, {0xff8b6000}, 
+    {0xff8b8000}, {0xff8ba000}, {0xff8bc000}, {0xff8be000}, 
+    {0xff8c0000}, {0xff8c2000}, {0xff8c4000}, {0xff8c6000}, 
+    {0xff8c8000}, {0xff8ca000}, {0xff8cc000}, {0xff8ce000}, 
+    {0xff8d0000}, {0xff8d2000}, {0xff8d4000}, {0xff8d6000}, 
+    {0xff8d8000}, {0xff8da000}, {0xff8dc000}, {0xff8de000}, 
+    {0xff8e0000}, {0xff8e2000}, {0xff8e4000}, {0xff8e6000}, 
+    {0xff8e8000}, {0xff8ea000}, {0xff8ec000}, {0xff8ee000}, 
+    {0xff8f0000}, {0xff8f2000}, {0xff8f4000}, {0xff8f6000}, 
+    {0xff8f8000}, {0xff8fa000}, {0xff8fc000}, {0xff8fe000}, 
+    {0xff900000}, {0xff902000}, {0xff904000}, {0xff906000}, 
+    {0xff908000}, {0xff90a000}, {0xff90c000}, {0xff90e000}, 
+    {0xff910000}, {0xff912000}, {0xff914000}, {0xff916000}, 
+    {0xff918000}, {0xff91a000}, {0xff91c000}, {0xff91e000}, 
+    {0xff920000}, {0xff922000}, {0xff924000}, {0xff926000}, 
+    {0xff928000}, {0xff92a000}, {0xff92c000}, {0xff92e000}, 
+    {0xff930000}, {0xff932000}, {0xff934000}, {0xff936000}, 
+    {0xff938000}, {0xff93a000}, {0xff93c000}, {0xff93e000}, 
+    {0xff940000}, {0xff942000}, {0xff944000}, {0xff946000}, 
+    {0xff948000}, {0xff94a000}, {0xff94c000}, {0xff94e000}, 
+    {0xff950000}, {0xff952000}, {0xff954000}, {0xff956000}, 
+    {0xff958000}, {0xff95a000}, {0xff95c000}, {0xff95e000}, 
+    {0xff960000}, {0xff962000}, {0xff964000}, {0xff966000}, 
+    {0xff968000}, {0xff96a000}, {0xff96c000}, {0xff96e000}, 
+    {0xff970000}, {0xff972000}, {0xff974000}, {0xff976000}, 
+    {0xff978000}, {0xff97a000}, {0xff97c000}, {0xff97e000}, 
+    {0xff980000}, {0xff982000}, {0xff984000}, {0xff986000}, 
+    {0xff988000}, {0xff98a000}, {0xff98c000}, {0xff98e000}, 
+    {0xff990000}, {0xff992000}, {0xff994000}, {0xff996000}, 
+    {0xff998000}, {0xff99a000}, {0xff99c000}, {0xff99e000}, 
+    {0xff9a0000}, {0xff9a2000}, {0xff9a4000}, {0xff9a6000}, 
+    {0xff9a8000}, {0xff9aa000}, {0xff9ac000}, {0xff9ae000}, 
+    {0xff9b0000}, {0xff9b2000}, {0xff9b4000}, {0xff9b6000}, 
+    {0xff9b8000}, {0xff9ba000}, {0xff9bc000}, {0xff9be000}, 
+    {0xff9c0000}, {0xff9c2000}, {0xff9c4000}, {0xff9c6000}, 
+    {0xff9c8000}, {0xff9ca000}, {0xff9cc000}, {0xff9ce000}, 
+    {0xff9d0000}, {0xff9d2000}, {0xff9d4000}, {0xff9d6000}, 
+    {0xff9d8000}, {0xff9da000}, {0xff9dc000}, {0xff9de000}, 
+    {0xff9e0000}, {0xff9e2000}, {0xff9e4000}, {0xff9e6000}, 
+    {0xff9e8000}, {0xff9ea000}, {0xff9ec000}, {0xff9ee000}, 
+    {0xff9f0000}, {0xff9f2000}, {0xff9f4000}, {0xff9f6000}, 
+    {0xff9f8000}, {0xff9fa000}, {0xff9fc000}, {0xff9fe000}, 
+    {0xffa00000}, {0xffa02000}, {0xffa04000}, {0xffa06000}, 
+    {0xffa08000}, {0xffa0a000}, {0xffa0c000}, {0xffa0e000}, 
+    {0xffa10000}, {0xffa12000}, {0xffa14000}, {0xffa16000}, 
+    {0xffa18000}, {0xffa1a000}, {0xffa1c000}, {0xffa1e000}, 
+    {0xffa20000}, {0xffa22000}, {0xffa24000}, {0xffa26000}, 
+    {0xffa28000}, {0xffa2a000}, {0xffa2c000}, {0xffa2e000}, 
+    {0xffa30000}, {0xffa32000}, {0xffa34000}, {0xffa36000}, 
+    {0xffa38000}, {0xffa3a000}, {0xffa3c000}, {0xffa3e000}, 
+    {0xffa40000}, {0xffa42000}, {0xffa44000}, {0xffa46000}, 
+    {0xffa48000}, {0xffa4a000}, {0xffa4c000}, {0xffa4e000}, 
+    {0xffa50000}, {0xffa52000}, {0xffa54000}, {0xffa56000}, 
+    {0xffa58000}, {0xffa5a000}, {0xffa5c000}, {0xffa5e000}, 
+    {0xffa60000}, {0xffa62000}, {0xffa64000}, {0xffa66000}, 
+    {0xffa68000}, {0xffa6a000}, {0xffa6c000}, {0xffa6e000}, 
+    {0xffa70000}, {0xffa72000}, {0xffa74000}, {0xffa76000}, 
+    {0xffa78000}, {0xffa7a000}, {0xffa7c000}, {0xffa7e000}, 
+    {0xffa80000}, {0xffa82000}, {0xffa84000}, {0xffa86000}, 
+    {0xffa88000}, {0xffa8a000}, {0xffa8c000}, {0xffa8e000}, 
+    {0xffa90000}, {0xffa92000}, {0xffa94000}, {0xffa96000}, 
+    {0xffa98000}, {0xffa9a000}, {0xffa9c000}, {0xffa9e000}, 
+    {0xffaa0000}, {0xffaa2000}, {0xffaa4000}, {0xffaa6000}, 
+    {0xffaa8000}, {0xffaaa000}, {0xffaac000}, {0xffaae000}, 
+    {0xffab0000}, {0xffab2000}, {0xffab4000}, {0xffab6000}, 
+    {0xffab8000}, {0xffaba000}, {0xffabc000}, {0xffabe000}, 
+    {0xffac0000}, {0xffac2000}, {0xffac4000}, {0xffac6000}, 
+    {0xffac8000}, {0xffaca000}, {0xffacc000}, {0xfface000}, 
+    {0xffad0000}, {0xffad2000}, {0xffad4000}, {0xffad6000}, 
+    {0xffad8000}, {0xffada000}, {0xffadc000}, {0xffade000}, 
+    {0xffae0000}, {0xffae2000}, {0xffae4000}, {0xffae6000}, 
+    {0xffae8000}, {0xffaea000}, {0xffaec000}, {0xffaee000}, 
+    {0xffaf0000}, {0xffaf2000}, {0xffaf4000}, {0xffaf6000}, 
+    {0xffaf8000}, {0xffafa000}, {0xffafc000}, {0xffafe000}, 
+    {0xffb00000}, {0xffb02000}, {0xffb04000}, {0xffb06000}, 
+    {0xffb08000}, {0xffb0a000}, {0xffb0c000}, {0xffb0e000}, 
+    {0xffb10000}, {0xffb12000}, {0xffb14000}, {0xffb16000}, 
+    {0xffb18000}, {0xffb1a000}, {0xffb1c000}, {0xffb1e000}, 
+    {0xffb20000}, {0xffb22000}, {0xffb24000}, {0xffb26000}, 
+    {0xffb28000}, {0xffb2a000}, {0xffb2c000}, {0xffb2e000}, 
+    {0xffb30000}, {0xffb32000}, {0xffb34000}, {0xffb36000}, 
+    {0xffb38000}, {0xffb3a000}, {0xffb3c000}, {0xffb3e000}, 
+    {0xffb40000}, {0xffb42000}, {0xffb44000}, {0xffb46000}, 
+    {0xffb48000}, {0xffb4a000}, {0xffb4c000}, {0xffb4e000}, 
+    {0xffb50000}, {0xffb52000}, {0xffb54000}, {0xffb56000}, 
+    {0xffb58000}, {0xffb5a000}, {0xffb5c000}, {0xffb5e000}, 
+    {0xffb60000}, {0xffb62000}, {0xffb64000}, {0xffb66000}, 
+    {0xffb68000}, {0xffb6a000}, {0xffb6c000}, {0xffb6e000}, 
+    {0xffb70000}, {0xffb72000}, {0xffb74000}, {0xffb76000}, 
+    {0xffb78000}, {0xffb7a000}, {0xffb7c000}, {0xffb7e000}, 
+    {0xffb80000}, {0xffb82000}, {0xffb84000}, {0xffb86000}, 
+    {0xffb88000}, {0xffb8a000}, {0xffb8c000}, {0xffb8e000}, 
+    {0xffb90000}, {0xffb92000}, {0xffb94000}, {0xffb96000}, 
+    {0xffb98000}, {0xffb9a000}, {0xffb9c000}, {0xffb9e000}, 
+    {0xffba0000}, {0xffba2000}, {0xffba4000}, {0xffba6000}, 
+    {0xffba8000}, {0xffbaa000}, {0xffbac000}, {0xffbae000}, 
+    {0xffbb0000}, {0xffbb2000}, {0xffbb4000}, {0xffbb6000}, 
+    {0xffbb8000}, {0xffbba000}, {0xffbbc000}, {0xffbbe000}, 
+    {0xffbc0000}, {0xffbc2000}, {0xffbc4000}, {0xffbc6000}, 
+    {0xffbc8000}, {0xffbca000}, {0xffbcc000}, {0xffbce000}, 
+    {0xffbd0000}, {0xffbd2000}, {0xffbd4000}, {0xffbd6000}, 
+    {0xffbd8000}, {0xffbda000}, {0xffbdc000}, {0xffbde000}, 
+    {0xffbe0000}, {0xffbe2000}, {0xffbe4000}, {0xffbe6000}, 
+    {0xffbe8000}, {0xffbea000}, {0xffbec000}, {0xffbee000}, 
+    {0xffbf0000}, {0xffbf2000}, {0xffbf4000}, {0xffbf6000}, 
+    {0xffbf8000}, {0xffbfa000}, {0xffbfc000}, {0xffbfe000}, 
+    {0xffc00000}, {0xffc02000}, {0xffc04000}, {0xffc06000}, 
+    {0xffc08000}, {0xffc0a000}, {0xffc0c000}, {0xffc0e000}, 
+    {0xffc10000}, {0xffc12000}, {0xffc14000}, {0xffc16000}, 
+    {0xffc18000}, {0xffc1a000}, {0xffc1c000}, {0xffc1e000}, 
+    {0xffc20000}, {0xffc22000}, {0xffc24000}, {0xffc26000}, 
+    {0xffc28000}, {0xffc2a000}, {0xffc2c000}, {0xffc2e000}, 
+    {0xffc30000}, {0xffc32000}, {0xffc34000}, {0xffc36000}, 
+    {0xffc38000}, {0xffc3a000}, {0xffc3c000}, {0xffc3e000}, 
+    {0xffc40000}, {0xffc42000}, {0xffc44000}, {0xffc46000}, 
+    {0xffc48000}, {0xffc4a000}, {0xffc4c000}, {0xffc4e000}, 
+    {0xffc50000}, {0xffc52000}, {0xffc54000}, {0xffc56000}, 
+    {0xffc58000}, {0xffc5a000}, {0xffc5c000}, {0xffc5e000}, 
+    {0xffc60000}, {0xffc62000}, {0xffc64000}, {0xffc66000}, 
+    {0xffc68000}, {0xffc6a000}, {0xffc6c000}, {0xffc6e000}, 
+    {0xffc70000}, {0xffc72000}, {0xffc74000}, {0xffc76000}, 
+    {0xffc78000}, {0xffc7a000}, {0xffc7c000}, {0xffc7e000}, 
+    {0xffc80000}, {0xffc82000}, {0xffc84000}, {0xffc86000}, 
+    {0xffc88000}, {0xffc8a000}, {0xffc8c000}, {0xffc8e000}, 
+    {0xffc90000}, {0xffc92000}, {0xffc94000}, {0xffc96000}, 
+    {0xffc98000}, {0xffc9a000}, {0xffc9c000}, {0xffc9e000}, 
+    {0xffca0000}, {0xffca2000}, {0xffca4000}, {0xffca6000}, 
+    {0xffca8000}, {0xffcaa000}, {0xffcac000}, {0xffcae000}, 
+    {0xffcb0000}, {0xffcb2000}, {0xffcb4000}, {0xffcb6000}, 
+    {0xffcb8000}, {0xffcba000}, {0xffcbc000}, {0xffcbe000}, 
+    {0xffcc0000}, {0xffcc2000}, {0xffcc4000}, {0xffcc6000}, 
+    {0xffcc8000}, {0xffcca000}, {0xffccc000}, {0xffcce000}, 
+    {0xffcd0000}, {0xffcd2000}, {0xffcd4000}, {0xffcd6000}, 
+    {0xffcd8000}, {0xffcda000}, {0xffcdc000}, {0xffcde000}, 
+    {0xffce0000}, {0xffce2000}, {0xffce4000}, {0xffce6000}, 
+    {0xffce8000}, {0xffcea000}, {0xffcec000}, {0xffcee000}, 
+    {0xffcf0000}, {0xffcf2000}, {0xffcf4000}, {0xffcf6000}, 
+    {0xffcf8000}, {0xffcfa000}, {0xffcfc000}, {0xffcfe000}, 
+    {0xffd00000}, {0xffd02000}, {0xffd04000}, {0xffd06000}, 
+    {0xffd08000}, {0xffd0a000}, {0xffd0c000}, {0xffd0e000}, 
+    {0xffd10000}, {0xffd12000}, {0xffd14000}, {0xffd16000}, 
+    {0xffd18000}, {0xffd1a000}, {0xffd1c000}, {0xffd1e000}, 
+    {0xffd20000}, {0xffd22000}, {0xffd24000}, {0xffd26000}, 
+    {0xffd28000}, {0xffd2a000}, {0xffd2c000}, {0xffd2e000}, 
+    {0xffd30000}, {0xffd32000}, {0xffd34000}, {0xffd36000}, 
+    {0xffd38000}, {0xffd3a000}, {0xffd3c000}, {0xffd3e000}, 
+    {0xffd40000}, {0xffd42000}, {0xffd44000}, {0xffd46000}, 
+    {0xffd48000}, {0xffd4a000}, {0xffd4c000}, {0xffd4e000}, 
+    {0xffd50000}, {0xffd52000}, {0xffd54000}, {0xffd56000}, 
+    {0xffd58000}, {0xffd5a000}, {0xffd5c000}, {0xffd5e000}, 
+    {0xffd60000}, {0xffd62000}, {0xffd64000}, {0xffd66000}, 
+    {0xffd68000}, {0xffd6a000}, {0xffd6c000}, {0xffd6e000}, 
+    {0xffd70000}, {0xffd72000}, {0xffd74000}, {0xffd76000}, 
+    {0xffd78000}, {0xffd7a000}, {0xffd7c000}, {0xffd7e000}, 
+    {0xffd80000}, {0xffd82000}, {0xffd84000}, {0xffd86000}, 
+    {0xffd88000}, {0xffd8a000}, {0xffd8c000}, {0xffd8e000}, 
+    {0xffd90000}, {0xffd92000}, {0xffd94000}, {0xffd96000}, 
+    {0xffd98000}, {0xffd9a000}, {0xffd9c000}, {0xffd9e000}, 
+    {0xffda0000}, {0xffda2000}, {0xffda4000}, {0xffda6000}, 
+    {0xffda8000}, {0xffdaa000}, {0xffdac000}, {0xffdae000}, 
+    {0xffdb0000}, {0xffdb2000}, {0xffdb4000}, {0xffdb6000}, 
+    {0xffdb8000}, {0xffdba000}, {0xffdbc000}, {0xffdbe000}, 
+    {0xffdc0000}, {0xffdc2000}, {0xffdc4000}, {0xffdc6000}, 
+    {0xffdc8000}, {0xffdca000}, {0xffdcc000}, {0xffdce000}, 
+    {0xffdd0000}, {0xffdd2000}, {0xffdd4000}, {0xffdd6000}, 
+    {0xffdd8000}, {0xffdda000}, {0xffddc000}, {0xffdde000}, 
+    {0xffde0000}, {0xffde2000}, {0xffde4000}, {0xffde6000}, 
+    {0xffde8000}, {0xffdea000}, {0xffdec000}, {0xffdee000}, 
+    {0xffdf0000}, {0xffdf2000}, {0xffdf4000}, {0xffdf6000}, 
+    {0xffdf8000}, {0xffdfa000}, {0xffdfc000}, {0xffdfe000}, 
+    {0xffe00000}, {0xffe02000}, {0xffe04000}, {0xffe06000}, 
+    {0xffe08000}, {0xffe0a000}, {0xffe0c000}, {0xffe0e000}, 
+    {0xffe10000}, {0xffe12000}, {0xffe14000}, {0xffe16000}, 
+    {0xffe18000}, {0xffe1a000}, {0xffe1c000}, {0xffe1e000}, 
+    {0xffe20000}, {0xffe22000}, {0xffe24000}, {0xffe26000}, 
+    {0xffe28000}, {0xffe2a000}, {0xffe2c000}, {0xffe2e000}, 
+    {0xffe30000}, {0xffe32000}, {0xffe34000}, {0xffe36000}, 
+    {0xffe38000}, {0xffe3a000}, {0xffe3c000}, {0xffe3e000}, 
+    {0xffe40000}, {0xffe42000}, {0xffe44000}, {0xffe46000}, 
+    {0xffe48000}, {0xffe4a000}, {0xffe4c000}, {0xffe4e000}, 
+    {0xffe50000}, {0xffe52000}, {0xffe54000}, {0xffe56000}, 
+    {0xffe58000}, {0xffe5a000}, {0xffe5c000}, {0xffe5e000}, 
+    {0xffe60000}, {0xffe62000}, {0xffe64000}, {0xffe66000}, 
+    {0xffe68000}, {0xffe6a000}, {0xffe6c000}, {0xffe6e000}, 
+    {0xffe70000}, {0xffe72000}, {0xffe74000}, {0xffe76000}, 
+    {0xffe78000}, {0xffe7a000}, {0xffe7c000}, {0xffe7e000}, 
+    {0xffe80000}, {0xffe82000}, {0xffe84000}, {0xffe86000}, 
+    {0xffe88000}, {0xffe8a000}, {0xffe8c000}, {0xffe8e000}, 
+    {0xffe90000}, {0xffe92000}, {0xffe94000}, {0xffe96000}, 
+    {0xffe98000}, {0xffe9a000}, {0xffe9c000}, {0xffe9e000}, 
+    {0xffea0000}, {0xffea2000}, {0xffea4000}, {0xffea6000}, 
+    {0xffea8000}, {0xffeaa000}, {0xffeac000}, {0xffeae000}, 
+    {0xffeb0000}, {0xffeb2000}, {0xffeb4000}, {0xffeb6000}, 
+    {0xffeb8000}, {0xffeba000}, {0xffebc000}, {0xffebe000}, 
+    {0xffec0000}, {0xffec2000}, {0xffec4000}, {0xffec6000}, 
+    {0xffec8000}, {0xffeca000}, {0xffecc000}, {0xffece000}, 
+    {0xffed0000}, {0xffed2000}, {0xffed4000}, {0xffed6000}, 
+    {0xffed8000}, {0xffeda000}, {0xffedc000}, {0xffede000}, 
+    {0xffee0000}, {0xffee2000}, {0xffee4000}, {0xffee6000}, 
+    {0xffee8000}, {0xffeea000}, {0xffeec000}, {0xffeee000}, 
+    {0xffef0000}, {0xffef2000}, {0xffef4000}, {0xffef6000}, 
+    {0xffef8000}, {0xffefa000}, {0xffefc000}, {0xffefe000}, 
+    {0xfff00000}, {0xfff02000}, {0xfff04000}, {0xfff06000}, 
+    {0xfff08000}, {0xfff0a000}, {0xfff0c000}, {0xfff0e000}, 
+    {0xfff10000}, {0xfff12000}, {0xfff14000}, {0xfff16000}, 
+    {0xfff18000}, {0xfff1a000}, {0xfff1c000}, {0xfff1e000}, 
+    {0xfff20000}, {0xfff22000}, {0xfff24000}, {0xfff26000}, 
+    {0xfff28000}, {0xfff2a000}, {0xfff2c000}, {0xfff2e000}, 
+    {0xfff30000}, {0xfff32000}, {0xfff34000}, {0xfff36000}, 
+    {0xfff38000}, {0xfff3a000}, {0xfff3c000}, {0xfff3e000}, 
+    {0xfff40000}, {0xfff42000}, {0xfff44000}, {0xfff46000}, 
+    {0xfff48000}, {0xfff4a000}, {0xfff4c000}, {0xfff4e000}, 
+    {0xfff50000}, {0xfff52000}, {0xfff54000}, {0xfff56000}, 
+    {0xfff58000}, {0xfff5a000}, {0xfff5c000}, {0xfff5e000}, 
+    {0xfff60000}, {0xfff62000}, {0xfff64000}, {0xfff66000}, 
+    {0xfff68000}, {0xfff6a000}, {0xfff6c000}, {0xfff6e000}, 
+    {0xfff70000}, {0xfff72000}, {0xfff74000}, {0xfff76000}, 
+    {0xfff78000}, {0xfff7a000}, {0xfff7c000}, {0xfff7e000}, 
+    {0xfff80000}, {0xfff82000}, {0xfff84000}, {0xfff86000}, 
+    {0xfff88000}, {0xfff8a000}, {0xfff8c000}, {0xfff8e000}, 
+    {0xfff90000}, {0xfff92000}, {0xfff94000}, {0xfff96000}, 
+    {0xfff98000}, {0xfff9a000}, {0xfff9c000}, {0xfff9e000}, 
+    {0xfffa0000}, {0xfffa2000}, {0xfffa4000}, {0xfffa6000}, 
+    {0xfffa8000}, {0xfffaa000}, {0xfffac000}, {0xfffae000}, 
+    {0xfffb0000}, {0xfffb2000}, {0xfffb4000}, {0xfffb6000}, 
+    {0xfffb8000}, {0xfffba000}, {0xfffbc000}, {0xfffbe000}, 
+    {0xfffc0000}, {0xfffc2000}, {0xfffc4000}, {0xfffc6000}, 
+    {0xfffc8000}, {0xfffca000}, {0xfffcc000}, {0xfffce000}, 
+    {0xfffd0000}, {0xfffd2000}, {0xfffd4000}, {0xfffd6000}, 
+    {0xfffd8000}, {0xfffda000}, {0xfffdc000}, {0xfffde000}, 
+    {0xfffe0000}, {0xfffe2000}, {0xfffe4000}, {0xfffe6000}, 
+    {0xfffe8000}, {0xfffea000}, {0xfffec000}, {0xfffee000}, 
+    {0xffff0000}, {0xffff2000}, {0xffff4000}, {0xffff6000}, 
+    {0xffff8000}, {0xffffa000}, {0xffffc000}, {0xffffe000}, 
+};
+// clang-format on
diff --git a/src/ImathTest/CMakeLists.txt b/src/ImathTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5882031
--- /dev/null
@@ -0,0 +1,125 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+if("${CMAKE_PROJECT_NAME}" STREQUAL "")
+  # If the project name is set, this is being configured as a part of
+  # Imath.  If there is no project name, it's being configured as a
+  # standalone program linking against an already-installed Imath
+  # library.
+  cmake_minimum_required(VERSION 3.12)
+  project(ImathTest)
+  find_package(Imath)
+endif()
+
+add_executable(ImathTest 
+  main.cpp
+  testBox.cpp
+  testBoxAlgo.cpp
+  testColor.cpp
+  testExtractEuler.cpp
+  testExtractSHRT.cpp
+  testFrustum.cpp
+  testFrustumTest.cpp
+  testFun.cpp
+  testInterval.cpp
+  testInvert.cpp
+  testJacobiEigenSolver.cpp
+  testLineAlgo.cpp
+  testMatrix.cpp
+  testMiscMatrixAlgo.cpp
+  testProcrustes.cpp
+  testQuat.cpp
+  testQuatSetRotation.cpp
+  testQuatSlerp.cpp
+  testRandom.cpp
+  testRoots.cpp
+  testShear.cpp
+  testTinySVD.cpp
+  testVec.cpp
+  testArithmetic.cpp
+  testBitPatterns.cpp
+  testClassification.cpp
+  testError.cpp
+  testFunction.cpp
+  testLimits.cpp
+  testSize.cpp
+  testToFloat.cpp
+  testInterop.cpp
+  testNoInterop.cpp
+)
+
+target_link_libraries(ImathTest Imath::Imath)
+set_target_properties(ImathTest PROPERTIES
+  RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+  )
+
+
+if(NOT "${CMAKE_PROJECT_NAME}" STREQUAL "ImathTest")
+
+  add_executable(ImathHalfCTest half_c_main.c)
+  target_link_libraries(ImathHalfCTest Imath::Config)
+  target_include_directories(ImathHalfCTest PRIVATE "../Imath")
+  #target_compile_options(ImathHalfCTest PRIVATE -mavx2 -mf16c)
+  if (IMATH_USE_HALF_LOOKUP_TABLE)
+    target_link_libraries(ImathHalfCTest Imath::Imath)
+  endif()
+
+  set_target_properties(ImathHalfCTest PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+    )
+  add_test(NAME Imath.half_c_only COMMAND $<TARGET_FILE:ImathHalfCTest>)
+
+endif()
+
+add_executable(ImathHalfPerfTest half_perf_test.cpp)
+set_target_properties(ImathHalfPerfTest PROPERTIES
+RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+)
+target_link_libraries(ImathHalfPerfTest Imath::Imath)
+add_test(NAME Imath.half_perf_test COMMAND $<TARGET_FILE:ImathHalfPerfTest>)
+
+function(DEFINE_IMATH_TESTS)
+  foreach(curtest IN LISTS ARGN)
+    add_test(NAME Imath.${curtest} COMMAND $<TARGET_FILE:ImathTest> ${curtest})
+  endforeach()
+endfunction()
+
+define_imath_tests(
+  testToFloat
+  testSize
+  testArithmetic
+  testNormalizedConversionError
+  testDenormalizedConversionError
+  testRoundingError
+  testBitPatterns
+  testClassification
+  testLimits
+  testHalfLimits
+  testFunction
+  testVec
+  testColor
+  testShear
+  testMatrix
+  testMiscMatrixAlgo
+  testRoots
+  testFun
+  testInvert
+  testInterval
+  testFrustum
+  testRandom
+  testExtractEuler
+  testExtractSHRT
+  testQuat
+  testQuatSetRotation
+  testQuatSlerp
+  testLineAlgo
+  testBoxAlgo
+  testBox
+  testProcrustes
+  testTinySVD
+  testJacobiEigenSolver
+  testFrustumTest
+  testInterop
+  testNoInterop
+)
+
diff --git a/src/ImathTest/eLut.h b/src/ImathTest/eLut.h
new file mode 100644 (file)
index 0000000..305e714
--- /dev/null
@@ -0,0 +1,78 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// This is an automatically generated file.
+// Do not edit.
+//
+
+// clang-format off
+{
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,  1024,  2048,  3072,  4096,  5120,  6144,  7168, 
+     8192,  9216, 10240, 11264, 12288, 13312, 14336, 15360, 
+    16384, 17408, 18432, 19456, 20480, 21504, 22528, 23552, 
+    24576, 25600, 26624, 27648, 28672, 29696,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0, 33792, 34816, 35840, 36864, 37888, 38912, 39936, 
+    40960, 41984, 43008, 44032, 45056, 46080, 47104, 48128, 
+    49152, 50176, 51200, 52224, 53248, 54272, 55296, 56320, 
+    57344, 58368, 59392, 60416, 61440, 62464,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+        0,     0,     0,     0,     0,     0,     0,     0, 
+};
+// clang-format on
diff --git a/src/ImathTest/half_c_main.c b/src/ImathTest/half_c_main.c
new file mode 100644 (file)
index 0000000..5c928a2
--- /dev/null
@@ -0,0 +1,227 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// For the C version test, omit the lookup table, which validates that
+// ``half.h`` works as a "header-only" implementation not requiring
+// the compiled library. Note that the C-language support for half
+// only includes conversion to and from float.
+#define IMATH_HALF_NO_LOOKUP_TABLE
+
+#include <half.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef union
+{
+    uint32_t i;
+    float f;
+} c_half_uif;
+
+static const c_half_uif half_to_float[1 << 16] =
+#include "../Imath/toFloat.h"
+
+static const unsigned short half_eLut[1 << 9] =
+#include "eLut.h"
+
+static short exp_long_convert (int i)
+{
+    int s = (i >> 16) & 0x00008000;
+    int e = ((i >> 23) & 0x000000ff) - (127 - 15);
+    int m = i & 0x007fffff;
+
+    //fprintf( stderr, "old_convert: s %d   e = %d, m = %d\n", s, e, m );
+    if (e <= 0)
+    {
+        if (e < -10)
+        {
+            return s;
+        }
+
+        m = m | 0x00800000;
+
+        int t = 14 - e;
+        int a = (1 << (t - 1)) - 1;
+        int b = (m >> t) & 1;
+
+        m = (m + a + b) >> t;
+
+        //fprintf( stderr, " <OLD> e %d, m: 0x%08X, t %d, a: %d 0x%08X, b: %d 0x%08X\n", e, m, t, a, a, b, b );
+        return s | m;
+    }
+    else if (e == 0xff - (127 - 15))
+    {
+        if (m == 0)
+        {
+            return s | 0x7c00;
+        }
+        else
+        {
+            m >>= 13;
+            return s | 0x7c00 | m | (m == 0);
+        }
+    }
+    else
+    {
+        m = m + 0x00000fff + ((m >> 13) & 1);
+
+        if (m & 0x00800000)
+        {
+            m = 0;  // overflow in significand,
+            e += 1; // adjust exponent
+        }
+        if (e > 30)
+        {
+            return s | 0x7c00; // if this returns, the half becomes an
+        }                      // infinity with the same sign as f.
+        return s | (e << 10) | (m >> 13);
+    }
+}
+
+static uint16_t
+exptable_method (float f)
+{
+    c_half_uif x;
+    uint16_t _h = 0;
+    x.f         = f;
+
+    if (f == 0)
+    {
+        //
+        // Common special case - zero.
+        // Preserve the zero's sign bit.
+        //
+
+        _h = (x.i >> 16);
+    }
+    else
+    {
+        //
+        // We extract the combined sign and exponent, e, from our
+        // floating-point number, f.  Then we convert e to the sign
+        // and exponent of the half number via a table lookup.
+        //
+        // For the most common case, where a normalized half is produced,
+        // the table lookup returns a non-zero value; in this case, all
+        // we have to do is round f's significand to 10 bits and combine
+        // the result with e.
+        //
+        // For all other cases (overflow, zeroes, denormalized numbers
+        // resulting from underflow, infinities and NANs), the table
+        // lookup returns zero, and we call a longer, non-inline function
+        // to do the float-to-half conversion.
+        //
+
+        int e = (x.i >> 23) & 0x000001ff;
+
+        e = half_eLut[e];
+
+        if (e)
+        {
+            //
+            // Simple case - round the significand, m, to 10
+            // bits and combine it with the sign and exponent.
+            //
+
+            int m = x.i & 0x007fffff;
+            _h    = e + ((m + 0x00000fff + ((m >> 13) & 1)) >> 13);
+        }
+        else
+        {
+            //
+            // Difficult case - call a function.
+            //
+            _h = exp_long_convert (x.i);
+        }
+    }
+    return _h;
+}
+
+int
+main (int argc, char* argv[])
+{
+    int ret = 0;
+    c_half_uif conv;
+    half test, test2;
+    conv.f = HALF_DENORM_MIN + HALF_DENORM_MIN * 0.5f;
+    test   = imath_float_to_half (conv.f);
+    test2  = exptable_method (conv.f);
+    if (test != test2)
+    {
+        fprintf (stderr,
+                 "Invalid conversion of %.10g 0x%08X 0x%08X downconvert 0x%04X vs 0x%04X\n",
+                 conv.f,
+                 (conv.i >> 13) & 0x3ff,
+                 (conv.i >> 13) & 0x3ff,
+                 test,
+                 test2);
+        ret = 1;
+    }
+
+    int diffcount = 0;
+    for (int i = 0; i < (1 << 16); ++i)
+    {
+        conv.f = imath_half_to_float ((half) i);
+        if (conv.i != half_to_float[i].i)
+        {
+            uint16_t h  = (uint16_t) i;
+            uint16_t he = (h >> 10) & 0x1f;
+            uint16_t hm = (h & 0x3ff);
+
+#ifdef __F16C__
+            // the intel instructions do something different w/ NaN values than the original half library
+            if (he == 0x1f && isnan (conv.f))
+            {
+                ++diffcount;
+                continue;
+            }
+#endif
+            fprintf (
+                stderr,
+                "half to float %d: C gives %.10f (0x%08X) vs %.10f (0x%08X) [h 0x%04X he 0x%04X hm 0x%04X]\n",
+                i,
+                conv.f,
+                conv.i,
+                half_to_float[i].f,
+                half_to_float[i].i,
+                h,
+                he,
+                hm);
+            ret = 1;
+        }
+    }
+    if (diffcount != 0)
+        fprintf (
+            stderr,
+            "WARNING: Seems safe, but %d NaN values were different between hardware implementation and library implementation\n",
+            diffcount);
+
+    for (int i = 0; i < (1 << 16); ++i)
+    {
+        conv = half_to_float[i];
+        test = imath_float_to_half (conv.f);
+        if (test != i)
+        {
+            // well, we ensure that nan stays nan after conversion by
+            // adding a low bit, so it won't always align
+            int e = (conv.i >> 23) & 0xff;
+            int m = (conv.i & 0x007fffff);
+            if (e == 255 && m != 0)
+                continue;
+
+            fprintf (stderr,
+                     "float to half %d: %.10f (0x%08X) gives %d 0x%04X (e is %d)\n",
+                     i,
+                     conv.f,
+                     conv.i,
+                     (int) test,
+                     test,
+                     e);
+            ret = 1;
+        }
+    }
+
+    return ret;
+}
diff --git a/src/ImathTest/half_perf_test.cpp b/src/ImathTest/half_perf_test.cpp
new file mode 100644 (file)
index 0000000..5a8faa5
--- /dev/null
@@ -0,0 +1,395 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef _WIN32
+#    define _CRT_RAND_S
+#endif
+
+#include <ImathConfig.h>
+#include <ImathRandom.h>
+#include <half.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#ifdef _WIN32
+#    include <windows.h>
+#else
+#    include <time.h>
+#endif
+
+#include <memory>
+
+static const unsigned short imath_float_half_exp_table[1 << 9] =
+#include "eLut.h"
+
+using namespace IMATH_NAMESPACE;
+
+#ifdef IMATH_USE_HALF_LOOKUP_TABLE
+
+static inline float table_half_cast(const half &h)
+{
+    return imath_half_to_float_table[h.bits()].f;
+}
+
+//-----------------------------------------------
+// Overflow handler for float-to-half conversion;
+// generates a hardware floating-point overflow,
+// which may be trapped by the operating system.
+//-----------------------------------------------
+
+static float
+half_overflow()
+{
+    float f = 1e10;
+
+    for (int i = 0; i < 10; i++)
+        f *= f; // this will overflow before the for loop terminates
+
+    return f;
+}
+
+//-----------------------------------------------------
+// Float-to-half conversion -- general case, including
+// zeroes, denormalized numbers and exponent overflows.
+//-----------------------------------------------------
+
+static uint16_t
+long_convert (int i)
+{
+    //
+    // Our floating point number, f, is represented by the bit
+    // pattern in integer i.  Disassemble that bit pattern into
+    // the sign, s, the exponent, e, and the significand, m.
+    // Shift s into the position where it will go in in the
+    // resulting half number.
+    // Adjust e, accounting for the different exponent bias
+    // of float and half (127 versus 15).
+    //
+
+    int s =  (i >> 16) & 0x00008000;
+    int e = ((i >> 23) & 0x000000ff) - (127 - 15);
+    int m =   i        & 0x007fffff;
+
+    //
+    // Now reassemble s, e and m into a half:
+    //
+
+    if (e <= 0)
+    {
+        if (e < -10)
+        {
+            //
+            // E is less than -10.  The absolute value of f is
+            // less than HALF_DENORM_MIN (f may be a small normalized
+            // float, a denormalized float or a zero).
+            //
+            // We convert f to a half zero with the same sign as f.
+            //
+
+            return s;
+        }
+
+        //
+        // E is between -10 and 0.  F is a normalized float
+        // whose magnitude is less than HALF_NRM_MIN.
+        //
+        // We convert f to a denormalized half.
+        //
+
+        //
+        // Add an explicit leading 1 to the significand.
+        //
+
+        m = m | 0x00800000;
+
+        //
+        // Round to m to the nearest (10+e)-bit value (with e between
+        // -10 and 0); in case of a tie, round to the nearest even value.
+        //
+        // Rounding may cause the significand to overflow and make
+        // our number normalized.  Because of the way a half's bits
+        // are laid out, we don't have to treat this case separately;
+        // the code below will handle it correctly.
+        //
+
+        int t = 14 - e;
+        int a = (1 << (t - 1)) - 1;
+        int b = (m >> t) & 1;
+
+        m = (m + a + b) >> t;
+
+        //
+        // Assemble the half from s, e (zero) and m.
+        //
+
+        return s | m;
+    }
+    else if (e == 0xff - (127 - 15))
+    {
+        if (m == 0)
+        {
+            //
+            // F is an infinity; convert f to a half
+            // infinity with the same sign as f.
+            //
+
+            return s | 0x7c00;
+        }
+        else
+        {
+            //
+            // F is a NAN; we produce a half NAN that preserves
+            // the sign bit and the 10 leftmost bits of the
+            // significand of f, with one exception: If the 10
+            // leftmost bits are all zero, the NAN would turn
+            // into an infinity, so we have to set at least one
+            // bit in the significand.
+            //
+
+            m >>= 13;
+            return s | 0x7c00 | m | (m == 0);
+        }
+    }
+    else
+    {
+        //
+        // E is greater than zero.  F is a normalized float.
+        // We try to convert f to a normalized half.
+        //
+
+        //
+        // Round to m to the nearest 10-bit value.  In case of
+        // a tie, round to the nearest even value.
+        //
+
+        m = m + 0x00000fff + ((m >> 13) & 1);
+
+        if (m & 0x00800000)
+        {
+            m = 0;  // overflow in significand,
+            e += 1; // adjust exponent
+        }
+
+        //
+        // Handle exponent overflow
+        //
+
+        if (e > 30)
+        {
+            half_overflow ();        // Cause a hardware floating point overflow;
+            return s | 0x7c00; // if this returns, the half becomes an
+        }                      // infinity with the same sign as f.
+
+        //
+        // Assemble the half from s, e and m.
+        //
+
+        return s | (e << 10) | (m >> 13);
+    }
+}
+
+static inline half exptable_half_constructor(float f)
+{
+    half ret;
+    imath_half_uif x;
+
+    x.f = f;
+
+    if (f == 0)
+    {
+        //
+        // Common special case - zero.
+        // Preserve the zero's sign bit.
+        //
+
+        ret.setBits( (x.i >> 16) );
+    }
+    else
+    {
+        //
+        // We extract the combined sign and exponent, e, from our
+        // floating-point number, f.  Then we convert e to the sign
+        // and exponent of the half number via a table lookup.
+        //
+        // For the most common case, where a normalized half is produced,
+        // the table lookup returns a non-zero value; in this case, all
+        // we have to do is round f's significand to 10 bits and combine
+        // the result with e.
+        //
+        // For all other cases (overflow, zeroes, denormalized numbers
+        // resulting from underflow, infinities and NANs), the table
+        // lookup returns zero, and we call a longer, non-inline function
+        // to do the float-to-half conversion.
+        //
+
+        int e = (x.i >> 23) & 0x000001ff;
+
+        e = imath_float_half_exp_table[e];
+
+        if (e)
+        {
+            //
+            // Simple case - round the significand, m, to 10
+            // bits and combine it with the sign and exponent.
+            //
+
+            int m = x.i & 0x007fffff;
+            ret.setBits (e + ((m + 0x00000fff + ((m >> 13) & 1)) >> 13));
+        }
+        else
+        {
+            //
+            // Difficult case - call a function.
+            //
+
+            ret.setBits (long_convert (x.i));
+        }
+    }
+    return ret;
+}
+#else
+// provide a wrapping function for consistency/readability
+static inline float table_half_cast(const half &h)
+{
+    return static_cast<float>( h );
+}
+
+static inline half exptable_half_constructor(float f)
+{
+    return half {f};
+}
+
+#endif
+
+int64_t
+get_ticks (void)
+{
+#ifdef _WIN32
+    static uint64_t scale = 0;
+    if (scale == 0)
+    {
+        LARGE_INTEGER freq;
+        QueryPerformanceFrequency (&freq);
+        scale = (1000000000 / freq.QuadPart);
+    }
+
+    LARGE_INTEGER ticks;
+    QueryPerformanceCounter (&ticks);
+    return ticks.QuadPart * scale;
+#else
+    struct timespec t;
+    uint64_t nsecs;
+
+    static uint64_t start = 0;
+    if (start == 0)
+    {
+        clock_gettime (CLOCK_MONOTONIC, &t);
+        start = t.tv_sec;
+    }
+
+    clock_gettime (CLOCK_MONOTONIC, &t);
+    nsecs = (t.tv_sec - start) * 1000000000;
+    nsecs += t.tv_nsec;
+    return nsecs;
+#endif
+}
+
+void
+perf_test_half_to_float (float* floats, const uint16_t* halfs, int numentries)
+{
+    const half* halfvals = reinterpret_cast<const half*> (halfs);
+
+    int64_t st = get_ticks();
+    for (int i = 0; i < numentries; ++i)
+        floats[i] = imath_half_to_float (halfs[i]);
+    int64_t et = get_ticks();
+
+    int64_t ost = get_ticks();
+    for (int i = 0; i < numentries; ++i)
+        floats[i] = table_half_cast (halfvals[i]);
+    int64_t oet = get_ticks();
+
+    int64_t onanos = (oet - ost);
+    int64_t nnanos = (et - st);
+    fprintf (stderr,
+             "half -> float Old: %10lld (%g ns) New: %10lld (%g ns) (%10lld)\n",
+             (long long) onanos,
+             (double) onanos / ((double) numentries),
+             (long long) nnanos,
+             (double) nnanos / ((double) numentries),
+             ((long long) (onanos - nnanos)));
+}
+
+void
+perf_test_float_to_half (uint16_t* halfs, const float* floats, int numentries)
+{
+    half* halfvals = reinterpret_cast<half*> (halfs);
+
+    int64_t st = get_ticks();
+    for (int i = 0; i < numentries; ++i)
+        halfs[i] = imath_float_to_half (floats[i]);
+    int64_t et = get_ticks();
+
+    int64_t ost = get_ticks();
+    for (int i = 0; i < numentries; ++i)
+        halfvals[i] = exptable_half_constructor (floats[i]);
+    int64_t oet = get_ticks();
+
+    int64_t onanos = (oet - ost);
+    int64_t nnanos = (et - st);
+    fprintf (stderr,
+             "float -> half Old: %10lld (%g ns) New: %10lld (%g ns) (%10lld)\n",
+             (long long) onanos,
+             (double) onanos / ((double) numentries),
+             (long long) nnanos,
+             (double) nnanos / ((double) numentries),
+             ((long long) (onanos - nnanos)));
+}
+
+int
+main (int argc, char* argv[])
+{
+    int ret        = 0;
+    int numentries = 1920 * 1080 * 3;
+    if (argc > 1)
+    {
+        numentries = atoi (argv[1]);
+
+        if (numentries <= 0)
+        {
+            fprintf (stderr, "Bad entry count '%s'\n", argv[1]);
+            ret = 1;
+        }
+    }
+
+    if (numentries > 0)
+    {
+        uint16_t* halfs = new uint16_t[numentries];
+        float* floats   = new float[numentries];
+
+        if (halfs && floats)
+        {
+            Rand48 r(numentries);
+            for (int i = 0; i < numentries; ++i)
+            {
+                halfs[i]  = (uint16_t) r.nexti();
+                floats[i] = imath_half_to_float (halfs[i]);
+            }
+            perf_test_half_to_float (floats, halfs, numentries);
+
+            // test float -> half with real-world values
+            for (int i = 0; i < numentries; ++i)
+                floats[i] = float(r.nextf(-65504, 65504));
+            perf_test_float_to_half (halfs, floats, numentries);
+        }
+
+        delete[] halfs;
+        delete[] floats;
+    }
+
+    return ret;
+}
diff --git a/src/ImathTest/main.cpp b/src/ImathTest/main.cpp
new file mode 100644 (file)
index 0000000..427a01a
--- /dev/null
@@ -0,0 +1,96 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include "testArithmetic.h"
+#include "testBitPatterns.h"
+#include "testClassification.h"
+#include "testError.h"
+#include "testFunction.h"
+#include "testLimits.h"
+#include "testSize.h"
+#include "testToFloat.h"
+#include "testBox.h"
+#include "testBoxAlgo.h"
+#include "testColor.h"
+#include "testExtractEuler.h"
+#include "testExtractSHRT.h"
+#include "testFrustum.h"
+#include "testFrustumTest.h"
+#include "testFun.h"
+#include "testInterop.h"
+#include "testNoInterop.h"
+#include "testInterval.h"
+#include "testInvert.h"
+#include "testJacobiEigenSolver.h"
+#include "testLineAlgo.h"
+#include "testMatrix.h"
+#include "testMiscMatrixAlgo.h"
+#include "testProcrustes.h"
+#include "testQuat.h"
+#include "testQuatSetRotation.h"
+#include "testQuatSlerp.h"
+#include "testRandom.h"
+#include "testRoots.h"
+#include "testShear.h"
+#include "testTinySVD.h"
+#include "testVec.h"
+
+#include <iostream>
+#include <string.h>
+
+#define TEST(x)                                                                                    \
+    if (argc < 2 || !strcmp (argv[1], #x))                                                         \
+        x();
+
+int
+main (int argc, char* argv[])
+{
+    // NB: If you add a test here, make sure to enumerate it in the
+    // CMakeLists.txt so it runs as part of the test suite
+    TEST (testToFloat);
+    TEST (testSize);
+    TEST (testArithmetic);
+    TEST (testNormalizedConversionError);
+    TEST (testDenormalizedConversionError);
+    TEST (testRoundingError);
+    TEST (testBitPatterns);
+    TEST (testClassification);
+    TEST (testLimits);
+    TEST (testHalfLimits);
+    TEST (testFunction);
+    TEST (testVec);
+    TEST (testColor);
+    TEST (testShear);
+    TEST (testMatrix);
+    TEST (testMiscMatrixAlgo);
+    TEST (testRoots);
+    TEST (testFun);
+    TEST (testInvert);
+    TEST (testInterval);
+    TEST (testFrustum);
+    TEST (testRandom);
+    TEST (testExtractEuler);
+    TEST (testExtractSHRT);
+    TEST (testQuat);
+    TEST (testQuatSetRotation);
+    TEST (testQuatSlerp);
+    TEST (testLineAlgo);
+    TEST (testBoxAlgo);
+    TEST (testBox);
+    TEST (testProcrustes);
+    TEST (testTinySVD);
+    TEST (testJacobiEigenSolver);
+    TEST (testFrustumTest);
+    TEST (testInterop);
+    TEST (testNoInterop);
+    // NB: If you add a test here, make sure to enumerate it in the
+    // CMakeLists.txt so it runs as part of the test suite
+
+    return 0;
+}
diff --git a/src/ImathTest/testArithmetic.cpp b/src/ImathTest/testArithmetic.cpp
new file mode 100644 (file)
index 0000000..0b1d60a
--- /dev/null
@@ -0,0 +1,69 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <half.h>
+#include <assert.h>
+#include <iostream>
+#include "testArithmetic.h"
+
+using namespace std;
+
+void
+testArithmetic()
+{
+    cout << "basic arithmetic operations:\n";
+
+    float f1 (1);
+    float f2 (2);
+    half h1 (3);
+    half h2 (4);
+
+    cout << "f1 = " << f1
+         << ", "
+            "f2 = "
+         << f2
+         << ", "
+            "h1 = "
+         << h1
+         << ", "
+            "h2 = "
+         << h2 << endl;
+
+    h1 = f1 + f2;
+    assert (h1 == 3);
+
+    cout << "h1 = f1 + f2: " << h1 << endl;
+
+    h2 += f1;
+    assert (h2 == 5);
+
+    cout << "h2 += f1: " << h2 << endl;
+
+    h2 = h1 + h2;
+    assert (h2 == 8);
+
+    cout << "h2 = h1 + h2: " << h2 << endl;
+
+    h2 += h1;
+    assert (h2 == 11);
+
+    cout << "h2 += h1: " << h2 << endl;
+
+    h1 = h2;
+    assert (h1 == 11);
+
+    cout << "h1 = h2: " << h1 << endl;
+
+    h2 = -h1;
+    assert (h2 == -11);
+
+    cout << "h2 = -h1: " << h2 << endl;
+
+    cout << "ok\n\n" << flush;
+}
diff --git a/src/ImathTest/testArithmetic.h b/src/ImathTest/testArithmetic.h
new file mode 100644 (file)
index 0000000..c703579
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testArithmetic();
diff --git a/src/ImathTest/testBitPatterns.cpp b/src/ImathTest/testBitPatterns.cpp
new file mode 100644 (file)
index 0000000..d341810
--- /dev/null
@@ -0,0 +1,433 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <half.h>
+#include <assert.h>
+#include <float.h>
+#include <iostream>
+#include <string.h>
+#include "testBitPatterns.h"
+
+using namespace std;
+
+namespace
+{
+
+bool
+equalBitPatterns (const char* b1, const char* b2)
+{
+    //
+    // Returns true if the characters in zero-terminated string b1
+    // are the same as the charaters in string b2, except for places
+    // where b1 or b2 contains an 'X'.  For example:
+    //
+    // equalBitPatterns ("100", "100") returns true
+    // equalBitPatterns ("100", "101") returns false
+    // equalBitPatterns ("10X", "101") returns true
+    // equalBitPatterns ("10X", "100") returns true
+    //
+
+    while (*b1 && *b2)
+    {
+        if (*b1 != *b2 && *b1 != 'X' && *b2 != 'X')
+            return false;
+
+        ++b1;
+        ++b2;
+    }
+
+    return !(*b1 || *b2);
+}
+
+void
+testBits (float f, const char bh[19], const char bg[35])
+{
+    half h (f);
+    float g (h);
+
+    cout.width (15);
+    cout.precision (8);
+    cout << f << "    ";
+    printBits (cout, f);
+    cout << "    ";
+    printBits (cout, h);
+    cout << '\n';
+    cout.width (15);
+    cout << g << "    ";
+    printBits (cout, g);
+    cout << "\n\n";
+
+    if (bh || bg)
+    {
+        char ch[19], cg[35];
+
+        printBits (ch, h);
+        printBits (cg, g);
+
+        if (!equalBitPatterns (ch, bh))
+        {
+            cout << "error: expected " << bh << ", got " << ch << endl;
+            assert (false);
+        }
+
+        if (!equalBitPatterns (cg, bg))
+        {
+            cout << "error: expected " << bg << ", got " << cg << endl;
+            assert (false);
+        }
+    }
+}
+
+float
+floatPosInfinity()
+{
+    half::uif x;
+    x.i = 0x7f800000;
+    return x.f;
+}
+
+float
+floatNegInfinity()
+{
+    half::uif x;
+    x.i = 0xff800000;
+    return x.f;
+}
+
+float
+floatPosQNan1()
+{
+    half::uif x;
+    x.i = 0x7fffffff;
+    return x.f;
+}
+
+float
+floatNegQNan1()
+{
+    half::uif x;
+    x.i = 0xffffffff;
+    return x.f;
+}
+
+float
+floatPosQNan2()
+{
+    half::uif x;
+    x.i = 0x7fd55555;
+    return x.f;
+}
+
+float
+floatNegQNan2()
+{
+    half::uif x;
+    x.i = 0xffd55555;
+    return x.f;
+}
+
+} // namespace
+
+void
+testBitPatterns()
+{
+    cout << "specific bit patterns\n\n";
+
+    //
+    // Numbers close to 1.0
+    //
+
+    testBits (1.0f, "0 01111 0000000000", "0 01111111 00000000000000000000000");
+    testBits (1.0f + HALF_EPSILON, "0 01111 0000000001", "0 01111111 00000000010000000000000");
+    testBits (1.0f + HALF_EPSILON * 0.5f,
+              "0 01111 0000000000",
+              "0 01111111 00000000000000000000000");
+    testBits (1.0f + HALF_EPSILON * 0.4999f,
+              "0 01111 0000000000",
+              "0 01111111 00000000000000000000000");
+    testBits (1.0f + HALF_EPSILON * 0.5001f,
+              "0 01111 0000000001",
+              "0 01111111 00000000010000000000000");
+    testBits (1.0f + HALF_EPSILON + HALF_EPSILON,
+              "0 01111 0000000010",
+              "0 01111111 00000000100000000000000");
+    testBits (1.0f + HALF_EPSILON + HALF_EPSILON * 0.5f,
+              "0 01111 0000000010",
+              "0 01111111 00000000100000000000000");
+    testBits (1.0f + HALF_EPSILON + HALF_EPSILON * 0.4999f,
+              "0 01111 0000000001",
+              "0 01111111 00000000010000000000000");
+    testBits (1.0f + HALF_EPSILON + HALF_EPSILON * 0.5001f,
+              "0 01111 0000000010",
+              "0 01111111 00000000100000000000000");
+    testBits (1.0f - HALF_EPSILON * 0.5f,
+              "0 01110 1111111111",
+              "0 01111110 11111111110000000000000");
+    testBits (1.0f - HALF_EPSILON * 0.5f * 0.5f,
+              "0 01111 0000000000",
+              "0 01111111 00000000000000000000000");
+    testBits (1.0f - HALF_EPSILON * 0.5f * 0.4999f,
+              "0 01111 0000000000",
+              "0 01111111 00000000000000000000000");
+    testBits (1.0f - HALF_EPSILON * 0.5f * 0.5001f,
+              "0 01110 1111111111",
+              "0 01111110 11111111110000000000000");
+
+    //
+    // Numbers close to HALF_DENORM_MIN
+    //
+
+    testBits (HALF_DENORM_MIN, "0 00000 0000000001", "0 01100111 00000000000000000000000");
+    testBits (HALF_DENORM_MIN + HALF_DENORM_MIN, "0 00000 0000000010", "0 01101000 00000000000000000000000");
+    testBits (HALF_DENORM_MIN + HALF_DENORM_MIN * 0.5f,
+              "0 00000 0000000010",
+              "0 01101000 00000000000000000000000");
+    testBits (HALF_DENORM_MIN + HALF_DENORM_MIN * 0.4999f,
+              "0 00000 0000000001",
+              "0 01100111 00000000000000000000000");
+    testBits (HALF_DENORM_MIN + HALF_DENORM_MIN * 0.5001f,
+              "0 00000 0000000010",
+              "0 01101000 00000000000000000000000");
+    testBits (HALF_DENORM_MIN - HALF_DENORM_MIN, // NOSONAR - suppress SonarCloud bug report.
+              "0 00000 0000000000",
+              "0 00000000 00000000000000000000000");
+    testBits (HALF_DENORM_MIN - HALF_DENORM_MIN * 0.5f,
+              "0 00000 0000000000",
+              "0 00000000 00000000000000000000000");
+    testBits (HALF_DENORM_MIN - HALF_DENORM_MIN * 0.4999f,
+              "0 00000 0000000001",
+              "0 01100111 00000000000000000000000");
+    testBits (HALF_DENORM_MIN - HALF_DENORM_MIN * 0.5001f,
+              "0 00000 0000000000",
+              "0 00000000 00000000000000000000000");
+
+    //
+    // Numbers close to HALF_NRM_MIN
+    //
+
+    testBits (HALF_NRM_MIN, "0 00001 0000000000", "0 01110001 00000000000000000000000");
+    testBits (HALF_NRM_MIN + HALF_DENORM_MIN, "0 00001 0000000001", "0 01110001 00000000010000000000000");
+    testBits (HALF_NRM_MIN + HALF_DENORM_MIN * 0.5f,
+              "0 00001 0000000000",
+              "0 01110001 00000000000000000000000");
+    testBits (HALF_NRM_MIN + HALF_DENORM_MIN * 0.4999f,
+              "0 00001 0000000000",
+              "0 01110001 00000000000000000000000");
+    testBits (HALF_NRM_MIN + HALF_DENORM_MIN * 0.5001f,
+              "0 00001 0000000001",
+              "0 01110001 00000000010000000000000");
+    testBits (HALF_NRM_MIN - HALF_DENORM_MIN, "0 00000 1111111111", "0 01110000 11111111100000000000000");
+    testBits (HALF_NRM_MIN - HALF_DENORM_MIN * 0.5f,
+              "0 00001 0000000000",
+              "0 01110001 00000000000000000000000");
+    testBits (HALF_NRM_MIN - HALF_DENORM_MIN * 0.49995f,
+              "0 00001 0000000000",
+              "0 01110001 00000000000000000000000");
+    testBits (HALF_NRM_MIN - HALF_DENORM_MIN * 0.50005f,
+              "0 00000 1111111111",
+              "0 01110000 11111111100000000000000");
+
+    //
+    // Small positive integers and simple decimal fractions
+    //
+
+    testBits (2, "0 10000 0000000000", "0 10000000 00000000000000000000000");
+    testBits (3, "0 10000 1000000000", "0 10000000 10000000000000000000000");
+    testBits (10, "0 10010 0100000000", "0 10000010 01000000000000000000000");
+    testBits (0.1f, "0 01011 1001100110", "0 01111011 10011001100000000000000");
+    testBits (0.2f, "0 01100 1001100110", "0 01111100 10011001100000000000000");
+    testBits (0.3f, "0 01101 0011001101", "0 01111101 00110011010000000000000");
+
+    //
+    // Numbers close to HALF_MAX
+    //
+
+    testBits (HALF_MAX, "0 11110 1111111111", "0 10001110 11111111110000000000000");
+    testBits ((1 << HALF_MAX_EXP) * 1.0,
+              "0 11111 0000000000",                  // +infinity
+              "0 11111111 00000000000000000000000"); // +infinity
+    testBits ((1 << HALF_MAX_EXP) * (1.0f - HALF_EPSILON * 0.25f),
+              "0 11111 0000000000",                  // +infinity
+              "0 11111111 00000000000000000000000"); // +infinity
+    testBits ((1 << HALF_MAX_EXP) * (1.0f - HALF_EPSILON * 0.25005f),
+              "0 11110 1111111111",
+              "0 10001110 11111111110000000000000");
+    testBits ((1 << HALF_MAX_EXP) * (1.0f - HALF_EPSILON * 0.24995f),
+              "0 11111 0000000000",                  // +infinity
+              "0 11111111 00000000000000000000000"); // +infinity
+
+    //
+    // Large positive numbers, positive infinity and NANs
+    //
+
+    testBits (HALF_MAX * HALF_MAX,
+              "0 11111 0000000000",                  // +infinity
+              "0 11111111 00000000000000000000000"); // +infinity
+    testBits (FLT_MAX,
+              "0 11111 0000000000",                  // +infinity
+              "0 11111111 00000000000000000000000"); // +infinity
+    testBits (floatPosInfinity(),
+              "0 11111 0000000000",                  // +infinity
+              "0 11111111 00000000000000000000000"); // +infinity
+    testBits (floatPosQNan1(),
+              "0 11111 1111111111",                  // nan
+              "0 11111111 11111111110000000000000"); // nan
+    testBits (floatPosQNan2(),
+              "0 11111 1010101010",                  // nan
+              "0 11111111 10101010100000000000000"); // nan
+
+    //
+    // Numbers close to -1.0
+    //
+
+    testBits (-1.0, "1 01111 0000000000", "1 01111111 00000000000000000000000");
+    testBits (-(1.0f + HALF_EPSILON), "1 01111 0000000001", "1 01111111 00000000010000000000000");
+    testBits (-(1.0f + HALF_EPSILON * 0.5f),
+              "1 01111 0000000000",
+              "1 01111111 00000000000000000000000");
+    testBits (-(1.0f + HALF_EPSILON * 0.4999f),
+              "1 01111 0000000000",
+              "1 01111111 00000000000000000000000");
+    testBits (-(1.0f + HALF_EPSILON * 0.5001f),
+              "1 01111 0000000001",
+              "1 01111111 00000000010000000000000");
+    testBits (-(1.0f + HALF_EPSILON + HALF_EPSILON),
+              "1 01111 0000000010",
+              "1 01111111 00000000100000000000000");
+    testBits (-(1.0f + HALF_EPSILON + HALF_EPSILON * 0.5f),
+              "1 01111 0000000010",
+              "1 01111111 00000000100000000000000");
+    testBits (-(1.0f + HALF_EPSILON + HALF_EPSILON * 0.4999f),
+              "1 01111 0000000001",
+              "1 01111111 00000000010000000000000");
+    testBits (-(1.0f + HALF_EPSILON + HALF_EPSILON * 0.5001f),
+              "1 01111 0000000010",
+              "1 01111111 00000000100000000000000");
+    testBits (-(1.0f - HALF_EPSILON * 0.5f),
+              "1 01110 1111111111",
+              "1 01111110 11111111110000000000000");
+    testBits (-(1.0f - HALF_EPSILON * 0.5f * 0.5f),
+              "1 01111 0000000000",
+              "1 01111111 00000000000000000000000");
+    testBits (-(1.0f - HALF_EPSILON * 0.5f * 0.4999f),
+              "1 01111 0000000000",
+              "1 01111111 00000000000000000000000");
+    testBits (-(1.0f - HALF_EPSILON * 0.5f * 0.5001f),
+              "1 01110 1111111111",
+              "1 01111110 11111111110000000000000");
+
+    //
+    // Numbers close to -HALF_DENORM_MIN
+    //
+
+    testBits (-HALF_DENORM_MIN, "1 00000 0000000001", "1 01100111 00000000000000000000000");
+    testBits (-(HALF_DENORM_MIN + HALF_DENORM_MIN), "1 00000 0000000010", "1 01101000 00000000000000000000000");
+    testBits (-(HALF_DENORM_MIN + HALF_DENORM_MIN * 0.5f),
+              "1 00000 0000000010",
+              "1 01101000 00000000000000000000000");
+    testBits (-(HALF_DENORM_MIN + HALF_DENORM_MIN * 0.4999f),
+              "1 00000 0000000001",
+              "1 01100111 00000000000000000000000");
+    testBits (-(HALF_DENORM_MIN + HALF_DENORM_MIN * 0.5001f),
+              "1 00000 0000000010",
+              "1 01101000 00000000000000000000000");
+    testBits (-(HALF_DENORM_MIN - HALF_DENORM_MIN), // NOSONAR - suppress SonarCloud bug report.
+              "X 00000 0000000000",
+              "X 00000000 00000000000000000000000");
+    testBits (-(HALF_DENORM_MIN - HALF_DENORM_MIN * 0.5f),
+              "1 00000 0000000000",
+              "1 00000000 00000000000000000000000");
+    testBits (-(HALF_DENORM_MIN - HALF_DENORM_MIN * 0.4999f),
+              "1 00000 0000000001",
+              "1 01100111 00000000000000000000000");
+    testBits (-(HALF_DENORM_MIN - HALF_DENORM_MIN * 0.5001f),
+              "1 00000 0000000000",
+              "1 00000000 00000000000000000000000");
+
+    //
+    // Numbers close to -HALF_NRM_MIN
+    //
+
+    testBits (-HALF_NRM_MIN, "1 00001 0000000000", "1 01110001 00000000000000000000000");
+    testBits (-(HALF_NRM_MIN + HALF_DENORM_MIN),
+              "1 00001 0000000001",
+              "1 01110001 00000000010000000000000");
+    testBits (-(HALF_NRM_MIN + HALF_DENORM_MIN * 0.5f),
+              "1 00001 0000000000",
+              "1 01110001 00000000000000000000000");
+    testBits (-(HALF_NRM_MIN + HALF_DENORM_MIN * 0.4999f),
+              "1 00001 0000000000",
+              "1 01110001 00000000000000000000000");
+    testBits (-(HALF_NRM_MIN + HALF_DENORM_MIN * 0.5001f),
+              "1 00001 0000000001",
+              "1 01110001 00000000010000000000000");
+    testBits (-(HALF_NRM_MIN - HALF_DENORM_MIN),
+              "1 00000 1111111111",
+              "1 01110000 11111111100000000000000");
+    testBits (-(HALF_NRM_MIN - HALF_DENORM_MIN * 0.5f),
+              "1 00001 0000000000",
+              "1 01110001 00000000000000000000000");
+    testBits (-(HALF_NRM_MIN - HALF_DENORM_MIN * 0.49995f),
+              "1 00001 0000000000",
+              "1 01110001 00000000000000000000000");
+    testBits (-(HALF_NRM_MIN - HALF_DENORM_MIN * 0.50005f),
+              "1 00000 1111111111",
+              "1 01110000 11111111100000000000000");
+
+    //
+    // Small negative integers and simple decimal fractions
+    //
+
+    testBits (-2, "1 10000 0000000000", "1 10000000 00000000000000000000000");
+    testBits (-3, "1 10000 1000000000", "1 10000000 10000000000000000000000");
+    testBits (-10, "1 10010 0100000000", "1 10000010 01000000000000000000000");
+    testBits (-0.1f, "1 01011 1001100110", "1 01111011 10011001100000000000000");
+    testBits (-0.2f, "1 01100 1001100110", "1 01111100 10011001100000000000000");
+    testBits (-0.3f, "1 01101 0011001101", "1 01111101 00110011010000000000000");
+
+    //
+    // Numbers close to -HALF_MAX
+    //
+
+    testBits (-HALF_MAX, "1 11110 1111111111", "1 10001110 11111111110000000000000");
+    testBits (-(1 << HALF_MAX_EXP) * 1.0f,
+              "1 11111 0000000000",                  // +infinity
+              "1 11111111 00000000000000000000000"); // +infinity
+    testBits (-(1 << HALF_MAX_EXP) * (1.0f - HALF_EPSILON * 0.25f),
+              "1 11111 0000000000",                  // +infinity
+              "1 11111111 00000000000000000000000"); // +infinity
+    testBits (-(1 << HALF_MAX_EXP) * (1.0f - HALF_EPSILON * 0.25005f),
+              "1 11110 1111111111",
+              "1 10001110 11111111110000000000000");
+    testBits (-(1 << HALF_MAX_EXP) * (1.0f - HALF_EPSILON * 0.24995f),
+              "1 11111 0000000000",                  // +infinity
+              "1 11111111 00000000000000000000000"); // +infinity
+
+    //
+    // Large negative numbers, negative infinity and NANs
+    //
+
+    testBits (-HALF_MAX * HALF_MAX,
+              "1 11111 0000000000",                  // +infinity
+              "1 11111111 00000000000000000000000"); // +infinity
+    testBits (-FLT_MAX,
+              "1 11111 0000000000",                  // +infinity
+              "1 11111111 00000000000000000000000"); // +infinity
+    testBits (floatNegInfinity(),
+              "1 11111 0000000000",                  // +infinity
+              "1 11111111 00000000000000000000000"); // +infinity
+    testBits (floatNegQNan1(),
+              "1 11111 1111111111",                  // nan
+              "1 11111111 11111111110000000000000"); // nan
+    testBits (floatNegQNan2(),
+              "1 11111 1010101010",                  // nan
+              "1 11111111 10101010100000000000000"); // nan
+
+    cout << "ok\n\n" << flush;
+}
diff --git a/src/ImathTest/testBitPatterns.h b/src/ImathTest/testBitPatterns.h
new file mode 100644 (file)
index 0000000..62192b9
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testBitPatterns();
diff --git a/src/ImathTest/testBox.cpp b/src/ImathTest/testBox.cpp
new file mode 100644 (file)
index 0000000..d9c1f66
--- /dev/null
@@ -0,0 +1,1210 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathBoxAlgo.h>
+#include <ImathRandom.h>
+
+#include <algorithm>
+#include <assert.h>
+#include <iostream>
+#include <typeinfo>
+#include <vector>
+#include "testBoxAlgo.h"
+
+// Include ImathForward *after* other headers to validate forward declarations
+#include <ImathForward.h>
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+//
+// Test case generation utility - create a vector of IMATH_INTERNAL_NAMESPACE::Vec{2,3,4}
+// with all permutations of integers 1..T::dimensions().
+//
+// Algorithm from www.bearcave.com/random_hacks/permute.html
+//
+template <class T>
+static void
+addItem (const std::vector<int>& value, std::vector<T>& perms)
+{
+    T p;
+    for (unsigned int i = 0; i < value.size(); i++)
+    {
+        p[i] = static_cast<typename T::BaseType>(value[i]);
+    }
+    perms.push_back (p);
+}
+
+template <class T>
+static void
+visit (int& level, int n, int k, std::vector<int>& value, std::vector<T>& perms)
+{
+    level    = level + 1;
+    value[k] = level;
+
+    if (level == n)
+        addItem (value, perms);
+    else
+        for (int i = 0; i < n; i++)
+            if (value[i] == 0)
+                visit (level, n, i, value, perms);
+
+    level    = level - 1;
+    value[k] = 0;
+}
+
+template <class T>
+static void
+permutations (std::vector<T>& perms)
+{
+    std::vector<int> value (T::dimensions());
+    int level = -1;
+    int n     = T::dimensions();
+
+    visit (level, n, 0, value, perms);
+}
+
+template <class T>
+static void
+testConstructors (const char* type)
+{
+    cout << "    constructors for type " << type << endl;
+
+    //
+    // Empty
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        assert (b.min == T (T::baseTypeMax()) && b.max == T (T::baseTypeLowest()));
+    }
+
+    //
+    // Single point
+    //
+    {
+        T p;
+        for (unsigned int i = 0; i < T::dimensions (); i++)
+            p[i] = static_cast<typename T::BaseType>(i);
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (p);
+        assert (b.min == p && b.max == p);
+    }
+
+    //
+    // Min and max
+    //
+    {
+        T p0;
+        T p1;
+        for (unsigned int i = 0; i < T::dimensions(); i++)
+        {
+            p0[i] = static_cast<typename T::BaseType>(i);
+            p1[i] = static_cast<typename T::BaseType>(10 * T::dimensions () - i - 1);
+        }
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (p0, p1);
+        assert (b.min == p0 && b.max == p1);
+    }
+}
+
+template <class T>
+void
+testMakeEmpty (const char* type)
+{
+    cout << "    makeEmpty() for type " << type << endl;
+
+    //
+    // Empty box
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        b.makeEmpty();
+        assert (b.min == T (T::baseTypeMax()) && b.max == T (T::baseTypeLowest()));
+    }
+
+    //
+    // Non-empty, has volume
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (T (-1), T (1));
+        b.makeEmpty();
+        assert (b.min == T (T::baseTypeMax()) && b.max == T (T::baseTypeLowest()));
+    }
+
+    //
+    // Non-empty, no volume
+    // Boxes are:
+    //    2D: [(0, 0),       (0, 1)      ]
+    //    3D: [(0, 0, 0),    (0, 0, 1)   ]
+    //    4D: [(0, 0, 0, 0), (0, 0, 0, 1)]
+    //
+    {
+        T min (0);
+        T max (0);
+        max[T::dimensions() - 1] = 1;
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (min, max);
+        b.makeEmpty();
+        assert (b.min == T (T::baseTypeMax()) && b.max == T (T::baseTypeLowest()));
+    }
+}
+
+template <class T>
+void
+testMakeInfinite (const char* type)
+{
+    cout << "    makeInfinite() for type " << type << endl;
+
+    //
+    // Infinite box
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        b.makeInfinite ();
+        assert (
+            b.min == T (T::baseTypeLowest ()) &&
+            b.max == T (T::baseTypeMax ()));
+
+        for (unsigned int i=0; i<b.min.dimensions(); i++)
+        {
+            IMATH_INTERNAL_NAMESPACE::Box<T> c = b;
+            c.max[i] = 0;
+            assert (!c.isInfinite());
+
+            c = b;
+            c.min[i] = 0;
+            assert (!c.isInfinite());
+        }
+    }
+
+    //
+    // Non-empty, has volume
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (T (-1), T (1));
+        b.makeInfinite();
+        assert (b.min == T (T::baseTypeLowest()) && b.max == T (T::baseTypeMax()));
+    }
+
+    //
+    // Non-empty, no volume
+    // Boxes are:
+    //    2D: [(0, 0),       (0, 1)      ]
+    //    3D: [(0, 0, 0),    (0, 0, 1)   ]
+    //    4D: [(0, 0, 0, 0), (0, 0, 0, 1)]
+    //
+    {
+        T min (0);
+        T max (0);
+        max[T::dimensions() - 1] = 1;
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (min, max);
+        b.makeInfinite();
+        assert (b.min == T (T::baseTypeLowest()) && b.max == T (T::baseTypeMax()));
+    }
+}
+
+template <class T>
+void
+testExtendByPoint (const char* type)
+{
+    cout << "    extendBy() point for type " << type << endl;
+
+    IMATH_INTERNAL_NAMESPACE::Rand32 rand (0);
+
+    const unsigned int iters = 10;
+
+    //
+    // Extend empty box with a single point.
+    //
+    for (unsigned int i = 0; i < iters; i++)
+    {
+        T p;
+        for (unsigned int j = 0; j < T::dimensions(); j++)
+            p[j] = typename T::BaseType (rand.nextf (-12345, 12345));
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        b.extendBy (p);
+        assert (b.min == p && b.max == p);
+    }
+
+    //
+    // Extend empty box with a number of random points. Note that
+    // this also covers extending a non-empty box.
+    //
+    for (unsigned int i = 0; i < iters; i++)
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+
+        T min;
+        T max;
+
+        for (unsigned int j = 0; j < i; j++)
+        {
+            T p;
+            for (unsigned int k = 0; k < T::dimensions(); k++)
+                p[k] = typename T::BaseType (rand.nextf (-12345, 12345));
+
+            if (j == 0)
+            {
+                min = p;
+                max = p;
+            }
+            for (unsigned int k = 0; k < T::dimensions(); k++)
+            {
+                min[k] = std::min (min[k], p[k]);
+                max[k] = std::max (max[k], p[k]);
+            }
+
+            b.extendBy (p);
+
+            assert (b.min == min && b.max == max);
+        }
+    }
+}
+
+template <class T>
+void
+testExtendByBox (const char* type)
+{
+    cout << "    extendBy() box for type " << type << endl;
+
+    //
+    // Extend empty box with an empty box;
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        b.extendBy (IMATH_INTERNAL_NAMESPACE::Box<T>());
+        assert (b.min == T (T::baseTypeMax()) && b.max == T (T::baseTypeLowest()));
+    }
+
+    //
+    // Extend empty box with a non-empty box and vice versa.
+    //
+    {
+        std::vector<T> perms;
+        permutations (perms);
+
+        for (unsigned int i = 0; i < perms.size(); i++)
+        {
+            for (unsigned int j = 0; j < perms.size(); j++)
+            {
+                T p0 = -perms[i];
+                T p1 = perms[j];
+
+                IMATH_INTERNAL_NAMESPACE::Box<T> b0;
+                b0.extendBy (IMATH_INTERNAL_NAMESPACE::Box<T> (p0, p1));
+                assert (b0.min == p0 && b0.max == p1);
+
+                IMATH_INTERNAL_NAMESPACE::Box<T> b1 (p0, p1);
+                b1.extendBy (IMATH_INTERNAL_NAMESPACE::Box<T>());
+                assert (b1.min == p0 && b1.max == p1);
+            }
+        }
+    }
+
+    //
+    // Extend non-empty box with non-empty box. Starts with empty, then builds.
+    //
+    IMATH_INTERNAL_NAMESPACE::Rand32 rand (0);
+    const unsigned int iters = 10;
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+
+        T min, max;
+
+        for (unsigned int i = 1; i < iters; i++)
+        {
+            T p0;
+            T p1;
+            for (unsigned int k = 0; k < T::dimensions(); k++)
+            {
+                p0[k] = typename T::BaseType (rand.nextf (0, 999));
+                p1[k] = typename T::BaseType (rand.nextf (1000, 1999));
+            }
+
+            min = b.min;
+            max = b.max;
+            for (unsigned int k = 0; k < T::dimensions(); k++)
+            {
+                min[k] = std::min (min[k], p0[k]);
+                max[k] = std::max (max[k], p1[k]);
+            }
+            b.extendBy (IMATH_INTERNAL_NAMESPACE::Box<T> (p0, p1));
+
+            assert (b.min == min && b.max == max);
+        }
+    }
+}
+
+template <class T>
+void
+testComparators (const char* type)
+{
+    cout << "    comparators for type " << type << endl;
+
+    IMATH_INTERNAL_NAMESPACE::Rand32 rand (0);
+
+    //
+    // Compare empty.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b0;
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1;
+
+        assert (b0 == b1);
+        assert (!(b0 != b1));
+    }
+
+    //
+    // Compare empty to non-empty.
+    //
+    {
+        std::vector<T> perms;
+        permutations (perms);
+
+        for (unsigned int i = 0; i < perms.size(); i++)
+        {
+            for (unsigned int j = 0; j < perms.size(); j++)
+            {
+                T p0 = -perms[i];
+                T p1 = perms[j];
+
+                IMATH_INTERNAL_NAMESPACE::Box<T> b0;
+                IMATH_INTERNAL_NAMESPACE::Box<T> b1 (p0, p1);
+                assert (!(b0 == b1));
+                assert (b0 != b1);
+            }
+        }
+    }
+
+    //
+    // Compare two non-empty
+    //
+    {
+        std::vector<T> perms;
+        permutations (perms);
+
+        for (unsigned int i = 0; i < perms.size(); i++)
+        {
+            for (unsigned int j = 0; j < perms.size(); j++)
+            {
+                T p0 = -perms[i];
+                T p1 = perms[j];
+
+                T p2 = -perms[j];
+                T p3 = perms[i];
+
+                IMATH_INTERNAL_NAMESPACE::Box<T> b0 (p0, p1);
+                IMATH_INTERNAL_NAMESPACE::Box<T> b1 (p2, p3);
+                IMATH_INTERNAL_NAMESPACE::Box<T> b2 (p0, p1);
+
+                if (i == j)
+                {
+                    assert (b0 == b1);
+                    assert (!(b0 != b1));
+                }
+                else
+                {
+                    assert (b0 != b1);
+                    assert (!(b0 == b1));
+                }
+                assert (b0 == b2);
+                assert (!(b0 != b2));
+            }
+        }
+    }
+}
+
+template <class T>
+void
+testIntersects (const char* type)
+{
+    cout << "    intersects() for type " << type << endl;
+
+    IMATH_INTERNAL_NAMESPACE::Rand32 rand (0);
+
+    //
+    // Intersect point with empty box.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        T p (1);
+
+        assert (!b.intersects (p));
+    }
+
+    //
+    // Intersect point with non-empty, has-volume box.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (T (-1), T (1));
+        T p0 (0);
+        T p1 (5);
+        T p2 (-5);
+
+        assert (b.intersects (p0));
+        assert (!b.intersects (p1));
+        assert (!b.intersects (p2));
+    }
+
+    //
+    // Intersect point with non-empty, no-volume box.
+    // Boxes are:
+    //    2D: [(0, 0),       (0, 1)      ]
+    //    3D: [(0, 0, 0),    (0, 0, 1)   ]
+    //    4D: [(0, 0, 0, 0), (0, 0, 0, 1)]
+    //
+    {
+        T min (0);
+        T max                    = min;
+        max[T::dimensions() - 1] = 1;
+
+        T p0 (0);
+        T p1 (5);
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (min, max);
+
+        assert (b.intersects (p0));
+        assert (!b.intersects (p1));
+    }
+
+    //
+    // Intersect empty box with empty box.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b0;
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1;
+
+        assert (!b0.intersects (b1));
+        assert (!b1.intersects (b0));
+    }
+
+    //
+    // Intersect empty box with non-empty has-volume boxes.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b0;
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1 (T (-1), T (1));
+        IMATH_INTERNAL_NAMESPACE::Box<T> b2 (T (1), T (2));
+
+        assert (!b0.intersects (b1));
+        assert (!b0.intersects (b2));
+
+        assert (!b1.intersects (b0));
+        assert (!b2.intersects (b0));
+    }
+
+    //
+    // Intersect empty box with non-empty no-volume box.
+    // Boxes are:
+    //    2D: [(0, 0),       (0, 1)      ]
+    //    3D: [(0, 0, 0),    (0, 0, 1)   ]
+    //    4D: [(0, 0, 0, 0), (0, 0, 0, 1)]
+    //
+    {
+        T min (0);
+        T max                    = min;
+        max[T::dimensions() - 1] = 1;
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b0;
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1 (min, max);
+
+        assert (!b0.intersects (b1));
+        assert (!b1.intersects (b0));
+    }
+
+    //
+    // Intersect non-empty has-volume box with non-empty has-volume box.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1 (T (-1), T (1));
+        IMATH_INTERNAL_NAMESPACE::Box<T> b2 (T (-1), T (1));
+        IMATH_INTERNAL_NAMESPACE::Box<T> b3 (T (1), T (2));
+        IMATH_INTERNAL_NAMESPACE::Box<T> b4 (T (2), T (3));
+
+        assert (b1.intersects (b1));
+        assert (b1.intersects (b3));
+        assert (!b1.intersects (b4));
+
+        assert (b3.intersects (b1));
+        assert (!b4.intersects (b1));
+    }
+
+    //
+    // Intersect non-empty has-volume box with non-empty no-volume box.
+    //
+    // Boxes are:
+    //    2D: [(0, 0),       (0, 1)      ]
+    //    3D: [(0, 0, 0),    (0, 0, 1)   ]
+    //    4D: [(0, 0, 0, 0), (0, 0, 0, 1)]
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b0 (T (-1), T (1));
+
+        T min (0);
+        T max                    = min;
+        max[T::dimensions() - 1] = 1;
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1 (min, max);
+        IMATH_INTERNAL_NAMESPACE::Box<T> b2 (min + T (2), max + T (2));
+
+        assert (b0.intersects (b1));
+        assert (b1.intersects (b0));
+
+        assert (!b0.intersects (b2));
+        assert (!b2.intersects (b1));
+    }
+
+    //
+    // Intersect non-empty no-volume box with non-empty no-volume box.
+    //
+    // Boxes are:
+    //    2D: [(0, 0),       (0, 1)      ]
+    //    3D: [(0, 0, 0),    (0, 0, 1)   ]
+    //    4D: [(0, 0, 0, 0), (0, 0, 0, 1)]
+    //
+    {
+        T min (0);
+        T max                    = min;
+        max[T::dimensions() - 1] = 1;
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b0 (min, max);
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1 (min, max + T (2));
+        IMATH_INTERNAL_NAMESPACE::Box<T> b2 (min + T (2), max + T (2));
+
+        assert (b0.intersects (b1));
+        assert (b1.intersects (b0));
+
+        assert (!b0.intersects (b2));
+        assert (!b2.intersects (b0));
+    }
+}
+
+template <class T>
+void
+testSize (const char* type)
+{
+    cout << "    size() for type " << type << endl;
+
+    //
+    // Size of empty box.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        assert (b.size() == T (0));
+    }
+
+    //
+    // Size of non-empty, has-volume box.
+    // Boxes are:
+    //    2D: [(-1, -1),         (1, 1)       ]
+    //    3D: [(-1, -1, -1),     (1, 1, 1)    ]
+    //    4D: [(-1, -1, -1, -1), (1, 1, 1, 1) ]
+    //
+    // and
+    //
+    //    2D: [(-1, -2),         (1, 2)       ]
+    //    3D: [(-1, -2, -3),     (1, 2, 3)    ]
+    //    4D: [(-1, -2, -3, -4), (1, 2, 3, 4) ]
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b0 (T (-1), T (1));
+        assert (b0.size() == T (2));
+
+        T p;
+        for (unsigned int i = 0; i < T::dimensions(); i++)
+        {
+            p[i] = static_cast<typename T::BaseType>(i);
+        }
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1 (-p, p);
+        assert (b1.size() == p * T (2));
+    }
+
+    //
+    // Size of non-empty, no-volume box.
+    // Boxes are:
+    //    2D: [(0, 0),       (0, 1)      ]
+    //    3D: [(0, 0, 0),    (0, 0, 1)   ]
+    //    4D: [(0, 0, 0, 0), (0, 0, 0, 1)]
+    //
+    {
+        T min (0);
+        T max                    = min;
+        max[T::dimensions() - 1] = 1;
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (min, max);
+
+        assert (b.size() == max);
+    }
+}
+
+template <class T>
+void
+testCenter (const char* type)
+{
+    cout << "    center() for type " << type << endl;
+
+    //
+    // Center of empty box.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        assert (b.center() == T (0));
+    }
+
+    //
+    // Center of non-empty, has-volume box.
+    // Boxes are:
+    //    2D: [(-1, -1),         (1, 1)       ]
+    //    3D: [(-1, -1, -1),     (1, 1, 1)    ]
+    //    4D: [(-1, -1, -1, -1), (1, 1, 1, 1) ]
+    //
+    // and
+    //
+    //    2D: [(-2, -4),         ( 8,  2)       ]
+    //    3D: [(-2, -4, -6),     (12,  8, 2)    ]
+    //    4D: [(-2, -4, -6, -8), (16, 12, 8, 4) ]
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b0 (T (-1), T (1));
+        assert (b0.center() == T (0));
+
+        T p0;
+        T p1;
+        for (unsigned int i = 0; i < T::dimensions(); i++)
+        {
+            int lo = 1 << (i + 1);
+            int hi = 1 << (T::dimensions () - i);
+            p0[i] = -static_cast<typename T::BaseType>(lo);
+            p1[i] = static_cast<typename T::BaseType>(hi);
+        }
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1 (p0, p1);
+        assert (b1.center() == (p1 + p0) / 2);
+    }
+
+    //
+    // Center of non-empty, no-volume box.
+    // Boxes are:
+    //    2D: [(0, 0),       (0, 2)      ]
+    //    3D: [(0, 0, 0),    (0, 0, 2)   ]
+    //    4D: [(0, 0, 0, 0), (0, 0, 0, 2)]
+    //
+    {
+        T min (0);
+        T max                    = min;
+        max[T::dimensions() - 1] = 2;
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (min, max);
+
+        assert (b.center() == max / 2);
+    }
+}
+
+template <class T>
+void
+testIsEmpty (const char* type)
+{
+    cout << "    isEmpty() for type " << type << endl;
+
+    //
+    // Empty box.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        assert (b.isEmpty());
+    }
+
+    //
+    // Non-empty, has-volume box.
+    //    2D: [(-2, -4),         ( 8,  2)       ]
+    //    3D: [(-2, -4, -6),     (12,  8, 2)    ]
+    //    4D: [(-2, -4, -6, -8), (16, 12, 8, 4) ]
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b0 (T (-1), T (1));
+        assert (!b0.isEmpty());
+
+        T p0;
+        T p1;
+        for (unsigned int i = 0; i < T::dimensions(); i++)
+        {
+            int lo = 1 << (i + 1);
+            int hi = 1 << (T::dimensions () - i);
+            p0[i] = -static_cast<typename T::BaseType>(lo);
+            p1[i] = static_cast<typename T::BaseType>(hi);
+        }
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1 (p0, p1);
+        assert (!b1.isEmpty());
+    }
+
+    //
+    // Non-empty, no-volume box.
+    // Boxes are:
+    //    2D: [(0, 0),       (0, 2)      ]
+    //    3D: [(0, 0, 0),    (0, 0, 2)   ]
+    //    4D: [(0, 0, 0, 0), (0, 0, 0, 2)]
+    //
+    {
+        T min (0);
+        T max                    = min;
+        max[T::dimensions() - 1] = 2;
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (min, max);
+
+        assert (!b.isEmpty());
+    }
+}
+
+template <class T>
+void
+testIsInfinite (const char* type)
+{
+    cout << "    isInfinite() for type " << type << endl;
+
+    //
+    // Infinite box.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        b.makeInfinite();
+        assert (b.isInfinite());
+    }
+
+    //
+    // Non-empty, has-volume box.
+    //    2D: [(-2, -4),         ( 8,  2)       ]
+    //    3D: [(-2, -4, -6),     (12,  8, 2)    ]
+    //    4D: [(-2, -4, -6, -8), (16, 12, 8, 4) ]
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b0 (T (-1), T (1));
+        assert (!b0.isInfinite());
+
+        T p0;
+        T p1;
+        for (unsigned int i = 0; i < T::dimensions(); i++)
+        {
+            int lo = 1 << (i + 1);
+            int hi = 1 << (T::dimensions () - i);
+            p0[i] = -static_cast<typename T::BaseType>(lo);
+            p1[i] = static_cast<typename T::BaseType>(hi);
+        }
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1 (p0, p1);
+        assert (!b1.isInfinite());
+    }
+
+    //
+    // Non-empty, no-volume box.
+    // Boxes are:
+    //    2D: [(0, 0),       (0, 2)      ]
+    //    3D: [(0, 0, 0),    (0, 0, 2)   ]
+    //    4D: [(0, 0, 0, 0), (0, 0, 0, 2)]
+    //
+    {
+        T min (0);
+        T max                    = min;
+        max[T::dimensions() - 1] = 2;
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (min, max);
+
+        assert (!b.isInfinite());
+    }
+}
+
+template <class T>
+void
+testHasVolume (const char* type)
+{
+    cout << "    hasVolume() for type " << type << endl;
+
+    //
+    // Empty box.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        assert (!b.hasVolume());
+    }
+
+    //
+    // Infinite box.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        b.makeInfinite();
+        assert (b.hasVolume());
+    }
+
+    //
+    // Non-empty, has-volume box.
+    //    2D: [(-2, -4),         ( 8,  2)       ]
+    //    3D: [(-2, -4, -6),     (12,  8, 2)    ]
+    //    4D: [(-2, -4, -6, -8), (16, 12, 8, 4) ]
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b0 (T (-1), T (1));
+        assert (b0.hasVolume());
+
+        T p0;
+        T p1;
+        for (unsigned int i = 0; i < T::dimensions(); i++)
+        {
+            int lo = 1 << (i + 1);
+            int hi = 1 << (T::dimensions () - i);
+            p0[i] = -static_cast<typename T::BaseType>(lo);
+            p1[i] = static_cast<typename T::BaseType>(hi);
+        }
+        IMATH_INTERNAL_NAMESPACE::Box<T> b1 (p0, p1);
+        assert (b1.hasVolume());
+    }
+
+    //
+    // Non-empty, no-volume box.
+    // Boxes are:
+    //    2D: [(0, 0),       (0, 2)      ]
+    //    3D: [(0, 0, 0),    (0, 0, 2)   ]
+    //    4D: [(0, 0, 0, 0), (0, 0, 0, 2)]
+    //
+    {
+        T min (0);
+        T max                    = min;
+        max[T::dimensions() - 1] = 2;
+
+        IMATH_INTERNAL_NAMESPACE::Box<T> b (min, max);
+
+        assert (!b.hasVolume());
+    }
+}
+
+template <class T>
+void
+testMajorAxis (const char* type)
+{
+    cout << "    majorAxis() for type " << type << endl;
+
+    //
+    // Empty box.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Box<T> b;
+        assert (b.majorAxis() == 0);
+    }
+
+    //
+    // Non-empty, has-volume box.
+    // Boxes are [ (0, 0, ...), (<all permutations of 1..T::dimensions()>) ]
+    //
+    {
+        std::vector<T> perms;
+        permutations (perms);
+
+        for (unsigned int i = 0; i < perms.size(); i++)
+        {
+            IMATH_INTERNAL_NAMESPACE::Box<T> b (T (0), perms[i]);
+
+            unsigned int major = 0;
+            T size             = perms[i] - T (0);
+            for (unsigned int j = 1; j < T::dimensions(); j++)
+                if (size[j] > size[major])
+                    major = j;
+
+            assert (b.majorAxis() == major);
+        }
+    }
+
+    //
+    // Non-empty, no-volume box.
+    // Boxes are:
+    //    2D: [(0, 0), (1, 0) ]
+    //    2D: [(0, 0), (0, 1) ]
+    //
+    //    3D: [(0, 0), (1, 0, 0) ]
+    //    3D: [(0, 0), (0, 1, 0) ]
+    //    3D: [(0, 0), (0, 0, 1) ]
+    //
+    //    and similarly for 4D
+    //
+    {
+        for (unsigned int i = 0; i < T::dimensions(); i++)
+        {
+            for (unsigned int j = 0; j < T::dimensions(); j++)
+            {
+                T max (0);
+                max[j] = 1;
+
+                IMATH_INTERNAL_NAMESPACE::Box<T> b (T (0), max);
+                assert (b.majorAxis() == j);
+            }
+        }
+    }
+}
+
+} // anonymous namespace
+
+void
+testBox()
+{
+    cout << "Testing box methods" << endl;
+
+    //
+    // Constructors
+    //
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testConstructors<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    //
+    // makeEmpty()
+    //
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testMakeEmpty<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    //
+    // makeInfinite()
+    //
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testMakeInfinite<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    //
+    // extendBy() (point)
+    //
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testExtendByPoint<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    //
+    // extendBy() box
+    //
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testExtendByBox<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    //
+    // == and !==
+    //
+    testComparators<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testComparators<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testComparators<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testComparators<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    //
+    // size()
+    //
+    testSize<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testSize<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testSize<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testSize<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testSize<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testSize<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testSize<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testSize<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testSize<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testSize<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testSize<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testSize<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testSize<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testSize<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testSize<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    //
+    // center()
+    //
+    testCenter<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testCenter<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testCenter<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testCenter<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    //
+    // isEmpty()
+    //
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testIsEmpty<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    //
+    // isInfinite()
+    //
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testIsInfinite<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    //
+    // hasVolume()
+    //
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testHasVolume<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    //
+    // majorAxis()
+    //
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V2s> ("V2s");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V2i> ("V2i");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V2i64> ("V2i64");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V2f> ("V2f");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V2d> ("V2d");
+
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V3s> ("V3s");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V3i> ("V3i");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V3i64> ("V3i64");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V3f> ("V3f");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V3d> ("V3d");
+
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V4s> ("V4s");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V4i> ("V4i");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V4i64> ("V4i64");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V4f> ("V4f");
+    testMajorAxis<IMATH_INTERNAL_NAMESPACE::V4d> ("V4d");
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testBox.h b/src/ImathTest/testBox.h
new file mode 100644 (file)
index 0000000..eb9352c
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testBox();
diff --git a/src/ImathTest/testBoxAlgo.cpp b/src/ImathTest/testBoxAlgo.cpp
new file mode 100644 (file)
index 0000000..bdf9727
--- /dev/null
@@ -0,0 +1,929 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathBoxAlgo.h>
+#include <ImathRandom.h>
+#include <algorithm>
+#include <assert.h>
+#include <iostream>
+#include "testBoxAlgo.h"
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+bool
+approximatelyEqual (const V3f& p1, const V3f& p2, float e)
+{
+    float m = 0;
+
+    for (int i = 0; i < 3; ++i)
+    {
+        m = max (m, abs (p1[i]));
+        m = max (m, abs (p2[i]));
+    }
+
+    for (int i = 0; i < 3; ++i)
+        if (!equalWithAbsError (p1[i], p2[i], m * e))
+            return false;
+
+    return true;
+}
+
+void
+testEntryAndExitPoints (const Box3f& box)
+{
+    Rand48 random (2007);
+
+    float e = 50 * std::numeric_limits<float>::epsilon();
+
+    if (box.isEmpty())
+    {
+        cout << "    empty box, no rays intersect" << endl;
+
+        for (int i = 0; i < 100000; ++i)
+        {
+            V3f p1 (
+                float(random.nextf (box.max.x, box.min.x)),
+                float(random.nextf (box.max.y, box.min.y)),
+                float(random.nextf (box.max.z, box.min.z)));
+
+            V3f p2 (p1 + hollowSphereRand<V3f> (random));
+
+            V3f r, s;
+            assert (!findEntryAndExitPoints (Line3f (p1, p2), box, r, s));
+        }
+
+        return;
+    }
+
+    cout << "    box = (" << box.min << " " << box.max << ")" << endl;
+
+    if (box.max == box.min)
+    {
+        cout << "    single-point box, ray intersects" << endl;
+
+        static const float off[6][3] = { { -1, 0, 0 }, { 1, 0, 0 },  { 0, -1, 0 },
+                                         { 0, 1, 0 },  { 0, 0, -1 }, { 0, 0, 1 } };
+
+        for (int i = 0; i < 6; ++i)
+        {
+            V3f p1 (box.min.x + off[i][0], box.min.y + off[i][1], box.min.z + off[i][2]);
+
+            V3f r, s;
+            assert (findEntryAndExitPoints (Line3f (p1, box.min), box, r, s));
+            assert (r == box.min && s == box.min);
+        }
+
+        cout << "    single-point box, ray does not intersect" << endl;
+
+        for (int i = 0; i < 100000; ++i)
+        {
+            //
+            // The ray starts at a distance of r2 from the of the
+            // box, and it passes the box at a minimum distance of r1.
+            //
+
+            const float r1 = 0.00001f;
+            const float r2 = 1.0f;
+
+            V3f p1 = box.min + r2 * hollowSphereRand<V3f> (random);
+            V3f p2;
+            float r3;
+
+            do
+            {
+                do
+                {
+                    p2 = box.min + r2 * hollowSphereRand<V3f> (random);
+                } while (approximatelyEqual (p1, p2, e));
+
+                V3f d1 = (p2 - p1).normalized();
+                V3f d2 = (box.min - p1);
+                r3     = (d2 - d1 * (d1 ^ d2)).length();
+            } while (r3 < r1);
+
+            Line3f ray (p1, p2);
+            V3f r, s;
+
+            assert (!findEntryAndExitPoints (ray, box, r, s));
+        }
+
+        return;
+    }
+
+    cout << "    ray starts outside box, intersects" << endl;
+
+    Box3f bigBox (box.min - (box.max - box.min), box.max + (box.max - box.min));
+
+    for (int i = 0; i < 100000; ++i)
+    {
+        //
+        // Find starting point outside the box, end point inside the box
+        //
+
+        V3f p1;
+
+        do
+        {
+            p1 = V3f (
+                float(random.nextf (bigBox.min.x, bigBox.max.x)),
+                float(random.nextf (bigBox.min.y, bigBox.max.y)),
+                float(random.nextf (bigBox.min.z, bigBox.max.z)));
+        } while (box.intersects (p1));
+
+        V3f p2;
+
+        do
+        {
+            p2 = V3f (
+                float(random.nextf (box.min.x, box.max.x)),
+                float(random.nextf (box.min.y, box.max.y)),
+                float(random.nextf (box.min.z, box.max.z)));
+        } while (approximatelyEqual (p1, p2, e));
+
+        Line3f ray (p1, p2);
+
+        V3f r, s;
+        bool b = findEntryAndExitPoints (ray, box, r, s);
+
+        //
+        // Ray and box must intersect, entry and exit points
+        // must be on the surface of the box.
+        //
+
+        assert (b);
+
+        assert (r.x == box.min.x || r.x == box.max.x || r.y == box.min.y || r.y == box.max.y ||
+                r.z == box.min.z || r.z == box.max.z);
+
+        assert (s.x == box.min.x || s.x == box.max.x || s.y == box.min.y || s.y == box.max.y ||
+                s.z == box.min.z || s.z == box.max.z);
+
+        //
+        // Entry and exit points must be consistent
+        // with the direction of the ray
+        //
+
+        if (r.x == box.min.x)
+            assert (ray.dir.x >= 0);
+
+        if (r.x == box.max.x)
+            assert (ray.dir.x <= 0);
+
+        if (r.y == box.min.y)
+            assert (ray.dir.y >= 0);
+
+        if (r.y == box.max.y)
+            assert (ray.dir.y <= 0);
+
+        if (r.z == box.min.z)
+            assert (ray.dir.z >= 0);
+
+        if (r.z == box.max.z)
+            assert (ray.dir.z <= 0);
+
+        if (s.x == box.max.x)
+            assert (ray.dir.x >= 0);
+
+        if (s.x == box.min.x)
+            assert (ray.dir.x <= 0);
+
+        if (s.y == box.max.y)
+            assert (ray.dir.y >= 0);
+
+        if (s.y == box.min.y)
+            assert (ray.dir.y <= 0);
+
+        if (s.z == box.max.z)
+            assert (ray.dir.z >= 0);
+
+        if (s.z == box.min.z)
+            assert (ray.dir.z <= 0);
+
+        //
+        // Entry and exit points must be approximately on the ray
+        // How far they can be off depends on how far p1 and the
+        // entry and exit points are are from the origin.
+        //
+
+        {
+            V3f p3  = p1 + ray.dir * (ray.dir ^ (r - p1));
+            float m = 0;
+
+            for (int j = 0; j < 3; ++j)
+            {
+                m = max (abs (p1[j]), m);
+                m = max (abs (r[j]), m);
+            }
+
+            float err = 30 * m * std::numeric_limits<float>::epsilon();
+            assert (p3.equalWithAbsError (r, err));
+        }
+
+        {
+            V3f p3  = p1 + ray.dir * (ray.dir ^ (s - p1));
+            float m = 0;
+
+            for (int j = 0; j < 3; ++j)
+            {
+                m = max (abs (p1[j]), m);
+                m = max (abs (s[j]), m);
+            }
+
+            float err = 30 * m * std::numeric_limits<float>::epsilon();
+            assert (p3.equalWithAbsError (s, err));
+        }
+    }
+
+    cout << "    ray starts outside box, does not intersect" << endl;
+
+    V3f center = (box.min + box.max) * 0.5f;
+    float r1   = (box.max - box.min).length() * 0.51f;
+    float r2   = 2 * r1;
+
+    for (int i = 0; i < 100000; ++i)
+    {
+        //
+        // The ray starts at a distance of r2 from the center
+        // of the box, and it passes the center at a minimum
+        // distance of r1.  (r1 and r2 are both greater than
+        // the distance between the center and the corners
+        // of the box.)
+        //
+
+        V3f p1 = center + r2 * hollowSphereRand<V3f> (random);
+        V3f p2;
+        float r3;
+
+        do
+        {
+            do
+            {
+                p2 = center + r2 * hollowSphereRand<V3f> (random);
+            } while (approximatelyEqual (p1, p2, e));
+
+            V3f d1 = (p2 - p1).normalized();
+            V3f d2 = (center - p1);
+            r3     = (d2 - d1 * (d1 ^ d2)).length();
+        } while (r3 < r1);
+
+        Line3f ray (p1, p2);
+        V3f r, s;
+
+        assert (!findEntryAndExitPoints (ray, box, r, s));
+    }
+}
+
+void
+entryAndExitPoints1()
+{
+    cout << "  ray-box entry and exit, random rays" << endl;
+
+    Box3f boxes[] = { // Boxes with a positive volume
+
+                      Box3f (V3f (-1, -1, -1), V3f (1, 1, 1)),
+                      Box3f (V3f (10, 20, 30), V3f (1010, 21, 31)),
+                      Box3f (V3f (10, 20, 30), V3f (11, 1020, 31)),
+                      Box3f (V3f (10, 20, 30), V3f (11, 21, 1030)),
+                      Box3f (V3f (-1e10f, -2e10f, -3e10f), V3f (5e15f, 6e15f, 7e15f)),
+
+                      // Non-empty, zero-volume boxes
+
+                      Box3f (V3f (1, 1, 1), V3f (2, 1, 1)),
+                      Box3f (V3f (1, 1, 1), V3f (1, 2, 1)),
+                      Box3f (V3f (1, 1, 1), V3f (1, 1, 2)),
+                      Box3f (V3f (1, 1, 1), V3f (1, 2, 3)),
+                      Box3f (V3f (1, 1, 1), V3f (2, 3, 1)),
+                      Box3f (V3f (1, 1, 1), V3f (2, 1, 3)),
+                      Box3f (V3f (-1, -2, 1), V3f (-1, -2, 1)),
+                      Box3f (V3f (1, 1, 1), V3f (1, 1, 1)),
+                      Box3f (V3f (0, 0, 0), V3f (0, 0, 0)),
+
+                      // empty box
+
+                      Box3f()
+    };
+
+    for (size_t i = 0; i < sizeof (boxes) / sizeof (boxes[0]); ++i)
+        testEntryAndExitPoints (boxes[i]);
+}
+
+void
+testPerturbedRayBoxEntryExit (const Box3f& box, const Line3f& ray, bool result)
+{
+    cout << "    dir ~ " << ray.dir << ", result = " << result << endl;
+
+    {
+        V3f r, s;
+        assert (result == findEntryAndExitPoints (ray, box, r, s));
+    }
+
+    Rand48 random (19);
+    const float e = 1e-25f;
+
+    for (int i = 0; i < 10000; ++i)
+    {
+        Line3f ray1 (ray);
+        ray1.dir += e * solidSphereRand<V3f> (random);
+
+        V3f r, s;
+        assert (result == findEntryAndExitPoints (ray1, box, r, s));
+    }
+}
+
+void
+entryAndExitPoints2()
+{
+
+    cout << "  ray-box entry and exit, nearly axis-parallel rays" << endl;
+
+    Box3f box (V3f (-1e15f, -1e15f, -1e15f), V3f (1e15f, 1e15f, 1e15f));
+    Line3f ray;
+    V3f r, s;
+    bool b;
+
+    ray = Line3f (V3f (-2e15f, 0, 0), V3f (2e15f, 0, 0));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (b && r == V3f (-1e15f, 0, 0) && s == V3f (1e15f, 0, 0));
+    testPerturbedRayBoxEntryExit (box, ray, true);
+
+    ray = Line3f (V3f (2e15f, 0, 0), V3f (-2e15f, 0, 0));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (b && r == V3f (1e15f, 0, 0) && s == V3f (-1e15f, 0, 0));
+    testPerturbedRayBoxEntryExit (box, ray, true);
+
+    ray = Line3f (V3f (-2e15f, 2e15f, 0), V3f (2e15f, 2e15f, 0));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (!b);
+    testPerturbedRayBoxEntryExit (box, ray, false);
+
+    ray = Line3f (V3f (2e15f, 2e15f, 0), V3f (-2e15f, 2e15f, 0));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (!b);
+    testPerturbedRayBoxEntryExit (box, ray, false);
+
+    ray = Line3f (V3f (0, -2e15f, 0), V3f (0, 2e15f, 0));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (b && r == V3f (0, -1e15f, 0) && s == V3f (0, 1e15f, 0));
+    testPerturbedRayBoxEntryExit (box, ray, true);
+
+    ray = Line3f (V3f (0, 2e15f, 0), V3f (0, -2e15f, 0));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (b && r == V3f (0, 1e15f, 0) && s == V3f (0, -1e15f, 0));
+    testPerturbedRayBoxEntryExit (box, ray, true);
+
+    ray = Line3f (V3f (0, -2e15f, 2e15f), V3f (0, 2e15f, 2e15f));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (!b);
+    testPerturbedRayBoxEntryExit (box, ray, false);
+
+    ray = Line3f (V3f (0, 2e15f, 2e15f), V3f (0, -2e15f, 2e15f));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (!b);
+    testPerturbedRayBoxEntryExit (box, ray, false);
+
+    ray = Line3f (V3f (0, 0, -2e15f), V3f (0, 0, 2e15f));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (b && r == V3f (0, 0, -1e15f) && s == V3f (0, 0, 1e15f));
+    testPerturbedRayBoxEntryExit (box, ray, true);
+
+    ray = Line3f (V3f (0, 0, 2e15f), V3f (0, 0, -2e15f));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (b && r == V3f (0, 0, 1e15f) && s == V3f (0, 0, -1e15f));
+    testPerturbedRayBoxEntryExit (box, ray, true);
+
+    ray = Line3f (V3f (2e15f, 0, -2e15f), V3f (2e15f, 0, 2e15f));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (!b);
+    testPerturbedRayBoxEntryExit (box, ray, false);
+
+    ray = Line3f (V3f (2e15f, 0, 2e15f), V3f (2e15f, 0, -2e15f));
+    b   = findEntryAndExitPoints (ray, box, r, s);
+    assert (!b);
+    testPerturbedRayBoxEntryExit (box, ray, false);
+}
+
+void
+testRayBoxIntersection (const Box3f& box)
+{
+    Rand48 random (2007);
+
+    float e = 50 * std::numeric_limits<float>::epsilon();
+
+    if (box.isEmpty())
+    {
+        cout << "    empty box, no rays intersect" << endl;
+
+        for (int i = 0; i < 100000; ++i)
+        {
+            V3f p1 (
+                float(random.nextf (box.max.x, box.min.x)),
+                float(random.nextf (box.max.y, box.min.y)),
+                float(random.nextf (box.max.z, box.min.z)));
+
+            V3f p2 (p1 + hollowSphereRand<V3f> (random));
+
+            V3f ip;
+            assert (!intersects (box, Line3f (p1, p2), ip));
+        }
+
+        return;
+    }
+
+    cout << "    box = (" << box.min << " " << box.max << ")" << endl;
+
+    if (box.max == box.min)
+    {
+        cout << "    single-point box, ray intersects" << endl;
+
+        static const float off[6][3] = { { -1, 0, 0 }, { 1, 0, 0 },  { 0, -1, 0 },
+                                         { 0, 1, 0 },  { 0, 0, -1 }, { 0, 0, 1 } };
+
+        for (int i = 0; i < 6; ++i)
+        {
+            V3f p1 (box.min.x + off[i][0], box.min.y + off[i][1], box.min.z + off[i][2]);
+
+            V3f ip;
+            assert (intersects (box, Line3f (p1, box.min), ip));
+            assert (ip == box.min);
+        }
+
+        cout << "    single-point box, ray does not intersect" << endl;
+
+        for (int i = 0; i < 100000; ++i)
+        {
+            //
+            // The ray starts at a distance of r2 from the of the
+            // box, and it passes the box at a minimum distance of r1.
+            //
+
+            const float r1 = 0.00001f;
+            const float r2 = 1.0f;
+
+            V3f p1 = box.min + r2 * hollowSphereRand<V3f> (random);
+            V3f p2;
+            float r3;
+
+            do
+            {
+                do
+                {
+                    p2 = box.min + r2 * hollowSphereRand<V3f> (random);
+                } while (approximatelyEqual (p1, p2, e));
+
+                V3f d1 = (p2 - p1).normalized();
+                V3f d2 = (box.min - p1);
+                r3     = (d2 - d1 * (d1 ^ d2)).length();
+            } while (r3 < r1);
+
+            Line3f ray (p1, p2);
+            V3f ip;
+
+            assert (!intersects (box, ray, ip));
+        }
+
+        return;
+    }
+
+    cout << "    ray starts inside box" << endl;
+
+    for (int i = 0; i < 1000; ++i)
+    {
+        V3f p1 (
+            float(random.nextf (box.min.x, box.max.x)),
+            float(random.nextf (box.min.y, box.max.y)),
+            float(random.nextf (box.min.z, box.max.z)));
+
+        V3f p2 (p1 + hollowSphereRand<V3f> (random));
+
+        V3f ip;
+        bool b = intersects (box, Line3f (p1, p2), ip);
+
+        assert (b && ip == p1);
+    }
+
+    cout << "    ray starts outside box, intersects" << endl;
+
+    Box3f bigBox (box.min - (box.max - box.min), box.max + (box.max - box.min));
+
+    for (int i = 0; i < 100000; ++i)
+    {
+        //
+        // Find starting point outside the box, end point inside the box
+        //
+
+        V3f p1;
+
+        do
+        {
+            p1 = V3f (
+                float(random.nextf (bigBox.min.x, bigBox.max.x)),
+                float(random.nextf (bigBox.min.y, bigBox.max.y)),
+                float(random.nextf (bigBox.min.z, bigBox.max.z)));
+        } while (box.intersects (p1));
+
+        V3f p2;
+
+        do
+        {
+            p2 = V3f (
+                float(random.nextf (box.min.x, box.max.x)),
+                float(random.nextf (box.min.y, box.max.y)),
+                float(random.nextf (box.min.z, box.max.z)));
+        } while (approximatelyEqual (p1, p2, e));
+
+        Line3f ray (p1, p2);
+
+        V3f ip;
+        bool b = intersects (box, ray, ip);
+
+        //
+        // Ray and box must intersect, intersection point
+        // must be on the surface of the box.
+        //
+
+        assert (b);
+
+        assert (ip.x == box.min.x || ip.x == box.max.x || ip.y == box.min.y || ip.y == box.max.y ||
+                ip.z == box.min.z || ip.z == box.max.z);
+
+        //
+        // Intersection point must be consistent with the origin
+        // and direction of the ray
+        //
+
+        if (ip.x == box.min.x)
+            assert (ray.pos.x <= box.min.x && ray.dir.x >= 0);
+
+        if (ip.x == box.max.x)
+            assert (ray.pos.x >= box.max.x && ray.dir.x <= 0);
+
+        if (ip.y == box.min.y)
+            assert (ray.pos.y <= box.min.y && ray.dir.y >= 0);
+
+        if (ip.y == box.max.y)
+            assert (ray.pos.y >= box.max.y && ray.dir.y <= 0);
+
+        if (ip.z == box.min.z)
+            assert (ray.pos.z <= box.min.z && ray.dir.z >= 0);
+
+        if (ip.z == box.max.z)
+            assert (ray.pos.z >= box.max.z && ray.dir.z <= 0);
+
+        //
+        // Intersection point must be approximately on the ray
+        // How far it can be off depends on how far p1 and ip
+        // are from the origin.
+        //
+
+        V3f p3  = p1 + ray.dir * (ray.dir ^ (ip - p1));
+        float m = 0;
+
+        for (int j = 0; j < 3; ++j)
+        {
+            m = max (abs (p1[j]), m);
+            m = max (abs (ip[j]), m);
+        }
+
+        float err = 30 * m * std::numeric_limits<float>::epsilon();
+        assert (p3.equalWithAbsError (ip, err));
+
+        //
+        // Try same starting point, opposite direction
+        //
+
+        ray.dir *= -1;
+        V3f ip2;
+
+        assert (!intersects (box, ray, ip2));
+    }
+
+    cout << "    ray starts outside box, does not intersect" << endl;
+
+    V3f center = (box.min + box.max) * 0.5f;
+    float r1   = (box.max - box.min).length() * 0.51f;
+    float r2   = 2 * r1;
+
+    for (int i = 0; i < 100000; ++i)
+    {
+        //
+        // The ray starts at a distance of r2 from the center
+        // of the box, and it passes the center at a minimum
+        // distance of r1.  (r1 and r2 are both greater than
+        // the distance between the center and the corners
+        // of the box.)
+        //
+
+        V3f p1 = center + r2 * hollowSphereRand<V3f> (random);
+        V3f p2;
+        float r3;
+
+        do
+        {
+            do
+            {
+                p2 = center + r2 * hollowSphereRand<V3f> (random);
+            } while (approximatelyEqual (p1, p2, e));
+
+            V3f d1 = (p2 - p1).normalized();
+            V3f d2 = (center - p1);
+            r3     = (d2 - d1 * (d1 ^ d2)).length();
+        } while (r3 < r1);
+
+        Line3f ray (p1, p2);
+        V3f ip;
+
+        assert (!intersects (box, ray, ip));
+    }
+}
+
+void
+rayBoxIntersection1()
+{
+    cout << "  ray-box intersection, random rays" << endl;
+
+    Box3f boxes[] = { // Boxes with a positive volume
+
+                      Box3f (V3f (-1, -1, -1), V3f (1, 1, 1)),
+                      Box3f (V3f (10, 20, 30), V3f (1010, 21, 31)),
+                      Box3f (V3f (10, 20, 30), V3f (11, 1020, 31)),
+                      Box3f (V3f (10, 20, 30), V3f (11, 21, 1030)),
+                      Box3f (V3f (-1e10f, -2e10f, -3e10f), V3f (5e15f, 6e15f, 7e15f)),
+
+                      // Non-empty, zero-volume boxes
+
+                      Box3f (V3f (1, 1, 1), V3f (2, 1, 1)),
+                      Box3f (V3f (1, 1, 1), V3f (1, 2, 1)),
+                      Box3f (V3f (1, 1, 1), V3f (1, 1, 2)),
+                      Box3f (V3f (1, 1, 1), V3f (1, 2, 3)),
+                      Box3f (V3f (1, 1, 1), V3f (2, 3, 1)),
+                      Box3f (V3f (1, 1, 1), V3f (2, 1, 3)),
+                      Box3f (V3f (-1, -2, 1), V3f (-1, -2, 1)),
+                      Box3f (V3f (1, 1, 1), V3f (1, 1, 1)),
+                      Box3f (V3f (0, 0, 0), V3f (0, 0, 0)),
+
+                      // empty box
+
+                      Box3f()
+    };
+
+    for (size_t i = 0; i < sizeof (boxes) / sizeof (boxes[0]); ++i)
+        testRayBoxIntersection (boxes[i]);
+}
+
+void
+testPerturbedRayBox (const Box3f& box, const Line3f& ray, bool result)
+{
+    cout << "    dir ~ " << ray.dir << ", result = " << result << endl;
+
+    {
+        V3f ip;
+        assert (result == intersects (box, ray, ip));
+    }
+
+    Rand48 random (19);
+    const float e = 1e-25f;
+
+    for (int i = 0; i < 10000; ++i)
+    {
+        Line3f ray1 (ray);
+        ray1.dir += e * solidSphereRand<V3f> (random);
+
+        V3f ip;
+        assert (result == intersects (box, ray1, ip));
+    }
+}
+
+void
+rayBoxIntersection2()
+{
+
+    cout << "  ray-box intersection, nearly axis-parallel rays" << endl;
+
+    Box3f box (V3f (-1e15f, -1e15f, -1e15f), V3f (1e15f, 1e15f, 1e15f));
+    Line3f ray;
+    V3f ip;
+    bool b;
+
+    ray = Line3f (V3f (-2e15f, 0, 0), V3f (2e15f, 0, 0));
+    b   = intersects (box, ray, ip);
+    assert (b && ip == V3f (-1e15f, 0, 0));
+    testPerturbedRayBox (box, ray, true);
+
+    ray = Line3f (V3f (2e15f, 0, 0), V3f (-2e15f, 0, 0));
+    b   = intersects (box, ray, ip);
+    assert (b && ip == V3f (1e15f, 0, 0));
+    testPerturbedRayBox (box, ray, true);
+
+    ray = Line3f (V3f (-2e15f, 2e15f, 0), V3f (2e15f, 2e15f, 0));
+    b   = intersects (box, ray, ip);
+    assert (!b);
+    testPerturbedRayBox (box, ray, false);
+
+    ray = Line3f (V3f (2e15f, 2e15f, 0), V3f (-2e15f, 2e15f, 0));
+    b   = intersects (box, ray, ip);
+    assert (!b);
+    testPerturbedRayBox (box, ray, false);
+
+    ray = Line3f (V3f (0, -2e15f, 0), V3f (0, 2e15f, 0));
+    b   = intersects (box, ray, ip);
+    assert (b && ip == V3f (0, -1e15f, 0));
+    testPerturbedRayBox (box, ray, true);
+
+    ray = Line3f (V3f (0, 2e15f, 0), V3f (0, -2e15f, 0));
+    b   = intersects (box, ray, ip);
+    assert (b && ip == V3f (0, 1e15f, 0));
+    testPerturbedRayBox (box, ray, true);
+
+    ray = Line3f (V3f (0, -2e15f, 2e15f), V3f (0, 2e15f, 2e15f));
+    b   = intersects (box, ray, ip);
+    assert (!b);
+    testPerturbedRayBox (box, ray, false);
+
+    ray = Line3f (V3f (0, 2e15f, 2e15f), V3f (0, -2e15f, 2e15f));
+    b   = intersects (box, ray, ip);
+    assert (!b);
+    testPerturbedRayBox (box, ray, false);
+
+    ray = Line3f (V3f (0, 0, -2e15f), V3f (0, 0, 2e15f));
+    b   = intersects (box, ray, ip);
+    assert (b && ip == V3f (0, 0, -1e15f));
+    testPerturbedRayBox (box, ray, true);
+
+    ray = Line3f (V3f (0, 0, 2e15f), V3f (0, 0, -2e15f));
+    b   = intersects (box, ray, ip);
+    assert (b && ip == V3f (0, 0, 1e15f));
+    testPerturbedRayBox (box, ray, true);
+
+    ray = Line3f (V3f (2e15f, 0, -2e15f), V3f (2e15f, 0, 2e15f));
+    b   = intersects (box, ray, ip);
+    assert (!b);
+    testPerturbedRayBox (box, ray, false);
+
+    ray = Line3f (V3f (2e15f, 0, 2e15f), V3f (2e15f, 0, -2e15f));
+    b   = intersects (box, ray, ip);
+    assert (!b);
+    testPerturbedRayBox (box, ray, false);
+}
+
+Box3f
+transformSimple (const Box3f& b, const M44f& M)
+{
+    Box3f b1;
+
+    for (int i = 0; i < 8; ++i)
+    {
+        V3f p;
+
+        for (int j = 0; j < 3; ++j)
+            p[j] = ((i >> j) & 1) ? b.max[j] : b.min[j];
+
+        b1.extendBy (p * M);
+    }
+
+    return b1;
+}
+
+void
+boxMatrixTransform()
+{
+    cout << "  transform box by matrix" << endl;
+
+    const float e = 5 * std::numeric_limits<float>::epsilon();
+
+    Box3f b1 (V3f (4, 5, 6), V3f (7, 8, 9));
+
+    M44f M;
+    M.setEulerAngles (V3f (1, 2, 3));
+    M.translate (V3f (20, -15, 2));
+
+    Box3f b2 = transform (b1, M);
+    Box3f b3 = affineTransform (b1, M);
+    Box3f b4 = transformSimple (b1, M);
+    Box3f b21;
+    Box3f b31;
+
+    transform (b1, M, b21);
+    affineTransform (b1, M, b31);
+
+    assert (approximatelyEqual (b2.min, b4.min, e));
+    assert (approximatelyEqual (b2.max, b4.max, e));
+    assert (approximatelyEqual (b3.max, b4.max, e));
+    assert (approximatelyEqual (b3.max, b4.max, e));
+
+    assert (b21 == b2);
+    assert (b31 == b3);
+
+    M[0][3] = 1;
+    M[1][3] = 2;
+    M[2][3] = 3;
+    M[3][3] = 4;
+
+    Box3f b5 = transform (b1, M);
+    Box3f b6 = transformSimple (b1, M);
+    Box3f b51;
+
+    transform (b1, M, b51);
+
+    assert (approximatelyEqual (b5.min, b6.min, e));
+    assert (approximatelyEqual (b5.max, b6.max, e));
+    assert (b51 == b5);
+
+    Box3f b7;
+    Box3f r;
+    b7.makeEmpty();
+    assert (b7.isEmpty() && !b7.isInfinite());
+    affineTransform (b7, M, r);
+    assert (r.isEmpty());
+
+    Box3f b8;
+    b8.makeInfinite();
+    assert (b8.isInfinite() && !b8.isEmpty());
+    affineTransform (b8, M, r);
+    assert (r.isInfinite());
+}
+
+void
+pointInAndOnBox()
+{
+    cout << "  closest points in and on box" << endl;
+
+    Box3f box (V3f (1, 2, 3), V3f (5, 4, 6));
+
+    //
+    // Points outside the box
+    //
+
+    assert (closestPointOnBox (V3f (0, 0, 0), box) == V3f (1, 2, 3));
+    assert (closestPointInBox (V3f (0, 0, 0), box) == V3f (1, 2, 3));
+    assert (closestPointOnBox (V3f (7, 7, 7), box) == V3f (5, 4, 6));
+    assert (closestPointInBox (V3f (7, 7, 7), box) == V3f (5, 4, 6));
+
+    assert (closestPointOnBox (V3f (2, 3, 0), box) == V3f (2, 3, 3));
+    assert (closestPointInBox (V3f (2, 3, 0), box) == V3f (2, 3, 3));
+    assert (closestPointOnBox (V3f (2, 3, 7), box) == V3f (2, 3, 6));
+    assert (closestPointInBox (V3f (2, 3, 7), box) == V3f (2, 3, 6));
+
+    assert (closestPointOnBox (V3f (2, 0, 4), box) == V3f (2, 2, 4));
+    assert (closestPointInBox (V3f (2, 0, 4), box) == V3f (2, 2, 4));
+    assert (closestPointOnBox (V3f (2, 7, 4), box) == V3f (2, 4, 4));
+    assert (closestPointInBox (V3f (2, 7, 4), box) == V3f (2, 4, 4));
+
+    assert (closestPointOnBox (V3f (0, 3, 4), box) == V3f (1, 3, 4));
+    assert (closestPointInBox (V3f (0, 3, 4), box) == V3f (1, 3, 4));
+    assert (closestPointOnBox (V3f (7, 3, 4), box) == V3f (5, 3, 4));
+    assert (closestPointInBox (V3f (7, 3, 4), box) == V3f (5, 3, 4));
+
+    //
+    // Points inside the box
+    //
+
+    assert (closestPointOnBox (V3f (1.5, 3, 5), box) == V3f (1, 3, 5));
+    assert (closestPointInBox (V3f (1.5, 3, 5), box) == V3f (1.5, 3, 5));
+    assert (closestPointOnBox (V3f (4.5, 3, 5), box) == V3f (5, 3, 5));
+    assert (closestPointInBox (V3f (4.5, 3, 5), box) == V3f (4.5, 3, 5));
+
+    assert (closestPointOnBox (V3f (2, 2.5, 4), box) == V3f (2, 2, 4));
+    assert (closestPointInBox (V3f (2, 2.5, 4), box) == V3f (2, 2.5, 4));
+    assert (closestPointOnBox (V3f (2, 3.5, 4), box) == V3f (2, 4, 4));
+    assert (closestPointInBox (V3f (2, 3.5, 4), box) == V3f (2, 3.5, 4));
+
+    assert (closestPointOnBox (V3f (2, 3, 3.5), box) == V3f (2, 3, 3));
+    assert (closestPointInBox (V3f (2, 3, 3.5), box) == V3f (2, 3, 3.5));
+    assert (closestPointOnBox (V3f (2, 3, 5.5), box) == V3f (2, 3, 6));
+    assert (closestPointInBox (V3f (2, 3, 5.5), box) == V3f (2, 3, 5.5));
+
+    //
+    // Point at the center of the box.  "Closest point on box" is
+    // in at the center of +Y side
+    //
+
+    assert (closestPointOnBox (V3f (3, 3, 4.5), box) == V3f (3, 4, 4.5));
+    assert (closestPointInBox (V3f (3, 3, 4.5), box) == V3f (3, 3, 4.5));
+}
+
+} // namespace
+
+void
+testBoxAlgo()
+{
+    cout << "Testing box algorithms" << endl;
+
+    entryAndExitPoints1();
+    entryAndExitPoints2();
+    rayBoxIntersection1();
+    rayBoxIntersection2();
+    boxMatrixTransform();
+    pointInAndOnBox();
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testBoxAlgo.h b/src/ImathTest/testBoxAlgo.h
new file mode 100644 (file)
index 0000000..d6774de
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testBoxAlgo();
diff --git a/src/ImathTest/testClassification.cpp b/src/ImathTest/testClassification.cpp
new file mode 100644 (file)
index 0000000..69484b5
--- /dev/null
@@ -0,0 +1,178 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <half.h>
+#include <assert.h>
+#include <iostream>
+#include <type_traits>
+#include "testClassification.h"
+
+using namespace std;
+
+namespace
+{
+
+#if __cplusplus >= 201402L
+static_assert (std::is_trivially_default_constructible<half>::value,
+               "half is trivial and default constructible");
+#endif
+
+void
+testClass (half h,
+           bool finite,
+           bool normalized,
+           bool denormalized,
+           bool zero,
+           bool nan,
+           bool infinity,
+           bool negative)
+{
+    cout.width (15);
+    cout.precision (8);
+
+    cout << h << "    ";
+    printBits (cout, h);
+    cout << "    ";
+
+    if (h.isFinite())
+        cout << "finite ";
+
+    if (h.isNormalized())
+        cout << "normalized ";
+
+    if (h.isDenormalized())
+        cout << "denormalized ";
+
+    if (h.isZero())
+        cout << "zero ";
+
+    if (h.isNan())
+        cout << "nan ";
+
+    if (h.isInfinity())
+        cout << "infinity ";
+
+    if (h.isNegative())
+        cout << "negative ";
+
+    cout << endl;
+
+    assert (h.isFinite() == finite);
+    assert (h.isNormalized() == normalized);
+    assert (h.isDenormalized() == denormalized);
+    assert (h.isZero() == zero);
+    assert (h.isNan() == nan);
+    assert (h.isInfinity() == infinity);
+    assert (h.isNegative() == negative);
+}
+
+float
+floatPosInfinity()
+{
+    half::uif x;
+    x.i = 0x7f800000;
+    return x.f;
+}
+
+float
+floatNegInfinity()
+{
+    half::uif x;
+    x.i = 0xff800000;
+    return x.f;
+}
+
+float
+floatPosQNan1()
+{
+    half::uif x;
+    x.i = 0x7fffffff;
+    return x.f;
+}
+
+float
+floatNegQNan1()
+{
+    half::uif x;
+    x.i = 0xffffffff;
+    return x.f;
+}
+
+float
+floatPosQNan2()
+{
+    half::uif x;
+    x.i = 0x7fd55555;
+    return x.f;
+}
+
+float
+floatNegQNan2()
+{
+    half::uif x;
+    x.i = 0xffd55555;
+    return x.f;
+}
+
+} // namespace
+
+void
+testClassification()
+{
+    cout << "classification of bit patterns\n\n";
+
+    //
+    //                                 fini norm deno zero nan  inf  neg
+    //
+
+    testClass (0.0, 1, 0, 0, 1, 0, 0, 0);
+
+    testClass (1.0, 1, 1, 0, 0, 0, 0, 0);
+    testClass (1.0f + HALF_EPSILON, 1, 1, 0, 0, 0, 0, 0);
+    testClass (HALF_DENORM_MIN, 1, 0, 1, 0, 0, 0, 0);
+    testClass (HALF_DENORM_MIN + HALF_DENORM_MIN, 1, 0, 1, 0, 0, 0, 0);
+    testClass (HALF_NRM_MIN, 1, 1, 0, 0, 0, 0, 0);
+    testClass (HALF_NRM_MIN + HALF_DENORM_MIN, 1, 1, 0, 0, 0, 0, 0);
+    testClass (HALF_NRM_MIN - HALF_DENORM_MIN, 1, 0, 1, 0, 0, 0, 0);
+    testClass (2.0f, 1, 1, 0, 0, 0, 0, 0);
+    testClass (3.0f, 1, 1, 0, 0, 0, 0, 0);
+    testClass (0.1f, 1, 1, 0, 0, 0, 0, 0);
+    testClass (0.2f, 1, 1, 0, 0, 0, 0, 0);
+    testClass (0.3f, 1, 1, 0, 0, 0, 0, 0);
+    testClass (HALF_MAX, 1, 1, 0, 0, 0, 0, 0);
+    testClass (floatPosInfinity(), 0, 0, 0, 0, 0, 1, 0);
+    testClass (floatPosQNan1(), 0, 0, 0, 0, 1, 0, 0);
+    testClass (floatPosQNan2(), 0, 0, 0, 0, 1, 0, 0);
+
+    testClass (-1.0f, 1, 1, 0, 0, 0, 0, 1);
+    testClass (-1.0f - HALF_EPSILON, 1, 1, 0, 0, 0, 0, 1);
+    testClass (-HALF_DENORM_MIN, 1, 0, 1, 0, 0, 0, 1);
+    testClass (-HALF_DENORM_MIN - HALF_DENORM_MIN, 1, 0, 1, 0, 0, 0, 1);
+    testClass (-HALF_NRM_MIN, 1, 1, 0, 0, 0, 0, 1);
+    testClass (-HALF_NRM_MIN - HALF_DENORM_MIN, 1, 1, 0, 0, 0, 0, 1);
+    testClass (-HALF_NRM_MIN + HALF_DENORM_MIN, 1, 0, 1, 0, 0, 0, 1);
+    testClass (-2.0f, 1, 1, 0, 0, 0, 0, 1);
+    testClass (-3.0f, 1, 1, 0, 0, 0, 0, 1);
+    testClass (-0.1f, 1, 1, 0, 0, 0, 0, 1);
+    testClass (-0.2f, 1, 1, 0, 0, 0, 0, 1);
+    testClass (-0.3f, 1, 1, 0, 0, 0, 0, 1);
+    testClass (-HALF_MAX, 1, 1, 0, 0, 0, 0, 1);
+    testClass (floatNegInfinity(), 0, 0, 0, 0, 0, 1, 1);
+    testClass (floatNegQNan1(), 0, 0, 0, 0, 1, 0, 1);
+    testClass (floatNegQNan2(), 0, 0, 0, 0, 1, 0, 1);
+
+    cout << "\n";
+
+    testClass (half::posInf(), 0, 0, 0, 0, 0, 1, 0);
+    testClass (half::negInf(), 0, 0, 0, 0, 0, 1, 1);
+    testClass (half::qNan(), 0, 0, 0, 0, 1, 0, 0);
+    testClass (half::sNan(), 0, 0, 0, 0, 1, 0, 0);
+
+    cout << "ok\n\n" << flush;
+}
diff --git a/src/ImathTest/testClassification.h b/src/ImathTest/testClassification.h
new file mode 100644 (file)
index 0000000..8aa3290
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testClassification();
diff --git a/src/ImathTest/testColor.cpp b/src/ImathTest/testColor.cpp
new file mode 100644 (file)
index 0000000..df86dad
--- /dev/null
@@ -0,0 +1,246 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathColor.h>
+#include <ImathColorAlgo.h>
+#include <ImathMath.h>
+#include <ImathFun.h>
+#include <assert.h>
+#include <iostream>
+#include "testColor.h"
+
+// Include ImathForward *after* other headers to validate forward declarations
+#include <ImathForward.h>
+
+using namespace std;
+
+void
+testColor()
+{
+    cout << "Testing functions in ImathColor.h & ImathColorAlgo.h" << endl;
+
+    cout << "rgb2packed -> packed2rgb" << endl;
+
+    const float epsilon = std::numeric_limits<float>::epsilon();
+
+    IMATH_INTERNAL_NAMESPACE::PackedColor packed;
+    IMATH_INTERNAL_NAMESPACE::C3c in3 (52, 128, 254);
+    IMATH_INTERNAL_NAMESPACE::C3c out3;
+
+    packed = IMATH_INTERNAL_NAMESPACE::rgb2packed (in3);
+    IMATH_INTERNAL_NAMESPACE::packed2rgb (packed, out3);
+
+    assert (in3 == out3);
+
+    IMATH_INTERNAL_NAMESPACE::C4c testConstructor1;
+    IMATH_INTERNAL_NAMESPACE::C4c testConstructor1i (0);
+    IMATH_INTERNAL_NAMESPACE::C4c testConstructor2 (testConstructor1i);
+
+    testConstructor1 = testConstructor2; // use these so the compiler doesn't emit a warning
+
+    IMATH_INTERNAL_NAMESPACE::C4c testConstructor3 (52, 128, 254, 127);
+    IMATH_INTERNAL_NAMESPACE::C4c A (testConstructor3);
+    IMATH_INTERNAL_NAMESPACE::C4c B;
+    IMATH_INTERNAL_NAMESPACE::C4f X, Y, tmp;
+
+    packed = IMATH_INTERNAL_NAMESPACE::rgb2packed (A);
+    IMATH_INTERNAL_NAMESPACE::packed2rgb (packed, B);
+
+    assert (A == B);
+
+    cout << "Imath::Color4 * f" << endl;
+
+    assert ((IMATH_INTERNAL_NAMESPACE::C4f (0.330f, 0.710f, 0.010f, 0.999f) * 0.999f) ==
+            IMATH_INTERNAL_NAMESPACE::C4f (0.330f * 0.999f,
+                                           0.710f * 0.999f,
+                                           0.010f * 0.999f,
+                                           0.999f * 0.999f));
+
+    cout << "Imath::Color4 / f" << endl;
+
+    assert ((IMATH_INTERNAL_NAMESPACE::C4f (0.330f, 0.710f, 0.010f, 0.999f) / 0.999f) ==
+            IMATH_INTERNAL_NAMESPACE::C4f (0.330f / 0.999f,
+                                           0.710f / 0.999f,
+                                           0.010f / 0.999f,
+                                           0.999f / 0.999f));
+
+    cout << "Assignment and comparison" << endl;
+
+    B = A;
+    assert (B == A);
+    assert (!(B != A));
+
+    X = Y = IMATH_INTERNAL_NAMESPACE::C4f (0.123f, -0.420f, 0.501f, 0.998f);
+
+    X *= 0.001f;
+
+    assert (std::fabs ((Y.r * 0.001f) - X.r) <= epsilon &&
+            std::fabs ((Y.g * 0.001f) - X.g) <= epsilon &&
+            std::fabs ((Y.b * 0.001f) - X.b) <= epsilon &&
+            std::fabs ((Y.a * 0.001f) - X.a) <= epsilon);
+
+    X = Y = IMATH_INTERNAL_NAMESPACE::C4f (0.123f, -0.420f, 0.501f, 0.998f);
+
+    X /= -1.001f;
+
+    assert (std::fabs ((Y.r / -1.001f) - X.r) <= epsilon &&
+            std::fabs ((Y.g / -1.001f) - X.g) <= epsilon &&
+            std::fabs ((Y.b / -1.001f) - X.b) <= epsilon &&
+            std::fabs ((Y.a / -1.001f) - X.a) <= epsilon);
+
+    Y = IMATH_INTERNAL_NAMESPACE::C4f (0.998f, -0.001f, 0.501f, 1.001f);
+    X = IMATH_INTERNAL_NAMESPACE::C4f (0.011f, -0.420f, -0.501f, 0.998f);
+
+    tmp = X + Y;
+
+    assert (std::fabs ((X.r + Y.r) - tmp.r) <= epsilon &&
+            std::fabs ((X.g + Y.g) - tmp.g) <= epsilon &&
+            std::fabs ((X.b + Y.b) - tmp.b) <= epsilon &&
+            std::fabs ((X.a + Y.a) - tmp.a) <= epsilon);
+
+    tmp = X - Y;
+
+    assert (std::fabs ((X.r - Y.r) - tmp.r) <= epsilon &&
+            std::fabs ((X.g - Y.g) - tmp.g) <= epsilon &&
+            std::fabs ((X.b - Y.b) - tmp.b) <= epsilon &&
+            std::fabs ((X.a - Y.a) - tmp.a) <= epsilon);
+
+    tmp = X * Y;
+
+    assert (std::fabs ((X.r * Y.r) - tmp.r) <= epsilon &&
+            std::fabs ((X.g * Y.g) - tmp.g) <= epsilon &&
+            std::fabs ((X.b * Y.b) - tmp.b) <= epsilon &&
+            std::fabs ((X.a * Y.a) - tmp.a) <= epsilon);
+
+    tmp = X / Y;
+
+    //
+    // epsilon doesn't work here.
+    //
+    assert (std::fabs ((X.r / Y.r) - tmp.r) <= 1e-5f &&
+            std::fabs ((X.g / Y.g) - tmp.g) <= 1e-5f &&
+            std::fabs ((X.b / Y.b) - tmp.b) <= 1e-5f &&
+            std::fabs ((X.a / Y.a) - tmp.a) <= 1e-5f);
+
+    tmp = X;
+    tmp += Y;
+
+    assert (std::fabs ((X.r + Y.r) - tmp.r) <= epsilon &&
+            std::fabs ((X.g + Y.g) - tmp.g) <= epsilon &&
+            std::fabs ((X.b + Y.b) - tmp.b) <= epsilon &&
+            std::fabs ((X.a + Y.a) - tmp.a) <= epsilon);
+
+    tmp = X;
+    tmp -= Y;
+
+    assert (std::fabs ((X.r - Y.r) - tmp.r) <= epsilon &&
+            std::fabs ((X.g - Y.g) - tmp.g) <= epsilon &&
+            std::fabs ((X.b - Y.b) - tmp.b) <= epsilon &&
+            std::fabs ((X.a - Y.a) - tmp.a) <= epsilon);
+
+    tmp = X;
+    tmp *= Y;
+
+    assert (std::fabs ((X.r * Y.r) - tmp.r) <= epsilon &&
+            std::fabs ((X.g * Y.g) - tmp.g) <= epsilon &&
+            std::fabs ((X.b * Y.b) - tmp.b) <= epsilon &&
+            std::fabs ((X.a * Y.a) - tmp.a) <= epsilon);
+
+    tmp = X;
+    tmp /= Y;
+
+    //
+    // epsilon doesn't work here.
+    //
+    assert (std::fabs ((X.r / Y.r) - tmp.r) <= 1e-5f &&
+            std::fabs ((X.g / Y.g) - tmp.g) <= 1e-5f &&
+            std::fabs ((X.b / Y.b) - tmp.b) <= 1e-5f &&
+            std::fabs ((X.a / Y.a) - tmp.a) <= 1e-5f);
+
+    cout << "rgb2hsv and hsv2rgb" << endl;
+
+    // C4f
+    
+    IMATH_INTERNAL_NAMESPACE::C4f c4f, r4f, tmp4f;
+
+    for (float r=0.0f; r<=1.0; r += 1.0f)
+        for (float g=0.0f; g<=1.0; g += 1.0f)
+            for (float b=0.0f; b<=1.0; b += 1.0f)
+            {
+                c4f.r = r;
+                c4f.g = g;
+                c4f.b = b;
+                c4f.a = 1.0f;
+                tmp4f = rgb2hsv(c4f);
+                r4f = hsv2rgb(tmp4f);
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r4f.r, c4f.r, 1e-5f));
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r4f.g, c4f.g, 1e-5f));
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r4f.b, c4f.b, 1e-5f));
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r4f.a, c4f.a, 1e-5f));
+            }
+    
+    // C3f
+    
+    IMATH_INTERNAL_NAMESPACE::C3f c3f, r3f, tmp3f;
+
+    for (float r=0.0f; r<=1.0; r += 1.0f)
+        for (float g=0.0f; g<=1.0; g += 1.0f)
+            for (float b=0.0f; b<=1.0; b += 1.0f)
+            {
+                c3f.x = r;
+                c3f.y = g;
+                c3f.z = b;
+                tmp3f = rgb2hsv(c3f);
+                r3f = hsv2rgb(tmp3f);
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r3f.x, c3f.x, 1e-5f));
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r3f.y, c3f.y, 1e-5f));
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r3f.z, c3f.z, 1e-5f));
+            }
+    
+    // C4d
+    
+    IMATH_INTERNAL_NAMESPACE::Color4<double> c4d, r4d, tmp4d;
+
+    for (double r=0.0; r<=1.0; r += 1.0)
+        for (double g=0.0; g<=1.0; g += 1.0)
+            for (double b=0.0; b<=1.0; b += 1.0)
+            {
+                c4d.r = r;
+                c4d.g = g;
+                c4d.b = b;
+                c4d.a = 1.0;
+                tmp4d = rgb2hsv(c4d);
+                r4d = hsv2rgb(tmp4d);
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r4d.r, c4d.r, 1e-5f));
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r4d.g, c4d.g, 1e-5f));
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r4d.b, c4d.b, 1e-5f));
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r4d.a, c4d.a, 1e-5f));
+            }
+    
+
+    // C3d
+    
+    IMATH_INTERNAL_NAMESPACE::Color3<double> c3d, r3d, tmp3d;
+
+    for (double r=0.0; r<=1.0; r += 1.0)
+        for (double g=0.0; g<=1.0; g += 1.0)
+            for (double b=0.0; b<=1.0; b += 1.0)
+            {
+                c3d.x = r;
+                c3d.y = g;
+                c3d.z = b;
+                tmp3d = rgb2hsv(c3d);
+                r3d = hsv2rgb(tmp3d);
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r3d.x, c3d.x, 1e-5f));
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r3d.y, c3d.y, 1e-5f));
+                assert (IMATH_INTERNAL_NAMESPACE::equal (r3d.z, c3d.z, 1e-5f));
+            }
+    
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testColor.h b/src/ImathTest/testColor.h
new file mode 100644 (file)
index 0000000..23a0d0d
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testColor();
diff --git a/src/ImathTest/testError.cpp b/src/ImathTest/testError.cpp
new file mode 100644 (file)
index 0000000..33e599c
--- /dev/null
@@ -0,0 +1,213 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include "half.h"
+#include <assert.h>
+#include <iostream>
+#include <random>
+#include <stdlib.h>
+#include "testError.h"
+
+using namespace std;
+
+namespace
+{
+
+float
+drand()
+{
+    static std::default_random_engine generator;
+    static std::uniform_real_distribution<float> distribution (0.0f, 1.0f);
+    float r = distribution (generator);
+    return r;
+}
+
+} // namespace
+
+void
+testNormalizedConversionError()
+{
+    cout << "float-to-half conversion error for normalized half numbers\n";
+
+    float eMax = 0;
+
+    for (int i = 0; i < 20000000; i++)
+    {
+        float f (drand() * HALF_MAX);
+
+        if (f < HALF_NRM_MIN)
+            continue;
+
+        if (i & 1)
+            f = -f;
+
+        half h (f);
+        float e = 1.0f - h / f;
+
+        if (e < 0)
+            e = -e;
+
+        if (e > HALF_EPSILON * 0.5)
+        {
+            cout << "float = " << f << ", half = " << h << ", error = " << e << endl;
+
+            assert (false);
+        }
+
+        if (e > eMax)
+            eMax = e;
+    }
+
+    cout << "max error          = " << eMax << endl;
+    cout << "max expected error = " << HALF_EPSILON * 0.5 << endl;
+    cout << "ok\n\n" << flush;
+}
+
+void
+testDenormalizedConversionError()
+{
+    cout << "float-to-half conversion error for denormalized half numbers\n";
+
+    float eMax = 0;
+
+    for (int i = 0; i < 20000000; i++)
+    {
+        float f (drand() * (HALF_NRM_MIN - HALF_DENORM_MIN));
+
+        if (i & 1)
+            f = -f;
+
+        half h (f);
+        float e = h - f;
+
+        if (e < 0)
+            e = -e;
+
+        if (e > HALF_DENORM_MIN * 0.5)
+        {
+            cout << "float = " << f << ", half = " << h << ", error = " << e << endl;
+
+            assert (false);
+        }
+
+        if (e > eMax)
+            eMax = e;
+    }
+
+    cout << "max error          = " << eMax << endl;
+    cout << "max expected error = " << HALF_DENORM_MIN * 0.5 << endl;
+    cout << "ok\n\n" << flush;
+}
+
+namespace
+{
+
+void
+testNormalizedRounding (int n)
+{
+    cout << "rounding normalized numbers to " << n << "-bit precision\n";
+
+    float eExpected = (n < 10) ? HALF_EPSILON * 0.5f * (1 << (10 - n)) : 0;
+    float eMax      = 0;
+
+    for (int i = 0; i < 200000; i++)
+    {
+        half h (drand() * HALF_MAX);
+
+        if (h < HALF_NRM_MIN)
+            continue;
+
+        if (i & 1)
+            h = -h;
+
+        half r (h.round (n));
+        float e = 1.0f - r / h;
+
+        if (e < 0)
+            e = -e;
+
+        if (e > eExpected)
+        {
+            cout << "half = " << h << ", rounded = " << r << ", error = " << e
+                 << ", expected error = " << eExpected << endl;
+
+            printBits (cout, h);
+            cout << endl;
+            printBits (cout, r);
+            cout << endl;
+
+            assert (false);
+        }
+
+        if (e > eMax)
+            eMax = e;
+    }
+
+    cout << "max error          = " << eMax << endl;
+    cout << "max expected error = " << eExpected << endl;
+    cout << "ok\n\n" << flush;
+}
+
+void
+testDenormalizedRounding (int n)
+{
+    cout << "rounding denormalized numbers to " << n << "-bit precision\n";
+
+    float eExpected = (n < 10) ? HALF_DENORM_MIN * 0.5f * (1 << (10 - n)) : 0;
+    float eMax      = 0;
+
+    for (int i = 0; i < 200000; i++)
+    {
+        half h (drand() * (HALF_NRM_MIN - HALF_DENORM_MIN));
+
+        if (i & 1)
+            h = -h;
+
+        half r (h.round (n));
+        float e = r - h;
+
+        if (e < 0)
+            e = -e;
+
+        if (e > eExpected)
+        {
+            cout << "half = " << h << ", rounded = " << r << ", error = " << e
+                 << ", expected error = " << eExpected << endl;
+
+            printBits (cout, h);
+            cout << endl;
+            printBits (cout, r);
+            cout << endl;
+
+            assert (false);
+        }
+
+        if (e > eMax)
+            eMax = e;
+    }
+
+    cout << "max error          = " << eMax << endl;
+    cout << "max expected error = " << eExpected << endl;
+    cout << "ok\n\n" << flush;
+}
+
+} // namespace
+
+void
+testRoundingError()
+{
+    testNormalizedRounding (10);
+    testDenormalizedRounding (10);
+    testNormalizedRounding (9);
+    testDenormalizedRounding (9);
+    testNormalizedRounding (1);
+    testDenormalizedRounding (1);
+    testNormalizedRounding (0);
+    testDenormalizedRounding (0);
+}
diff --git a/src/ImathTest/testError.h b/src/ImathTest/testError.h
new file mode 100644 (file)
index 0000000..675c8a9
--- /dev/null
@@ -0,0 +1,8 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testNormalizedConversionError();
+void testDenormalizedConversionError();
+void testRoundingError();
diff --git a/src/ImathTest/testExtractEuler.cpp b/src/ImathTest/testExtractEuler.cpp
new file mode 100644 (file)
index 0000000..506c3d1
--- /dev/null
@@ -0,0 +1,243 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathEuler.h>
+#include <ImathFun.h>
+#include <ImathMatrixAlgo.h>
+#include <ImathRandom.h>
+#include <assert.h>
+#include <iostream>
+#include "testExtractEuler.h"
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+float
+rad (float deg)
+{
+    return deg * float(M_PI / 180);
+}
+
+M44f
+matrixEulerMatrix_1 (const M44f& M, Eulerf::Order order)
+{
+    V3f f;
+
+    if (order == Eulerf::XYZ)
+        extractEulerXYZ (M, f);
+    else
+        extractEulerZYX (M, f);
+
+    return Eulerf (f, order).toMatrix44();
+}
+
+M44f
+matrixEulerMatrix_2 (const M44f& M, Eulerf::Order order)
+{
+    Eulerf f (order);
+    f.extract (M);
+    return f.toMatrix44();
+}
+
+void
+testMatrix (const M44f M,
+            M44f (*matrixEulerMatrix) (const M44f&, Eulerf::Order),
+            Eulerf::Order order)
+{
+    //
+    // Extract Euler angles from M, and convert the
+    // Euler angles back to a matrix, N.
+    //
+
+    M44f N = matrixEulerMatrix (M, order);
+
+    //
+    // Verify that the entries in M and N do not
+    // differ too much.
+    //
+
+    M44f D (M - N);
+
+    for (int j = 0; j < 3; ++j)
+    {
+        for (int k = 0; k < 3; ++k)
+        {
+            if (abs (D[j][k]) > 0.000002)
+            {
+                cout << "unexpectedly large matrix to "
+                        "euler angles conversion error: "
+                     << D[j][k] << endl;
+
+                cout << j << " " << k << endl;
+
+                cout << "M\n" << M << endl;
+                cout << "N\n" << N << endl;
+                cout << "D\n" << D << endl;
+
+                assert (false);
+            }
+        }
+    }
+}
+
+void
+testRandomAngles (M44f (*matrixEulerMatrix) (const M44f&, Eulerf::Order), Eulerf::Order order)
+{
+    Rand48 r (0);
+
+    for (int i = 0; i < 100000; ++i)
+    {
+        //
+        // Create a rotation matrix, M
+        //
+
+        Eulerf e (
+            rad (float(r.nextf (-180, 180))),
+            rad (float(r.nextf (-180, 180))),
+            rad (float(r.nextf (-180, 180))),
+            Eulerf::XYZ);
+
+        M44f M (e.toMatrix44());
+
+        //
+        // Add a small random error to the elements of M
+        //
+
+        for (int j = 0; j < 3; ++j)
+            for (int k = 0; k < 3; ++k)
+                M[j][k] += float(r.nextf (-1e-7, 1e-7));
+
+        //
+        // Extract Euler angles from M, convert the Euler angles
+        // back to a matrix, N, and verify that the entries in M
+        // and N do not differ too much.
+        //
+
+        testMatrix (M, matrixEulerMatrix, order);
+    }
+}
+
+void
+testAngles (V3f angles, M44f (*matrixEulerMatrix) (const M44f&, Eulerf::Order), Eulerf::Order order)
+{
+    Eulerf e (rad (angles.x), rad (angles.y), rad (angles.z), order);
+
+    M44f M (e.toMatrix44());
+
+    //
+    // With rounding errors from e.toMatrix.
+    //
+
+    testMatrix (M, matrixEulerMatrix, order);
+
+    //
+    // Without rounding errors (assuming that
+    // all angles are multiples of 90 degrees).
+    //
+
+    for (int i = 0; i < 3; ++i)
+        for (int j = 0; j < 3; ++j)
+            if (M[i][j] < -0.5)
+                M[i][j] = -1;
+            else if (M[i][j] > 0.5)
+                M[i][j] = 1;
+            else
+                M[i][j] = 0;
+
+    testMatrix (M, matrixEulerMatrix, order);
+}
+
+void
+test (M44f (*matrixEulerMatrix) (const M44f&, Eulerf::Order), Eulerf::Order order)
+{
+    cout << "order = " << setbase (16) << int (order) << setbase (10) << endl;
+
+    // cout << "random angles" << endl;
+
+    testRandomAngles (matrixEulerMatrix, order);
+
+    // cout << "special angles" << endl;
+
+    for (int i = 0; i < 360; i += 90)
+        for (int j = 0; j < 360; j += 90)
+            for (int k = 0; k < 360; k += 90)
+                testAngles (V3f (float(i), float(j), float(k)), matrixEulerMatrix, order);
+}
+
+void
+testRandomAngles33()
+{
+    Rand48 r (0);
+
+    float eps = 8.0f * std::numeric_limits<float>::epsilon ();
+
+    for (int i = 0; i < 100000; ++i)
+    {
+        float angle = rad (float(r.nextf (-180, 180)));
+
+        M33f M;
+        M.setRotation (angle);
+
+        float angleEx;
+        extractEuler (M, angleEx);
+
+        assert (IMATH_INTERNAL_NAMESPACE::equal (angle, angleEx, eps));
+    }
+}
+
+} // namespace
+
+void
+testExtractEuler()
+{
+    cout << "Testing extraction of rotation angle from 3x3 matrices" << endl;
+    testRandomAngles33();
+
+    cout << "Testing extraction of Euler angles from matrices" << endl;
+
+    cout << "extractEulerXYZ()" << endl;
+    test (matrixEulerMatrix_1, Eulerf::XYZ);
+
+    cout << "extractEulerZYX()" << endl;
+    test (matrixEulerMatrix_1, Eulerf::ZYX);
+
+    cout << "Eulerf::extract()" << endl;
+    test (matrixEulerMatrix_2, Eulerf::XYZ);
+    test (matrixEulerMatrix_2, Eulerf::XZY);
+    test (matrixEulerMatrix_2, Eulerf::YZX);
+    test (matrixEulerMatrix_2, Eulerf::YXZ);
+    test (matrixEulerMatrix_2, Eulerf::ZXY);
+    test (matrixEulerMatrix_2, Eulerf::ZYX);
+
+    test (matrixEulerMatrix_2, Eulerf::XZX);
+    test (matrixEulerMatrix_2, Eulerf::XYX);
+    test (matrixEulerMatrix_2, Eulerf::YXY);
+    test (matrixEulerMatrix_2, Eulerf::YZY);
+    test (matrixEulerMatrix_2, Eulerf::ZYZ);
+    test (matrixEulerMatrix_2, Eulerf::ZXZ);
+
+    test (matrixEulerMatrix_2, Eulerf::XYZr);
+    test (matrixEulerMatrix_2, Eulerf::XZYr);
+    test (matrixEulerMatrix_2, Eulerf::YZXr);
+    test (matrixEulerMatrix_2, Eulerf::YXZr);
+    test (matrixEulerMatrix_2, Eulerf::ZXYr);
+    test (matrixEulerMatrix_2, Eulerf::ZYXr);
+
+    test (matrixEulerMatrix_2, Eulerf::XZXr);
+    test (matrixEulerMatrix_2, Eulerf::XYXr);
+    test (matrixEulerMatrix_2, Eulerf::YXYr);
+    test (matrixEulerMatrix_2, Eulerf::YZYr);
+    test (matrixEulerMatrix_2, Eulerf::ZYZr);
+    test (matrixEulerMatrix_2, Eulerf::ZXZr);
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testExtractEuler.h b/src/ImathTest/testExtractEuler.h
new file mode 100644 (file)
index 0000000..cb8840d
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testExtractEuler();
diff --git a/src/ImathTest/testExtractSHRT.cpp b/src/ImathTest/testExtractSHRT.cpp
new file mode 100644 (file)
index 0000000..af4c3e0
--- /dev/null
@@ -0,0 +1,418 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathEuler.h>
+#include <ImathFun.h>
+#include <ImathMatrixAlgo.h>
+#include <ImathRandom.h>
+#include <assert.h>
+#include <exception>
+#include <iostream>
+#include <stdio.h>
+#include "testExtractSHRT.h"
+
+#if 0
+#    define debug(x) (printf x, fflush (stdout))
+#else
+#    define debug(x)
+#endif
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+float
+rad (float deg)
+{
+    return deg * float(M_PI / 180);
+}
+
+void
+testMatrix (const M33f M)
+{
+    //
+    // Extract the rotation angle from M, and convert the
+    // angle back to a matrix, N.
+    //
+
+    V2f s (0.f), t (0.f);
+    float h, r = 0.f;
+
+    if (!extractSHRT (M, s, h, r, t, true))
+    {
+        cout << "Unable to extractSHRT" << std::endl;
+        assert (false);
+    }
+
+    M33f N;
+
+    N *= M33f().setScale (s);
+    N *= M33f().setShear (h);
+    N *= M33f().setRotation (r);
+    N *= M33f().setTranslation (t);
+
+    debug (("Re-scale: %f %f\n", s[0], s[1]));
+    debug (("Re-shear: %f\n", h));
+    debug (("Re-rot  : %f\n", r));
+    debug (("Re-trans: %f %f\n", t[0], t[1]));
+
+    //
+    // Verify that the entries in M and N do not
+    // differ too much.
+    //
+
+    M33f D (M - N);
+
+    for (int j = 0; j < 3; ++j)
+    {
+        for (int k = 0; k < 3; ++k)
+        {
+            if (abs (D[j][k]) > 0.00001)
+            {
+                cout << "unexpectedly large matrix to "
+                        "euler angles conversion error: "
+                     << D[j][k] << endl;
+
+                cout << j << " " << k << endl;
+
+                cout << "M\n" << M << endl;
+                cout << "N\n" << N << endl;
+                cout << "D\n" << D << endl;
+
+                assert (false);
+            }
+        }
+    }
+}
+
+void
+testRandomAngles33()
+{
+    Rand48 random (0);
+
+    for (int i = 0; i < 100000; ++i)
+    {
+        debug (("iteration: %d\n", i));
+
+        M33f M;
+
+        //
+        // Scale M.
+        //
+
+        V2f s (float(random.nextf (0.000001, 2.0)), 
+               float(random.nextf (0.000001, 2.0)));
+
+        for (int j = 0; j < 2; j++)
+            if (random.nextf (0.0, 1.0) >= 0.5)
+                s[j] *= -1;
+
+        M *= M33f().setScale (s);
+
+        //
+        // Shear M.
+        //
+
+        float h = float(random.nextf (0.000001, 2.));
+        if (random.nextf (0.0, 1.0) >= 0.5) h *= -1;
+
+        M *= M33f().setShear (h);
+
+        //
+        // Rotate M.
+        //
+
+        float r = rad (float(random.nextf (-180, 180)));
+
+        M *= M33f().setRotation (r);
+
+        //
+        // Translate M.
+        //
+
+        V2f t (float(random.nextf (-10, 10)),
+               float(random.nextf (-10, 10)));
+
+        M *= M33f().setTranslation (t);
+
+        //
+        // Add a small random error to the elements of M
+        //
+
+        for (int j = 0; j < 3; ++j)
+            for (int k = 0; k < 2; ++k)
+                M[j][k] += float(random.nextf (-1e-7, 1e-7));
+
+        debug (("Scale   : %f %f\n", s[0], s[1]));
+        debug (("Shear   : %f\n", h));
+        debug (("Rot     : %f\n", r));
+        debug (("Trans   : %f %f\n", t[0], t[1]));
+
+        //
+        // Extract Euler angles from M, convert the Euler angles
+        // back to a matrix, N, and verify that the entries in M
+        // and N do not differ too much.
+        //
+
+        testMatrix (M);
+
+        debug (("\n"));
+    }
+}
+
+void
+testAngles33 (float angle)
+{
+    M33f M;
+    M.setRotation (rad (angle));
+
+    //
+    // With rounding errors from e.toMatrix.
+    //
+
+    testMatrix (M);
+
+    //
+    // Without rounding errors (assuming that
+    // all angles are multiples of 90 degrees).
+    //
+
+    for (int i = 0; i < 2; ++i)
+        for (int j = 0; j < 2; ++j)
+            if (M[i][j] < -0.5)
+                M[i][j] = -1;
+            else if (M[i][j] > 0.5)
+                M[i][j] = 1;
+            else
+                M[i][j] = 0;
+
+    testMatrix (M);
+}
+
+void
+testMatrix (const M44f M)
+{
+    //
+    // Extract Euler angles from M, and convert the
+    // Euler angles back to a matrix, N.
+    //
+
+    V3f s, h, r, t;
+
+    if (!extractSHRT (M, s, h, r, t, true))
+    {
+        cout << "Unable to extractSHRT" << std::endl;
+        assert (false);
+    }
+
+    M44f N;
+
+    N.translate (t); // ... matrix compositions
+    N.rotate (r);
+    N.shear (h);
+    N.scale (s);
+
+    debug (("Re-scale: %f %f %f\n", s[0], s[1], s[2]));
+    debug (("Re-shear: %f %f %f\n", h[0], h[1], h[2]));
+    debug (("Re-rot  : %f %f %f\n", r[0], r[1], r[2]));
+    debug (("Re-trans: %f %f %f\n", t[0], t[1], t[2]));
+
+    //
+    // Verify that the entries in M and N do not
+    // differ too much.
+    //
+
+    M44f D (M - N);
+
+    for (int j = 0; j < 4; ++j)
+    {
+        for (int k = 0; k < 4; ++k)
+        {
+            if (abs (D[j][k]) > 0.00001)
+            {
+                cout << "unexpectedly large matrix to "
+                        "euler angles conversion error: "
+                     << D[j][k] << endl;
+
+                cout << j << " " << k << endl;
+
+                cout << "M\n" << M << endl;
+                cout << "N\n" << N << endl;
+                cout << "D\n" << D << endl;
+
+                assert (false);
+            }
+        }
+    }
+}
+
+void
+testRandomAngles44()
+{
+    Rand48 random (0);
+
+    for (int i = 0; i < 100000; ++i)
+    {
+        debug (("iteration: %d\n", i));
+
+        M44f M;
+
+        //
+        // Translate M.
+        //
+
+        V3f t (
+            float(random.nextf (-10, 10)),
+            float(random.nextf (-10, 10)),
+            float(random.nextf (-10, 10)));
+
+        M.translate (t);
+
+        //
+        // Rotate M.
+        //
+
+        V3f r (
+            rad (float(random.nextf (-180, 180))),
+            rad (float(random.nextf (-180, 180))),
+            rad (float(random.nextf (-180, 180))));
+
+        M.rotate (r);
+
+        //
+        // Shear M.
+        //
+
+        V3f h (
+            float(random.nextf (0.000001, 2.0)),
+            float(random.nextf (0.000001, 2.0)),
+            float(random.nextf (0.000001, 2.0)));
+
+        for (int j = 0; j < 3; j++)
+            if (random.nextf (0.0, 1.0) >= 0.5)
+                h[j] *= -1;
+
+        M.shear (h);
+
+        //
+        // Scale M.
+        //
+
+        V3f s (
+            float(random.nextf (0.000001, 2.0)),
+            float(random.nextf (0.000001, 2.0)),
+            float(random.nextf (0.000001, 2.0)));
+
+        for (int j = 0; j < 3; j++)
+            if (random.nextf (0.0, 1.0) >= 0.5)
+                s[j] *= -1;
+
+        M.scale (s);
+
+        //
+        // Add a small random error to the elements of M
+        //
+
+        for (int j = 0; j < 4; ++j)
+            for (int k = 0; k < 3; ++k)
+                M[j][k] += float(random.nextf (-1e-7, 1e-7));
+
+        debug (("Scale   : %f %f %f\n", s[0], s[1], s[2]));
+        debug (("Shear   : %f %f %f\n", h[0], h[1], h[2]));
+        debug (("Rot     : %f %f %f\n", r[0], r[1], r[2]));
+        debug (("Trans   : %f %f %f\n", t[0], t[1], t[2]));
+
+        //
+        // Extract Euler angles from M, convert the Euler angles
+        // back to a matrix, N, and verify that the entries in M
+        // and N do not differ too much.
+        //
+
+        testMatrix (M);
+
+        debug (("\n"));
+    }
+}
+
+void
+testAngles44 (V3f angles)
+{
+    Eulerf e (rad (angles.x), rad (angles.y), rad (angles.z));
+
+    M44f M (e.toMatrix44());
+
+    //
+    // With rounding errors from e.toMatrix.
+    //
+
+    testMatrix (M);
+
+    //
+    // Without rounding errors (assuming that
+    // all angles are multiples of 90 degrees).
+    //
+
+    for (int i = 0; i < 3; ++i)
+        for (int j = 0; j < 3; ++j)
+            if (M[i][j] < -0.5)
+                M[i][j] = -1;
+            else if (M[i][j] > 0.5)
+                M[i][j] = 1;
+            else
+                M[i][j] = 0;
+
+    testMatrix (M);
+}
+
+void
+test()
+{
+    cout << "  random angles" << endl;
+
+    cout << "    3x3" << endl;
+    testRandomAngles33();
+
+    cout << "    4x4" << endl;
+    testRandomAngles44();
+
+    cout << "  special angles" << endl;
+
+    cout << "    3x3" << endl;
+    for (int i = 0; i < 360; i += 90)
+        testAngles33 (float (i));
+
+    cout << "    4x4" << endl;
+    for (int i = 0; i < 360; i += 90)
+        for (int j = 0; j < 360; j += 90)
+            for (int k = 0; k < 360; k += 90)
+                testAngles44 (V3f (float(i), float(j), float(k)));
+}
+
+} // namespace
+
+void
+testExtractSHRT()
+{
+    try
+    {
+        cout << "Testing extraction of scale, shear, rotation, translation "
+             << "from matrices" << endl;
+
+        cout << "Imath::extractSHRT()" << endl;
+        test();
+
+        cout << "ok\n" << endl;
+    }
+    catch (std::exception& e)
+    {
+        cerr << "  Caught exception: " << e.what() << endl;
+    }
+}
diff --git a/src/ImathTest/testExtractSHRT.h b/src/ImathTest/testExtractSHRT.h
new file mode 100644 (file)
index 0000000..ab5022f
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testExtractSHRT();
diff --git a/src/ImathTest/testFrustum.cpp b/src/ImathTest/testFrustum.cpp
new file mode 100644 (file)
index 0000000..3bc6dfc
--- /dev/null
@@ -0,0 +1,359 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathEuler.h>
+#include <ImathFrustum.h>
+#include <ImathFun.h>
+#include <ImathVec.h>
+#include <assert.h>
+#include <iostream>
+#include "testFrustum.h"
+
+// Include ImathForward *after* other headers to validate forward declarations
+#include <ImathForward.h>
+
+using namespace std;
+
+namespace
+{
+
+void
+testFrustumPlanes (IMATH_INTERNAL_NAMESPACE::Frustumf& frustum)
+{
+    bool ortho = frustum.orthographic();
+    IMATH_INTERNAL_NAMESPACE::V3f o (0.0f, 0.0f, 0.0f);
+    float                         eps = 5.0e-4f;
+
+    for (auto xRo : { 0.0f, 100.0f, 200.0f })
+    {
+        for (auto yRo : { 0.0f, 105.0f, 210.0f, 315.0f })
+        {
+            for (auto zRo : { 0.0f, 110.0f, 220.0f, 330.0f })
+            {
+                for (auto xTr :
+                     { -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f, 8.0f })
+                {
+                    for (auto yTr : { -10.0f, -7.0f, -4.0f, -1.0f, 2.0f, 5.0f, 8.0f })
+                    {
+                        for (auto zTr : { -10.0f, -6.0f, -2.0f, 2.0f, 6.0f })
+                        {
+                            float xRoRad = xRo * (2.0f * float (M_PI) / 360.0f);
+                            float yRoRad = yRo * (2.0f * float (M_PI) / 360.0f);
+                            float zRoRad = zRo * (2.0f * float (M_PI) / 360.0f);
+                            IMATH_INTERNAL_NAMESPACE::Eulerf e (xRoRad, yRoRad, zRoRad);
+                            IMATH_INTERNAL_NAMESPACE::M44f mView = e.toMatrix44();
+                            mView.translate (IMATH_INTERNAL_NAMESPACE::V3f (xTr, yTr, zTr));
+
+                            IMATH_INTERNAL_NAMESPACE::Plane3f planes0[6];
+                            frustum.planes (planes0);
+
+                            IMATH_INTERNAL_NAMESPACE::Plane3f planes[6];
+                            frustum.planes (planes, mView);
+
+                            IMATH_INTERNAL_NAMESPACE::V3f up =
+                                IMATH_INTERNAL_NAMESPACE::V3f (0, 1, 0);
+                            assert ((up ^ planes0[0].normal) > 0.0);
+                            mView.multDirMatrix (up, up);
+                            assert ((up ^ planes[0].normal) > 0.0);
+
+                            IMATH_INTERNAL_NAMESPACE::V3f pt =
+                                (!ortho)
+                                    ? o
+                                    : IMATH_INTERNAL_NAMESPACE::V3f (0.0f, frustum.top(), 0.0f);
+                            float d = planes0[0].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+                            pt = pt * mView;
+                            d  = planes[0].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+
+                            IMATH_INTERNAL_NAMESPACE::V3f right =
+                                IMATH_INTERNAL_NAMESPACE::V3f (1, 0, 0);
+                            assert ((right ^ planes0[1].normal) > 0.0);
+                            mView.multDirMatrix (right, right);
+                            assert ((right ^ planes[1].normal) > 0.0);
+
+                            pt = (!ortho)
+                                     ? o
+                                     : IMATH_INTERNAL_NAMESPACE::V3f (frustum.right(), 0.0f, 0.0f);
+                            d = planes0[1].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+                            pt = pt * mView;
+                            d  = planes[1].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+
+                            IMATH_INTERNAL_NAMESPACE::V3f down =
+                                IMATH_INTERNAL_NAMESPACE::V3f (0, -1, 0);
+                            assert ((down ^ planes0[2].normal) > 0.0);
+                            mView.multDirMatrix (down, down);
+                            assert ((down ^ planes[2].normal) > 0.0);
+
+                            pt = (!ortho)
+                                     ? o
+                                     : IMATH_INTERNAL_NAMESPACE::V3f (0.0f, frustum.bottom(), 0.0f);
+                            d = planes0[2].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+                            pt = pt * mView;
+                            d  = planes[2].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+
+                            IMATH_INTERNAL_NAMESPACE::V3f left =
+                                IMATH_INTERNAL_NAMESPACE::V3f (-1, 0, 0);
+                            assert ((left ^ planes0[3].normal) > 0.0);
+                            mView.multDirMatrix (left, left);
+                            assert ((left ^ planes[3].normal) > 0.0);
+
+                            pt = (!ortho)
+                                     ? o
+                                     : IMATH_INTERNAL_NAMESPACE::V3f (frustum.left(), 0.0f, 0.0f);
+                            d = planes0[3].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+                            pt = pt * mView;
+                            d  = planes[3].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+
+                            IMATH_INTERNAL_NAMESPACE::V3f front =
+                                IMATH_INTERNAL_NAMESPACE::V3f (0, 0, 1);
+                            assert ((front ^ planes0[4].normal) > 0.0);
+                            mView.multDirMatrix (front, front);
+                            assert ((front ^ planes[4].normal) > 0.0);
+
+                            pt = IMATH_INTERNAL_NAMESPACE::V3f (0.0f, 0.0f, -frustum.nearPlane());
+                            d  = planes0[4].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+                            pt = pt * mView;
+                            d  = planes[4].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+
+                            IMATH_INTERNAL_NAMESPACE::V3f back =
+                                IMATH_INTERNAL_NAMESPACE::V3f (0, 0, -1);
+                            assert ((back ^ planes0[5].normal) > 0.0);
+                            mView.multDirMatrix (back, back);
+                            assert ((back ^ planes[5].normal) > 0.0);
+
+                            pt = IMATH_INTERNAL_NAMESPACE::V3f (0.0f, 0.0f, -frustum.farPlane());
+                            d  = planes0[5].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+                            pt = pt * mView;
+                            d  = planes[5].distanceTo (pt);
+                            assert (IMATH_INTERNAL_NAMESPACE::iszero (d, eps));
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+} // namespace
+
+void
+testFrustum()
+{
+    cout << "Testing functions in ImathFrustum.h";
+
+    cout << "\nperspective ";
+
+    float n = 1.7f;
+    float f = 567.0f;
+    float l = -3.5f;
+    float r = 2.0f;
+    float b = -1.3f;
+    float t = 0.9f;
+
+    IMATH_INTERNAL_NAMESPACE::Frustum<float> frustum (n, f, l, r, t, b, false);
+
+    assert (IMATH_INTERNAL_NAMESPACE::abs<float> (frustum.fovx() - (atan2 (r, n) - atan2 (l, n))) <
+            1e-6);
+    assert (IMATH_INTERNAL_NAMESPACE::abs<float> (frustum.fovy() - (atan2 (t, n) - atan2 (b, n))) <
+            1e-6);
+    cout << "1";
+    assert (IMATH_INTERNAL_NAMESPACE::abs<float> (frustum.aspectExc() - ((r - l) / (t - b))) < 1e-6);
+    assert (IMATH_INTERNAL_NAMESPACE::abs<float> (frustum.aspect() - ((r - l) / (t - b))) <
+            1e-6);
+    cout << "2";
+
+    IMATH_INTERNAL_NAMESPACE::M44f m = frustum.projectionMatrixExc ();
+    assert (
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][0] - ((2 * n) / (r - l))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][1]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][2]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][3]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][0]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][1] - ((2 * n) / (t - b))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][2]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][3]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][0] - ((r + l) / (r - l))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][1] - ((t + b) / (t - b))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][2] - (-(f + n) / (f - n))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][3] - -1.0f) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[3][0]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[3][1]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (
+            m[3][2] - ((-2 * f * n) / (f - n))) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[3][3]) < 1e-6f);
+    m = frustum.projectionMatrix ();
+    assert (
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][0] - ((2 * n) / (r - l))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][1]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][2]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][3]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][0]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][1] - ((2 * n) / (t - b))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][2]) < 1e-6 &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][3]) < 1e-6 &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][0] - ((r + l) / (r - l))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][1] - ((t + b) / (t - b))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][2] - (-(f + n) / (f - n))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][3] - -1.0f) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[3][0]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[3][1]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (
+            m[3][2] - ((-2 * f * n) / (f - n))) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[3][3]) < 1e-6f);
+    cout << "3";
+
+    cout << "\nplanes ";
+    testFrustumPlanes (frustum);
+
+    cout << "\nexceptions ";
+    IMATH_INTERNAL_NAMESPACE::Frustum<float> badFrustum;
+
+    bool caught;
+
+    badFrustum.set (n, n, l, r, t, b, false);
+    caught = false;
+    try
+    {
+        (void) badFrustum.projectionMatrixExc();
+        assert (!"near == far didn't throw an exception");
+    }
+    catch (std::domain_error&)
+    {
+        caught = true;
+    }
+    assert (caught);
+    cout << "1";
+
+    badFrustum.set (n, f, l, l, t, b, false);
+    caught = false;
+    try
+    {
+        (void) badFrustum.projectionMatrixExc();
+        assert (!"left == right didn't throw an exception");
+    }
+    catch (std::domain_error&)
+    {
+        caught = true;
+    }
+    assert (caught);
+    cout << "2";
+
+    badFrustum.set (n, f, l, r, t, t, false);
+    caught = false;
+    try
+    {
+        (void) badFrustum.projectionMatrixExc();
+        assert (!"top == bottom didn't throw an exception");
+    }
+    catch (std::domain_error&)
+    {
+        caught = true;
+    }
+    assert (caught);
+    cout << "3";
+
+    cout << "\northographic ";
+
+    frustum.setOrthographic (true);
+
+    m = frustum.projectionMatrix ();
+    assert (
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][0] - (2 / (r - l))) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][1]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][2]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[0][3]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][0]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][1] - (2 / (t - b))) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][2]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[1][3]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][0]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][1]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][2] - (-2 / (f - n))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[2][3]) < 1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[3][0] - (-(r + l) / (r - l))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[3][1] - (-(t + b) / (t - b))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[3][2] - (-(f + n) / (f - n))) <
+            1e-6f &&
+        IMATH_INTERNAL_NAMESPACE::abs<float> (m[3][3] - 1.0f) < 1e-6f);
+    cout << "1";
+
+    cout << "\nplanes ";
+    testFrustumPlanes (frustum);
+
+    // TODO - There are many little functions in IMATH_INTERNAL_NAMESPACE::Frustum which
+    // aren't tested here.  Those test should be added.  But this is
+    // a start.
+
+    IMATH_INTERNAL_NAMESPACE::Frustum<float> f1 (n, f, l, r, t, b, false);
+    IMATH_INTERNAL_NAMESPACE::Frustum<float> f2 (n, f, l, r, t, b, true);
+    assert (f1 != f2);
+    f2.set (n + 0.1f, f, l, r, t, b, false);
+    assert (f1 != f2);
+    f2.set (n, f + 0.1f, l, r, t, b, false);
+    assert (f1 != f2);
+    f2.set (n, f, l + 0.1f, r, t, b, false);
+    assert (f1 != f2);
+    f2.set (n, f, l, r + 0.1f, t, b, false);
+    assert (f1 != f2);
+    f2.set (n, f, l, r, t + 0.1f, b, false);
+    assert (f1 != f2);
+    f2.set (n, f, l, r, t, b + 0.1f, false);
+    assert (f1 != f2);
+    cout << "\npassed inequality test";
+
+    f1 = f2;
+    assert (f1 == f2);
+    cout << "\npassed equality test";
+
+    long zMax  = 100;
+    long zMin  = 1;
+    float zero = 0;
+    float one  = 1;
+    IMATH_INTERNAL_NAMESPACE::Vec3<float> v3 (zero, zero, one);
+
+    f1.set (n, f, one, zero, one);
+    f2.setExc (n, f, one, zero, one);
+
+    assert (f1 == f2);
+
+    assert (
+        f1.ZToDepth (zMin, zMin, zMax) == f1.ZToDepthExc (zMin, zMin, zMax));
+    assert (f1.normalizedZToDepth (float(zMin)) == f1.normalizedZToDepthExc (float(zMin)));
+    assert (f1.DepthToZ (n, zMin, zMax) == f1.DepthToZExc (n, zMin, zMax));
+    assert (f1.worldRadius (v3, one) == f1.worldRadiusExc (v3, one));
+    assert (f1.screenRadius (v3, one) == f1.screenRadiusExc (v3, one));
+    assert (f1.projectPointToScreen (v3) == f1.projectPointToScreenExc (v3));
+
+    cout << "\npassed noexcept equality verification";
+
+    cout << "\nok\n\n";
+}
diff --git a/src/ImathTest/testFrustum.h b/src/ImathTest/testFrustum.h
new file mode 100644 (file)
index 0000000..9047932
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testFrustum();
diff --git a/src/ImathTest/testFrustumTest.cpp b/src/ImathTest/testFrustumTest.cpp
new file mode 100644 (file)
index 0000000..1f29b2a
--- /dev/null
@@ -0,0 +1,158 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathBox.h>
+#include <ImathFrustum.h>
+#include <ImathFrustumTest.h>
+#include <ImathSphere.h>
+#include <assert.h>
+#include <iostream>
+#include "testFrustumTest.h"
+
+// Include ImathForward *after* other headers to validate forward declarations
+#include <ImathForward.h>
+
+using namespace std;
+
+void
+testFrustumTest()
+{
+    cout << "Testing functions in ImathFrustumTest.h";
+
+    cout << "\nisVisible(Vec3) ";
+
+    float n = 1.7f;
+    float f = 567.0f;
+    float l = -3.5f;
+    float r = 2.0f;
+    float b = -1.3f;
+    float t = 0.9f;
+
+    IMATH_INTERNAL_NAMESPACE::Frustum<float> frustum (n, f, l, r, t, b, false);
+
+    IMATH_INTERNAL_NAMESPACE::Matrix44<float> cameraMat;
+    IMATH_INTERNAL_NAMESPACE::Vec3<float> cameraPos (100.0f, 200.0f, 300.0f);
+    cameraMat.makeIdentity();
+    cameraMat.translate (cameraPos);
+
+    IMATH_INTERNAL_NAMESPACE::FrustumTest<float> frustumTest (frustum, cameraMat);
+
+    /////////////////////////////////////////////////////
+    // Test Vec3's
+    IMATH_INTERNAL_NAMESPACE::Vec3<float> insideVec (100.0f, 200.0f, 300 - 2.0f);
+    IMATH_INTERNAL_NAMESPACE::Vec3<float> outsideVec_near (100.0f, 200.0f, 300 - 1.5f);
+    IMATH_INTERNAL_NAMESPACE::Vec3<float> outsideVec_far (100.0f, 200.0f, 300 - 568.0f);
+    IMATH_INTERNAL_NAMESPACE::Vec3<float> outsideVec_side (100.0f, 200.0f + 100.0f, 300 - 2.0f);
+    IMATH_INTERNAL_NAMESPACE::Vec3<float> outsideVec_up (100.0f + 100.0f, 200.0f, 300 - 2.0f);
+
+    assert (frustumTest.isVisible (insideVec));
+    assert (!frustumTest.isVisible (outsideVec_near));
+    assert (!frustumTest.isVisible (outsideVec_far));
+    assert (!frustumTest.isVisible (outsideVec_side));
+    assert (!frustumTest.isVisible (outsideVec_up));
+
+    cout << "passed Vec3\n";
+
+    /////////////////////////////////////////////////////
+    // Test Boxes
+    IMATH_INTERNAL_NAMESPACE::Vec3<float> tinySize (0.0001f, 0.0001f, 0.0001f);
+    IMATH_INTERNAL_NAMESPACE::Vec3<float> hugeSize (1000.0f, 1000.0f, 1000.0f);
+
+    // Empty box should NOT be visible
+    assert (!frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>>()));
+
+    // Tiny box inside the frust should be visible
+    assert (frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>> (
+            insideVec + tinySize,
+            insideVec + tinySize)));
+
+    assert (frustumTest.completelyContains (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>> (
+            insideVec + tinySize, insideVec + tinySize)));
+    
+    // Huge boxes inside and outside should be visible
+    assert (frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>> (
+            insideVec - hugeSize,
+            insideVec + hugeSize)));
+    assert (frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>> (
+            outsideVec_near - hugeSize,
+            outsideVec_near + hugeSize)));
+    assert (frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>> (
+            outsideVec_far - hugeSize,
+            outsideVec_far + hugeSize)));
+    assert (frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>> (
+            outsideVec_side - hugeSize,
+            outsideVec_side + hugeSize)));
+    assert (frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>> (
+            outsideVec_up - hugeSize,
+            outsideVec_up + hugeSize)));
+
+    // Tiny boxes outside should NOT be visible
+    assert (!frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>> (
+            outsideVec_near - tinySize,
+            outsideVec_near + tinySize)));
+    assert (!frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>> (
+            outsideVec_far - tinySize,
+            outsideVec_far + tinySize)));
+    assert (!frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>> (
+            outsideVec_side - tinySize,
+            outsideVec_side + tinySize)));
+    assert (!frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Box<IMATH_INTERNAL_NAMESPACE::Vec3<float>> (
+            outsideVec_up - tinySize,
+            outsideVec_up + tinySize)));
+    cout << "passed Box\n";
+
+    /////////////////////////////////////////////////////
+    // Test Spheres
+    float tinyRadius = 0.0001f;
+    float hugeRadius = 1000.0f;
+
+    // Tiny sphere inside the frust should be visible
+    assert (
+        frustumTest.isVisible (IMATH_INTERNAL_NAMESPACE::Sphere3<float> (insideVec, tinyRadius)));
+
+    assert (frustumTest.completelyContains(
+        IMATH_INTERNAL_NAMESPACE::Sphere3<float> (insideVec, tinyRadius)));
+
+    // Huge spheres inside and outside should be visible
+    assert (
+        frustumTest.isVisible (IMATH_INTERNAL_NAMESPACE::Sphere3<float> (insideVec, hugeRadius)));
+    assert (frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Sphere3<float> (outsideVec_near, hugeRadius)));
+    assert (frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Sphere3<float> (outsideVec_far, hugeRadius)));
+    assert (frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Sphere3<float> (outsideVec_side, hugeRadius)));
+    assert (frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Sphere3<float> (outsideVec_up, hugeRadius)));
+
+    // Tiny spheres outside should NOT be visible
+    assert (!frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Sphere3<float> (outsideVec_near, tinyRadius)));
+    assert (!frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Sphere3<float> (outsideVec_far, tinyRadius)));
+    assert (!frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Sphere3<float> (outsideVec_side, tinyRadius)));
+    assert (!frustumTest.isVisible (
+        IMATH_INTERNAL_NAMESPACE::Sphere3<float> (outsideVec_up, tinyRadius)));
+    cout << "passed Sphere\n";
+
+    cout << "\nok\n\n";
+}
diff --git a/src/ImathTest/testFrustumTest.h b/src/ImathTest/testFrustumTest.h
new file mode 100644 (file)
index 0000000..8bbe987
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testFrustumTest();
diff --git a/src/ImathTest/testFun.cpp b/src/ImathTest/testFun.cpp
new file mode 100644 (file)
index 0000000..483b6ac
--- /dev/null
@@ -0,0 +1,295 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathFun.h>
+#if __cplusplus >= 202002L
+#    include <bit>
+#endif
+#include <iostream>
+#include <assert.h>
+#include <iostream>
+#include <cstdint>
+#include <stdio.h>
+#include <inttypes.h>
+
+using namespace std;
+
+#if __cplusplus < 202002L
+    template <typename To, typename From>
+    static inline To
+    bit_cast (From from)
+    {
+        static_assert (sizeof (From) == sizeof (To), "Type sizes do not match");
+        union
+        {
+            From f;
+            To   t;
+        } u;
+        u.f = from;
+        return u.t;
+    }
+#endif
+
+void
+testf (float f, bool changeExpected = true)
+{
+    printf ("\n");
+
+    float sf = IMATH_INTERNAL_NAMESPACE::succf (f);
+    float pf = IMATH_INTERNAL_NAMESPACE::predf (f);
+    float spf = IMATH_INTERNAL_NAMESPACE::succf (IMATH_INTERNAL_NAMESPACE::predf (f));
+    float psf = IMATH_INTERNAL_NAMESPACE::predf (IMATH_INTERNAL_NAMESPACE::succf (f));
+
+    printf ("f %.9g %" PRIx32 "\n", f, bit_cast<uint32_t> (f));
+    printf ("sf %.9g %" PRIx32 "\n", sf, bit_cast<uint32_t> (sf));
+    printf ("pf %.9g %" PRIx32 "\n", pf, bit_cast<uint32_t> (pf));
+    printf ("spf %.9g %" PRIx32 "\n", spf, bit_cast<uint32_t> (spf));
+    printf ("psf %.9g %" PRIx32 "\n", psf, bit_cast<uint32_t> (psf));
+
+    fflush (stdout);
+
+    if (changeExpected)
+    {
+        assert (pf < f);
+        assert (f < sf);
+    }
+    else
+    {
+        if (isnan(f))
+        {
+            // If f is nan, pf and sf may be converted from signaling
+            // to quiet nan, but they'll still be nan's.
+            assert (isnan(pf));
+            assert (isnan(sf));
+        }
+        else
+        {
+            // No bit change expected if input was inf.
+            assert (bit_cast<uint32_t> (pf) == bit_cast<uint32_t> (f));
+            assert (bit_cast<uint32_t> (sf) == bit_cast<uint32_t> (f));
+        }
+    }
+}
+
+void
+testd (double d, bool changeExpected = true)
+{
+    printf ("\n");
+
+    double sd = IMATH_INTERNAL_NAMESPACE::succd (d);
+    double pd = IMATH_INTERNAL_NAMESPACE::predd (d);
+    double spd = IMATH_INTERNAL_NAMESPACE::succd (IMATH_INTERNAL_NAMESPACE::predd (d));
+    double psd = IMATH_INTERNAL_NAMESPACE::predd (IMATH_INTERNAL_NAMESPACE::succd (d));
+
+    printf ("d   %0.18lg %" PRIx64 "\n", d, bit_cast<uint64_t> (d));
+    printf ("sd  %0.18lg %" PRIx64 "\n", sd, bit_cast<uint64_t> (sd));
+    printf ("pd  %0.18lg %" PRIx64 "\n", pd, bit_cast<uint64_t> (pd));
+    printf ("spd %0.18lg %" PRIx64 "\n", spd, bit_cast<uint64_t> (spd));
+    printf ("psd %0.18lg %" PRIx64 "\n", psd, bit_cast<uint64_t> (psd));
+
+    fflush (stdout);
+
+    if (changeExpected)
+    {
+        assert (pd < d);
+        assert (d < sd);
+    }
+    else
+    {
+        if (isnan(d))
+        {
+            // If f is nan, pf and sf may be converted from signaling
+            // to quiet nan, but they'll still be nan's.
+            assert (isnan(pd));
+            assert (isnan(sd));
+        }
+        else
+        {
+            // No bit change expected if input was inf.
+            assert (bit_cast<uint64_t> (pd) == bit_cast<uint64_t> (d));
+            assert (bit_cast<uint64_t> (sd) == bit_cast<uint64_t> (d));
+        }
+    }
+}
+
+void
+testFun()
+{
+    cout << "Testing functions in ImathFun.h" << endl;
+
+    cout << "floor" << endl;
+
+    assert (IMATH_INTERNAL_NAMESPACE::floor (0.0f) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::floor (0.5f) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::floor (-0.5f) == -1);
+    assert (IMATH_INTERNAL_NAMESPACE::floor (1.0f) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::floor (-1.0f) == -1);
+    assert (IMATH_INTERNAL_NAMESPACE::floor (1.5f) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::floor (-1.5f) == -2);
+
+    cout << "ceil" << endl;
+
+    assert (IMATH_INTERNAL_NAMESPACE::ceil (0.0f) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::ceil (0.5f) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::ceil (-0.5f) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::ceil (1.0f) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::ceil (-1.0f) == -1);
+    assert (IMATH_INTERNAL_NAMESPACE::ceil (1.5f) == 2);
+    assert (IMATH_INTERNAL_NAMESPACE::ceil (-1.5f) == -1);
+
+    cout << "trunc" << endl;
+
+    assert (IMATH_INTERNAL_NAMESPACE::trunc (0.0f) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::trunc (0.5f) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::trunc (-0.5f) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::trunc (1.0f) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::trunc (-1.0f) == -1);
+    assert (IMATH_INTERNAL_NAMESPACE::trunc (1.5f) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::trunc (-1.5f) == -1);
+
+    cout << "divs / mods" << endl;
+
+    assert (IMATH_INTERNAL_NAMESPACE::divs (5, 2) == 2 &&
+            IMATH_INTERNAL_NAMESPACE::mods (5, 2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (4, 2) == 2 &&
+            IMATH_INTERNAL_NAMESPACE::mods (4, 2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (3, 2) == 1 &&
+            IMATH_INTERNAL_NAMESPACE::mods (3, 2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (2, 2) == 1 &&
+            IMATH_INTERNAL_NAMESPACE::mods (2, 2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (1, 2) == 0 &&
+            IMATH_INTERNAL_NAMESPACE::mods (1, 2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (0, 2) == 0 &&
+            IMATH_INTERNAL_NAMESPACE::mods (0, 2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (-1, 2) == 0 &&
+            IMATH_INTERNAL_NAMESPACE::mods (-1, 2) == -1);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (-2, 2) == -1 &&
+            IMATH_INTERNAL_NAMESPACE::mods (-2, 2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (-3, 2) == -1 &&
+            IMATH_INTERNAL_NAMESPACE::mods (-3, 2) == -1);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (-4, 2) == -2 &&
+            IMATH_INTERNAL_NAMESPACE::mods (-4, 2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (-5, 2) == -2 &&
+            IMATH_INTERNAL_NAMESPACE::mods (-5, 2) == -1);
+
+    assert (IMATH_INTERNAL_NAMESPACE::divs (5, -2) == -2 &&
+            IMATH_INTERNAL_NAMESPACE::mods (5, -2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (4, -2) == -2 &&
+            IMATH_INTERNAL_NAMESPACE::mods (4, -2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (3, -2) == -1 &&
+            IMATH_INTERNAL_NAMESPACE::mods (3, -2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (2, -2) == -1 &&
+            IMATH_INTERNAL_NAMESPACE::mods (2, -2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (1, -2) == 0 &&
+            IMATH_INTERNAL_NAMESPACE::mods (1, -2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (0, -2) == 0 &&
+            IMATH_INTERNAL_NAMESPACE::mods (0, -2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (-1, -2) == 0 &&
+            IMATH_INTERNAL_NAMESPACE::mods (-1, -2) == -1);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (-2, -2) == 1 &&
+            IMATH_INTERNAL_NAMESPACE::mods (-2, -2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (-3, -2) == 1 &&
+            IMATH_INTERNAL_NAMESPACE::mods (-3, -2) == -1);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (-4, -2) == 2 &&
+            IMATH_INTERNAL_NAMESPACE::mods (-4, -2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divs (-5, -2) == 2 &&
+            IMATH_INTERNAL_NAMESPACE::mods (-5, -2) == -1);
+
+    cout << "divp / modp" << endl;
+
+    assert (IMATH_INTERNAL_NAMESPACE::divp (5, 2) == 2 &&
+            IMATH_INTERNAL_NAMESPACE::modp (5, 2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (4, 2) == 2 &&
+            IMATH_INTERNAL_NAMESPACE::modp (4, 2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (3, 2) == 1 &&
+            IMATH_INTERNAL_NAMESPACE::modp (3, 2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (2, 2) == 1 &&
+            IMATH_INTERNAL_NAMESPACE::modp (2, 2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (1, 2) == 0 &&
+            IMATH_INTERNAL_NAMESPACE::modp (1, 2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (0, 2) == 0 &&
+            IMATH_INTERNAL_NAMESPACE::modp (0, 2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (-1, 2) == -1 &&
+            IMATH_INTERNAL_NAMESPACE::modp (-1, 2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (-2, 2) == -1 &&
+            IMATH_INTERNAL_NAMESPACE::modp (-2, 2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (-3, 2) == -2 &&
+            IMATH_INTERNAL_NAMESPACE::modp (-3, 2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (-4, 2) == -2 &&
+            IMATH_INTERNAL_NAMESPACE::modp (-4, 2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (-5, 2) == -3 &&
+            IMATH_INTERNAL_NAMESPACE::modp (-5, 2) == 1);
+
+    assert (IMATH_INTERNAL_NAMESPACE::divp (5, -2) == -2 &&
+            IMATH_INTERNAL_NAMESPACE::modp (5, -2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (4, -2) == -2 &&
+            IMATH_INTERNAL_NAMESPACE::modp (4, -2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (3, -2) == -1 &&
+            IMATH_INTERNAL_NAMESPACE::modp (3, -2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (2, -2) == -1 &&
+            IMATH_INTERNAL_NAMESPACE::modp (2, -2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (1, -2) == 0 &&
+            IMATH_INTERNAL_NAMESPACE::modp (1, -2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (0, -2) == 0 &&
+            IMATH_INTERNAL_NAMESPACE::modp (0, -2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (-1, -2) == 1 &&
+            IMATH_INTERNAL_NAMESPACE::modp (-1, -2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (-2, -2) == 1 &&
+            IMATH_INTERNAL_NAMESPACE::modp (-2, -2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (-3, -2) == 2 &&
+            IMATH_INTERNAL_NAMESPACE::modp (-3, -2) == 1);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (-4, -2) == 2 &&
+            IMATH_INTERNAL_NAMESPACE::modp (-4, -2) == 0);
+    assert (IMATH_INTERNAL_NAMESPACE::divp (-5, -2) == 3 &&
+            IMATH_INTERNAL_NAMESPACE::modp (-5, -2) == 1);
+
+    cout << "successor, predecessor" << endl;
+
+    testf (0);
+    testf (0.0f * -1.0f);
+    testf (1);
+    testf (-1);
+    testf (16);
+    testf (7);
+    testf (0.7f);
+
+    union {float f; uint32_t i;} u;
+    u.i = 0x7f800000; //  inf
+    testf (u.f, false);
+    u.i = 0xff800000; // -inf
+    testf (u.f, false);
+    u.i = 0x7f800001; //  nan
+    testf (u.f, false);
+    u.i = 0x7f7fffff; //  FLT_MAX
+    testf (u.f);
+    u.i = 0xff7fffff; // -FLT_MAX
+    testf (u.f);
+
+    testd (0);
+    testd (0.0 * -1.0);
+    testd (1);
+    testd (-1);
+    testd (16);
+    testd (7);
+    testd (0.7);
+
+    union {double d; uint64_t i;} v;
+    v.i = 0x7ff0000000000000ULL; //  inf
+    testd (v.d, false);
+    v.i = 0xfff0000000000000ULL; // -inf
+    testd (v.d, false);
+    v.i = 0x7ff0000000000001ULL; //  NAN
+    testd (v.d, false);
+    v.i = 0x7fefffffffffffffULL; //  FLT_MAX
+    testd (v.d);
+    v.i = 0xffefffffffffffffULL; // -FLT_MAX
+    testd (v.d);
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testFun.h b/src/ImathTest/testFun.h
new file mode 100644 (file)
index 0000000..830b92d
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testFun();
diff --git a/src/ImathTest/testFunction.cpp b/src/ImathTest/testFunction.cpp
new file mode 100644 (file)
index 0000000..ad235a8
--- /dev/null
@@ -0,0 +1,74 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include "halfFunction.h"
+#include <assert.h>
+#include <iostream>
+#include "testFunction.h"
+
+using namespace std;
+
+namespace
+{
+
+float
+divideByTwo (float x)
+{
+    return x / 2;
+}
+
+struct timesN
+{
+    timesN (float n) : n (n) {}
+    float operator() (float x) { return x * n; }
+    float n;
+};
+
+} // namespace
+
+void
+testFunction()
+{
+    cout << "halfFunction<T>\n";
+
+    halfFunction<float> d2 (divideByTwo);
+
+    assert (d2 (0) == 0);
+    assert (d2 (2) == 1);
+    assert (d2 (-2) == -1);
+    assert (d2 (HALF_MAX) == HALF_MAX / 2);
+    assert (d2 (-HALF_MAX) == -HALF_MAX / 2);
+    assert (d2 (half::posInf()) == 0);
+    assert (d2 (half::negInf()) == 0);
+    assert (d2 (half::qNan()) == 0);
+
+    halfFunction<half> t5 (timesN (5), // function
+                           0,
+                           HALF_MAX / 8,   // domain
+                           -1,             // default value
+                           half::posInf(), // posInfValue
+                           half::negInf(), // negInfValue
+                           half::qNan());  // nanValue
+
+    assert (t5 (0) == 0);
+    assert (t5 (2) == 10);
+    assert (t5 (-2) == -1);
+    assert (t5 (HALF_MAX) == -1);
+    assert (t5 (-HALF_MAX) == -1);
+
+    assert (t5 (half::posInf()).isInfinity());
+    assert (!t5 (half::posInf()).isNegative());
+
+    assert (t5 (half::negInf()).isInfinity());
+    assert (t5 (half::negInf()).isNegative());
+
+    assert (t5 (half::qNan()).isNan());
+
+    cout << "ok\n\n" << flush;
+}
diff --git a/src/ImathTest/testFunction.h b/src/ImathTest/testFunction.h
new file mode 100644 (file)
index 0000000..daa14a9
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testFunction();
diff --git a/src/ImathTest/testInterop.cpp b/src/ImathTest/testInterop.cpp
new file mode 100644 (file)
index 0000000..8cbfc17
--- /dev/null
@@ -0,0 +1,719 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathFun.h>
+#include <ImathVec.h>
+#include <ImathMatrix.h>
+#include <array>
+#include <cassert>
+#include <cmath>
+#include <iostream>
+#include <vector>
+#include "testVec.h"
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+#if IMATH_FOREIGN_VECTOR_INTEROP
+
+// Imath::has_subscript fails for std::vector because its length does not
+// appear to be the length of N elements. Carve out an exception here that
+// allows this to work.
+IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER
+template<typename T, int N>
+struct has_subscript<std::vector<T>, T, N> : public std::true_type { };
+IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT
+
+
+
+namespace
+{
+
+// Extra simple vector that does nothing but allow element access, as an
+// example of a vector type that an app might use and want interop with
+// our vectors.
+template <typename T, int N>
+struct SimpleVec {
+    T elements[N];
+
+    SimpleVec(T val = T(0)) {
+        for (int i = 0; i < N; ++i)
+            elements[i] = val;
+    }
+    ~SimpleVec() = default;
+    constexpr T operator[](int i) const { return elements[i]; }
+    T& operator[](int i) { return elements[i]; }
+};
+
+
+
+// Extra simple matrix that does nothing but allow element access, as an
+// example of a matrix type that an app might use and want interop with
+// our vectors.
+template <typename T, int N>
+struct SimpleMx {
+    T elements[N][N];
+
+    SimpleMx(T val = T(0)) {
+        for (int j = 0; j < N; ++j)
+            for (int i = 0; i < N; ++i)
+                elements[j][i] = val;
+    }
+    ~SimpleMx() = default;
+    const T* operator[](int i) const { return elements[i]; }
+    T* operator[](int i) { return elements[i]; }
+};
+
+
+
+// Small structs containing just x,y,z,w elements.
+template<typename T>
+struct xy {
+    T x, y;
+};
+
+
+template<typename T>
+struct xyz {
+    T x, y, z;
+};
+
+
+template<typename T>
+struct xyzw {
+    T x, y, z, w;
+};
+
+
+template<typename T>
+struct xyz_wrong {
+    T x() { return 0; }
+    T y() { return 1; }
+    T z() { return 2; }
+};
+
+
+
+// A class that has *both* subscripting and named members
+template<typename T>
+struct ComboVec2 {
+    union {
+        T elements[2];
+        struct { T x, y; };
+    };
+
+    ComboVec2(T val = T(0)) : x(val), y(val) { }
+    ~ComboVec2() = default;
+    constexpr T operator[](int i) const { return elements[i]; }
+    T& operator[](int i) { return elements[i]; }
+};
+
+
+
+// A class that has *both* subscripting and named members
+template<typename T>
+struct ComboVec3 {
+    union {
+        T elements[3];
+        struct { T x, y, z; };
+    };
+
+    ComboVec3(T val = T(0)) : x(val), y(val), z(val) { }
+    ~ComboVec3() = default;
+    constexpr T operator[](int i) const { return elements[i]; }
+    T& operator[](int i) { return elements[i]; }
+};
+
+
+
+// A class that has *both* subscripting and named members
+template<typename T>
+struct ComboVec4 {
+    union {
+        T elements[4];
+        struct { T x, y, z, w; };
+    };
+
+    ComboVec4(T val = T(0)) : x(val), y(val), z(val), w(val) { }
+    ~ComboVec4() = default;
+    constexpr T operator[](int i) const { return elements[i]; }
+    T& operator[](int i) { return elements[i]; }
+};
+
+
+
+// Test whether a Vec contains the given elements.
+void
+testVecVal2f(const V2f& v, float a, float b)
+{
+    assert(v[0] == a && v[1] == b);
+}
+
+void
+testVecVal3f(const V3f& v, float a, float b, float c)
+{
+    assert(v[0] == a && v[1] == b && v[2] == c);
+}
+
+void
+testVecVal4f(const V4f& v, float a, float b, float c, float d)
+{
+    assert(v[0] == a && v[1] == b && v[2] == c && v[3] == d);
+}
+
+
+
+
+void
+testInteropVec2()
+{
+    std::cout << "has_xy<SimpleVec<float,2>, float>::value = "
+              << has_xy<SimpleVec<float,2>, float>::value << "\n";
+    std::cout << "has_xy<SimpleVec<int,2>, float>::value = "
+              << has_xy<SimpleVec<int,2>, float>::value << "\n";
+    std::cout << "has_xy<SimpleVec<float,4>, float>::value = "
+              << has_xy<SimpleVec<float,4>, float>::value << "\n";
+    std::cout << "has_xy<xyz<float>, float>::value = "
+              << has_xy<xyz<float>, float>::value << "\n";
+    std::cout << "has_xy<xyzw<float>, float>::value = "
+              << has_xy<xyzw<float>, float>::value << "\n";
+    std::cout << "has_xy<xy<float>, float>::value = "
+              << has_xy<xy<float>, float>::value << "\n";
+    std::cout << "has_xy<xyz<int>, float>::value = "
+              << has_xy<xyz<int>, float>::value << "\n";
+    std::cout << "has_xy<xyz_wrong<float>, float>::value = "
+              << has_xy<xyz_wrong<float>, float>::value << "\n";
+    std::cout << "\n";
+    std::cout << "has_subscript<SimpleVec<float,2>, float, 2>::value = "
+              << has_subscript<SimpleVec<float,2>, float, 2>::value << "\n";
+    std::cout << "has_subscript<SimpleVec<int,2>, float, 2>::value = "
+              << has_subscript<SimpleVec<int,2>, float, 2>::value << "\n";
+    std::cout << "has_subscript<SimpleVec<float,4>, float, 2>::value = "
+              << has_subscript<SimpleVec<float,4>, float, 2>::value << "\n";
+    std::cout << "has_subscript<xyz<float>, float, 2>::value = "
+              << has_subscript<xyz<float>, float, 2>::value << "\n";
+    std::cout << "has_subscript<xyzw<float>, float, 2>::value = "
+              << has_subscript<xyzw<float>, float, 2>::value << "\n";
+    std::cout << "has_subscript<xy<float>, float, 2>::value = "
+              << has_subscript<xy<float>, float, 2>::value << "\n";
+    std::cout << "has_subscript<xyz<int>, float, 2>::value = "
+              << has_subscript<xyz<int>, float, 2>::value << "\n";
+    std::cout << "has_subscript<xyz_wrong<float>, float, 2>::value = "
+              << has_subscript<xyz_wrong<float>, float, 2>::value << "\n";
+    std::cout << "has_subscript<std::array<float, 2>, float, 2>::value = "
+              << has_subscript<std::array<float, 2>, float, 2>::value << "\n";
+    std::cout << "has_subscript<std::array<int, 2>, float, 2>::value = "
+              << has_subscript<std::array<int, 2>, float, 2>::value << "\n";
+    std::cout << "has_subscript<std::array<float, 4>, float, 2>::value = "
+              << has_subscript<std::array<float, 4>, float, 2>::value << "\n";
+    std::cout << "has_subscript<std::vector<float>, float, 2>::value = "
+              << has_subscript<std::vector<float>, float, 2>::value << "\n";
+    std::cout << "\n";
+    std::cout << "has_xy<ComboVec3<float>, float, 2>::value = "
+              << has_xy<ComboVec3<float>, float>::value << "\n";
+    std::cout << "has_subscript<ComboVec3<float>, float, 2>::value = "
+              << has_subscript<ComboVec3<float>, float, 2>::value << "\n";
+    std::cout << "\n";
+
+    assert((!has_xy<SimpleVec<float,2>, float>::value));
+    assert((has_xy<xy<float>, float>::value));
+    assert((!has_xy<xyz<float>, float>::value));
+
+    assert((has_subscript<SimpleVec<float,2>, float, 2>::value));
+    assert((!has_subscript<SimpleVec<float,4>, float, 2>::value));
+    assert((!has_subscript<SimpleVec<float,2>, int, 2>::value));
+    assert((!has_subscript<xyz<float>, float, 2>::value));
+    assert((!has_subscript<xy<float>, float, 2>::value));
+
+    // Test construction/assignment/paramater pass of a vector type with
+    // subscripting to access components.
+    {
+        SimpleVec<float,2> s;
+        s[0] = 1;
+        s[1] = 2;
+        Vec2<float> v(s);
+        assert(v[0] == 1 && v[1] == 2);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42);
+        testVecVal2f(V2f(s), 1.0f, 42.0f);
+    }
+    // Test construction/assignment/paramater pass of a vector type with
+    // explicit .y, .y, .z components but no subscripting.
+    {
+        xy<float> s { 1, 2 };
+        Vec2<float> v(s);
+        assert(v[0] == 1 && v[1] == 2);
+        s.y = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42);
+        testVecVal2f(V2f(s), 1.0f, 42.0f);
+    }
+    // Test construction/assignment/paramater pass of a std::vector of length 3
+    {
+        std::vector<float> s { 1, 2 };
+        Vec2<float> v(s);
+        assert(v[0] == 1 && v[1] == 2);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42);
+        testVecVal2f(V2f(s), 1.0f, 42.0f);
+    }
+    // Test construction/assignment/paramater pass of a std::array of length 3
+    {
+        std::array<float, 2> s { 1, 2 };
+        Vec2<float> v(s);
+        assert(v[0] == 1 && v[1] == 2);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42);
+        testVecVal2f(V2f(s), 1.0f, 42.0f);
+    }
+    // Test construction/assignment/paramater pass of initializer lists.
+    {
+        Vec2<float> v({ 1.0f, 2.0f });
+        assert(v[0] == 1 && v[1] == 2);
+        v = { 1.0f, 42.0f };
+        assert(v[0] == 1 && v[1] == 42);
+        testVecVal2f({ 1.0f, 42.0f}, 1.0f, 42.0f);
+    }
+    // Test construction/assignment/paramater pass of a C array
+    {
+        float s[2] = { 1, 2 };
+        Vec2<float> v(s);
+        assert(v[0] == 1 && v[1] == 2);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42);
+        testVecVal2f(V2f(s), 1.0f, 42.0f);
+    }
+}
+
+
+//---------
+
+void
+testInteropVec3()
+{
+    std::cout << "has_xyz<SimpleVec<float,3>, float>::value = "
+              << has_xyz<SimpleVec<float,3>, float>::value << "\n";
+    std::cout << "has_xyz<SimpleVec<int,3>, float>::value = "
+              << has_xyz<SimpleVec<int,3>, float>::value << "\n";
+    std::cout << "has_xyz<SimpleVec<float,4>, float>::value = "
+              << has_xyz<SimpleVec<float,4>, float>::value << "\n";
+    std::cout << "has_xyz<xyz<float>, float>::value = "
+              << has_xyz<xyz<float>, float>::value << "\n";
+    std::cout << "has_xyz<xyzw<float>, float>::value = "
+              << has_xyz<xyzw<float>, float>::value << "\n";
+    std::cout << "has_xyz<xy<float>, float>::value = "
+              << has_xyz<xy<float>, float>::value << "\n";
+    std::cout << "has_xyz<xyz<int>, float>::value = "
+              << has_xyz<xyz<int>, float>::value << "\n";
+    std::cout << "has_xyz<xyz_wrong<float>, float>::value = "
+              << has_xyz<xyz_wrong<float>, float>::value << "\n";
+    std::cout << "\n";
+    std::cout << "has_subscript<SimpleVec<float,3>, float, 3>::value = "
+              << has_subscript<SimpleVec<float,3>, float, 3>::value << "\n";
+    std::cout << "has_subscript<SimpleVec<int,3>, float, 3>::value = "
+              << has_subscript<SimpleVec<int,3>, float, 3>::value << "\n";
+    std::cout << "has_subscript<SimpleVec<float,4>, float, 3>::value = "
+              << has_subscript<SimpleVec<float,4>, float, 3>::value << "\n";
+    std::cout << "has_subscript<xyz<float>, float, 3>::value = "
+              << has_subscript<xyz<float>, float, 3>::value << "\n";
+    std::cout << "has_subscript<xyzw<float>, float, 3>::value = "
+              << has_subscript<xyzw<float>, float, 3>::value << "\n";
+    std::cout << "has_subscript<xy<float>, float, 3>::value = "
+              << has_subscript<xy<float>, float, 3>::value << "\n";
+    std::cout << "has_subscript<xyz<int>, float, 3>::value = "
+              << has_subscript<xyz<int>, float, 3>::value << "\n";
+    std::cout << "has_subscript<xyz_wrong<float>, float, 3>::value = "
+              << has_subscript<xyz_wrong<float>, float, 3>::value << "\n";
+    std::cout << "has_subscript<std::array<float, 3>, float, 3>::value = "
+              << has_subscript<std::array<float, 3>, float, 3>::value << "\n";
+    std::cout << "has_subscript<std::array<int, 3>, float, 3>::value = "
+              << has_subscript<std::array<int, 3>, float, 3>::value << "\n";
+    std::cout << "has_subscript<std::array<float, 4>, float, 3>::value = "
+              << has_subscript<std::array<float, 4>, float, 3>::value << "\n";
+    std::cout << "has_subscript<std::vector<float>, float, 3>::value = "
+              << has_subscript<std::vector<float>, float, 3>::value << "\n";
+    std::cout << "\n";
+    std::cout << "has_xyz<ComboVec3<float>, float, 3>::value = "
+              << has_xyz<ComboVec3<float>, float>::value << "\n";
+    std::cout << "has_subscript<ComboVec3<float>, float, 3>::value = "
+              << has_subscript<ComboVec3<float>, float, 3>::value << "\n";
+    std::cout << "\n";
+
+    assert((!has_xyz<SimpleVec<float,3>, float>::value));
+    assert((has_xyz<xyz<float>, float>::value));
+    assert((!has_xyz<xy<float>, float>::value));
+
+    assert((has_subscript<SimpleVec<float,3>, float, 3>::value));
+    assert((!has_subscript<SimpleVec<float,4>, float, 3>::value));
+    assert((!has_subscript<SimpleVec<float,3>, int, 3>::value));
+    assert((!has_subscript<xyz<float>, float, 3>::value));
+    assert((!has_subscript<xy<float>, float, 3>::value));
+
+    // Test construction/assignment/paramater pass of a vector type with
+    // subscripting to access components.
+    {
+        SimpleVec<float,3> s;
+        s[0] = 1;
+        s[1] = 2;
+        s[2] = 3;
+        Vec3<float> v(s);
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3);
+        testVecVal3f(V3f(s), 1.0f, 42.0f, 3.0f);
+    }
+    // Test construction/assignment/paramater pass of a vector type with
+    // explicit .y, .y, .z components but no subscripting.
+    {
+        xyz<float> s { 1, 2, 3 };
+        Vec3<float> v(s);
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3);
+        s.y = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3);
+        testVecVal3f(V3f(s), 1.0f, 42.0f, 3.0f);
+    }
+    // Test construction/assignment/paramater pass of a std::vector of length 3
+    {
+        std::vector<float> s { 1, 2, 3 };
+        Vec3<float> v(s);
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3);
+        testVecVal3f(V3f(s), 1.0f, 42.0f, 3.0f);
+    }
+    // Test construction/assignment/paramater pass of a std::array of length 3
+    {
+        std::array<float, 3> s { 1, 2, 3 };
+        Vec3<float> v(s);
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3);
+        testVecVal3f(V3f(s), 1.0f, 42.0f, 3.0f);
+    }
+    // Test construction/assignment/paramater pass of initializer lists.
+    {
+        Vec3<float> v({ 1.0f, 2.0f, 3.0f });
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3);
+        v = { 1.0f, 42.0f, 3.0f };
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3);
+        testVecVal3f({ 1.0f, 42.0f, 3.0f }, 1, 42, 3);
+    }
+    // Test construction/assignment/paramater pass of a C array
+    {
+        float s[3] = { 1, 2, 3 };
+        Vec3<float> v(s);
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3);
+        testVecVal3f(V3f(s), 1.0f, 42.0f, 3.0f);
+    }
+}
+
+
+//---------
+
+void
+testInteropVec4()
+{
+    std::cout << "has_xyzw<SimpleVec<float,4>, float>::value = "
+              << has_xyzw<SimpleVec<float,4>, float>::value << "\n";
+    std::cout << "has_xyzw<SimpleVec<int,4>, float>::value = "
+              << has_xyzw<SimpleVec<int,4>, float>::value << "\n";
+    std::cout << "has_xyzw<SimpleVec<float,4>, float>::value = "
+              << has_xyzw<SimpleVec<float,4>, float>::value << "\n";
+    std::cout << "has_xyzw<xyzw<float>, float>::value = "
+              << has_xyzw<xyzw<float>, float>::value << "\n";
+    std::cout << "has_xyzw<xyzw<float>, float>::value = "
+              << has_xyzw<xyzw<float>, float>::value << "\n";
+    std::cout << "has_xyzw<xy<float>, float>::value = "
+              << has_xyzw<xy<float>, float>::value << "\n";
+    std::cout << "has_xyzw<xyzw<int>, float>::value = "
+              << has_xyzw<xyzw<int>, float>::value << "\n";
+    std::cout << "has_xyzw<xyz_wrong<float>, float>::value = "
+              << has_xyzw<xyz_wrong<float>, float>::value << "\n";
+    std::cout << "\n";
+    std::cout << "has_subscript<SimpleVec<float,4>, float, 4>::value = "
+              << has_subscript<SimpleVec<float,4>, float, 4>::value << "\n";
+    std::cout << "has_subscript<SimpleVec<int,4>, float, 4>::value = "
+              << has_subscript<SimpleVec<int,4>, float, 4>::value << "\n";
+    std::cout << "has_subscript<SimpleVec<float,4>, float, 4>::value = "
+              << has_subscript<SimpleVec<float,4>, float, 4>::value << "\n";
+    std::cout << "has_subscript<xyzw<float>, float, 4>::value = "
+              << has_subscript<xyzw<float>, float, 4>::value << "\n";
+    std::cout << "has_subscript<xyzw<float>, float, 4>::value = "
+              << has_subscript<xyzw<float>, float, 4>::value << "\n";
+    std::cout << "has_subscript<xy<float>, float, 4>::value = "
+              << has_subscript<xy<float>, float, 4>::value << "\n";
+    std::cout << "has_subscript<xyzw<int>, float, 4>::value = "
+              << has_subscript<xyzw<int>, float, 4>::value << "\n";
+    std::cout << "has_subscript<xyz_wrong<float>, float, 4>::value = "
+              << has_subscript<xyz_wrong<float>, float, 4>::value << "\n";
+    std::cout << "has_subscript<std::array<float, 3>, float, 4>::value = "
+              << has_subscript<std::array<float, 3>, float, 4>::value << "\n";
+    std::cout << "has_subscript<std::array<int, 3>, float, 4>::value = "
+              << has_subscript<std::array<int, 3>, float, 4>::value << "\n";
+    std::cout << "has_subscript<std::array<float, 4>, float, 4>::value = "
+              << has_subscript<std::array<float, 4>, float, 4>::value << "\n";
+    std::cout << "has_subscript<std::vector<float>, float, 4>::value = "
+              << has_subscript<std::vector<float>, float, 4>::value << "\n";
+    std::cout << "\n";
+    std::cout << "has_xyzw<ComboVec4<float>, float, 4>::value = "
+              << has_xyzw<ComboVec4<float>, float>::value << "\n";
+    std::cout << "has_subscript<ComboVec4<float>, float, 4>::value = "
+              << has_subscript<ComboVec4<float>, float, 4>::value << "\n";
+    std::cout << "\n";
+
+    assert((!has_xyzw<SimpleVec<float,4>, float>::value));
+    assert((has_xyzw<xyzw<float>, float>::value));
+    assert((!has_xyzw<xyz<float>, float>::value));
+
+    assert((has_subscript<SimpleVec<float,4>, float, 4>::value));
+    assert((!has_subscript<SimpleVec<float,4>, float, 3>::value));
+    assert((!has_subscript<SimpleVec<float,4>, int, 4>::value));
+    assert((!has_subscript<xyzw<float>, float, 4>::value));
+    assert((!has_subscript<xy<float>, float, 4>::value));
+
+    // Test construction/assignment/paramater pass of a vector type with
+    // subscripting to access components.
+    {
+        SimpleVec<float,4> s;
+        s[0] = 1;
+        s[1] = 2;
+        s[2] = 3;
+        s[3] = 4;
+        Vec4<float> v(s);
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3 && v[3] == 4);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3 && v[3] == 4);
+        testVecVal4f(V4f(s), 1.0f, 42.0f, 3.0f, 4.0f);
+    }
+    // Test construction/assignment/paramater pass of a vector type with
+    // explicit .y, .y, .z components but no subscripting.
+    {
+        xyzw<float> s { 1, 2, 3, 4 };
+        Vec4<float> v(s);
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3 && v[3] == 4);
+        s.y = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3 && v[3] == 4);
+        testVecVal4f(V4f(s), 1.0f, 42.0f, 3.0f, 4.0f);
+    }
+    // Test construction/assignment/paramater pass of a std::vector of length 3
+    {
+        std::vector<float> s { 1, 2, 3, 4 };
+        Vec4<float> v(s);
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3 && v[3] == 4);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3 && v[3] == 4);
+        testVecVal4f(V4f(s), 1.0f, 42.0f, 3.0f, 4.0f);
+    }
+    // Test construction/assignment/paramater pass of a std::array of length 3
+    {
+        std::array<float, 4> s { 1, 2, 3, 4 };
+        Vec4<float> v(s);
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3 && v[3] == 4);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3 && v[3] == 4);
+        testVecVal4f(V4f(s), 1.0f, 42.0f, 3.0f, 4.0f);
+    }
+    // Test construction/assignment/paramater pass of initializer lists.
+    {
+        Vec4<float> v({ 1.0f, 2.0f, 3.0f, 4.0f });
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3 && v[3] == 4);
+        v = { 1.0f, 42.0f, 3.0f, 4.0f };
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3 && v[3] == 4);
+        testVecVal4f({ 1.0f, 42.0f, 3.0f, 4.0f }, 1, 42, 3, 4);
+    }
+    // Test construction/assignment/paramater pass of a C array
+    {
+        float s[4] = { 1, 2, 3, 4 };
+        Vec4<float> v(s);
+        assert(v[0] == 1 && v[1] == 2 && v[2] == 3 && v[3] == 4);
+        s[1] = 42;
+        v = s;
+        assert(v[0] == 1 && v[1] == 42 && v[2] == 3 && v[3] == 4);
+        testVecVal4f(V4f(s), 1.0f, 42.0f, 3.0f, 4.0f);
+    }
+}
+
+
+//---------
+
+void
+testInteropMx2()
+{
+    std::cout << "has_double_subscript<SimpleMx<float,2>, float, 2, 2>::value = "
+              << has_double_subscript<SimpleMx<float,2>, float, 2, 2>::value << "\n";
+    std::cout << "has_double_subscript<SimpleMx<int,2>, float, 2, 2>::value = "
+              << has_double_subscript<SimpleMx<int,2>, float, 2, 2>::value << "\n";
+    std::cout << "has_double_subscript<SimpleMx<float,2>, float, 4, 4>::value = "
+              << has_double_subscript<SimpleMx<float,2>, float, 4, 4>::value << "\n";
+    std::cout << "has_double_subscript<xyzw<float>, float, 2, 2>::value = "
+              << has_double_subscript<xyzw<float>, float, 2, 2>::value << "\n";
+    std::cout << "has_double_subscript<xyz_wrong<float>, float, 2, 2>::value = "
+              << has_double_subscript<xyz_wrong<float>, float, 2, 2>::value << "\n";
+    std::cout << "\n";
+
+    assert((has_double_subscript<SimpleMx<float,2>, float, 2, 2>::value));
+    assert((!has_double_subscript<SimpleMx<float,2>, float, 4, 4>::value));
+    assert((!has_double_subscript<SimpleMx<float,2>, int, 2, 2>::value));
+    assert((!has_double_subscript<xyzw<float>, float, 2, 2>::value));
+    assert((!has_double_subscript<xy<float>, float, 2, 2>::value));
+
+    // Test construction/assignment/paramater pass of a vector type with
+    // subscripting to access components.
+    {
+        Matrix22<float> ref;
+        SimpleMx<float,2> s;
+        for (int j = 0; j < 2; ++j)
+            for (int i = 0; i < 2; ++i)
+            {
+                s[j][i]   = float(i + j * 2);
+                ref[j][i] = float(i + j * 2);
+            }
+        Matrix22<float> v(s);
+        assert(v[0][0] == 0 && v[0][1] == 1 &&
+               v[1][0] == 2 && v[1][1] == 3);
+        s[1][1] = 42;
+        v = s;
+        assert(v[0][0] == 0 && v[0][1] == 1 &&
+               v[1][0] == 2 && v[1][1] == 42);
+    }
+}
+
+
+
+void
+testInteropMx3()
+{
+    std::cout << "has_double_subscript<SimpleMx<float,3>, float, 3, 3>::value = "
+              << has_double_subscript<SimpleMx<float,3>, float, 3, 3>::value << "\n";
+    std::cout << "has_double_subscript<SimpleMx<int,3>, float, 3, 3>::value = "
+              << has_double_subscript<SimpleMx<int,3>, float, 3, 3>::value << "\n";
+    std::cout << "has_double_subscript<SimpleMx<float,3>, float, 4, 4>::value = "
+              << has_double_subscript<SimpleMx<float,3>, float, 4, 4>::value << "\n";
+    std::cout << "has_double_subscript<xyzw<float>, float, 3, 3>::value = "
+              << has_double_subscript<xyzw<float>, float, 3, 3>::value << "\n";
+    std::cout << "has_double_subscript<xyz_wrong<float>, float, 3, 3>::value = "
+              << has_double_subscript<xyz_wrong<float>, float, 3, 3>::value << "\n";
+    std::cout << "\n";
+
+    assert((has_double_subscript<SimpleMx<float,3>, float, 3, 3>::value));
+    assert((!has_double_subscript<SimpleMx<float,3>, float, 4, 4>::value));
+    assert((!has_double_subscript<SimpleMx<float,3>, int, 3, 3>::value));
+    assert((!has_double_subscript<xyzw<float>, float, 3, 3>::value));
+    assert((!has_double_subscript<xy<float>, float, 3, 3>::value));
+
+    // Test construction/assignment/paramater pass of a vector type with
+    // subscripting to access components.
+    {
+        Matrix33<float> ref;
+        SimpleMx<float,3> s;
+        for (int j = 0; j < 3; ++j)
+            for (int i = 0; i < 3; ++i)
+            {
+                s[j][i]   = float(i + j * 3);
+                ref[j][i] = float(i + j * 3);
+            }
+        Matrix33<float> v(s);
+        assert(v[0][0] == 0 && v[0][1] == 1 && v[0][2] == 2 &&
+               v[1][0] == 3 && v[1][1] == 4 && v[1][2] == 5 &&
+               v[2][0] == 6 && v[2][1] == 7 && v[2][2] == 8);
+        s[1][1] = 42;
+        v = s;
+        assert(v[0][0] == 0 && v[0][1] == 1 && v[0][2] == 2 &&
+               v[1][0] == 3 && v[1][1] == 42 && v[1][2] == 5 &&
+               v[2][0] == 6 && v[2][1] == 7 && v[2][2] == 8);
+    }
+}
+
+
+
+void
+testInteropMx4()
+{
+    std::cout << "has_double_subscript<SimpleMx<float,4>, float, 4, 4>::value = "
+              << has_double_subscript<SimpleMx<float,4>, float, 4, 4>::value << "\n";
+    std::cout << "has_double_subscript<SimpleMx<int,4>, float, 4, 4>::value = "
+              << has_double_subscript<SimpleMx<int,4>, float, 4, 4>::value << "\n";
+    std::cout << "has_double_subscript<SimpleMx<float,4>, float, 4, 4>::value = "
+              << has_double_subscript<SimpleMx<float,4>, float, 4, 4>::value << "\n";
+    std::cout << "has_double_subscript<xyzw<float>, float, 4, 4>::value = "
+              << has_double_subscript<xyzw<float>, float, 4, 4>::value << "\n";
+    std::cout << "has_double_subscript<xyz_wrong<float>, float, 4, 4>::value = "
+              << has_double_subscript<xyz_wrong<float>, float, 4, 4>::value << "\n";
+    std::cout << "\n";
+
+    assert((has_double_subscript<SimpleMx<float,4>, float, 4, 4>::value));
+    assert((!has_double_subscript<SimpleMx<float,4>, float, 3, 3>::value));
+    assert((!has_double_subscript<SimpleMx<float,4>, int, 4, 4>::value));
+    assert((!has_double_subscript<xyzw<float>, float, 4, 4>::value));
+    assert((!has_double_subscript<xy<float>, float, 4, 4>::value));
+
+    // Test construction/assignment/paramater pass of a vector type with
+    // subscripting to access components.
+    {
+        Matrix44<float> ref;
+        SimpleMx<float,4> s;
+        for (int j = 0; j < 4; ++j)
+            for (int i = 0; i < 4; ++i)
+            {
+                s[j][i]   = float(i + j * 4);
+                ref[j][i] = float(i + j * 4);
+            }
+        Matrix44<float> v(s);
+        assert(v[0][0] == 0 && v[0][1] == 1 && v[0][2] == 2 && v[0][3] == 3 &&
+               v[1][0] == 4 && v[1][1] == 5 && v[1][2] == 6 && v[1][3] == 7 &&
+               v[2][0] == 8 && v[2][1] == 9 && v[2][2] == 10 && v[2][3] == 11 &&
+               v[3][0] == 12 && v[3][1] == 13 && v[3][2] == 14 && v[3][3] == 15);
+        s[1][1] = 42;
+        v = s;
+        assert(v[0][0] == 0 && v[0][1] == 1 && v[0][2] == 2 && v[0][3] == 3 &&
+               v[1][0] == 4 && v[1][1] == 42 && v[1][2] == 6 && v[1][3] == 7 &&
+               v[2][0] == 8 && v[2][1] == 9 && v[2][2] == 10 && v[2][3] == 11 &&
+               v[3][0] == 12 && v[3][1] == 13 && v[3][2] == 14 && v[3][3] == 15);
+    }
+}
+
+} // namespace
+#endif
+
+
+void
+testInterop()
+{
+#if IMATH_FOREIGN_VECTOR_INTEROP
+    
+    cout << "Testing interoperability with foreign types" << endl;
+
+    testInteropVec2 ();
+    testInteropVec3 ();
+    testInteropVec4 ();
+
+    testInteropMx2();
+    testInteropMx3();
+    testInteropMx4();
+
+    cout << "ok\n" << endl;
+#else
+    cout << "Foreign vector type interopability is disabled.\n";
+#endif
+}
diff --git a/src/ImathTest/testInterop.h b/src/ImathTest/testInterop.h
new file mode 100644 (file)
index 0000000..9e3fd00
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testInterop();
diff --git a/src/ImathTest/testInterval.cpp b/src/ImathTest/testInterval.cpp
new file mode 100644 (file)
index 0000000..582e8ab
--- /dev/null
@@ -0,0 +1,785 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathInterval.h>
+#include <ImathRandom.h>
+#include <algorithm>
+#include <assert.h>
+#include <iostream>
+#include <sstream>
+#include <typeinfo>
+#include <vector>
+
+// Include ImathForward *after* other headers to validate forward declarations
+#include <ImathForward.h>
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+template <class T>
+static void
+testConstructors (const char* type)
+{
+    cout << "    constructors for type " << type << endl;
+
+    //
+    // Empty
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        assert (b.min == T (std::numeric_limits<T>::max()) && b.max == T (std::numeric_limits<T>::lowest()));
+    }
+
+    //
+    // Single point
+    //
+    {
+        T p (42);
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (p);
+        assert (b.min == p && b.max == p);
+    }
+
+    //
+    // Min and max
+    //
+    {
+        T p0 (42);
+        T p1 (666);
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (p0, p1);
+        assert (b.min == p0 && b.max == p1);
+    }
+
+    {
+        T p0 (666);
+        T p1 (42);
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (p0, p1);
+        assert (b.min == p0 && b.max == p1);
+    }
+}
+
+template <class T>
+void
+testMakeEmpty (const char* type)
+{
+    cout << "    makeEmpty() for type " << type << endl;
+
+    //
+    // Empty interval
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        b.makeEmpty();
+        assert (b.min == T (std::numeric_limits<T>::max()) && b.max == T (std::numeric_limits<T>::lowest()));
+    }
+
+    //
+    // Non-empty, has volume
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (T (-1), T (1));
+        b.makeEmpty();
+        assert (b.min == T (std::numeric_limits<T>::max()) && b.max == T (std::numeric_limits<T>::lowest()));
+    }
+
+    //
+    // Non-empty, no volume
+    //
+    {
+        T min (0);
+        T max (10);
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (min, max);
+        b.makeEmpty();
+        assert (b.min == T (std::numeric_limits<T>::max()) && b.max == T (std::numeric_limits<T>::lowest()));
+    }
+}
+
+template <class T>
+void
+testMakeInfinite (const char* type)
+{
+    cout << "    makeInfinite() for type " << type << endl;
+
+    //
+    // Infinite interval
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        b.makeInfinite();
+        assert (b.min == T (std::numeric_limits<T>::lowest()) && b.max == T (std::numeric_limits<T>::max()));
+    }
+
+    //
+    // Non-empty, has volume
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (T (-1), T (1));
+        b.makeInfinite();
+        assert (b.min == T (std::numeric_limits<T>::lowest()) && b.max == T (std::numeric_limits<T>::max()));
+    }
+
+    //
+    // Non-empty, no volume
+    //
+    {
+        T min (0);
+        T max (1);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (min, max);
+        b.makeInfinite();
+        assert (b.min == T (std::numeric_limits<T>::lowest()) && b.max == T (std::numeric_limits<T>::max()));
+    }
+}
+
+template <class T>
+void
+testExtendByPoint (const char* type)
+{
+    cout << "    extendBy() point for type " << type << endl;
+
+    IMATH_INTERNAL_NAMESPACE::Rand32 rand (0);
+
+    const unsigned int iters = 10;
+
+    //
+    // Extend empty interval with a single point.
+    //
+    for (unsigned int i = 0; i < iters; i++)
+    {
+        T p (static_cast<T>(rand.nextf (-12345, 12345)));
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        b.extendBy (p);
+        assert (b.min == p && b.max == p);
+    }
+
+    //
+    // Extend empty interval with a number of random points. Note that
+    // this also covers extending a non-empty interval.
+    //
+    for (unsigned int i = 0; i < iters; i++)
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+
+        T min;
+        T max;
+
+        for (unsigned int j = 0; j < i; j++)
+        {
+            T p (static_cast<T>(rand.nextf (-12345, 12345)));
+
+            if (j == 0)
+            {
+                min = p;
+                max = p;
+            }
+
+            min = std::min (min, p);
+            max = std::max (max, p);
+
+            b.extendBy (p);
+
+            assert (b.min == min && b.max == max);
+        }
+    }
+}
+
+template <class T>
+void
+testExtendByInterval (const char* type)
+{
+    cout << "    extendBy() interval for type " << type << endl;
+
+    //
+    // Extend empty interval with an empty interval
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        b.extendBy (IMATH_INTERNAL_NAMESPACE::Interval<T>());
+        assert (b.min == T (std::numeric_limits<T>::max()) && b.max == T (std::numeric_limits<T>::lowest()));
+    }
+
+    //
+    // Extend empty interval with a non-empty interval and vice versa.
+    //
+    {
+        T p0 (-1);
+        T p1 (1);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0;
+        b0.extendBy (IMATH_INTERNAL_NAMESPACE::Interval<T> (p0, p1));
+        assert (b0.min == p0 && b0.max == p1);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (p0, p1);
+        b1.extendBy (IMATH_INTERNAL_NAMESPACE::Interval<T>());
+        assert (b1.min == p0 && b1.max == p1);
+    }
+
+    //
+    // Extend non-empty interval with non-empty interval. Starts with empty, then builds.
+    //
+    IMATH_INTERNAL_NAMESPACE::Rand32 rand (0);
+    const unsigned int iters = 10;
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+
+        T min, max;
+
+        for (unsigned int i = 1; i < iters; i++)
+        {
+            T p0 (static_cast<T>(rand.nextf (0, 999)));
+            T p1 (static_cast<T>(rand.nextf (1000, 1999)));
+
+            min = b.min;
+            max = b.max;
+            min = std::min (min, p0);
+            max = std::max (max, p1);
+
+            b.extendBy (IMATH_INTERNAL_NAMESPACE::Interval<T> (p0, p1));
+
+            assert (b.min == min && b.max == max);
+        }
+    }
+}
+
+template <class T>
+void
+testComparators (const char* type)
+{
+    cout << "    comparators for type " << type << endl;
+
+    IMATH_INTERNAL_NAMESPACE::Rand32 rand (0);
+
+    //
+    // Compare empty.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0;
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1;
+
+        assert (b0 == b1);
+        assert (!(b0 != b1));
+    }
+
+    //
+    // Compare empty to non-empty.
+    //
+    {
+        T p0 (-1);
+        T p1 (1);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0;
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (p0, p1);
+        assert (!(b0 == b1));
+        assert (b0 != b1);
+    }
+
+    //
+    // Compare two non-empty
+    //
+    {
+        T p0 (-1);
+        T p1 (1);
+
+        T p2 (-2);
+        T p3 (2);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0 (p0, p1);
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (p2, p3);
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b2 (p0, p1);
+
+        assert (b0 != b1);
+        assert (!(b0 == b1));
+
+        assert (b0 == b2);
+        assert (!(b0 != b2));
+    }
+}
+
+template <class T>
+void
+testIntersects (const char* type)
+{
+    cout << "    intersects() for type " << type << endl;
+
+    IMATH_INTERNAL_NAMESPACE::Rand32 rand (0);
+
+    //
+    // Intersect point with empty interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        T p (1);
+
+        assert (!b.intersects (p));
+    }
+
+    //
+    // Intersect point with non-empty, has-volume interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (T (-1), T (1));
+        T p0 (0);
+        T p1 (5);
+        T p2 (-5);
+
+        assert (b.intersects (p0));
+        assert (!b.intersects (p1));
+        assert (!b.intersects (p2));
+    }
+
+    //
+    // Intersect point with non-empty, no-volume interval.
+    //
+    {
+        T min (0);
+        T max (1);
+
+        T p0 (0);
+        T p1 (5);
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (min, max);
+
+        assert (b.intersects (p0));
+        assert (!b.intersects (p1));
+    }
+
+    //
+    // Intersect empty interval with empty interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0;
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1;
+
+        assert (!b0.intersects (b1));
+        assert (!b1.intersects (b0));
+    }
+
+    //
+    // Intersect empty interval with non-empty has-volume intervales.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0;
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (T (-1), T (1));
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b2 (T (1), T (2));
+
+        assert (!b0.intersects (b1));
+        assert (!b0.intersects (b2));
+
+        assert (!b1.intersects (b0));
+        assert (!b2.intersects (b0));
+    }
+
+    //
+    // Intersect empty interval with non-empty no-volume interval.
+    //
+    {
+        T min (0);
+        T max                    = min;
+        max[T::dimensions() - 1] = 1;
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0;
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (min, max);
+
+        assert (!b0.intersects (b1));
+        assert (!b1.intersects (b0));
+    }
+
+    //
+    // Intersect non-empty has-volume interval with non-empty has-volume interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (T (-1), T (1));
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b2 (T (-1), T (1));
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b3 (T (1), T (2));
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b4 (T (2), T (3));
+
+        assert (b1.intersects (b1));
+        assert (b1.intersects (b3));
+        assert (!b1.intersects (b4));
+
+        assert (b3.intersects (b1));
+        assert (!b4.intersects (b1));
+    }
+
+    //
+    // Intersect non-empty has-volume interval with non-empty no-volume interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0 (T (-1), T (1));
+
+        T min (0);
+        T max (1);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (min, max);
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b2 (min + T (2), max + T (2));
+
+        assert (b0.intersects (b1));
+        assert (b1.intersects (b0));
+
+        assert (!b0.intersects (b2));
+        assert (!b2.intersects (b1));
+    }
+
+    //
+    // Intersect non-empty no-volume interval with non-empty no-volume interval.
+    //
+    {
+        T min (0);
+        T max (1);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0 (min, max);
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (min, max + T (2));
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b2 (min + T (2), max + T (2));
+
+        assert (b0.intersects (b1));
+        assert (b1.intersects (b0));
+
+        assert (!b0.intersects (b2));
+        assert (!b2.intersects (b0));
+    }
+}
+
+template <class T>
+void
+testSize (const char* type)
+{
+    cout << "    size() for type " << type << endl;
+
+    //
+    // Size of empty interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        assert (b.size() == T (0));
+    }
+
+    //
+    // Size of non-empty, has-volume interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0 (T (-1), T (1));
+        assert (b0.size() == T (2));
+        T p (42);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (-p, p);
+        assert (b1.size() == p * T (2));
+    }
+
+    //
+    // Size of non-empty, no-volume interval.
+    //
+    {
+        T min (0);
+        T max (1);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (min, max);
+
+        assert (b.size() == max);
+    }
+}
+
+template <class T>
+void
+testCenter (const char* type)
+{
+    cout << "    center() for type " << type << endl;
+
+    //
+    // Center of empty interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        assert (b.center() == T (0));
+    }
+
+    //
+    // Center of non-empty, has-volume interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0 (T (-1), T (1));
+        assert (b0.center() == T (0));
+
+        T p0 (1);
+        T p1 (2);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (p0, p1);
+        assert (b1.center() == (p1 + p0) / 2);
+    }
+
+    //
+    // Center of non-empty, no-volume interval.
+    //
+    {
+        T min (0);
+        T max (2);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (min, max);
+
+        assert (b.center() == max / 2);
+    }
+}
+
+template <class T>
+void
+testIsEmpty (const char* type)
+{
+    cout << "    isEmpty() for type " << type << endl;
+
+    //
+    // Empty interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        assert (b.isEmpty());
+    }
+
+    //
+    // Non-empty, has-volume interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0 (T (-1), T (1));
+        assert (!b0.isEmpty());
+
+        T p0 (2);
+        T p1 (4);
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (p0, p1);
+        assert (!b1.isEmpty());
+    }
+
+    //
+    // Non-empty, no-volume interval.
+    //
+    {
+        T min (0);
+        T max (2);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (min, max);
+
+        assert (!b.isEmpty());
+    }
+}
+
+template <class T>
+void
+testIsInfinite (const char* type)
+{
+    cout << "    isInfinite() for type " << type << endl;
+
+    //
+    // Infinite interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        b.makeInfinite();
+        assert (b.isInfinite());
+    }
+
+    //
+    // Non-empty, has-volume interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0 (T (-1), T (1));
+        assert (!b0.isInfinite());
+
+        T p0 (2);
+        T p1 (4);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (p0, p1);
+        assert (!b1.isInfinite());
+    }
+
+    //
+    // Non-empty, no-volume interval.
+    //
+    {
+        T min (0);
+        T max (2);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (min, max);
+
+        assert (!b.isInfinite());
+    }
+}
+
+template <class T>
+void
+testHasVolume (const char* type)
+{
+    cout << "    hasVolume() for type " << type << endl;
+
+    //
+    // Empty interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        assert (!b.hasVolume());
+    }
+
+    //
+    // Infinite interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b;
+        b.makeInfinite();
+        assert (b.hasVolume());
+    }
+
+    //
+    // Non-empty, has-volume interval.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b0 (T (-1), T (1));
+        assert (b0.hasVolume());
+
+        T p0 (2);
+        T p1 (4);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b1 (p0, p1);
+        assert (b1.hasVolume());
+    }
+
+    //
+    // Non-empty, no-volume interval.
+    //
+    {
+        T min (0);
+        T max (2);
+
+        IMATH_INTERNAL_NAMESPACE::Interval<T> b (min, max);
+        b.makeEmpty();
+        assert (!b.hasVolume());
+    }
+}
+
+template <class T>
+void
+testStream (const char* type)
+{
+    cout << "    hasVolume() for type " << type << endl;
+
+    T min (0);
+    T max (1);
+    
+    IMATH_INTERNAL_NAMESPACE::Interval<T> b (min, max);
+    std::stringstream s1;
+    s1 << '(' << min << ' ' << max << ')';
+
+    std::stringstream s2;
+    s2 << b;
+
+    assert (s1.str() == s2.str());
+}
+
+} // anonymous namespace
+
+void
+testInterval()
+{
+    cout << "Testing interval methods" << endl;
+
+    //
+    // Constructors
+    //
+    testConstructors<short> ("short");
+    testConstructors<int> ("int");
+    testConstructors<float> ("float");
+    testConstructors<double> ("double");
+
+    //
+    // makeEmpty()
+    //
+    testMakeEmpty<short> ("short");
+    testMakeEmpty<int> ("int");
+    testMakeEmpty<float> ("float");
+    testMakeEmpty<double> ("double");
+
+    //
+    // makeInfinite()
+    //
+    testMakeInfinite<short> ("short");
+    testMakeInfinite<int> ("int");
+    testMakeInfinite<float> ("float");
+    testMakeInfinite<double> ("double");
+    
+    //
+    // extendBy() (point)
+    //
+    testExtendByPoint<short> ("short");
+    testExtendByPoint<int> ("int");
+    testExtendByPoint<float> ("float");
+    testExtendByPoint<double> ("double");
+
+    //
+    // extendBy() interval
+    //
+    testExtendByInterval<short> ("short");
+    testExtendByInterval<int> ("int");
+    testExtendByInterval<float> ("float");
+    testExtendByInterval<double> ("double");
+
+    //
+    // == and !==
+    //
+    testComparators<short> ("short");
+    testComparators<int> ("int");
+    testComparators<float> ("float");
+    testComparators<double> ("double");
+
+    //
+    // size()
+    //
+    testSize<short> ("short");
+    testSize<int> ("int");
+    testSize<float> ("float");
+    testSize<double> ("double");
+
+    //
+    // center()
+    //
+    testCenter<short> ("short");
+    testCenter<int> ("int");
+    testCenter<float> ("float");
+    testCenter<double> ("double");
+
+    //
+    // isEmpty()
+    //
+    testIsEmpty<short> ("short");
+    testIsEmpty<int> ("int");
+    testIsEmpty<float> ("float");
+    testIsEmpty<double> ("double");
+
+    //
+    // isInfinite()
+    //
+    testIsInfinite<short> ("short");
+    testIsInfinite<int> ("int");
+    testIsInfinite<float> ("float");
+    testIsInfinite<double> ("double");
+    
+    //
+    // hasVolume()
+    //
+    testHasVolume<short> ("short");
+    testHasVolume<int> ("int");
+    testHasVolume<float> ("float");
+    testHasVolume<double> ("double");
+
+    //
+    // stream
+    //
+    testStream<short> ("short");
+    testStream<int> ("int");
+    testStream<float> ("float");
+    testStream<double> ("double");
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testInterval.h b/src/ImathTest/testInterval.h
new file mode 100644 (file)
index 0000000..fefbe7b
--- /dev/null
@@ -0,0 +1,5 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+void testInterval();
diff --git a/src/ImathTest/testInvert.cpp b/src/ImathTest/testInvert.cpp
new file mode 100644 (file)
index 0000000..cf35260
--- /dev/null
@@ -0,0 +1,138 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathMatrix.h>
+#include <ImathMatrixAlgo.h>
+#include <assert.h>
+#include <iostream>
+#include "testInvert.h"
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+void
+invertM44f (const M44f &m, float e)
+{
+    M44f inv1 = m.inverse();
+    M44f inv2 = m.gjInverse();
+    M44f ident1 = m * inv1;
+    M44f ident2 = m * inv2;
+
+    //cout << "m\n" << m << endl;
+    //cout << "inv1\n" << inv1 << "ident1\n" << ident1 << endl;
+    //cout << "inv2\n" << inv2 << "ident2\n" << ident2 << endl;
+
+    assert (ident1.equalWithAbsError (identity44f, e));
+    assert (ident2.equalWithAbsError (identity44f, e));
+}
+
+
+void
+invertM33f (const M33f &m, float e)
+{
+    M33f inv1 = m.inverse();
+    M33f inv2 = m.gjInverse();
+    M33f ident1 = m * inv1;
+    M33f ident2 = m * inv2;
+
+    //cout << "m\n" << m << endl;
+    //cout << "inv1\n" << inv1 << "ident1\n" << ident1 << endl;
+    //cout << "inv2\n" << inv2 << "ident2\n" << ident2 << endl;
+
+    assert (ident1.equalWithAbsError (identity33f, e));
+    assert (ident2.equalWithAbsError (identity33f, e));
+}
+
+
+} // namespace
+
+
+void
+testInvert ()
+{
+    cout << "Testing 4x4 and 3x3 matrix inversion:" << endl;
+
+    {
+       cout << "M44f" << endl;
+
+        // clang-format off
+
+       M44f m1 ( 1,  0,  0,  0,
+                 0,  1,  0,  0,
+                 0,  0,  1,  0,
+                 0,  0,  0,  1);
+
+       M44f m2 ( 0,  1,  0,  0,
+                -1,  0,  0,  0,
+                 0,  0,  1,  0,
+                 0,  0,  0,  1);
+
+       M44f m3 ( 1,  0,  0,  0,
+                 0,  2,  0,  0,
+                 0,  0,  0, -1,
+                 0,  0,  1,  0);
+
+       M44f m4 ( 4.683281e-01f, -8.749647e-01f,  1.229049e-01f,  0.000000e+00f,
+                 1.251189e-02f,  1.456563e-01f,  9.892561e-01f,  0.000000e+00f,
+                -8.834660e-01f, -4.617587e-01f,  7.916244e-02f,  0.000000e+00f,
+                -4.726541e+00f,  3.044795e+00f, -6.737138e+00f,  1.000000e+00f);
+
+       M44f m5 ( 4.683281e-01f, -8.749647e-01f,  1.229049e-01f,  1.000000e+00f,
+                 1.251189e-02f,  1.456563e-01f,  9.892561e-01f,  2.000000e+00f,
+                -8.834660e-01f, -4.617587e-01f,  7.916244e-02f,  3.000000e+00f,
+                -4.726541e+00f,  3.044795e+00f, -6.737138e+00f,  4.000000e+00f);
+
+        // clang-format on
+
+        invertM44f (m1, 0);
+        invertM44f (m2, 0);
+        invertM44f (m3, 0);
+        invertM44f (m4, 1e-6f);
+        invertM44f (m5, 1e-6f);
+    }
+
+    {
+       cout << "M33f" << endl;
+
+        // clang-format off
+
+       M33f m1 ( 1,  0,  0,
+                 0,  1,  0,
+                 0,  0,  1);
+
+       M33f m2 ( 0,  1,  0,
+                -1,  0,  0,
+                 0,  0,  1);
+
+       M33f m3 ( 2,  0,  0,
+                 0,  0, -1,
+                 0,  1,  0);
+
+       M33f m4 ( 4.683281e-01f, -8.749647e-01f,  0.000000e+00f,
+                 1.251189e-02f,  1.456563e-01f,  0.000000e+00f,
+                 0.000000e+00f,  0.000000e+00f,  1.000000e+00f);
+
+       M33f m5 ( 4.683281e-01f, -8.749647e-01f,  1.229049e-01f,
+                 1.251189e-02f,  1.456563e-01f,  9.892561e-01f,
+                -8.834660e-01f, -4.617587e-01f,  7.916244e-02f);
+
+        // clang-format on
+
+        invertM33f (m1, 0);
+        invertM33f (m2, 0);
+        invertM33f (m3, 0);
+        invertM33f (m4, 1e-6f);
+        invertM33f (m5, 1e-6f);
+    }
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testInvert.h b/src/ImathTest/testInvert.h
new file mode 100644 (file)
index 0000000..2f27f17
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testInvert();
diff --git a/src/ImathTest/testJacobiEigenSolver.cpp b/src/ImathTest/testJacobiEigenSolver.cpp
new file mode 100644 (file)
index 0000000..3b23092
--- /dev/null
@@ -0,0 +1,285 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathMatrix.h>
+#include <ImathMatrixAlgo.h>
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <ctime>
+#include <iostream>
+#include <limits>
+#include <math.h>
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+// clang-format off
+
+const Matrix33<double> A33_1 ( 1, 0, 0, 0, 1, 0, 0, 0, 1 );
+const Matrix33<double> A33_2 ( 1, 0, 0, 0,-1, 0, 0, 0, 1 );
+const Matrix33<double> A33_3 ( 1, 0, 0, 0, 1, 0, 0, 0, 0 );
+const Matrix33<double> A33_4 ( 1, 0, 0, 0, 0, 0, 0, 0, 0 );
+const Matrix33<double> A33_5 ( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+const Matrix33<double> A33_6 ( 1, 0, 0, 0, 1e-10, 0, 0, 0, 0 );
+const Matrix33<double> A33_7 ( 1, 0, 0, 0, 1e-10, 0, 0, 0, 1e+10 );
+const Matrix33<double> A33_8 (
+     0.25058694044821,  0.49427229444416,  0.81415724537748,
+     0.49427229444416,  0.80192384710853, -0.61674948224910,
+     0.81415724537748, -0.61674948224910, -1.28486154645285);
+
+const Matrix44<double> A44_1 ( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 );
+const Matrix44<double> A44_2 ( 1, 0, 0, 0, 0,-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 );
+const Matrix44<double> A44_3 ( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+const Matrix44<double> A44_4 ( 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+const Matrix44<double> A44_5 ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+const Matrix44<double> A44_6 ( 1, 0, 0, 0, 0, 1e-20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+const Matrix44<double> A44_7 ( 1, 0, 0, 0, 0, 1e-20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1e+20 );
+const Matrix44<double> A44_8 (
+     4.05747631538951,  0.16358123075600,  0.11541756047409, -1.65369223465270,
+     0.16358123075600,  0.57629829390780,  3.88542912704029,  0.92016316185369,
+     0.11541756047409,  3.88542912704029,  0.65367032943707, -0.21971103270410,
+    -1.65369223465270,  0.92016316185369, -0.21971103270410, -0.28108876552761);
+
+// clang-format on
+
+template <typename TM>
+void
+verifyOrthonormal (const TM& A, const typename TM::BaseType threshold)
+{
+    const TM prod = A * A.transposed ();
+    for (unsigned int i = 0; i < TM::dimensions (); ++i)
+        for (unsigned int j = 0; j < TM::dimensions (); ++j)
+            if (i == j)
+                assert (std::abs (prod[i][j] - 1) < threshold);
+            else
+                assert (std::abs (prod[i][j]) < threshold);
+}
+
+template <typename TM>
+typename TM::BaseType
+computeThreshold(const TM& A)
+{
+   typedef typename TM::BaseType T;
+   T maxAbsEntry(0);
+
+    for (unsigned int i = 0; i < TM::dimensions (); ++i)
+        for (unsigned int j = 0; j < TM::dimensions (); ++j)
+            maxAbsEntry = std::max (maxAbsEntry, std::abs (A[i][j]));
+
+   const T eps = std::numeric_limits<T>::epsilon();
+   maxAbsEntry = std::max(maxAbsEntry, eps);
+
+   return maxAbsEntry * T(100) * eps;
+}
+
+template<class TM>
+void
+testJacobiEigenSolver(const TM& A)
+{
+    using std::abs;
+
+    typedef typename TM::BaseType T;
+    typedef typename TM::BaseVecType TV;
+
+    const T threshold = computeThreshold(A);
+
+    TM AA(A);
+    TV S;
+    TM V;
+
+    jacobiEigenSolver(AA, S, V);
+
+    // Orthogonality of V
+    verifyOrthonormal(V, threshold);
+    // Determinant of V
+    assert(abs(V.determinant()) - 1 < threshold);
+
+    // Determinant of A and S
+    TM MS;
+    for (unsigned int i = 0; i < TM::dimensions (); ++i)
+        for (unsigned int j = 0; j < TM::dimensions (); ++j)
+            if (i == j)
+                MS[i][j] = S[i];
+            else
+                MS[i][j] = 0;
+
+    assert (abs (A.determinant()) - abs (MS.determinant()) < threshold);
+
+    // A = V * S * V^T
+    TM MA = V * MS * V.transposed();
+
+    for (unsigned int i = 0; i < TM::dimensions (); ++i)
+        for (unsigned int j = 0; j < TM::dimensions (); ++j)
+            assert (abs (A[i][j] - MA[i][j]) < threshold);
+}
+
+template<class TM>
+void
+testMinMaxEigenValue(const TM& A)
+{
+  typedef typename TM::BaseVecType TV;
+  typedef typename TM::BaseType T;
+
+  TV minV, maxV, S;
+  TM U, V;
+  
+  const T threshold = computeThreshold(A);
+
+  {
+      TM A1(A);
+      minEigenVector(A1, minV);
+      TM A2(A);
+      maxEigenVector(A2, maxV);
+  }
+  {
+      TM A3(A);
+      jacobiSVD(A3, U, S, V);
+  }
+
+  const int dim = TM::dimensions();
+
+    for (int i = 0; i < dim; ++i)
+    {
+      assert(abs(minV[i]-V[i][dim - 1]) < threshold);
+      assert(abs(maxV[i]-V[i][0]) < threshold);
+  }
+}
+
+template <class T>
+void
+testJacobiTiming()
+{
+
+    int rounds(100000);
+    clock_t tJacobi,tSVD, t;
+
+    {
+        Matrix33<T> A,V,U;
+        Vec3<T> S;
+
+        t = clock();
+        for (int i = 0; i < rounds; ++i)
+        {
+            A = Matrix33<T>(A33_7);
+            jacobiEigenSolver(A, S, V);
+            A = Matrix33<T>(A33_8);
+            jacobiEigenSolver(A, S, V);
+        }
+        tJacobi = clock() - t;
+        cout << "Jacobi EigenSolver of 3x3 matrices took " << tJacobi << " clocks." << endl;
+
+        t = clock();
+        for (int i = 0; i < rounds; ++i)
+        {
+            A = Matrix33<T>(A33_7);
+            jacobiSVD(A, U, S, V);
+            A = Matrix33<T>(A33_8);
+            jacobiSVD(A, U, S, V);
+        }
+        tSVD = clock() - t;
+        cout << "TinySVD            of 3x3 matrices took " << tSVD << " clocks." << endl;
+        cout << (float)(tSVD-tJacobi)*100.0f/(float)(tSVD) << "% speed up." << endl;
+    }
+
+    {
+        Matrix44<T> A,V,U;
+        Vec4<T> S;
+
+        t = clock();
+        for (int i = 0; i < rounds; ++i)
+        {
+            A = Matrix44<T>(A44_7);
+            jacobiEigenSolver(A, S, V);
+            A = Matrix44<T>(A44_8);
+            jacobiEigenSolver(A, S, V);
+        }
+        tJacobi = clock() - t;
+        cout << "Jacobi EigenSolver of 4x4 matrices took " << tJacobi << " clocks" << endl;
+
+        t = clock();
+        for (int i = 0; i < rounds; ++i)
+        {
+            A = Matrix44<T>(A44_7);
+            jacobiSVD(A, U, S, V);
+            A = Matrix44<T>(A44_8);
+            jacobiSVD(A, U, S, V);
+        }
+        tSVD = clock() - t;
+        cout << "TinySVD            of 4x4 matrices took " << tSVD << " clocks" << endl;
+        cout << (float)(tSVD-tJacobi)*100.0f/(float)(tSVD) << "% speed up." << endl;
+    }
+}
+
+template <class T>
+void
+testJacobiEigenSolverImp()
+{
+    testJacobiEigenSolver(Matrix33<T>(A33_1));
+    testJacobiEigenSolver(Matrix33<T>(A33_2));
+    testJacobiEigenSolver(Matrix33<T>(A33_3));
+    testJacobiEigenSolver(Matrix33<T>(A33_4));
+    testJacobiEigenSolver(Matrix33<T>(A33_5));
+    testJacobiEigenSolver(Matrix33<T>(A33_6));
+    testJacobiEigenSolver(Matrix33<T>(A33_7));
+    testJacobiEigenSolver(Matrix33<T>(A33_8));
+
+    testJacobiEigenSolver(Matrix44<T>(A44_1));
+    testJacobiEigenSolver(Matrix44<T>(A44_2));
+    testJacobiEigenSolver(Matrix44<T>(A44_3));
+    testJacobiEigenSolver(Matrix44<T>(A44_4));
+    testJacobiEigenSolver(Matrix44<T>(A44_5));
+    testJacobiEigenSolver(Matrix44<T>(A44_6));
+    testJacobiEigenSolver(Matrix44<T>(A44_7));
+    testJacobiEigenSolver(Matrix44<T>(A44_8));
+}
+
+template <class T>
+void
+testMinMaxEigenValueImp()
+{
+    testMinMaxEigenValue(Matrix33<T>(A33_7));
+    testMinMaxEigenValue(Matrix33<T>(A33_8));
+
+    testMinMaxEigenValue(Matrix44<T>(A44_7));
+    testMinMaxEigenValue(Matrix44<T>(A44_8));
+}
+
+void
+testJacobiEigenSolver()
+{
+    cout << endl;
+    cout << "************ Testing IMATH_INTERNAL_NAMESPACE::ImathJacobiEigenSolver ************"
+         << endl;
+    
+    cout << "Jacobi EigenSolver in single precision...";
+    testJacobiEigenSolverImp<float>();
+    cout << "PASS" << endl;
+
+    cout << "Jacobi EigenSolver in double precision...";
+    testJacobiEigenSolverImp<double>();
+    cout << "PASS" << endl;
+
+    cout << "Min/Max EigenValue in single precision...";
+    testMinMaxEigenValueImp<float>();
+    cout << "PASS" << endl;
+
+    cout << "Min/Max EigenValue in double precision...";
+    testMinMaxEigenValueImp<double>();
+    cout << "PASS" << endl;
+
+    cout << "Timing Jacobi EigenSolver in single precision...\n";
+    testJacobiTiming<float>();
+
+    cout << "Timing Jacobi EigenSolver in double precision...\n";
+    testJacobiTiming<double>();
+    
+    cout << "************      ALL PASS          ************" << endl;
+}
diff --git a/src/ImathTest/testJacobiEigenSolver.h b/src/ImathTest/testJacobiEigenSolver.h
new file mode 100644 (file)
index 0000000..2e9dbcd
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testJacobiEigenSolver();
diff --git a/src/ImathTest/testLimits.cpp b/src/ImathTest/testLimits.cpp
new file mode 100644 (file)
index 0000000..87ac8d1
--- /dev/null
@@ -0,0 +1,153 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include "testLimits.h"
+#include "half.h"
+#include <assert.h>
+#include <cmath>
+#include <iostream>
+#include "testLimits.h"
+
+using namespace std;
+
+namespace
+{
+
+float
+mypow (int x, int y)
+{
+    bool negative = false;
+
+    if (y < 0)
+    {
+        negative = true;
+        y        = -y;
+    }
+
+    float z = 1;
+
+    while (y > 0)
+    {
+        z *= x;
+        y -= 1;
+    }
+
+    if (negative)
+        z = 1 / z;
+
+    return z;
+}
+
+} // namespace
+
+void
+testLimits()
+{
+    cout << "values in std::numeric_limits<half>\n";
+
+    cout << "min_exponent\n";
+
+    {
+        half h (mypow (2, numeric_limits<half>::min_exponent - 1));
+        assert (h.isNormalized());
+    }
+
+    {
+        half h (mypow (2, numeric_limits<half>::min_exponent - 2));
+        assert (h.isDenormalized());
+    }
+
+    cout << "max_exponent\n";
+
+    {
+        half h (mypow (2, numeric_limits<half>::max_exponent - 1));
+        assert (h.isNormalized());
+    }
+
+    {
+        half h (mypow (2, numeric_limits<half>::max_exponent));
+        assert (h.isInfinity());
+    }
+
+    cout << "min_exponent10\n";
+
+    {
+        half h (mypow (10, numeric_limits<half>::min_exponent10));
+        assert (h.isNormalized());
+    }
+
+    {
+        half h (mypow (10, numeric_limits<half>::min_exponent10 - 1));
+        assert (h.isDenormalized());
+    }
+
+    cout << "max_exponent10\n";
+
+    {
+        half h (mypow (10, numeric_limits<half>::max_exponent10));
+        assert (h.isNormalized());
+    }
+
+    {
+        half h (mypow (10, numeric_limits<half>::max_exponent10 + 1));
+        assert (h.isInfinity());
+    }
+
+#if __cplusplus >= 201103L
+
+    cout << "max_digits10\n";
+    assert (numeric_limits<half>::max_digits10 ==
+            std::ceil (numeric_limits<half>::digits * std::log10 (2) + 1));
+
+    cout << "lowest\n";
+    assert (numeric_limits<half>::lowest() == -HALF_MAX);
+
+#endif
+
+    cout << "ok\n\n" << flush;
+}
+
+void
+testHalfLimits()
+{
+    cout << "values in std::numeric_limits<half>\n";
+
+    // For reference:
+    printf("HALF_DENORM_MIN %g -> 0x%04x\n", (float)HALF_DENORM_MIN, half(HALF_DENORM_MIN).bits());
+    printf("HALF_NRM_MIN %g -> 0x%04x\n", (float)HALF_NRM_MIN, half(HALF_NRM_MIN).bits());
+    printf("HALF_MIN %g -> 0x%04x\n", (float)HALF_MIN, half(HALF_MIN).bits());
+    printf("HALF_MAX %g -> 0x%04x\n", (float)HALF_MAX, half(HALF_MAX).bits());
+    printf("HALF_LOWEST %g -> 0x%04x\n", (float)-HALF_MAX, half(-HALF_MAX).bits());
+    printf("HALF_EPSILON %g -> 0x%04x\n", (float)HALF_EPSILON, half(HALF_EPSILON).bits());
+    printf("half posInf %g -> 0x%04x\n", (float)half::posInf(), half::posInf().bits());
+    printf("half negInf %g -> 0x%04x\n", (float)half::negInf(), half::negInf().bits());
+    printf("half qNan %g -> 0x%04x\n", (float)half::qNan(), half::qNan().bits());
+    printf("half sNan %g -> 0x%04x\n", (float)half::sNan(), half::sNan().bits());
+    printf("numeric_limits<half> min %g -> 0x%04x\n", (float)std::numeric_limits<half>::min(), std::numeric_limits<half>::min().bits());
+    printf("numeric_limits<half> max %g -> 0x%04x\n", (float)std::numeric_limits<half>::max(), std::numeric_limits<half>::max().bits());
+    printf("numeric_limits<half> lowest %g -> 0x%04x\n", (float)std::numeric_limits<half>::lowest(), std::numeric_limits<half>::lowest().bits());
+    printf("numeric_limits<half> epsilon %g -> 0x%04x\n", (float)std::numeric_limits<half>::epsilon(), std::numeric_limits<half>::epsilon().bits());
+    printf("numeric_limits<half> round_error %g -> 0x%04x\n", (float)std::numeric_limits<half>::round_error(), std::numeric_limits<half>::round_error().bits());
+    printf("numeric_limits<half> infinity %g -> 0x%04x\n", (float)std::numeric_limits<half>::infinity(), std::numeric_limits<half>::infinity().bits());
+    printf("numeric_limits<half> quiet_NaN %g -> 0x%04x\n", (float)std::numeric_limits<half>::quiet_NaN(), std::numeric_limits<half>::quiet_NaN().bits());
+    printf("numeric_limits<half> signaling_NaN %g -> 0x%04x\n", (float)std::numeric_limits<half>::signaling_NaN(), std::numeric_limits<half>::signaling_NaN().bits());
+    printf("numeric_limits<half> denorm_min %g -> 0x%04x\n", (float)std::numeric_limits<half>::denorm_min(), std::numeric_limits<half>::denorm_min().bits());
+
+    assert (std::numeric_limits<half>::max() == half(HALF_MAX));
+    assert (std::numeric_limits<half>::min() == half(HALF_NRM_MIN));
+    assert (std::numeric_limits<half>::denorm_min() == half(HALF_DENORM_MIN));
+    assert (std::numeric_limits<half>::lowest() == half(-HALF_MAX));
+    assert (std::numeric_limits<half>::epsilon() == half(HALF_EPSILON));
+    assert (std::numeric_limits<half>::infinity() == half::posInf());
+    assert (std::numeric_limits<half>::quiet_NaN().bits() == half::qNan().bits());
+    assert (std::numeric_limits<half>::signaling_NaN().bits() == half::sNan().bits());
+    assert (std::numeric_limits<half>::infinity() == half::posInf());
+
+    cout << "ok\n\n" << flush;
+}
diff --git a/src/ImathTest/testLimits.h b/src/ImathTest/testLimits.h
new file mode 100644 (file)
index 0000000..309aa60
--- /dev/null
@@ -0,0 +1,7 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testLimits();
+void testHalfLimits();
diff --git a/src/ImathTest/testLineAlgo.cpp b/src/ImathTest/testLineAlgo.cpp
new file mode 100644 (file)
index 0000000..36b3bae
--- /dev/null
@@ -0,0 +1,427 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathLineAlgo.h>
+#include <ImathRandom.h>
+#include <assert.h>
+#include <iostream>
+#include "testLineAlgo.h"
+
+// Include ImathForward *after* other headers to validate forward declarations
+#include <ImathForward.h>
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+void
+testClosestPoints (const Line3f& line1,
+                   const Line3f& line2,
+                   bool returnValue,
+                   const V3f& point1,
+                   const V3f& point2)
+{
+    V3f p1;
+    V3f p2;
+    bool rv = closestPoints (line1, line2, p1, p2);
+
+    assert (rv == returnValue);
+
+    if (rv)
+    {
+        float e = 10 * std::numeric_limits<float>::epsilon();
+        assert (point1.equalWithAbsError (p1, e));
+        assert (point2.equalWithAbsError (p2, e));
+    }
+}
+
+void
+testClosestPoints()
+{
+    cout << "closest points on two lines" << endl;
+
+    cout << "  non-intersecting, non-parallel lines" << endl;
+
+    testClosestPoints (Line3f (V3f (0, -1, -1), V3f (0, 1, -1)),
+                       Line3f (V3f (-1, 0, 1), V3f (1, 0, 1)),
+                       true,
+                       V3f (0, 0, -1),
+                       V3f (0, 0, 1));
+
+    testClosestPoints (Line3f (V3f (2, -1, -1), V3f (2, 1, -1)),
+                       Line3f (V3f (-1, 3, 1), V3f (1, 3, 1)),
+                       true,
+                       V3f (2, 3, -1),
+                       V3f (2, 3, 1));
+
+    cout << "  intersecting, non-parallel lines" << endl;
+
+    testClosestPoints (Line3f (V3f (2, -1, 0), V3f (2, 1, 0)),
+                       Line3f (V3f (-1, 3, 0), V3f (1, 3, 0)),
+                       true,
+                       V3f (2, 3, 0),
+                       V3f (2, 3, 0));
+
+    cout << "  parallel lines" << endl;
+
+    testClosestPoints (Line3f (V3f (2, -1, 0), V3f (2, 1, 0)),
+                       Line3f (V3f (2, -1, 1), V3f (2, 1, 1)),
+                       false,
+                       V3f (0, 0, 0),
+                       V3f (0, 0, 0));
+
+    testClosestPoints (Line3f (V3f (2, -1, 0), V3f (2, 1, 0)),
+                       Line3f (V3f (2, 1, 1), V3f (2, -1, 1)),
+                       false,
+                       V3f (0, 0, 0),
+                       V3f (0, 0, 0));
+
+    cout << "  coincident lines" << endl;
+
+    testClosestPoints (Line3f (V3f (2, -1, 0), V3f (2, -1, 1)),
+                       Line3f (V3f (2, -1, 0), V3f (2, -1, 1)),
+                       false,
+                       V3f (0, 0, 0),
+                       V3f (0, 0, 0));
+
+    cout << "  random lines" << endl;
+
+    Rand48 rand (7);
+
+    for (int i = 0; i < 10000; ++i)
+    {
+        Line3f line1 (solidSphereRand<V3f> (rand) * 100.f, solidSphereRand<V3f> (rand) * 100.f);
+
+        Line3f line2 (solidSphereRand<V3f> (rand) * 100.f, solidSphereRand<V3f> (rand) * 100.f);
+
+        V3f point1;
+        V3f point2;
+        bool rv = closestPoints (line1, line2, point1, point2);
+
+        if (rv)
+        {
+            //
+            // We test if the line that connects point1 and point2
+            // is perpendicular to line1 and line2.  The numerical
+            // accuracy of point1 and point2 depends strongly on
+            // the relative directions of line1 and line2; accuracy
+            // degrades rather quickly if line1 and line2 become
+            // close to parallel.
+            //
+
+            float e = 2000 * std::numeric_limits<float>::epsilon();
+            float d = 1 - (line1.dir ^ line2.dir) * (line1.dir ^ line2.dir);
+            V3f n   = point1 - point2;
+
+            assert (equalWithAbsError (0.0f, (line1.dir ^ n) * d, e));
+            assert (equalWithAbsError (0.0f, (line2.dir ^ n) * d, e));
+        }
+    }
+}
+
+void
+testIntersect (const Line3f& line,
+               const V3f& v0,
+               const V3f& v1,
+               const V3f& v2,
+               const V3f& point,
+               bool front,
+               bool returnValue)
+{
+    V3f pt;
+    V3f bary;
+    bool fr;
+
+    bool rv = intersect (line, v0, v1, v2, pt, bary, fr);
+
+    assert (rv == returnValue);
+
+    float e = 10 * std::numeric_limits<float>::epsilon();
+
+    if (rv)
+    {
+        assert (front == fr);
+        assert (pt.equalWithAbsError (point, e));
+        V3f pt2 = v0 * bary.x + v1 * bary.y + v2 * bary.z;
+        assert (pt.equalWithAbsError (pt2, e));
+    }
+}
+
+void
+testIntersect()
+{
+    cout << "line-triangle intersection" << endl;
+
+    cout << "  line-plane intersection inside triangle" << endl;
+
+    testIntersect (Line3f (V3f (0, 0, -1), V3f (0, 0, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 0, 7),
+                   true,
+                   true);
+
+    testIntersect (Line3f (V3f (0, 0, -1), V3f (-1, -2, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (-1, -2, 7),
+                   true,
+                   true);
+
+    testIntersect (Line3f (V3f (0, 0, -1), V3f (-1, 1, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (-1, 1, 7),
+                   true,
+                   true);
+
+    testIntersect (Line3f (V3f (0, 0, -1), V3f (-1, 1, 7)),
+                   V3f (4, -4, 7),
+                   V3f (-4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (-1, 1, 7),
+                   false,
+                   true);
+
+    testIntersect (Line3f (V3f (1, 1, 2), V3f (0, 0, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 0, 7),
+                   true,
+                   true);
+
+    testIntersect (Line3f (V3f (2, 3, -5), V3f (-1, -2, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (-1, -2, 7),
+                   true,
+                   true);
+
+    testIntersect (Line3f (V3f (2, 8, -10), V3f (-1, 1, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (-1, 1, 7),
+                   true,
+                   true);
+
+    testIntersect (Line3f (V3f (-10, 2, -1), V3f (-1, 1, 7)),
+                   V3f (4, -4, 7),
+                   V3f (-4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (-1, 1, 7),
+                   false,
+                   true);
+
+    cout << "  line-plane intersection outside triangle" << endl;
+
+    testIntersect (Line3f (V3f (0, 0, -1), V3f (4, 0, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 0, 0),
+                   false,
+                   false);
+
+    testIntersect (Line3f (V3f (0, 0, -1), V3f (-4, 1, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 0, 0),
+                   false,
+                   false);
+
+    testIntersect (Line3f (V3f (0, 0, -1), V3f (0, -5, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 0, 0),
+                   false,
+                   false);
+
+    testIntersect (Line3f (V3f (0, 0, -1), V3f (0, -7, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 0, 0),
+                   false,
+                   false);
+
+    cout << "  line parallel to triangle" << endl;
+
+    testIntersect (Line3f (V3f (0, 0, -1), V3f (4, 0, -1)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 0, 0),
+                   false,
+                   false);
+
+    testIntersect (Line3f (V3f (0, 4, 7), V3f (4, 0, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 0, 0),
+                   false,
+                   false);
+
+    cout << "  zero-area triangle" << endl;
+
+    testIntersect (Line3f (V3f (2, 3, -5), V3f (-1, -2, 7)),
+                   V3f (0, 6, 7),
+                   V3f (4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 0, 0),
+                   false,
+                   false);
+
+    testIntersect (Line3f (V3f (2, 3, -5), V3f (-1, -2, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (-4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 0, 0),
+                   false,
+                   false);
+
+    testIntersect (Line3f (V3f (2, 3, -5), V3f (-1, -2, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 6, 7),
+                   V3f (0, 0, 0),
+                   false,
+                   false);
+
+    testIntersect (Line3f (V3f (2, 3, -5), V3f (-1, -2, 7)),
+                   V3f (-4, -4, 7),
+                   V3f (-4, -4, 7),
+                   V3f (-4, -4, 7),
+                   V3f (0, 0, 0),
+                   false,
+                   false);
+
+    cout << "  random lines and triangles" << endl;
+
+    Rand48 rand (8);
+
+    for (int i = 0; i < 10000; ++i)
+    {
+        //
+        // Generate a random triangle with non-zero area
+        //
+
+        V3f v0, v1, v2;
+        V3f normal;
+
+        do
+        {
+            v0     = solidSphereRand<V3f> (rand);
+            v1     = solidSphereRand<V3f> (rand);
+            v2     = solidSphereRand<V3f> (rand);
+            normal = (v2 - v1) % (v1 - v0);
+        } while (normal.length() < 0.01);
+
+        {
+            //
+            // Generate a line that intersects inside the triangle
+            //
+
+            V3f b;
+
+            do
+            {
+                b.x = float(rand.nextf (0.001, 0.999));
+                b.y = float(rand.nextf (0.001, 0.999));
+                b.z = 1 - b.x - b.y;
+            } while (b.x + b.y > 0.999);
+
+            V3f p1 = v0 * b.x + v1 * b.y + v2 * b.z;
+
+            V3f p0;
+
+            do
+            {
+                p0 = solidSphereRand<V3f> (rand);
+            } while (abs (normal.normalized() ^ (p1 - p0).normalized()) < 0.1);
+
+            //
+            // Test for intersection
+            //
+
+            V3f point;
+            V3f bary;
+            bool front;
+
+            bool rv = intersect (Line3f (p0, p1), v0, v1, v2, point, bary, front);
+
+            assert (rv == true);
+
+            float nd = abs (normal.normalized() ^ (p1 - p0).normalized());
+            float ep = 20 * std::numeric_limits<float>::epsilon() / nd;
+
+            assert (point.equalWithAbsError (p1, ep));
+        }
+
+        {
+            //
+            // Generate a line that intersects the triangle's plane
+            // but outside the triangle
+            //
+
+            V3f b;
+
+            do
+            {
+                b.x = float(rand.nextf (-3, 3));
+                b.y = float(rand.nextf (-3, 3));
+                b.z = 1 - b.x - b.y;
+            } while (b.x > -0.001 && b.y > -0.001 && b.z > -0.001);
+
+            V3f p1 = v0 * b.x + v1 * b.y + v2 * b.z;
+
+            V3f p0;
+
+            do
+            {
+                p0 = solidSphereRand<V3f> (rand) * 10;
+            } while (abs (normal.normalized() ^ (p1 - p0).normalized()) < 0.1);
+
+            //
+            // Test for intersection
+            //
+
+            V3f point;
+            V3f bary;
+            bool front;
+
+            bool rv = intersect (Line3f (p0, p1), v0, v1, v2, point, bary, front);
+
+            assert (rv == false);
+        }
+    }
+}
+
+} // namespace
+
+void
+testLineAlgo()
+{
+    cout << "Testing line algorithms" << endl;
+
+    testClosestPoints();
+    testIntersect();
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testLineAlgo.h b/src/ImathTest/testLineAlgo.h
new file mode 100644 (file)
index 0000000..bfd81ca
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testLineAlgo();
diff --git a/src/ImathTest/testMatrix.cpp b/src/ImathTest/testMatrix.cpp
new file mode 100644 (file)
index 0000000..28d3a06
--- /dev/null
@@ -0,0 +1,950 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathInt64.h>
+#include <ImathMath.h>
+#include <ImathMatrix.h>
+#include <ImathMatrixAlgo.h>
+#include <ImathRandom.h>
+#include <ImathVec.h>
+#include <assert.h>
+#include <iostream>
+#include "testMatrix.h"
+#include <sstream>
+
+// Include ImathForward *after* other headers to validate forward declarations
+#include <ImathForward.h>
+
+using namespace std;
+using IMATH_INTERNAL_NAMESPACE::Int64;
+
+//
+// This file is not currently intended to exhaustively test
+// the Imath Matrix33<T> and Matrix44<T> classes.  We leave
+// that to PyImathTest.
+//
+// Instead, in this file we test only those aspects of the
+// Imath Matrix33<T> and Matrix44<T> classes that must be
+// or are more convenient to test from C++.
+//
+
+void
+testMatrix22ArrayConstructor(const float a[2][2])
+{
+    IMATH_INTERNAL_NAMESPACE::M22f m(a);
+    assert(m == IMATH_INTERNAL_NAMESPACE::M22f());
+}
+
+void
+testMatrix33ArrayConstructor(const float a[3][3])
+{
+    IMATH_INTERNAL_NAMESPACE::M33f m(a);
+    assert(m == IMATH_INTERNAL_NAMESPACE::M33f());
+}
+
+void
+testMatrix44ArrayConstructor(const float a[4][4])
+{
+    IMATH_INTERNAL_NAMESPACE::M44f m(a);
+    assert(m == IMATH_INTERNAL_NAMESPACE::M44f());
+}
+
+
+void
+testMatrix ()
+{
+    cout << "Testing functions in ImathMatrix.h" << endl;
+
+    union
+    {
+        float f;
+        int i;
+    } nanf;
+    nanf.i = 0x7f800001; //  NAN
+
+    union
+    {
+        double d;
+        uint64_t i;
+    } nand;
+    nand.i = 0x7ff0000000000001ULL; //  NAN
+
+    {
+        cout << "Imath::M22f constructors and equality operators" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::M22f m1;
+        m1[0][0] = 99.0f;
+        m1[1][1] = 101.0f;
+
+        const IMATH_INTERNAL_NAMESPACE::M22f test (m1);
+        assert (test == m1);
+
+        IMATH_INTERNAL_NAMESPACE::M22f test2;
+        assert (test != test2);
+
+        IMATH_INTERNAL_NAMESPACE::M22f test3;
+        test3.makeIdentity();
+        assert (test2 == test3);
+
+        const float a[2][2] = {
+            { 1.0f, 0.0f },
+            { 0.0f, 1.0f }
+        };
+        testMatrix22ArrayConstructor(a);
+        
+        m1 = 42;
+        assert (m1[0][0] == 42 && m1[0][1] == 42 && m1[1][0] == 42 && m1[1][1] == 42);
+
+        const float* i1 = test.getValue();
+        assert(i1[0] == 99.0f);
+        assert(i1[3] == 101.0f);
+        
+        float* i2 = m1.getValue();
+        assert(i2[0] == 42.0f);
+        assert(i2[1] == 42.0f);
+        assert(i2[2] == 42.0f);
+        assert(i2[3] == 42.0f);
+
+        IMATH_INTERNAL_NAMESPACE::M22f test4;
+        test.getValue(test4);
+        assert (test == test4);
+
+        test4.setTheMatrix(test3);
+        assert(test4 == test3);
+    }
+
+    {
+        cout << "M22d constructors and equality operators" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::M22d m2;
+        m2[0][0] = 99.0f;
+        m2[1][1] = 101.0f;
+
+        IMATH_INTERNAL_NAMESPACE::M22d test (m2);
+        assert (test == m2);
+
+        IMATH_INTERNAL_NAMESPACE::M22d test2;
+        assert (test != test2);
+
+        IMATH_INTERNAL_NAMESPACE::M22d test3;
+        test3.makeIdentity();
+        assert (test2 == test3);
+
+        IMATH_INTERNAL_NAMESPACE::M22f test4 (1.0f, 2.0f, 3.0f, 4.0f);
+
+        IMATH_INTERNAL_NAMESPACE::M22d test5 = IMATH_INTERNAL_NAMESPACE::M22d (test4);
+
+        assert (test5[0][0] == 1.0);
+        assert (test5[0][1] == 2.0);
+
+        assert (test5[1][0] == 3.0);
+        assert (test5[1][1] == 4.0);
+
+        const float a[3][3] = {
+            { 1.0f, 0.0f, 0.0f },
+            { 0.0f, 1.0f, 0.0f },
+            { 0.0f, 0.0f, 1.0f }
+        };
+        testMatrix33ArrayConstructor(a);
+    }
+
+    {
+        cout << "M22f inversion operators" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::M22f m1 (3.0f, 3.0f, 5.0f, 5.0f);
+        IMATH_INTERNAL_NAMESPACE::M22f m2 = m1;
+        assert(m1.inverse(false) == m1.inverse());
+        m2.invert(false);
+        m1.invert();
+        assert(m1 == m2);
+
+        IMATH_INTERNAL_NAMESPACE::M22f m3 (4.0f, 7.0f, 2.0f, 6.0f);
+        m2 = m3;
+        assert(m2.inverse(true) == m2.inverse());
+        m3.invert(true);
+        m2.invert();
+        assert(m3 == m2);
+    }
+
+    {
+        cout << "Imath::M33f shear functions" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::M33f m1, m2;
+        m1.setShear (2.0f);
+        assert (m1[0][0] == 1.0f && m1[0][1] == 0.0f && m1[0][2] == 0.0f && m1[1][0] == 2.0f &&
+                m1[1][1] == 1.0f && m1[1][2] == 0.0f && m1[2][0] == 0.0f && m1[2][1] == 0.0f &&
+                m1[2][2] == 1.0f);
+
+        m2.setShear (IMATH_INTERNAL_NAMESPACE::V2f (3.0f, 4.0f));
+        assert (m2[0][0] == 1.0f && m2[0][1] == 4.0f && m2[0][2] == 0.0f && m2[1][0] == 3.0f &&
+                m2[1][1] == 1.0f && m2[1][2] == 0.0f && m2[2][0] == 0.0f && m2[2][1] == 0.0f &&
+                m2[2][2] == 1.0f);
+
+        m1.shear (IMATH_INTERNAL_NAMESPACE::V2f (5.0f, 6.0f));
+        assert (m1[0][0] == 13.0f && m1[0][1] == 6.0f && m1[0][2] == 0.0f && m1[1][0] == 7.0f &&
+                m1[1][1] == 1.0f && m1[1][2] == 0.0f && m1[2][0] == 0.0f && m1[2][1] == 0.0f &&
+                m1[2][2] == 1.0f);
+
+        m2.shear (7.0f);
+        assert (m2[0][0] == 1.0f && m2[0][1] == 4.0f && m2[0][2] == 0.0f && m2[1][0] == 10.0f &&
+                m2[1][1] == 29.0f && m2[1][2] == 0.0f && m2[2][0] == 0.0f && m2[2][1] == 0.0f &&
+                m2[2][2] == 1.0f);
+
+        cout << "M33f constructors and equality operators" << endl;
+
+        const IMATH_INTERNAL_NAMESPACE::M33f test (m2);
+        assert (test == m2);
+
+        IMATH_INTERNAL_NAMESPACE::M33f test2;
+        assert (test != test2);
+
+        IMATH_INTERNAL_NAMESPACE::M33f test3;
+        test3.makeIdentity();
+        assert (test2 == test3);
+
+        m1 = 42;
+        assert (m1[0][0] == 42 && m1[0][1] == 42 && m1[0][2] == 42 &&
+                m1[1][0] == 42 && m1[1][1] == 42 && m1[1][2] == 42 &&
+                m1[2][0] == 42 && m1[2][1] == 42 && m1[2][2] == 42);
+
+        const float* i1 = test.getValue();
+        assert (i1[0] == 1.0f  && i1[1] == 4.0f  && i1[2] == 0.0f &&
+                i1[3] == 10.0f && i1[4] == 29.0f && i1[5] == 0.0f &&
+                i1[6] == 0.0f  && i1[7] == 0.0f  && i1[8] == 1.0f);
+        
+        float* i2 = m1.getValue();
+        assert(i2[0] == 42.0f);
+        assert(i2[1] == 42.0f);
+        assert(i2[2] == 42.0f);
+        assert(i2[3] == 42.0f);
+
+        IMATH_INTERNAL_NAMESPACE::M33f test4;
+        test.getValue(test4);
+        assert (test == test4);
+
+        test4.setTheMatrix(test3);
+        assert(test4 == test3);
+
+        IMATH_INTERNAL_NAMESPACE::V3f v(2.0f);
+        IMATH_INTERNAL_NAMESPACE::M33f m(2.0f);
+        v *= m;
+        assert (IMATH_INTERNAL_NAMESPACE::equal(v[0], 12.0f, 0.0001f));
+        assert (IMATH_INTERNAL_NAMESPACE::equal(v[1], 12.0f, 0.0001f));
+        assert (IMATH_INTERNAL_NAMESPACE::equal(v[2], 12.0f, 0.0001f));
+    }
+
+    {
+      cout << "M33f inversion operators" << endl;
+
+      IMATH_INTERNAL_NAMESPACE::M33f m1 (0.0f, 2.0f, -1.0f, 3.0f, -2.0f, 1.0f, 3.0f, 2.0f, -1.0f);
+      IMATH_INTERNAL_NAMESPACE::M33f m2 = m1;
+      assert(m1.inverse(false) == m1.inverse());
+      m2.invert(false);
+      m1.invert();
+      assert(m1 == m2);
+
+      IMATH_INTERNAL_NAMESPACE::M33f m3 (1.0f, 0.0f, 5.0f, 2.0f, 1.0f, 6.0f, 3.0f, 4.0f, 0.0f);
+      m2 = m3;
+      assert(m3.inverse(true) == m3.inverse());
+      m3.invert(true);
+      m2.invert();
+      assert(m3 == m2);
+
+      IMATH_INTERNAL_NAMESPACE::M33f m4 (0.0f, 2.0f, -1.0f, 3.0f, -2.0f, 1.0f, 3.0f, 2.0f, -1.0f);
+      m2 = m4;
+      assert(m4.gjInverse(false) == m4.gjInverse());
+      m2.gjInvert(false);
+      m4.gjInvert();
+      assert(m4 == m2);
+
+      IMATH_INTERNAL_NAMESPACE::M33f m5 (1.0f, 0.0f, 5.0f, 2.0f, 1.0f, 6.0f, 3.0f, 4.0f, 0.0f);
+      m2 = m5;
+      assert(m5.gjInverse(true) == m5.gjInverse());
+      m5.gjInvert(true);
+      m2.gjInvert();
+      assert(m5 == m2);
+    }
+
+    {
+        cout << "M33d constructors and equality operators" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::M33d m2;
+        m2[0][0] = 99.0f;
+        m2[1][2] = 101.0f;
+
+        IMATH_INTERNAL_NAMESPACE::M33d test (m2);
+        assert (test == m2);
+
+        IMATH_INTERNAL_NAMESPACE::M33d test2;
+        assert (test != test2);
+
+        IMATH_INTERNAL_NAMESPACE::M33d test3;
+        test3.makeIdentity();
+        assert (test2 == test3);
+
+        IMATH_INTERNAL_NAMESPACE::M33f test4 (1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f);
+
+        IMATH_INTERNAL_NAMESPACE::M33d test5 = IMATH_INTERNAL_NAMESPACE::M33d (test4);
+
+        assert (test5[0][0] == 1.0);
+        assert (test5[0][1] == 2.0);
+        assert (test5[0][2] == 3.0);
+
+        assert (test5[1][0] == 4.0);
+        assert (test5[1][1] == 5.0);
+        assert (test5[1][2] == 6.0);
+
+        assert (test5[2][0] == 7.0);
+        assert (test5[2][1] == 8.0);
+        assert (test5[2][2] == 9.0);
+    }
+
+    {
+        IMATH_INTERNAL_NAMESPACE::M44f m2;
+        m2[0][0] = 99.0f;
+        m2[1][2] = 101.0f;
+
+        cout << "M44f constructors and equality operators" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::M44f test (m2);
+        assert (test == m2);
+
+        IMATH_INTERNAL_NAMESPACE::M44f test2;
+        assert (test != test2);
+
+        IMATH_INTERNAL_NAMESPACE::M44f test3;
+        test3.makeIdentity();
+        assert (test2 == test3);
+
+        //
+        // Test non-equality when a NAN is in the same
+        // place in two identical matrices
+        //
+
+        test2[0][0] = nanf.f;
+        test3       = test2;
+        assert (test2 != test3);
+    }
+
+    {
+        IMATH_INTERNAL_NAMESPACE::M44d m2;
+        m2[0][0] = 99.0f;
+        m2[1][2] = 101.0f;
+
+        cout << "M44d constructors and equality operators" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::M44d test (m2);
+        assert (test == m2);
+
+        IMATH_INTERNAL_NAMESPACE::M44d test2;
+        assert (test != test2);
+
+        IMATH_INTERNAL_NAMESPACE::M44d test3;
+        test3.makeIdentity();
+        assert (test2 == test3);
+
+        const float a[4][4] = {
+            { 1.0f, 0.0f, 0.0f, 0.0f },
+            { 0.0f, 1.0f, 0.0f, 0.0f },
+            { 0.0f, 0.0f, 1.0f, 0.0f },
+            { 0.0f, 0.0f, 0.0f, 1.0f }
+        };
+        testMatrix44ArrayConstructor(a);
+
+        //
+        // Test non-equality when a NAN is in the same
+        // place in two identical matrices
+        //
+
+        test2[0][0] = nand.d;
+        test3       = test2;
+        assert (test2 != test3);
+
+        IMATH_INTERNAL_NAMESPACE::M44f test4 (1.0f,
+                                              2.0f,
+                                              3.0f,
+                                              4.0f,
+                                              5.0f,
+                                              6.0f,
+                                              7.0f,
+                                              8.0f,
+                                              9.0f,
+                                              10.0f,
+                                              11.0f,
+                                              12.0f,
+                                              13.0f,
+                                              14.0f,
+                                              15.0f,
+                                              16.0f);
+
+        IMATH_INTERNAL_NAMESPACE::M44d test5 = IMATH_INTERNAL_NAMESPACE::M44d (test4);
+
+        assert (test5[0][0] == 1.0);
+        assert (test5[0][1] == 2.0);
+        assert (test5[0][2] == 3.0);
+        assert (test5[0][3] == 4.0);
+
+        assert (test5[1][0] == 5.0);
+        assert (test5[1][1] == 6.0);
+        assert (test5[1][2] == 7.0);
+        assert (test5[1][3] == 8.0);
+
+        assert (test5[2][0] == 9.0);
+        assert (test5[2][1] == 10.0);
+        assert (test5[2][2] == 11.0);
+        assert (test5[2][3] == 12.0);
+
+        assert (test5[3][0] == 13.0);
+        assert (test5[3][1] == 14.0);
+        assert (test5[3][2] == 15.0);
+        assert (test5[3][3] == 16.0);
+    }
+
+    {
+        cout << "M44f *= operators" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::V3f v(2.0f);
+        IMATH_INTERNAL_NAMESPACE::M44f m(2.0f);
+        m.setScale(2.0f);
+        v *= m;
+        assert (IMATH_INTERNAL_NAMESPACE::equal(v[0], 4.0f, 0.0001f));
+        assert (IMATH_INTERNAL_NAMESPACE::equal(v[1], 4.0f, 0.0001f));
+        assert (IMATH_INTERNAL_NAMESPACE::equal(v[2], 4.0f, 0.0001f));
+
+        IMATH_INTERNAL_NAMESPACE::V4f v4f(2.0f);
+        IMATH_INTERNAL_NAMESPACE::V4f v4f2 = v4f * m;
+        
+        assert (IMATH_INTERNAL_NAMESPACE::equal(v4f2[0], 4.0f, 0.0001f));
+        assert (IMATH_INTERNAL_NAMESPACE::equal(v4f2[1], 4.0f, 0.0001f));
+        assert (IMATH_INTERNAL_NAMESPACE::equal(v4f2[2], 4.0f, 0.0001f));
+        assert (IMATH_INTERNAL_NAMESPACE::equal(v4f2[3], 2.0f, 0.0001f));
+
+        v4f *= m;
+        assert (v4f == v4f2);
+        
+        IMATH_INTERNAL_NAMESPACE::M44f a(2.0f);
+        IMATH_INTERNAL_NAMESPACE::M44f b(3.0f);
+        IMATH_INTERNAL_NAMESPACE::M44f c;
+
+        IMATH_INTERNAL_NAMESPACE::M44f::multiply(a, b, c);
+        assert (IMATH_INTERNAL_NAMESPACE::equal(c[0][0], 24.0f, 0.0001f));
+        assert (IMATH_INTERNAL_NAMESPACE::equal(c[1][1], 24.0f, 0.0001f));
+        assert (IMATH_INTERNAL_NAMESPACE::equal(c[2][2], 24.0f, 0.0001f));
+        assert (IMATH_INTERNAL_NAMESPACE::equal(c[3][3], 24.0f, 0.0001f));
+    }
+    
+    cout << "Matrix << operators" << endl;
+    
+    {
+        std::stringstream s;
+        s << IMATH_INTERNAL_NAMESPACE::identity22f;
+        const char v[] = "(  1.000000e+00   0.000000e+00\n   0.000000e+00   1.000000e+00)\n";
+        assert (s.str() == v);
+    }
+        
+    {
+        std::stringstream s;
+        s << IMATH_INTERNAL_NAMESPACE::identity33f;
+        const char v[] = "(  1.000000e+00   0.000000e+00   0.000000e+00\n   0.000000e+00   1.000000e+00   0.000000e+00\n   0.000000e+00   0.000000e+00   1.000000e+00)\n";
+        assert (s.str() == v);
+    }
+
+    {
+        std::stringstream s;
+        s << IMATH_INTERNAL_NAMESPACE::identity44f;
+        const char v[] = "(  1.000000e+00   0.000000e+00   0.000000e+00   0.000000e+00\n   0.000000e+00   1.000000e+00   0.000000e+00   0.000000e+00\n   0.000000e+00   0.000000e+00   1.000000e+00   0.000000e+00\n   0.000000e+00   0.000000e+00   0.000000e+00   1.000000e+00)\n";
+        assert (s.str() == v);
+    }
+
+    {
+        cout << "M44f inversion operators" << endl;
+
+      IMATH_INTERNAL_NAMESPACE::M44f m1 (1.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         1.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         1.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f);
+      IMATH_INTERNAL_NAMESPACE::M44f m2 = m1;
+      assert(m1.inverse(false) == m1.inverse());
+      m2.invert(false);
+      m1.invert();
+      assert(m1 == m2);
+
+      IMATH_INTERNAL_NAMESPACE::M44f m3 (5.0f,
+                                         6.0f,
+                                         6.0f,
+                                         8.0f,
+                                         2.0f,
+                                         2.0f,
+                                         2.0f,
+                                         8.0f,
+                                         6.0f,
+                                         6.0f,
+                                         2.0f,
+                                         8.0f,
+                                         2.0f,
+                                         3.0f,
+                                         6.0f,
+                                         7.0f);
+      m2 = m3;
+      assert(m3.inverse(true) == m3.inverse());
+      m3.invert(true);
+      m2.invert();
+      assert(m3 == m2);
+
+      IMATH_INTERNAL_NAMESPACE::M44f m4 (1.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         1.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         1.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f,
+                                         0.0f);
+      m2 = m4;
+      assert(m4.gjInverse(false) == m4.gjInverse());
+      m2.gjInvert(false);
+      m4.gjInvert();
+      assert(m4 == m2);
+
+      IMATH_INTERNAL_NAMESPACE::M44f m5 (5.0f,
+                                         6.0f,
+                                         6.0f,
+                                         8.0f,
+                                         2.0f,
+                                         2.0f,
+                                         2.0f,
+                                         8.0f,
+                                         6.0f,
+                                         6.0f,
+                                         2.0f,
+                                         8.0f,
+                                         2.0f,
+                                         3.0f,
+                                         6.0f,
+                                         7.0f);
+      m2 = m5;
+      assert(m5.gjInverse(true) == m5.gjInverse());
+      m5.gjInvert(true);
+      m2.gjInvert();
+      assert(m5 == m2);
+    }
+
+    {
+        cout << "Converting between M33 and M44" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::M44d m1;
+        m1[0][0] = 99;
+        IMATH_INTERNAL_NAMESPACE::M44f m2;
+        m2.setValue (m1);
+        assert (m2[0][0] == (float) m1[0][0]);
+        m1[0][0] = 101;
+        m1.setValue (m2);
+        assert (m2[0][0] == (float) m1[0][0]);
+    }
+
+    // Matrix minors
+    {
+        cout << "3x3 Matrix minors" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::M33f a (1, 2, 3, 4, 5, 6, 7, 8, 9);
+
+        assert (a.minorOf (0, 0) == a.fastMinor (1, 2, 1, 2));
+        assert (a.minorOf (0, 1) == a.fastMinor (1, 2, 0, 2));
+        assert (a.minorOf (0, 2) == a.fastMinor (1, 2, 0, 1));
+        assert (a.minorOf (1, 0) == a.fastMinor (0, 2, 1, 2));
+        assert (a.minorOf (1, 1) == a.fastMinor (0, 2, 0, 2));
+        assert (a.minorOf (1, 2) == a.fastMinor (0, 2, 0, 1));
+        assert (a.minorOf (2, 0) == a.fastMinor (0, 1, 1, 2));
+        assert (a.minorOf (2, 1) == a.fastMinor (0, 1, 0, 2));
+        assert (a.minorOf (2, 2) == a.fastMinor (0, 1, 0, 1));
+    }
+    {
+        IMATH_INTERNAL_NAMESPACE::M33d a (1, 2, 3, 4, 5, 6, 7, 8, 9);
+
+        assert (a.minorOf (0, 0) == a.fastMinor (1, 2, 1, 2));
+        assert (a.minorOf (0, 1) == a.fastMinor (1, 2, 0, 2));
+        assert (a.minorOf (0, 2) == a.fastMinor (1, 2, 0, 1));
+        assert (a.minorOf (1, 0) == a.fastMinor (0, 2, 1, 2));
+        assert (a.minorOf (1, 1) == a.fastMinor (0, 2, 0, 2));
+        assert (a.minorOf (1, 2) == a.fastMinor (0, 2, 0, 1));
+        assert (a.minorOf (2, 0) == a.fastMinor (0, 1, 1, 2));
+        assert (a.minorOf (2, 1) == a.fastMinor (0, 1, 0, 2));
+        assert (a.minorOf (2, 2) == a.fastMinor (0, 1, 0, 1));
+    }
+
+    // Determinants (by building a random singular value decomposition)
+
+    {
+        cout << "2x2 determinant" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M22f u;
+        IMATH_INTERNAL_NAMESPACE::M22f v;
+        IMATH_INTERNAL_NAMESPACE::M22f s;
+
+        u.setRotation (random.nextf());
+        v.setRotation (random.nextf());
+        s[0][0] = random.nextf();
+        s[1][1] = random.nextf();
+
+        IMATH_INTERNAL_NAMESPACE::M22f c = u * s * v.transpose();
+        assert (fabsf (c.determinant() - s[0][0] * s[1][1]) <= u.baseTypeEpsilon());
+    }
+    {
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M22d u;
+        IMATH_INTERNAL_NAMESPACE::M22d v;
+        IMATH_INTERNAL_NAMESPACE::M22d s;
+
+        u.setRotation ((double) random.nextf());
+        v.setRotation ((double) random.nextf());
+        s[0][0] = (double) random.nextf();
+        s[1][1] = (double) random.nextf();
+
+        IMATH_INTERNAL_NAMESPACE::M22d c = u * s * v.transpose();
+        assert (fabs (c.determinant() - s[0][0] * s[1][1]) <= u.baseTypeEpsilon());
+    }
+
+    {
+        cout << "3x3 determinant" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M33f u;
+        IMATH_INTERNAL_NAMESPACE::M33f v;
+        IMATH_INTERNAL_NAMESPACE::M33f s;
+
+        u.setRotation (random.nextf());
+        v.setRotation (random.nextf());
+        s[0][0] = random.nextf();
+        s[1][1] = random.nextf();
+        s[2][2] = random.nextf();
+
+        IMATH_INTERNAL_NAMESPACE::M33f c = u * s * v.transpose();
+        assert (fabsf (c.determinant() - s[0][0] * s[1][1] * s[2][2]) <= u.baseTypeEpsilon());
+    }
+    {
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M33d u;
+        IMATH_INTERNAL_NAMESPACE::M33d v;
+        IMATH_INTERNAL_NAMESPACE::M33d s;
+
+        u.setRotation ((double) random.nextf());
+        v.setRotation ((double) random.nextf());
+        s[0][0] = (double) random.nextf();
+        s[1][1] = (double) random.nextf();
+        s[2][2] = (double) random.nextf();
+
+        IMATH_INTERNAL_NAMESPACE::M33d c = u * s * v.transpose();
+        assert (fabs (c.determinant() - s[0][0] * s[1][1] * s[2][2]) <= u.baseTypeEpsilon());
+    }
+
+    // Outer product of two 3D vectors
+    {
+        cout << "Outer product of two 3D vectors" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::V3f a (1, 2, 3);
+        IMATH_INTERNAL_NAMESPACE::V3f b (4, 5, 6);
+        IMATH_INTERNAL_NAMESPACE::M33f p = IMATH_INTERNAL_NAMESPACE::outerProduct (a, b);
+
+        for (int i = 0; i < 3; i++)
+        {
+            for (int j = 0; j < 3; j++)
+            {
+                assert (p[i][j] == a[i] * b[j]);
+            }
+        }
+    }
+    {
+        IMATH_INTERNAL_NAMESPACE::V3d a (1, 2, 3);
+        IMATH_INTERNAL_NAMESPACE::V3d b (4, 5, 6);
+        IMATH_INTERNAL_NAMESPACE::M33d p = IMATH_INTERNAL_NAMESPACE::outerProduct (a, b);
+
+        for (int i = 0; i < 3; i++)
+        {
+            for (int j = 0; j < 3; j++)
+            {
+                assert (p[i][j] == a[i] * b[j]);
+            }
+        }
+    }
+
+    // Determinants (by building a random singular value decomposition)
+    {
+        cout << "4x4 determinants" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M44f u = IMATH_INTERNAL_NAMESPACE::rotationMatrix (
+            IMATH_INTERNAL_NAMESPACE::V3f (random.nextf(), random.nextf(), random.nextf())
+                .normalize(),
+            IMATH_INTERNAL_NAMESPACE::V3f (random.nextf(), random.nextf(), random.nextf())
+                .normalize());
+        IMATH_INTERNAL_NAMESPACE::M44f v = IMATH_INTERNAL_NAMESPACE::rotationMatrix (
+            IMATH_INTERNAL_NAMESPACE::V3f (random.nextf(), random.nextf(), random.nextf())
+                .normalize(),
+            IMATH_INTERNAL_NAMESPACE::V3f (random.nextf(), random.nextf(), random.nextf())
+                .normalize());
+        IMATH_INTERNAL_NAMESPACE::M44f s;
+
+        s[0][0] = random.nextf();
+        s[1][1] = random.nextf();
+        s[2][2] = random.nextf();
+        s[3][3] = random.nextf();
+
+        IMATH_INTERNAL_NAMESPACE::M44f c = u * s * v.transpose();
+        assert (fabsf (c.determinant() - s[0][0] * s[1][1] * s[2][2] * s[3][3]) <=
+                u.baseTypeEpsilon());
+    }
+    {
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M44d u = IMATH_INTERNAL_NAMESPACE::rotationMatrix (
+            IMATH_INTERNAL_NAMESPACE::V3d (random.nextf(), random.nextf(), random.nextf())
+                .normalize(),
+            IMATH_INTERNAL_NAMESPACE::V3d (random.nextf(), random.nextf(), random.nextf())
+                .normalize());
+        IMATH_INTERNAL_NAMESPACE::M44d v = IMATH_INTERNAL_NAMESPACE::rotationMatrix (
+            IMATH_INTERNAL_NAMESPACE::V3d (random.nextf(), random.nextf(), random.nextf())
+                .normalize(),
+            IMATH_INTERNAL_NAMESPACE::V3d (random.nextf(), random.nextf(), random.nextf())
+                .normalize());
+        IMATH_INTERNAL_NAMESPACE::M44d s;
+
+        s[0][0] = random.nextf();
+        s[1][1] = random.nextf();
+        s[2][2] = random.nextf();
+        s[3][3] = random.nextf();
+
+        IMATH_INTERNAL_NAMESPACE::M44d c = u * s * v.transpose();
+        assert (fabs (c.determinant() - s[0][0] * s[1][1] * s[2][2] * s[3][3]) <=
+                u.baseTypeEpsilon());
+    }
+
+    // Trace
+    {
+        cout << "2x2 trace" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M22f u;
+        float                          trace = 0;
+        for (int i = 0; i < 2; i++)
+        {
+            for (int j = 0; j < 2; j++)
+            {
+                const float randomNum = random.nextf ();
+                u[i][j]               = randomNum;
+                if (i == j) { trace += randomNum; }
+            }
+        }
+
+        assert (fabsf (u.trace () - trace) <= u.baseTypeEpsilon ());
+    }
+    {
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M22d u;
+        double                         trace = 0;
+        for (int i = 0; i < 2; i++)
+        {
+            for (int j = 0; j < 2; j++)
+            {
+                const double randomNum = random.nextf ();
+                u[i][j]                = randomNum;
+                if (i == j) { trace += randomNum; }
+            }
+        }
+
+        assert (fabs (u.trace () - trace) <= u.baseTypeEpsilon ());
+    }
+    {
+        cout << "3x3 trace" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M33f u;
+        float                          trace = 0;
+        for (int i = 0; i < 3; i++)
+        {
+            for (int j = 0; j < 3; j++)
+            {
+                const float randomNum = random.nextf ();
+                u[i][j]               = randomNum;
+                if (i == j) { trace += randomNum; }
+            }
+        }
+
+        assert (fabsf (u.trace () - trace) <= u.baseTypeEpsilon ());
+    }
+    {
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M33d u;
+        double                         trace = 0;
+        for (int i = 0; i < 3; i++)
+        {
+            for (int j = 0; j < 3; j++)
+            {
+                const double randomNum = random.nextf ();
+                u[i][j]                = randomNum;
+                if (i == j) { trace += randomNum; }
+            }
+        }
+
+        assert (fabs (u.trace () - trace) <= u.baseTypeEpsilon ());
+    }
+    {
+        cout << "4x4 trace" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M44f u;
+        float                          trace = 0;
+        for (int i = 0; i < 4; i++)
+        {
+            for (int j = 0; j < 4; j++)
+            {
+                const float randomNum = random.nextf ();
+                u[i][j]               = randomNum;
+                if (i == j) { trace += randomNum; }
+            }
+        }
+
+        assert (fabsf (u.trace () - trace) <= u.baseTypeEpsilon ());
+    }
+    {
+        IMATH_INTERNAL_NAMESPACE::Rand32 random;
+
+        IMATH_INTERNAL_NAMESPACE::M44d u;
+        double                         trace = 0;
+        for (int i = 0; i < 4; i++)
+        {
+            for (int j = 0; j < 4; j++)
+            {
+                const double randomNum = random.nextf ();
+                u[i][j]                = randomNum;
+                if (i == j) { trace += randomNum; }
+            }
+        }
+
+        assert (fabs (u.trace () - trace) <= u.baseTypeEpsilon ());
+    }
+
+    // Matrix minors
+    {
+        cout << "4x4 matrix minors" << endl;
+
+        IMATH_INTERNAL_NAMESPACE::M44d a (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
+
+        assert (a.minorOf (0, 0) == a.fastMinor (1, 2, 3, 1, 2, 3));
+        assert (a.minorOf (0, 1) == a.fastMinor (1, 2, 3, 0, 2, 3));
+        assert (a.minorOf (0, 2) == a.fastMinor (1, 2, 3, 0, 1, 3));
+        assert (a.minorOf (0, 3) == a.fastMinor (1, 2, 3, 0, 1, 2));
+        assert (a.minorOf (1, 0) == a.fastMinor (0, 2, 3, 1, 2, 3));
+        assert (a.minorOf (1, 1) == a.fastMinor (0, 2, 3, 0, 2, 3));
+        assert (a.minorOf (1, 2) == a.fastMinor (0, 2, 3, 0, 1, 3));
+        assert (a.minorOf (1, 3) == a.fastMinor (0, 2, 3, 0, 1, 2));
+        assert (a.minorOf (2, 0) == a.fastMinor (0, 1, 3, 1, 2, 3));
+        assert (a.minorOf (2, 1) == a.fastMinor (0, 1, 3, 0, 2, 3));
+        assert (a.minorOf (2, 2) == a.fastMinor (0, 1, 3, 0, 1, 3));
+        assert (a.minorOf (2, 3) == a.fastMinor (0, 1, 3, 0, 1, 2));
+        assert (a.minorOf (3, 0) == a.fastMinor (0, 1, 2, 1, 2, 3));
+        assert (a.minorOf (3, 1) == a.fastMinor (0, 1, 2, 0, 2, 3));
+        assert (a.minorOf (3, 2) == a.fastMinor (0, 1, 2, 0, 1, 3));
+        assert (a.minorOf (3, 3) == a.fastMinor (0, 1, 2, 0, 1, 2));
+    }
+    {
+        IMATH_INTERNAL_NAMESPACE::M44f a (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
+
+        assert (a.minorOf (0, 0) == a.fastMinor (1, 2, 3, 1, 2, 3));
+        assert (a.minorOf (0, 1) == a.fastMinor (1, 2, 3, 0, 2, 3));
+        assert (a.minorOf (0, 2) == a.fastMinor (1, 2, 3, 0, 1, 3));
+        assert (a.minorOf (0, 3) == a.fastMinor (1, 2, 3, 0, 1, 2));
+        assert (a.minorOf (1, 0) == a.fastMinor (0, 2, 3, 1, 2, 3));
+        assert (a.minorOf (1, 1) == a.fastMinor (0, 2, 3, 0, 2, 3));
+        assert (a.minorOf (1, 2) == a.fastMinor (0, 2, 3, 0, 1, 3));
+        assert (a.minorOf (1, 3) == a.fastMinor (0, 2, 3, 0, 1, 2));
+        assert (a.minorOf (2, 0) == a.fastMinor (0, 1, 3, 1, 2, 3));
+        assert (a.minorOf (2, 1) == a.fastMinor (0, 1, 3, 0, 2, 3));
+        assert (a.minorOf (2, 2) == a.fastMinor (0, 1, 3, 0, 1, 3));
+        assert (a.minorOf (2, 3) == a.fastMinor (0, 1, 3, 0, 1, 2));
+        assert (a.minorOf (3, 0) == a.fastMinor (0, 1, 2, 1, 2, 3));
+        assert (a.minorOf (3, 1) == a.fastMinor (0, 1, 2, 0, 2, 3));
+        assert (a.minorOf (3, 2) == a.fastMinor (0, 1, 2, 0, 1, 3));
+        assert (a.minorOf (3, 3) == a.fastMinor (0, 1, 2, 0, 1, 2));
+    }
+
+    // VC 2005 64 bits compiler has a bug with __restrict keword.
+    // Pointers with __restrict should not alias the same symbol.
+    // But, with optimization on, VC removes intermediate temp variable
+    // and ignores __restrict.
+    {
+        cout << "M44 multiplicaftion test" << endl;
+        IMATH_INTERNAL_NAMESPACE::M44f M (1.0f,
+                                          2.0f,
+                                          3.0f,
+                                          4.0f,
+                                          5.0f,
+                                          6.0f,
+                                          7.0f,
+                                          8.0f,
+                                          9.0f,
+                                          10.0f,
+                                          11.0f,
+                                          12.0f,
+                                          13.0f,
+                                          14.0f,
+                                          15.0f,
+                                          16.0f);
+
+        IMATH_INTERNAL_NAMESPACE::M44f N;
+        N.makeIdentity();
+
+        // N should be equal to M
+        // This typical test fails
+        // when __restrict is used for pointers in "multiply" function.
+        N = N * M;
+
+        assert (N == M);
+
+        if (N != M)
+        {
+            cout << "M44 multiplication test has failed, error." << endl
+                 << "M" << endl
+                 << M << endl
+                 << "N" << endl
+                 << N << endl;
+        }
+    }
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testMatrix.h b/src/ImathTest/testMatrix.h
new file mode 100644 (file)
index 0000000..b4f7245
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testMatrix();
diff --git a/src/ImathTest/testMiscMatrixAlgo.cpp b/src/ImathTest/testMiscMatrixAlgo.cpp
new file mode 100644 (file)
index 0000000..e915547
--- /dev/null
@@ -0,0 +1,320 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathMatrixAlgo.h>
+#include <ImathRandom.h>
+#include <assert.h>
+#include <exception>
+#include <iostream>
+#include <stdio.h>
+#include "testMiscMatrixAlgo.h"
+
+#if 0
+#    define debug(x) (printf x, fflush (stdout))
+#else
+#    define debug(x)
+#endif
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+float
+rad (float deg)
+{
+    return deg * float(M_PI / 180);
+}
+
+void
+testComputeLocalFrame()
+{
+    float  eps = 0.00005f;
+    Rand48 random (0);
+    for (int i = 0; i < 100000; ++i)
+    {
+        debug (("iteration: %d\n", i));
+
+        // Random pos
+        V3f p (
+            float(random.nextf (-10, 10)),
+            float(random.nextf (-10, 10)),
+            float(random.nextf (-10, 10)));
+
+        // Random xDir
+        V3f xDir (
+            float(random.nextf (-10, 10)),
+            float(random.nextf (-10, 10)),
+            float(random.nextf (-10, 10)));
+
+        // Random normalDir
+        V3f normalDir (
+            float(random.nextf (-10, 10)),
+            float(random.nextf (-10, 10)),
+            float(random.nextf (-10, 10)));
+
+        // Run computeLocalFrame we want to test
+        M44f L = computeLocalFrame (p, xDir, normalDir);
+
+        // test position
+        for (int j = 0; j < 3; j++)
+        {
+            if (abs (L[3][j] - p[j]) > eps)
+                assert (false);
+        }
+        if (abs (L[3][3] - 1.0) > eps)
+            assert (false);
+
+        // check that xAxis has the same dir as xDir and that is is normalized
+        V3f x (L[0][0], L[0][1], L[0][2]);
+        assert ((x % xDir).length() < eps);
+        if (abs (L[0][3]) > eps)
+            assert (false);
+        assert ((abs (x.length() - 1.f) < eps));
+
+        // Check that y is normal to x and to normalDir, and is normalized
+        V3f y (L[1][0], L[1][1], L[1][2]);
+        if (abs (L[1][3]) > eps)
+            assert (false);
+        assert (abs (x ^ y) < eps);
+        /*std::cout<<y<<"\n";
+        std::cout<<normalDir<<"\n";
+        std::cout<<(y^normalDir)<<"\n";*/
+        assert (abs (y ^ normalDir) < eps);
+        assert ((abs (y.length() - 1.f) < eps));
+
+        // check that z is normalized, normal to x and y, and direct
+        V3f z (L[2][0], L[2][1], L[2][2]);
+        if (abs (L[2][3]) > eps)
+            assert (false);
+        assert ((abs (z.length() - 1.f) < eps));
+        assert (abs (x ^ z) < eps);
+        assert (abs (y ^ z) < eps);
+        assert (((x % y) ^ z) > 0);
+    }
+}
+
+void
+getRandTRS (Rand48& random, V3f& trans, V3f& rot, V3f& scale)
+{
+    // Translate
+    trans = V3f (
+            float(random.nextf (-10, 10)),
+            float(random.nextf (-10, 10)),
+            float(random.nextf (-10, 10)));
+    // Rotate
+    rot = V3f (
+        rad (float(random.nextf (-180, 180))),
+        rad (float(random.nextf (-180, 180))),
+        rad (float(random.nextf (-180, 180))));
+
+    // Scale
+    V3f s (
+        float(random.nextf (0.000001, 2.0)),
+        float(random.nextf (0.000001, 2.0)),
+        float(random.nextf (0.000001, 2.0)));
+    for (int j = 0; j < 3; j++)
+        if (random.nextf (0.0, 1.0) >= 0.5)
+            s[j] *= -1;
+    scale = s;
+}
+
+M44f
+createRandomMat (Rand48& random, V3f& trans, V3f& rot, V3f& scale)
+{
+
+    M44f M;
+    V3f t, r, s;
+    getRandTRS (random, t, r, s);
+
+    M.translate (t);
+    M.rotate (r);
+
+    // Shear M.
+    V3f h (
+        float(random.nextf (0.000001, 2.0)),
+        float(random.nextf (0.000001, 2.0)),
+        float(random.nextf (0.000001, 2.0)));
+
+    for (int j = 0; j < 3; j++)
+        if (random.nextf (0.0, 1.0) >= 0.5)
+            h[j] *= -1;
+    M.shear (h);
+
+    M.scale (s);
+
+    //
+    // Add a small random error to the elements of M
+    //
+    for (int j = 0; j < 4; ++j)
+        for (int k = 0; k < 3; ++k)
+            M[j][k] += float(random.nextf (-1e-7, 1e-7));
+
+    V3f sh;
+    extractSHRT (M, scale, sh, rot, trans);
+
+    debug (("Scale   : %f %f %f\n", s[0], s[1], s[2]));
+    debug (("Shear   : %f %f %f\n", h[0], h[1], h[2]));
+    debug (("Rot     : %f %f %f\n", r[0], r[1], r[2]));
+    debug (("Trans   : %f %f %f\n", t[0], t[1], t[2]));
+
+    return M;
+}
+
+void
+compareMat (M44f& M, M44f& N)
+{
+    float eps = 0.0001f;
+
+    /// Verify that the entries in M and N do not
+    // differ too much.
+
+    M44f D (M - N);
+
+    for (int j = 0; j < 4; ++j)
+    {
+        for (int k = 0; k < 4; ++k)
+        {
+            //cout << "diff="<<D[j][k] << endl;
+            if (abs (D[j][k]) > eps)
+            {
+                cout << "unexpectedly diff " << D[j][k] << endl;
+
+                cout << j << " " << k << endl;
+
+                cout << "M\n" << M << endl;
+                cout << "N\n" << N << endl;
+                cout << "D\n" << D << endl;
+
+                assert (false);
+            }
+        }
+    }
+}
+
+void
+testAddOffset()
+{
+    Rand48 random (0);
+
+    for (int i = 0; i < 100000; ++i)
+    {
+        debug (("iteration: %d\n", i));
+
+        V3f transA, transB, rotA, rotB, scaleA, scaleB;
+        V3f tOffset, rOffset, sOffset;
+        M44f inMat  = createRandomMat (random, transA, rotA, scaleA);
+        M44f refMat = createRandomMat (random, transB, rotB, scaleB);
+        getRandTRS (random, tOffset, rOffset, sOffset);
+
+        // addOffset : function to test
+        M44f outMat = addOffset (inMat, tOffset, rOffset, sOffset, refMat);
+
+        // add the inverse offset
+        M44f invO;
+        invO.rotate (V3f (rad (rOffset[0]), rad (rOffset[1]), rad (rOffset[2])));
+        invO[3][0] = tOffset[0];
+        invO[3][1] = tOffset[1];
+        invO[3][2] = tOffset[2];
+        invO.invert();
+
+        M44f invS;
+        invS.scale (sOffset);
+        invS.invert(); // zero scale is avoided in getRandTRS
+
+        // in ref mat from the function result
+        M44f outInRefMat = invO * invS * outMat;
+
+        // in ref mat from the inputs
+        M44f inRefMat = inMat * refMat;
+
+        // compare the mat
+        compareMat (outInRefMat, inRefMat);
+    }
+}
+
+void
+testRSMatrix (M44f& M, V3f& t, V3f& r, V3f& s)
+{
+    M44f N;
+    N.makeIdentity();
+    N.translate (t); // ... matrix compositions
+    N.rotate (r);
+    N.scale (s);
+
+    compareMat (M, N);
+}
+
+void
+testComputeRSMatrix()
+{
+    Rand48 random (0);
+
+    for (int i = 0; i < 100000; ++i)
+    {
+        debug (("iteration: %d\n", i));
+
+        V3f transA, transB, rotA, rotB, scaleA, scaleB;
+
+        M44f A = createRandomMat (random, transA, rotA, scaleA);
+        M44f B = createRandomMat (random, transB, rotB, scaleB);
+
+        M44f ArAsA = computeRSMatrix (true, true, A, B);
+        M44f ArBsB = computeRSMatrix (false, false, A, B);
+        M44f ArAsB = computeRSMatrix (true, false, A, B);
+        M44f ArBsA = computeRSMatrix (false, true, A, B);
+
+        testRSMatrix (ArAsA, transA, rotA, scaleA);
+        testRSMatrix (ArBsB, transA, rotB, scaleB);
+        testRSMatrix (ArAsB, transA, rotA, scaleB);
+        testRSMatrix (ArBsA, transA, rotB, scaleA);
+
+        debug (("\n"));
+    }
+}
+
+} // namespace
+
+void
+testMiscMatrixAlgo()
+{
+    try
+    {
+        cout << "Testing misc functions in ImathMatrixAlgo.h" << endl;
+
+        cout << "Testing the building of an orthonormal direct frame from : a position, "
+             << "an x axis direction and a normal to the y axis" << endl;
+        cout << "IMATH_INTERNAL_NAMESPACE::computeLocalFrame()" << endl;
+
+        testComputeLocalFrame();
+
+        cout << "ok\n" << endl;
+
+        cout << "Add a translate/rotate/scale offset to an input frame "
+             << "and put it in another frame of reference" << endl;
+        cout << "IMATH_INTERNAL_NAMESPACE::addOffset()" << endl;
+
+        testAddOffset();
+
+        cout << "ok\n" << endl;
+
+        cout << "Compute Translate/Rotate/Scale matrix from matrix A " << endl;
+        cout << "with the Rotate/Scale of Matrix B" << endl;
+        cout << "IMATH_INTERNAL_NAMESPACE::computeRSMatrix()" << endl;
+
+        testComputeRSMatrix();
+
+        cout << "ok\n" << endl;
+    }
+    catch (std::exception& e)
+    {
+        cerr << "  Caught exception: " << e.what() << endl;
+    }
+}
diff --git a/src/ImathTest/testMiscMatrixAlgo.h b/src/ImathTest/testMiscMatrixAlgo.h
new file mode 100644 (file)
index 0000000..fdc67dc
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testMiscMatrixAlgo();
diff --git a/src/ImathTest/testNoInterop.cpp b/src/ImathTest/testNoInterop.cpp
new file mode 100644 (file)
index 0000000..fa425e7
--- /dev/null
@@ -0,0 +1,78 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#define IMATH_FOREIGN_VECTOR_INTEROP 0
+
+#include <ImathMatrix.h>
+#include <ImathVec.h>
+#include <cassert>
+#include <iostream>
+
+using namespace std;
+
+void
+testNoInterop ()
+{
+    cout << "Testing without interoperability with foreign types" << endl;
+
+    // Construction from a double-indexed array is handled by the
+    // interoperability constructors, unless theyre disabled, in which
+    // there are fallbacks for the simple types.
+    
+    {
+        const float a[2][2] = {
+            { 1.0f, 0.0f },
+            { 0.0f, 1.0f }
+        };
+        IMATH_INTERNAL_NAMESPACE::M22f m(a);
+        assert (m[0][0] == a[0][0]);
+        assert (m[0][1] == a[0][1]);
+        assert (m[1][0] == a[1][0]);
+        assert (m[1][1] == a[1][1]);
+    }
+    
+    {
+        const float a[3][3] = {
+            { 1.0f, 0.0f, 0.0f },
+            { 0.0f, 1.0f, 0.0f },
+            { 0.0f, 0.0f, 1.0f } 
+        };
+        IMATH_INTERNAL_NAMESPACE::M33f m(a);
+        assert (m[0][0] == a[0][0]);
+        assert (m[0][1] == a[0][1]);
+        assert (m[0][2] == a[0][2]);
+        assert (m[1][0] == a[1][0]);
+        assert (m[1][1] == a[1][1]);
+        assert (m[1][2] == a[1][2]);
+        assert (m[2][0] == a[2][0]);
+        assert (m[2][1] == a[2][1]);
+        assert (m[2][2] == a[2][2]);
+    }
+    
+    {
+        const float a[4][4] = {
+            { 1.0f, 0.0f, 0.0f, 0.0f },
+            { 0.0f, 1.0f, 0.0f, 0.0f },
+            { 0.0f, 0.0f, 1.0f, 0.0f },
+            { 0.0f, 0.0f, 0.0f, 1.0f } 
+        };
+        IMATH_INTERNAL_NAMESPACE::M44f m(a);
+        assert (m[0][0] == a[0][0]);
+        assert (m[0][1] == a[0][1]);
+        assert (m[0][2] == a[0][2]);
+        assert (m[1][0] == a[1][0]);
+        assert (m[1][1] == a[1][1]);
+        assert (m[1][2] == a[1][2]);
+        assert (m[2][0] == a[2][0]);
+        assert (m[2][1] == a[2][1]);
+        assert (m[2][2] == a[2][2]);
+    }
+    
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testNoInterop.h b/src/ImathTest/testNoInterop.h
new file mode 100644 (file)
index 0000000..5484f18
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testNoInterop ();
diff --git a/src/ImathTest/testProcrustes.cpp b/src/ImathTest/testProcrustes.cpp
new file mode 100644 (file)
index 0000000..1566083
--- /dev/null
@@ -0,0 +1,410 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathEuler.h>
+#include <ImathMatrixAlgo.h>
+#include <ImathRandom.h>
+#include <assert.h>
+#include <cmath>
+#include <iostream>
+#include <limits>
+#include <vector>
+
+// Verify that if our transformation is already orthogonal, procrustes doesn't
+// change that:
+template <typename T>
+void
+testTranslationRotationMatrix (const IMATH_INTERNAL_NAMESPACE::M44d& mat)
+{
+    std::cout << "Testing known translate/rotate matrix:\n " << mat;
+    typedef IMATH_INTERNAL_NAMESPACE::Vec3<T> Vec;
+
+    static IMATH_INTERNAL_NAMESPACE::Rand48 rand (2047);
+
+    size_t numPoints = 7;
+    std::vector<Vec> from;
+    from.reserve (numPoints);
+    std::vector<Vec> to;
+    to.reserve (numPoints);
+    for (size_t i = 0; i < numPoints; ++i)
+    {
+        IMATH_INTERNAL_NAMESPACE::V3d a (rand.nextf(), rand.nextf(), rand.nextf());
+        IMATH_INTERNAL_NAMESPACE::V3d b = a * mat;
+
+        from.push_back (Vec (a));
+        to.push_back (Vec (b));
+    }
+
+    std::vector<T> weights (numPoints, T (1));
+    const IMATH_INTERNAL_NAMESPACE::M44d m1 =
+        procrustesRotationAndTranslation (&from[0], &to[0], &weights[0], numPoints);
+    const IMATH_INTERNAL_NAMESPACE::M44d m2 =
+        procrustesRotationAndTranslation (&from[0], &to[0], numPoints);
+
+    const T eps = sizeof (T) == 8 ? T(1e-8) : T(1e-4);
+    for (size_t i = 0; i < numPoints; ++i)
+    {
+        const IMATH_INTERNAL_NAMESPACE::V3d a  = from[i];
+        const IMATH_INTERNAL_NAMESPACE::V3d b  = to[i];
+        const IMATH_INTERNAL_NAMESPACE::V3d b1 = a * m1;
+        const IMATH_INTERNAL_NAMESPACE::V3d b2 = a * m2;
+
+        assert ((b - b1).length() < eps);
+        assert ((b - b2).length() < eps);
+    }
+    std::cout << "  OK\n";
+}
+
+// Test that if we pass in a matrix that we know consists only of translates,
+// rotates, and uniform scale that we get an exact match.
+template <typename T>
+void
+testWithTranslateRotateAndScale (const IMATH_INTERNAL_NAMESPACE::M44d& m)
+{
+    std::cout << "Testing with known translate/rotate/scale matrix\n" << m;
+    IMATH_INTERNAL_NAMESPACE::Rand48 rand (5376);
+
+    typedef IMATH_INTERNAL_NAMESPACE::Vec3<T> V3;
+    std::vector<V3> from;
+    std::vector<T> weights;
+
+    const float eps = 1e-4f;
+    std::cout << "numPoints: " << std::flush;
+    for (size_t numPoints = 1; numPoints < 10; ++numPoints)
+    {
+        from.push_back (V3(
+            static_cast<T>(rand.nextf()),
+            static_cast<T>(rand.nextf()),
+            static_cast<T>(rand.nextf())));
+        weights.push_back(static_cast<T>(rand.nextf()));
+        std::cout << from.size () << " ";
+
+        std::vector<V3> to;
+        for (size_t i = 0; i < from.size(); ++i)
+            to.push_back (from[i] * m);
+
+        // weighted:
+        IMATH_INTERNAL_NAMESPACE::M44d res =
+            IMATH_INTERNAL_NAMESPACE::procrustesRotationAndTranslation (&from[0],
+                                                                        &to[0],
+                                                                        &weights[0],
+                                                                        from.size(),
+                                                                        true);
+        for (size_t i = 0; i < from.size(); ++i)
+            assert ((from[i] * res - to[i]).length() < eps);
+
+        // unweighted:
+        res = IMATH_INTERNAL_NAMESPACE::procrustesRotationAndTranslation (&from[0],
+                                                                          &to[0],
+                                                                          from.size(),
+                                                                          true);
+        for (size_t i = 0; i < from.size(); ++i)
+            assert ((from[i] * res - to[i]).length() < eps);
+    }
+    std::cout << "  OK\n";
+}
+
+template <typename T>
+double
+procrustesError (const IMATH_INTERNAL_NAMESPACE::Vec3<T>* from,
+                 const IMATH_INTERNAL_NAMESPACE::Vec3<T>* to,
+                 const T* weights,
+                 const size_t n,
+                 const IMATH_INTERNAL_NAMESPACE::M44d& xform)
+{
+    double result   = 0.0;
+    double residual = 0.0;
+    for (size_t i = 0; i < n; ++i)
+    {
+        IMATH_INTERNAL_NAMESPACE::V3d xformed = IMATH_INTERNAL_NAMESPACE::V3d (from[i]) * xform;
+        IMATH_INTERNAL_NAMESPACE::V3d diff    = xformed - IMATH_INTERNAL_NAMESPACE::V3d (to[i]);
+        const double w                        = weights[i];
+        const double mag                      = w * diff.length2();
+
+        // Use Kahan summation for the heck of it:
+        const double y = mag - residual;
+        const double t = result + y;
+        residual       = (t - result) - y;
+        result         = t;
+    }
+    return result;
+}
+
+template <typename T>
+void
+verifyProcrustes (const std::vector<IMATH_INTERNAL_NAMESPACE::Vec3<T>>& from,
+                  const std::vector<IMATH_INTERNAL_NAMESPACE::Vec3<T>>& to)
+{
+    const T eps = std::sqrt (std::numeric_limits<T>::epsilon());
+
+    const size_t n = from.size();
+
+    // Validate that passing in uniform weights gives the same answer as
+    // passing in no weights:
+    std::vector<T> weights (from.size());
+    for (size_t i = 0; i < weights.size(); ++i)
+        weights[i] = 1;
+    IMATH_INTERNAL_NAMESPACE::M44d m1 = procrustesRotationAndTranslation (&from[0], &to[0], n);
+    IMATH_INTERNAL_NAMESPACE::M44d m2 =
+        procrustesRotationAndTranslation (&from[0], &to[0], &weights[0], n);
+    for (int i = 0; i < 4; ++i)
+        for (int j = 0; j < 4; ++j)
+            assert (std::abs (m1[i][j] - m2[i][j]) < eps);
+
+    // Now try the weighted version:
+    for (size_t i = 0; i < weights.size (); ++i)
+        weights[i] = static_cast<T>(i + 1);
+
+    IMATH_INTERNAL_NAMESPACE::M44d m =
+        procrustesRotationAndTranslation (&from[0], &to[0], &weights[0], n);
+
+    // with scale:
+    IMATH_INTERNAL_NAMESPACE::M44d ms =
+        procrustesRotationAndTranslation (&from[0], &to[0], &weights[0], n, true);
+
+    // Verify that it's orthonormal w/ positive determinant.
+    const T det = static_cast<T>(m.determinant ());
+    assert (std::abs (det - T (1)) < eps);
+
+    // Verify orthonormal:
+    IMATH_INTERNAL_NAMESPACE::M33d upperLeft;
+    for (int i = 0; i < 3; ++i)
+        for (int j = 0; j < 3; ++j)
+            upperLeft[i][j] = m[i][j];
+    IMATH_INTERNAL_NAMESPACE::M33d product = upperLeft * upperLeft.transposed();
+    for (int i = 0; i < 3; ++i)
+    {
+        for (int j = 0; j < 3; ++j)
+        {
+            const double expected = (i == j ? 1.0 : 0.0);
+            assert (std::abs (product[i][j] - expected) < eps);
+        }
+    }
+
+    // Verify that nearby transforms are worse:
+    const size_t numTries = 10;
+    IMATH_INTERNAL_NAMESPACE::Rand48 rand (1056);
+    const double delta = 1e-3;
+    for (size_t i = 0; i < numTries; ++i)
+    {
+        // Construct an orthogonal rotation matrix using Euler angles:
+        IMATH_INTERNAL_NAMESPACE::Eulerd diffRot (delta * rand.nextf(),
+                                                  delta * rand.nextf(),
+                                                  delta * rand.nextf());
+
+        assert (procrustesError (&from[0], &to[0], &weights[0], n, m * diffRot.toMatrix44()) >
+                procrustesError (&from[0], &to[0], &weights[0], n, m));
+
+        // Try a small translation:
+        IMATH_INTERNAL_NAMESPACE::V3d diffTrans (delta * rand.nextf(),
+                                                 delta * rand.nextf(),
+                                                 delta * rand.nextf());
+        IMATH_INTERNAL_NAMESPACE::M44d translateMatrix;
+        translateMatrix.translate (diffTrans);
+        assert (procrustesError (&from[0], &to[0], &weights[0], n, m * translateMatrix) >
+                procrustesError (&from[0], &to[0], &weights[0], n, m));
+    }
+
+    // Try a small scale:
+    IMATH_INTERNAL_NAMESPACE::M44d newMat    = ms;
+    const double                   scaleDiff = delta;
+    for (int i = 0; i < 3; ++i)
+        for (int j = 0; j < 3; ++j)
+            newMat[i][j] = ms[i][j] * (1.0 + scaleDiff);
+    assert (procrustesError (&from[0], &to[0], &weights[0], n, newMat) >
+            procrustesError (&from[0], &to[0], &weights[0], n, ms));
+
+    for (int i = 0; i < 3; ++i)
+        for (int j = 0; j < 3; ++j)
+            newMat[i][j] = ms[i][j] * (1.0 - scaleDiff);
+    assert (procrustesError (&from[0], &to[0], &weights[0], n, newMat) >
+            procrustesError (&from[0], &to[0], &weights[0], n, ms));
+
+    //
+    // Verify the magical property that makes shape springs work:
+    // when the displacements Q*A-B, times the weights,
+    // are applied as forces at B,
+    // there is zero net force and zero net torque.
+    //
+    {
+        IMATH_INTERNAL_NAMESPACE::V3d netForce (0);
+        IMATH_INTERNAL_NAMESPACE::V3d netTorque (0);
+        for (size_t iPoint = 0; iPoint < n; ++iPoint)
+        {
+            const IMATH_INTERNAL_NAMESPACE::V3d force =
+                weights[iPoint] * (from[iPoint] * m - to[iPoint]);
+            netForce += force;
+            netTorque += to[iPoint].cross (force);
+        }
+
+        assert (netForce.length2() < eps);
+        assert (netTorque.length2() < eps);
+    }
+}
+
+template <typename T>
+void
+testProcrustesWithMatrix (const IMATH_INTERNAL_NAMESPACE::M44d& m)
+{
+    std::cout << "Testing Procrustes algorithm with arbitrary matrix: \n" << m;
+    std::vector<IMATH_INTERNAL_NAMESPACE::Vec3<T>> fromPoints;
+    std::vector<IMATH_INTERNAL_NAMESPACE::Vec3<T>> toPoints;
+
+    IMATH_INTERNAL_NAMESPACE::Rand48 random (1209);
+    std::cout << "   numPoints: ";
+    for (size_t numPoints = 1; numPoints < 10; ++numPoints)
+    {
+        std::cout << numPoints << " " << std::flush;
+        fromPoints.clear();
+        toPoints.clear();
+        for (size_t i = 0; i < numPoints; ++i)
+        {
+            const IMATH_INTERNAL_NAMESPACE::V3d fromPt (random.nextf(),
+                                                        random.nextf(),
+                                                        random.nextf());
+            const IMATH_INTERNAL_NAMESPACE::V3d toPt = fromPt * m;
+            fromPoints.push_back (IMATH_INTERNAL_NAMESPACE::Vec3<T> (fromPt));
+            toPoints.push_back (IMATH_INTERNAL_NAMESPACE::Vec3<T> (toPt));
+        }
+        verifyProcrustes (fromPoints, toPoints);
+    }
+    std::cout << "OK\n";
+}
+
+template <typename T>
+void
+testProcrustesImp()
+{
+    // Test the empty case:
+    IMATH_INTERNAL_NAMESPACE::M44d id =
+        procrustesRotationAndTranslation ((IMATH_INTERNAL_NAMESPACE::Vec3<T>*) 0,
+                                          (IMATH_INTERNAL_NAMESPACE::Vec3<T>*) 0,
+                                          (T*) 0,
+                                          0);
+    assert (id == IMATH_INTERNAL_NAMESPACE::M44d());
+
+    id = procrustesRotationAndTranslation ((IMATH_INTERNAL_NAMESPACE::Vec3<T>*) 0,
+                                           (IMATH_INTERNAL_NAMESPACE::Vec3<T>*) 0,
+                                           0);
+    assert (id == IMATH_INTERNAL_NAMESPACE::M44d());
+
+    // First we'll test with a bunch of known translation/rotation matrices
+    // to make sure we get back exactly the same points:
+    IMATH_INTERNAL_NAMESPACE::M44d m;
+    m.makeIdentity();
+    testTranslationRotationMatrix<T> (m);
+
+    m.translate (IMATH_INTERNAL_NAMESPACE::V3d (3.0, 5.0, -0.2));
+    testTranslationRotationMatrix<T> (m);
+
+    m.rotate (IMATH_INTERNAL_NAMESPACE::V3d (M_PI, 0, 0));
+    testTranslationRotationMatrix<T> (m);
+
+    m.rotate (IMATH_INTERNAL_NAMESPACE::V3d (0, M_PI / 4.0, 0));
+    testTranslationRotationMatrix<T> (m);
+
+    m.rotate (IMATH_INTERNAL_NAMESPACE::V3d (0, 0, -3.0 / 4.0 * M_PI));
+    testTranslationRotationMatrix<T> (m);
+
+    m.makeIdentity();
+    testWithTranslateRotateAndScale<T> (m);
+
+    m.translate (IMATH_INTERNAL_NAMESPACE::V3d (0.4, 6.0, 10.0));
+    testWithTranslateRotateAndScale<T> (m);
+
+    m.rotate (IMATH_INTERNAL_NAMESPACE::V3d (M_PI, 0, 0));
+    testWithTranslateRotateAndScale<T> (m);
+
+    m.rotate (IMATH_INTERNAL_NAMESPACE::V3d (0, M_PI / 4.0, 0));
+    testWithTranslateRotateAndScale<T> (m);
+
+    m.rotate (IMATH_INTERNAL_NAMESPACE::V3d (0, 0, -3.0 / 4.0 * M_PI));
+    testWithTranslateRotateAndScale<T> (m);
+
+    m.scale (IMATH_INTERNAL_NAMESPACE::V3d (2.0, 2.0, 2.0));
+    testWithTranslateRotateAndScale<T> (m);
+
+    m.scale (IMATH_INTERNAL_NAMESPACE::V3d (0.01, 0.01, 0.01));
+    testWithTranslateRotateAndScale<T> (m);
+
+    // Now we'll test with some random point sets and verify
+    // the various Procrustes properties:
+    std::vector<IMATH_INTERNAL_NAMESPACE::Vec3<T>> fromPoints;
+    std::vector<IMATH_INTERNAL_NAMESPACE::Vec3<T>> toPoints;
+    fromPoints.clear();
+    toPoints.clear();
+
+    for (size_t i = 0; i < 4; ++i)
+    {
+        const T theta = T (2 * i) / T (M_PI);
+        const T offset = T(M_PI / 3.0);
+        fromPoints.push_back (
+            IMATH_INTERNAL_NAMESPACE::Vec3<T> (cos (theta), sin (theta), 0));
+        toPoints.push_back (IMATH_INTERNAL_NAMESPACE::Vec3<T> (
+            cos (theta + offset), sin (theta + offset), 0));
+    }
+    verifyProcrustes (fromPoints, toPoints);
+
+    IMATH_INTERNAL_NAMESPACE::Rand48 random (1209);
+    for (size_t numPoints = 1; numPoints < 10; ++numPoints)
+    {
+        fromPoints.clear();
+        toPoints.clear();
+        for (size_t i = 0; i < numPoints; ++i)
+        {
+            fromPoints.push_back (IMATH_INTERNAL_NAMESPACE::Vec3<T> (
+                static_cast<T>(random.nextf ()),
+                static_cast<T>(random.nextf ()),
+                static_cast<T>(random.nextf ())));
+            toPoints.push_back (IMATH_INTERNAL_NAMESPACE::Vec3<T> (
+                static_cast<T>(random.nextf ()),
+                static_cast<T>(random.nextf ()),
+                static_cast<T>(random.nextf ())));
+        }
+    }
+    verifyProcrustes (fromPoints, toPoints);
+
+    // Test with some known matrices of varying degrees of quality:
+    testProcrustesWithMatrix<T> (m);
+
+    m.translate (IMATH_INTERNAL_NAMESPACE::Vec3<T> (3, 4, 1));
+    testProcrustesWithMatrix<T> (m);
+
+    m.translate (IMATH_INTERNAL_NAMESPACE::Vec3<T> (-10, 2, 1));
+    testProcrustesWithMatrix<T> (m);
+
+    IMATH_INTERNAL_NAMESPACE::Eulerd rot (M_PI / 3.0, 3.0 * M_PI / 4.0, 0);
+    m = m * rot.toMatrix44();
+    testProcrustesWithMatrix<T> (m);
+
+    m.scale (IMATH_INTERNAL_NAMESPACE::Vec3<T> (T(1.5), T(6.4), T(2.0)));
+    testProcrustesWithMatrix<T> (m);
+
+    IMATH_INTERNAL_NAMESPACE::Eulerd rot2 (1.0, M_PI, M_PI / 3.0);
+    m = m * rot.toMatrix44();
+
+    m.scale (IMATH_INTERNAL_NAMESPACE::Vec3<T> (-1, 1, 1));
+    testProcrustesWithMatrix<T> (m);
+
+    m.scale (IMATH_INTERNAL_NAMESPACE::Vec3<T> (1, T(0.001), 1));
+    testProcrustesWithMatrix<T> (m);
+
+    m.scale (IMATH_INTERNAL_NAMESPACE::Vec3<T> (1, 1, 0));
+    testProcrustesWithMatrix<T> (m);
+}
+
+void
+testProcrustes()
+{
+    std::cout << "Testing Procrustes algorithms in single precision..." << std::endl;
+    testProcrustesImp<float>();
+
+    std::cout << "Testing Procrustes algorithms in double precision..." << std::endl;
+    testProcrustesImp<double>();
+}
diff --git a/src/ImathTest/testProcrustes.h b/src/ImathTest/testProcrustes.h
new file mode 100644 (file)
index 0000000..5a1e3ba
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testProcrustes();
diff --git a/src/ImathTest/testQuat.cpp b/src/ImathTest/testQuat.cpp
new file mode 100644 (file)
index 0000000..db01187
--- /dev/null
@@ -0,0 +1,247 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathFun.h>
+#include <ImathMatrixAlgo.h>
+#include <ImathPlatform.h>
+#include <ImathQuat.h>
+#include <cassert>
+#include <cmath>
+#include <iostream>
+#include "testQuat.h"
+
+// Include ImathForward *after* other headers to validate forward declarations
+#include <ImathForward.h>
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+template <class T>
+void
+testQuatT ()
+{
+    const T s = std::numeric_limits<T>::min();
+    const T e = 4 * std::numeric_limits<T>::epsilon();
+
+    //
+    // constructors, r(), v()
+    //
+
+    {
+       Quat<T> q = Quat<T>();
+       assert (q.r == 1 && q.v == Vec3<T> (0, 0, 0));
+
+       q = Quat<T> (2, 3, 4, 5);
+       assert (q.r == 2 && q.v == Vec3<T> (3, 4, 5));
+
+       q = Quat<T> (6, Vec3<T> (7, 8, 9));
+       assert (q.r == 6 && q.v == Vec3<T> (7, 8, 9));
+
+       Quat<T> q1 = Quat<T> (q);
+       assert (q1.r == 6 && q1.v == Vec3<T> (7, 8, 9));
+    }
+
+    //
+    // invert(), inverse()
+    //
+
+    {
+       Quat<T> q = Quat<T> (1, 0, 0, 1);
+       assert (q.inverse() == Quat<T> (0.5, 0, 0, -0.5));
+
+       q.invert();
+       assert (q == Quat<T> (0.5, 0, 0, -0.5));
+    }
+
+    //
+    // normalize(), normalized()
+    //
+
+    {
+       Quat<T> q = Quat<T> (2, Vec3<T> (0, 0, 0));
+       assert (q.normalized() == Quat<T> (1, 0, 0, 0));
+
+       q.normalize();
+       assert (q == Quat<T> (1, 0, 0, 0));
+
+       q = Quat<T> (0, Vec3<T> (0, 2, 0));
+       assert (q.normalized() == Quat<T> (0, 0, 1, 0));
+
+       q.normalize();
+       assert (q == Quat<T> (0, 0, 1, 0));
+    }
+
+    //
+    // length()
+    //
+
+    {
+       Quat<T> q = Quat<T> (3, 0, 4, 0);
+       assert (q.length() == 5);
+    }
+
+    //
+    // setAxisAngle(), angle(), axis()
+    //
+
+    {
+        Quat<T> q;
+        q.setAxisAngle (Vec3<T> (0, 0, 1), T(M_PI_2));
+        Vec3<T> v = q.axis ();
+        T       a = q.angle ();
+        assert (v.equalWithAbsError (Vec3<T> (0, 0, 1), e));
+        assert (IMATH_INTERNAL_NAMESPACE::equal (a, T (M_PI_2), e));
+    }
+
+    //
+    // Accuracy of angle() for very small angles
+    // and when real part is slightly greater than 1.
+    //
+
+    {
+        T t = 10 * std::sqrt (s);
+
+        Quat<T> q;
+        q.setAxisAngle (Vec3<T> (0, 0, 1), t);
+        Vec3<T> v = q.axis ();
+        T       a = q.angle ();
+        assert (v.equalWithAbsError (Vec3<T> (0, 0, 1), e));
+        assert (IMATH_INTERNAL_NAMESPACE::equal (a, t, t * e));
+
+        q.r *= T(1.1);
+        q.v *= T(1.1);
+        v = q.axis ();
+        a = q.angle ();
+        assert (v.equalWithAbsError (Vec3<T> (0, 0, 1), e));
+        assert (IMATH_INTERNAL_NAMESPACE::equal (a, t, t * e));
+    }
+
+    {
+        T t = T(0.001) * std::sqrt (s);
+
+        Quat<T> q;
+        q.setAxisAngle (Vec3<T> (0, 0, 1), t);
+        Vec3<T> v = q.axis ();
+        T       a = q.angle ();
+        assert (v.equalWithAbsError (Vec3<T> (0, 0, 1), e));
+        assert (IMATH_INTERNAL_NAMESPACE::equal (a, t, t * e));
+
+        q.r *= T(1.1);
+        q.v *= T(1.1);
+        v = q.axis ();
+        a = q.angle ();
+        assert (v.equalWithAbsError (Vec3<T> (0, 0, 1), e));
+        assert (IMATH_INTERNAL_NAMESPACE::equal (a, t, t * e));
+    }
+
+    //
+    // toMatrix33(), toMatrix44()
+    //
+
+    {
+       Quat<T> q;
+       q.setRotation (Vec3<T> (1, 0, 0), Vec3<T> (0, 1, 0));
+
+       Matrix33<T> m1 = q.toMatrix33();
+
+        // clang-format off
+        
+       assert (m1.equalWithAbsError (Matrix33<T> (0, 1, 0,
+                                                 -1, 0, 0,
+                                                  0, 0, 1),
+                                     e));
+
+       Matrix44<T> m2 = q.toMatrix44();
+
+       assert (m2.equalWithAbsError (Matrix44<T> (0, 1, 0, 0,
+                                                 -1, 0, 0, 0,
+                                                  0, 0, 1, 0,
+                                                  0, 0, 0, 1),
+                                     e));
+        // clang-format on
+    }
+
+    //
+    // +, - (unary and binary), ~ *, /, ^
+    //
+
+    assert (Quat<T> (1, 2, 3, 4) + Quat<T> (5, 6, 7, 8) == Quat<T> (6, 8, 10, 12));
+
+    assert (Quat<T> (-1, -2, -3, -4) - Quat<T> (5, 6, 7, 8) == Quat<T> (-6, -8, -10, -12));
+
+    assert (-Quat<T> (1, 2, 3, 4) == Quat<T> (-1, -2, -3, -4));
+    
+    assert (~Quat<T> (1, 2, 3, 4) == Quat<T> (1, -2, -3, -4));
+
+    assert (T (2) * Quat<T> (1, 2, 3, 4) == Quat<T> (2, 4, 6, 8));
+
+    assert (Quat<T> (1, 2, 3, 4) * T (2 )== Quat<T> (2, 4, 6, 8));
+
+    assert (Quat<T> (1, 0, 0, 1) * Quat<T> (1, 1, 0, 0) == Quat<T> (1, 1, 1, 1));
+
+    assert (Quat<T> (1, 1, 0, 0) * Quat<T> (1, 0, 0, 1) == Quat<T> (1, 1, -1, 1));
+    
+    assert (Quat<T> (1, 0, 0, 1) / Quat<T> (0.5, -0.5, 0, 0) == Quat<T> (1, 1, 1, 1));
+
+    assert (Quat<T> (2, 4, 6, 8) / T (2) == Quat<T> (1, 2, 3, 4));
+
+    assert ((Quat<T> (1, 2, 3, 4) ^ Quat<T> (2, 2, 2, 2)) == 20);
+
+    //
+    // extract()
+    //
+
+    {
+       Vec3<T> vFrom (1, 0, 0);
+       Vec3<T> vTo (0, 1, 1);
+       Matrix44<T> m1 = rotationMatrix (vFrom, vTo);
+       
+        Quat<T> q = extractQuat (m1);
+        ;
+
+       Matrix44<T> m2 = q.toMatrix44();
+
+       assert (m2.equalWithAbsError (m1, 2 * e));
+    }
+}
+
+
+void
+testQuatConversions ()
+{
+    {
+       Quatf q (1, V3f (2, 3, 4));
+       Quatd q1 = Quatd (q);
+       assert (q1.r == 1 && q1.v == V3d (2, 3, 4));
+    }
+
+    {
+       Quatd q (1, V3d (2, 3, 4));
+       Quatf q1 = Quatf (q);
+       assert (q1.r == 1 && q1.v == V3f (2, 3, 4));
+    }
+}
+
+} // namespace
+
+
+void
+testQuat ()
+{
+    cout << "Testing basic quaternion operations" << endl;
+
+    testQuatT<float>();
+    testQuatT<double>();
+    testQuatConversions();
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testQuat.h b/src/ImathTest/testQuat.h
new file mode 100644 (file)
index 0000000..2bc00fc
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testQuat();
diff --git a/src/ImathTest/testQuatSetRotation.cpp b/src/ImathTest/testQuatSetRotation.cpp
new file mode 100644 (file)
index 0000000..7b226a4
--- /dev/null
@@ -0,0 +1,170 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathQuat.h>
+#include <ImathRandom.h>
+#include <assert.h>
+#include <iostream>
+#include "testQuatSetRotation.h"
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+void
+testRotation (const V3f& from, const V3f& to)
+{
+    //
+    // Build a quaternion.
+    //
+
+    Quatf Q;
+    Q.setRotation (from, to);
+    M44f M = Q.toMatrix44();
+
+    //
+    // Verify that the quaternion rotates vector from into vector to.
+    //
+
+    float e = 20 * std::numeric_limits<float>::epsilon();
+
+    V3f fromM = from * M;
+    V3f fromQ = from * Q;
+    V3f t0    = to.normalized();
+    V3f fM0   = fromM.normalized();
+    V3f fQ0   = fromQ.normalized();
+
+    assert (t0.equalWithAbsError (fM0, e));
+    assert (t0.equalWithAbsError (fQ0, e));
+
+    //
+    // Verify that the rotation axis is the cross product of from and to.
+    //
+
+    V3f f0 = from.normalized();
+
+    if (abs (f0 ^ t0) < 0.9)
+    {
+        V3f n0  = (from % to).normalized();
+        V3f n0M = n0 * M;
+
+        assert (n0.equalWithAbsError (n0M, e));
+    }
+}
+
+void
+specificVectors()
+{
+    cout << "  exact 90-degree rotations" << endl;
+
+    testRotation (V3f (1, 0, 0), V3f (0, 1, 0));
+    testRotation (V3f (1, 0, 0), V3f (0, 0, 1));
+    testRotation (V3f (0, 1, 0), V3f (1, 0, 0));
+    testRotation (V3f (0, 1, 0), V3f (0, 0, 1));
+    testRotation (V3f (0, 0, 1), V3f (1, 0, 0));
+    testRotation (V3f (0, 0, 1), V3f (0, 1, 0));
+
+    cout << "  exact zero-degree rotations" << endl;
+
+    testRotation (V3f (1, 0, 0), V3f (1, 0, 0));
+    testRotation (V3f (0, 1, 0), V3f (0, 1, 0));
+    testRotation (V3f (0, 0, 1), V3f (0, 0, 1));
+    testRotation (V3f (1, 2, 3), V3f (2, 4, 6));
+
+    cout << "  exact 180-degree rotations" << endl;
+
+    testRotation (V3f (1, 0, 0), V3f (-1, 0, 0));
+    testRotation (V3f (0, 1, 0), V3f (0, -1, 0));
+    testRotation (V3f (0, 0, 1), V3f (0, 0, -1));
+    testRotation (V3f (1, 2, 3), V3f (-2, -4, -6));
+    testRotation (V3f (1, 3, 2), V3f (-2, -6, -4));
+    testRotation (V3f (2, 1, 3), V3f (-4, -2, -6));
+    testRotation (V3f (3, 1, 2), V3f (-6, -2, -4));
+    testRotation (V3f (2, 3, 1), V3f (-4, -6, -2));
+    testRotation (V3f (3, 2, 1), V3f (-6, -4, -2));
+
+    cout << "  other angles" << endl;
+
+    testRotation (V3f (1, 2, 3), V3f (4, 5, 6));
+    testRotation (V3f (1, 2, 3), V3f (4, 6, 5));
+    testRotation (V3f (1, 2, 3), V3f (5, 4, 6));
+    testRotation (V3f (1, 2, 3), V3f (6, 4, 5));
+    testRotation (V3f (1, 2, 3), V3f (5, 6, 4));
+    testRotation (V3f (1, 2, 3), V3f (6, 5, 4));
+    testRotation (V3f (1, 2, 3), V3f (-4, -5, -6));
+    testRotation (V3f (1, 2, 3), V3f (-4, -6, -5));
+    testRotation (V3f (1, 2, 3), V3f (-5, -4, -6));
+    testRotation (V3f (1, 2, 3), V3f (-6, -4, -5));
+    testRotation (V3f (1, 2, 3), V3f (-5, -6, -4));
+    testRotation (V3f (1, 2, 3), V3f (-6, -5, -4));
+}
+
+void
+randomVectors()
+{
+    cout << "  random from and to vectors" << endl;
+
+    Rand48 rand (17);
+
+    for (int i = 0; i < 500000; ++i)
+    {
+        V3f from = hollowSphereRand<V3f> (rand) * float(rand.nextf (0.1, 10.0));
+        V3f to   = hollowSphereRand<V3f> (rand) * float(rand.nextf (0.1, 10.0));
+        testRotation (from, to);
+    }
+}
+
+void
+nearlyEqualVectors()
+{
+    cout << "  nearly equal from and to vectors" << endl;
+
+    Rand48 rand (19);
+    float e = 100 * std::numeric_limits<float>::epsilon();
+
+    for (int i = 0; i < 500000; ++i)
+    {
+        V3f from = hollowSphereRand<V3f> (rand);
+        V3f to   = from + e * hollowSphereRand<V3f> (rand);
+        testRotation (from, to);
+    }
+}
+
+void
+nearlyOppositeVectors()
+{
+    cout << "  nearly opposite from and to vectors" << endl;
+
+    Rand48 rand (19);
+    float e = 100 * std::numeric_limits<float>::epsilon();
+
+    for (int i = 0; i < 500000; ++i)
+    {
+        V3f from = hollowSphereRand<V3f> (rand);
+        V3f to   = -from + e * hollowSphereRand<V3f> (rand);
+        testRotation (from, to);
+    }
+}
+
+} // namespace
+
+void
+testQuatSetRotation()
+{
+    cout << "Testing quaternion rotations" << endl;
+
+    specificVectors();
+    randomVectors();
+    nearlyEqualVectors();
+    nearlyOppositeVectors();
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testQuatSetRotation.h b/src/ImathTest/testQuatSetRotation.h
new file mode 100644 (file)
index 0000000..fc3d30a
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testQuatSetRotation();
diff --git a/src/ImathTest/testQuatSlerp.cpp b/src/ImathTest/testQuatSlerp.cpp
new file mode 100644 (file)
index 0000000..b1c47f8
--- /dev/null
@@ -0,0 +1,167 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathQuat.h>
+#include <ImathRandom.h>
+#include <assert.h>
+#include <iostream>
+#include <math.h>
+#include "testQuatSlerp.h"
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+void
+compareQuats (const Quatf& q1, const Quatf& q2, float e)
+{
+    assert (equalWithAbsError (q1.v.x, q2.v.x, e));
+    assert (equalWithAbsError (q1.v.y, q2.v.y, e));
+    assert (equalWithAbsError (q1.v.z, q2.v.z, e));
+    assert (equalWithAbsError (q1.r, q2.r, e));
+}
+
+Quatd
+pow (const Quatd q, int n)
+{
+    Quatd result;
+
+    for (int i = 0; i < n; ++i)
+        result *= q;
+
+    return result;
+}
+
+void
+testSlerp (const Quatf q1, const Quatf q2, int m, int n)
+{
+    //
+    // For two quaternions, q1 and q2, and the identity quaternion, qi,
+    //
+    //     slerp (q1, q2, f) == q1 * slerp (qi, q1.inverse() * q2, f);  (1)
+    //
+    // In addition, for integers m and n, with m >= 0, n > 0,
+    //
+    //     pow (slerp (qi, q3, m/n), n) == pow (q3, m)                  (2)
+    //
+    // This allows us to test if slerp (q1, q2, m/n) works correctly.
+    // Thanks to Dan Piponi for pointing this out.
+    //
+    // Note that e2, our upper bound for the numerical error in (2) is
+    // fairly large.  The reason for this is that testSlerp() will be
+    // called with m and n up to 16.  Taking quaternions to the 16th
+    // power amplifies any inaccuracies.
+    //
+
+    Quatf qi;
+    Quatf q3   = q1.inverse() * q2;
+    Quatf q1q2 = slerp (q1, q2, float (m) / float (n));
+    Quatf qiq3 = slerp (qi, q3, float (m) / float (n));
+    float e1   = 60 * std::numeric_limits<float>::epsilon();
+    float e2   = 600 * std::numeric_limits<float>::epsilon();
+
+    compareQuats (q1q2, q1 * qiq3, e1);
+    compareQuats (pow (qiq3, n), pow (q3, m), e2);
+}
+
+void
+testSlerp (const Quatf q1, const Quatf q2)
+{
+    const int n = 16;
+
+    for (int m = 0; m <= n; ++m)
+        testSlerp (q1, q2, m, n);
+}
+
+void
+specificRotations()
+{
+    cout << "  combinations of 90-degree rotations around x, y and z" << endl;
+
+    for (int x1 = 0; x1 < 3; ++x1)
+    {
+        V3f axis1 (0, 0, 0);
+        axis1[x1] = 1;
+
+        for (int n1 = 0; n1 < 4; ++n1)
+        {
+            float angle1 = n1 * float(M_PI / 2);
+
+            Quatf q1;
+            q1.setAxisAngle (axis1, angle1);
+
+            for (int x2 = 0; x2 < 3; ++x2)
+            {
+                V3f axis2 (0, 0, 0);
+                axis2[x2] = 1;
+
+                for (int n2 = 0; n2 < 4; ++n2)
+                {
+                    float angle2 = n2 * float(M_PI / 2);
+
+                    Quatf q2;
+                    q2.setAxisAngle (axis2, angle2);
+
+                    testSlerp (q1, q2);
+                    testSlerp (-q1, -q2);
+
+                    if ((q1 ^ q2) < 0.99)
+                    {
+                        testSlerp (q1, -q2);
+                        testSlerp (-q1, q2);
+                    }
+                }
+            }
+        }
+    }
+}
+
+void
+randomRotations()
+{
+    cout << "  random rotations" << endl;
+
+    Rand48 rand (53);
+
+    for (int i = 0; i < 10000; ++i)
+    {
+        V3f   axis1  = hollowSphereRand<V3f> (rand);
+        V3f   axis2  = hollowSphereRand<V3f> (rand);
+        float angle1 = float(rand.nextf (0, M_PI));
+        float angle2 = float(rand.nextf (0, M_PI));
+
+        Quatf q1, q2;
+        q1.setAxisAngle (axis1, angle1);
+        q2.setAxisAngle (axis2, angle2);
+
+        testSlerp (q1, q2);
+        testSlerp (-q1, -q2);
+
+        if ((q1 ^ q2) < 0.99)
+        {
+            testSlerp (q1, -q2);
+            testSlerp (-q1, q2);
+        }
+    }
+}
+
+} // namespace
+
+void
+testQuatSlerp()
+{
+    cout << "Testing quaternion spherical linear interpolation" << endl;
+
+    specificRotations();
+    randomRotations();
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testQuatSlerp.h b/src/ImathTest/testQuatSlerp.h
new file mode 100644 (file)
index 0000000..6249123
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testQuatSlerp();
diff --git a/src/ImathTest/testRandom.cpp b/src/ImathTest/testRandom.cpp
new file mode 100644 (file)
index 0000000..d2c2bbe
--- /dev/null
@@ -0,0 +1,268 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathFun.h>
+#include <ImathRandom.h>
+#include <ImathVec.h>
+#include <assert.h>
+#include <iomanip>
+#include <iostream>
+#include "testRandom.h"
+
+// Include ImathForward *after* other headers to validate forward declarations
+#include <ImathForward.h>
+
+using namespace std;
+using IMATH_INTERNAL_NAMESPACE::abs;
+
+namespace
+{
+
+void
+testErand48()
+{
+    //
+    // Our implementation of erand48(), nrand48(), etc.
+    // assumes that sizeof (unsigned short) == 2.
+    //
+
+    assert (sizeof (unsigned short) == 2);
+
+    //
+    // starting with a given seed, erand48() and nrand48()
+    // must generate the same sequence as the standard
+    // Unix/Linux functions.
+    //
+
+    unsigned short state[3];
+    state[0] = 0;
+    state[1] = 1;
+    state[2] = 2;
+
+    assert (abs (IMATH_INTERNAL_NAMESPACE::erand48 (state) - 0.671004) < 0.00001);
+    assert (abs (IMATH_INTERNAL_NAMESPACE::erand48 (state) - 0.786905) < 0.00001);
+    assert (abs (IMATH_INTERNAL_NAMESPACE::erand48 (state) - 0.316850) < 0.00001);
+    assert (abs (IMATH_INTERNAL_NAMESPACE::erand48 (state) - 0.384870) < 0.00001);
+    assert (abs (IMATH_INTERNAL_NAMESPACE::erand48 (state) - 0.854650) < 0.00001);
+
+    assert (IMATH_INTERNAL_NAMESPACE::nrand48 (state) == 0x4f4e8cb0);
+    assert (IMATH_INTERNAL_NAMESPACE::nrand48 (state) == 0x063e864b);
+    assert (IMATH_INTERNAL_NAMESPACE::nrand48 (state) == 0x2d10f1dd);
+    assert (IMATH_INTERNAL_NAMESPACE::nrand48 (state) == 0x1aadc122);
+    assert (IMATH_INTERNAL_NAMESPACE::nrand48 (state) == 0x1836a71f);
+
+    assert (state[0] == 0x2a42);
+    assert (state[1] == 0x4e3e);
+    assert (state[2] == 0x306d);
+}
+
+void
+testDrand48 ()
+{
+    std::cout << "testDrand48()" << std::endl;
+    
+    //
+    // Confirm that drand48/lrand48 return the same values as
+    // erand48/nrand48 with the same seed.
+    //
+    
+    unsigned short state[3];
+    state[2] = 0;
+    state[1] = 0;
+    state[0] = 0x330e;
+
+    IMATH_INTERNAL_NAMESPACE::srand48(0);
+
+    double e = IMATH_INTERNAL_NAMESPACE::erand48(state);
+    double d = IMATH_INTERNAL_NAMESPACE::drand48();
+    assert (e == d);
+
+    state[2] = 0;
+    state[1] = 0;
+    state[0] = 0x330e;
+
+    IMATH_INTERNAL_NAMESPACE::srand48(0);
+
+    long int n = IMATH_INTERNAL_NAMESPACE::nrand48(state);
+    long int l = IMATH_INTERNAL_NAMESPACE::lrand48();
+    assert (l == n);
+}
+
+template <class Rand>
+void
+testGenerator()
+{
+    //
+    // Test if the values, and the differences between
+    // successive values, are evenly distributed.
+    //
+
+    const int N = 10;
+    const int M = 100000;
+
+    int values[N + 1];
+    int diffs[2 * N + 3];
+    int* v = &values[0];
+    int* d = &diffs[N + 2];
+
+    for (int i = 0; i <= N; ++i)
+        v[i] = 0;
+
+    for (int i = -N; i <= N; ++i)
+        d[i] = 0;
+
+    Rand rand (0);
+    float previous = 0;
+
+    for (int i = 0; i < M * N; ++i)
+    {
+        float r    = float(rand.nextf (0.0, 1.0));
+        float diff = r - previous;
+        previous   = r;
+
+        v[int (r * N)] += 1;
+        d[IMATH_INTERNAL_NAMESPACE::floor (diff * N + 0.5)] += 1;
+    }
+
+    cout << "  values" << endl;
+
+    for (int i = 0; i < N; ++i)
+    {
+        // cout << setw (4) << i << ' ' << setw(6) << v[i] << ' ';
+        assert (abs (v[i] - M) < 0.01 * M);
+
+        // for (int j = 0; j < v[i] * 60 / M; ++j)
+        //      cout << '*';
+
+        // cout << endl;
+    }
+
+    assert (v[N] == 0);
+
+    cout << "  differences between successive values" << endl;
+
+    for (int i = -N; i <= N; ++i)
+    {
+        // cout << setw (4) << i << ' ' << setw (6) << d[i] << ' ';
+        assert (abs ((N - abs (i)) * M / N - d[i]) < 0.05 * M);
+
+        // for (int j = 0; j < d[i] * 60 / M; ++j)
+        //     cout << '*';
+
+        // cout << endl;
+    }
+
+    cout << "  range" << endl;
+
+    double rMin = 1.0;
+    double rMax = 0.0;
+
+    for (int i = 0; i <= 10000000; ++i)
+    {
+        double r = rand.nextf (0.0, 1.0);
+
+        if (rMin > r)
+            rMin = r;
+
+        if (rMax < r)
+            rMax = r;
+    }
+
+    assert (rMin < 0.0001 && rMax > 0.9999);
+
+    const double pow_2_60 = double (1073741824) * double (1073741824);
+
+    for (int i = 0; i <= 10000000; ++i)
+    {
+        double r0 = rand.nextf (-2.0, 3.0);
+        assert (r0 >= -2.0 && r0 <= 3.0);
+
+        double r1 = rand.nextf (-pow_2_60, 1);
+        assert (r1 >= -pow_2_60 && r1 <= 1);
+
+        double r2 = rand.nextf (-1, pow_2_60);
+        assert (r2 >= -1 && r2 <= pow_2_60);
+    }
+}
+
+template <class Rand>
+void
+testSolidSphere()
+{
+    const int N = 10;
+    const int M = 10000;
+    int v[N + 1];
+
+    for (int i = 0; i <= N; ++i)
+        v[i] = 0;
+
+    Rand rand (0);
+
+    for (int i = 0; i < M * N; ++i)
+    {
+        IMATH_INTERNAL_NAMESPACE::V3f p =
+            IMATH_INTERNAL_NAMESPACE::solidSphereRand<IMATH_INTERNAL_NAMESPACE::V3f> (rand);
+        float l = p.length();
+        v[IMATH_INTERNAL_NAMESPACE::floor (l * N)] += 1;
+
+        assert (l < 1.00001);
+    }
+
+    for (int i = 0; i < N; ++i)
+        assert (v[i] > 0);
+}
+
+template <class Rand>
+void
+testHollowSphere()
+{
+    const int M = 100000;
+    Rand rand (0);
+
+    for (int i = 0; i < M; ++i)
+    {
+        IMATH_INTERNAL_NAMESPACE::V3f p =
+            IMATH_INTERNAL_NAMESPACE::hollowSphereRand<IMATH_INTERNAL_NAMESPACE::V3f> (rand);
+        float l = p.length();
+
+        assert (abs (l - 1) < 0.00001);
+    }
+}
+
+} // namespace
+
+void
+testRandom()
+{
+    cout << "Testing random number generators" << endl;
+
+    cout << "erand48(), nrand48()" << endl;
+    testErand48();
+
+    cout << "drand48(), lrand48()" << endl;
+    testDrand48 ();
+
+    cout << "Rand32" << endl;
+    testGenerator<IMATH_INTERNAL_NAMESPACE::Rand32>();
+
+    cout << "Rand48" << endl;
+    testGenerator<IMATH_INTERNAL_NAMESPACE::Rand48>();
+
+    cout << "Rand48" << endl;
+    testGenerator<IMATH_INTERNAL_NAMESPACE::Rand48> ();
+    
+    
+    cout << "solidSphereRand()" << endl;
+    testSolidSphere<IMATH_INTERNAL_NAMESPACE::Rand32>();
+
+    cout << "hollowSphereRand()" << endl;
+    testHollowSphere<IMATH_INTERNAL_NAMESPACE::Rand32>();
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testRandom.h b/src/ImathTest/testRandom.h
new file mode 100644 (file)
index 0000000..fd25453
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testRandom();
diff --git a/src/ImathTest/testRoots.cpp b/src/ImathTest/testRoots.cpp
new file mode 100644 (file)
index 0000000..62dce65
--- /dev/null
@@ -0,0 +1,231 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathFun.h>
+#include <ImathRoots.h>
+#include <algorithm>
+#include <assert.h>
+#include <iomanip>
+#include <iostream>
+#include "testRoots.h"
+
+using namespace std;
+
+void
+sort (int nx, double& x0, double& x1, double& x2)
+{
+    if (nx == 2)
+    {
+        if (x0 > x1)
+            swap (x0, x1);
+    }
+
+    if (nx == 3)
+    {
+        if (x0 > x1)
+            swap (x0, x1);
+        if (x1 > x2)
+            swap (x1, x2);
+        if (x0 > x1)
+            swap (x0, x1);
+    }
+}
+
+void
+sort (int nx, double x[])
+{
+    if (nx == 2)
+    {
+        if (x[0] > x[1])
+            swap (x[0], x[1]);
+    }
+
+    if (nx == 3)
+    {
+        if (x[0] > x[1])
+            swap (x[0], x[1]);
+        if (x[1] > x[2])
+            swap (x[1], x[2]);
+        if (x[0] > x[1])
+            swap (x[0], x[1]);
+    }
+}
+
+void
+solve (double a,
+       double b,
+       double c,
+       double d, // coefficients
+       int nx,   // number of expected solutions
+       double x0,
+       double x1,
+       double x2) // expected solutions
+{
+    cout << "coefficients: " << setw (3) << a << ' ' << setw (3) << b << ' ' << setw (3) << c << ' '
+         << setw (3) << d << ' ';
+
+    //
+    // Solve the equation a*x^3 + b*x^2 + c*x +d
+    //
+
+    double x[3] = { 0, 0, 0 };
+    int    n = IMATH_INTERNAL_NAMESPACE::solveCubic (a, b, c, d, x);
+
+    //
+    // Sort the numerical solutions.
+    // Sort the expected solutions.
+    //
+    sort (nx, x0, x1, x2);
+    sort (n, x);
+
+    //
+    // Compare the numerical and the expected solutions.
+    //
+
+    assert (n == nx);
+
+    cout << " solutions: ";
+
+    if (n == -1)
+        cout << "[-inf, inf]";
+
+    if (n == 0)
+        cout << "none";
+
+    const double e = 0.0000001; // maximum expected error for
+                                // the test cases listed below
+    if (n >= 1)
+    {
+        cout << x[0];
+        assert (IMATH_INTERNAL_NAMESPACE::equal (x[0], x0, e));
+    }
+    if (n >= 2)
+    {
+        cout << ' ' << x[1];
+        assert (IMATH_INTERNAL_NAMESPACE::equal (x[1], x1, e));
+    }
+    if (n >= 3)
+    {
+        cout << ' ' << x[2];
+        assert (IMATH_INTERNAL_NAMESPACE::equal (x[2], x2, e));
+    }
+
+    cout << endl;
+}
+
+void
+solve (double a,
+       double b,
+       double c, // coefficients
+       int nx,   // number of expected solutions
+       double x0,
+       double x1) // expected solutions
+{
+    cout << "coefficients: " << setw (3) << a << ' ' << setw (3) << b << ' ' << setw (3) << c
+         << ' ';
+    //
+    // Solve the equation a*x^2 + b*x^1 + c*x
+    //
+
+    double x[2] = { 0.0, 0.0 };
+    int n       = IMATH_INTERNAL_NAMESPACE::solveQuadratic (a, b, c, x);
+
+    //
+    // Sort the numerical solutions.
+    // Sort the expected solutions.
+    //
+    // Dummy variable for sort
+    double x2 = 0;
+    sort (nx, x0, x1, x2);
+    sort (n, x);
+
+    //
+    // Compare the numerical and the expected solutions.
+    //
+
+    assert (n == nx);
+    cout << " solutions: ";
+
+    if (n == -1)
+        cout << "[-inf, inf]";
+
+    if (n == 0)
+        cout << "none";
+
+    const double e = 0.0000001; // maximum expected error for
+                                // the test cases listed below
+
+    if (n >= 1)
+    {
+        cout << x[0];
+        assert (IMATH_INTERNAL_NAMESPACE::equal (x[0], x0, e));
+    }
+
+    if (n >= 2)
+    {
+        cout << ' ' << x[1];
+        assert (IMATH_INTERNAL_NAMESPACE::equal (x[1], x1, e));
+    }
+
+    cout << endl;
+}
+
+void
+testRoots()
+{
+    cout << "Testing functions in ImathRoots.h" << endl;
+
+    cout << endl << "solveCubic" << endl;
+    // Solve cubiec equations
+    //
+    //    coefficients         number of expected solutions
+    //            |            |
+    //            |            |   expected solutions
+    //            |            |         |
+    //    +-------+--------+   |  +------+-----+
+    //    |                |   |  |            |
+    solve (1, 6, 11, 6, 3, -1, -2, -3);  // real solutions: -1, -2, -3
+    solve (2, 2, -20, 16, 3, 1, -4, 2);  // real solutions: 1, -4, 2
+    solve (3, -3, 1, -1, 1, 1, 0, 0);    // real solutions: 1
+    solve (2, 0, -24, -32, 2, 4, -2, 0); // real solutions: 4, -2
+    solve (1, 0, 0, 0, 1, 0, 0, 0);      // real solutions: 0
+    solve (8, -24, 24, -8, 1, 1, 0, 0);  // real solutions: 1
+    solve (0, 2, -10, 12, 2, 2, 3, 0);   // real solutions: 2, 3
+    solve (0, 1, -1, -20, 2, 5, -4, 0);  // real solutions: 5, -4
+    solve (0, 3, -12, 12, 1, 2, 0, 0);   // real solutions: 2
+    solve (0, 1, 0, 0, 1, 0, 0, 0);      // real solutions: 0
+    solve (0, 1, 0, 1, 0, 0, 0, 0);      // real solutions: none
+    solve (0, 0, 3, -6, 1, 2, 0, 0);     // real solutions: 2
+    solve (0, 0, 5, 15, 1, -3, 0, 0);    // real solutions: -3
+    solve (0, 0, 1, 0, 1, 0, 0, 0);      // real solutions: 0
+    solve (0, 0, 0, 1, 0, 0, 0, 0);      // real solutions: none
+    solve (0, 0, 0, 0, -1, 0, 0, 0);     // real solutions: [-inf, inf]
+    solve (36, -37, 0, 12, 1, -0.4715155, 0, 0);
+
+    cout << endl << "solveQuadratic" << endl;
+    // Solve quadratic equations
+    //
+    //    coefficients    number of expected solutions
+    //          |         |
+    //          |         |  expected solutions
+    //          |         |      |
+    //    +-----+-----+   |  +---+---+
+    //    |           |   |  |       |
+    solve (1, 3, 2, 2, -1, -2); // real solutions: -1, -2
+    solve (1, 0, -9, 2, -3, 3); // real solutions: -3, 3
+    solve (1, -4, 0, 2, 4, 0);  // real solutions: 0, 4
+    solve (2, -4, 2, 1, 1, 0);  // real solutions: 1
+    solve (0, -4, 8, 1, 2, 0);  // real solutions: 2
+    solve (0, 7, 0, 1, 0, 0);   // real solutions: 0
+    solve (10, 0, 0, 1, 0, 0);  // real solutions: 0
+    solve (0, 0, 0, -1, 0, 0);  // real solutions: [-inf, inf]
+    solve (0, 0, 1, 0, 0, 0);   // real solutions: none
+    solve (3, -6, 30, 0, 0, 0); // real solutions: none
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testRoots.h b/src/ImathTest/testRoots.h
new file mode 100644 (file)
index 0000000..b8234ea
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testRoots();
diff --git a/src/ImathTest/testShear.cpp b/src/ImathTest/testShear.cpp
new file mode 100644 (file)
index 0000000..21b9e9b
--- /dev/null
@@ -0,0 +1,176 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathMath.h>
+#include <ImathShear.h>
+#include <assert.h>
+#include <iostream>
+#include "testShear.h"
+
+// Include ImathForward *after* other headers to validate forward declarations
+#include <ImathForward.h>
+
+using namespace std;
+
+void
+testShear()
+{
+    cout << "Testing functions in ImathShear.h" << endl;
+
+    cout << "Imath::Shear6 constructors" << endl;
+
+    const float epsilon = std::numeric_limits<float>::epsilon();
+
+    IMATH_INTERNAL_NAMESPACE::Shear6f testConstructor1;
+    IMATH_INTERNAL_NAMESPACE::Shear6f testConstructor2 (testConstructor1);
+
+    testConstructor1 = testConstructor2;
+
+    IMATH_INTERNAL_NAMESPACE::Shear6f testConstructor3 (52, 128, 254, 127, 12, -20);
+    IMATH_INTERNAL_NAMESPACE::Shear6f A (testConstructor3);
+    IMATH_INTERNAL_NAMESPACE::Shear6f B = A;
+    IMATH_INTERNAL_NAMESPACE::Shear6f X, Y, tmp;
+
+    assert (A == B);
+
+    cout << "Imath::Shear6 * f" << endl;
+
+    assert ((IMATH_INTERNAL_NAMESPACE::Shear6f (0.330f, 0.710f, 0.010f, 0.999f, -0.531f, -0.012f) *
+             0.999f) == IMATH_INTERNAL_NAMESPACE::Shear6f (0.330f * 0.999f,
+                                                           0.710f * 0.999f,
+                                                           0.010f * 0.999f,
+                                                           0.999f * 0.999f,
+                                                           -0.531f * 0.999f,
+                                                           -0.012f * 0.999f));
+
+    cout << "Imath::Shear6 / f" << endl;
+
+    assert ((IMATH_INTERNAL_NAMESPACE::Shear6f (0.330f, 0.710f, 0.010f, 0.999f, -0.531f, -0.012f) /
+             0.999f) == IMATH_INTERNAL_NAMESPACE::Shear6f (0.330f / 0.999f,
+                                                           0.710f / 0.999f,
+                                                           0.010f / 0.999f,
+                                                           0.999f / 0.999f,
+                                                           -0.531f / 0.999f,
+                                                           -0.012f / 0.999f));
+
+    cout << "Assignment and comparison" << endl;
+
+    B = A;
+    assert (B == A);
+    assert (!(B != A));
+
+    X = Y = IMATH_INTERNAL_NAMESPACE::Shear6f (0.123f, -0.420f, 0.501f, 0.998f, -0.231f, -0.034f);
+
+    X *= 0.001f;
+
+    assert (std::fabs ((Y.xy * 0.001f) - X.xy) <= epsilon &&
+            std::fabs ((Y.xz * 0.001f) - X.xz) <= epsilon &&
+            std::fabs ((Y.yz * 0.001f) - X.yz) <= epsilon &&
+            std::fabs ((Y.yx * 0.001f) - X.yx) <= epsilon &&
+            std::fabs ((Y.zx * 0.001f) - X.zx) <= epsilon &&
+            std::fabs ((Y.zy * 0.001f) - X.zy) <= epsilon);
+
+    X = Y = IMATH_INTERNAL_NAMESPACE::Shear6f (0.123f, -0.420f, 0.501f, 0.998f, -0.231f, -0.034f);
+
+    X /= -1.001f;
+
+    assert (std::fabs ((Y.xy / -1.001f) - X.xy) <= epsilon &&
+            std::fabs ((Y.xz / -1.001f) - X.xz) <= epsilon &&
+            std::fabs ((Y.yz / -1.001f) - X.yz) <= epsilon &&
+            std::fabs ((Y.yx / -1.001f) - X.yx) <= epsilon &&
+            std::fabs ((Y.zx / -1.001f) - X.zx) <= epsilon &&
+            std::fabs ((Y.zy / -1.001f) - X.zy) <= epsilon);
+
+    Y = IMATH_INTERNAL_NAMESPACE::Shear6f (0.998f, -0.001f, 0.501f, 1.001f, -0.231f, -0.034f);
+    X = IMATH_INTERNAL_NAMESPACE::Shear6f (0.011f, -0.420f, -0.501f, 0.998f, -0.231f, -0.034f);
+
+    tmp = X + Y;
+
+    assert (std::fabs ((X.xy + Y.xy) - tmp.xy) <= epsilon &&
+            std::fabs ((X.xz + Y.xz) - tmp.xz) <= epsilon &&
+            std::fabs ((X.yz + Y.yz) - tmp.yz) <= epsilon &&
+            std::fabs ((X.yx + Y.yx) - tmp.yx) <= epsilon &&
+            std::fabs ((X.zx + Y.zx) - tmp.zx) <= epsilon &&
+            std::fabs ((X.zy + Y.zy) - tmp.zy) <= epsilon);
+
+    tmp = X - Y;
+
+    assert (std::fabs ((X.xy - Y.xy) - tmp.xy) <= epsilon &&
+            std::fabs ((X.xz - Y.xz) - tmp.xz) <= epsilon &&
+            std::fabs ((X.yz - Y.yz) - tmp.yz) <= epsilon &&
+            std::fabs ((X.yx - Y.yx) - tmp.yx) <= epsilon &&
+            std::fabs ((X.zx - Y.zx) - tmp.zx) <= epsilon &&
+            std::fabs ((X.zy - Y.zy) - tmp.zy) <= epsilon);
+
+    tmp = X * Y;
+
+    assert (std::fabs ((X.xy * Y.xy) - tmp.xy) <= epsilon &&
+            std::fabs ((X.xz * Y.xz) - tmp.xz) <= epsilon &&
+            std::fabs ((X.yz * Y.yz) - tmp.yz) <= epsilon &&
+            std::fabs ((X.yx * Y.yx) - tmp.yx) <= epsilon &&
+            std::fabs ((X.zx * Y.zx) - tmp.zx) <= epsilon &&
+            std::fabs ((X.zy * Y.zy) - tmp.zy) <= epsilon);
+
+    tmp = X / Y;
+
+    //
+    // epsilon doesn't work here.
+    //
+    assert (std::fabs ((X.xy / Y.xy) - tmp.xy) <= 1e-5f &&
+            std::fabs ((X.xz / Y.xz) - tmp.xz) <= 1e-5f &&
+            std::fabs ((X.yz / Y.yz) - tmp.yz) <= 1e-5f &&
+            std::fabs ((X.yx / Y.yx) - tmp.yx) <= 1e-5f &&
+            std::fabs ((X.zx / Y.zx) - tmp.zx) <= 1e-5f &&
+            std::fabs ((X.zy / Y.zy) - tmp.zy) <= 1e-5f);
+
+    tmp = X;
+    tmp += Y;
+
+    assert (std::fabs ((X.xy + Y.xy) - tmp.xy) <= epsilon &&
+            std::fabs ((X.xz + Y.xz) - tmp.xz) <= epsilon &&
+            std::fabs ((X.yz + Y.yz) - tmp.yz) <= epsilon &&
+            std::fabs ((X.yx + Y.yx) - tmp.yx) <= epsilon &&
+            std::fabs ((X.zx + Y.zx) - tmp.zx) <= epsilon &&
+            std::fabs ((X.zy + Y.zy) - tmp.zy) <= epsilon);
+
+    tmp = X;
+    tmp -= Y;
+
+    assert (std::fabs ((X.xy - Y.xy) - tmp.xy) <= epsilon &&
+            std::fabs ((X.xz - Y.xz) - tmp.xz) <= epsilon &&
+            std::fabs ((X.yz - Y.yz) - tmp.yz) <= epsilon &&
+            std::fabs ((X.yx - Y.yx) - tmp.yx) <= epsilon &&
+            std::fabs ((X.xz - Y.xz) - tmp.xz) <= epsilon &&
+            std::fabs ((X.yz - Y.yz) - tmp.yz) <= epsilon);
+
+    tmp = X;
+    tmp *= Y;
+
+    assert (std::fabs ((X.xy * Y.xy) - tmp.xy) <= epsilon &&
+            std::fabs ((X.xz * Y.xz) - tmp.xz) <= epsilon &&
+            std::fabs ((X.yz * Y.yz) - tmp.yz) <= epsilon &&
+            std::fabs ((X.yx * Y.yx) - tmp.yx) <= epsilon &&
+            std::fabs ((X.zx * Y.zx) - tmp.zx) <= epsilon &&
+            std::fabs ((X.zy * Y.zy) - tmp.zy) <= epsilon);
+
+    tmp = X;
+    tmp /= Y;
+
+    //
+    // epsilon doesn't work here.
+    //
+    assert (std::fabs ((X.xy / Y.xy) - tmp.xy) <= 1e-5f &&
+            std::fabs ((X.xz / Y.xz) - tmp.xz) <= 1e-5f &&
+            std::fabs ((X.yz / Y.yz) - tmp.yz) <= 1e-5f &&
+            std::fabs ((X.yx / Y.yx) - tmp.yx) <= 1e-5f &&
+            std::fabs ((X.zx / Y.zx) - tmp.zx) <= 1e-5f &&
+            std::fabs ((X.zy / Y.zy) - tmp.zy) <= 1e-5f);
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testShear.h b/src/ImathTest/testShear.h
new file mode 100644 (file)
index 0000000..ab3435d
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testShear();
diff --git a/src/ImathTest/testSize.cpp b/src/ImathTest/testSize.cpp
new file mode 100644 (file)
index 0000000..c57ed78
--- /dev/null
@@ -0,0 +1,34 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include "half.h"
+#include <assert.h>
+#include <iostream>
+#include <stddef.h>
+#include "testSize.h"
+
+using namespace std;
+
+void
+testSize()
+{
+    cout << "size and alignment\n";
+
+    half h[2];
+
+    int size       = sizeof (half);
+    ptrdiff_t algn = (char*) &h[1] - (char*) &h[0];
+
+    cout << "sizeof  (half) = " << size << endl;
+    cout << "alignof (half) = " << (int) algn << endl;
+
+    assert (size == 2 && algn == 2);
+
+    cout << "ok\n\n" << flush;
+}
diff --git a/src/ImathTest/testSize.h b/src/ImathTest/testSize.h
new file mode 100644 (file)
index 0000000..53cc512
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testSize();
diff --git a/src/ImathTest/testTinySVD.cpp b/src/ImathTest/testTinySVD.cpp
new file mode 100644 (file)
index 0000000..b2f1911
--- /dev/null
@@ -0,0 +1,393 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathMatrixAlgo.h>
+#include <algorithm>
+#include <assert.h>
+#include <cmath>
+#include <iostream>
+#include <limits>
+
+template <typename T>
+void
+verifyOrthonormal (const IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A)
+{
+    const T valueEps = T (100) * std::numeric_limits<T>::epsilon();
+
+    const IMATH_INTERNAL_NAMESPACE::Matrix33<T> prod = A * A.transposed();
+    for (int i = 0; i < 3; ++i)
+    {
+        for (int j = 0; j < 3; ++j)
+        {
+            if (i == j)
+                assert (std::abs (prod[i][j] - 1) < valueEps);
+            else
+                assert (std::abs (prod[i][j]) < valueEps);
+        }
+    }
+}
+
+template <typename T>
+void
+verifyOrthonormal (const IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A)
+{
+    const T valueEps = T (100) * std::numeric_limits<T>::epsilon();
+
+    const IMATH_INTERNAL_NAMESPACE::Matrix44<T> prod = A * A.transposed();
+    for (int i = 0; i < 4; ++i)
+    {
+        for (int j = 0; j < 4; ++j)
+        {
+            if (i == j)
+                assert (std::abs (prod[i][j] - 1) <= valueEps);
+            else
+                assert (std::abs (prod[i][j]) <= valueEps);
+        }
+    }
+}
+
+template <typename T>
+void
+verifyTinySVD_3x3 (const IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A)
+{
+    T maxEntry = 0;
+    for (int i = 0; i < 3; ++i)
+        for (int j = 0; j < 3; ++j)
+            maxEntry = std::max (maxEntry, std::abs (A[i][j]));
+
+    const T eps      = std::numeric_limits<T>::epsilon();
+    const T valueEps = maxEntry * T (10) * eps;
+
+    for (int i = 0; i < 2; ++i)
+    {
+        const bool posDet = (i == 0);
+
+        IMATH_INTERNAL_NAMESPACE::Matrix33<T> U, V;
+        IMATH_INTERNAL_NAMESPACE::Vec3<T> S;
+        IMATH_INTERNAL_NAMESPACE::jacobiSVD (A, U, S, V, eps, posDet);
+
+        IMATH_INTERNAL_NAMESPACE::Matrix33<T> S_times_Vt;
+        for (int i = 0; i < 3; ++i)
+            for (int j = 0; j < 3; ++j)
+                S_times_Vt[i][j] = S[j] * V[i][j];
+        S_times_Vt.transpose();
+
+        // Verify that the product of the matrices is A:
+        const IMATH_INTERNAL_NAMESPACE::Matrix33<T> product = U * S_times_Vt;
+        for (int i = 0; i < 3; ++i)
+            for (int j = 0; j < 3; ++j)
+                assert (std::abs (product[i][j] - A[i][j]) <= valueEps);
+
+        // Verify that U and V are orthogonal:
+        if (posDet)
+        {
+            assert (U.determinant() > 0.9);
+            assert (V.determinant() > 0.9);
+        }
+
+        // Verify that the singular values are sorted:
+        for (int i = 0; i < 2; ++i)
+            assert (S[i] >= S[i + 1]);
+
+        // Verify that all the SVs except maybe the last one are positive:
+        for (int i = 0; i < 2; ++i)
+            assert (S[i] >= T (0));
+
+        if (!posDet)
+            assert (S[2] >= T (0));
+
+        verifyOrthonormal (U);
+        verifyOrthonormal (V);
+    }
+}
+
+template <typename T>
+void
+verifyTinySVD_4x4 (const IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A)
+{
+    T maxEntry = 0;
+    for (int i = 0; i < 4; ++i)
+        for (int j = 0; j < 4; ++j)
+            maxEntry = std::max (maxEntry, std::abs (A[i][j]));
+
+    const T eps      = std::numeric_limits<T>::epsilon();
+    const T valueEps = maxEntry * T (100) * eps;
+
+    for (int i = 0; i < 2; ++i)
+    {
+        const bool posDet = (i == 0);
+
+        IMATH_INTERNAL_NAMESPACE::Matrix44<T> U, V;
+        IMATH_INTERNAL_NAMESPACE::Vec4<T> S;
+        IMATH_INTERNAL_NAMESPACE::jacobiSVD (A, U, S, V, eps, posDet);
+
+        IMATH_INTERNAL_NAMESPACE::Matrix44<T> S_times_Vt;
+        for (int i = 0; i < 4; ++i)
+            for (int j = 0; j < 4; ++j)
+                S_times_Vt[i][j] = S[j] * V[i][j];
+        S_times_Vt.transpose();
+
+        // Verify that the product of the matrices is A:
+        const IMATH_INTERNAL_NAMESPACE::Matrix44<T> product = U * S_times_Vt;
+        for (int i = 0; i < 4; ++i)
+            for (int j = 0; j < 4; ++j)
+                assert (std::abs (product[i][j] - A[i][j]) <= valueEps);
+
+        // Verify that U and V have positive determinant if requested:
+        if (posDet)
+        {
+            assert (U.determinant() > 0.99);
+            assert (V.determinant() > 0.99);
+        }
+
+        // Verify that the singular values are sorted:
+        for (int i = 0; i < 3; ++i)
+            assert (S[i] >= S[i + 1]);
+
+        // Verify that all the SVs except maybe the last one are positive:
+        for (int i = 0; i < 3; ++i)
+            assert (S[i] >= T (0));
+
+        if (!posDet)
+            assert (S[3] >= T (0));
+
+        verifyOrthonormal (U);
+        verifyOrthonormal (V);
+    }
+}
+
+template <typename T>
+void
+testTinySVD_3x3 (const IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A)
+{
+    std::cout << "Verifying SVD for [[" << A[0][0] << ", " << A[0][1] << ", " << A[0][2] << "], "
+              << "[" << A[1][0] << ", " << A[1][1] << ", " << A[1][2] << "], "
+              << "[" << A[2][0] << ", " << A[2][1] << ", " << A[2][2] << "]]\n";
+
+    verifyTinySVD_3x3 (A);
+    verifyTinySVD_3x3 (A.transposed());
+
+    // Try all different orderings of the columns of A:
+    int cols[3] = { 0, 1, 2 };
+    do
+    {
+        IMATH_INTERNAL_NAMESPACE::Matrix33<T> B;
+        for (int i = 0; i < 3; ++i)
+            for (int j = 0; j < 3; ++j)
+                B[i][j] = A[i][cols[j]];
+
+        verifyTinySVD_3x3 (B);
+    } while (std::next_permutation (cols, cols + 3));
+}
+
+template <typename T>
+void
+testTinySVD_3x3 (const T a,
+                 const T b,
+                 const T c,
+                 const T d,
+                 const T e,
+                 const T f,
+                 const T g,
+                 const T h,
+                 const T i)
+{
+    const IMATH_INTERNAL_NAMESPACE::Matrix33<T> A (a, b, c, d, e, f, g, h, i);
+    testTinySVD_3x3 (A);
+}
+
+template <typename T>
+void
+testTinySVD_4x4 (const IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A)
+{
+    std::cout << "Verifying SVD for [[" << A[0][0] << ", " << A[0][1] << ", " << A[0][2] << ", "
+              << A[0][3] << "], "
+              << "[" << A[1][0] << ", " << A[1][1] << ", " << A[1][2] << ", " << A[1][3] << "], "
+              << "[" << A[2][0] << ", " << A[2][1] << ", " << A[2][2] << ", " << A[2][3] << "], "
+              << "[" << A[3][0] << ", " << A[3][1] << ", " << A[3][2] << ", " << A[3][3] << "]]\n";
+
+    verifyTinySVD_4x4 (A);
+    verifyTinySVD_4x4 (A.transposed());
+
+    // Try all different orderings of the columns of A:
+    int cols[4] = { 0, 1, 2, 3 };
+    do
+    {
+        IMATH_INTERNAL_NAMESPACE::Matrix44<T> B;
+        for (int i = 0; i < 4; ++i)
+            for (int j = 0; j < 4; ++j)
+                B[i][j] = A[i][cols[j]];
+
+        verifyTinySVD_4x4 (B);
+    } while (std::next_permutation (cols, cols + 4));
+}
+
+template <typename T>
+void
+testTinySVD_4x4 (const T a,
+                 const T b,
+                 const T c,
+                 const T d,
+                 const T e,
+                 const T f,
+                 const T g,
+                 const T h,
+                 const T i,
+                 const T j,
+                 const T k,
+                 const T l,
+                 const T m,
+                 const T n,
+                 const T o,
+                 const T p)
+{
+    const IMATH_INTERNAL_NAMESPACE::Matrix44<T> A (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p);
+    testTinySVD_4x4 (A);
+}
+
+template <typename T>
+void
+testTinySVDImp()
+{
+    // Try a bunch of 3x3 matrices:
+    testTinySVD_3x3<T> (1, 0, 0, 0, 1, 0, 0, 0, 1);
+    testTinySVD_3x3<T> (1, 0, 0, 0, -1, 0, 0, 0, 1);
+    testTinySVD_3x3<T> (0, 0, 0, 0, 0, 0, 0, 0, 0);
+    testTinySVD_3x3<T> (0, 0, 0, 0, 0, 0, 0, 0, 1);
+    testTinySVD_3x3<T> (1, 0, 0, 0, 1, 0, 0, 0, 0);
+    testTinySVD_3x3<T> (1, 0, 0, 0, 0, 0, 0, 0, 0);
+    testTinySVD_3x3<T> (1, 0, 0, T(1e-10), 0, 0, 0, 0, 0);
+    testTinySVD_3x3<T> (1, 0, 0, T(1e-10), 0, 0, 0, 0, 100000);
+    testTinySVD_3x3<T> (1, 2, 3, 4, 5, 6, 7, 8, 9);
+    testTinySVD_3x3<T> (1, 2, 3, 4, 5, 6, 7, 8, 9);
+    testTinySVD_3x3<T> (outerProduct (
+        IMATH_INTERNAL_NAMESPACE::Vec3<T> (100, T(1e-5), 0),
+        IMATH_INTERNAL_NAMESPACE::Vec3<T> (100, T(1e-5), 0)));
+    testTinySVD_3x3<T> (outerProduct (
+        IMATH_INTERNAL_NAMESPACE::Vec3<T> (245, 20, 1),
+        IMATH_INTERNAL_NAMESPACE::Vec3<T> (256, 300, 20)));
+    testTinySVD_3x3<T> (
+        outerProduct (
+            IMATH_INTERNAL_NAMESPACE::Vec3<T> (245, 20, 1),
+            IMATH_INTERNAL_NAMESPACE::Vec3<T> (245, 20, 1)) +
+        outerProduct (
+            IMATH_INTERNAL_NAMESPACE::Vec3<T> (1, 2, 3),
+            IMATH_INTERNAL_NAMESPACE::Vec3<T> (1, 2, 3)));
+
+    // Some problematic matrices from SVDTest:
+    testTinySVD_3x3<T> (
+        T(0.0023588321752040036),
+        T(-0.0096558131480729038),
+        T(0.0010959850449366493),
+        T(0.0088671829608044754),
+        T(0.0016771794267033666),
+        T(-0.0043081475729438235),
+        T(0.003976050440932701),
+        T(0.0019880497026345716),
+        T(0.0089576046614601966));
+    testTinySVD_3x3<T> (
+        T(2.3588321752040035e-09),
+        T(-9.6558131480729038e-09),
+        T(1.0959850449366498e-09),
+        T(8.8671829608044748e-09),
+        T(1.6771794267033661e-09),
+        T(-4.3081475729438225e-09),
+        T(3.9760504409327016e-09),
+        T(1.9880497026345722e-09),
+        T(8.9576046614601957e-09));
+    testTinySVD_3x3<T> (
+        T(-0.46673855799602715),
+        T(0.67466260360310948),
+        T(0.97646986796448998),
+        T(-0.032460753747103721),
+        T(0.046584527749418278),
+        T(0.067431228641151142),
+        T(-0.088885055229687815),
+        T(0.1280389179308779),
+        T(0.18532617511453064));
+    testTinySVD_3x3<T> (T(1e-8), 0, 0, 0, T(1e-8), 0, 0, 0, T(1e-8));
+    testTinySVD_3x3<T> (1, 0, 0, 0, T(.00036), 0, T(1e-18), 0, T(.00018));
+    testTinySVD_3x3<T> (T(1.3), 0, 0, 0, T(.0003), 0, T(1e-17), 0, 0);
+    testTinySVD_3x3<T> (1, 0, 0, 0, T(1e-2), 0, 0, 0, T(1e-2));
+    testTinySVD_3x3<T> (1, 0, 0, 0, 1, 0, 0, 0, 0);
+    testTinySVD_3x3<T> (1, 0, 0, 0, T(1e-3), 0, 0, 0, T(1e-6));
+    testTinySVD_3x3<T> (
+        T(0.59588638570136332),
+        T(-0.79761234126107794),
+        -1,
+        T(0.39194500425202045),
+        T(0.91763115383440363),
+        T(-0.341818175044664),
+        T(-0.45056075218951946),
+        T(-0.71259057727425101),
+        T(0.47125008216720271));
+    testTinySVD_3x3<T> (
+        T(4.38805348e-09),
+        T(-2.53189691e-09),
+        T(-4.65678607e-09),
+        T(-3.23000099e-10),
+        T(1.86370294e-10),
+        T(3.42781192e-10),
+        T(-4.61572824e-09),
+        T(2.6632645e-09),
+        T(4.89840346e-09));
+    // problematic 2x2 one for lapack on suse (see below), padded with 0's
+    testTinySVD_3x3<T> (0, T(-1.00000003e-22), 0, T(1.00000001e-07), 0, 0, 0, 0, 0);
+    // problematic 2x2 one for lapack on suse (see below), padded with 0's and 1
+    testTinySVD_3x3<T> (0, T(-1.00000003e-22), 0, T(1.00000001e-07), 0, 0, 0, 0, 1);
+
+    // Now, 4x4 matrices:
+    testTinySVD_4x4<T> (1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+    testTinySVD_4x4<T> (1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+    testTinySVD_4x4<T> (1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);
+    testTinySVD_4x4<T> (1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+    testTinySVD_4x4<T> (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+    testTinySVD_4x4<T> (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+    testTinySVD_4x4<T> (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
+    testTinySVD_4x4<T> (
+        0,
+        T(-1.00000003e-22),
+        0,
+        0,
+        T(00000001e-07),
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+        1);
+    testTinySVD_4x4<T> (outerProduct (
+        IMATH_INTERNAL_NAMESPACE::Vec4<T> (100, T(1e-5), 0, 0),
+        IMATH_INTERNAL_NAMESPACE::Vec4<T> (100, T(1e-5), 0, 0)));
+    testTinySVD_4x4<T> (outerProduct (
+        IMATH_INTERNAL_NAMESPACE::Vec4<T> (245, 20, 1, T(0.5)),
+        IMATH_INTERNAL_NAMESPACE::Vec4<T> (256, 300, 20, 10)));
+    testTinySVD_4x4<T> (
+        outerProduct (
+            IMATH_INTERNAL_NAMESPACE::Vec4<T> (245, 20, 1, T(0.5)),
+            IMATH_INTERNAL_NAMESPACE::Vec4<T> (256, 300, 20, 10)) +
+        outerProduct (
+            IMATH_INTERNAL_NAMESPACE::Vec4<T> (30, 10, 10, 10),
+            IMATH_INTERNAL_NAMESPACE::Vec4<T> (1, 2, 3, 3)));
+}
+
+void
+testTinySVD()
+{
+    std::cout << "Testing TinySVD algorithms in single precision..." << std::endl;
+    testTinySVDImp<float>();
+
+    std::cout << "Testing TinySVD algorithms in double precision..." << std::endl;
+    testTinySVDImp<double>();
+}
diff --git a/src/ImathTest/testTinySVD.h b/src/ImathTest/testTinySVD.h
new file mode 100644 (file)
index 0000000..c600d32
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testTinySVD();
diff --git a/src/ImathTest/testToFloat.cpp b/src/ImathTest/testToFloat.cpp
new file mode 100644 (file)
index 0000000..7bcb33a
--- /dev/null
@@ -0,0 +1,159 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <assert.h>
+#include <cmath>
+#include <half.h>
+#include <iomanip>
+#include <iostream>
+
+using namespace std;
+
+//
+// This test uses the code that generates the toFLoat.h header to
+// validate the the tabel values are correct.
+//
+
+//---------------------------------------------------
+// Interpret an unsigned short bit pattern as a half,
+// and convert that half to the corresponding float's
+// bit pattern.
+//---------------------------------------------------
+
+unsigned int
+halfToFloat (unsigned short y)
+{
+
+    int s = (y >> 15) & 0x00000001;
+    int e = (y >> 10) & 0x0000001f;
+    int m = y & 0x000003ff;
+
+    if (e == 0)
+    {
+        if (m == 0)
+        {
+            //
+            // Plus or minus zero
+            //
+
+            return s << 31;
+        }
+        else
+        {
+            //
+            // Denormalized number -- renormalize it
+            //
+
+            while (!(m & 0x00000400))
+            {
+                m <<= 1;
+                e -= 1;
+            }
+
+            e += 1;
+            m &= ~0x00000400;
+        }
+    }
+    else if (e == 31)
+    {
+        if (m == 0)
+        {
+            //
+            // Positive or negative infinity
+            //
+
+            return (s << 31) | 0x7f800000;
+        }
+        else
+        {
+            //
+            // Nan -- preserve sign and significand bits
+            //
+
+            return (s << 31) | 0x7f800000 | (m << 13);
+        }
+    }
+
+    //
+    // Normalized number
+    //
+
+    e = e + (127 - 15);
+    m = m << 13;
+
+    //
+    // Assemble s, e and m.
+    //
+
+    return (s << 31) | (e << 23) | m;
+}
+
+
+
+void
+testToFloat()
+{
+    std::cout << "running testToFloat" << std::endl;
+
+    constexpr int iMax = (1 << 16);
+
+    //
+    // for each 16-bit bit pattern...
+    //
+
+    for (unsigned int s = 0; s < iMax; s++)
+    {
+        half hs(half::FromBits, static_cast<unsigned short>(s));
+        assert (hs.bits() == s);
+
+        //
+        // cast these bits to a float, using the cast-to-float
+        // operator.
+        //
+
+        float f = float (hs); // = _toFloat[s]
+
+        //
+        // Cast that float back to a half.
+        //
+
+        half h = half (f);
+
+        //
+        // halfToFloat() above is what generated the _toFloat table.
+        // The i value return is the integer bit pattern of the corresponding
+        // float.
+        //
+
+        half::uif uif;
+        uif.i = halfToFloat (s);
+
+        //
+        // Equality operators fail for inf and nan, so handle them
+        // specially.
+        //
+
+        if (isnan (f))
+        {
+            assert (h.isNan());
+            assert (isnan (uif.f));
+        }
+        else if (isinf (f))
+        {
+            assert (h.isInfinity());
+            assert (isinf (uif.f));
+        }
+        else
+        {
+            assert (f == uif.f);
+        }
+    }
+
+    std::cout << "ok" << std::endl;
+}
diff --git a/src/ImathTest/testToFloat.h b/src/ImathTest/testToFloat.h
new file mode 100644 (file)
index 0000000..8b2ed74
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testToFloat();
diff --git a/src/ImathTest/testVec.cpp b/src/ImathTest/testVec.cpp
new file mode 100644 (file)
index 0000000..5bcab00
--- /dev/null
@@ -0,0 +1,258 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <ImathFun.h>
+#include <ImathVec.h>
+#include <cassert>
+#include <cmath>
+#include <iostream>
+#include "testVec.h"
+
+// Include ImathForward *after* other headers to validate forward declarations
+#include <ImathForward.h>
+
+using namespace std;
+using namespace IMATH_INTERNAL_NAMESPACE;
+
+namespace
+{
+
+template <class T>
+void
+testLength2T()
+{
+    const T s = std::sqrt (std::numeric_limits<T>::min());
+    const T e = 4 * std::numeric_limits<T>::epsilon();
+
+    Vec2<T> v;
+
+    v = Vec2<T> (0, 0);
+    assert (v.length() == 0);
+    assert (v.normalized().length() == 0);
+
+    v = Vec2<T> (3, 4);
+    assert (v.length() == 5);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    v = Vec2<T> (3000, 4000);
+    assert (v.length() == 5000);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    T t = s * (1 << 4);
+
+    v = Vec2<T> (t, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec2<T> (0, t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec2<T> (-t, -t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t * std::sqrt (2), t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    t = s / (1 << 4);
+
+    v = Vec2<T> (t, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec2<T> (0, t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec2<T> (-t, -t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t * std::sqrt (2), t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    t = s / (1 << 20);
+
+    v = Vec2<T> (t, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec2<T> (0, t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec2<T> (-t, -t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t * std::sqrt (2), t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+}
+
+template <class T>
+void
+testLength3T()
+{
+    const T s = std::sqrt (std::numeric_limits<T>::min());
+    const T e = 4 * std::numeric_limits<T>::epsilon();
+
+    Vec3<T> v;
+
+    v = Vec3<T> (0, 0, 0);
+    assert (v.length() == 0);
+    assert (v.normalized().length() == 0);
+
+    v = Vec3<T> (3, 4, 0);
+    assert (v.length() == 5);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    v = Vec3<T> (3000, 4000, 0);
+    assert (v.length() == 5000);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    v = Vec3<T> (1, -1, 1);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), 1 * std::sqrt (3), e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    v = Vec3<T> (1000, -1000, 1000);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), 1000 * std::sqrt (3), 1000 * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    T t = s * (1 << 4);
+
+    v = Vec3<T> (t, 0, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec3<T> (0, t, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec3<T> (0, 0, t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec3<T> (-t, -t, -t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t * std::sqrt (3), t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    t = s / (1 << 4);
+
+    v = Vec3<T> (t, 0, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec3<T> (0, t, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec3<T> (0, 0, t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec3<T> (-t, -t, -t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t * std::sqrt (3), t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    t = s / (1 << 20);
+
+    v = Vec3<T> (t, 0, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec3<T> (0, t, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec3<T> (0, 0, t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec3<T> (-t, -t, -t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t * std::sqrt (3), t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+}
+
+template <class T>
+void
+testLength4T()
+{
+    const T s = std::sqrt (std::numeric_limits<T>::min());
+    const T e = 4 * std::numeric_limits<T>::epsilon();
+
+    Vec4<T> v;
+
+    v = Vec4<T> (0, 0, 0, 0);
+    assert (v.length() == 0);
+    assert (v.normalized().length() == 0);
+
+    v = Vec4<T> (3, 4, 0, 0);
+    assert (v.length() == 5);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    v = Vec4<T> (3000, 4000, 0, 0);
+    assert (v.length() == 5000);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    v = Vec4<T> (1, -1, 1, 1);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), 2, e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    v = Vec4<T> (1000, -1000, 1000, 1000);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), 2000, 1000 * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    T t = s * (1 << 4);
+
+    v = Vec4<T> (t, 0, 0, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (0, t, 0, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (0, 0, t, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (0, 0, 0, t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (-t, -t, -t, -t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t * 2, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    t = s / (1 << 4);
+
+    v = Vec4<T> (t, 0, 0, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (0, t, 0, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (0, 0, t, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (0, 0, 0, t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (-t, -t, -t, -t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t * 2, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+
+    t = s / (1 << 20);
+
+    v = Vec4<T> (t, 0, 0, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (0, t, 0, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (0, 0, t, 0);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (0, 0, 0, t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+    v = Vec4<T> (-t, -t, -t, -t);
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.length(), t * 2, t * e));
+    assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized().length(), 1, e));
+}
+
+} // namespace
+
+void
+testVec()
+{
+    cout << "Testing some basic vector operations" << endl;
+
+    testLength2T<float>();
+    testLength2T<double>();
+    testLength3T<float>();
+    testLength3T<double>();
+    testLength4T<float>();
+    testLength4T<double>();
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/ImathTest/testVec.h b/src/ImathTest/testVec.h
new file mode 100644 (file)
index 0000000..652c142
--- /dev/null
@@ -0,0 +1,6 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+void testVec();
diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1bc1e54
--- /dev/null
@@ -0,0 +1,214 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+#######################################
+#######################################
+# This declares all the configuration variables visible
+# in cmake-gui or similar and the rest of the global
+# project setup
+#
+# Please look at this file to see what is configurable
+#######################################
+#######################################
+include(config/PyImathSetup.cmake)
+
+# we are building a python extension, so of course we depend on
+# python as well. Except we don't know which version...
+# cmake 3.14 can also search for numpy, but we only depend on 3.12
+# in the rest of OpenEXR right now...
+
+# first make sure we find *some* python
+find_package(Python COMPONENTS Interpreter Development)
+if(NOT TARGET Python::Interpreter AND NOT TARGET Python::Python)
+  message(WARNING "Unable to find any python interpreter or libraries, disabling PyImath")
+  return()
+endif()
+
+# we don't need cmake_dependant_option here, because the file is
+# included only if -DPYTHON=ON
+option(USE_PYTHON2 "Whether to use Python 2.x or 3.x" OFF)
+
+# now determine which (or both), and compile for both
+if(USE_PYTHON2)
+  find_package(Python2 COMPONENTS Interpreter Development)
+  if(Python2_FOUND)
+    message(STATUS "Found Python ${Python2_VERSION}")
+  elseif(Python2::Python)
+    message(WARNING "Found Python ${Python2_VERSION} development libraries, but no interpreter")
+  elseif(Python2::Interpreter)
+    message(WARNING "Found Python ${Python2_VERSION} interpreter, but no development libraries")
+  else()
+    message(WARNING "Unable to find Python2 interpreter or development libraries")
+  endif()
+  set(PY_MAJOR_VERSION ${Python2_VERSION_MAJOR})
+  set(Python_VERSION_MAJOR ${Python2_VERSION_MAJOR})
+  set(Python_VERSION_MINOR ${Python2_VERSION_MINOR})
+  set(Python_EXECUTABLE ${Python2_EXECUTABLE})
+  set(Python_SITEARCH ${Python2_SITEARCH})
+else()
+  find_package(Python3 COMPONENTS Interpreter Development)
+  if(Python3_FOUND)
+    message(STATUS "Found Python ${Python3_VERSION}")
+  elseif(Python3::Python)
+    message(WARNING "Found Python ${Python3_VERSION} development libraries, but no interpreter")
+  elseif(Python3::Interpreter)
+    message(WARNING "Found Python ${Python3_VERSION} interpreter, but no development libraries")
+  else()
+    message(WARNING "Unable to find Python3 interpreter or development libraries")
+  endif()
+  set(PY_MAJOR_VERSION ${Python3_VERSION_MAJOR})
+  set(Python_VERSION_MAJOR ${Python3_VERSION_MAJOR})
+  set(Python_VERSION_MINOR ${Python3_VERSION_MINOR})
+  set(Python_EXECUTABLE ${Python3_EXECUTABLE})
+  set(Python_SITEARCH ${Python3_SITEARCH})
+endif()
+
+if (NOT Python2_FOUND AND NOT Python3_FOUND)
+  message(WARNING "Disabling PyImath")
+  return()
+endif()
+
+# Now that we know what versions of python we have, let's look
+# for our other dependency - boost.
+# Boost Python has some .. annoyances in that the python module
+# has version names attached to it
+function(PYIMATH_EXTRACT_REL_SITEARCH varname pyver pyexe pysitearch)
+  if(PYIMATH_OVERRIDE_PYTHON_INSTALL_DIR)
+    set(${varname} ${PYIMATH_OVERRIDE_PYTHON_INSTALL_DIR} CACHE STRING "Destination sub-folder (relative) for the python ${pyver} modules")
+    message(STATUS "Will install to: ${PYIMATH_OVERRIDE_PYTHON_INSTALL_DIR}")
+  else()
+    get_filename_component(_exedir ${pyexe} DIRECTORY)
+    # we do this such that cmake will canonicalize the slashes
+    # so the directory search will work under windows and unix
+    # consistently
+    get_filename_component(_basedir ${pysitearch} DIRECTORY)
+    get_filename_component(_basename ${pysitearch} NAME)
+    set(_basedir "${_basedir}/${_basename}")
+    string(FIND ${_basedir} ${_exedir} _findloc)
+    string(LENGTH ${_exedir} _elen)
+    while(_findloc EQUAL -1 AND _elen GREATER 0)
+      get_filename_component(_nexedir ${_exedir} DIRECTORY)
+      string(FIND ${_basedir} ${_nexedir} _findloc)
+      if (_nexedir STREQUAL _exedir)
+          message(WARNING "Unable to get parent directory for ${_exedir}, using absolute python site arch folder ${pysitearch}")
+          set(_elen -1)
+          break()
+      else()
+          set(_exedir ${_nexedir})
+      endif()
+      string(LENGTH ${_exedir} _elen)
+    endwhile()
+    math(EXPR _elen "${_elen}+1")
+    string(SUBSTRING ${_basedir} ${_elen} -1 _reldir)
+    if(APPLE)
+      # on macOS, set install path to user's python package directory
+      # so that elevated privileges are not necessary
+      execute_process(
+        COMMAND "${pyexe}" -c "if True:
+          import sysconfig
+          print(sysconfig.get_path('platlib', 'posix_user'))"
+        OUTPUT_VARIABLE _reldir
+        OUTPUT_STRIP_TRAILING_WHITESPACE)
+    endif()
+    set(${varname} ${_reldir} CACHE STRING "Destination sub-folder (relative) for the python ${pyver} modules")
+    message(STATUS "Will install to: ${_reldir}")
+  endif()
+endfunction()
+
+set(PYIMATH_BOOST_PY_COMPONENT "python${Python_VERSION_MAJOR}${Python_VERSION_MINOR}")
+message(STATUS "Found Python${Python_VERSION_MAJOR} libraries: ${Python_VERSION_MAJOR}${Python_VERSION_MINOR}")
+# we can't just use the Python2_SITEARCH variable as that then will
+# ignore CMAKE_INSTALL_PREFIX. Could extract this to a function somewhere
+# if it is generally useful
+pyimath_extract_rel_sitearch(PyImath_Python${Python_VERSION_MAJOR}_SITEARCH_REL ${Python_VERSION_MAJOR} ${Python_EXECUTABLE} ${Python_SITEARCH})
+
+# different flavors of O.S. have multiple versions of python
+# some of them have both. Then for boost, some versions of boost
+# have just a python component, some it's by major version (python2/python3)
+# and still others have maj/min (python27)
+# let's run a search and see what we get instead of making it
+# an explicit required. The older names are not portable, but
+# we'll do the best we can
+
+### NB: We are turning this on globally by default as the boost
+###     generated cmake config files seem to be broken and they
+###     cross-wire python 2 with 3 in the same variables
+option(Boost_NO_BOOST_CMAKE "Disable boost-provided cmake config" ON)
+if(Boost_NO_BOOST_CMAKE)
+  message(STATUS "Disabling boost-provided cmake config. If this causes problems, consider setting Boost_NO_BOOST_CMAKE variable to OFF")
+endif()
+
+find_package(Boost OPTIONAL_COMPONENTS
+  python
+  python${Python_VERSION_MAJOR}
+  ${PYIMATH_BOOST_PY_COMPONENT})
+set(_pyimath_have_perver_boost)
+if(PYIMATH_BOOST_PY_COMPONENT)
+  string(TOUPPER ${PYIMATH_BOOST_PY_COMPONENT} PYIMATH_PY_UPPER)
+else()
+  set(PYIMATH_BOOST_PY_COMPONENT python${Python_VERSION_MAJOR}x_NOTFOUND)
+  set(PYIMATH_PY_UPPER PYTHON${Python_VERSION_MAJOR}X_NOTFOUND)
+endif()
+if(Boost_PYTHON${Python_VERSION_MAJOR}_FOUND OR Boost_${PYIMATH_PY_UPPER}_FOUND)
+  set(_pyimath_have_perver_boost TRUE)
+  if(NOT Boost_${PYIMATH_PY_UPPER}_FOUND)
+    message(WARNING "Legacy Boost python${Python_VERSION_MAJOR} found, but does not include minor version, this is an old configuration and may not be portable")
+    set(PYIMATH_BOOST_PY_COMPONENT python${Python_VERSION_MAJOR})
+  endif()
+endif()
+
+if(Boost_PYTHON_FOUND AND NOT _pyimath_have_perver_boost)
+  # old boost case, I guess we just warn and assume it is python2 (likely)
+  message(WARNING "Ambiguous boost python module found, assuming python ${Python_VERSION_MAJOR}. If you have a new boost library, try cleaning the cmake cache and reconfigure with -DBoost_NO_BOOST_CMAKE=ON")
+  set(PYIMATH_BOOST_PY_COMPONENT python)
+  # set it to a bogus string but not empty so later we don't test against a namespace only target
+#  set(PYIMATH_BOOST_PY3_COMPONENT pythonIgnore)
+elseif(NOT _pyimath_have_perver_boost)
+  message(WARNING "Unable to find boost::python library, disabling PyImath. If you believe this is wrong, check the cmake documentation and see if you need to set Boost_ROOT or Boost_NO_BOOST_CMAKE")
+  return()
+else()
+  if(TARGET Boost::${PYIMATH_BOOST_PY_COMPONENT})
+    message(STATUS "Found Python ${Python_VERSION_MAJOR} boost: Boost::${PYIMATH_BOOST_PY_COMPONENT}")
+  elseif(Boost_PYTHON_FOUND OR Boost_${PYIMATH_PY_UPPER}_FOUND)
+    message(WARNING "Found boost for python ${Python_VERSION_MAJOR}, but FindBoost did not create an import library. If you believe this is wrong, check the cmake documentation and see if you need to set Boost_ROOT or Boost_NO_BOOST_CMAKE")
+    return()
+  endif()
+endif()
+unset(PYIMATH_PY_UPPER)
+unset(_pyimath_have_perver_boost)
+
+# unfortunately, we can't use the boost numpy stuff, as that requires a
+# version of boost that is newer than is mandated by many active versions
+# of the VFX reference platform (numpy became active in 1.63 of boost).
+# rather than make this an "official" find package thing
+include(config/NumPyLocate.cmake)
+
+
+# utility function for the repeated boilerplate of defining
+# the libraries and/or python modules
+include(config/ModuleDefine.cmake)
+
+##########################
+add_subdirectory(config)
+
+if(NOT BUILD_SHARED_LIBS)
+  message(WARNING "Forcing python bindings to be built with dynamic libraries")
+endif()
+
+add_subdirectory( PyImath )
+if(TARGET Python2::ImathNumPy OR TARGET Python3::ImathNumPy)
+  add_subdirectory( PyImathNumpy )
+endif()
+
+##########################
+# Tests
+##########################
+include(CTest)
+if(BUILD_TESTING)
+  enable_testing()
+  add_subdirectory( PyImathTest )
+  add_subdirectory( PyImathSpeedTest )
+  if(TARGET Python2::ImathNumPy OR TARGET Python3::ImathNumPy)
+    add_subdirectory( PyImathNumpyTest )
+  endif()
+endif()
diff --git a/src/python/PyImath.pc.in b/src/python/PyImath.pc.in
new file mode 100644 (file)
index 0000000..8e8de6f
--- /dev/null
@@ -0,0 +1,16 @@
+##
+## SPDX-License-Identifier: BSD-3-Clause
+## Copyright Contributors to the OpenEXR Project.
+##
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+libsuffix=@LIB_SUFFIX_DASH@
+
+Name: PyImath
+Description: Python bindings for the Imath libraries
+Version: @IMATH_VERSION@
+Libs: -L${libdir} -lImath${libsuffix} -lPyImath@PYIMATH_LIB_PYTHONVER_ROOT@@Python_VERSION_MAJOR@_@Python_VERSION_MINOR@${libsuffix}
+Cflags: -I${includedir} -I${includedir}/Imath
diff --git a/src/python/PyImath/CMakeLists.txt b/src/python/PyImath/CMakeLists.txt
new file mode 100644 (file)
index 0000000..df8adbc
--- /dev/null
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+pyimath_define_module(imath
+  LIBNAME PyImath
+  PRIV_EXPORT PYIMATH_BUILD
+  CURDIR ${CMAKE_CURRENT_SOURCE_DIR}
+  LIBSOURCE
+    PyImath.cpp
+    PyImathAutovectorize.cpp
+    PyImathBox2Array.cpp
+    PyImathBox3Array.cpp
+    PyImathBox.cpp
+    PyImathBufferProtocol.cpp
+    PyImathColor3.cpp
+    PyImathColor4.cpp
+    PyImathEuler.cpp
+    PyImathFixedArray.cpp
+    PyImathFrustum.cpp
+    PyImathLine.cpp
+    PyImathMatrix22.cpp
+    PyImathMatrix33.cpp
+    PyImathMatrix44.cpp
+    PyImathPlane.cpp
+    PyImathQuat.cpp
+    PyImathRandom.cpp
+    PyImathShear.cpp
+    PyImathStringArray.cpp
+    PyImathStringTable.cpp
+    PyImathTask.cpp
+    PyImathUtil.cpp
+    PyImathFixedVArray.cpp
+    PyImathVec2fd.cpp
+    PyImathVec2si.cpp
+    PyImathVec3fd.cpp
+    PyImathVec3siArray.cpp
+    PyImathVec3si.cpp
+    PyImathVec4fd.cpp
+    PyImathVec4siArray.cpp
+    PyImathVec4si.cpp
+  MODSOURCE
+    imathmodule.cpp
+    PyImathFun.cpp
+    PyImathBasicTypes.cpp
+  HEADERS
+    PyImath.h
+    PyImathAPI.h
+    PyImathAutovectorize.h
+    PyImathBasicTypes.h
+    PyImathBox.h
+    PyImathBoxArrayImpl.h
+    PyImathBufferProtocol.h
+    PyImathColor.h
+    PyImathColor3ArrayImpl.h
+    PyImathColor4Array2DImpl.h
+    PyImathColor4ArrayImpl.h
+    PyImathDecorators.h
+    PyImathEuler.h
+    PyImathExport.h
+    PyImathFixedArray.h
+    PyImathFixedArray2D.h
+    PyImathFixedArrayTraits.h
+    PyImathFixedMatrix.h
+    PyImathFixedVArray.h
+    PyImathFrustum.h
+    PyImathFun.h
+    PyImathLine.h
+    PyImathMathExc.h
+    PyImathMatrix.h
+    PyImathOperators.h
+    PyImathPlane.h
+    PyImathQuat.h
+    PyImathQuatOperators.h
+    PyImathRandom.h
+    PyImathShear.h
+    PyImathStringArray.h
+    PyImathStringArrayRegister.h
+    PyImathStringTable.h
+    PyImathTask.h
+    PyImathUtil.h
+    PyImathVec.h
+    PyImathVec2Impl.h
+    PyImathVec3ArrayImpl.h
+    PyImathVec3Impl.h
+    PyImathVec4ArrayImpl.h
+    PyImathVec4Impl.h
+    PyImathVecOperators.h
+  DEPENDENCIES
+    Imath
+  )
diff --git a/src/python/PyImath/PyImath.cpp b/src/python/PyImath/PyImath.cpp
new file mode 100644 (file)
index 0000000..23fab37
--- /dev/null
@@ -0,0 +1,27 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImath.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+
+template <> PYIMATH_EXPORT const char * BoolArray::name()         { return "BoolArray"; }
+template <> PYIMATH_EXPORT const char * SignedCharArray::name()   { return "SignedCharArray"; }
+template <> PYIMATH_EXPORT const char * UnsignedCharArray::name() { return "UnsignedCharArray"; }
+template <> PYIMATH_EXPORT const char * ShortArray::name()        { return "ShortArray"; }
+template <> PYIMATH_EXPORT const char * UnsignedShortArray::name(){ return "UnsignedShortArray"; }
+template <> PYIMATH_EXPORT const char * IntArray::name()          { return "IntArray"; }
+template <> PYIMATH_EXPORT const char * UnsignedIntArray::name()  { return "UnsignedIntArray"; }
+template <> PYIMATH_EXPORT const char * FloatArray::name()        { return "FloatArray"; }
+template <> PYIMATH_EXPORT const char * DoubleArray::name()       { return "DoubleArray"; }
+template <> PYIMATH_EXPORT const char * VIntArray::name()         { return "VIntArray"; }
+template <> PYIMATH_EXPORT const char * VFloatArray::name()       { return "VFloatArray"; }
+template <> PYIMATH_EXPORT const char * VV2iArray::name()         { return "VV2iArray"; }
+template <> PYIMATH_EXPORT const char * VV2fArray::name()         { return "VV2fArray"; }
+
+}
diff --git a/src/python/PyImath/PyImath.h b/src/python/PyImath/PyImath.h
new file mode 100644 (file)
index 0000000..38ba488
--- /dev/null
@@ -0,0 +1,49 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImath_h_
+#define _PyImath_h_
+
+#include <ImathVec.h>
+#include <ImathQuat.h>
+#include <PyImathAPI.h>
+#include "PyImathFixedArray.h"
+#include "PyImathFixedMatrix.h"
+#include "PyImathFixedArray2D.h"
+#include "PyImathFixedVArray.h"
+
+namespace PyImath {
+
+typedef FixedArray<bool> BoolArray;
+typedef FixedArray<signed char> SignedCharArray;
+typedef FixedArray<unsigned char> UnsignedCharArray;
+typedef FixedArray<short> ShortArray;
+typedef FixedArray<unsigned short> UnsignedShortArray;
+typedef FixedArray<int> IntArray;
+typedef FixedArray<unsigned int> UnsignedIntArray;
+typedef FixedArray<float> FloatArray;
+typedef FixedArray<double> DoubleArray;
+
+typedef FixedArray<IMATH_NAMESPACE::Quatf> QuatfArray;
+typedef FixedArray<IMATH_NAMESPACE::Quatd> QuatdArray;
+
+typedef FixedMatrix<int> IntMatrix;
+typedef FixedMatrix<float> FloatMatrix;
+typedef FixedMatrix<double> DoubleMatrix;
+
+typedef FixedArray2D<float> FloatArray2D;
+typedef FixedArray2D<int> IntArray2D;
+typedef FixedArray2D<double> DoubleArray2D;
+
+typedef FixedVArray<int> VIntArray;
+typedef FixedVArray<float> VFloatArray;
+typedef FixedVArray<Imath::Vec2<int> > VV2iArray;
+typedef FixedVArray<Imath::Vec2<float> > VV2fArray;
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathAPI.h b/src/python/PyImath/PyImathAPI.h
new file mode 100644 (file)
index 0000000..9da24ec
--- /dev/null
@@ -0,0 +1,60 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathAPI_h_
+#define _PyImathAPI_h_
+
+#include <patchlevel.h>
+
+#if PY_MAJOR_VERSION >= 3
+
+  //  Big changes in Python3 with regard to PyClass.  Most of these functions
+  // are gone so the equivalent functionality is done this way...
+  #define  PyClass_Check(object) \
+           PyObject_IsInstance (object, reinterpret_cast<PyObject *> (&PyType_Type))
+
+  //  Py_FindMethod is gone and so you must search for functions by searching
+  // through an object's attributes.
+  #define  Py_FindMethod(methods, self, name) \
+           PyObject_GenericGetAttr(self, PyBytes_FromString(name))
+
+  //  One of the biggest differences between 2&3 is use support for Unicode.
+  // Working with strings at the C API level one has be careful that the
+  // returned object will not be Unicode and thus need to be decoded before
+  // being interpreted.  These macros will return the PyBytes type of PyObject
+  // pointer that replaces PyString.
+  #define  PyString_Check(str)                     PyBytes_Check(str)
+  #define  PyString_FromString(str)                PyBytes_FromString(str)  
+  #define  PyString_AsString(obj)                  PyBytes_AsString(obj)  
+  #define  PyString_AsStringAndSize(obj, str, len) PyBytes_AsStringAndSize(obj, str, len)
+
+  //  Python3 interprets all integers as long types and has deprecated PyInt.
+  #define  PyInt_Check(x)            PyLong_Check(x)
+  #define  PyInt_AsLong(x)           PyLong_AsLong(x)
+  #define  PyInt_AS_LONG(x)          PyLong_AsLong(x)
+  #define  PyInt_AsSsize_t(x)        PyLong_AsSsize_t(x)
+  #define  PyInt_FromLong(x)         PyLong_FromLong(x)
+
+  //  These flags are not present in Python3 and must be replaced with the
+  // default set of flags so that OR'ing them together doesn't alter the
+  // flags.
+  #define  Py_TPFLAGS_CHECKTYPES         Py_TPFLAGS_DEFAULT
+  #define  Py_TPFLAGS_HAVE_RICHCOMPARE   Py_TPFLAGS_DEFAULT
+
+  //  The __repr__ for a TypeObject will be encoded and needs to be
+  // processed as a PyBytes object before it can be return as a string.
+  #define  PYUTIL_OBJECT_REPR(obj)       PyObject_Str (PyObject_Repr (obj))
+
+#else
+
+  //  Python2 code will need to access PyObject_Repr() via this macro so
+  // that both 2&3 can compile without modification.
+  #define  PYUTIL_OBJECT_REPR(obj)      PyObject_Repr (obj)
+
+#endif
+
+#endif  // _PyImathAPI_h_
diff --git a/src/python/PyImath/PyImathAutovectorize.cpp b/src/python/PyImath/PyImathAutovectorize.cpp
new file mode 100644 (file)
index 0000000..9699e63
--- /dev/null
@@ -0,0 +1,90 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathAutovectorize.h"
+
+
+namespace PyImath {
+
+namespace detail {
+//
+// cheek possible vectorizations to ensure correctness
+//
+// single argument should be ((false),(true))
+//
+BOOST_STATIC_ASSERT(( size<possible_vectorizations<1>::type>::type::value == 2 ));
+BOOST_STATIC_ASSERT(( size<at_c<possible_vectorizations<1>::type,0>::type>::type::value == 1 ));
+BOOST_STATIC_ASSERT(( at_c<at_c<possible_vectorizations<1>::type,0>::type,0>::type::value == false ));
+BOOST_STATIC_ASSERT(( size<at_c<possible_vectorizations<1>::type,1>::type>::type::value == 1 ));
+BOOST_STATIC_ASSERT(( at_c<at_c<possible_vectorizations<1>::type,1>::type,0>::type::value == true ));
+
+//
+// two argument should be ((false,false),(false,true),(true,false),(true,true))
+//
+BOOST_STATIC_ASSERT(( size<possible_vectorizations<2>::type>::type::value == 4 ));
+BOOST_STATIC_ASSERT(( size<at_c<possible_vectorizations<2>::type,0>::type>::type::value == 2 ));
+BOOST_STATIC_ASSERT(( at_c<at_c<possible_vectorizations<2>::type,0>::type,0>::type::value == false ));
+BOOST_STATIC_ASSERT(( at_c<at_c<possible_vectorizations<2>::type,0>::type,1>::type::value == false ));
+BOOST_STATIC_ASSERT(( size<at_c<possible_vectorizations<2>::type,1>::type>::type::value == 2 ));
+BOOST_STATIC_ASSERT(( at_c<at_c<possible_vectorizations<2>::type,1>::type,0>::type::value == false ));
+BOOST_STATIC_ASSERT(( at_c<at_c<possible_vectorizations<2>::type,1>::type,1>::type::value == true ));
+BOOST_STATIC_ASSERT(( size<at_c<possible_vectorizations<2>::type,2>::type>::type::value == 2 ));
+BOOST_STATIC_ASSERT(( at_c<at_c<possible_vectorizations<2>::type,2>::type,0>::type::value == true ));
+BOOST_STATIC_ASSERT(( at_c<at_c<possible_vectorizations<2>::type,2>::type,1>::type::value == false ));
+BOOST_STATIC_ASSERT(( size<at_c<possible_vectorizations<2>::type,3>::type>::type::value == 2 ));
+BOOST_STATIC_ASSERT(( at_c<at_c<possible_vectorizations<2>::type,3>::type,0>::type::value == true ));
+BOOST_STATIC_ASSERT(( at_c<at_c<possible_vectorizations<2>::type,3>::type,1>::type::value == true ));
+BOOST_STATIC_ASSERT(( size<possible_vectorizations<3>::type>::type::value == 8 ));
+
+//
+// Check disallow_vectorization for given vectorizable flags
+//
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<true_ > >::apply<vector<true_ > >::type::value == false  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<true_ > >::apply<vector<false_> >::type::value == false  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<false_> >::apply<vector<true_ > >::type::value == true  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<false_> >::apply<vector<false_> >::type::value == false  ));
+
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<true_ , true_ > >::apply<vector<true_ , true_ > >::type::value == false  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<true_ , true_ > >::apply<vector<false_, true_ > >::type::value == false  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<true_ , true_ > >::apply<vector<true_ , false_> >::type::value == false  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<true_ , true_ > >::apply<vector<false_, false_> >::type::value == false  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<true_ , false_> >::apply<vector<true_ , true_ > >::type::value == true  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<true_ , false_> >::apply<vector<false_, true_ > >::type::value == true  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<true_ , false_> >::apply<vector<true_ , false_> >::type::value == false  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<true_ , false_> >::apply<vector<false_, false_> >::type::value == false  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<false_, true_ > >::apply<vector<true_ , true_ > >::type::value == true   ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<false_, true_ > >::apply<vector<false_, true_ > >::type::value == false  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<false_, true_ > >::apply<vector<true_ , false_> >::type::value == true  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<false_, true_ > >::apply<vector<false_, false_> >::type::value == false  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<false_, false_> >::apply<vector<true_ , true_ > >::type::value == true  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<false_, false_> >::apply<vector<false_, true_ > >::type::value == true  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<false_, false_> >::apply<vector<true_ , false_> >::type::value == true  ));
+BOOST_STATIC_ASSERT(( disallow_vectorization<vector<false_, false_> >::apply<vector<false_, false_> >::type::value == false  ));
+
+//
+// Check allowable_vectorizations, single argument not vectorizable, and two argument second argument vectorizable.
+//
+typedef allowable_vectorizations<vector<false_> > AV1f;
+BOOST_STATIC_ASSERT(( size<AV1f::possible>::type::value == 2 ));
+BOOST_STATIC_ASSERT(( at_c<at_c<AV1f::possible,0>::type,0>::type::value == false ));
+BOOST_STATIC_ASSERT(( at_c<at_c<AV1f::possible,1>::type,0>::type::value == true ));
+BOOST_STATIC_ASSERT(( size<AV1f::type>::type::value == 1 ));
+BOOST_STATIC_ASSERT(( size<at_c<AV1f::type,0>::type>::type::value == 1 ));
+BOOST_STATIC_ASSERT(( at_c<at_c<AV1f::type,0>::type,0>::type::value == false ));
+
+typedef allowable_vectorizations<vector<false_,true_> > AV2ft;
+BOOST_STATIC_ASSERT(( size<AV2ft::type>::type::value == 2 ));
+BOOST_STATIC_ASSERT(( size<at_c<AV2ft::type,0>::type>::type::value == 2 ));
+BOOST_STATIC_ASSERT(( at_c<at_c<AV2ft::type,0>::type,0>::type::value == false ));
+BOOST_STATIC_ASSERT(( at_c<at_c<AV2ft::type,0>::type,1>::type::value == false ));
+BOOST_STATIC_ASSERT(( size<at_c<AV2ft::type,1>::type>::type::value == 2 ));
+BOOST_STATIC_ASSERT(( at_c<at_c<AV2ft::type,1>::type,0>::type::value == false ));
+BOOST_STATIC_ASSERT(( at_c<at_c<AV2ft::type,1>::type,1>::type::value == true ));
+
+} // namespace detail
+
+} // namespace PyImath
diff --git a/src/python/PyImath/PyImathAutovectorize.h b/src/python/PyImath/PyImathAutovectorize.h
new file mode 100644 (file)
index 0000000..4418cb5
--- /dev/null
@@ -0,0 +1,2865 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+
+#ifndef _PyImathAutovectorize_h_
+#define _PyImathAutovectorize_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/mpl/size.hpp>
+#include <boost/mpl/pop_front.hpp>
+#include <boost/mpl/push_front.hpp>
+#include <boost/mpl/front.hpp>
+#include <boost/mpl/eval_if.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/mpl/transform.hpp>
+#include <boost/mpl/remove_if.hpp>
+#include <boost/mpl/equal.hpp>
+#include <boost/mpl/for_each.hpp>
+#include <boost/mpl/not.hpp>
+#include <boost/mpl/count.hpp>
+#include <boost/mpl/or.hpp>
+#include <boost/type_traits/is_base_of.hpp>
+#include <boost/type_traits/function_traits.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/python/args.hpp>
+#include <iostream>
+#include "PyImathFixedArray.h"
+#include "PyImathTask.h"
+#include "PyImathUtil.h"
+
+namespace PyImath {
+
+struct op_with_precomputation {};
+
+namespace detail {
+
+using boost::is_base_of;
+using boost::is_same;
+using boost::is_const;
+using boost::remove_const;
+using boost::remove_reference;
+using boost::function_traits;
+
+using boost::mpl::at;
+using boost::mpl::at_c;
+using boost::mpl::push_front;
+using boost::mpl::vector;
+using boost::mpl::push_back;
+using boost::mpl::transform;
+using boost::mpl::fold;
+using boost::mpl::_;
+using boost::mpl::_1;
+using boost::mpl::_2;
+using boost::mpl::long_;
+using boost::mpl::false_;
+using boost::mpl::true_;
+using boost::mpl::not_;
+using boost::mpl::or_;
+using boost::mpl::and_;
+using boost::mpl::size;
+using boost::mpl::remove_if;
+using boost::mpl::if_;
+using boost::mpl::for_each;
+
+
+struct null_precomputation {
+    static void precompute(size_t len) { return; }
+};
+
+template <class T> struct op_precompute
+{
+    static void
+    apply(size_t len)
+    {
+        if_<is_base_of<op_with_precomputation,T>,
+            T,
+            null_precomputation>::type::precompute(len);
+    }
+};
+
+template <int N>
+struct possible_vectorizations
+{
+    typedef typename fold<
+        typename possible_vectorizations<N-1>::type,
+        vector<>,
+        push_back<push_back<_1,push_back<_2,false_> >,push_back<_2,true_> >
+    >::type type;
+};
+
+template <>
+struct possible_vectorizations<0>
+{
+    typedef vector<vector<> > type;    
+};
+
+template <class Vectorizable>
+struct disallow_vectorization
+{
+    template <class Vectorize>
+    struct apply
+    {
+        // Valid = !Vectorize || Vectorizable
+        typedef typename transform<Vectorize,not_<_> >::type DontVectorize;
+        typedef typename transform<DontVectorize,Vectorizable,or_<_,_> >::type Valid;
+        typedef typename not_<fold<Valid,true_,and_<_,_> > >::type type;
+    };
+};
+
+template <class Vectorizable>
+struct allowable_vectorizations
+{
+    typedef typename possible_vectorizations<size<Vectorizable>::value>::type possible;
+    typedef typename remove_if<possible,disallow_vectorization<Vectorizable> >::type type;
+};
+
+template <class T>
+bool any_masked(const T &value)
+{
+    return false;
+};
+
+template <class T>
+bool any_masked(const PyImath::FixedArray<T> &value)
+{
+    return value.isMaskedReference();
+};
+
+template <class T1, class T2>
+bool any_masked(const T1 &a, const T2 &b)
+{
+    return any_masked(a) || any_masked(b);
+}
+
+template <class T1, class T2, class T3>
+bool any_masked(const T1 &a, const T2 &b, const T3 &c)
+{
+    return any_masked(a,b) || any_masked(c);
+}
+
+template <class T1, class T2, class T3, class T4>
+bool any_masked(const T1 &a, const T2 &b, const T3 &c, const T4 &d)
+{
+    return any_masked(a,b) || any_masked(c,d);
+}
+
+//-----------------------------------------------------------------------------------------
+
+//
+// measure_argument returns a pair indicating the integral length of the argument
+// (scalar arguments have implicit length 1), and a bool indicating whether the argument
+// is a vectorized argument.
+//
+template <class T>
+struct measure_argument
+{
+    static inline std::pair<size_t,bool> apply(T arg) { return std::make_pair(1,false); }
+};
+
+template <class T>
+struct measure_argument<PyImath::FixedArray<T> >
+{
+    static inline std::pair<size_t,bool> apply(const PyImath::FixedArray<T> &arg) { return std::make_pair(arg.len(),true); }
+};
+
+//
+// match_lengths returns the compatible length given two argument lengths
+//
+static inline std::pair<size_t,bool>
+match_lengths(const std::pair<size_t,bool> &len1, const std::pair<size_t,bool> &len2)
+{
+    // scalar arguemnts are always compatible with other arguments
+    if (len1.second == false) return len2;
+    if (len2.second == false) return len1;
+
+    // now both arguments are vectorized, check for dimension match
+    if (len1.first != len2.first)
+      throw std::invalid_argument("Array dimensions passed into function do not match");
+
+    return len1;
+}
+
+
+//
+// measure_arguments finds the length that a return value from a given
+// set of arguments should have, throwing an exception if the lengths
+// are incompatible.  If all arguments are scalar, length 1 is returned.
+//
+template <class arg1_type>
+size_t
+measure_arguments(const arg1_type &arg1)
+{
+    std::pair<size_t,bool> len = measure_argument<arg1_type>::apply(arg1);
+    return len.first;
+}
+
+template <class arg1_type, class arg2_type>
+size_t
+measure_arguments(const arg1_type &arg1, const arg2_type &arg2)
+{
+    std::pair<size_t,bool> len = measure_argument<arg1_type>::apply(arg1);
+    len = match_lengths(len,measure_argument<arg2_type>::apply(arg2));
+    return len.first;
+}
+
+template <class arg1_type, class arg2_type, class arg3_type>
+size_t
+measure_arguments(const arg1_type &arg1, const arg2_type &arg2, const arg3_type &arg3)
+{
+    std::pair<size_t,bool> len = measure_argument<arg1_type>::apply(arg1);
+    len = match_lengths(len,measure_argument<arg2_type>::apply(arg2));
+    len = match_lengths(len,measure_argument<arg3_type>::apply(arg3));
+    return len.first;
+}
+
+template <class arg1_type, class arg2_type, class arg3_type, class arg4_type>
+size_t
+measure_arguments(const arg1_type &arg1, const arg2_type &arg2, const arg3_type &arg3, const arg4_type &arg4)
+{
+    std::pair<size_t,bool> len = measure_argument<arg1_type>::apply(arg1);
+    len = match_lengths(len,measure_argument<arg2_type>::apply(arg2));
+    len = match_lengths(len,measure_argument<arg3_type>::apply(arg3));
+    len = match_lengths(len,measure_argument<arg4_type>::apply(arg4));
+    return len.first;
+}
+
+template <class arg1_type, class arg2_type, class arg3_type, class arg4_type, class arg5_type>
+size_t
+measure_arguments(const arg1_type &arg1, const arg2_type &arg2, const arg3_type &arg3, const arg4_type &arg4, const arg5_type &arg5)
+{
+    std::pair<size_t,bool> len = measure_argument<arg1_type>::apply(arg1);
+    len = match_lengths(len,measure_argument<arg2_type>::apply(arg2));
+    len = match_lengths(len,measure_argument<arg3_type>::apply(arg3));
+    len = match_lengths(len,measure_argument<arg4_type>::apply(arg4));
+    len = match_lengths(len,measure_argument<arg5_type>::apply(arg5));
+    return len.first;
+}
+
+//-----------------------------------------------------------------------------------------
+
+template <class T>
+struct create_uninitalized_return_value
+{
+    static T apply(size_t length)
+    {
+        return T();
+    }
+};
+
+template <class T>
+struct create_uninitalized_return_value<PyImath::FixedArray<T> >
+{
+    static PyImath::FixedArray<T> apply(size_t length)
+    {
+        return PyImath::FixedArray<T>(Py_ssize_t(length),PyImath::UNINITIALIZED);
+    }
+};
+
+template <class T, class VectorizeArg>
+struct vectorized_result_type
+{
+    typedef typename if_<VectorizeArg,PyImath::FixedArray<T>,T>::type type;
+};
+
+template <typename T>
+struct SimpleNonArrayWrapper
+{
+    struct ReadOnlyDirectAccess
+    {
+        ReadOnlyDirectAccess (const T& arg)
+            : _arg (arg) {}
+        ReadOnlyDirectAccess (const ReadOnlyDirectAccess& other)
+            : _arg (other._arg) {}
+
+        const T&  operator[] (size_t) const { return _arg; }
+
+      private:
+        const T&  _arg;
+    };
+
+    struct WritableDirectAccess : public ReadOnlyDirectAccess
+    {
+        WritableDirectAccess (T& arg)
+            : ReadOnlyDirectAccess (arg), _arg (arg) {}
+        WritableDirectAccess (const WritableDirectAccess& other)
+            : ReadOnlyDirectAccess (other), _arg (other._arg) {}
+
+        T&  operator[] (size_t) { return _arg; }
+
+      private:
+        T&  _arg;
+    };
+
+    typedef ReadOnlyDirectAccess ReadOnlyMaskedAccess;
+    typedef WritableDirectAccess WritableMaskedAccess;
+};
+
+
+template <class T>
+struct access_type
+{
+    typedef typename remove_reference<T>::type     prim_type;
+    typedef typename remove_const<prim_type>::type base_type;
+    typedef typename if_<is_const<prim_type>,
+                         const PyImath::FixedArray<base_type> &,
+                               PyImath::FixedArray<base_type> &>::type reference_type;
+    typedef typename remove_reference<reference_type>::type class_type;
+
+    typedef typename if_<is_const<prim_type>,
+                         typename class_type::ReadOnlyMaskedAccess,
+                         typename class_type::WritableMaskedAccess>::type masked;
+    typedef typename if_<is_const<prim_type>,
+                         typename class_type::ReadOnlyDirectAccess,
+                         typename class_type::WritableDirectAccess>::type direct;
+};
+
+template <class T, class VectorizeArg>
+struct argument_access_type
+{
+    typedef typename remove_const<typename remove_reference<T>::type>::type base_type;
+    typedef typename if_<VectorizeArg,const PyImath::FixedArray<base_type> &,T>::type type;
+
+    typedef typename if_<VectorizeArg,
+                         typename remove_reference<type>::type,
+                              SimpleNonArrayWrapper<base_type> >::type _class_type;
+
+    typedef typename _class_type::ReadOnlyMaskedAccess masked;
+    typedef typename _class_type::ReadOnlyDirectAccess direct;
+};
+
+template <class T, class VectorizeArg>
+struct result_access_type
+{
+    typedef typename remove_const<typename remove_reference<T>::type>::type base_type;
+    typedef typename if_<VectorizeArg,PyImath::FixedArray<base_type>,T>::type type;
+
+    typedef typename if_<VectorizeArg, type,
+                         SimpleNonArrayWrapper<base_type> >::type _class_type;
+
+    typedef typename _class_type::WritableMaskedAccess masked;
+    typedef typename _class_type::WritableDirectAccess direct;
+};
+
+template <class AccessType, class T>
+AccessType getArrayAccess (T&  value)
+           { return AccessType (value); }
+
+template <class AccessType, class T>
+AccessType getArrayAccess (const PyImath::FixedArray<T>& array)
+           { return AccessType (array); }
+
+template <class AccessType, class T>
+AccessType getArrayAccess (PyImath::FixedArray<T>& array)
+           { return AccessType (array); }
+
+//
+
+template <class Op, class result_access_type, class access_type>
+struct VectorizedOperation1 : public Task
+{
+    result_access_type retAccess;
+    access_type        access;
+
+    VectorizedOperation1 (result_access_type r, access_type a1)
+        : retAccess (r), access (a1) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            retAccess[i] = Op::apply (access[i]);
+        }
+    }
+};
+
+template <class Op, class result_access_type, class access_type, class arg1_access_type>
+struct VectorizedOperation2 : public Task
+{
+    result_access_type retAccess;
+    access_type        access;
+    arg1_access_type   argAccess;
+
+    VectorizedOperation2(result_access_type r, access_type a1, arg1_access_type a2)
+        : retAccess (r), access (a1), argAccess (a2) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            retAccess[i] = Op::apply (access[i], argAccess[i]);
+        }
+    }
+};
+
+template <class Op, class result_access_type, class access_type,
+                    class arg1_access_type, class arg2_access_type>
+struct VectorizedOperation3 : public Task
+{
+    result_access_type retAccess;
+    access_type        access;
+    arg1_access_type   arg1Access;
+    arg2_access_type   arg2Access;
+
+    VectorizedOperation3(result_access_type r, access_type a,
+                         arg1_access_type a1, arg2_access_type a2)
+        : retAccess(r), access(a), arg1Access(a1), arg2Access(a2) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            retAccess[i] = Op::apply(access[i], arg1Access[i], arg2Access[i]);
+        }
+    }
+};
+
+template <class Op, class result_access_type, class access_type,
+                    class arg1_access_type, class arg2_access_type, class arg3_access_type>
+struct VectorizedOperation4 : public Task
+{
+    result_access_type retAccess;
+    access_type        access;
+    arg1_access_type   arg1Access;
+    arg2_access_type   arg2Access;
+    arg3_access_type   arg3Access;
+
+    VectorizedOperation4(result_access_type r, access_type a,
+                         arg1_access_type a1, arg2_access_type a2, arg3_access_type a3)
+        : retAccess(r), access(a), arg1Access(a1), arg2Access(a2), arg3Access(a3) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            retAccess[i] = Op::apply(access[i], arg1Access[i], arg2Access[i], arg3Access[i]);
+        }
+    }
+};
+
+template <class Op, class result_access_type, class access_type,
+                    class arg1_access_type, class arg2_access_type, class arg3_access_type, class arg4_access_type>
+struct VectorizedOperation5 : public Task
+{
+    result_access_type retAccess;
+    access_type        access;
+    arg1_access_type   arg1Access;
+    arg2_access_type   arg2Access;
+    arg3_access_type   arg3Access;
+    arg4_access_type   arg4Access;
+
+    VectorizedOperation5(result_access_type r, access_type a,
+                         arg1_access_type a1, arg2_access_type a2, arg3_access_type a3, arg4_access_type a4)
+        : retAccess(r), access(a), arg1Access(a1), arg2Access(a2), arg3Access(a3), arg4Access(a4) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            retAccess[i] = Op::apply(access[i], arg1Access[i], arg2Access[i], arg3Access[i], arg4Access[i]);
+        }
+    }
+};
+
+template <class Op, class Vectorize, class Func>
+struct VectorizedFunction1 {
+    BOOST_STATIC_ASSERT((size<Vectorize>::value == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+    typedef typename fold<Vectorize,false_,or_<_,_> >::type any_vectorized;
+
+    typedef typename result_access_type<typename traits::result_type,
+                                        any_vectorized>::type result_type;
+    typedef typename result_access_type<typename traits::result_type,
+                                        any_vectorized>::direct result_access_type;
+    // Result array is created here 'from scratch', so is always 'direct' access.
+
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::type arg1_type;
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::direct arg1_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::masked arg1_masked_access_type;
+
+    static result_type
+    apply(arg1_type arg1)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = measure_arguments(arg1);
+        op_precompute<Op>::apply(len);
+        result_type retval = create_uninitalized_return_value<result_type>::apply(len);
+
+        result_access_type resultAccess = getArrayAccess<result_access_type> (retval);
+
+        if (any_masked(arg1))
+        {
+            arg1_masked_access_type argAccess =
+                 getArrayAccess<arg1_masked_access_type> (arg1);
+
+            VectorizedOperation1<Op,result_access_type,arg1_masked_access_type>
+                vop (resultAccess, argAccess);
+            dispatchTask(vop,len);
+        }
+        else
+        {
+            arg1_direct_access_type argAccess =
+                 getArrayAccess<arg1_direct_access_type> (arg1);
+
+            VectorizedOperation1<Op,result_access_type,arg1_direct_access_type>
+                vop (resultAccess, argAccess);
+            dispatchTask(vop,len);
+        }
+
+        PY_IMATH_RETURN_PYTHON;        
+        return retval;
+    }
+
+    static std::string
+    format_arguments(const boost::python::detail::keywords<1> &args)
+    {
+        // TODO: add types here
+        return std::string("(")+args.elements[0].name+") - ";
+    }
+};
+
+template <class Op, class Vectorize, class Func>
+struct VectorizedFunction2 {
+    BOOST_STATIC_ASSERT((size<Vectorize>::value == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+    typedef typename fold<Vectorize,false_,or_<_,_> >::type any_vectorized;
+
+    typedef typename result_access_type<typename traits::result_type,
+                                        any_vectorized>::type result_type;
+    typedef typename result_access_type<typename traits::result_type,
+                                        any_vectorized>::direct result_access_type;
+    // Result array is created here 'from scratch', so is always 'direct' access.
+
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::type arg1_type;
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::direct arg1_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::masked arg1_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::type arg2_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::direct arg2_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::masked arg2_masked_access_type;
+
+    static result_type
+    apply(arg1_type arg1, arg2_type arg2)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = measure_arguments(arg1,arg2);
+        op_precompute<Op>::apply(len);
+        result_type retval = create_uninitalized_return_value<result_type>::apply(len);
+
+        result_access_type resultAccess = getArrayAccess<result_access_type> (retval);
+
+        if (any_masked(arg1))
+        {
+            arg1_masked_access_type arg1Access =
+                 getArrayAccess<arg1_masked_access_type> (arg1);
+
+            if (any_masked(arg2))
+            {
+                arg2_masked_access_type arg2Access =
+                     getArrayAccess<arg2_masked_access_type> (arg2);
+
+                VectorizedOperation2<Op,result_access_type,
+                                   arg1_masked_access_type,
+                                   arg2_masked_access_type>
+                    vop (resultAccess, arg1Access, arg2Access);
+                dispatchTask(vop,len);
+            }
+            else
+            {
+                arg2_direct_access_type arg2Access =
+                     getArrayAccess<arg2_direct_access_type> (arg2);
+
+                VectorizedOperation2<Op,result_access_type,
+                                   arg1_masked_access_type,
+                                   arg2_direct_access_type>
+                    vop (resultAccess, arg1Access, arg2Access);
+                dispatchTask(vop,len);
+            }
+        }
+        else
+        {
+            arg1_direct_access_type arg1Access =
+                 getArrayAccess<arg1_direct_access_type> (arg1);
+
+            if (any_masked(arg2))
+            {
+                arg2_masked_access_type arg2Access =
+                     getArrayAccess<arg2_masked_access_type> (arg2);
+
+                VectorizedOperation2<Op,result_access_type,
+                                   arg1_direct_access_type,
+                                   arg2_masked_access_type>
+                    vop (resultAccess, arg1Access, arg2Access);
+                dispatchTask(vop,len);
+            }
+            else
+            {
+                arg2_direct_access_type arg2Access =
+                     getArrayAccess<arg2_direct_access_type> (arg2);
+
+                VectorizedOperation2<Op,result_access_type,
+                                   arg1_direct_access_type,
+                                   arg2_direct_access_type>
+                    vop (resultAccess, arg1Access, arg2Access);
+                dispatchTask(vop,len);
+            }
+        }
+
+        PY_IMATH_RETURN_PYTHON;        
+        return retval;
+    }
+
+    static std::string
+    format_arguments(const boost::python::detail::keywords<2> &args)
+    {
+        // TODO: add types here
+        return std::string("(")+args.elements[0].name+","+args.elements[1].name+") - ";
+    }
+};
+
+template <class Op, class Vectorize, class Func>
+struct VectorizedFunction3 {
+    BOOST_STATIC_ASSERT((size<Vectorize>::value == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+    typedef typename fold<Vectorize,false_,or_<_,_> >::type any_vectorized;
+
+    typedef typename result_access_type<typename traits::result_type,
+                                        any_vectorized>::type result_type;
+    typedef typename result_access_type<typename traits::result_type,
+                                        any_vectorized>::direct result_access_type;
+    // Result array is created here 'from scratch', so is always 'direct' access.
+
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::type arg1_type;
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::direct arg1_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::masked arg1_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::type arg2_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::direct arg2_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::masked arg2_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<2> >::type>::type arg3_type;
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<2> >::type>::direct arg3_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<2> >::type>::masked arg3_masked_access_type;
+
+    static result_type
+    apply(arg1_type arg1, arg2_type arg2, arg3_type arg3)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = measure_arguments(arg1,arg2,arg3);
+        op_precompute<Op>::apply(len);
+        result_type retval = create_uninitalized_return_value<result_type>::apply(len);
+
+        result_access_type resultAccess = getArrayAccess<result_access_type> (retval);
+
+        if (any_masked(arg1))
+        {
+            arg1_masked_access_type arg1Access =
+                 getArrayAccess<arg1_masked_access_type> (arg1);
+
+            if (any_masked(arg2))
+            {
+                arg2_masked_access_type arg2Access =
+                     getArrayAccess<arg2_masked_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                       arg1_masked_access_type,
+                                       arg2_masked_access_type,
+                                       arg3_masked_access_type>
+                        vop (resultAccess, arg1Access, arg2Access, arg3Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                       arg1_masked_access_type,
+                                       arg2_masked_access_type,
+                                       arg3_direct_access_type>
+                        vop (resultAccess, arg1Access, arg2Access, arg3Access);
+                    dispatchTask(vop,len);
+                }
+            }
+            else
+            {
+                arg2_direct_access_type arg2Access =
+                     getArrayAccess<arg2_direct_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                       arg1_masked_access_type,
+                                       arg2_direct_access_type,
+                                       arg3_masked_access_type>
+                        vop (resultAccess, arg1Access, arg2Access, arg3Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                       arg1_masked_access_type,
+                                       arg2_direct_access_type,
+                                       arg3_direct_access_type>
+                        vop (resultAccess, arg1Access, arg2Access, arg3Access);
+                    dispatchTask(vop,len);
+                }
+            }
+        }
+        else
+        {
+            arg1_direct_access_type arg1Access =
+                 getArrayAccess<arg1_direct_access_type> (arg1);
+
+            if (any_masked(arg2))
+            {
+                arg2_masked_access_type arg2Access =
+                     getArrayAccess<arg2_masked_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                       arg1_direct_access_type,
+                                       arg2_masked_access_type,
+                                       arg3_masked_access_type>
+                        vop (resultAccess, arg1Access, arg2Access, arg3Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                       arg1_direct_access_type,
+                                       arg2_masked_access_type,
+                                       arg3_direct_access_type>
+                        vop (resultAccess, arg1Access, arg2Access, arg3Access);
+                    dispatchTask(vop,len);
+                }
+            }
+            else
+            {
+                arg2_direct_access_type arg2Access =
+                     getArrayAccess<arg2_direct_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                       arg1_direct_access_type,
+                                       arg2_direct_access_type,
+                                       arg3_masked_access_type>
+                        vop (resultAccess, arg1Access, arg2Access, arg3Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                       arg1_direct_access_type,
+                                       arg2_direct_access_type,
+                                       arg3_direct_access_type>
+                        vop (resultAccess, arg1Access, arg2Access, arg3Access);
+                    dispatchTask(vop,len);
+                }
+            }
+        }
+
+        PY_IMATH_RETURN_PYTHON;
+        return retval;
+    }
+
+    static std::string
+    format_arguments(const boost::python::detail::keywords<3> &args)
+    {
+        // TODO: add types here
+        return std::string("(")+args.elements[0].name+","+args.elements[1].name+","+args.elements[2].name+") - ";
+    }
+};
+
+template <class Op, class Vectorize, class Func>
+struct VectorizedFunction4 {
+    BOOST_STATIC_ASSERT((size<Vectorize>::value == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+    typedef typename fold<Vectorize,false_,or_<_,_> >::type any_vectorized;
+
+    typedef typename result_access_type<typename traits::result_type,
+                                        any_vectorized>::type result_type;
+    typedef typename result_access_type<typename traits::result_type,
+                                        any_vectorized>::direct result_access_type;
+    // Result array is created here 'from scratch', so is always 'direct' access.
+
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::type arg1_type;
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::direct arg1_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::masked arg1_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::type arg2_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::direct arg2_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::masked arg2_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<2> >::type>::type arg3_type;
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<2> >::type>::direct arg3_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<2> >::type>::masked arg3_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg4_type,
+                              typename at<Vectorize,long_<3> >::type>::type arg4_type;
+    typedef typename argument_access_type<typename traits::arg4_type,
+                              typename at<Vectorize,long_<3> >::type>::direct arg4_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg4_type,
+                              typename at<Vectorize,long_<3> >::type>::masked arg4_masked_access_type;
+
+    static result_type
+    apply(arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = measure_arguments(arg1,arg2,arg3,arg4);
+        op_precompute<Op>::apply(len);
+        result_type retval = create_uninitalized_return_value<result_type>::apply(len);
+
+        result_access_type resultAccess = getArrayAccess<result_access_type> (retval);
+
+        if (any_masked(arg1))
+        {
+            arg1_masked_access_type arg1Access =
+                 getArrayAccess<arg1_masked_access_type> (arg1);
+
+            if (any_masked(arg2))
+            {
+                arg2_masked_access_type arg2Access =
+                     getArrayAccess<arg2_masked_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_masked_access_type,
+                                           arg3_masked_access_type,
+                                           arg4_masked_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_masked_access_type,
+                                           arg3_masked_access_type,
+                                           arg4_direct_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_masked_access_type,
+                                           arg3_direct_access_type,
+                                           arg4_masked_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_masked_access_type,
+                                           arg3_direct_access_type,
+                                           arg4_direct_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                }
+            }
+            else
+            {
+                arg2_direct_access_type arg2Access =
+                     getArrayAccess<arg2_direct_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_direct_access_type,
+                                           arg3_masked_access_type,
+                                           arg4_masked_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_direct_access_type,
+                                           arg3_masked_access_type,
+                                           arg4_direct_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_direct_access_type,
+                                           arg3_direct_access_type,
+                                           arg4_masked_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_direct_access_type,
+                                           arg3_direct_access_type,
+                                           arg4_direct_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                }
+            }
+        }
+        else
+        {
+            arg1_direct_access_type arg1Access =
+                 getArrayAccess<arg1_direct_access_type> (arg1);
+
+            if (any_masked(arg2))
+            {
+                arg2_masked_access_type arg2Access =
+                     getArrayAccess<arg2_masked_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_masked_access_type,
+                                           arg3_masked_access_type,
+                                           arg4_masked_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_masked_access_type,
+                                           arg3_masked_access_type,
+                                           arg4_direct_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_masked_access_type,
+                                           arg3_direct_access_type,
+                                           arg4_masked_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_masked_access_type,
+                                           arg3_direct_access_type,
+                                           arg4_direct_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                }
+            }
+            else
+            {
+                arg2_direct_access_type arg2Access =
+                     getArrayAccess<arg2_direct_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_direct_access_type,
+                                           arg3_masked_access_type,
+                                           arg4_masked_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_direct_access_type,
+                                           arg3_masked_access_type,
+                                           arg4_direct_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_direct_access_type,
+                                           arg3_direct_access_type,
+                                           arg4_masked_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        VectorizedOperation4<Op,result_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_direct_access_type,
+                                           arg3_direct_access_type,
+                                           arg4_direct_access_type>
+                            vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access);
+                        dispatchTask(vop,len);
+                    }
+                }
+            }
+        }
+
+        PY_IMATH_RETURN_PYTHON;
+        return retval;
+    }
+
+    static std::string
+    format_arguments(const boost::python::detail::keywords<4> &args)
+    {
+        // TODO: add types here
+        return std::string("(")+args.elements[0].name+","+args.elements[1].name+","+args.elements[2].name+","+args.elements[3].name+") - ";
+    }
+};
+
+template <class Op, class Vectorize, class Func>
+struct VectorizedFunction5 {
+    BOOST_STATIC_ASSERT((size<Vectorize>::value == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+    typedef typename fold<Vectorize,false_,or_<_,_> >::type any_vectorized;
+
+    typedef typename result_access_type<typename traits::result_type,
+                                        any_vectorized>::type result_type;
+    typedef typename result_access_type<typename traits::result_type,
+                                        any_vectorized>::direct result_access_type;
+    // Result array is created here 'from scratch', so is always 'direct' access.
+
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::type arg1_type;
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::direct arg1_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg1_type,
+                              typename at<Vectorize,long_<0> >::type>::masked arg1_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::type arg2_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::direct arg2_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<1> >::type>::masked arg2_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<2> >::type>::type arg3_type;
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<2> >::type>::direct arg3_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<2> >::type>::masked arg3_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg4_type,
+                              typename at<Vectorize,long_<3> >::type>::type arg4_type;
+    typedef typename argument_access_type<typename traits::arg4_type,
+                              typename at<Vectorize,long_<3> >::type>::direct arg4_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg4_type,
+                              typename at<Vectorize,long_<3> >::type>::masked arg4_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg5_type,
+                              typename at<Vectorize,long_<4> >::type>::type arg5_type;
+    typedef typename argument_access_type<typename traits::arg5_type,
+                              typename at<Vectorize,long_<4> >::type>::direct arg5_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg5_type,
+                              typename at<Vectorize,long_<4> >::type>::masked arg5_masked_access_type;
+
+    static result_type
+    apply(arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, arg5_type arg5)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = measure_arguments(arg1,arg2,arg3,arg4,arg5);
+        op_precompute<Op>::apply(len);
+        result_type retval = create_uninitalized_return_value<result_type>::apply(len);
+
+        result_access_type resultAccess = getArrayAccess<result_access_type> (retval);
+
+        if (any_masked(arg1))
+        {
+            arg1_masked_access_type arg1Access =
+                 getArrayAccess<arg1_masked_access_type> (arg1);
+
+            if (any_masked(arg2))
+            {
+                arg2_masked_access_type arg2Access =
+                     getArrayAccess<arg2_masked_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                arg2_direct_access_type arg2Access =
+                     getArrayAccess<arg2_direct_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_masked_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                }
+            }
+        }
+        else
+        {
+            arg1_direct_access_type arg1Access =
+                 getArrayAccess<arg1_direct_access_type> (arg1);
+
+            if (any_masked(arg2))
+            {
+                arg2_masked_access_type arg2Access =
+                     getArrayAccess<arg2_masked_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_masked_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                arg2_direct_access_type arg2Access =
+                     getArrayAccess<arg2_direct_access_type> (arg2);
+
+                if (any_masked(arg3))
+                {
+                    arg3_masked_access_type arg3Access =
+                         getArrayAccess<arg3_masked_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_masked_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                }
+                else
+                {
+                    arg3_direct_access_type arg3Access =
+                         getArrayAccess<arg3_direct_access_type> (arg3);
+
+                    if (any_masked(arg4))
+                    {
+                        arg4_masked_access_type arg4Access =
+                            getArrayAccess<arg4_masked_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_masked_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                    else
+                    {
+                        arg4_direct_access_type arg4Access =
+                            getArrayAccess<arg4_direct_access_type> (arg4);
+
+                        if (any_masked(arg5))
+                        {
+                            arg5_masked_access_type arg5Access =
+                                getArrayAccess<arg5_masked_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_masked_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                        else
+                        {
+                            arg5_direct_access_type arg5Access =
+                                getArrayAccess<arg5_direct_access_type> (arg5);
+
+                            VectorizedOperation5<Op,result_access_type,
+                                               arg1_direct_access_type,
+                                               arg2_direct_access_type,
+                                               arg3_direct_access_type,
+                                               arg4_direct_access_type,
+                                               arg5_direct_access_type>
+                                vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access);
+                            dispatchTask(vop,len);
+                        }
+                    }
+                }
+            }
+        }
+
+        PY_IMATH_RETURN_PYTHON;
+        return retval;
+    }
+
+    static std::string
+    format_arguments(const boost::python::detail::keywords<5> &args)
+    {
+        // TODO: add types here
+        return std::string("(")+args.elements[0].name+","+args.elements[1].name+","+args.elements[2].name+","+args.elements[3].name+","+args.elements[4].name+") - ";
+    }
+};
+
+template <class Op, class Func, class Keywords>
+struct function_binding
+{
+    std::string _name, _doc;
+    const Keywords &_args;
+
+
+    function_binding(const std::string &name, const std::string &doc,const Keywords &args)
+        : _name(name), _doc(doc), _args(args)
+    {}
+
+    template <class Vectorize>
+    void operator()(Vectorize) const
+    {
+        typedef typename at<vector<
+             int,  // unused, arity 0
+             VectorizedFunction1<Op,Vectorize,Func>,
+             VectorizedFunction2<Op,Vectorize,Func>,
+             VectorizedFunction3<Op,Vectorize,Func>,
+             VectorizedFunction4<Op,Vectorize,Func>,
+             VectorizedFunction5<Op,Vectorize,Func>
+            >,
+            long_<function_traits<Func>::arity> >::type vectorized_function_type;
+        std::string doc = _name + vectorized_function_type::format_arguments(_args) + _doc;
+        boost::python::def(_name.c_str(),&vectorized_function_type::apply,doc.c_str(),_args);
+    }
+};
+
+template <class Op,class Func,class Keywords>
+function_binding<Op,Func,Keywords>
+build_function_binding(Func *func,const std::string &name,const std::string &doc,const Keywords &args)
+{
+    return function_binding<Op,Func,Keywords>(name,doc,args);
+}
+
+template <class Op,class Vectorizable,class Keywords>
+struct generate_bindings_struct
+{
+    //BOOST_STATIC_ASSERT(size<Vectorizable>::value == function_traits<Op::apply>::arity);
+    static void apply(const std::string &name,const std::string &doc,const Keywords &args) {
+        for_each<typename allowable_vectorizations<Vectorizable>::type>(build_function_binding<Op>(Op::apply,name,doc,args));
+    }
+};
+
+
+template <class Op, class access_type>
+struct VectorizedVoidOperation0 : public Task
+{
+    access_type access;
+
+    VectorizedVoidOperation0 (access_type a) : access(a) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            Op::apply (access[i]);
+        }
+    }
+};
+
+template <class Op, class access_type, class arg1_access_type>
+struct VectorizedVoidOperation1 : public Task
+{
+    access_type      access;
+    arg1_access_type arg1;
+
+    VectorizedVoidOperation1(access_type a, arg1_access_type a1) : access(a), arg1(a1) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            Op::apply (access[i], arg1[i]);
+        }
+    }
+};
+
+template <class Op, class access_type, class arg1_access_type, class array_type>
+struct VectorizedMaskedVoidOperation1 : public Task
+{
+    access_type      access;
+    arg1_access_type arg1;
+    array_type       array;
+
+    VectorizedMaskedVoidOperation1(access_type a, arg1_access_type a1, array_type arr)
+        : access(a), arg1(a1), array(arr) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            const size_t ri = array.raw_ptr_index(i);
+            Op::apply (access[i], arg1[ri]);
+        }
+    }
+};
+
+template <class Op, class access_type, class arg1_access_type, class arg2_access_type>
+struct VectorizedVoidOperation2 : public Task
+{
+    access_type      access;
+    arg1_access_type arg1;
+    arg2_access_type arg2;
+
+    VectorizedVoidOperation2(access_type a, arg1_access_type a1, arg2_access_type a2)
+        : access(a), arg1(a1), arg2(a2) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            Op::apply (access[i], arg1[i], arg2[i]);
+        }
+    }
+};
+
+
+template <class Op, class Vectorize, class Func>
+struct VectorizedVoidMemberFunction0 {
+    BOOST_STATIC_ASSERT((size<Vectorize>::value+1 == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+
+    typedef typename access_type<typename traits::arg1_type>::reference_type reference_type;
+    typedef typename access_type<typename traits::arg1_type>::direct direct_access_type;
+    typedef typename access_type<typename traits::arg1_type>::masked masked_access_type;
+
+    static reference_type
+    apply(reference_type array)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = measure_arguments(array);
+        op_precompute<Op>::apply(len);
+
+        if (any_masked(array))
+        {
+            masked_access_type access (array);
+            VectorizedVoidOperation0<Op,masked_access_type> vop (access);
+            dispatchTask(vop,len);
+        }
+        else
+        {
+            direct_access_type access (array);
+            VectorizedVoidOperation0<Op,direct_access_type> vop (access);
+            dispatchTask(vop,len);
+        }
+
+        PY_IMATH_RETURN_PYTHON;
+        return array;
+    }
+};
+
+template <class Op, class Vectorize, class Func>
+struct VectorizedVoidMemberFunction1 {
+    BOOST_STATIC_ASSERT((size<Vectorize>::value+1 == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+
+    typedef typename access_type<typename traits::arg1_type>::reference_type reference_type;
+    typedef typename access_type<typename traits::arg1_type>::direct direct_access_type;
+    typedef typename access_type<typename traits::arg1_type>::masked masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::type arg1_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::direct arg1_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::masked arg1_masked_access_type;
+
+    static reference_type
+    apply(reference_type array, arg1_type arg1)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = measure_arguments(array,arg1);
+        op_precompute<Op>::apply(len);
+
+        if (any_masked(array))
+        {
+            masked_access_type arrayAccess (array);
+
+            if (any_masked(arg1))
+            {
+                arg1_masked_access_type argAccess =
+                     getArrayAccess<arg1_masked_access_type> (arg1);
+
+                VectorizedVoidOperation1<Op,masked_access_type,arg1_masked_access_type>
+                    vop (arrayAccess, argAccess);
+                dispatchTask(vop,len);
+            }
+            else
+            {
+                arg1_direct_access_type argAccess =
+                     getArrayAccess<arg1_direct_access_type> (arg1);
+
+                VectorizedVoidOperation1<Op,masked_access_type,arg1_direct_access_type>
+                    vop (arrayAccess, argAccess);
+                dispatchTask(vop,len);
+            }
+        }
+        else
+        {
+            direct_access_type arrayAccess (array);
+
+            if (any_masked(arg1))
+            {
+                arg1_masked_access_type argAccess =
+                     getArrayAccess<arg1_masked_access_type> (arg1);
+
+                VectorizedVoidOperation1<Op,direct_access_type,arg1_masked_access_type>
+                    vop (arrayAccess, argAccess);
+                dispatchTask(vop,len);
+            }
+            else
+            {
+                arg1_direct_access_type argAccess =
+                     getArrayAccess<arg1_direct_access_type> (arg1);
+
+                VectorizedVoidOperation1<Op,direct_access_type,arg1_direct_access_type>
+                    vop (arrayAccess, argAccess);
+                dispatchTask(vop,len);
+            }
+        }
+
+        PY_IMATH_RETURN_PYTHON;
+        return array;
+    }
+
+    static std::string
+    format_arguments(const boost::python::detail::keywords<1> &args)
+    {
+        // TODO: add types here
+        return std::string("(")+args.elements[0].name+") - ";
+    }
+};
+
+//
+// special class to handle single argument void memberfunctions, such as those
+// used for the inplace operators like +=, -=, etc.  In this case we allow additional
+// compatibilty between a masked class and an unmasked right hand side, using the
+// mask to select results.
+//
+template <class Op, class Func>
+struct VectorizedVoidMaskableMemberFunction1 {
+    BOOST_STATIC_ASSERT((2 == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+
+    typedef typename access_type<typename traits::arg1_type>::reference_type reference_type;
+    typedef typename access_type<typename traits::arg1_type>::direct direct_access_type;
+    typedef typename access_type<typename traits::arg1_type>::masked masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg2_type,
+                                                   boost::mpl::true_>::type arg1_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                                                   boost::mpl::true_>::direct arg1_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                                                   boost::mpl::true_>::masked arg1_masked_access_type;
+
+    static reference_type
+    apply(reference_type array, arg1_type arg1)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = array.match_dimension(arg1, false);
+        op_precompute<Op>::apply(len);
+
+        if (array.isMaskedReference() && (size_t) arg1.len() == array.unmaskedLength())
+        {
+            // class is masked, and the unmasked length matches the right hand side
+
+            masked_access_type arrayAccess (array);
+
+            if (any_masked(arg1))
+            {
+                arg1_masked_access_type argAccess =
+                     getArrayAccess<arg1_masked_access_type> (arg1);
+
+                VectorizedMaskedVoidOperation1<Op,masked_access_type,
+                                             arg1_masked_access_type,
+                                                      reference_type>
+                    vop (arrayAccess, argAccess, array);
+                dispatchTask(vop,len);
+            }
+            else
+            {
+                arg1_direct_access_type argAccess =
+                     getArrayAccess<arg1_direct_access_type> (arg1);
+
+                VectorizedMaskedVoidOperation1<Op,masked_access_type,
+                                             arg1_direct_access_type,
+                                                      reference_type>
+                    vop (arrayAccess, argAccess, array);
+                dispatchTask(vop,len);
+            }
+        }
+        else
+        {
+            // the two arrays match length (masked or otherwise), use the standard path.
+
+            if (any_masked(array))
+            {
+                masked_access_type arrayAccess (array);
+
+                if (any_masked(arg1))
+                {
+                    arg1_masked_access_type argAccess =
+                         getArrayAccess<arg1_masked_access_type> (arg1);
+
+                    VectorizedVoidOperation1<Op,masked_access_type,arg1_masked_access_type>
+                        vop (arrayAccess, argAccess);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg1_direct_access_type argAccess =
+                         getArrayAccess<arg1_direct_access_type> (arg1);
+
+                    VectorizedVoidOperation1<Op,masked_access_type,arg1_direct_access_type>
+                        vop (arrayAccess, argAccess);
+                    dispatchTask(vop,len);
+                }
+            }
+            else
+            {
+                direct_access_type arrayAccess (array);
+
+                if (any_masked(arg1))
+                {
+                    arg1_masked_access_type argAccess =
+                         getArrayAccess<arg1_masked_access_type> (arg1);
+
+                    VectorizedVoidOperation1<Op,direct_access_type,arg1_masked_access_type>
+                        vop (arrayAccess, argAccess);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg1_direct_access_type argAccess =
+                         getArrayAccess<arg1_direct_access_type> (arg1);
+
+                    VectorizedVoidOperation1<Op,direct_access_type,arg1_direct_access_type>
+                        vop (arrayAccess, argAccess);
+                    dispatchTask(vop,len);
+                }
+            }
+        }
+           
+        PY_IMATH_RETURN_PYTHON;
+        return array;
+    }
+
+    static std::string
+    format_arguments(const boost::python::detail::keywords<1> &args)
+    {
+        // TODO: add types here
+        return std::string("(")+args.elements[0].name+") - ";
+    }
+};
+
+template <class Op, class Vectorize, class Func>
+struct VectorizedVoidMemberFunction2 {
+    BOOST_STATIC_ASSERT((size<Vectorize>::value+1 == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+
+    typedef typename access_type<typename traits::arg1_type>::reference_type reference_type;
+    typedef typename access_type<typename traits::arg1_type>::direct direct_access_type;
+    typedef typename access_type<typename traits::arg1_type>::masked masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::type arg1_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::direct arg1_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::masked arg1_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<1> >::type>::type arg2_type;
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<1> >::type>::direct arg2_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<1> >::type>::masked arg2_masked_access_type;
+
+    static reference_type
+    apply(reference_type array, arg1_type arg1, arg2_type arg2)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = measure_arguments(array,arg1,arg2);
+        op_precompute<Op>::apply(len);
+
+        if (any_masked(array))
+        {
+            masked_access_type arrayAccess (array);
+
+            if (any_masked(arg1))
+            {
+                arg1_masked_access_type arg1Access =
+                     getArrayAccess<arg1_masked_access_type> (arg1);
+
+                if (any_masked(arg2))
+                {
+                    arg2_masked_access_type arg2Access =
+                         getArrayAccess<arg2_masked_access_type> (arg2);
+
+                    VectorizedVoidOperation2<Op,masked_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_masked_access_type>
+                          vop (arrayAccess, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg2_direct_access_type arg2Access =
+                         getArrayAccess<arg2_direct_access_type> (arg2);
+
+                    VectorizedVoidOperation2<Op,masked_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_direct_access_type>
+                          vop (arrayAccess, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+            }
+            else
+            {
+                arg1_direct_access_type arg1Access =
+                     getArrayAccess<arg1_direct_access_type> (arg1);
+
+                if (any_masked(arg2))
+                {
+                    arg2_masked_access_type arg2Access =
+                         getArrayAccess<arg2_masked_access_type> (arg2);
+
+                    VectorizedVoidOperation2<Op,masked_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_masked_access_type>
+                          vop (arrayAccess, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg2_direct_access_type arg2Access =
+                         getArrayAccess<arg2_direct_access_type> (arg2);
+
+                    VectorizedVoidOperation2<Op,masked_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_direct_access_type>
+                          vop (arrayAccess, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+            }
+        }
+        else
+        {
+            direct_access_type arrayAccess (array);
+
+            if (any_masked(arg1))
+            {
+                arg1_masked_access_type arg1Access =
+                     getArrayAccess<arg1_masked_access_type> (arg1);
+
+                if (any_masked(arg2))
+                {
+                    arg2_masked_access_type arg2Access =
+                         getArrayAccess<arg2_masked_access_type> (arg2);
+
+                    VectorizedVoidOperation2<Op,direct_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_masked_access_type>
+                          vop (arrayAccess, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg2_direct_access_type arg2Access =
+                         getArrayAccess<arg2_direct_access_type> (arg2);
+
+                    VectorizedVoidOperation2<Op,direct_access_type,
+                                           arg1_masked_access_type,
+                                           arg2_direct_access_type>
+                          vop (arrayAccess, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+            }
+            else
+            {
+                arg1_direct_access_type arg1Access =
+                     getArrayAccess<arg1_direct_access_type> (arg1);
+
+                if (any_masked(arg2))
+                {
+                    arg2_masked_access_type arg2Access =
+                         getArrayAccess<arg2_masked_access_type> (arg2);
+
+                    VectorizedVoidOperation2<Op,direct_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_masked_access_type>
+                          vop (arrayAccess, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg2_direct_access_type arg2Access =
+                         getArrayAccess<arg2_direct_access_type> (arg2);
+
+                    VectorizedVoidOperation2<Op,direct_access_type,
+                                           arg1_direct_access_type,
+                                           arg2_direct_access_type>
+                          vop (arrayAccess, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+            }
+        }
+
+        PY_IMATH_RETURN_PYTHON;
+        return array;
+    }
+
+    static std::string
+    format_arguments(const boost::python::detail::keywords<2> &args)
+    {
+        // TODO: add types here
+        return std::string("(")+args.elements[0].name+","+args.elements[1].name+") - ";
+    }
+};
+
+
+template <class Op, class Vectorize, class Func>
+struct VectorizedMemberFunction0 {
+    BOOST_STATIC_ASSERT((size<Vectorize>::value+1 == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+
+    typedef typename vectorized_result_type<typename traits::result_type,true_>::type result_type;
+
+    typedef typename access_type<typename traits::arg1_type>::reference_type reference_type;
+    typedef typename access_type<typename traits::arg1_type>::direct direct_access_type;
+    typedef typename access_type<typename traits::arg1_type>::masked masked_access_type;
+
+    // The return value can't be const or masked.  Verify that condition.
+    BOOST_STATIC_ASSERT( !is_const<result_type>::value );
+    typedef typename result_type::WritableDirectAccess result_access_type;
+
+    static result_type
+    apply(reference_type array)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = measure_arguments(array);
+        op_precompute<Op>::apply(len);
+        result_type retval = create_uninitalized_return_value<result_type>::apply(len);
+
+        result_access_type returnAccess (retval);
+
+        if (any_masked(array))
+        {
+            masked_access_type access (array);
+            VectorizedOperation1<Op,result_access_type,masked_access_type> vop(returnAccess,access);
+            dispatchTask(vop,len);
+        }
+        else
+        {
+            direct_access_type access (array);
+            VectorizedOperation1<Op,result_access_type,direct_access_type> vop(returnAccess,access);
+            dispatchTask(vop,len);
+        }
+
+        PY_IMATH_RETURN_PYTHON;
+        return retval;
+    }
+};
+
+template <class Op, class Vectorize, class Func>
+struct VectorizedMemberFunction1 {
+    BOOST_STATIC_ASSERT((size<Vectorize>::value+1 == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+
+    typedef typename vectorized_result_type<typename traits::result_type,true_>::type result_type;
+
+    typedef typename access_type<typename traits::arg1_type>::reference_type reference_type;
+    typedef typename access_type<typename traits::arg1_type>::direct direct_access_type;
+    typedef typename access_type<typename traits::arg1_type>::masked masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::type arg1_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::direct arg1_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::masked arg1_masked_access_type;
+
+    // The return value can't be const or masked.  Verify that condition.
+    BOOST_STATIC_ASSERT( !is_const<result_type>::value );
+    typedef typename result_type::WritableDirectAccess result_access_type;
+
+    static result_type
+    apply(reference_type array, arg1_type arg1)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = measure_arguments(array,arg1);
+        op_precompute<Op>::apply(len);
+        result_type retval = create_uninitalized_return_value<result_type>::apply(len);
+
+        result_access_type returnAccess (retval);
+
+        if (any_masked(array))
+        {
+            masked_access_type access (array);
+
+            if (any_masked(arg1))
+            {
+                arg1_masked_access_type argAccess =
+                     getArrayAccess<arg1_masked_access_type> (arg1);
+
+                VectorizedOperation2<Op,result_access_type,
+                                        masked_access_type,
+                                   arg1_masked_access_type> vop (returnAccess, access, argAccess);
+                dispatchTask(vop,len);
+            }
+            else
+            {
+                arg1_direct_access_type argAccess =
+                     getArrayAccess<arg1_direct_access_type> (arg1);
+
+                VectorizedOperation2<Op,result_access_type,
+                                        masked_access_type,
+                                   arg1_direct_access_type> vop (returnAccess, access, argAccess);
+                dispatchTask(vop,len);
+            }
+        }
+        else
+        {
+            direct_access_type access (array);
+
+            if (any_masked(arg1))
+            {
+                arg1_masked_access_type argAccess =
+                     getArrayAccess<arg1_masked_access_type> (arg1);
+
+                VectorizedOperation2<Op,result_access_type,
+                                        direct_access_type,
+                                   arg1_masked_access_type> vop (returnAccess, access, argAccess);
+                dispatchTask(vop,len);
+            }
+            else
+            {
+                arg1_direct_access_type argAccess =
+                     getArrayAccess<arg1_direct_access_type> (arg1);
+
+                VectorizedOperation2<Op,result_access_type,
+                                        direct_access_type,
+                                   arg1_direct_access_type> vop (returnAccess, access, argAccess);
+                dispatchTask(vop,len);
+            }
+        }
+
+        PY_IMATH_RETURN_PYTHON;
+        return retval;
+    }
+
+    static std::string
+    format_arguments(const boost::python::detail::keywords<1> &args)
+    {
+        // TODO: add types here
+        return std::string("(")+args.elements[0].name+") - ";
+    }
+};
+
+template <class Op, class Vectorize, class Func>
+struct VectorizedMemberFunction2 {
+    BOOST_STATIC_ASSERT((size<Vectorize>::value+1 == function_traits<Func>::arity));
+
+    typedef function_traits<Func> traits;
+
+    typedef typename vectorized_result_type<typename traits::result_type,true_>::type result_type;
+
+    typedef typename access_type<typename traits::arg1_type>::reference_type reference_type;
+    typedef typename access_type<typename traits::arg1_type>::direct direct_access_type;
+    typedef typename access_type<typename traits::arg1_type>::masked masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::type arg1_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::direct arg1_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg2_type,
+                              typename at<Vectorize,long_<0> >::type>::masked arg1_masked_access_type;
+
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<1> >::type>::type arg2_type;
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<1> >::type>::direct arg2_direct_access_type;
+    typedef typename argument_access_type<typename traits::arg3_type,
+                              typename at<Vectorize,long_<1> >::type>::masked arg2_masked_access_type;
+
+    // The return value can't be const or masked.  Verify that condition.
+    BOOST_STATIC_ASSERT( !is_const<result_type>::value );
+    typedef typename result_type::WritableDirectAccess result_access_type;
+
+    static result_type
+    apply(reference_type array, arg1_type arg1, arg2_type arg2)
+    {
+        PY_IMATH_LEAVE_PYTHON;
+        size_t len = measure_arguments(array,arg1,arg2);
+        op_precompute<Op>::apply(len);
+        result_type retval = create_uninitalized_return_value<result_type>::apply(len);
+
+        result_access_type returnAccess (retval);
+
+        if (any_masked(array))
+        {
+            masked_access_type access (array);
+
+            if (any_masked(arg1))
+            {
+                arg1_masked_access_type arg1Access =
+                     getArrayAccess<arg1_masked_access_type> (arg1);
+
+                if (any_masked(arg2))
+                {
+                    arg2_masked_access_type arg2Access =
+                         getArrayAccess<arg2_masked_access_type> (arg2);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                            masked_access_type,
+                                       arg1_masked_access_type,
+                                       arg2_masked_access_type>
+                        vop (returnAccess, access, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg2_direct_access_type arg2Access =
+                         getArrayAccess<arg2_direct_access_type> (arg2);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                            masked_access_type,
+                                       arg1_masked_access_type,
+                                       arg2_direct_access_type>
+                        vop (returnAccess, access, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+            }
+            else
+            {
+                arg1_direct_access_type arg1Access =
+                     getArrayAccess<arg1_direct_access_type> (arg1);
+
+                if (any_masked(arg2))
+                {
+                    arg2_masked_access_type arg2Access =
+                         getArrayAccess<arg2_masked_access_type> (arg2);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                            masked_access_type,
+                                       arg1_direct_access_type,
+                                       arg2_masked_access_type>
+                        vop (returnAccess, access, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg2_direct_access_type arg2Access =
+                         getArrayAccess<arg2_direct_access_type> (arg2);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                            masked_access_type,
+                                       arg1_direct_access_type,
+                                       arg2_direct_access_type>
+                        vop (returnAccess, access, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+            }
+        }
+        else
+        {
+            direct_access_type access (array);
+
+            if (any_masked(arg1))
+            {
+                arg1_masked_access_type arg1Access =
+                     getArrayAccess<arg1_masked_access_type> (arg1);
+
+                if (any_masked(arg2))
+                {
+                    arg2_masked_access_type arg2Access =
+                         getArrayAccess<arg2_masked_access_type> (arg2);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                            direct_access_type,
+                                       arg1_masked_access_type,
+                                       arg2_masked_access_type>
+                        vop (returnAccess, access, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg2_direct_access_type arg2Access =
+                         getArrayAccess<arg2_direct_access_type> (arg2);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                            direct_access_type,
+                                       arg1_masked_access_type,
+                                       arg2_direct_access_type>
+                        vop (returnAccess, access, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+            }
+            else
+            {
+                arg1_direct_access_type arg1Access =
+                     getArrayAccess<arg1_direct_access_type> (arg1);
+
+                if (any_masked(arg2))
+                {
+                    arg2_masked_access_type arg2Access =
+                         getArrayAccess<arg2_masked_access_type> (arg2);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                            direct_access_type,
+                                       arg1_direct_access_type,
+                                       arg2_masked_access_type>
+                        vop (returnAccess, access, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+                else
+                {
+                    arg2_direct_access_type arg2Access =
+                         getArrayAccess<arg2_direct_access_type> (arg2);
+
+                    VectorizedOperation3<Op,result_access_type,
+                                            direct_access_type,
+                                       arg1_direct_access_type,
+                                       arg2_direct_access_type>
+                        vop (returnAccess, access, arg1Access, arg2Access);
+                    dispatchTask(vop,len);
+                }
+            }
+        }
+
+        PY_IMATH_RETURN_PYTHON;
+        return retval;
+    }
+
+    static std::string
+    format_arguments(const boost::python::detail::keywords<2> &args)
+    {
+        // TODO: add types here
+        return std::string("(")+args.elements[0].name+","+args.elements[1].name+") - ";
+    }
+};
+
+template <class Op, class Cls, class Func, class Keywords>
+struct member_function_binding
+{
+    Cls &_cls;
+    std::string _name, _doc;
+    const Keywords &_args;
+
+    member_function_binding(Cls &cls,const std::string &name, const std::string &doc,const Keywords &args)
+        : _cls(cls), _name(name), _doc(doc), _args(args)
+    {}
+
+    template <class Vectorize>
+    void operator()(Vectorize) const
+    {
+        typedef typename if_<is_same<void,typename function_traits<Func>::result_type>,
+                             typename if_<boost::mpl::equal<Vectorize,boost::mpl::vector<boost::mpl::true_> >,
+                                 VectorizedVoidMaskableMemberFunction1<Op,Func>,
+                                 VectorizedVoidMemberFunction1<Op,Vectorize,Func> >::type,
+                             VectorizedMemberFunction1<Op,Vectorize,Func>
+                         >::type member_func1_type;
+
+        typedef typename if_<is_same<void,typename function_traits<Func>::result_type>,
+                         VectorizedVoidMemberFunction2<Op,Vectorize,Func>,
+                         VectorizedMemberFunction2<Op,Vectorize,Func> >::type member_func2_type;
+
+        typedef typename if_<is_same<void,typename function_traits<Func>::result_type>,
+                         boost::python::return_internal_reference<>,  // the void vectorizations return a reference to self
+                         boost::python::default_call_policies>::type call_policies;
+
+        typedef typename at<vector<
+            int,  // unused, arity 0
+            int,  // unused, arity 1 - first argument corresponds to the class type
+            member_func1_type,
+            member_func2_type
+            >,
+            long_<function_traits<Func>::arity> >::type vectorized_function_type;
+        std::string doc = _name + vectorized_function_type::format_arguments(_args) + _doc;
+        _cls.def(_name.c_str(),&vectorized_function_type::apply,doc.c_str(),_args,call_policies());
+    }
+};
+
+template <class Op,class Cls,class Func,class Keywords>
+member_function_binding<Op,Cls,Func,Keywords>
+build_member_function_binding(Cls &cls,Func *func,const std::string &name,const std::string &doc,const Keywords &args)
+{
+    return member_function_binding<Op,Cls,Func,Keywords>(cls,name,doc,args);
+}
+
+template <class Op,class Cls,class Vectorizable,class Keywords>
+struct generate_member_bindings_struct
+{
+    //BOOST_STATIC_ASSERT(size<Vectorizable>::value+1 == function_traits<Op::apply>::arity);
+    static void apply(Cls &cls,const std::string &name,const std::string &doc,const Keywords &args) {
+        for_each<typename allowable_vectorizations<Vectorizable>::type>(build_member_function_binding<Op>(cls,Op::apply,name,doc,args));
+    }
+};
+
+template <class Op,class Cls,class Func>
+void
+generate_single_member_binding(Cls &cls,Func *func,const std::string &name,const std::string &doc)
+{
+    typedef typename if_<is_same<void,typename function_traits<Func>::result_type>,
+                         VectorizedVoidMemberFunction0<Op,boost::mpl::vector<>,Func>,
+                         VectorizedMemberFunction0<Op,boost::mpl::vector<>,Func> >::type vectorized_function_type;
+
+    typedef typename if_<is_same<void,typename function_traits<Func>::result_type>,
+                         boost::python::return_internal_reference<>,  // the void vectorizations return a reference to self
+                         boost::python::default_call_policies>::type call_policies;
+
+    cls.def(name.c_str(),&vectorized_function_type::apply,doc.c_str(),call_policies());
+}
+
+} // namespace detail
+
+// TODO: update for arg("name")=default_value syntax
+template <class Op,class Vectorizable0>
+void generate_bindings(const std::string &name,const std::string &doc,const boost::python::detail::keywords<1> &args) {
+    using namespace detail;
+    generate_bindings_struct<Op,vector<Vectorizable0>,boost::python::detail::keywords<1> >::apply(name,doc,args);
+}
+
+template <class Op,class Vectorizable0, class Vectorizable1>
+void generate_bindings(const std::string &name,const std::string &doc,const boost::python::detail::keywords<2> &args) {
+    using namespace detail;
+    generate_bindings_struct<Op,vector<Vectorizable0,Vectorizable1>,boost::python::detail::keywords<2> >::apply(name,doc,args);
+}
+
+template <class Op,class Vectorizable0, class Vectorizable1, class Vectorizable2>
+void generate_bindings(const std::string &name,const std::string &doc,const boost::python::detail::keywords<3> &args) {
+    using namespace detail;
+    generate_bindings_struct<Op,vector<Vectorizable0,Vectorizable1,Vectorizable2>,boost::python::detail::keywords<3> >::apply(name,doc,args);
+}
+
+template <class Op,class Vectorizable0, class Vectorizable1, class Vectorizable2, class Vectorizable3>
+void generate_bindings(const std::string &name,const std::string &doc,const boost::python::detail::keywords<4> &args) {
+    using namespace detail;
+    generate_bindings_struct<Op,vector<Vectorizable0,Vectorizable1,Vectorizable2,Vectorizable3>,boost::python::detail::keywords<4> >::apply(name,doc,args);
+}
+
+template <class Op,class Vectorizable0, class Vectorizable1, class Vectorizable2, class Vectorizable3, class Vectorizable4>
+void generate_bindings(const std::string &name,const std::string &doc,const boost::python::detail::keywords<5> &args) {
+    using namespace detail;
+    generate_bindings_struct<Op,vector<Vectorizable0,Vectorizable1,Vectorizable2,Vectorizable3,Vectorizable4>,boost::python::detail::keywords<5> >::apply(name,doc,args);
+}
+
+template <class Op,class Cls>
+void
+generate_member_bindings(Cls &cls,const std::string &name,const std::string &doc)
+{
+    using namespace detail;
+    generate_single_member_binding<Op>(cls,&Op::apply,name,doc);
+}
+
+template <class Op,class Vectorizable0,class Cls>
+void
+generate_member_bindings(Cls &cls,const std::string &name,const std::string &doc,
+                         const boost::python::detail::keywords<1> &args)
+{
+    using boost::mpl::vector;
+    detail::generate_member_bindings_struct<Op,Cls,vector<Vectorizable0>,
+                                            boost::python::detail::keywords<1> >::apply(cls,name,doc,args);
+}
+
+template <class Op,class Vectorizable0,class Vectorizable1,class Cls>
+void
+generate_member_bindings(Cls &cls,const std::string &name,const std::string &doc,
+                         const boost::python::detail::keywords<2> &args)
+{
+    using boost::mpl::vector;
+    detail::generate_member_bindings_struct<Op,Cls,vector<Vectorizable0,Vectorizable1>,
+                                            boost::python::detail::keywords<2> >::apply(cls,name,doc,args);
+}
+
+} // namespace PyImath
+
+#endif // _PyImathAutovectorize_h_
diff --git a/src/python/PyImath/PyImathBasicTypes.cpp b/src/python/PyImath/PyImathBasicTypes.cpp
new file mode 100644 (file)
index 0000000..dfc3b4b
--- /dev/null
@@ -0,0 +1,95 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include "PyImath.h"
+#include "PyImathExport.h"
+#include "PyImathBasicTypes.h"
+#include "PyImathFixedArray.h"
+#include "PyImathFixedVArray.h"
+#include "PyImathBufferProtocol.h"
+
+using namespace boost::python;
+
+namespace PyImath {
+
+void
+register_basicTypes()
+{
+    class_<BoolArray> bclass = BoolArray::register_("Fixed length array of bool");
+    add_comparison_functions(bclass);
+
+    class_<SignedCharArray> scclass = SignedCharArray::register_("Fixed length array of signed chars");
+    add_arithmetic_math_functions(scclass);
+    add_mod_math_functions(scclass);
+    add_comparison_functions(scclass);
+    add_ordered_comparison_functions(scclass);
+
+    class_<UnsignedCharArray> ucclass = UnsignedCharArray::register_("Fixed length array of unsigned chars");
+    add_arithmetic_math_functions(ucclass);
+    add_mod_math_functions(ucclass);
+    add_comparison_functions(ucclass);
+    add_ordered_comparison_functions(ucclass);
+    add_buffer_protocol<UnsignedCharArray>(ucclass);
+
+    class_<ShortArray> sclass = ShortArray::register_("Fixed length array of shorts");
+    add_arithmetic_math_functions(sclass);
+    add_mod_math_functions(sclass);
+    add_comparison_functions(sclass);
+    add_ordered_comparison_functions(sclass);
+
+    class_<UnsignedShortArray> usclass = UnsignedShortArray::register_("Fixed length array of unsigned shorts");
+    add_arithmetic_math_functions(usclass);
+    add_mod_math_functions(usclass);
+    add_comparison_functions(usclass);
+    add_ordered_comparison_functions(usclass);
+
+    class_<IntArray> iclass = IntArray::register_("Fixed length array of ints");
+    add_arithmetic_math_functions(iclass);
+    add_mod_math_functions(iclass);
+    add_comparison_functions(iclass);
+    add_ordered_comparison_functions(iclass);
+    add_explicit_construction_from_type<float>(iclass);
+    add_explicit_construction_from_type<double>(iclass);
+    add_buffer_protocol<IntArray>(iclass);
+
+    class_<UnsignedIntArray> uiclass = UnsignedIntArray::register_("Fixed length array of unsigned ints");
+    add_arithmetic_math_functions(uiclass);
+    add_mod_math_functions(uiclass);
+    add_comparison_functions(uiclass);
+    add_ordered_comparison_functions(uiclass);
+    add_explicit_construction_from_type<float>(uiclass);
+    add_explicit_construction_from_type<double>(uiclass);
+
+    class_<FloatArray> fclass = FloatArray::register_("Fixed length array of floats");
+    add_arithmetic_math_functions(fclass);
+    add_pow_math_functions(fclass);
+    add_comparison_functions(fclass);
+    add_ordered_comparison_functions(fclass);
+    add_explicit_construction_from_type<int>(fclass);
+    add_explicit_construction_from_type<double>(fclass);
+    add_buffer_protocol<FloatArray>(fclass);
+
+    class_<DoubleArray> dclass = DoubleArray::register_("Fixed length array of doubles");
+    add_arithmetic_math_functions(dclass);
+    add_pow_math_functions(dclass);
+    add_comparison_functions(dclass);
+    add_ordered_comparison_functions(dclass);
+    add_explicit_construction_from_type<int>(dclass);
+    add_explicit_construction_from_type<float>(dclass);
+    add_buffer_protocol<DoubleArray>(dclass);
+
+    class_<VIntArray>   ivclass = VIntArray::register_("Variable fixed length array of ints");
+    class_<VFloatArray> fvclass = VFloatArray::register_("Variable fixed length array of floats");
+    class_<VV2iArray> v2ivclass = VV2iArray::register_("Variable fixed length array of V2i");
+    class_<VV2fArray> v2fvclass = VV2fArray::register_("Variable fixed length array of V2f");
+    // Don't add other functionality until its defined better.
+}
+
+} // namespace PyImath
diff --git a/src/python/PyImath/PyImathBasicTypes.h b/src/python/PyImath/PyImathBasicTypes.h
new file mode 100644 (file)
index 0000000..16c5ad5
--- /dev/null
@@ -0,0 +1,20 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+
+#ifndef _PyImathBasicTypes_h_
+#define _PyImathBasicTypes_h_
+
+#include "PyImathExport.h"
+
+namespace PyImath {
+
+PYIMATH_EXPORT void register_basicTypes();
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathBox.cpp b/src/python/PyImath/PyImathBox.cpp
new file mode 100644 (file)
index 0000000..cb0885a
--- /dev/null
@@ -0,0 +1,398 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <boost/python/make_constructor.hpp>
+#include <vector>
+#include <ImathBoxAlgo.h>
+#include "PyImathBox.h"
+#include "PyImathVec.h"
+#include "PyImathMathExc.h"
+#include "PyImathDecorators.h"
+#include "PyImathExport.h"
+#include "PyImathTask.h"
+#include "PyImathBoxArrayImpl.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+using namespace PyImath;
+
+template <class T> struct BoxName { static const char *value; };
+template <> const char *BoxName<IMATH_NAMESPACE::V2s>::value   = "Box2s";
+template <> const char *BoxName<IMATH_NAMESPACE::V2i>::value   = "Box2i";
+template <> const char *BoxName<IMATH_NAMESPACE::V2i64>::value = "Box2i64";
+template <> const char *BoxName<IMATH_NAMESPACE::V2f>::value   = "Box2f";
+template <> const char *BoxName<IMATH_NAMESPACE::V2d>::value   = "Box2d";
+template <> const char *BoxName<IMATH_NAMESPACE::V3s>::value   = "Box3s";
+template <> const char *BoxName<IMATH_NAMESPACE::V3i>::value   = "Box3i";
+template <> const char *BoxName<IMATH_NAMESPACE::V3i64>::value = "Box3i64";
+template <> const char *BoxName<IMATH_NAMESPACE::V3f>::value   = "Box3f";
+template <> const char *BoxName<IMATH_NAMESPACE::V3d>::value   = "Box3d";
+
+template <> PYIMATH_EXPORT const char *PyImath::Box2sArray::name()   { return "Box2sArray"; }
+template <> PYIMATH_EXPORT const char *PyImath::Box2iArray::name()   { return "Box2iArray"; }
+template <> PYIMATH_EXPORT const char *PyImath::Box2i64Array::name() { return "Box2i64Array"; }
+template <> PYIMATH_EXPORT const char *PyImath::Box2fArray::name()   { return "Box2fArray"; }
+template <> PYIMATH_EXPORT const char *PyImath::Box2dArray::name()   { return "Box2dArray"; }
+template <> PYIMATH_EXPORT const char *PyImath::Box3sArray::name()   { return "Box3sArray"; }
+template <> PYIMATH_EXPORT const char *PyImath::Box3iArray::name()   { return "Box3iArray"; }
+template <> PYIMATH_EXPORT const char *PyImath::Box3i64Array::name() { return "Box3i64Array"; }
+template <> PYIMATH_EXPORT const char *PyImath::Box3fArray::name()   { return "Box3fArray"; }
+template <> PYIMATH_EXPORT const char *PyImath::Box3dArray::name()   { return "Box3dArray"; }
+
+template <class T>
+static Box<T> * box2TupleConstructor1(const tuple &t)
+{
+    if(t.attr("__len__")() == 2)
+    {
+        // The constructor was called like this:
+        // Box2f ((V2f(1,2), V2f(3,4))) or
+        // Box2f (((1,2), (3,4)))
+
+        PyObject *t0Obj = extract <object> (t[0])().ptr();
+        PyObject *t1Obj = extract <object> (t[1])().ptr();
+        T t0, t1;
+        if (V2<typename T::BaseType>::convert (t0Obj, &t0) &&
+            V2<typename T::BaseType>::convert (t1Obj, &t1))
+        {
+            return new Box<T> (t0, t1);
+        }
+
+        // The constructor was called like this:
+        // Box2f ((1,2))
+
+        else
+        {
+            T point;
+            point.x = extract<double>(t[0]);
+            point.y = extract<double>(t[1]);
+            return new Box<T>(point);
+        }
+    }
+    else
+      throw std::invalid_argument ( "Invalid input to Box tuple constructor");
+}
+
+template <class T>
+static Box<T> * box2TupleConstructor2(const tuple &t0, const tuple &t1)
+{
+    if(t0.attr("__len__")() == 2 && t1.attr("__len__")() == 2)
+    {
+        T point0, point1;
+        point0.x = extract<double>(t0[0]); point0.y = extract<double>(t0[1]);
+        point1.x = extract<double>(t1[0]); point1.y = extract<double>(t1[1]);
+        
+        return new Box<T>(point0, point1);
+    }
+    else
+      throw std::invalid_argument ("Invalid input to Box tuple constructor");
+}
+
+template <class T, class S>
+static Box<T> *boxConstructor(const Box<S> &box)
+{
+    Box<T> *newBox = new Box<T>;
+    newBox->min = box.min;
+    newBox->max = box.max;
+    
+    return newBox;
+}
+
+template <class T>
+static Box<T> * box3TupleConstructor1(const tuple &t)
+{
+    if(t.attr("__len__")() == 3)
+    {
+        // The constructor was called like this:
+        // Box3f ((1,2,3))
+
+        T point;
+        point.x = extract<double>(t[0]);
+        point.y = extract<double>(t[1]);
+        point.z = extract<double>(t[2]);
+        return new Box<T>(point);
+    }
+
+    else if (t.attr("__len__")() == 2)
+    {
+        // The constructor was called like this:
+        // Box3f ((V3f(1,2,3), V3f(4,5,6))) or
+        // Box3f (((1,2,3), (4,5,6)))
+
+        PyObject *t0Obj = extract <object> (t[0])().ptr();
+        PyObject *t1Obj = extract <object> (t[1])().ptr();
+        T t0, t1;
+        if (V3<typename T::BaseType>::convert (t0Obj, &t0) &&
+            V3<typename T::BaseType>::convert (t1Obj, &t1))
+        {
+            return new Box<T> (t0, t1);
+        }
+        else
+          throw std::invalid_argument ("Invalid input to Box tuple constructor");
+    }
+
+    else
+      throw std::invalid_argument ("Invalid input to Box tuple constructor");
+}
+
+template <class T>
+static Box<T> * box3TupleConstructor2(const tuple &t0, const tuple &t1)
+{
+    if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3)
+    {
+        T point0, point1;
+        point0.x = extract<double>(t0[0]); 
+        point0.y = extract<double>(t0[1]);
+        point0.z = extract<double>(t0[2]);
+        
+        point1.x = extract<double>(t1[0]); 
+        point1.y = extract<double>(t1[1]);
+        point1.z = extract<double>(t1[2]);
+        
+        return new Box<T>(point0, point1);
+    }
+    else
+        throw std::invalid_argument ("Invalid input to Box tuple constructor");
+}
+
+template <class T>
+static std::string Box_repr(const Box<T> &box)
+{
+    std::stringstream stream;
+    typename boost::python::return_by_value::apply <T>::type converter;
+
+    handle<> minObj (converter (box.min));
+    handle<> minH (PYUTIL_OBJECT_REPR (minObj.get()));
+    std::string minReprStr = extract<std::string> (minH.get());
+
+    handle<> maxObj (converter (box.max));
+    handle<> maxH (PYUTIL_OBJECT_REPR (maxObj.get()));
+    std::string maxReprStr = extract<std::string> (maxH.get());
+
+    stream << BoxName<T>::value << "(" << minReprStr << ", " << maxReprStr << ")";
+    
+    return stream.str();
+}
+
+template <class T>
+static void boxSetMin(IMATH_NAMESPACE::Box<T> &box, const T &m)
+{
+    box.min = m;
+}
+
+template <class T>
+static void boxSetMax(IMATH_NAMESPACE::Box<T> &box, const T &m)
+{
+    box.max = m;
+}
+
+template <class T>
+static T
+boxMin(IMATH_NAMESPACE::Box<T> &box)
+{
+    return box.min;
+}
+
+template <class T>
+static T
+boxMax(IMATH_NAMESPACE::Box<T> &box)
+{
+    return box.max;
+}
+
+template <class T>
+struct IntersectsTask : public Task
+{
+    const IMATH_NAMESPACE::Box<T>& box;
+    const PyImath::FixedArray<T>& points;
+    PyImath::FixedArray<int>& results;
+
+    IntersectsTask(IMATH_NAMESPACE::Box<T>& b, const PyImath::FixedArray<T> &p, PyImath::FixedArray<int> &r)
+        : box(b), points(p), results(r) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for(size_t p = start; p < end; ++p) 
+            results[p] = box.intersects(points[p]);
+    }
+};
+
+template <class T>
+struct ExtendByTask : public Task
+{
+    std::vector<IMATH_NAMESPACE::Box<T> >& boxes;
+    const PyImath::FixedArray<T>& points;
+
+    ExtendByTask(std::vector<IMATH_NAMESPACE::Box<T> >& b, const PyImath::FixedArray<T> &p)
+        : boxes(b), points(p) {}
+
+    void execute(size_t start, size_t end, int tid)
+    {
+        for(size_t p = start; p < end; ++p) 
+            boxes[tid].extendBy(points[p]);
+    }
+    void execute(size_t start, size_t end)
+    {
+        throw std::invalid_argument ("Box::ExtendBy execute requires a thread id");
+    }
+};
+
+template <class T>
+static void
+box_extendBy(IMATH_NAMESPACE::Box<T> &box, const PyImath::FixedArray<T> &points)
+{
+    size_t numBoxes = workers();
+    std::vector<IMATH_NAMESPACE::Box<T> > boxes(numBoxes);
+    ExtendByTask<T> task(boxes,points);
+    dispatchTask(task,points.len());
+    for (size_t i=0; i<numBoxes; ++i) {
+        box.extendBy(boxes[i]);
+    }
+}
+
+template <class T>
+PyImath::FixedArray<int>
+box_intersects(IMATH_NAMESPACE::Box<T>& box, const PyImath::FixedArray<T>& points)
+{
+    size_t numPoints = points.len();
+    PyImath::FixedArray<int> mask(numPoints);
+
+    IntersectsTask<T> task(box,points,mask);
+    dispatchTask(task,numPoints);
+    return mask;
+}
+
+template <class T>
+class_<IMATH_NAMESPACE::Box<T> >
+register_Box2()
+{
+    void (IMATH_NAMESPACE::Box<T>::*extendBy1)(const T&)              = &IMATH_NAMESPACE::Box<T>::extendBy;
+    void (IMATH_NAMESPACE::Box<T>::*extendBy2)(const IMATH_NAMESPACE::Box<T>&)  = &IMATH_NAMESPACE::Box<T>::extendBy;
+    bool (IMATH_NAMESPACE::Box<T>::*intersects1)(const T&) const              = &IMATH_NAMESPACE::Box<T>::intersects;
+    bool (IMATH_NAMESPACE::Box<T>::*intersects2)(const IMATH_NAMESPACE::Box<T>&) const  = &IMATH_NAMESPACE::Box<T>::intersects;
+    const char *name = BoxName<T>::value;
+    class_<Box<T> > box_class(name);
+    box_class
+        .def(init<>("Box() create empty box") )
+        .def(init<T>("Box(point)create box containing the given point") )
+        .def(init<T,T>("Box(point,point) create box continaing min and max") )
+        .def("__init__", make_constructor(box2TupleConstructor1<T>), "Box(point) where point is a python tuple")
+        .def("__init__", make_constructor(box2TupleConstructor2<T>), "Box(point,point) where point is a python tuple")
+        .def("__init__", make_constructor(boxConstructor<T, IMATH_NAMESPACE::V2f>))
+        .def("__init__", make_constructor(boxConstructor<T, IMATH_NAMESPACE::V2d>))
+        .def("__init__", make_constructor(boxConstructor<T, IMATH_NAMESPACE::V2i>))
+        .def("__init__", make_constructor(boxConstructor<T, IMATH_NAMESPACE::V2i64>))
+        .def_readwrite("min",&Box<T>::min)
+        .def_readwrite("max",&Box<T>::max)
+        .def("min", &boxMin<T>)
+        .def("max", &boxMax<T>)
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__repr__", &Box_repr<T>)
+        .def("makeEmpty",&Box<T>::makeEmpty,"makeEmpty() make the box empty")
+        .def("makeInfinite",&Box<T>::makeInfinite,"makeInfinite() make the box cover all space")
+        .def("extendBy",extendBy1,"extendBy(point) extend the box by a point")
+        .def("extendBy",box_extendBy<T>,"extendBy(array) extend the box the values in the array")
+        .def("extendBy",extendBy2,"extendBy(box) extend the box by a box")
+        .def("size",&Box<T>::size,"size() size of the box")
+        .def("center",&Box<T>::center,"center() center of the box")
+        .def("intersects",intersects1,"intersects(point) returns true if the box intersects the given point")
+        .def("intersects",intersects2,"intersects(box) returns true if the box intersects the given box")
+        .def("majorAxis",&Box<T>::majorAxis,"majorAxis() major axis of the box")
+        .def("isEmpty",&Box<T>::isEmpty,"isEmpty() returns true if the box is empty")
+        .def("isInfinite",&Box<T>::isInfinite,"isInfinite() returns true if the box covers all space")
+        .def("hasVolume",&Box<T>::hasVolume,"hasVolume() returns true if the box has volume")
+        .def("setMin",&boxSetMin<T>,"setMin() sets the min value of the box")
+        .def("setMax",&boxSetMax<T>,"setMax() sets the max value of the box")
+        ;
+    return box_class;
+}
+
+template <class T, class U>
+static IMATH_NAMESPACE::Box<T>
+mulM44 (const IMATH_NAMESPACE::Box<T> &b, const Matrix44<U> &m)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::transform (b, m);
+}
+
+template <class T, class U>
+static const IMATH_NAMESPACE::Box<T> &
+imulM44 (IMATH_NAMESPACE::Box<T> &b, const Matrix44<U> &m)
+{
+    MATH_EXC_ON;
+    b = IMATH_NAMESPACE::transform (b, m);
+    return b;
+}
+
+template <class T>
+class_<IMATH_NAMESPACE::Box<T> >
+register_Box3()
+{
+    void (IMATH_NAMESPACE::Box<T>::*extendBy1)(const T&)              = &IMATH_NAMESPACE::Box<T>::extendBy;
+    void (IMATH_NAMESPACE::Box<T>::*extendBy2)(const IMATH_NAMESPACE::Box<T>&)  = &IMATH_NAMESPACE::Box<T>::extendBy;
+    bool (IMATH_NAMESPACE::Box<T>::*intersects1)(const T&) const              = &IMATH_NAMESPACE::Box<T>::intersects;
+    bool (IMATH_NAMESPACE::Box<T>::*intersects2)(const IMATH_NAMESPACE::Box<T>&) const  = &IMATH_NAMESPACE::Box<T>::intersects;
+    const char *name = BoxName<T>::value;
+    class_<Box<T> > box_class(name);
+    box_class
+        .def(init<>("Box() create empty box") )
+        .def(init<T>("Box(point)create box containing the given point") )
+        .def(init<T,T>("Box(point,point) create box continaing min and max") )
+        .def("__init__", make_constructor(box3TupleConstructor1<T>), "Box(point) where point is a python tuple")
+        .def("__init__", make_constructor(box3TupleConstructor2<T>), "Box(point,point) where point is a python tuple")
+        .def("__init__", make_constructor(boxConstructor<T, IMATH_NAMESPACE::V3f>))
+        .def("__init__", make_constructor(boxConstructor<T, IMATH_NAMESPACE::V3d>))
+        .def("__init__", make_constructor(boxConstructor<T, IMATH_NAMESPACE::V3i>))
+        .def("__init__", make_constructor(boxConstructor<T, IMATH_NAMESPACE::V3i64>))
+        .def_readwrite("min",&Box<T>::min)
+        .def_readwrite("max",&Box<T>::max)
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__mul__", &mulM44<T, float>)
+        .def("__mul__", &mulM44<T, double>)
+        .def("__imul__", &imulM44<T, float>,return_internal_reference<>())
+        .def("__imul__", &imulM44<T, double>,return_internal_reference<>())
+        .def("min", &boxMin<T>)
+        .def("max", &boxMax<T>)
+        .def("__repr__", &Box_repr<T>)
+        .def("makeEmpty",&Box<T>::makeEmpty,"makeEmpty() make the box empty")
+        .def("makeInfinite",&Box<T>::makeInfinite,"makeInfinite() make the box cover all space")
+        .def("extendBy",extendBy1,"extendBy(point) extend the box by a point")
+        .def("extendBy",box_extendBy<T>,"extendBy(array) extend the box the values in the array")
+        .def("extendBy",extendBy2,"extendBy(box) extend the box by a box")
+        .def("size",&Box<T>::size,"size() size of the box")
+        .def("center",&Box<T>::center,"center() center of the box")
+        .def("intersects",intersects1,"intersects(point) returns true if the box intersects the given point")
+        .def("intersects",intersects2,"intersects(box) returns true if the box intersects the given box")
+        .def("intersects",box_intersects<T>, "intersects(array) returns an int array where 0 indicates the point is not in the box and 1 indicates that it is")
+        .def("majorAxis",&Box<T>::majorAxis,"majorAxis() major axis of the box")
+        .def("isEmpty",&Box<T>::isEmpty,"isEmpty() returns true if the box is empty")
+        .def("isInfinite",&Box<T>::isInfinite,"isInfinite() returns true if the box covers all space")
+        .def("hasVolume",&Box<T>::hasVolume,"hasVolume() returns true if the box has volume")
+        .def("setMin",&boxSetMin<T>,"setMin() sets the min value of the box")
+        .def("setMax",&boxSetMax<T>,"setMax() sets the max value of the box")
+        ;
+
+    decoratecopy(box_class);
+
+    return box_class;
+}
+
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V2s> >   register_Box2<IMATH_NAMESPACE::V2s>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V2i> >   register_Box2<IMATH_NAMESPACE::V2i>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V2i64> > register_Box2<IMATH_NAMESPACE::V2i64>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V2f> >   register_Box2<IMATH_NAMESPACE::V2f>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V2d> >   register_Box2<IMATH_NAMESPACE::V2d>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V3s> >   register_Box3<IMATH_NAMESPACE::V3s>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V3i> >   register_Box3<IMATH_NAMESPACE::V3i>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V3i64> > register_Box3<IMATH_NAMESPACE::V3i64>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V3f> >   register_Box3<IMATH_NAMESPACE::V3f>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V3d> >   register_Box3<IMATH_NAMESPACE::V3d>();
+
+}
diff --git a/src/python/PyImath/PyImathBox.h b/src/python/PyImath/PyImathBox.h
new file mode 100644 (file)
index 0000000..c41f3b6
--- /dev/null
@@ -0,0 +1,207 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathBox_h_
+#define _PyImathBox_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <ImathBox.h>
+#include "PyImathVec.h"
+#include "PyImathFixedArray.h"
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Box<T> > register_Box2();
+template <class T> boost::python::class_<IMATH_NAMESPACE::Box<T> > register_Box3();
+
+template <class T> boost::python::class_<FixedArray<IMATH_NAMESPACE::Box<T> > > register_BoxArray();
+
+typedef FixedArray<IMATH_NAMESPACE::Box2s>   Box2sArray;
+typedef FixedArray<IMATH_NAMESPACE::Box2i>   Box2iArray;
+typedef FixedArray<IMATH_NAMESPACE::Box2i64> Box2i64Array;
+typedef FixedArray<IMATH_NAMESPACE::Box2f>   Box2fArray;
+typedef FixedArray<IMATH_NAMESPACE::Box2d>   Box2dArray;
+
+typedef FixedArray<IMATH_NAMESPACE::Box3s>   Box3sArray;
+typedef FixedArray<IMATH_NAMESPACE::Box3i>   Box3iArray;
+typedef FixedArray<IMATH_NAMESPACE::Box3i64> Box3i64Array;
+typedef FixedArray<IMATH_NAMESPACE::Box3f>   Box3fArray;
+typedef FixedArray<IMATH_NAMESPACE::Box3d>   Box3dArray;
+
+//
+
+// Other code in the Zeno code base assumes the existance of a class with the
+// same name as the Imath class, and with static functions wrap() and
+// convert() to produce a PyImath object from an Imath object and vice-versa,
+// respectively.  The class Boost generates from the Imath class does not
+// have these properties, so we define a companion class here.
+// The template argument, T, is the element type for the box (e.g., int,
+// float).
+
+template <class T>
+class Box2 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Box< IMATH_NAMESPACE::Vec2<T> > &b);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Box< IMATH_NAMESPACE::Vec2<T> > *b);
+};
+
+template <class T>
+class Box3 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Box< IMATH_NAMESPACE::Vec3<T> > &b);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Box< IMATH_NAMESPACE::Vec3<T> > *v);
+};
+
+template <class T>
+PyObject *
+Box2<T>::wrap (const IMATH_NAMESPACE::Box< IMATH_NAMESPACE::Vec2<T> > &b)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Box< IMATH_NAMESPACE::Vec2<T> > >::type converter;
+    PyObject *p = converter (b);
+    return p;
+}
+
+template <class T>
+PyObject *
+Box3<T>::wrap (const IMATH_NAMESPACE::Box< IMATH_NAMESPACE::Vec3<T> > &b)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Box< IMATH_NAMESPACE::Vec3<T> > >::type converter;
+    PyObject *p = converter (b);
+    return p;
+}
+
+template <class T>
+int
+Box2<T>::convert (PyObject *p, IMATH_NAMESPACE::Box< IMATH_NAMESPACE::Vec2<T> > *v)
+{
+    boost::python::extract < IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V2i> > extractorV2i (p);
+    if (extractorV2i.check())
+    {
+        IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V2i> b = extractorV2i();
+        v->min = b.min;
+        v->max = b.max;
+        return 1;
+    }
+
+    boost::python::extract < IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V2f> > extractorV2f (p);
+    if (extractorV2f.check())
+    {
+        IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V2f> b = extractorV2f();
+        v->min = b.min;
+        v->max = b.max;
+        return 1;
+    }
+
+    boost::python::extract < IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V2d> > extractorV2d (p);
+    if (extractorV2d.check())
+    {
+        IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V2d> b = extractorV2d();
+        v->min = b.min;
+        v->max = b.max;
+        return 1;
+    }
+
+    boost::python::extract <boost::python::tuple> extractorTuple (p);
+    if (extractorTuple.check())
+    {
+        boost::python::tuple t = extractorTuple();
+        if (t.attr ("__len__") () == 2)
+        {
+            PyObject *minObj = 
+                boost::python::extract <boost::python::object> (t[0])().ptr();
+            PyObject *maxObj = 
+                boost::python::extract <boost::python::object> (t[1])().ptr();
+
+            IMATH_NAMESPACE::Vec2<T> min, max;
+            if (! V2<T>::convert (minObj, &min))
+                return 0;
+            if (! V2<T>::convert (maxObj, &max))
+                return 0;
+
+            v->min = min;
+            v->max = max;
+
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+template <class T>
+int
+Box3<T>::convert (PyObject *p, IMATH_NAMESPACE::Box< IMATH_NAMESPACE::Vec3<T> > *v)
+{
+    boost::python::extract < IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V3i> > extractorV3i (p);
+    if (extractorV3i.check())
+    {
+        IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V3i> b = extractorV3i();
+        v->min = b.min;
+        v->max = b.max;
+        return 1;
+    }
+
+    boost::python::extract < IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V3f> > extractorV3f (p);
+    if (extractorV3f.check())
+    {
+        IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V3f> b = extractorV3f();
+        v->min = b.min;
+        v->max = b.max;
+        return 1;
+    }
+
+    boost::python::extract < IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V3d> > extractorV3d (p);
+    if (extractorV3d.check())
+    {
+        IMATH_NAMESPACE::Box<IMATH_NAMESPACE::V3d> b = extractorV3d();
+        v->min = b.min;
+        v->max = b.max;
+        return 1;
+    }
+
+    boost::python::extract <boost::python::tuple> extractorTuple (p);
+    if (extractorTuple.check())
+    {
+        boost::python::tuple t = extractorTuple();
+        if (t.attr ("__len__") () == 2)
+        {
+            PyObject *minObj = 
+                boost::python::extract <boost::python::object> (t[0])().ptr();
+            PyObject *maxObj = 
+                boost::python::extract <boost::python::object> (t[1])().ptr();
+
+            IMATH_NAMESPACE::Vec3<T> min, max;
+            if (! V3<T>::convert (minObj, &min))
+                return 0;
+            if (! V3<T>::convert (maxObj, &max))
+                return 0;
+
+            v->min = min;
+            v->max = max;
+
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+typedef Box2<int>      Box2i;
+typedef Box2<int64_t>  Box2i64;
+typedef Box2<float>    Box2f;
+typedef Box2<double>   Box2d;
+
+typedef Box3<int>      Box3i;
+typedef Box3<int64_t>  Box3i64;
+typedef Box3<float>    Box3f;
+typedef Box3<double>   Box3d;
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathBox2Array.cpp b/src/python/PyImath/PyImathBox2Array.cpp
new file mode 100644 (file)
index 0000000..6020b30
--- /dev/null
@@ -0,0 +1,25 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathBoxArrayImpl.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+using namespace boost::python;
+
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Box2s> >   register_BoxArray<IMATH_NAMESPACE::V2s>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Box2i> >   register_BoxArray<IMATH_NAMESPACE::V2i>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Box2i64> > register_BoxArray<IMATH_NAMESPACE::V2i64>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Box2f> >   register_BoxArray<IMATH_NAMESPACE::V2f>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Box2d> >   register_BoxArray<IMATH_NAMESPACE::V2d>();
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Box2s   PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Box2s>::value()   { return IMATH_NAMESPACE::Box2s(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Box2i   PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Box2i>::value()   { return IMATH_NAMESPACE::Box2i(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Box2i64 PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Box2i64>::value() { return IMATH_NAMESPACE::Box2i64(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Box2f   PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Box2f>::value()   { return IMATH_NAMESPACE::Box2f(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Box2d   PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Box2d>::value()   { return IMATH_NAMESPACE::Box2d(); }
+}
diff --git a/src/python/PyImath/PyImathBox3Array.cpp b/src/python/PyImath/PyImathBox3Array.cpp
new file mode 100644 (file)
index 0000000..7bf3a8b
--- /dev/null
@@ -0,0 +1,25 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathBoxArrayImpl.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+using namespace boost::python;
+
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Box3s> >   register_BoxArray<IMATH_NAMESPACE::V3s>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Box3i> >   register_BoxArray<IMATH_NAMESPACE::V3i>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Box3i64> > register_BoxArray<IMATH_NAMESPACE::V3i64>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Box3f> >   register_BoxArray<IMATH_NAMESPACE::V3f>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Box3d> >   register_BoxArray<IMATH_NAMESPACE::V3d>();
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Box3s   PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Box3s>::value()   { return IMATH_NAMESPACE::Box3s(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Box3i   PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Box3i>::value()   { return IMATH_NAMESPACE::Box3i(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Box3i64 PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Box3i64>::value() { return IMATH_NAMESPACE::Box3i64(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Box3f   PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Box3f>::value()   { return IMATH_NAMESPACE::Box3f(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Box3d   PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Box3d>::value()   { return IMATH_NAMESPACE::Box3d(); }
+}
diff --git a/src/python/PyImath/PyImathBoxArrayImpl.h b/src/python/PyImath/PyImathBoxArrayImpl.h
new file mode 100644 (file)
index 0000000..2e0b4be
--- /dev/null
@@ -0,0 +1,84 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathBoxArrayImpl_h_
+#define _PyImathBoxArrayImpl_h_
+
+//
+// This .C file was turned into a header file so that instantiations
+// of the various Box* types can be spread across multiple files in
+// order to work around MSVC limitations.
+//
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <ImathVec.h>
+#include <ImathVecAlgo.h>
+#include <ImathBox.h>
+#include "PyImath.h"
+#include "PyImathBox.h"
+#include "PyImathDecorators.h"
+#include "PyImathMathExc.h"
+#include "PyImathOperators.h"
+#include "PyImathVecOperators.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T,int index>
+static FixedArray<T>
+BoxArray_get(FixedArray<IMATH_NAMESPACE::Box<T> > &va)
+{
+    return index == 0 ? 
+           FixedArray<T>(&(va.unchecked_index(0).min),
+                         va.len(),2*va.stride(),va.handle(),va.writable()) :
+           FixedArray<T>(&(va.unchecked_index(0).max),
+                         va.len(),2*va.stride(),va.handle(),va.writable());
+}
+
+template <class T>
+static void
+setItemTuple(FixedArray<IMATH_NAMESPACE::Box<T> > &va, Py_ssize_t index, const tuple &t)
+{
+    if(t.attr("__len__")() == 2)
+    {
+        Box<T> v;
+        v.min = extract<T>(t[0]);
+        v.max = extract<T>(t[1]);
+        va[(size_t)va.canonical_index(index)] = v;
+    }
+    else
+      throw std::invalid_argument ("tuple of length 2 expected");
+}
+
+template <class T>
+class_<FixedArray<IMATH_NAMESPACE::Box<T> > >
+register_BoxArray()
+{
+    using boost::mpl::true_;
+    using boost::mpl::false_;
+
+    class_<FixedArray<IMATH_NAMESPACE::Box<T> > > boxArray_class = FixedArray<IMATH_NAMESPACE::Box<T> >::register_("Fixed length array of IMATH_NAMESPACE::Box");
+    boxArray_class
+        .add_property("min",&BoxArray_get<T,0>)
+        .add_property("max",&BoxArray_get<T,1>)
+        .def("__setitem__", &setItemTuple<T>)
+    ;
+
+    add_comparison_functions(boxArray_class);
+    decoratecopy(boxArray_class);
+
+    return boxArray_class;
+}
+
+}  // namespace PyImath
+
+#endif   // _PyImathBoxArrayImpl_h_
diff --git a/src/python/PyImath/PyImathBufferProtocol.cpp b/src/python/PyImath/PyImathBufferProtocol.cpp
new file mode 100644 (file)
index 0000000..c4bce93
--- /dev/null
@@ -0,0 +1,415 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <ImathVec.h>
+#include "PyImathBufferProtocol.h"
+#include "PyImathExport.h"
+#include "PyImathFixedArray.h"
+#include "PyImathFixedArrayTraits.h"
+
+#include <type_traits>
+
+namespace PyImath {
+
+namespace {
+
+//  A wrapper API for the buffer protocol functions to access and traverse
+// the memory of a FixedArray.
+//
+template <class ArrayT>
+class BufferAPI
+{
+  using T = typename ArrayT::BaseType;
+  static_assert (std::is_same<ArrayT, FixedArray<T> >::value,
+                 "BufferAPI is only valid for FixedArray classes");
+
+  public:
+
+    virtual ~BufferAPI()
+      { delete[] shape; delete[] stride; }
+
+    //  The size, in bytes, of the smallest individual element of a buffer
+    // element.  For example, a V3fArray is a 2D array of 4-byte floats.
+    Py_ssize_t atomicSize() const
+      { return FixedArrayAtomicSize<T>::value; }
+
+    //  NonCopyable
+    BufferAPI (const BufferAPI &rhs)            = delete;
+    BufferAPI &operator= (const BufferAPI &rhs) = delete;
+
+    //  API
+    virtual bool        sharedBuffer() const = 0;
+    virtual Py_ssize_t  numBytes() const     = 0;
+    virtual bool        readOnly() const     = 0;
+    virtual void *      buffer()             = 0;
+
+  protected:
+
+    BufferAPI (const unsigned int length, const unsigned int interleave)
+     : dimensions (FixedArrayDimension<T>::value),
+            shape (new Py_ssize_t[dimensions]),
+           stride (new Py_ssize_t[dimensions])
+    {
+        shape[0]  = Py_ssize_t (length);
+        stride[0] = atomicSize() * FixedArrayWidth<T>::value * interleave;
+        for (int d=1; d<dimensions; d++)
+        {
+            shape[d]  = FixedArrayWidth<T>::value * interleave;
+            stride[d] = atomicSize();
+        }
+    }
+
+  public:
+
+    //  The number of dimensions in the data buffer (e.g. a one dimensional
+    // FixedArray of V3fs would have a data buffer dimension of 2).
+    int dimensions;
+
+    Py_ssize_t *shape;
+    Py_ssize_t *stride;
+};
+
+
+//  The SharedBuffer class is used for buffers that will be shared between
+// two different Python objects, and so the FixedArray is stored internally
+// as a reference.
+//
+template <class ArrayT>
+class SharedBufferAPI : public BufferAPI<ArrayT>
+{
+  public:
+
+    using BufferAPI<ArrayT>::atomicSize;
+
+    explicit
+    SharedBufferAPI (ArrayT &a)
+     : BufferAPI<ArrayT> (a.len(), a.stride()),
+              _orig (a)
+    {}
+
+    //  NonCopyable
+    SharedBufferAPI (const SharedBufferAPI &rhs)            = delete;
+    SharedBufferAPI &operator= (const SharedBufferAPI &rhs) = delete;
+
+    virtual ~SharedBufferAPI() = default;
+
+    bool sharedBuffer() const override
+     { return true; }
+
+    Py_ssize_t numBytes() const override
+     { return _orig.len() * atomicSize() * _orig.stride(); }
+
+    bool readOnly() const override
+     { return !_orig.writable(); }
+
+    void *buffer() override
+     { return static_cast<void *> (&_orig.direct_index(0)); }
+
+  private:
+
+    ArrayT &_orig;
+};
+
+
+//  This class exists for the case in which the Python array view
+// object is writable but the source FixedArray is not.
+//
+template <class ArrayT>
+class CopyBufferAPI : public BufferAPI<ArrayT>
+{
+  public:
+
+    using BufferAPI<ArrayT>::atomicSize;
+
+    explicit
+    CopyBufferAPI (ArrayT &a)
+     : BufferAPI<ArrayT> (a.len(), a.stride()),
+              _copy (a)
+    {}
+
+    virtual ~CopyBufferAPI() = default;
+
+    //  NonCopyable
+    CopyBufferAPI (const CopyBufferAPI &rhs)            = delete;
+    CopyBufferAPI &operator= (const CopyBufferAPI &rhs) = delete;
+
+    bool sharedBuffer() const override
+     { return false; }
+
+    Py_ssize_t numBytes() const override
+     { return _copy.len() * atomicSize() * _copy.stride(); }
+
+    bool readOnly() const override
+     { return false; }
+
+    void *buffer() override
+     { return static_cast<void *> (&_copy.direct_index(0)); }
+
+  private:
+
+    ArrayT _copy;
+};
+
+
+template <class ArrayT>
+Py_ssize_t
+bufferInfo (ArrayT &array, void **buf)
+{
+    *buf = static_cast<void *> (&array.direct_index(0));
+    return array.len() * sizeof(typename ArrayT::BaseType);
+}
+
+
+template <class ArrayT>
+Py_ssize_t
+getreadbuf (PyObject *obj, Py_ssize_t segment, void **buf)
+{
+    if (segment != 0)
+    {
+        PyErr_SetString (PyExc_ValueError, "FixedArrays are not segmented");
+        return -1;
+    }
+
+    boost::python::extract<ArrayT> eObj (obj);
+    if (!eObj.check())
+    {
+        PyErr_SetString (PyExc_ValueError, "Cannot extract FixedArray");
+        return -1;
+    }
+
+    ArrayT array = eObj();
+    return bufferInfo<ArrayT> (array, buf);
+}
+
+
+template <class ArrayT>
+Py_ssize_t
+getwritebuf (PyObject *obj, Py_ssize_t segment, void **buf)
+{
+    PyErr_SetString
+        (PyExc_ValueError,
+         "writable buffers supported only with new-style buffer protocol.");
+
+    return -1;
+}
+
+
+template <class ArrayT>
+Py_ssize_t
+getsegcount (PyObject *obj, Py_ssize_t *lenp)
+{
+    //  FixedArrays are always in one, fixed-sized block
+    return 1;
+}
+
+
+template <class ArrayT>
+Py_ssize_t
+getcharbuf (PyObject *obj, Py_ssize_t segment, const char **charBuf)
+{
+    return getreadbuf<ArrayT> (obj, segment, (void **)charBuf);
+}
+
+
+template <class ArrayT>
+void
+releasebuffer (PyObject *obj, Py_buffer *view)
+{
+    delete static_cast<BufferAPI<ArrayT> *>(view->internal);
+}
+
+
+template <class ArrayT>
+int
+getbuffer (PyObject *obj, Py_buffer *view, int flags)
+{
+    if (view == nullptr)
+    {
+        PyErr_SetString (PyExc_ValueError, "Buffer view is NULL");
+        return -1;
+    }
+
+    if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS)
+    {
+        PyErr_SetString (PyExc_ValueError, "FORTRAN order not supported");
+        return -1;
+    }
+
+    boost::python::extract<ArrayT> eObj (obj);
+    if (!eObj.check())
+    {
+        PyErr_SetString (PyExc_ValueError, "Cannot extract FixedArray");
+        return -1;
+    }
+    ArrayT array = eObj();
+
+    if (array.isMaskedReference())
+    {
+        PyErr_SetString (PyExc_ValueError, "Buffer protocol does not support masked references");
+        return -1;
+    }
+
+    BufferAPI<ArrayT> *api   = nullptr;
+    bool writableBuffer = ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE);
+    if (writableBuffer && !array.writable())
+        api = new CopyBufferAPI<ArrayT> (array);  
+    else
+        api = new SharedBufferAPI<ArrayT> (array);  
+
+    view->internal   = api;
+    view->buf        = api->buffer();
+    view->len        = api->numBytes();
+    view->readonly   = api->readOnly();
+    view->itemsize   = api->atomicSize();
+    view->suboffsets = nullptr;
+
+    view->format = ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) 
+                 ? PyFormat<typename ArrayT::BaseType>()
+                 : nullptr;
+
+    view->strides = ((flags & PyBUF_STRIDES) == PyBUF_STRIDES)
+                  ? api->stride
+                  : nullptr;
+
+    if ((flags & PyBUF_ND) == PyBUF_ND)
+    {
+        view->ndim  = api->dimensions;
+        view->shape = api->shape;
+    }
+    else
+    {
+        view->ndim  = 0;
+        view->shape = nullptr;
+    }
+
+    view->obj = obj;
+    Py_INCREF (obj);
+
+    return 0;
+}
+
+
+// This structure serves to instantiate a PyBufferProcs instance with pointers
+// to the right buffer protocol functions.
+template <class ArrayT>
+struct FixedArrayBufferProcs
+{
+    static PyBufferProcs procs;
+};
+
+
+template <class ArrayT>
+PyBufferProcs FixedArrayBufferProcs<ArrayT>::procs =
+{
+#if PY_MAJOR_VERSION == 2
+    (readbufferproc)    getreadbuf<ArrayT>,
+    (writebufferproc)   getwritebuf<ArrayT>,
+    (segcountproc)      getsegcount<ArrayT>,
+    (charbufferproc)    getcharbuf<ArrayT>,
+    (getbufferproc)     getbuffer<ArrayT>,
+    (releasebufferproc) releasebuffer<ArrayT>
+#else  //  Note deprecation of support for the older style
+    (getbufferproc)     getbuffer<ArrayT>,
+    (releasebufferproc) releasebuffer<ArrayT>
+#endif
+};
+
+} // anonymous
+
+
+template <class ArrayT>
+void
+add_buffer_protocol (boost::python::class_<ArrayT> &classObj)
+{
+    auto *typeObj = reinterpret_cast<PyTypeObject *> (classObj.ptr());
+    typeObj->tp_as_buffer = &FixedArrayBufferProcs<ArrayT>::procs;
+#if PY_MAJOR_VERSION == 2
+    typeObj->tp_flags |= (Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_HAVE_GETCHARBUFFER);
+#endif
+}
+
+
+template <class ArrayT>
+ArrayT *
+fixedArrayFromBuffer (PyObject *obj)
+{
+    if (!PyObject_CheckBuffer (obj))
+        throw std::invalid_argument ("Python object does not support the buffer protocol");
+
+    // Request a strided buffer with type & dimensions.
+    Py_buffer view;
+    memset(&view, 0, sizeof(view));
+    if (PyObject_GetBuffer (obj, &view, PyBUF_FORMAT | PyBUF_STRIDES) != 0)
+    {
+        throw std::logic_error ("Failed to get dimensioned, typed buffer");
+    }
+
+    // We have a buffer.  Check that the type matches.
+    if (!view.format ||
+        view.format[0] == '>' ||  
+        view.format[0] == '!' || 
+        view.format[0] == '=' || 
+        view.format[0] == '^')
+    {
+        PyBuffer_Release(&view);
+        throw std::invalid_argument ("Unsupported buffer type");
+    }
+
+    ArrayT *array = new ArrayT (view.shape[0], PyImath::UNINITIALIZED);
+    memcpy (reinterpret_cast<void*>(&array->direct_index(0)), view.buf, view.len);
+    PyBuffer_Release(&view);
+
+    return array;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<short> >         &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<int> >           &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<int64_t> >       &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<float> >         &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<double> >        &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<unsigned char> > &classObj);
+
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec2<short> > >   &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec2<int> > >     &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec2<int64_t> > > &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec2<float> > >   &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec2<double> > >  &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec3<short> > >   &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec3<int> > >     &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec3<int64_t> > > &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec3<float> > >   &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec3<double> > >  &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec4<short> > >   &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec4<int> > >     &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec4<int64_t> > > &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec4<float> > >   &classObj);
+template PYIMATH_EXPORT void add_buffer_protocol (boost::python::class_<FixedArray<Imath::Vec4<double> > >  &classObj);
+
+template PYIMATH_EXPORT FixedArray<Imath::Vec2<short> >*   fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec2<int> >*     fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec2<int64_t> >* fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec2<float> >*   fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec2<double> >*  fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec3<short> >*   fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec3<int> >*     fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec3<int64_t> >* fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec3<float> >*   fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec3<double> >*  fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec4<short> >*   fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec4<int> >*     fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec4<int64_t> >* fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec4<float> >*   fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<Imath::Vec4<double> >*  fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<short>*                 fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<int>*                   fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<int64_t>*               fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<float>*                 fixedArrayFromBuffer (PyObject *obj);
+template PYIMATH_EXPORT FixedArray<double>*                fixedArrayFromBuffer (PyObject *obj);
+
+}
diff --git a/src/python/PyImath/PyImathBufferProtocol.h b/src/python/PyImath/PyImathBufferProtocol.h
new file mode 100644 (file)
index 0000000..f0d42a1
--- /dev/null
@@ -0,0 +1,29 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathBufferProtocol_h_
+#define _PyImathBufferProtocol_h_
+
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+
+namespace PyImath {
+
+//  For more information on working with the protocol see:
+//
+//    https://docs.python.org/2.7/c-api/buffer.html
+//    https://docs.python.org/3.7.10/c-api/buffer.html
+
+template <class T>
+void add_buffer_protocol (boost::python::class_<T> &classObj);
+
+template <class ArrayT>
+ArrayT* fixedArrayFromBuffer (PyObject *obj);
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathColor.h b/src/python/PyImath/PyImathColor.h
new file mode 100644 (file)
index 0000000..767b9b1
--- /dev/null
@@ -0,0 +1,229 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathColor3_h_
+#define _PyImathColor3_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <ImathColor.h>
+#include "PyImath.h"
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Color4<T> > register_Color4();
+template <class T> boost::python::class_<PyImath::FixedArray2D<IMATH_NAMESPACE::Color4<T> > > register_Color4Array2D();
+template <class T> boost::python::class_<PyImath::FixedArray<IMATH_NAMESPACE::Color4<T> > > register_Color4Array();
+template <class T> boost::python::class_<IMATH_NAMESPACE::Color3<T>, boost::python::bases<IMATH_NAMESPACE::Vec3<T> > > register_Color3();
+template <class T> boost::python::class_<PyImath::FixedArray<IMATH_NAMESPACE::Color3<T> > > register_Color3Array();
+
+typedef FixedArray2D<IMATH_NAMESPACE::Color4f> Color4fArray;
+typedef FixedArray2D<IMATH_NAMESPACE::Color4c> Color4cArray;
+typedef FixedArray<IMATH_NAMESPACE::Color4f> C4fArray;
+typedef FixedArray<IMATH_NAMESPACE::Color4c> C4cArray;
+typedef FixedArray<IMATH_NAMESPACE::Color3f> C3fArray;
+typedef FixedArray<IMATH_NAMESPACE::Color3c> C3cArray;
+
+//
+// Other code in the Zeno code base assumes the existance of a class with the
+// same name as the Imath class, and with static functions wrap() and
+// convert() to produce a PyImath object from an Imath object and vice-versa,
+// respectively.  The class Boost generates from the Imath class does not
+// have these properties, so we define a companion class here.
+// The template argument, T, is the element type for the color in C++ (e.g., char,
+// float).  The other argument, U, is how this type is represented in Python
+// (e.g., int, float).
+
+template <class T, class U>
+class C3 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Color3<T> &c);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Color3<T> *v);
+};
+
+template <class T, class U>
+class C4 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Color4<T> &c);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Color4<T> *v);
+};
+
+template <class T, class U>
+PyObject *
+C3<T, U>::wrap (const IMATH_NAMESPACE::Color3<T> &c)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Color3<T> >::type converter;
+    PyObject *p = converter (c);
+    return p;
+}
+
+template <class T, class U>
+PyObject *
+C4<T, U>::wrap (const IMATH_NAMESPACE::Color4<T> &c)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Color4<T> >::type converter;
+    PyObject *p = converter (c);
+    return p;
+}
+
+template <class T, class U>
+int
+C3<T, U>::convert (PyObject *p, IMATH_NAMESPACE::Color3<T> *v)
+{
+    boost::python::extract <IMATH_NAMESPACE::C3c> extractorC3c (p);
+    if (extractorC3c.check())
+    {
+        IMATH_NAMESPACE::C3c c3c = extractorC3c();
+        v->setValue (U(c3c[0]), U(c3c[1]), U(c3c[2]));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::C3f> extractorC3f (p);
+    if (extractorC3f.check())
+    {
+        IMATH_NAMESPACE::C3f c3f = extractorC3f();
+        v->setValue (U(c3f[0]), U(c3f[1]), U(c3f[2]));
+        return 1;
+    }
+
+    boost::python::extract <boost::python::tuple> extractorTuple (p);
+    if (extractorTuple.check())
+    {
+        boost::python::tuple t = extractorTuple();
+        if (t.attr ("__len__") () == 3)
+        {
+            double a = boost::python::extract <double> (t[0]);
+            double b = boost::python::extract <double> (t[1]);
+            double c = boost::python::extract <double> (t[2]);
+            v->setValue (U(a), U(b), U(c));
+            return 1;
+        }
+    }
+
+    boost::python::extract <boost::python::list> extractorList (p);
+    if (extractorList.check())
+    {
+        boost::python::list l = extractorList();
+        if (l.attr ("__len__") () == 3)
+        {
+            boost::python::extract <double> extractor0 (l[0]);
+            boost::python::extract <double> extractor1 (l[1]);
+            boost::python::extract <double> extractor2 (l[2]);
+            if (extractor0.check() && extractor1.check() &&
+                extractor2.check())
+            {
+                v->setValue (U(extractor0()), U(extractor1()),
+                             U(extractor2()));
+                return 1;
+            }
+        }
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V3i> extractorV3i (p);
+    if (extractorV3i.check())
+    {
+        IMATH_NAMESPACE::V3i v3i = extractorV3i();
+        v->setValue (U(v3i[0]), U(v3i[1]), U(v3i[2]));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V3f> extractorV3f (p);
+    if (extractorV3f.check())
+    {
+        IMATH_NAMESPACE::V3f v3f = extractorV3f();
+        v->setValue (U(v3f[0]), U(v3f[1]), U(v3f[2]));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V3d> extractorV3d (p);
+    if (extractorV3d.check())
+    {
+        IMATH_NAMESPACE::V3d v3d = extractorV3d();
+        v->setValue (U(v3d[0]), U(v3d[1]), U(v3d[2]));
+        return 1;
+    }
+
+    return 0;
+}
+
+template <class T, class U>
+int
+C4<T, U>::convert (PyObject *p, IMATH_NAMESPACE::Color4<T> *v)
+{
+    boost::python::extract <IMATH_NAMESPACE::C4c> extractorC4c (p);
+    if (extractorC4c.check())
+    {
+        IMATH_NAMESPACE::C4c c4c = extractorC4c();
+        v->setValue (U(c4c[0]), U(c4c[1]), U(c4c[2]), U(c4c[3]));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::C4f> extractorC4f (p);
+    if (extractorC4f.check())
+    {
+        IMATH_NAMESPACE::C4f c4f = extractorC4f();
+        v->setValue (U(c4f[0]), U(c4f[1]), U(c4f[2]), U(c4f[3]));
+        return 1;
+    }
+
+    boost::python::extract <boost::python::tuple> extractorTuple (p);
+    if (extractorTuple.check())
+    {
+        boost::python::tuple t = extractorTuple();
+        if (t.attr ("__len__") () == 4)
+        {
+            // As with V3<T>, we extract the tuple elements as doubles and
+            // cast them to Ts in setValue(), to avoid any odd cases where
+            // extracting them as Ts from the start would fail.
+
+            double a = boost::python::extract <double> (t[0]);
+            double b = boost::python::extract <double> (t[1]);
+            double c = boost::python::extract <double> (t[2]);
+            double d = boost::python::extract <double> (t[3]);
+            v->setValue (U(a), U(b), U(c), U(d));
+            return 1;
+        }
+    }
+
+    boost::python::extract <boost::python::list> extractorList (p);
+    if (extractorList.check())
+    {
+        boost::python::list l = extractorList();
+        if (l.attr ("__len__") () == 4)
+        {
+            boost::python::extract <double> extractor0 (l[0]);
+            boost::python::extract <double> extractor1 (l[1]);
+            boost::python::extract <double> extractor2 (l[2]);
+            boost::python::extract <double> extractor3 (l[3]);
+            if (extractor0.check() && extractor1.check() &&
+                extractor2.check() && extractor3.check())
+            {
+                v->setValue (U(extractor0()), U(extractor1()),
+                             U(extractor2()), U(extractor3()));
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+typedef C3<float, float>       Color3f;
+typedef C3<unsigned char, int> Color3c;
+typedef Color3f                        C3f;
+typedef Color3c                        C3c;
+
+typedef C4<float, float>       Color4f;
+typedef C4<unsigned char, int> Color4c;
+typedef Color4f                        C4f;
+typedef Color4c                        C4c;
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathColor3.cpp b/src/python/PyImath/PyImathColor3.cpp
new file mode 100644 (file)
index 0000000..0b8dfee
--- /dev/null
@@ -0,0 +1,652 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+//
+// This .C file was turned into a header file so that instantiations
+// of the various V3* types can be spread across multiple files in
+// order to work around MSVC limitations.
+//
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <ImathVec.h>
+#include <ImathColor.h>
+#include <ImathColorAlgo.h>
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathColor.h"
+#include "PyImathVec.h"
+#include "PyImathDecorators.h"
+#include "PyImathExport.h"
+#include "PyImathColor3ArrayImpl.h"
+
+namespace PyImath {
+template <> const char *PyImath::C3cArray::name() { return "C3cArray"; }
+template <> const char *PyImath::C3fArray::name() { return "C3fArray"; }
+
+using namespace boost::python; 
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct Color3Name { static const char *value; };
+template<> const char *Color3Name<unsigned char>::value  = "Color3c";
+template<> const char *Color3Name<float>::value  = "Color3f";
+
+// create a new default constructor that initializes Color3<T> to zero.
+template <class T>
+static Color3<T> * Color3_construct_default()
+{
+    return new Color3<T>(T(0),T(0),T(0));
+}
+
+template <class T, class S>
+static Color3<T> * Color3_component_construct1(S x, S y, S z)
+{
+    // Assigning a floating point value to an integer type can cause a
+    // float-point error, which we want to translate into an exception. 
+    
+    MATH_EXC_ON;
+
+    if(strcmp(Color3Name<T>::value, "Color3c") == 0)
+    {
+        unsigned char r = (unsigned char) x;
+        unsigned char g = (unsigned char) y;
+        unsigned char b = (unsigned char) z;
+        
+        return new Color3<T>(r,g,b);
+    }
+    else    
+        return new Color3<T>(T (x), T(y), T(z));
+}
+
+template <class T, class S>
+static Color3<T> * Color3_component_construct2(S x)
+{
+    MATH_EXC_ON;
+
+    if(strcmp(Color3Name<T>::value, "Color3c") == 0)
+    {
+        unsigned char u = (unsigned char) x;
+
+        return new Color3<T>(u,u,u);
+    }
+    else    
+        return new Color3<T>(T(x), T(x), T(x));
+}
+
+template <class T, class S>
+static Color3<T> * Color3_color_construct(const Color3<S> &c)
+{
+    MATH_EXC_ON;
+
+    if(strcmp(Color3Name<T>::value, "Color3c") == 0)
+    {
+        unsigned char r = (unsigned char) c.x;
+        unsigned char g = (unsigned char) c.y;
+        unsigned char b = (unsigned char) c.z;
+        
+        return new Color3<T>(r,g,b);
+    }
+    else
+     return new Color3<T>(T (c.x), T(c.y), T(c.z));
+}
+
+template <class T, class S>
+static Color3<T> * Color3_vector_construct(const Vec3<S> &c)
+{
+    MATH_EXC_ON;
+
+    if(strcmp(Color3Name<T>::value, "Color3c") == 0)
+    {
+        unsigned char r = (unsigned char) c.x;
+        unsigned char g = (unsigned char) c.y;
+        unsigned char b = (unsigned char) c.z;
+        
+        return new Color3<T>(r,g,b);
+    }
+    else
+     return new Color3<T>(T (c.x), T(c.y), T(c.z));
+}
+
+
+template <class T>
+static std::string 
+color3_str(const Color3<T> &v)
+{
+    std::stringstream stream;
+    if(strcmp(Color3Name<T>::value, "Color3c") == 0)
+    {
+        int r = int(v.x);
+        int g = int(v.y);
+        int b = int(v.z);
+
+        stream << Color3Name<T>::value << "(" << r << ", " << g << ", " << b << ")";
+        return stream.str();
+    }
+    else
+    {    
+        stream << Color3Name<T>::value << "(" << v.x << ", " << v.y << ", " << v.z << ")";
+        return stream.str();
+    }
+}
+
+// Non-specialized repr is same as str
+template <class T>
+static std::string 
+color3_repr(const Color3<T> &v)
+{
+    return color3_str(v);
+}
+
+// Specialization for float to full precision
+template <>
+std::string 
+color3_repr(const Color3<float> &v)
+{
+    return (boost::format("%s(%.9g, %.9g, %.9g)")
+                        % Color3Name<float>::value % v.x % v.y % v.z).str();
+}
+
+// No specialization for double, since we don't instantiate Color3d
+
+
+template <class T>
+static Color3<T> * Color3_construct_tuple(const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        return new Color3<T>(extract<T>(t[0]), extract<T>(t[1]), extract<T>(t[2]));
+    }
+    else
+      throw std::invalid_argument ("Color3 expects tuple of length 3");
+}
+
+template <class T>
+static Color3<T> * Color3_construct_list(const list &l)
+{
+    MATH_EXC_ON;
+    if(l.attr("__len__")() == 3)
+    {
+        return new Color3<T>(extract<T>(l[0]), extract<T>(l[1]), extract<T>(l[2]));
+    }
+    else
+      throw std::invalid_argument ("Color3 expects list of length 3");
+}
+
+template <class T>
+static const Color3<T> &
+iadd(Color3<T> &color, const Color3<T> &color2)
+{
+    MATH_EXC_ON;
+    return color += color2;
+}
+
+template <class T>
+static Color3<T>
+add(Color3<T> &color, const Color3<T> &color2)
+{
+    MATH_EXC_ON;
+    return color + color2;
+}
+
+template <class T>
+static Color3<T>
+addTuple(Color3<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+        return Color3<T>(color.x + extract<T>(t[0]), 
+                         color.y + extract<T>(t[1]), 
+                         color.z + extract<T>(t[2]));
+    else
+        throw std::invalid_argument ("Color3 expects tuple of length 3");
+}
+
+template <class T>
+static Color3<T>
+addT(Color3<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Color3<T> w(v.x + a, v.y + a, v.z + a);
+    return w;
+}
+
+template <class T>
+static const Color3<T> &
+isub(Color3<T> &color, const Color3<T> &color2)
+{
+    MATH_EXC_ON;
+    return color -= color2;
+}
+
+template <class T>
+static Color3<T>
+sub(Color3<T> &color, const Color3<T> &color2)
+{
+    MATH_EXC_ON;
+    return color - color2;
+}
+
+template <class T>
+static Color3<T>
+subtractL(Color3<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+        return Color3<T>(color.x - extract<T>(t[0]), 
+                         color.y - extract<T>(t[1]), 
+                         color.z - extract<T>(t[2]));
+    else
+        throw std::invalid_argument ("Color3 expects tuple of length 3");
+}
+
+template <class T>
+static Color3<T>
+subtractLT(const Color3<T> &color, T a)
+{
+    MATH_EXC_ON;
+    return Color3<T>(color.x - a, 
+                     color.y - a, 
+                     color.z - a);
+}
+
+template <class T>
+static Color3<T>
+subtractRT(const Color3<T> &color, T a)
+{
+    MATH_EXC_ON;
+    return Color3<T>(a - color.x, 
+                     a - color.y, 
+                     a - color.z);
+}
+
+template <class T>
+static Color3<T>
+subtractR(Color3<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+        return Color3<T>(extract<T>(t[0]) - color.x, 
+                         extract<T>(t[1]) - color.y, 
+                         extract<T>(t[2]) - color.z);
+    else
+        throw std::invalid_argument ("Color3 expects tuple of length 3");
+}
+
+template <class T>
+static Color3<T>
+neg(Color3<T> &color)
+{
+    MATH_EXC_ON;
+    return -color;
+}
+
+template <class T>
+static const Color3<T> &
+negate(Color3<T> &color)
+{
+    MATH_EXC_ON;
+    return color.negate();
+}
+
+template <class T>
+static const Color3<T> &
+imul(Color3<T> &color, const Color3<T> &color2)
+{
+    MATH_EXC_ON;
+    return color *= color2;
+}
+
+template <class T>
+static const Color3<T> &
+imulT(Color3<T> &color, const T &t)
+{
+    MATH_EXC_ON;
+    return color *= t;
+}
+
+template <class T>
+static Color3<T>
+mul(Color3<T> &color, const Color3<T> &color2)
+{
+    MATH_EXC_ON;
+    return color * color2;
+}
+
+template <class T>
+static Color3<T>
+mulT(Color3<T> &color, const T &t)
+{
+    MATH_EXC_ON;
+    return color * t;
+}
+
+template <class T>
+static Color3<T>
+rmulT(Color3<T> &color, const T &t)
+{
+    MATH_EXC_ON;
+    return t * color;
+}
+
+template <class T>
+static Color3<T>
+mulTuple(Color3<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+        return Color3<T>(color.x * extract<T>(t[0]), 
+                         color.y * extract<T>(t[1]), 
+                         color.z * extract<T>(t[2]));
+    else
+        throw std::invalid_argument ("Color3 expects tuple of length 3");
+}
+
+template <class T>
+static const Color3<T> &
+idiv(Color3<T> &color, const Color3<T> &color2)
+{
+    MATH_EXC_ON;
+    return color /= color2;
+}
+
+template <class T>
+static const Color3<T> &
+idivT(Color3<T> &color, const T &t)
+{
+    MATH_EXC_ON;
+    return color /= t;
+}
+
+template <class T>
+static Color3<T>
+div(Color3<T> &color, const Color3<T> &color2)
+{
+    MATH_EXC_ON;
+    return color / color2;
+}
+
+template <class T>
+static Color3<T>
+divT(Color3<T> &color, const T &t)
+{
+    MATH_EXC_ON;
+    return color / t;
+}
+
+template <class T>
+static Color3<T>
+divTupleL(Color3<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+        return Color3<T>(color.x / extract<T>(t[0]), 
+                         color.y / extract<T>(t[1]), 
+                         color.z / extract<T>(t[2]));
+    else
+        throw std::invalid_argument ("Color3 expects tuple of length 3");    
+}
+
+template <class T>
+static Color3<T>
+divTupleR(Color3<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+        return Color3<T>(extract<T>(t[0]) / color.x, 
+                         extract<T>(t[1]) / color.y, 
+                         extract<T>(t[2]) / color.z);
+    else
+        throw std::invalid_argument ("Color3 expects tuple of length 3");    
+}
+
+template <class T>
+static Color3<T>
+divTR(Color3<T> &color, T a)
+{
+    MATH_EXC_ON;
+    return Color3<T>(a / color.x, 
+                     a / color.y, 
+                     a / color.z);
+}
+
+template <class T>
+static Color3<T>
+hsv2rgb(Color3<T> &color)
+{    
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::hsv2rgb(color);
+}
+
+template <class T>
+static Color3<T>
+hsv2rgbTuple(const tuple &t)
+{
+    MATH_EXC_ON;
+    Color3<T> color;
+    if(t.attr("__len__")() == 3)
+    {
+        color.x = extract<T>(t[0]);
+        color.y = extract<T>(t[1]);
+        color.z = extract<T>(t[2]); 
+        
+        return IMATH_NAMESPACE::hsv2rgb(color);
+    }
+    else
+        throw std::invalid_argument ("Color3 expects tuple of length 3");    
+}
+
+template <class T>
+static Color3<T>
+rgb2hsv(Color3<T> &color)
+{    
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::rgb2hsv(color);
+}
+
+template <class T>
+static Color3<T>
+rgb2hsvTuple(const tuple &t)
+{
+    MATH_EXC_ON;
+    Color3<T> color;
+    if(t.attr("__len__")() == 3)
+    {
+        color.x = extract<T>(t[0]);
+        color.y = extract<T>(t[1]);
+        color.z = extract<T>(t[2]); 
+        
+        return IMATH_NAMESPACE::rgb2hsv(color);
+    }
+    else
+        throw std::invalid_argument ("Color3 expects tuple of length 3");    
+}
+
+template <class T>
+static void
+setValue1(Color3<T> &color, const T &a, const T &b, const T &c)
+{
+    MATH_EXC_ON;
+    color.setValue(a, b, c);
+}
+
+template <class T>
+static void
+setValue2(Color3<T> &color, const Color3<T> &v)
+{
+    MATH_EXC_ON;
+    color.setValue(v);
+}
+
+template <class T>
+static void
+setValueTuple(Color3<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    Color3<T> v;
+    if(t.attr("__len__")() == 3)
+    {
+        v.x = extract<T>(t[0]);
+        v.y = extract<T>(t[1]);
+        v.z = extract<T>(t[2]); 
+        
+        color.setValue(v);
+    }
+    else
+        throw std::invalid_argument ("Color3 expects tuple of length 3");
+}
+
+template <class T>
+static bool
+lessThan(Color3<T> &v, const Color3<T> &w)
+{
+    bool isLessThan = (v.x <= w.x && v.y <= w.y && v.z <= w.z)
+                    && v != w;
+                   
+   return isLessThan;
+}
+
+template <class T>
+static bool
+greaterThan(Color3<T> &v, const Color3<T> &w)
+{
+    bool isGreaterThan = (v.x >= w.x && v.y >= w.y && v.z >= w.z)
+                       && v != w;
+                   
+   return isGreaterThan;
+}
+
+template <class T>
+static bool
+lessThanEqual(Color3<T> &v, const Color3<T> &w)
+{
+    bool isLessThanEqual = (v.x <= w.x && v.y <= w.y && v.z <= w.z);
+
+    return isLessThanEqual;
+}
+
+template <class T>
+static bool
+greaterThanEqual(Color3<T> &v, const Color3<T> &w)
+{
+    bool isGreaterThanEqual = (v.x >= w.x && v.y >= w.y && v.z >= w.z);
+
+    return isGreaterThanEqual;
+}
+
+template <class T>
+class_<Color3<T>, bases<Vec3<T> > >
+register_Color3()
+{
+    class_<Color3<T>, bases<Vec3<T> > > color3_class(Color3Name<T>::value, Color3Name<T>::value,init<Color3<T> >("copy construction"));
+    color3_class
+        .def("__init__",make_constructor(Color3_construct_default<T>),"initialize to (0,0,0)")
+        .def("__init__",make_constructor(Color3_construct_tuple<T>), "initialize to (r,g,b) with a python tuple")
+        .def("__init__",make_constructor(Color3_construct_list<T>), "initialize to (r,g,b) with a python list")
+        .def("__init__",make_constructor(Color3_component_construct1<T,float>))
+        .def("__init__",make_constructor(Color3_component_construct1<T,int>))
+        .def("__init__",make_constructor(Color3_component_construct2<T,float>))
+        .def("__init__",make_constructor(Color3_component_construct2<T,int>))
+        .def("__init__",make_constructor(Color3_color_construct<T,float>))
+        .def("__init__",make_constructor(Color3_color_construct<T,int>))
+        .def("__init__",make_constructor(Color3_color_construct<T,unsigned char>))
+        .def("__init__",make_constructor(Color3_vector_construct<T,float>))
+        .def("__init__",make_constructor(Color3_vector_construct<T,double>))
+        .def("__init__",make_constructor(Color3_vector_construct<T,int>))
+
+        .def_readwrite("r", &Color3<T>::x)
+        .def_readwrite("g", &Color3<T>::y)
+        .def_readwrite("b", &Color3<T>::z)
+        .def("__str__", &color3_str<T>)
+        .def("__repr__", &color3_repr<T>)
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__iadd__", &iadd<T>,return_internal_reference<>())
+        .def("__add__", &add<T>)
+        .def("__add__", &addTuple<T>)
+        .def("__add__", &addT<T>)
+        .def("__radd__", &addTuple<T>)
+        .def("__radd__", &addT<T>)
+        .def("__isub__", &isub<T>,return_internal_reference<>())
+        .def("__sub__", &sub<T>)
+        .def("__sub__", &subtractL<T>)
+        .def("__sub__", &subtractLT<T>)
+        .def("__rsub__", &subtractR<T>)
+        .def("__rsub__", &subtractRT<T>)
+        .def("__neg__", &neg<T>)
+        .def("negate",&negate<T>,return_internal_reference<>(),"component-wise multiplication by -1")
+        .def("__imul__", &imul<T>,return_internal_reference<>())
+        .def("__imul__", &imulT<T>,return_internal_reference<>())
+        .def("__mul__", &mul<T>)
+        .def("__mul__", &mulT<T>)
+        .def("__rmul__", &rmulT<T>)
+        .def("__mul__", &mulTuple<T>)
+        .def("__rmul__", &mulTuple<T>)
+        .def("__idiv__", &idiv<T>,return_internal_reference<>())
+        .def("__idiv__", &idivT<T>,return_internal_reference<>())
+        .def("__itruediv__", &idiv<T>,return_internal_reference<>())
+        .def("__itruediv__", &idivT<T>,return_internal_reference<>())
+        .def("__div__", &div<T>)
+        .def("__div__", &divT<T>)
+        .def("__div__", &divTupleL<T>)
+        .def("__truediv__", &div<T>)
+        .def("__truediv__", &divT<T>)
+        .def("__truediv__", &divTupleL<T>)
+        .def("__rdiv__", &divTupleR<T>)  
+        .def("__rdiv__", &divTR<T>)
+        .def("__rtruediv__", &divTupleR<T>)  
+        .def("__rtruediv__", &divTR<T>)
+        .def("__lt__", &lessThan<T>)
+        .def("__gt__", &greaterThan<T>)
+        .def("__le__", &lessThanEqual<T>)
+        .def("__ge__", &greaterThanEqual<T>)
+        .def("dimensions", &Color3<T>::dimensions,"dimensions() number of dimensions in the color")
+        .staticmethod("dimensions")
+        .def("baseTypeEpsilon", &Color3<T>::baseTypeEpsilon,"baseTypeEpsilon() epsilon value of the base type of the color")
+        .staticmethod("baseTypeEpsilon")
+        .def("baseTypeMax", &Color3<T>::baseTypeMax,"baseTypeMax() max value of the base type of the color")
+        .staticmethod("baseTypeMax")
+        .def("baseTypeLowest", &Color3<T>::baseTypeLowest,"baseTypeLowest() largest negative value of the base type of the color")
+        .staticmethod("baseTypeLowest")
+        .def("baseTypeSmallest", &Color3<T>::baseTypeSmallest,"baseTypeSmallest() smallest value of the base type of the color")
+        .staticmethod("baseTypeSmallest")
+        .def("hsv2rgb", &hsv2rgb<T>, 
+            "C.hsv2rgb() -- returns a new color which "
+             "is C converted from RGB to HSV")
+         .def("hsv2rgb", &rgb2hsvTuple<T>)
+         
+         .def("rgb2hsv", &rgb2hsv<T>,                          
+              "C.rgb2hsv() -- returns a new color which "
+                     "is C converted from HSV to RGB")
+         .def("rgb2hsv", &rgb2hsvTuple<T>)
+         
+         .def("setValue", &setValue1<T>,                               
+              "C1.setValue(C2)\nC1.setValue(a,b,c) -- "
+                     "set C1's  elements")         
+         .def("setValue", &setValue2<T>)
+         .def("setValue", &setValueTuple<T>)
+        ;
+
+    decoratecopy(color3_class);
+
+    return color3_class;
+}
+
+template PYIMATH_EXPORT class_<Color3<float>, bases<Vec3<float> > > register_Color3<float>();
+template PYIMATH_EXPORT class_<Color3<unsigned char>, bases<Vec3<unsigned char> > > register_Color3<unsigned char>();
+template PYIMATH_EXPORT class_<FixedArray<Color3<float> > > register_Color3Array<float>();
+template PYIMATH_EXPORT class_<FixedArray<Color3<unsigned char> > > register_Color3Array<unsigned char>();
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Color3<float> PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Color3<float> >::value()
+{ return IMATH_NAMESPACE::Color3<float>(0,0,0); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Color3<unsigned char> PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Color3<unsigned char> >::value()
+{ return IMATH_NAMESPACE::Color3<unsigned char>(0,0,0); }
+
+}
diff --git a/src/python/PyImath/PyImathColor3ArrayImpl.h b/src/python/PyImath/PyImathColor3ArrayImpl.h
new file mode 100644 (file)
index 0000000..a22db09
--- /dev/null
@@ -0,0 +1,58 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathColor3ArrayImpl_h_
+#define _PyImathColor3ArrayImpl_h_
+
+//
+// This .C file was turned into a header file so that instantiations
+// of the various V3* types can be spread across multiple files in
+// order to work around MSVC limitations.
+//
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathDecorators.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+// XXX fixme - template this
+// really this should get generated automatically...
+
+template <class T,int index>
+static FixedArray<T>
+Color3Array_get(FixedArray<IMATH_NAMESPACE::Color3<T> > &ca)
+{    
+    return FixedArray<T>(&(ca.unchecked_index(0)[index]),
+                         ca.len(),3*ca.stride(),ca.handle(),ca.writable());
+}
+
+// Currently we are only exposing the RGBA components.
+template <class T>
+class_<FixedArray<IMATH_NAMESPACE::Color3<T> > >
+register_Color3Array()
+{
+    class_<FixedArray<IMATH_NAMESPACE::Color3<T> > > color3Array_class = FixedArray<IMATH_NAMESPACE::Color3<T> >::register_("Fixed length array of Imath::Color3");
+    color3Array_class
+        .add_property("r",&Color3Array_get<T,0>)
+        .add_property("g",&Color3Array_get<T,1>)
+        .add_property("b",&Color3Array_get<T,2>)
+        ;
+
+    return color3Array_class;
+}
+
+} // namespace PyImath
+
+#endif // _PyImathColor3ArrayImpl_h_
diff --git a/src/python/PyImath/PyImathColor4.cpp b/src/python/PyImath/PyImathColor4.cpp
new file mode 100644 (file)
index 0000000..f39a143
--- /dev/null
@@ -0,0 +1,660 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <ImathColor.h>
+#include <ImathColorAlgo.h>
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathColor.h"
+#include "PyImathDecorators.h"
+#include "PyImathExport.h"
+#include "PyImathColor4Array2DImpl.h"
+#include "PyImathColor4ArrayImpl.h"
+
+namespace PyImath {
+template <> const char *PyImath::C4cArray::name() { return "C4cArray"; }
+template <> const char *PyImath::C4fArray::name() { return "C4fArray"; }
+
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct Color4Name { static const char *value; };
+template<> const char *Color4Name<unsigned char>::value  = "Color4c";
+template<> const char *Color4Name<float>::value  = "Color4f";
+// template<> const char *Color4ArrayName<float>::value() { return "Color4fArray"; }
+// template<> const char *Color4ArrayName<unsigned char>::value() { return "Color4cArray"; }
+template<> const char *Color4Array2DName<float>::value() { return "Color4fArray2D"; }
+template<> const char *Color4Array2DName<unsigned char>::value() { return "Color4cArray2D"; }
+
+// create a new default constructor that initializes Color4<T> to zero.
+template <class T>
+static Color4<T> * Color4_construct_default()
+{
+    return new Color4<T>(T(0),T(0),T(0),T(0));
+}
+
+template <class T, class S>
+static Color4<T> * Color4_component_construct1(S x, S y, S z, S w)
+{
+    // Assigning a floating point value to an integer type can cause a
+    // float-point error, which we want to translate into an exception. 
+    
+    MATH_EXC_ON;
+
+    if(strcmp(Color4Name<T>::value, "Color4c") == 0)
+    {
+        unsigned char r = (unsigned char) x;
+        unsigned char g = (unsigned char) y;
+        unsigned char b = (unsigned char) z;
+        unsigned char a = (unsigned char) w;
+        return new Color4<T>(r,g,b,a);
+    }
+    else
+        return new Color4<T>(T(x) , T(y), T(z), T(w));
+}
+
+template <class T, class S>
+static Color4<T> * Color4_component_construct2(S x)
+{
+    MATH_EXC_ON;
+    if(strcmp(Color4Name<T>::value, "Color4c") == 0)
+    {
+        unsigned char u = (unsigned char) x;
+
+        return new Color4<T>(u,u,u,u);
+    }
+    else    
+        return new Color4<T>(T(x),T(x),T(x),T(x));
+}
+
+template <class T, class S>
+static Color4<T> * Color4_color_construct(const Color4<S> &c)
+{
+    MATH_EXC_ON;
+    if(strcmp(Color4Name<T>::value, "Color4c") == 0)
+    {
+        unsigned char r = (unsigned char) c.r;
+        unsigned char g = (unsigned char) c.g;
+        unsigned char b = (unsigned char) c.b;
+        unsigned char a = (unsigned char) c.a;
+        
+        return new Color4<T>(r,g,b,a);
+    }
+    else
+     return new Color4<T>(T (c.r), T(c.g), T(c.b), T(c.a));
+}
+
+template <class T>
+static Color4<T> * Color4_construct_tuple(const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 4)
+    {
+        return new Color4<T>(extract<T>(t[0]), 
+                             extract<T>(t[1]), 
+                             extract<T>(t[2]),
+                             extract<T>(t[3]));
+    }
+    else
+        throw std::invalid_argument ("Color4 expects tuple of length 4");
+}
+
+template <class T>
+static Color4<T> * Color4_construct_list(const list &l)
+{
+    MATH_EXC_ON;
+    if(l.attr("__len__")() == 4)
+    {
+        return new Color4<T>(extract<T>(l[0]), 
+                             extract<T>(l[1]), 
+                             extract<T>(l[2]),
+                             extract<T>(l[3]));
+    }
+    else
+        throw std::invalid_argument ("Color4 expects list of length 4");
+}
+
+template <class T>
+static std::string 
+color4_str(const Color4<T> &c)
+{
+    std::stringstream stream;
+    if(strcmp(Color4Name<T>::value, "Color4c") == 0)
+    {
+        int r = int(c.r);
+        int g = int(c.g);
+        int b = int(c.b);
+        int a = int(c.a);
+
+        stream << Color4Name<T>::value << "(" << r << ", " << g << ", " << b << ", " << a << ")";
+        return stream.str();
+    }
+    else
+    {    
+        stream << Color4Name<T>::value << "(" << c.r << ", " << c.g << ", " << c.b << ", " << c.a << ")";
+        return stream.str();
+    }
+}
+
+// Non-specialized repr is same as str
+template <class T>
+static std::string 
+color4_repr(const Color4<T> &c)
+{
+    return color4_str(c);
+}
+
+// Specialization for float to full precision
+template <>
+std::string 
+color4_repr(const Color4<float> &c)
+{
+    return (boost::format("%s(%.9g, %.9g, %.9g, %.9g)")
+                        % Color4Name<float>::value % c.r % c.g % c.b % c.a).str();
+}
+
+// No specialization for double, since we don't instantiate Color4d
+
+
+template <class T>
+static Color4<T>
+hsv2rgb(Color4<T> &color)
+{    
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::hsv2rgb(color);
+}
+
+template <class T>
+static Color4<T>
+hsv2rgbTuple(const tuple &t)
+{
+    MATH_EXC_ON;
+    Color4<T> color;
+    if(t.attr("__len__")() == 4)
+    {
+        color.r = extract<T>(t[0]);
+        color.g = extract<T>(t[1]);
+        color.b = extract<T>(t[2]);
+        color.a = extract<T>(t[3]);
+        
+        return IMATH_NAMESPACE::hsv2rgb(color);
+    }
+    else
+        throw std::invalid_argument ("Color4 expects tuple of length 4");    
+}
+
+template <class T>
+static Color4<T>
+rgb2hsv(Color4<T> &color)
+{    
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::rgb2hsv(color);
+}
+
+template <class T>
+static Color4<T>
+rgb2hsvTuple(const tuple &t)
+{
+    MATH_EXC_ON;
+    Color4<T> color;
+    if(t.attr("__len__")() == 4)
+    {
+        color.r = extract<T>(t[0]);
+        color.g = extract<T>(t[1]);
+        color.b = extract<T>(t[2]);
+        color.a = extract<T>(t[3]);
+        
+        return IMATH_NAMESPACE::rgb2hsv(color);
+    }
+    else
+        throw std::invalid_argument ("Color4 expects tuple of length 4");    
+}
+
+
+template <class T>
+static void
+setValue1(Color4<T> &color, const T &a, const T &b, const T &c, const T &d)
+{
+    MATH_EXC_ON;
+    color.setValue(a, b, c, d);
+}
+
+template <class T>
+static void
+setValue2(Color4<T> &color, const Color4<T> &v)
+{
+    MATH_EXC_ON;
+    color.setValue(v);
+}
+
+template <class T>
+static void
+setValueTuple(Color4<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    Color4<T> v;
+    if(t.attr("__len__")() == 4)
+    {
+        v.r = extract<T>(t[0]);
+        v.g = extract<T>(t[1]);
+        v.b = extract<T>(t[2]);
+        v.a = extract<T>(t[3]);
+        
+        color.setValue(v);
+    }
+    else
+        throw std::invalid_argument ("Color4 expects tuple of length 4");
+}
+
+template <class T>
+static const Color4<T> &
+iadd(Color4<T> &color, const Color4<T> &color2)
+{
+    MATH_EXC_ON;
+    return color += color2;
+}
+
+template <class T>
+static Color4<T>
+add(Color4<T> &color, const Color4<T> &color2)
+{
+    MATH_EXC_ON;
+    return color + color2;
+}
+
+template <class T>
+static Color4<T>
+addTuple(Color4<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 4)
+        return Color4<T>(color.r + extract<T>(t[0]), 
+                         color.g + extract<T>(t[1]), 
+                         color.b + extract<T>(t[2]),
+                         color.a + extract<T>(t[3]));
+    else
+        throw std::invalid_argument ("Color4 expects tuple of length 4");
+}
+
+template <class T>
+static Color4<T>
+addT(Color4<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Color4<T> w(v.r + a, v.g + a, v.b + a, v.a + a);
+    return w;
+}
+
+template <class T>
+static const Color4<T> &
+isub(Color4<T> &color, const Color4<T> &color2)
+{
+    MATH_EXC_ON;
+    return color -= color2;
+}
+
+template <class T>
+static Color4<T>
+sub(Color4<T> &color, const Color4<T> &color2)
+{
+    MATH_EXC_ON;
+    return color - color2;
+}
+
+template <class T>
+static Color4<T>
+subtractL(Color4<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 4)
+        return Color4<T>(color.r - extract<T>(t[0]), 
+                         color.g - extract<T>(t[1]), 
+                         color.b - extract<T>(t[2]),
+                         color.a - extract<T>(t[3]));
+    else
+        throw std::invalid_argument ("Color4 expects tuple of length 4");
+}
+
+template <class T>
+static Color4<T>
+subtractR(Color4<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 4)
+        return Color4<T>(extract<T>(t[0]) - color.r, 
+                         extract<T>(t[1]) - color.g, 
+                         extract<T>(t[2]) - color.b,
+                         extract<T>(t[3]) - color.a);
+    else
+        throw std::invalid_argument ("Color4 expects tuple of length 4");
+}
+
+template <class T>
+static Color4<T>
+subtractLT(const Color4<T> &color, T a)
+{
+    MATH_EXC_ON;
+    return Color4<T>(color.r - a, 
+                     color.g - a, 
+                     color.b - a,
+                     color.a - a);
+}
+
+template <class T>
+static Color4<T>
+subtractRT(const Color4<T> &color, T a)
+{
+    MATH_EXC_ON;
+    return Color4<T>(a - color.r, 
+                     a - color.g, 
+                     a - color.b,
+                     a - color.a);
+}
+
+template <class T>
+static Color4<T>
+neg(Color4<T> &color)
+{
+    MATH_EXC_ON;
+    return -color;
+}
+
+template <class T>
+static const Color4<T> &
+negate(Color4<T> &color)
+{
+    MATH_EXC_ON;
+    return color.negate();
+}
+
+template <class T>
+static const Color4<T> &
+imul(Color4<T> &color, const Color4<T> &color2)
+{
+    MATH_EXC_ON;
+    return color *= color2;
+}
+
+template <class T>
+static const Color4<T> &
+imulT(Color4<T> &color, const T &t)
+{
+    MATH_EXC_ON;
+    return color *= t;
+}
+
+template <class T>
+static Color4<T>
+mul(Color4<T> &color, const Color4<T> &color2)
+{
+    MATH_EXC_ON;
+    return color * color2;
+}
+
+template <class T>
+static Color4<T>
+mulT(Color4<T> &color, const T &t)
+{
+    MATH_EXC_ON;
+    return color * t;
+}
+
+template <class T>
+static Color4<T>
+rmulT(Color4<T> &color, const T &t)
+{
+    MATH_EXC_ON;
+    return t * color;
+}
+
+template <class T>
+static Color4<T>
+mulTuple(Color4<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 4)
+        return Color4<T>(color.r * extract<T>(t[0]), 
+                         color.g * extract<T>(t[1]), 
+                         color.b * extract<T>(t[2]),
+                         color.a * extract<T>(t[3]));
+    else
+        throw std::invalid_argument ("Color4 expects tuple of length 4");
+}
+
+template <class T>
+static const Color4<T> &
+idiv(Color4<T> &color, const Color4<T> &color2)
+{
+    MATH_EXC_ON;
+    return color /= color2;
+}
+
+template <class T>
+static const Color4<T> &
+idivT(Color4<T> &color, const T &t)
+{
+    MATH_EXC_ON;
+    return color /= t;
+}
+
+template <class T>
+static Color4<T>
+div(Color4<T> &color, const Color4<T> &color2)
+{
+    MATH_EXC_ON;
+    return color / color2;
+}
+
+template <class T>
+static Color4<T>
+divT(Color4<T> &color, const T &t)
+{
+    MATH_EXC_ON;
+    return color / t;
+}
+
+template <class T>
+static Color4<T>
+divTupleL(Color4<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 4)
+        return Color4<T>(color.r / extract<T>(t[0]), 
+                         color.g / extract<T>(t[1]), 
+                         color.b / extract<T>(t[2]),
+                         color.a / extract<T>(t[3]));
+    else
+        throw std::invalid_argument ("Color4 expects tuple of length 4");    
+}
+
+template <class T>
+static Color4<T>
+divTupleR(Color4<T> &color, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 4)
+        return Color4<T>(extract<T>(t[0]) / color.r, 
+                         extract<T>(t[1]) / color.g, 
+                         extract<T>(t[2]) / color.b,
+                         extract<T>(t[3]) / color.a);
+    else
+        throw std::invalid_argument ("Color4 expects tuple of length 4");    
+}
+
+template <class T>
+static Color4<T>
+divTR(Color4<T> &color, T a)
+{
+    MATH_EXC_ON;
+    return Color4<T>(a / color.r,
+                     a / color.g,
+                     a / color.b,
+                     a / color.a);
+}
+
+template <class T>
+static bool
+lessThan(Color4<T> &v, const Color4<T> &w)
+{
+    bool isLessThan = (v.r <= w.r && v.g <= w.g && v.b <= w.b && v.a <= w.a)
+                    && v != w;
+                   
+   return isLessThan;
+}
+
+template <class T>
+static bool
+greaterThan(Color4<T> &v, const Color4<T> &w)
+{
+    bool isGreaterThan = (v.r >= w.r && v.g >= w.g && v.b >= w.b && v.a >= w.a)
+                       && v != w;
+                   
+   return isGreaterThan;
+}
+
+template <class T>
+static bool
+lessThanEqual(Color4<T> &v, const Color4<T> &w)
+{
+    bool isLessThanEqual = (v.r <= w.r && v.g <= w.g && v.b <= w.b && v.a <= w.a);
+
+    return isLessThanEqual;
+}
+
+template <class T>
+static bool
+greaterThanEqual(Color4<T> &v, const Color4<T> &w)
+{
+    bool isGreaterThanEqual = (v.r >= w.r && v.g >= w.g && v.b >= w.b) && v.a >= w.a;
+
+    return isGreaterThanEqual;
+}
+
+template <class T>
+class_<Color4<T> >
+register_Color4()
+{
+    typedef PyImath::StaticFixedArray<Color4<T>,T,4> Color4_helper;
+    void (IMATH_NAMESPACE::Color4<T>::*getValue1)(Color4<T> &) const = &IMATH_NAMESPACE::Color4<T>::getValue;
+    void (IMATH_NAMESPACE::Color4<T>::*getValue2)(T &, T &, T &, T &) const = &IMATH_NAMESPACE::Color4<T>::getValue;
+
+    class_<Color4<T> > color4_class(Color4Name<T>::value, Color4Name<T>::value,init<Color4<T> >("copy construction"));
+    color4_class
+        .def("__init__",make_constructor(Color4_construct_default<T>),"initialize to (0,0,0,0)")
+        .def("__init__",make_constructor(Color4_construct_tuple<T>), "initialize to (r,g,b,a) with a python tuple")
+        .def("__init__",make_constructor(Color4_construct_list<T>), "initialize to (r,g,b,a) with a python list")
+        .def("__init__",make_constructor(Color4_component_construct1<T,float>))
+        .def("__init__",make_constructor(Color4_component_construct1<T,int>))
+        .def("__init__",make_constructor(Color4_component_construct2<T,float>))
+        .def("__init__",make_constructor(Color4_component_construct2<T,int>))
+        .def("__init__",make_constructor(Color4_color_construct<T,float>))
+        .def("__init__",make_constructor(Color4_color_construct<T,int>))
+        .def("__init__",make_constructor(Color4_color_construct<T,unsigned char>))
+        .def_readwrite("r", &Color4<T>::r)
+        .def_readwrite("g", &Color4<T>::g)
+        .def_readwrite("b", &Color4<T>::b)
+        .def_readwrite("a", &Color4<T>::a)
+        .def("__str__", &color4_str<T>)
+        .def("__repr__", &color4_repr<T>)
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__iadd__", &iadd<T>,return_internal_reference<>())
+        .def("__add__", &add<T>)
+        .def("__add__", &addTuple<T>)
+        .def("__add__", &addT<T>)
+        .def("__radd__", &addTuple<T>)
+        .def("__radd__", &addT<T>)
+        .def("__isub__", &isub<T>,return_internal_reference<>())
+        .def("__sub__", &sub<T>)
+        .def("__sub__", &subtractL<T>)
+        .def("__sub__", &subtractLT<T>)
+        .def("__rsub__", &subtractR<T>)
+        .def("__rsub__", &subtractRT<T>)
+        .def("__neg__", &neg<T>)
+        .def("negate",&negate<T>,return_internal_reference<>(),"component-wise multiplication by -1")
+        .def("__imul__", &imul<T>,return_internal_reference<>())
+        .def("__imul__", &imulT<T>,return_internal_reference<>())
+        .def("__mul__", &mul<T>)
+        .def("__mul__", &mulT<T>)
+        .def("__rmul__", &mulT<T>)
+        .def("__mul__", &mulTuple<T>)
+        .def("__rmul__", &mulTuple<T>)
+        .def("__idiv__", &idiv<T>,return_internal_reference<>())
+        .def("__idiv__", &idivT<T>,return_internal_reference<>())
+        .def("__itruediv__", &idiv<T>,return_internal_reference<>())
+        .def("__itruediv__", &idivT<T>,return_internal_reference<>())
+        .def("__div__", &div<T>)
+        .def("__div__", &divT<T>)
+        .def("__div__", &divTupleL<T>)
+        .def("__truediv__", &div<T>)
+        .def("__truediv__", &divT<T>)
+        .def("__truediv__", &divTupleL<T>)
+        .def("__rdiv__", &divTupleR<T>)  
+        .def("__rdiv__", &divTR<T>)
+        .def("__rtruediv__", &divTupleR<T>)  
+        .def("__rtruediv__", &divTR<T>)
+        .def("__lt__", &lessThan<T>)
+        .def("__gt__", &greaterThan<T>)
+        .def("__le__", &lessThanEqual<T>)
+        .def("__ge__", &greaterThanEqual<T>)
+        .def("__len__", Color4_helper::len)
+        .def("__getitem__", Color4_helper::getitem,return_value_policy<copy_non_const_reference>())
+        .def("__setitem__", Color4_helper::setitem)
+           .def("dimensions", &Color4<T>::dimensions,"dimensions() number of dimensions in the color")
+        .staticmethod("dimensions")
+        .def("baseTypeEpsilon", &Color4<T>::baseTypeEpsilon,"baseTypeEpsilon() epsilon value of the base type of the color")
+        .staticmethod("baseTypeEpsilon")
+        .def("baseTypeMax", &Color4<T>::baseTypeMax,"baseTypeMax() max value of the base type of the color")
+        .staticmethod("baseTypeMax")
+        .def("baseTypeLowest", &Color4<T>::baseTypeLowest,"baseTypeLowest() largest negative value of the base type of the color")
+        .staticmethod("baseTypeLowest")
+        .def("baseTypeSmallest", &Color4<T>::baseTypeSmallest,"baseTypeSmallest() smallest value of the base type of the color")
+        .staticmethod("baseTypeSmallest")
+        .def("__repr__",&color4_repr<T>)
+        .def("hsv2rgb", &hsv2rgb<T>, 
+            "C.hsv2rgb() -- returns a new color which "
+             "is C converted from RGB to HSV")
+         
+         .def("hsv2rgb", &rgb2hsvTuple<T>)
+         
+         .def("rgb2hsv", &rgb2hsv<T>,                          
+              "C.rgb2hsv() -- returns a new color which "
+              "is C converted from HSV to RGB")
+         .def("rgb2hsv", &rgb2hsvTuple<T>)
+         
+         .def("setValue", &setValue1<T>,                               
+              "C1.setValue(C2)\nC1.setValue(a,b,c) -- "
+              "set C1's  elements")         
+         .def("setValue", &setValue2<T>)
+         .def("setValue", &setValueTuple<T>)
+    
+        .def("getValue", getValue1, "getValue()")
+        .def("getValue", getValue2)
+        ;
+
+    decoratecopy(color4_class);
+
+    return color4_class;
+}
+
+template PYIMATH_EXPORT class_<Color4<float> > register_Color4<float>();
+template PYIMATH_EXPORT class_<Color4<unsigned char> > register_Color4<unsigned char>();
+template PYIMATH_EXPORT class_<FixedArray<Color4<float> > > register_Color4Array<float>();
+template PYIMATH_EXPORT class_<FixedArray<Color4<unsigned char> > > register_Color4Array<unsigned char>();
+template PYIMATH_EXPORT class_<FixedArray2D<Color4<float> > > register_Color4Array2D<float>();
+template PYIMATH_EXPORT class_<FixedArray2D<Color4<unsigned char> > > register_Color4Array2D<unsigned char>();
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Color4<float> PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Color4<float> >::value()
+{ return IMATH_NAMESPACE::Color4<float>(0,0,0, 0); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Color4<unsigned char> PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Color4<unsigned char> >::value()
+{ return IMATH_NAMESPACE::Color4<unsigned char>(0,0,0,0); }
+}
diff --git a/src/python/PyImath/PyImathColor4Array2DImpl.h b/src/python/PyImath/PyImathColor4Array2DImpl.h
new file mode 100644 (file)
index 0000000..2d52f6b
--- /dev/null
@@ -0,0 +1,565 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathColor4Array2DImpl_h_
+#define _PyImathColor4Array2DImpl_h_
+
+//
+// This .C file was turned into a header file so that instantiations
+// of the various V3* types can be spread across multiple files in
+// order to work around MSVC limitations.
+//
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathDecorators.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct Color4Array2DName { static const char *value(); };
+
+
+// XXX fixme - template this
+// really this should get generated automatically...
+
+template <class T,int index>
+static FixedArray2D<T>
+Color4Array2D_get(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va)
+{
+    return FixedArray2D<T>(&va(0,0)[index], va.len().x,va.len().y, 4*va.stride().x, va.stride().y, va.handle());
+}
+
+
+// template <class T> 
+// static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+// Color4Array_cross0(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &vb) 
+// { 
+//     PY_IMATH_LEAVE_PYTHON;
+//     IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb); 
+//     FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+//     for (size_t i = 0; i < len; ++i) 
+//         f(i,j) = va(i,j).cross(vb(i,j)); 
+//     return f; 
+// }
+// 
+// template <class T> 
+// static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+// Color4Array_cross1(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Color4<T> &vb) 
+// { 
+//     PY_IMATH_LEAVE_PYTHON;
+//     IMATH_NAMESPACE::Vec2<size_t> len = va.len(); 
+//     FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+//     for (size_t i = 0; i < len; ++i) 
+//         f(i,j) = va(i,j).cross(vb); 
+//     return f; 
+// }
+// 
+// template <class T> 
+// static FixedArray2D<T>
+// Color4Array_dot0(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &vb) 
+// { 
+//     PY_IMATH_LEAVE_PYTHON;
+//     IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+//     FixedArray2D<T> f(len); 
+//     for (size_t i = 0; i < len; ++i) 
+//         f(i,j) = va(i,j).dot(vb(i,j)); 
+//     return f; 
+// }
+// 
+// template <class T> 
+// static FixedArray2D<T>
+// Color4Array_dot1(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Color4<T> &vb) 
+// { 
+//     PY_IMATH_LEAVE_PYTHON;
+//     IMATH_NAMESPACE::Vec2<size_t> len = va.len(); 
+//     FixedArray2D<T> f(len); 
+//     for (size_t i = 0; i < len; ++i) 
+//         f(i,j) = va(i,j).dot(vb); 
+//     return f; 
+// }
+
+// template <class T> 
+// static FixedArray2D<T>
+// Color4Array_length(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va) 
+// { 
+//     PY_IMATH_LEAVE_PYTHON;
+//     IMATH_NAMESPACE::Vec2<size_t> len = va.len(); 
+//     FixedArray2D<T> f(len); 
+//     for (size_t i = 0; i < len; ++i) 
+//         f(i,j) = va(i,j).length(); 
+//     return f; 
+// }
+// 
+// template <class T> 
+// static FixedArray2D<T>
+// Color4Array_length2(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va) 
+// { 
+//     PY_IMATH_LEAVE_PYTHON;
+//     IMATH_NAMESPACE::Vec2<size_t> len = va.len(); 
+//     FixedArray2D<T> f(len); 
+//     for (size_t i = 0; i < len; ++i) 
+//         f(i,j) = va(i,j).length2(); 
+//     return f; 
+// }
+// 
+// template <class T> 
+// static FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+// Color4Array_normalize(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va) 
+// { 
+//     PY_IMATH_LEAVE_PYTHON;
+//     IMATH_NAMESPACE::Vec2<size_t> len = va.len(); 
+//     for (size_t i = 0; i < len; ++i) 
+//         va(i,j).normalize(); 
+//     return va; 
+// }
+// 
+// template <class T> static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+// Color4Array_normalized(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va) 
+// { 
+//     PY_IMATH_LEAVE_PYTHON;
+//     IMATH_NAMESPACE::Vec2<size_t> len = va.len(); 
+//     FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+//     for (size_t i = 0; i < len; ++i) 
+//         f(i,j) = va(i,j).normalized(); 
+//     return f; 
+// }
+// 
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_mulT(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, T t) 
+{
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len();
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len);
+    for (size_t j = 0; j < len.y; ++j)
+        for (size_t i = 0; i < len.x; ++i)
+            f(i,j) = va(i,j) * t; 
+    return f; 
+}
+// 
+// template <class T, class U> 
+// static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+// Color4Array_mulM44(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Matrix44<U> &m) 
+// { 
+//     PY_IMATH_LEAVE_PYTHON;
+//     IMATH_NAMESPACE::Vec2<size_t> len = va.len(); 
+//     FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+//     for (size_t i = 0; i < len; ++i) 
+//         f(i,j) = va(i,j) * m; 
+//     return f; 
+// }
+// 
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_mulArrayT(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j)
+        for (size_t i = 0; i < len.x; ++i)
+            f(i,j) = va(i,j) * vb(i,j);
+    return f; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_imulT(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, T t) 
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len(); 
+    for (size_t j = 0; j < len.y; ++j)
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) *= t; 
+    return va; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_imulArrayT(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    for (size_t j = 0; j < len.y; ++j)
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) *= vb(i,j); 
+    return va; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_divT(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, T t) 
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len(); 
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = va(i,j) / t; 
+    return f; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_divArrayT(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = va(i,j) / vb(i,j); 
+    return f; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_idivT(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, T t) 
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len(); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) /= t; 
+    return va; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_idivArrayT(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) /= vb(i,j); 
+    return va; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_add(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = va(i,j) + vb(i,j); 
+    return f; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_addColor(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Color4<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len();
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = va(i,j) + vb; 
+    return f; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_sub(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = va(i,j) - vb(i,j); 
+    return f; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_subColor(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Color4<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len();
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = va(i,j) - vb; 
+    return f; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_rsubColor(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Color4<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len();
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = vb - va(i,j); 
+    return f; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_mul(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = va(i,j) * vb(i,j); 
+    return f; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_mulColor(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Color4<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len();
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = va(i,j) * vb; 
+    return f; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_div(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = va(i,j) / vb(i,j); 
+    return f; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_divColor(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Color4<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len();
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = va(i,j) / vb; 
+    return f; 
+}
+
+template <class T> 
+static FixedArray2D<IMATH_NAMESPACE::Color4<T> >
+Color4Array_neg(const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len();
+    FixedArray2D<IMATH_NAMESPACE::Color4<T> > f(len); 
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            f(i,j) = -va(i,j);
+    return f; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_iadd(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) += vb(i,j); 
+    return va; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_iaddColor(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Color4<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len();
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) += vb; 
+    return va; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_isub(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) -= vb(i,j); 
+    return va; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_isubColor(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Color4<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len();
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) -= vb; 
+    return va; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_imul(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) *= vb(i,j); 
+    return va; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_imulColor(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Color4<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len();
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) *= vb; 
+    return va; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_idiv(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.match_dimension(vb);
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) /= vb(i,j); 
+    return va; 
+}
+
+template <class T> 
+static const FixedArray2D<IMATH_NAMESPACE::Color4<T> > &
+Color4Array_idivColor(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const IMATH_NAMESPACE::Color4<T> &vb)
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    IMATH_NAMESPACE::Vec2<size_t> len = va.len();
+    for (size_t j = 0; j < len.y; ++j) 
+        for (size_t i = 0; i < len.x; ++i) 
+            va(i,j) /= vb; 
+    return va; 
+}
+
+template <class T>
+static void
+setItemTuple(FixedArray2D<IMATH_NAMESPACE::Color4<T> > &va, const tuple &index, const tuple &t)
+{
+    if(t.attr("__len__")() == 4 && index.attr("__len__")() == 2)
+    {
+        Color4<T> v;
+        v.r = extract<T>(t[0]);
+        v.g = extract<T>(t[1]);
+        v.b = extract<T>(t[2]);
+        v.a = extract<T>(t[3]);
+        va(va.canonical_index(extract<Py_ssize_t>(index[0]),va.len()[0]),
+           va.canonical_index(extract<Py_ssize_t>(index[1]),va.len()[1])) = v;
+    }
+    else
+      throw std::invalid_argument ("tuple of length 4 expected");
+}
+
+template <class T>
+class_<FixedArray2D<IMATH_NAMESPACE::Color4<T> > >
+register_Color4Array2D()
+{
+    class_<FixedArray2D<IMATH_NAMESPACE::Color4<T> > > color4Array2D_class =
+        FixedArray2D<IMATH_NAMESPACE::Color4<T> >::register_(Color4Array2DName<T>::value(),"Fixed length 2d array of IMATH_NAMESPACE::Color4");
+    color4Array2D_class
+        .add_property("r",&Color4Array2D_get<T,0>)
+        .add_property("g",&Color4Array2D_get<T,1>)
+        .add_property("b",&Color4Array2D_get<T,2>)
+        .add_property("a",&Color4Array2D_get<T,3>)
+//         .def("dot",&Color4Array_dot0<T>)
+//         .def("dot",&Color4Array_dot1<T>)
+//         .def("cross", &Color4Array_cross0<T>)
+//         .def("cross", &Color4Array_cross1<T>)
+//         .def("length", &Color4Array_length<T>)
+//         .def("length2", &Color4Array_length2<T>)
+//         .def("normalize", &Color4Array_normalize<T>,return_internal_reference<>())
+//         .def("normalized", &Color4Array_normalized<T>)
+        .def("__setitem__", &setItemTuple<T>)
+        .def("__mul__", &Color4Array_mulT<T>)
+//         .def("__mul__", &Color4Array_mulM44<T, float>)
+//         .def("__mul__", &Color4Array_mulM44<T, double>)
+        .def("__rmul__", &Color4Array_mulT<T>)
+        .def("__mul__", &Color4Array_mulArrayT<T>)
+        .def("__rmul__", &Color4Array_mulArrayT<T>)
+        .def("__imul__", &Color4Array_imulT<T>,return_internal_reference<>())
+        .def("__imul__", &Color4Array_imulArrayT<T>,return_internal_reference<>())
+        .def("__div__", &Color4Array_divT<T>)
+        .def("__div__", &Color4Array_divArrayT<T>)
+        .def("__truediv__", &Color4Array_divT<T>)
+        .def("__truediv__", &Color4Array_divArrayT<T>)
+        .def("__idiv__", &Color4Array_idivT<T>,return_internal_reference<>())
+        .def("__idiv__", &Color4Array_idivArrayT<T>,return_internal_reference<>())
+        .def("__itruediv__", &Color4Array_idivT<T>,return_internal_reference<>())
+        .def("__itruediv__", &Color4Array_idivArrayT<T>,return_internal_reference<>())
+        .def("__add__",&Color4Array_add<T>)
+        .def("__add__",&Color4Array_addColor<T>)
+        .def("__radd__",&Color4Array_addColor<T>)
+        .def("__sub__",&Color4Array_sub<T>)
+        .def("__sub__",&Color4Array_subColor<T>)
+        .def("__rsub__",&Color4Array_rsubColor<T>)
+        .def("__mul__",&Color4Array_mul<T>)
+        .def("__mul__",&Color4Array_mulColor<T>)
+        .def("__rmul__",&Color4Array_mulColor<T>)
+        .def("__div__",&Color4Array_div<T>)
+        .def("__div__",&Color4Array_divColor<T>)
+        .def("__truediv__",&Color4Array_div<T>)
+        .def("__truediv__",&Color4Array_divColor<T>)
+        .def("__neg__",&Color4Array_neg<T>)
+        .def("__iadd__",&Color4Array_iadd<T>, return_internal_reference<>())
+        .def("__iadd__",&Color4Array_iaddColor<T>, return_internal_reference<>())
+        .def("__isub__",&Color4Array_isub<T>, return_internal_reference<>())
+        .def("__isub__",&Color4Array_isubColor<T>, return_internal_reference<>())
+        .def("__imul__",&Color4Array_imul<T>, return_internal_reference<>())
+        .def("__imul__",&Color4Array_imulColor<T>, return_internal_reference<>())
+        .def("__idiv__",&Color4Array_idiv<T>, return_internal_reference<>())
+        .def("__idiv__",&Color4Array_idivColor<T>, return_internal_reference<>())
+        .def("__itruediv__",&Color4Array_idiv<T>, return_internal_reference<>())
+        .def("__itruediv__",&Color4Array_idivColor<T>, return_internal_reference<>())
+        ;
+
+    add_comparison_functions(color4Array2D_class);
+    decoratecopy(color4Array2D_class);
+
+    return color4Array2D_class;
+}
+
+
+}  // namespace PyImath
+
+#endif   // _PyImathColor4ArrayImpl_h_
diff --git a/src/python/PyImath/PyImathColor4ArrayImpl.h b/src/python/PyImath/PyImathColor4ArrayImpl.h
new file mode 100644 (file)
index 0000000..dd0bfb7
--- /dev/null
@@ -0,0 +1,59 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathColor4ArrayImpl_h_
+#define _PyImathColor4ArrayImpl_h_
+
+//
+// This .C file was turned into a header file so that instantiations
+// of the various V3* types can be spread across multiple files in
+// order to work around MSVC limitations.
+//
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathDecorators.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+// XXX fixme - template this
+// really this should get generated automatically...
+
+template <class T,int index>
+static FixedArray<T>
+Color4Array_get(FixedArray<IMATH_NAMESPACE::Color4<T> > &ca)
+{    
+    return FixedArray<T>(&(ca.unchecked_index(0)[index]),
+                         ca.len(),4*ca.stride(),ca.handle(),ca.writable());
+}
+
+// Currently we are only exposing the RGBA components.
+template <class T>
+class_<FixedArray<IMATH_NAMESPACE::Color4<T> > >
+register_Color4Array()
+{
+    class_<FixedArray<IMATH_NAMESPACE::Color4<T> > > color4Array_class = FixedArray<IMATH_NAMESPACE::Color4<T> >::register_("Fixed length array of IMATH_NAMESPACE::Color4");
+    color4Array_class
+        .add_property("r",&Color4Array_get<T,0>)
+        .add_property("g",&Color4Array_get<T,1>)
+        .add_property("b",&Color4Array_get<T,2>)
+        .add_property("a",&Color4Array_get<T,3>)
+        ;
+
+    return color4Array_class;
+}
+
+} // namespace PyImath
+
+#endif // _PyImathColor4ArrayImpl_h_
diff --git a/src/python/PyImath/PyImathDecorators.h b/src/python/PyImath/PyImathDecorators.h
new file mode 100644 (file)
index 0000000..3eb6ab7
--- /dev/null
@@ -0,0 +1,48 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef INCLUDED_PYIMATH_DECORATORS_H
+#define INCLUDED_PYIMATH_DECORATORS_H
+
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+
+namespace PyImath
+{
+
+// These function add __copy__ and __deepcopy__ methods
+// to python classes by simply wrapping the copy constructors
+// This interface is needed for using these classes with
+// the python copy module.
+
+template <class T>
+static T
+copy(const T& x)
+{
+    return T(x);
+}
+
+template <class T>
+static T
+deepcopy(const T& x, boost::python::dict&)
+{
+    return copy(x);
+}
+
+template <class T, class X1, class X2, class X3>
+boost::python::class_<T,X1,X2,X3>&
+decoratecopy(boost::python::class_<T,X1,X2,X3>& cls)
+{
+    cls.def("__copy__",&copy<T>);
+    cls.def("__deepcopy__",&deepcopy<T>);
+    return cls;
+}
+
+} // namespace PyImath
+
+#endif // INCLUDED_PYIMATH_DECORATORS_H
+
diff --git a/src/python/PyImath/PyImathEuler.cpp b/src/python/PyImath/PyImathEuler.cpp
new file mode 100644 (file)
index 0000000..2de636f
--- /dev/null
@@ -0,0 +1,841 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <ImathVec.h>
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathEuler.h"
+#include "PyImathDecorators.h"
+#include "PyImathExport.h"
+#include "PyImathOperators.h"
+
+// XXX incomplete array wrapping, docstrings missing
+
+namespace PyImath {
+template<> const char *PyImath::EulerfArray::name() { return "EulerfArray"; }
+template<> const char *PyImath::EulerdArray::name() { return "EulerdArray"; }
+}
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct EulerName { static const char *value; };
+template<> const char *EulerName<float>::value  = "Eulerf";
+template<> const char *EulerName<double>::value = "Eulerd";
+
+template <class T>
+static std::string nameOfOrder(typename IMATH_NAMESPACE::Euler<T>::Order order)
+{
+    switch(order)
+    {
+        case IMATH_NAMESPACE::Euler<T>::XYZ:
+            return "EULER_XYZ";
+        case IMATH_NAMESPACE::Euler<T>::XZY:
+            return "EULER_XZY";
+        case IMATH_NAMESPACE::Euler<T>::YZX:
+            return "EULER_YZX";
+        case IMATH_NAMESPACE::Euler<T>::YXZ:
+            return "EULER_YXZ";
+        case IMATH_NAMESPACE::Euler<T>::ZXY:
+            return "EULER_ZXY";
+        case IMATH_NAMESPACE::Euler<T>::ZYX:
+            return "EULER_ZYX";
+        case IMATH_NAMESPACE::Euler<T>::XZX:
+            return "EULER_XZX";
+        case IMATH_NAMESPACE::Euler<T>::XYX:
+            return "EULER_XYX";
+        case IMATH_NAMESPACE::Euler<T>::YXY:
+            return "EULER_YXY";
+        case IMATH_NAMESPACE::Euler<T>::YZY:
+            return "EULER_YZY";
+        case IMATH_NAMESPACE::Euler<T>::ZYZ:
+            return "EULER_ZYZ";
+        case IMATH_NAMESPACE::Euler<T>::ZXZ:
+            return "EULER_ZXZ";
+        case IMATH_NAMESPACE::Euler<T>::XYZr:
+            return "EULER_XYZr";
+        case IMATH_NAMESPACE::Euler<T>::XZYr:
+            return "EULER_XZYr";
+        case IMATH_NAMESPACE::Euler<T>::YZXr:
+            return "EULER_YZXr";
+        case IMATH_NAMESPACE::Euler<T>::YXZr:
+            return "EULER_YXZr";
+        case IMATH_NAMESPACE::Euler<T>::ZXYr:
+            return "EULER_ZXYr";
+        case IMATH_NAMESPACE::Euler<T>::ZYXr:
+            return "EULER_ZYXr";
+        case IMATH_NAMESPACE::Euler<T>::XZXr:
+            return "EULER_XZXr";
+        case IMATH_NAMESPACE::Euler<T>::XYXr:
+            return "EULER_XYXr";
+        case IMATH_NAMESPACE::Euler<T>::YXYr:
+            return "EULER_YXYr";
+        case IMATH_NAMESPACE::Euler<T>::YZYr:
+            return "EULER_YZYr";
+        case IMATH_NAMESPACE::Euler<T>::ZYZr:
+            return "EULER_ZYZr";
+        case IMATH_NAMESPACE::Euler<T>::ZXZr:
+            return "EULER_ZXZr";
+        default:
+            break;
+    }
+    
+    return "";
+}
+
+template <class T>
+static std::string Euler_str(const Euler<T> &e)
+{
+    std::stringstream stream;
+    stream << EulerName<T>::value << "(" << e.x << ", " << e.y << ", " << e.z << ", " 
+           << nameOfOrder<T> (e.order()) << ")";
+    return stream.str();
+}
+
+// Non-specialized repr is same as str
+template <class T>
+static std::string Euler_repr(const Euler<T> &e)
+{
+    return Euler_str(e);
+}
+
+// Specialization for float to full precision
+template <>
+std::string Euler_repr(const Euler<float> &e)
+{
+    return (boost::format("%s(%.9g, %.9g, %.9g, %s)")
+                        % EulerName<float>::value
+                        % e.x % e.y % e.z
+                        % nameOfOrder<float>(e.order()).c_str()).str();
+}
+
+// Specialization for double to full precision
+template <>
+std::string Euler_repr(const Euler<double> &e)
+{
+    return (boost::format("%s(%.17g, %.17g, %.17g, %s)")
+                        % EulerName<double>::value
+                        % e.x % e.y % e.z
+                        % nameOfOrder<double>(e.order()).c_str()).str();
+}
+
+
+template <class T>
+static bool
+equal(const Euler<T> &e0, const Euler<T> &e1)
+{
+    if(e0.x == e1.x && e0.y == e1.y && e0.z == e1.z && (e0.order())==(e1.order()))
+        return true;
+    else
+        return false;
+}
+
+template <class T>
+static bool
+notequal(const Euler<T> &e0, const Euler<T> &e1)
+{
+    if(e0.x != e1.x || e0.y != e1.y || e0.z != e1.z || (e0.order()) != (e1.order()))
+    {
+        return true;
+    }
+    else
+        return false;
+}
+
+template <class T>
+static IMATH_NAMESPACE::Vec3 <int> getAngleOrder(Euler <T> &euler)
+{
+    int i, j, k;
+    euler.angleOrder(i, j, k);
+    return IMATH_NAMESPACE::Vec3 <int> (i, j, k);
+}
+
+template <class T>
+static void
+setXYZTuple(Euler<T> &euler, const tuple &t)
+{
+    MATH_EXC_ON;
+    Vec3<T> v;
+    if(t.attr("__len__")() == 3)
+    {
+        v.x = extract<T>(t[0]);
+        v.y = extract<T>(t[1]);
+        v.z = extract<T>(t[2]); 
+        
+        euler.setXYZVector(v);
+    }
+    else
+        throw std::invalid_argument ("Color3 expects tuple of length 3");    
+}
+
+// needed to convert Eulerf::Order to Euler<T>::Order
+template <class T>
+static typename Euler<T>::Order interpretOrder(typename IMATH_NAMESPACE::Eulerf::Order order)
+{
+    typename Euler<T>::Order o = Euler<T>::XYZ;
+    switch(order)
+    {
+        case IMATH_NAMESPACE::Eulerf::XYZ:
+        {
+            o = Euler<T>::XYZ;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::XZY:
+        {
+            o = Euler<T>::XZY;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::YZX:
+        {
+            o = Euler<T>::YZX;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::YXZ:
+        {
+            o = Euler<T>::YXZ;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::ZXY:
+        {
+            o = Euler<T>::ZXY;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::ZYX:
+        {
+            o = Euler<T>::ZYX;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::XZX:
+        {
+            o = Euler<T>::XZX;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::XYX:
+        {
+            o = Euler<T>::XYX;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::YXY:
+        {
+            o = Euler<T>::YXY;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::YZY:
+        {
+            o = Euler<T>::YZY;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::ZYZ:
+        {
+            o = Euler<T>::ZYZ;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::ZXZ:
+        {
+            o = Euler<T>::ZXZ;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::XYZr:
+        {
+            o = Euler<T>::XYZr;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::XZYr:
+        {
+            o = Euler<T>::XZYr;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::YZXr:
+        {
+            o = Euler<T>::YZXr;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::YXZr:
+        {
+            o = Euler<T>::YXZr;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::ZXYr:
+        {
+            o = Euler<T>::ZXYr;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::ZYXr:
+        {
+            o = Euler<T>::ZYXr;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::XZXr:
+        {
+            o = Euler<T>::XZXr;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::XYXr:
+        {
+            o = Euler<T>::XYXr;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::YXYr:
+        {
+            o = Euler<T>::YXYr;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::YZYr:
+        {
+            o = Euler<T>::YZYr;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::ZYZr:
+        {
+            o = Euler<T>::ZYZr;
+        }break;
+        case IMATH_NAMESPACE::Eulerf::ZXZr:
+        {
+            o = Euler<T>::ZXZr;
+        }break;            
+        default:
+            break;
+    }
+    
+    return o;
+}
+
+// needed to convert Eulerf::Axis to Euler<T>::Axis
+template <class T>
+static typename Euler<T>::Axis interpretAxis(typename IMATH_NAMESPACE::Eulerf::Axis axis)
+{
+    if (axis == IMATH_NAMESPACE::Eulerf::X)
+        return Euler<T>::X;
+    else if (axis == IMATH_NAMESPACE::Eulerf::Y)
+        return Euler<T>::Y;
+    else
+        return Euler<T>::Z;
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor1(const Vec3<T> &v, typename IMATH_NAMESPACE::Eulerf::Order order)
+{
+    typename Euler<T>::Order o = interpretOrder<T>(order);
+    return new Euler<T>(v, o);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor1a(const Vec3<T> &v)
+{
+    return eulerConstructor1 (v, IMATH_NAMESPACE::Eulerf::Default);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor1b(const Vec3<T> &v, int iorder)
+{
+    typename Euler<T>::Order o = typename Euler<T>::Order (iorder);
+    return new Euler<T>(v, o);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor2(T i, T j, T k, typename IMATH_NAMESPACE::Eulerf::Order order)
+{
+    typename Euler<T>::Order o = interpretOrder<T>(order);
+    return new Euler<T>(i, j, k, o);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor2a(T i, T j, T k)
+{
+    return eulerConstructor2 (i, j, k, IMATH_NAMESPACE::Eulerf::Default);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor2b(T i, T j, T k, int iorder)
+{
+    typename Euler<T>::Order o = typename Euler<T>::Order (iorder);
+    return new Euler<T>(i, j, k, o);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor3(const Matrix33<T> &mat, typename IMATH_NAMESPACE::Eulerf::Order order)
+{
+    typename Euler<T>::Order o = interpretOrder<T>(order);
+    return new Euler<T>(mat, o);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor3a(const Matrix33<T> &mat)
+{
+    return eulerConstructor3 (mat, IMATH_NAMESPACE::Eulerf::Default);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor3b(const Matrix33<T> &mat, int iorder)
+{
+    typename Euler<T>::Order o = typename Euler<T>::Order (iorder);
+    return new Euler<T>(mat, o);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor4(const Matrix44<T> &mat, typename IMATH_NAMESPACE::Eulerf::Order order)
+{
+    typename Euler<T>::Order o = interpretOrder<T>(order);
+    return new Euler<T>(mat, o);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor4a(const Matrix44<T> &mat)
+{
+    return eulerConstructor4 (mat, IMATH_NAMESPACE::Eulerf::Default);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor4b(const Matrix44<T> &mat, int iorder)
+{
+    typename Euler<T>::Order o = typename Euler<T>::Order (iorder);
+    return new Euler<T>(mat, o);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor5(typename IMATH_NAMESPACE::Eulerf::Order order)
+{
+    typename Euler<T>::Order o = interpretOrder<T>(order);
+    return new Euler<T>(o);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor5a()
+{
+    typename Euler<T>::Order o = interpretOrder<T>(IMATH_NAMESPACE::Eulerf::Default);
+    return new Euler<T>(o);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor5b(int iorder)
+{
+    typename Euler<T>::Order o = typename Euler<T>::Order (iorder);
+    return new Euler<T>(o);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor6(T x, T y, T z)
+{
+    return new Euler<T>(Vec3<T>(x,y,z));
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor7(const Quat<T> &quat, typename IMATH_NAMESPACE::Eulerf::Order order)
+{
+    Euler<T> *e = eulerConstructor5<T>(order);
+    e->extract(quat);
+    return e;
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor7a(const Quat<T> &quat)
+{
+    return eulerConstructor7(quat, IMATH_NAMESPACE::Eulerf::Default);
+}
+
+template <class T>
+static Euler<T> *
+eulerConstructor7b(const Quat<T> &quat, int iorder)
+{
+    Euler<T> *e = eulerConstructor5b<T>(iorder);
+    e->extract(quat);
+    return e;
+}
+
+template <class T, class S>
+static Euler<T> *
+eulerConversionConstructor(const Euler<S> &euler)
+{
+    MATH_EXC_ON;
+    Euler<T> *e = new Euler<T>;
+    *e = euler;
+    return e;
+}
+
+template <class T>
+static void
+eulerMakeNear(Euler<T> &euler, Euler<T> &target)
+{
+    MATH_EXC_ON;
+    euler.makeNear (target);
+}
+
+template <class T>
+static void
+eulerSetOrder(Euler<T> &euler, typename IMATH_NAMESPACE::Eulerf::Order order)
+{
+    typename Euler<T>::Order o = interpretOrder<T>(order);
+    euler.setOrder (o);
+}
+template <class T>
+static void
+eulerSet(Euler<T> &euler, IMATH_NAMESPACE::Eulerf::Axis axis, int relative, int parityEven, int firstRepeats)
+{
+    MATH_EXC_ON;
+    typename Euler<T>::Axis a = interpretAxis<T>(axis);
+    euler.set (a, relative, parityEven, firstRepeats);
+}
+
+template <class T>
+static void 
+extract1(Euler<T> &euler, const Matrix33<T> &m)
+{
+    MATH_EXC_ON;
+    euler.extract(m);
+}
+
+template <class T>
+static void 
+extract2(Euler<T> &euler, const Matrix44<T> &m)
+{
+    MATH_EXC_ON;
+    euler.extract(m);
+}
+
+template <class T>
+static void 
+extract3(Euler<T> &euler, const Quat<T> &q)
+{
+    MATH_EXC_ON;
+    euler.extract(q);
+}
+
+template <class T>
+static Matrix33<T>
+toMatrix33(Euler<T> &euler)
+{
+    MATH_EXC_ON;
+    return euler.toMatrix33();
+}
+
+template <class T>
+static Matrix44<T>
+toMatrix44(Euler<T> &euler)
+{
+    MATH_EXC_ON;
+    return euler.toMatrix44();
+}
+
+template <class T>
+static Quat<T>
+toQuat(Euler<T> &euler)
+{
+    MATH_EXC_ON;
+    return euler.toQuat();
+}
+
+template <class T>
+static Vec3<T>
+toXYZVector(Euler<T> &euler)
+{
+    MATH_EXC_ON;
+    return euler.toXYZVector();
+}
+
+template <class T>
+class_<Euler<T>,bases<IMATH_NAMESPACE::Vec3<T> > >
+register_Euler()
+{
+    class_<Euler<T>,bases<Vec3<T> > > euler_class(EulerName<T>::value,EulerName<T>::value,init<Euler<T> >("copy construction"));
+    euler_class
+        .def(init<>("imath Euler default construction"))
+        .def("__init__", make_constructor(eulerConstructor1<T>))
+        .def("__init__", make_constructor(eulerConstructor1a<T>))
+        .def("__init__", make_constructor(eulerConstructor1b<T>))
+        .def("__init__", make_constructor(eulerConstructor2<T>))
+        .def("__init__", make_constructor(eulerConstructor2a<T>))
+        .def("__init__", make_constructor(eulerConstructor2b<T>))
+        .def("__init__", make_constructor(eulerConstructor3<T>),
+             "Euler-from-matrix construction assumes, but does\n"
+             "not verify, that the matrix includes no shear or\n"
+             "non-uniform scaling.  If necessary, you can fix\n"
+             "the matrix by calling the removeScalingAndShear()\n"
+             "function.\n")
+        .def("__init__", make_constructor(eulerConstructor3a<T>))
+        .def("__init__", make_constructor(eulerConstructor3b<T>))
+        .def("__init__", make_constructor(eulerConstructor4<T>))
+        .def("__init__", make_constructor(eulerConstructor4a<T>))
+        .def("__init__", make_constructor(eulerConstructor4b<T>))
+        .def("__init__", make_constructor(eulerConstructor5<T>))
+        .def("__init__", make_constructor(eulerConstructor5a<T>))
+        .def("__init__", make_constructor(eulerConstructor5b<T>))
+        .def("__init__", make_constructor(eulerConstructor6<T>))
+        .def("__init__", make_constructor(eulerConstructor7<T>))
+        .def("__init__", make_constructor(eulerConstructor7a<T>))
+        .def("__init__", make_constructor(eulerConstructor7b<T>))
+        .def("__init__", make_constructor(eulerConversionConstructor<T, float>))
+        .def("__init__", make_constructor(eulerConversionConstructor<T, double>))
+        
+        .def("angleOrder", &getAngleOrder<T>, "angleOrder() set the angle order")
+        
+        .def("frameStatic", &Euler<T>::frameStatic, 
+             "e.frameStatic() -- returns true if the angles of e\n"
+             "are measured relative to a set of fixed axes,\n"
+             "or false if the angles of e are measured relative to\n"
+             "each other\n")
+            
+        .def("initialAxis", &Euler<T>::initialAxis, 
+             "e.initialAxis() -- returns the initial rotation\n"
+             "axis of e (EULER_X_AXIS, EULER_Y_AXIS, EULER_Z_AXIS)")
+        
+        .def("initialRepeated", &Euler<T>::initialRepeated,
+             "e.initialRepeated() -- returns 1 if the initial\n"
+             "rotation axis of e is repeated (for example,\n"
+             "e.order() == EULER_XYX); returns 0 if the initial\n"
+             "rotation axis is not repeated.\n")
+             
+        .def("makeNear", &eulerMakeNear<T>,
+             "e.makeNear(t) -- adjusts Euler e so that it\n"
+             "represents the same rotation as before, but the\n"
+             "individual angles of e differ from the angles of\n"
+             "t by as little as possible.\n"
+             "This method might not make sense if e.order()\n"
+             "and t.order() are different\n")
+        
+        .def("order", &Euler<T>::order,
+             "e.order() -- returns the rotation order in e\n"
+             "(EULER_XYZ, EULER_XZY, ...)")
+        
+        .def("parityEven", &Euler<T>::parityEven, 
+             "e.parityEven() -- returns the parity of the\n"
+             "axis permutation of e\n")
+        
+        .def("set", &eulerSet<T>,
+             "e.set(i,r,p,f) -- sets the rotation order in e\n"
+             "according to the following flags:\n"
+             "\n"
+             "   i   initial axis (EULER_X_AXIS,\n"
+             "       EULER_Y_AXIS or EULER_Z_AXIS)\n"
+             "\n"
+             "   r   rotation angles are measured relative\n"
+             "       to each other (r == 1), or relative to a\n"
+             "       set of fixed axes (r == 0)\n"
+             "\n"
+             "   p   parity of axis permutation is even (r == 1)\n"
+             "       or odd (r == 0)\n"
+             "\n"
+             "   f   first rotation axis is repeated (f == 1)\n"
+             " or not repeated (f == 0)\n")
+        
+        .def("setOrder", &eulerSetOrder<T>,
+             "e.setOrder(o) -- sets the rotation order in e\n"
+             "to o (EULER_XYZ, EULER_XZY, ...)")
+             
+        .def("setXYZVector", &Euler<T>::setXYZVector,
+             "e.setXYZVector(v) -- sets the three rotation\n"
+             "angles in e to v[0], v[1], v[2]")
+        .def("setXYZVector", &setXYZTuple<T>)
+        
+        .def("extract", &extract1<T>,
+             "e.extract(m) -- extracts the rotation component\n"
+             "from 3x3 matrix m and stores the result in e.\n"
+             "Assumes that m does not contain shear or non-\n"
+             "uniform scaling.  If necessary, you can fix m\n"
+             "by calling m.removeScalingAndShear().")
+        
+        .def("extract", &extract2<T>,
+             "e.extract(m) -- extracts the rotation component\n"
+             "from 4x4 matrix m and stores the result in e.\n"
+             "Assumes that m does not contain shear or non-\n"
+             "uniform scaling.  If necessary, you can fix m\n"
+             "by calling m.removeScalingAndShear().")
+        
+        .def("extract", &extract3<T>,
+             "e.extract(q) -- extracts the rotation component\n"
+             "from quaternion q and stores the result in e")            
+        
+        .def("toMatrix33", &toMatrix33<T>, "e.toMatrix33() -- converts e into a 3x3 matrix\n")
+        
+        .def("toMatrix44", &toMatrix44<T>, "e.toMatrix44() -- converts e into a 4x4 matrix\n")
+        
+        .def("toQuat", &toQuat<T>, "e.toQuat() -- converts e into a quaternion\n")
+        
+        .def("toXYZVector", &toXYZVector<T>, 
+             "e.toXYZVector() -- converts e into an XYZ\n"
+             "rotation vector")
+        .def("__str__", &Euler_str<T>)
+        .def("__repr__", &Euler_repr<T>)
+        
+        .def("__eq__", &equal<T>)
+        .def("__ne__", &notequal<T>)
+        ;
+    
+    // fill in the Euler scope
+    {
+        scope euler_scope(euler_class);
+        enum_<typename Euler<T>::Order> euler_order("Order");
+        euler_order
+            .value("XYZ",Euler<T>::XYZ)
+            .value("XZY",Euler<T>::XZY)
+            .value("YZX",Euler<T>::YZX)
+            .value("YXZ",Euler<T>::YXZ)
+            .value("ZXY",Euler<T>::ZXY)
+            .value("ZYX",Euler<T>::ZYX)
+            .value("XZX",Euler<T>::XZX)
+            .value("XYX",Euler<T>::XYX)
+            .value("YXY",Euler<T>::YXY)
+            .value("YZY",Euler<T>::YZY)
+            .value("ZYZ",Euler<T>::ZYZ)
+            .value("ZXZ",Euler<T>::ZXZ)
+            .value("XYZr",Euler<T>::XYZr)
+            .value("XZYr",Euler<T>::XZYr)
+            .value("YZXr",Euler<T>::YZXr)
+            .value("YXZr",Euler<T>::YXZr)
+            .value("ZXYr",Euler<T>::ZXYr)
+            .value("ZYXr",Euler<T>::ZYXr)
+            .value("XZXr",Euler<T>::XZXr)
+            .value("XYXr",Euler<T>::XYXr)
+            .value("YXYr",Euler<T>::YXYr)
+            .value("YZYr",Euler<T>::YZYr)
+            .value("ZYZr",Euler<T>::ZYZr)
+            .value("ZXZr",Euler<T>::ZXZr)
+
+            // don't export these, they're not really part of the public interface
+            //.value("Legal",Euler<T>::Legal)
+            //.value("Min",Euler<T>::Min)
+            //.value("Max",Euler<T>::Max)
+
+            // handle Default seperately since boost sets up a 1-1 mapping for enum values
+            //.value("Default",Euler<T>::Default)
+            .export_values()
+            ;
+        // just set it to the XYZ value manually
+        euler_scope.attr("Default") = euler_scope.attr("XYZ");
+
+        enum_<typename Euler<T>::Axis>("Axis")
+            .value("X",Euler<T>::X)
+            .value("Y",Euler<T>::Y)
+            .value("Z",Euler<T>::Z)
+            .export_values()
+            ;
+
+        enum_<typename Euler<T>::InputLayout>("InputLayout")
+            .value("XYZLayout",Euler<T>::XYZLayout)
+            .value("IJKLayout",Euler<T>::IJKLayout)
+            .export_values()
+            ;
+    }
+
+    decoratecopy(euler_class);
+
+    return euler_class;
+}
+
+// XXX fixme - template this
+// really this should get generated automatically...
+
+/*
+template <class T,int index>
+static FixedArray<T>
+EulerArray_get(FixedArray<IMATH_NAMESPACE::Euler<T> > &qa)
+{
+    return FixedArray<T>( &(qa[0].r)+index, qa.len(), 4*qa.stride());
+}
+*/
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Euler<T> > *
+EulerArray_eulerConstructor7a(const FixedArray<IMATH_NAMESPACE::Quat<T> > &q)
+{
+    MATH_EXC_ON;
+    size_t len = q.len();
+    FixedArray<IMATH_NAMESPACE::Euler<T> >* result = new FixedArray<IMATH_NAMESPACE::Euler<T> >(len);
+    for (size_t i = 0; i < len; ++i) {
+        (*result)[i].extract(q[i]);
+    }
+    return result;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Euler<T> > *
+EulerArray_eulerConstructor8a(const FixedArray<IMATH_NAMESPACE::Vec3<T> >& v)
+{
+    MATH_EXC_ON;
+    size_t len = v.len();
+    FixedArray<IMATH_NAMESPACE::Euler<T> >* result = new FixedArray<IMATH_NAMESPACE::Euler<T> >(len);
+
+    for (size_t i = 0; i < len; ++i)
+        (*result)[i] = Euler<T>(v[i]);
+
+    return result;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Euler<T> > *
+EulerArray_eulerConstructor9a(const FixedArray<IMATH_NAMESPACE::Vec3<T> >& v, typename IMATH_NAMESPACE::Eulerf::Order order)
+{
+    MATH_EXC_ON;
+    size_t len = v.len();
+    FixedArray<IMATH_NAMESPACE::Euler<T> >* result = new FixedArray<IMATH_NAMESPACE::Euler<T> >(len);
+
+    typename Euler<T>::Order o = interpretOrder<T>(order);
+    for (size_t i = 0; i < len; ++i)
+        (*result)[i] = Euler<T>(v[i], o);
+
+    return result;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Vec3<T> >
+EulerArray_toXYZVector(const FixedArray<IMATH_NAMESPACE::Euler<T> >& e)
+{
+    MATH_EXC_ON;
+    size_t len = e.len();
+    FixedArray<IMATH_NAMESPACE::Vec3<T> > result(len, UNINITIALIZED);
+    for (size_t i = 0; i < len; ++i)
+        result[i] = e[i].toXYZVector();
+    return result;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Quat<T> >
+EulerArray_toQuat(const FixedArray<IMATH_NAMESPACE::Euler<T> >& e)
+{
+    MATH_EXC_ON;
+    size_t len = e.len();
+    FixedArray<IMATH_NAMESPACE::Quat<T> > result(len, UNINITIALIZED);
+    for (size_t i = 0; i < len; ++i)
+        result[i] = e[i].toQuat();
+    return result;
+}
+
+
+template <class T>
+class_<FixedArray<IMATH_NAMESPACE::Euler<T> > >
+register_EulerArray()
+{
+    class_<FixedArray<IMATH_NAMESPACE::Euler<T> > > eulerArray_class = FixedArray<IMATH_NAMESPACE::Euler<T> >::register_("Fixed length array of IMATH_NAMESPACE::Euler");
+    eulerArray_class
+        //.add_property("x",&EulerArray_get<T,1>)
+        //.add_property("y",&EulerArray_get<T,2>)
+        //.add_property("z",&EulerArray_get<T,3>)
+        .def("__init__", make_constructor(EulerArray_eulerConstructor7a<T>))
+        .def("__init__", make_constructor(EulerArray_eulerConstructor8a<T>))
+        .def("__init__", make_constructor(EulerArray_eulerConstructor9a<T>))
+        .def("toXYZVector", EulerArray_toXYZVector<T>)
+        .def("toQuat", EulerArray_toQuat<T>)
+        ;
+
+    add_comparison_functions(eulerArray_class);
+    PyImath::add_explicit_construction_from_type<IMATH_NAMESPACE::Matrix33<T> >(eulerArray_class);
+    PyImath::add_explicit_construction_from_type<IMATH_NAMESPACE::Matrix44<T> >(eulerArray_class);
+    return eulerArray_class;
+}
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Euler<float>,bases<IMATH_NAMESPACE::Vec3<float> > > register_Euler<float>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Euler<double>,bases<IMATH_NAMESPACE::Vec3<double> > > register_Euler<double>();
+
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Euler<float> > > register_EulerArray<float>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Euler<double> > > register_EulerArray<double>();
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Euler<float> FixedArrayDefaultValue<IMATH_NAMESPACE::Euler<float> >::value() { return IMATH_NAMESPACE::Euler<float>(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Euler<double> FixedArrayDefaultValue<IMATH_NAMESPACE::Euler<double> >::value() { return IMATH_NAMESPACE::Euler<double>(); }
+
+} // namespace PyImath
diff --git a/src/python/PyImath/PyImathEuler.h b/src/python/PyImath/PyImathEuler.h
new file mode 100644 (file)
index 0000000..34064d2
--- /dev/null
@@ -0,0 +1,85 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathEuler_h_
+#define _PyImathEuler_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <ImathEuler.h>
+#include <ImathVec.h>
+#include "PyImath.h"
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Euler<T>,boost::python::bases<IMATH_NAMESPACE::Vec3<T> > > register_Euler();
+template <class T> boost::python::class_<PyImath::FixedArray<IMATH_NAMESPACE::Euler<T> > > register_EulerArray();
+typedef FixedArray<IMATH_NAMESPACE::Eulerf>  EulerfArray;
+typedef FixedArray<IMATH_NAMESPACE::Eulerd>  EulerdArray;
+
+//
+
+// Other code in the Zeno code base assumes the existance of a class with the
+// same name as the Imath class, and with static functions wrap() and
+// convert() to produce a PyImath object from an Imath object and vice-versa,
+// respectively.  The class Boost generates from the Imath class does not
+// have these properties, so we define a companion class here.
+// The template argument, T, is the element type for the axis vector 
+// (e.g.,float, double).
+
+template <class T>
+class E {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Euler<T> &e);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Euler<T> *v);
+};
+
+template <class T>
+PyObject *
+E<T>::wrap (const IMATH_NAMESPACE::Euler<T> &e)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Euler<T> >::type converter;
+    PyObject *p = converter (e);
+    return p;
+}
+
+template <class T>
+int
+E<T>::convert (PyObject *p, IMATH_NAMESPACE::Euler<T> *v)
+{
+    boost::python::extract <IMATH_NAMESPACE::Eulerf> extractorEf (p);
+    if (extractorEf.check())
+    {
+        IMATH_NAMESPACE::Eulerf e = extractorEf();
+        v->x = T(e.x);
+        v->y = T(e.y);
+        v->z = T(e.z);
+        v->setOrder (typename IMATH_NAMESPACE::Euler<T>::Order (e.order()));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::Eulerd> extractorEd (p);
+    if (extractorEd.check())
+    {
+        IMATH_NAMESPACE::Eulerd e = extractorEd();
+        v->x = T(e.x);
+        v->y = T(e.y);
+        v->z = T(e.z);
+        v->setOrder (typename IMATH_NAMESPACE::Euler<T>::Order (e.order()));
+        return 1;
+    }
+
+    return 0;
+}
+
+typedef E<float>       Eulerf;
+typedef E<double>      Eulerd;
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathExport.h b/src/python/PyImath/PyImathExport.h
new file mode 100644 (file)
index 0000000..20312f8
--- /dev/null
@@ -0,0 +1,28 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef PYIMATHEXPORT_H
+#define PYIMATHEXPORT_H
+
+#if defined(IMATH_DLL)
+    #if defined(PLATFORM_VISIBILITY_AVAILABLE)
+        #define PYIMATH_EXPORT __attribute__((visibility("default")))
+        #define PYIMATH_EXPORT __attribute__((visibility("default")))
+    #elif defined(_MSC_VER)
+        #if defined(PYIMATH_BUILD)
+            #define PYIMATH_EXPORT __declspec(dllexport)
+        #else
+            #define PYIMATH_EXPORT __declspec(dllimport)
+        #endif
+    #else
+        #define PYIMATH_EXPORT
+    #endif
+#else
+    #define PYIMATH_EXPORT
+#endif
+
+#endif // #ifndef PYIMATHEXPORT_H
diff --git a/src/python/PyImath/PyImathFixedArray.cpp b/src/python/PyImath/PyImathFixedArray.cpp
new file mode 100644 (file)
index 0000000..efca302
--- /dev/null
@@ -0,0 +1,26 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathFixedArray.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+
+template <> PYIMATH_EXPORT bool FixedArrayDefaultValue<bool>::value() { return false; }
+template <> PYIMATH_EXPORT signed char FixedArrayDefaultValue<signed char>::value() { return 0; }
+template <> PYIMATH_EXPORT unsigned char FixedArrayDefaultValue<unsigned char>::value() { return 0; }
+template <> PYIMATH_EXPORT short FixedArrayDefaultValue<short>::value() { return 0; }
+template <> PYIMATH_EXPORT unsigned short FixedArrayDefaultValue<unsigned short>::value() { return 0; }
+template <> PYIMATH_EXPORT int FixedArrayDefaultValue<int>::value() { return 0; }
+template <> PYIMATH_EXPORT int64_t FixedArrayDefaultValue<int64_t>::value() { return 0; }
+template <> PYIMATH_EXPORT unsigned int FixedArrayDefaultValue<unsigned int>::value() { return 0; }
+template <> PYIMATH_EXPORT float FixedArrayDefaultValue<float>::value() { return 0; }
+template <> PYIMATH_EXPORT double FixedArrayDefaultValue<double>::value() { return 0; }
+
+//int alloc_count = 0;
+
+}
diff --git a/src/python/PyImath/PyImathFixedArray.h b/src/python/PyImath/PyImathFixedArray.h
new file mode 100644 (file)
index 0000000..6428398
--- /dev/null
@@ -0,0 +1,854 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathFixedArray_h_
+#define _PyImathFixedArray_h_
+
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/operators.hpp>
+#include <boost/shared_array.hpp>
+#include <boost/any.hpp>
+#include <iostream>
+#include "PyImathUtil.h"
+
+//
+// Note: when PyImath from the v2 release of OpenEXR depended on Iex,
+// the PY_IMATH_LEAVE/RETURN_PYTHON macros bracketed calls that
+// enabled/disabled float-point exceptions via via the MathExcOn
+// class. This was a compile-time option based on the setting of
+// PYIMATH_ENABLE_EXCEPTIONS. This behavior is now deprecated, hence
+// the empty macros.
+//
+
+#define PY_IMATH_LEAVE_PYTHON PyImath::PyReleaseLock pyunlock;
+#define PY_IMATH_RETURN_PYTHON
+
+namespace PyImath {
+
+namespace {
+
+//
+// Utility classes used for converting array members to boost python objects.
+//
+
+template <class T>
+struct ReturnReference
+{
+    static boost::python::object  applyReadOnly (const T& val)
+    {
+        typename boost::python::copy_const_reference::apply<const T&>::type converter;
+        return boost::python::object(boost::python::handle<>(converter(val)));
+    }
+
+    static boost::python::object  applyWritable (T& val)
+    {
+        typename boost::python::reference_existing_object::apply<T&>::type converter;
+        return boost::python::object(boost::python::handle<>(converter(val)));
+    }
+
+    static bool  isReferenceWrap () { return true; }
+};
+
+template <class T>
+struct ReturnByValue
+{
+    static boost::python::object  applyReadOnly (const T& val)
+    {
+        typename boost::python::return_by_value::apply<T>::type converter;
+        return boost::python::object(boost::python::handle<>(converter(val)));
+    }
+
+    static boost::python::object  applyWritable (T& val)
+    {
+        return applyReadOnly (val);
+    }
+
+    static bool  isReferenceWrap () { return false; }
+};
+
+} // namespace
+
+//
+// Utility class for a runtime-specified fixed length array type in python
+//
+template <class T>
+struct FixedArrayDefaultValue
+{
+    static T value();
+};
+
+enum Uninitialized {UNINITIALIZED};
+
+template <class T>
+class FixedArray
+{
+    T *     _ptr;
+    size_t  _length;
+    size_t  _stride;
+    bool    _writable;
+
+    // this handle optionally stores a shared_array to allocated array data
+    // so that everything is freed properly on exit.
+    boost::any _handle;
+
+    boost::shared_array<size_t> _indices; // non-NULL iff I'm a masked reference
+    size_t                      _unmaskedLength;
+
+
+  public:
+    typedef T   BaseType;
+
+    FixedArray(T *ptr, Py_ssize_t length, Py_ssize_t stride = 1, bool writable = true)
+        : _ptr(ptr), _length(length), _stride(stride), _writable(writable),
+          _handle(), _unmaskedLength(0)
+    {
+        if (length < 0)
+        {
+          throw std::domain_error  ("Fixed array length must be non-negative");
+        }
+        if (stride <= 0)
+        {
+          throw std::domain_error  ("Fixed array stride must be positive");
+        }
+        // nothing
+    }
+
+    FixedArray(T *ptr, Py_ssize_t length, Py_ssize_t stride,
+               boost::any handle, bool writable = true)
+        : _ptr(ptr), _length(length), _stride(stride), _writable(writable),
+          _handle(handle), _unmaskedLength(0)
+    {
+        if (_length < 0)
+        {
+            throw std::domain_error("Fixed array length must be non-negative");
+        }
+        if (stride <= 0)
+        {
+            throw std::domain_error("Fixed array stride must be positive");
+        }
+        // nothing
+    }
+
+    FixedArray(const T *ptr, Py_ssize_t length, Py_ssize_t stride = 1)
+        : _ptr(const_cast<T *>(ptr)), _length(length), _stride(stride),
+          _writable(false), _handle(), _unmaskedLength(0)
+    {
+        if (length < 0)
+        {
+            throw std::logic_error("Fixed array length must be non-negative");
+        }
+        if (stride <= 0)
+        {
+            throw std::logic_error("Fixed array stride must be positive");
+        }
+        // nothing
+    }
+
+    FixedArray(const T *ptr, Py_ssize_t length, Py_ssize_t stride, boost::any handle)
+        : _ptr(const_cast<T *>(ptr)), _length(length), _stride(stride), _writable(false),
+          _handle(handle), _unmaskedLength(0)
+    {
+        if (_length < 0)
+        {
+            throw std::logic_error("Fixed array length must be non-negative");
+        }
+        if (stride <= 0)
+        {
+            throw std::logic_error("Fixed array stride must be positive");
+        }
+        // nothing
+    }
+
+    explicit FixedArray(Py_ssize_t length)
+        : _ptr(0), _length(length), _stride(1), _writable(true),
+          _handle(), _unmaskedLength(0)
+    {
+        if (_length < 0) {
+            throw std::domain_error("Fixed array length must be non-negative");
+        }
+        boost::shared_array<T> a(new T[length]);
+        T tmp = FixedArrayDefaultValue<T>::value();
+        for (Py_ssize_t i=0; i<length; ++i) a[i] = tmp;
+        _handle = a;
+        _ptr = a.get();
+    }
+
+    FixedArray(Py_ssize_t length,Uninitialized)
+        : _ptr(0), _length(length), _stride(1), _writable(true),
+          _handle(), _unmaskedLength(0)
+    {
+        if (_length < 0) {
+            throw std::domain_error("Fixed array length must be non-negative");
+        }
+        boost::shared_array<T> a(new T[length]);
+        _handle = a;
+        _ptr = a.get();
+    }
+
+    FixedArray(const T &initialValue, Py_ssize_t length)
+        : _ptr(0), _length(length), _stride(1), _writable(true),
+          _handle(), _unmaskedLength(0)
+    {
+        if (_length < 0) {
+            throw std::domain_error("Fixed array length must be non-negative");
+        }
+        boost::shared_array<T> a(new T[length]);
+        for (Py_ssize_t i=0; i<length; ++i) a[i] = initialValue;
+        _handle = a;
+        _ptr = a.get();
+    }
+
+    template <typename MaskArrayType>
+    FixedArray(FixedArray& f, const MaskArrayType& mask) 
+        : _ptr(f._ptr), _stride(f._stride), _writable(f._writable), _handle(f._handle), _unmaskedLength(0)
+    {
+        if (f.isMaskedReference())
+        {
+            throw std::invalid_argument("Masking an already-masked FixedArray not supported yet (SQ27000)");
+        }
+
+        size_t len = f.match_dimension(mask);
+        _unmaskedLength = len;
+
+        size_t reduced_len = 0;
+        for (size_t i = 0; i < len; ++i)
+            if (mask[i])
+                reduced_len++;
+
+        _indices.reset(new size_t[reduced_len]);
+
+        for (size_t i = 0, j = 0; i < len; ++i)
+        {
+            if (mask[i])
+            {
+                _indices[j] = i;
+                j++;
+            }
+        }
+
+        _length = reduced_len;
+    }
+
+    template <typename MaskArrayType>
+    FixedArray(const FixedArray& f, const MaskArrayType& mask) 
+        : _ptr(f._ptr), _stride(f._stride), _writable(false), _handle(f._handle), _unmaskedLength(0)
+    {
+        if (f.isMaskedReference())
+        {
+            throw std::invalid_argument("Masking an already-masked FixedArray not supported yet (SQ27000)");
+        }
+
+        size_t len = f.match_dimension(mask);
+        _unmaskedLength = len;
+
+        size_t reduced_len = 0;
+        for (size_t i = 0; i < len; ++i)
+            if (mask[i])
+                reduced_len++;
+
+        _indices.reset(new size_t[reduced_len]);
+
+        for (size_t i = 0, j = 0; i < len; ++i)
+        {
+            if (mask[i])
+            {
+                _indices[j] = i;
+                j++;
+            }
+        }
+
+        _length = reduced_len;
+    }
+
+    template <class S>
+    explicit FixedArray(const FixedArray<S> &other)
+        : _ptr(0), _length(other.len()), _stride(1), _writable(true),
+          _handle(), _unmaskedLength(other.unmaskedLength())
+    {
+        boost::shared_array<T> a(new T[_length]);
+        for (size_t i=0; i<_length; ++i) a[i] = T(other[i]);
+        _handle = a;
+        _ptr = a.get();
+
+        if (_unmaskedLength)
+        {
+            _indices.reset(new size_t[_length]);
+
+            for (size_t i = 0; i < _length; ++i)
+                _indices[i] = other.raw_ptr_index(i);
+        }
+    }
+
+    FixedArray(const FixedArray &other)
+        : _ptr(other._ptr), _length(other._length), _stride(other._stride),
+          _writable(other._writable),
+          _handle(other._handle),
+          _indices(other._indices),
+          _unmaskedLength(other._unmaskedLength)
+    {
+    }
+        
+    const FixedArray &
+    operator = (const FixedArray &other)
+    {
+        if (&other == this) return *this;
+
+        _ptr = other._ptr;
+        _length = other._length;
+        _stride = other._stride;
+        _writable = other._writable;
+        _handle = other._handle;
+        _unmaskedLength = other._unmaskedLength;
+        _indices = other._indices;
+
+        return *this;
+    }
+
+    ~FixedArray()
+    {
+        // nothing
+    }
+
+    explicit operator bool() const {return _ptr != nullptr;}
+
+    const boost::any & handle() { return _handle; }
+
+    //
+    // Make an index suitable for indexing into an array in c++ from
+    // a python index, which can be negative for indexing relative to
+    // the end of an array
+    //
+    size_t canonical_index(Py_ssize_t index) const
+    {
+        if (index < 0) index += len();
+        if (index >= len() || index < 0) {
+            PyErr_SetString(PyExc_IndexError, "Index out of range");
+            boost::python::throw_error_already_set();
+        }
+        return index; // still a virtual index if this is a masked reference array
+    }
+
+    void extract_slice_indices(PyObject *index, size_t &start, size_t &end, Py_ssize_t &step, size_t &slicelength) const
+    {
+        if (PySlice_Check(index)) {
+#if PY_MAJOR_VERSION > 2
+            PyObject *slice = index;
+#else
+            PySliceObject *slice = reinterpret_cast<PySliceObject *>(index);
+#endif
+            Py_ssize_t s,e,sl;
+            if (PySlice_GetIndicesEx(slice,_length,&s,&e,&step,&sl) == -1) {
+                boost::python::throw_error_already_set();
+            }
+            // e can be -1 if the iteration is backwards with a negative slice operator [::-n] (n > 0).
+            if (s < 0 || e < -1 || sl < 0) {
+                throw std::domain_error("Slice extraction produced invalid start, end, or length indices");
+            }
+            start = s;
+            end = e;
+            slicelength = sl;
+        } else if (PyInt_Check(index)) {
+            size_t i = canonical_index(PyInt_AsSsize_t(index));
+            start = i; end = i+1; step = 1; slicelength = 1;
+        } else {
+            PyErr_SetString(PyExc_TypeError, "Object is not a slice");
+           boost::python::throw_error_already_set();
+        }
+    }
+
+    // Although this method isn't used directly by this class,
+    // there are some sub-classes that are using it.
+    typedef typename boost::mpl::if_<boost::is_class<T>,      T&,T>::type get_type;
+    get_type       getitem(Py_ssize_t index)       { return (*this)[canonical_index(index)]; }
+    typedef typename boost::mpl::if_<boost::is_class<T>,const T&,T>::type get_type_const;
+    get_type_const getitem(Py_ssize_t index) const { return (*this)[canonical_index(index)]; }
+
+    // We return an internal reference for class-types and a copy of the data
+    // for non-class types.  Returning an internal refeference doesn't seem
+    // to work with non-class types.
+
+    boost::python::object  getobjectTuple (Py_ssize_t index)
+    {
+        typedef typename boost::mpl::if_<boost::is_class<T>,
+                                         ReturnReference<T>,
+                                         ReturnByValue<T> >::type convertType;
+
+        boost::python::object retval;
+        int referenceMode = 0;
+
+        const size_t i = canonical_index(index);
+        T& val = _ptr[(isMaskedReference() ? raw_ptr_index(i) : i) * _stride];
+
+        if (_writable)
+        {
+            retval = convertType::applyWritable (val);
+
+            if (convertType::isReferenceWrap())
+                referenceMode = 0;  // Managed reference.
+            else
+                referenceMode = 2;  // Default policy (return-by-value)
+        }
+        else
+        {
+            retval = convertType::applyReadOnly (val);
+
+            if (convertType::isReferenceWrap())
+                referenceMode = 1;  // Copy const reference
+            else
+                referenceMode = 2;  // Default policy (return-by-value)
+        }
+
+        return boost::python::make_tuple (referenceMode, retval);
+    }
+
+    boost::python::object  getobjectTuple (Py_ssize_t index) const
+    {
+        typedef typename boost::mpl::if_<boost::is_class<T>,
+                                         ReturnReference<T>,
+                                         ReturnByValue<T> >::type convertType;
+
+        boost::python::object retval;
+        int referenceMode = 1;
+
+        const size_t i = canonical_index(index);
+        const T& val = _ptr[(isMaskedReference() ? raw_ptr_index(i) : i) * _stride];
+
+        retval = convertType::applyReadOnly (val);
+
+        if (convertType::isReferenceWrap())
+            referenceMode = 1;  // Copy const reference
+        else
+            referenceMode = 2;  // Default policy (return-by-value)
+
+        return boost::python::make_tuple (referenceMode, retval);
+    }
+
+    FixedArray getslice(::PyObject *index) const
+    {
+        size_t start=0, end=0, slicelength=0;
+        Py_ssize_t step;
+        extract_slice_indices(index,start,end,step,slicelength);
+        FixedArray f(slicelength);
+
+        if (isMaskedReference())
+        {
+            for (size_t i=0; i<slicelength; ++i)
+                f._ptr[i] = _ptr[raw_ptr_index(start+i*step)*_stride];
+        }
+        else
+        {
+            for (size_t i=0; i<slicelength; ++i)
+                f._ptr[i] = _ptr[(start+i*step)*_stride];
+        }
+        return f;
+    }
+
+    template <typename MaskArrayType>
+    FixedArray getslice_mask(const MaskArrayType& mask)
+    {
+        // 'writable' state is preserved in the returned fixed-array.
+        FixedArray f(*this, mask);
+        return f;
+    }
+
+    void
+    setitem_scalar(PyObject *index, const T &data)
+    {
+        if (!_writable)
+            throw std::invalid_argument("Fixed array is read-only.");
+
+        size_t start=0, end=0, slicelength=0;
+        Py_ssize_t step;
+        extract_slice_indices(index,start,end,step,slicelength);
+
+        if (isMaskedReference())
+        {
+            for (size_t i=0; i<slicelength; ++i)
+                _ptr[raw_ptr_index(start+i*step)*_stride] = data;
+        }
+        else
+        {
+            for (size_t i=0; i<slicelength; ++i)
+                _ptr[(start+i*step)*_stride] = data;
+        }
+    }
+
+    template <typename MaskArrayType>
+    void
+    setitem_scalar_mask(const MaskArrayType &mask, const T &data)
+    {
+        if (!_writable)
+            throw std::invalid_argument("Fixed array is read-only.");
+
+        size_t len = match_dimension(mask, false);
+
+        if (isMaskedReference())
+        {
+            for (size_t i = 0; i < len; ++i)
+                _ptr[raw_ptr_index(i)*_stride] = data;
+        }
+        else
+        {
+            for (size_t i=0; i<len; ++i)
+                if (mask[i]) _ptr[i*_stride] = data;
+        }
+    }
+
+    template <typename ArrayType>
+    void
+    setitem_vector(::PyObject *index, const ArrayType &data)
+    {
+        if (!_writable)
+            throw std::invalid_argument("Fixed array is read-only.");
+
+        size_t start=0, end=0, slicelength=0;
+        Py_ssize_t step;
+        extract_slice_indices(index,start,end,step,slicelength);
+        
+        // we have a valid range of indices
+        if ((size_t)data.len() != slicelength) {
+            PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
+            boost::python::throw_error_already_set();
+        }
+
+        if (isMaskedReference())
+        {
+            for (size_t i=0; i<slicelength; ++i)
+                _ptr[raw_ptr_index(start+i*step)*_stride] = data[i];
+        }
+        else
+        {
+            for (size_t i=0; i<slicelength; ++i)
+                _ptr[(start+i*step)*_stride] = data[i];
+        }
+    }
+
+    template <typename MaskArrayType, typename ArrayType>
+    void
+    setitem_vector_mask(const MaskArrayType &mask, const ArrayType &data)
+    {
+        if (!_writable)
+            throw std::invalid_argument("Fixed array is read-only.");
+
+        // We could relax this but this restriction if there's a good
+        // enough reason too.
+
+        if (isMaskedReference())
+        {
+            throw std::invalid_argument("We don't support setting item masks for masked reference arrays.");
+        }
+
+        size_t len = match_dimension(mask);
+        if ((size_t)data.len() == len)
+        {
+            for (size_t i = 0; i < len; ++i)
+                if (mask[i]) _ptr[i*_stride] = data[i];
+        }
+        else
+        {
+            Py_ssize_t count = 0;
+            for (size_t i = 0; i < len; ++i)
+                if (mask[i]) count++;
+
+            if (data.len() != count) {
+                throw std::invalid_argument("Dimensions of source data do not match destination either masked or unmasked");
+            }
+
+            Py_ssize_t dataIndex = 0;
+            for (size_t i = 0; i < len; ++i)
+            {
+                if (mask[i])
+                {
+                    _ptr[i*_stride] = data[dataIndex];
+                    dataIndex++;
+                }
+            }
+        }
+    }
+
+    // exposed as Py_ssize_t for compatilbity with standard python sequences
+    Py_ssize_t len()      const { return _length;   }
+    size_t     stride()   const { return _stride;   }
+    bool       writable() const { return _writable; }
+
+    // This method is mainly here for use in confidence tests, but there may
+    // be other use-cases where a writable array needs to be made read-only.
+    // Note that we do not provide a 'makeWritable' method here, because that
+    // type of operation shouldn't be allowed.
+    void       makeReadOnly() { _writable = false; }
+
+    // no bounds checking on i!
+    T& operator [] (size_t i)
+    {
+        if (!_writable)
+            throw std::invalid_argument("Fixed array is read-only.");
+
+        return _ptr[(isMaskedReference() ? raw_ptr_index(i) : i) * _stride];
+    }
+
+    // no bounds checking on i!
+    const T& operator [] (size_t i) const
+    {
+        return _ptr[(isMaskedReference() ? raw_ptr_index(i) : i) * _stride];
+    }
+
+    // no mask conversion or bounds checking on i!
+    T& direct_index(size_t i)
+    {
+        if (!_writable)
+            throw std::invalid_argument("Fixed array is read-only.");
+
+        return _ptr[i*_stride];
+    }
+
+    // no mask conversion or bounds checking on i!
+    const T& direct_index (size_t i) const
+    {
+        return _ptr[i*_stride];
+    }
+
+    // In some cases, an access to the raw data without the 'writable' check 
+    // is needed.  Generally in specialized python-wrapping helpers.
+    T& unchecked_index (size_t i)
+    {
+        return _ptr[(isMaskedReference() ? raw_ptr_index(i) : i) * _stride];
+    }
+
+    T& unchecked_direct_index (size_t i)
+    {
+        return _ptr[i*_stride];
+    }
+
+    bool isMaskedReference() const {return _indices.get() != 0;}
+    size_t unmaskedLength() const {return _unmaskedLength;}
+
+    // Conversion of indices to raw pointer indices.
+    // This should only be called when this is a masked reference.
+    // No safety checks done for performance.
+    size_t raw_ptr_index(size_t i) const
+    {
+        assert(isMaskedReference());
+        assert(i < _length);
+        assert(_indices[i] >= 0 && _indices[i] < _unmaskedLength);
+        return _indices[i];
+    }
+
+    static boost::python::class_<FixedArray<T> > register_(const char *doc)
+    {
+        // Depending on the data-type (class or fundamental) and the writable
+        // state of the array, different forms are returned by the '__getitem__' 
+        // method.  If writable and a class, an internal reference to the data
+        // is returned so that its value can be changed.  If not-writable or a
+        // fundemental data type (float, int, etc.), then a 'copy' of the data
+        // is returned.
+
+        typename boost::python::object (FixedArray<T>::*nonconst_getobject)(Py_ssize_t) =
+                                                 &FixedArray<T>::getobjectTuple;
+        typename boost::python::object (FixedArray<T>::   *const_getobject)(Py_ssize_t) const =
+                                                 &FixedArray<T>::getobjectTuple;
+
+        boost::python::class_<FixedArray<T> > c(name(),doc, boost::python::init<size_t>("construct an array of the specified length initialized to the default value for the type"));
+        c
+            .def(boost::python::init<const FixedArray<T> &>("construct an array with the same values as the given array"))
+            .def(boost::python::init<const T &,size_t>("construct an array of the specified length initialized to the specified default value"))
+            .def("__getitem__", &FixedArray<T>::getslice)
+            .def("__getitem__", &FixedArray<T>::getslice_mask<FixedArray<int> > )
+            .def("__getitem__",    const_getobject,
+                 selectable_postcall_policy_from_tuple<
+                     boost::python::with_custodian_and_ward_postcall<0,1>,
+                     boost::python::return_value_policy<boost::python::copy_const_reference>,
+                     boost::python::default_call_policies>())
+            .def("__getitem__", nonconst_getobject,
+                 selectable_postcall_policy_from_tuple<
+                     boost::python::with_custodian_and_ward_postcall<0,1>,
+                     boost::python::return_value_policy<boost::python::copy_const_reference>,
+                     boost::python::default_call_policies>())
+            .def("__setitem__", &FixedArray<T>::setitem_scalar)
+            .def("__setitem__", &FixedArray<T>::setitem_scalar_mask<FixedArray<int> >)
+            .def("__setitem__", &FixedArray<T>::setitem_vector<FixedArray<T> >)
+            .def("__setitem__", &FixedArray<T>::setitem_vector_mask<FixedArray<int>, FixedArray<T> >)
+            .def("__len__",&FixedArray<T>::len)
+            .def("writable",&FixedArray<T>::writable)
+            .def("makeReadOnly", &FixedArray<T>::makeReadOnly)
+            .def("ifelse",&FixedArray<T>::ifelse_scalar)
+            .def("ifelse",&FixedArray<T>::ifelse_vector)
+            ;
+        return c;
+    }
+
+    template <typename ArrayType>
+    size_t match_dimension(const ArrayType &a1, bool strictComparison = true) const
+    {
+        if (len() == a1.len())
+            return len();
+
+        bool throwExc = false;
+        if (strictComparison)
+            throwExc = true;
+        else if (isMaskedReference())
+        {
+            if (static_cast<Py_ssize_t>(_unmaskedLength) != a1.len())
+                throwExc = true;
+        }
+        else
+            throwExc = true;
+
+        if (throwExc)
+        {
+          throw std::invalid_argument("Dimensions of source do not match destination");
+        }
+
+        return len();
+    }
+
+    FixedArray<T> ifelse_vector(const FixedArray<int> &choice, const FixedArray<T> &other) {
+        size_t len = match_dimension(choice);
+        match_dimension(other);
+        FixedArray<T> tmp(len); // should use default construction but V3f doens't initialize
+        for (size_t i=0; i < len; ++i) tmp[i] = choice[i] ? (*this)[i] : other[i];
+        return tmp;
+    }
+
+    FixedArray<T> ifelse_scalar(const FixedArray<int> &choice, const T &other) {
+        size_t len = match_dimension(choice);
+        FixedArray<T> tmp(len); // should use default construction but V3f doens't initialize
+        for (size_t i=0; i < len; ++i) tmp[i] = choice[i] ? (*this)[i] : other;
+        return tmp;
+    }
+
+    // Instantiations of fixed ararys must implement this static member
+    static const char *name();
+
+    // Various 'Accessor' classes used in performance-critical areas while also
+    // managing the writable/read-only state efficiently.
+
+    class ReadOnlyDirectAccess
+    {
+      public:
+        ReadOnlyDirectAccess (const FixedArray<T>& array)
+            : _ptr (array._ptr), _stride (array._stride)
+        {
+            if (array.isMaskedReference())
+                throw std::invalid_argument ("Fixed array is masked. ReadOnlyDirectAccess not granted.");
+        }
+
+        ReadOnlyDirectAccess (const ReadOnlyDirectAccess& other)
+            : _ptr (other._ptr), _stride (other._stride) {}
+
+        const T&  operator[] (size_t i) const { return _ptr[i*_stride]; }
+
+      private:
+        const T*  _ptr;
+
+      protected:
+        const size_t  _stride;
+    };
+
+    class WritableDirectAccess : public ReadOnlyDirectAccess
+    {
+      public:
+        WritableDirectAccess (FixedArray<T>& array)
+            : ReadOnlyDirectAccess (array), _ptr (array._ptr)
+        {
+            if (!array.writable())
+                throw std::invalid_argument ("Fixed array is read-only.  WritableDirectAccess not granted.");
+        }
+
+        WritableDirectAccess (const WritableDirectAccess& other)
+            : ReadOnlyDirectAccess (other), _ptr (other._ptr) {}
+
+        T&  operator[] (size_t i) { return _ptr[i*_stride]; }
+
+      private:
+        T*  _ptr;
+
+        using ReadOnlyDirectAccess::_stride;
+    };
+
+    //
+
+    class ReadOnlyMaskedAccess
+    {
+      public:
+        ReadOnlyMaskedAccess (const FixedArray<T>& array)
+            : _ptr (array._ptr), _stride (array._stride),
+              _indices (array._indices)
+        {
+            if (!array.isMaskedReference())
+                throw std::invalid_argument ("Fixed array is not masked. ReadOnlyMaskedAccess not granted.");
+        }
+
+        ReadOnlyMaskedAccess (const ReadOnlyMaskedAccess& other)
+            : _ptr (other._ptr), _stride (other._stride),
+              _indices (other._indices) {}
+
+        // No index-range check here.
+        const T&  operator[] (size_t i) const { return _ptr[_indices[i]*_stride]; }
+
+      private:
+        const T*  _ptr;
+
+      protected:
+        const size_t                 _stride;
+        boost::shared_array<size_t>  _indices;
+    };
+
+    class WritableMaskedAccess : public ReadOnlyMaskedAccess
+    {
+      public:
+        WritableMaskedAccess (FixedArray<T>& array)
+            : ReadOnlyMaskedAccess (array), _ptr (array._ptr)
+        {
+            if (!array.writable())
+                std::invalid_argument ("Fixed array is read-only. WritableMaskedAccess not granted.");
+        }
+
+        WritableMaskedAccess (const WritableMaskedAccess& other)
+            : ReadOnlyMaskedAccess (other), _ptr (other._ptr) {}
+
+        // No index-range check here.
+        T&  operator[] (size_t i) { return _ptr[_indices[i]*_stride]; }
+
+      private:
+        T*  _ptr;
+
+        using ReadOnlyMaskedAccess::_stride;
+        using ReadOnlyMaskedAccess::_indices;
+    };
+
+};
+
+//
+// Helper struct for arary indexing  with a known compile time length
+//
+template <class Container, class Data>
+struct IndexAccessDefault {
+    typedef Data & result_type;
+    static Data & apply(Container &c, size_t i) { return c[i]; }
+};
+
+template <class Container, class Data, int Length, class IndexAccess = IndexAccessDefault<Container,Data> >
+struct StaticFixedArray
+{
+    static Py_ssize_t len(const Container &) { return Length; }
+    static typename   IndexAccess::result_type getitem(Container &c, Py_ssize_t index) { return IndexAccess::apply(c,canonical_index(index)); }
+    static void       setitem(Container &c, Py_ssize_t index, const Data &data) { IndexAccess::apply(c,canonical_index(index)) = data; }
+    static size_t     canonical_index(Py_ssize_t index)
+    {
+        if (index < 0) index += Length;
+        if (index < 0 || index >= Length) {
+            PyErr_SetString(PyExc_IndexError, "Index out of range");
+            boost::python::throw_error_already_set();
+        }
+        return index;
+    }
+};
+
+}
+
+#endif // _PyImathFixedArray_h_
diff --git a/src/python/PyImath/PyImathFixedArray2D.h b/src/python/PyImath/PyImathFixedArray2D.h
new file mode 100644 (file)
index 0000000..4f49eb8
--- /dev/null
@@ -0,0 +1,779 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathFixedArray2D_h_
+#define _PyImathFixedArray2D_h_
+
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/operators.hpp>
+#include <boost/shared_array.hpp>
+#include <boost/any.hpp>
+#include <iostream>
+#include <ImathVec.h>
+#include "PyImathFixedArray.h"
+#include "PyImathOperators.h"
+
+namespace PyImath {
+
+template <class T>
+class FixedArray2D
+{
+    T *                 _ptr;
+    IMATH_NAMESPACE::Vec2<size_t> _length;
+    IMATH_NAMESPACE::Vec2<size_t> _stride;
+    size_t              _size; //flattened size of the array
+
+    // this handle optionally stores a shared_array to allocated array data
+    // so that everything is freed properly on exit.
+    boost::any _handle;
+
+  public:
+
+    FixedArray2D(T *ptr, Py_ssize_t lengthX, Py_ssize_t lengthY, Py_ssize_t strideX = 1)
+        : _ptr(ptr), _length(lengthX, lengthY), _stride(strideX, lengthX), _handle()
+    {
+        if (lengthX < 0 || lengthY < 0)
+            throw std::domain_error("Fixed array 2d lengths must be non-negative");
+        if (strideX <= 0)
+            throw std::domain_error("Fixed array 2d strides must be positive");
+        initializeSize();
+        //std::cout << "fixed array external construct" << std::endl;
+        // nothing
+    }
+
+    FixedArray2D(T *ptr, Py_ssize_t lengthX, Py_ssize_t lengthY, Py_ssize_t strideX, Py_ssize_t strideY)
+        : _ptr(ptr), _length(lengthX, lengthY), _stride(strideX, strideY), _handle()
+    {
+        if (lengthX < 0 || lengthY < 0)
+            throw std::domain_error("Fixed array 2d lengths must be non-negative");
+        if (strideX <= 0 || strideY < 0)
+            throw std::domain_error("Fixed array 2d strides must be positive");
+        initializeSize();
+        //std::cout << "fixed array external construct" << std::endl;
+        // nothing
+    }
+
+    FixedArray2D(T *ptr, Py_ssize_t lengthX, Py_ssize_t lengthY, Py_ssize_t strideX, Py_ssize_t strideY, boost::any handle) 
+        : _ptr(ptr), _length(lengthX, lengthY), _stride(strideX, strideY), _handle(handle)
+    {
+        initializeSize();
+        //std::cout << "fixed array external construct with handle" << std::endl;
+        // nothing
+    }
+
+    explicit FixedArray2D(Py_ssize_t lengthX, Py_ssize_t lengthY)
+        : _ptr(0), _length(lengthX, lengthY), _stride(1, lengthX), _handle()
+    {
+        if (lengthX < 0 || lengthY < 0)
+            throw std::domain_error("Fixed array 2d lengths must be non-negative");
+        initializeSize();
+        T tmp = FixedArrayDefaultValue<T>::value();
+        boost::shared_array<T> a(new T[_size]);
+        for (size_t i=0; i<_size; ++i) a[i] = tmp;
+        _handle = a;
+        _ptr = a.get();
+    }
+
+    explicit FixedArray2D(const IMATH_NAMESPACE::V2i& length)
+        : _ptr(0), _length(length), _stride(1, length.x), _handle()
+    {
+        if (length.x < 0 || length.y < 0)
+            throw std::domain_error("Fixed array 2d lengths must be non-negative");
+        initializeSize();
+        T tmp = FixedArrayDefaultValue<T>::value();
+        boost::shared_array<T> a(new T[_size]);
+        for (size_t i=0; i<_size; ++i) a[i] = tmp;
+        _handle = a;
+        _ptr = a.get();
+    }
+
+    FixedArray2D(const T &initialValue, Py_ssize_t lengthX, Py_ssize_t lengthY)
+        : _ptr(0), _length(lengthX, lengthY), _stride(1, lengthX), _handle()
+    {
+        if (lengthX < 0 || lengthY < 0)
+            throw std::domain_error("Fixed array 2d lengths must be non-negative");
+        initializeSize();
+        boost::shared_array<T> a(new T[_size]);
+        for (size_t i=0; i<_size; ++i) a[i] = initialValue;
+        _handle = a;
+        _ptr = a.get();
+    }
+    void initializeSize()
+    {
+        _size = _length.x*_length.y;
+    }
+
+    template <class S>
+    explicit FixedArray2D(const FixedArray2D<S> &other)
+        : _ptr(0), _length(other.len()), _stride(1, other.len().x), _handle()
+    {
+        initializeSize();
+        boost::shared_array<T> a(new T[_size]);
+        size_t z = 0;
+        for (size_t j = 0; j < _length.y; ++j)
+            for (size_t i = 0; i < _length.x; ++i)
+                a[z++] = T(other(i,j));
+        _handle = a;
+        _ptr = a.get();
+    }
+
+    FixedArray2D(const FixedArray2D &other)
+        : _ptr(other._ptr), _length(other._length), _stride(other._stride), _size(other._size), _handle(other._handle)
+    {
+        //std::cout << "fixed array copy consturct construct" << std::endl;
+        // nothing
+    }
+        
+    const FixedArray2D &
+    operator = (const FixedArray2D &other)
+    {
+        if (&other == this) return *this;
+
+        //std::cout << "fixed array assign" << std::endl;
+
+        _ptr = other._ptr;
+        _length = other._length;
+        _stride = other._stride;
+        _handle = other._handle;
+
+        _size = _length.x*_length.y;
+
+        return *this;
+    }
+
+    ~FixedArray2D()
+    {
+        //std::cout << "fixed array delete" << std::endl;
+    }
+
+    const boost::any & handle() { return _handle; }
+
+    size_t canonical_index(Py_ssize_t index, size_t length) const
+    {
+        if (index < 0) index += length;
+        if ((size_t) index >= length || index < 0) {
+            PyErr_SetString(PyExc_IndexError, "Index out of range");
+            boost::python::throw_error_already_set();
+        }
+        return index;
+    }
+
+    void extract_slice_indices(PyObject *index, size_t length, size_t &start, size_t &end, Py_ssize_t &step, size_t &slicelength) const
+    {
+        if (PySlice_Check(index)) {
+#if PY_MAJOR_VERSION > 2
+            PyObject *slice = index;
+#else
+            PySliceObject *slice = reinterpret_cast<PySliceObject *>(index);
+#endif
+            Py_ssize_t s, e, sl;
+            if (PySlice_GetIndicesEx(slice,length,&s,&e,&step,&sl) == -1) {
+                boost::python::throw_error_already_set();
+            }
+            if (s < 0 || e < 0 || sl < 0) {
+                throw std::domain_error("Slice extraction produced invalid start, end, or length indices");
+            }
+            start = s;
+            end = e;
+            slicelength = sl;
+        } else if (PyInt_Check(index)) {
+            size_t i = canonical_index(PyInt_AsSsize_t(index), length);
+            start = i; end = i+1; step = 1; slicelength = 1;
+        } else {
+            PyErr_SetString(PyExc_TypeError, "Object is not a slice");
+           boost::python::throw_error_already_set();
+        }
+        //std::cout << "Slice indices are " << start << " " << end << " " << step << " " << slicelength << std::endl;
+    }
+
+    // return_internal_reference doesn't seem to work with non-class types
+    typedef typename boost::mpl::if_<boost::is_class<T>,T&,T>::type get_type;
+//    get_type    getitem(Py_ssize_t index) const { return _ptr[canonical_index(index)*_stride]; }
+    //FIXME: const does not work here with at least IMATH_NAMESPACE::Color4, why it works for V3fArray?
+    get_type getitem(Py_ssize_t i, Py_ssize_t j) //const
+    {
+        return (*this)(canonical_index(i, _length.x), canonical_index(j, _length.y));
+    }
+
+    //FIXME: anyway to seperate 2:3,4:5 from 2,4? we'd like to return int for the second one, and also 1d array for 2, 4:5 or 2:3, 4
+    FixedArray2D getslice(PyObject *index) const
+    {
+        if (PyTuple_Check(index) && PyTuple_Size(index) == 2)
+        {
+            size_t startx=0, endx=0, slicelengthx=0;
+            size_t starty=0, endy=0, slicelengthy=0;
+            Py_ssize_t stepx=0;
+            Py_ssize_t stepy=0;
+            extract_slice_indices(PyTuple_GetItem(index, 0),_length.x,startx,endx,stepx,slicelengthx);
+            extract_slice_indices(PyTuple_GetItem(index, 1),_length.y,starty,endy,stepy,slicelengthy);
+            FixedArray2D f(slicelengthx, slicelengthy);
+            for (size_t j=0,z=0; j<slicelengthy; j++)
+                for (size_t i=0; i<slicelengthx; ++i)
+                    f._ptr[z++] = (*this)(startx+i*stepx, starty+j*stepy);
+            return f;
+        }
+        else
+        {
+            PyErr_SetString(PyExc_TypeError, "Slice syntax error");
+            boost::python::throw_error_already_set();
+        }
+        return FixedArray2D(0,0);
+    }
+
+    //FIXME: for 2D array, cannot reduce the size, or maybe returning 1D array?
+    FixedArray2D getslice_mask(const FixedArray2D<int> &mask) const
+    {
+//         size_t len = match_dimension(mask);
+//         size_t slicelength = 0;
+//         for (size_t i=0; i<len; ++i) if (mask[i]) slicelength++;
+//         FixedArray2D f(slicelength, _length.y);
+//         for (size_t i=0,z=0; i<len; ++i) {
+//             if (mask[i]) {
+//                 for (size_t j = 0; j < _length.y; j++)
+//                     f._ptr[z++] = (*this)(i,j);
+//             }
+//         }
+//         return f;
+        IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(mask);
+        FixedArray2D f(len);
+        for (size_t j=0; j<len.y; j++)
+            for (size_t i=0; i<len.x; i++)
+                if (mask(i,j))
+                    f(i,j) = (*this)(i,j);
+        return f;
+    }
+
+//     void setitem(const boost::python::tuple& index, const T &data)
+//     {
+//         Py_ssize_t i = boost::python::extract<Py_ssize_t>(index[0]);
+//         Py_ssize_t j = boost::python::extract<Py_ssize_t>(index[1]);
+//         (*this)(i,j) = data;
+//     }
+    void
+    setitem_scalar(PyObject *index, const T &data)
+    {
+        if (!PyTuple_Check(index) || PyTuple_Size(index) != 2)
+        {
+            PyErr_SetString(PyExc_TypeError, "Slice syntax error");
+            boost::python::throw_error_already_set();
+        }
+
+        size_t startx=0, endx=0, slicelengthx=0;
+        size_t starty=0, endy=0, slicelengthy=0;
+        Py_ssize_t stepx=0;
+        Py_ssize_t stepy=0;
+        extract_slice_indices(PyTuple_GetItem(index, 0),_length.x,startx,endx,stepx,slicelengthx);
+        extract_slice_indices(PyTuple_GetItem(index, 1),_length.y,starty,endy,stepy,slicelengthy);
+        for (size_t j=0; j<slicelengthy; j++)
+            for (size_t i=0; i<slicelengthx; ++i)
+                (*this)(startx+i*stepx, starty+j*stepy) = data;
+    }
+
+    void
+    setitem_scalar_mask(const FixedArray2D<int> &mask, const T &data)
+    {
+        IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(mask);
+        for (size_t j = 0; j < len.y; j++)
+            for (size_t i=0; i<len.x; ++i)
+                if (mask(i,j))
+                    (*this)(i,j) = data;
+    }
+
+    void
+    setitem_vector(PyObject *index, const FixedArray2D &data)
+    {
+        //TODO:sanity check
+        size_t startx=0, endx=0, slicelengthx=0;
+        size_t starty=0, endy=0, slicelengthy=0;
+        Py_ssize_t stepx=0;
+        Py_ssize_t stepy=0;
+        extract_slice_indices(PyTuple_GetItem(index, 0),_length.x,startx,endx,stepx,slicelengthx);
+        extract_slice_indices(PyTuple_GetItem(index, 1),_length.y,starty,endy,stepy,slicelengthy);
+        // we have a valid range of indices
+        if (data.len() != IMATH_NAMESPACE::Vec2<size_t>(slicelengthx, slicelengthy)) {
+            PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
+            boost::python::throw_error_already_set();
+        }
+        for (size_t i=0; i<slicelengthx; ++i)
+            for (size_t j=0; j<slicelengthy; ++j)
+                (*this)(startx+i*stepx, starty+j*stepy) = data(i,j);
+    }
+
+    void
+    setitem_vector_mask(const FixedArray2D<int> &mask, const FixedArray2D &data)
+    {
+        IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(mask);
+        if (data.len() == len) {
+            for (size_t j = 0; j < len.y; j++)
+                for (size_t i=0; i<len.x; ++i)
+                    if (mask(i,j))
+                        (*this)(i,j) = data(i,j);
+        } else {
+            PyErr_SetString(PyExc_IndexError, "Dimensions of source data do not match destination");
+            boost::python::throw_error_already_set();
+        }
+    }
+
+    void
+    setitem_array1d_mask(const FixedArray2D<int> &mask, const FixedArray<T> &data)
+    {
+        IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(mask);
+        if ((size_t) data.len() == len.x*len.y) {
+            for (size_t j = 0, z = 0; j < len.y; j++)
+                for (size_t i=0; i<len.x; ++i, ++z)
+                    if (mask(i,j))
+                        (*this)(i,j) = data[z];
+        } else {
+            size_t count = 0;
+            for (size_t j = 0, z = 0; j < len.y; j++)
+                for (size_t i=0; i<len.x; ++i, ++z)
+                    if (mask(i,j)) count++;
+
+            if ((size_t) data.len() != count) {
+                PyErr_SetString(PyExc_IndexError, "Dimensions of source data do not match destination either masked or unmasked");
+                boost::python::throw_error_already_set();
+            }
+
+            for (size_t j = 0, z = 0; j < len.y; j++)
+                for (size_t i=0; i<len.x; ++i)
+                    if (mask(i,j))
+                        (*this)(i,j) = data[z++];
+        }
+    }
+
+    void
+    setitem_array1d(PyObject *index, const FixedArray<T> &data)
+    {
+        //TODO:sanity check
+        size_t startx=0, endx=0, slicelengthx=0;
+        size_t starty=0, endy=0, slicelengthy=0;
+        Py_ssize_t stepx=0;
+        Py_ssize_t stepy=0;
+        extract_slice_indices(PyTuple_GetItem(index, 0),_length.x,startx,endx,stepx,slicelengthx);
+        extract_slice_indices(PyTuple_GetItem(index, 1),_length.y,starty,endy,stepy,slicelengthy);
+        // we have a valid range of indices
+        if ((size_t) data.len() != slicelengthx*slicelengthy) {
+            PyErr_SetString(PyExc_IndexError, "Dimensions of source data do not match destination");
+            boost::python::throw_error_already_set();
+        }
+        for (size_t j=0, z=0; j<slicelengthy; ++j)
+            for (size_t i=0; i<slicelengthx; ++i, ++z)
+                (*this)(startx+i*stepx, starty+j*stepy) = data[z];
+    }
+
+    IMATH_NAMESPACE::Vec2<size_t> len() const { return _length; }
+    IMATH_NAMESPACE::Vec2<size_t> stride() const { return _stride; }
+    T       & operator () (size_t i, size_t j)       { return _ptr[_stride.x*(j*_stride.y + i)]; }
+    const T & operator () (size_t i, size_t j) const { return _ptr[_stride.x*(j*_stride.y + i)]; }
+    size_t totalLen() const { return _size; }
+    boost::python::tuple size() const
+    {
+        return boost::python::make_tuple(_length.x, _length.y);
+    }
+
+    static boost::python::class_<FixedArray2D<T> > register_(const char *name, const char *doc)
+    {
+        // a little tricky, but here we go - class types return internal references
+        // but fundemental types just get copied.  this typedef sets up the appropriate
+        // call policy for each type.
+        typedef typename boost::mpl::if_<
+            boost::is_class<T>,
+            boost::python::return_internal_reference<>,
+            boost::python::default_call_policies>::type call_policy;
+
+        boost::python::class_<FixedArray2D<T> > c(name,doc, boost::python::init<size_t, size_t>(
+            "construct an array of the specified length initialized to the default value for the type"));
+        c
+            .def(boost::python::init<const FixedArray2D<T> &>("construct an array with the same values as the given array"))
+            .def(boost::python::init<const T &,size_t,size_t>("construct an array of the specified length initialized to the specified default value"))
+            .def("__getitem__", &FixedArray2D<T>::getslice)
+            .def("__getitem__", &FixedArray2D<T>::getslice_mask)
+//             .def("__getitem__", &FixedArray2D<T>::getitem, call_policy())
+            .def("item", &FixedArray2D<T>::getitem, call_policy())
+//             .def("__setitem__", &FixedArray2D<T>::setitem)
+            .def("__setitem__", &FixedArray2D<T>::setitem_scalar)
+            .def("__setitem__", &FixedArray2D<T>::setitem_scalar_mask)
+            .def("__setitem__", &FixedArray2D<T>::setitem_vector)
+            .def("__setitem__", &FixedArray2D<T>::setitem_vector_mask)
+            .def("__setitem__", &FixedArray2D<T>::setitem_array1d)
+            .def("__setitem__", &FixedArray2D<T>::setitem_array1d_mask)
+            .def("__len__",&FixedArray2D<T>::totalLen)
+            .def("size",&FixedArray2D<T>::size)
+            .def("ifelse",&FixedArray2D<T>::ifelse_scalar)
+            .def("ifelse",&FixedArray2D<T>::ifelse_vector)
+            ;
+        return c;
+    }
+
+//     template <class T2>
+//     size_t match_dimension(const FixedArray<T2> &a1) const
+//     {
+//         if (_length.x != a1.len()) {
+//             PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
+//             boost::python::throw_error_already_set();
+//         }
+//         return _length.x;
+//     }
+
+    template <class T2>
+    IMATH_NAMESPACE::Vec2<size_t> match_dimension(const FixedArray2D<T2> &a1) const
+    {
+        if (len() != a1.len()) {
+            PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
+            boost::python::throw_error_already_set();
+        }
+        return len();
+    }
+
+    FixedArray2D<T> ifelse_vector(const FixedArray2D<int> &choice, const FixedArray2D<T> &other) {
+        IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(choice);
+        match_dimension(other);
+        FixedArray2D<T> tmp(len); // should use default construction but V3f doens't initialize
+        for (size_t j = 0; j < len.y; ++j)
+            for (size_t i = 0; i < len.x; ++i)
+                tmp(i,j) = choice(i,j) ? (*this)(i,j) : other(i,j);
+        return tmp;
+    }
+
+    FixedArray2D<T> ifelse_scalar(const FixedArray2D<int> &choice, const T &other) {
+        IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(choice);
+        FixedArray2D<T> tmp(len); // should use default construction but V3f doens't initialize
+        for (size_t j = 0; j < len.y; ++j)
+            for (size_t i = 0; i < len.x; ++i)
+                tmp(i,j) = choice(i,j) ? (*this)(i,j) : other;
+        return tmp;
+    }
+
+};
+// unary operation application
+template <template <class,class> class Op, class T1, class Ret>
+FixedArray2D<Ret> apply_array2d_unary_op(const FixedArray2D<T1> &a1)
+{
+    IMATH_NAMESPACE::Vec2<size_t> len = a1.len();
+    FixedArray2D<Ret> retval(len.x,len.y);
+    for (size_t j=0; j<len.y; ++j) {
+        for (size_t i=0;i<len.x;++i) {
+            retval(i,j) = Op<T1,Ret>::apply(a1(i,j));
+        }
+    }
+    return retval;
+}
+
+// binary operation application
+template <template <class,class,class> class Op, class T1, class T2, class Ret>
+FixedArray2D<Ret> apply_array2d_array2d_binary_op(const FixedArray2D<T1> &a1, const FixedArray2D<T2> &a2)
+{
+    IMATH_NAMESPACE::Vec2<size_t> len = a1.match_dimension(a2);
+    FixedArray2D<Ret> retval(len.x,len.y);
+    for (size_t j=0; j<len.y; ++j) {
+        for (size_t i=0;i<len.x;++i) {
+            retval(i,j) = Op<T1,T2,Ret>::apply(a1(i,j),a2(i,j));
+        }
+    }
+    return retval;
+}
+
+template <template <class,class,class> class Op, class T1, class T2, class Ret>
+FixedArray2D<Ret> apply_array2d_scalar_binary_op(const FixedArray2D<T1> &a1, const T2 &a2)
+{
+    IMATH_NAMESPACE::Vec2<size_t> len = a1.len();
+    FixedArray2D<Ret> retval(len.x,len.y);
+    for (size_t j=0; j<len.y; ++j) {
+        for (size_t i=0;i<len.x;++i) {
+            retval(i,j) = Op<T1,T2,Ret>::apply(a1(i,j),a2);
+        }
+    }
+    return retval;
+}
+
+template <template <class,class,class> class Op, class T1, class T2, class Ret>
+FixedArray2D<Ret> apply_array2d_scalar_binary_rop(const FixedArray2D<T1> &a1, const T2 &a2)
+{
+    IMATH_NAMESPACE::Vec2<size_t> len = a1.len();
+    FixedArray2D<Ret> retval(len.x,len.y);
+    for (size_t j=0; j<len.y; ++j) {
+        for (size_t i=0;i<len.x;++i) {
+            retval(i,j) = Op<T2,T1,Ret>::apply(a2,a1(i,j));
+        }
+    }
+    return retval;
+}
+
+// in-place binary operation application
+template <template <class,class> class Op, class T1, class T2>
+FixedArray2D<T1> & apply_array2d_array2d_ibinary_op(FixedArray2D<T1> &a1, const FixedArray2D<T2> &a2)
+{
+    IMATH_NAMESPACE::Vec2<size_t> len = a1.match_dimension(a2);
+    for (size_t j=0; j<len.y; ++j) {
+        for (size_t i=0;i<len.x;++i) {
+            Op<T1,T2>::apply(a1(i,j),a2(i,j));
+        }
+    }
+    return a1;
+}
+
+// in-place binary operation application
+template <template <class,class> class Op, class T1, class T2>
+FixedArray2D<T1> & apply_array2d_scalar_ibinary_op(FixedArray2D<T1> &a1, const T2 &a2)
+{
+    IMATH_NAMESPACE::Vec2<size_t> len = a1.len();
+    for (size_t j=0; j<len.y; ++j) {
+        for (size_t i=0;i<len.x;++i) {
+            Op<T1,T2>::apply(a1(i,j),a2);
+        }
+    }
+    return a1;
+}
+
+    
+// PyObject* PyNumber_Add(     PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> operator + (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_add,T,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> operator + (const FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_binary_op<op_add,T,T,T>(a0,v1); }
+template <class T> static FixedArray2D<T> operator + (const T &v1, const FixedArray2D<T> &a0)               { return a0+v1; }
+
+// PyObject* PyNumber_Subtract(        PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> operator - (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_sub,T,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> operator - (const FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_binary_op<op_sub,T,T,T>(a0,v1); }
+template <class T> static FixedArray2D<T> operator - (const T &v1, const FixedArray2D<T> &a0)               { return apply_array2d_scalar_binary_op<op_rsub,T,T,T>(a0,v1); }
+
+// PyObject* PyNumber_Multiply(        PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> operator * (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_mul,T,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> operator * (const FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_binary_op<op_mul,T,T,T>(a0,v1); }
+template <class T> static FixedArray2D<T> operator * (const T &v1, const FixedArray2D<T> &a0)               { return a0*v1; }
+
+// PyObject* PyNumber_Divide(  PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> operator / (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_div,T,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> operator / (const FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_binary_op<op_div,T,T,T>(a0,v1); }
+// no reversed scalar/array2d divide - no meaning
+
+// PyObject* PyNumber_FloorDivide(     PyObject *o1, PyObject *o2)
+// PyObject* PyNumber_TrueDivide(      PyObject *o1, PyObject *o2)
+// PyObject* PyNumber_Remainder(       PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> operator % (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_mod,T,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> operator % (const FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_binary_op<op_mod,T,T,T>(a0,v1); }
+// no reversed scalar%array2d remainder - no meaning
+
+// PyObject* PyNumber_Divmod(  PyObject *o1, PyObject *o2)
+
+// PyObject* PyNumber_Power(   PyObject *o1, PyObject *o2, PyObject *o3)
+template <class T> static FixedArray2D<T> pow_array2d_array2d (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_pow,T,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> pow_array2d_scalar (const FixedArray2D<T> &a0, const T &v1)                { return apply_array2d_scalar_binary_op<op_pow,T,T,T>(a0,v1); }
+// no reversed scalar/array2d pow - no meaning
+
+// PyObject* PyNumber_Negative(        PyObject *o)
+template <class T> static FixedArray2D<T> operator - (const FixedArray2D<T> &a0) { return apply_array2d_unary_op<op_neg,T,T>(a0); }
+
+// PyObject* PyNumber_Positive(        PyObject *o)
+
+// PyObject* PyNumber_Absolute(        PyObject *o)
+template <class T> static FixedArray2D<T> abs (const FixedArray2D<T> &a0)        { return apply_array2d_unary_op<op_abs,T,T>(a0); }
+
+// PyObject* PyNumber_Invert(  PyObject *o)
+template <class T> static FixedArray2D<T> operator ~ (const FixedArray2D<T> &a0) { return apply_array2d_unary_op<op_inverse,T,T>(a0); }
+
+// PyObject* PyNumber_Lshift(  PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> operator << (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_lshift,T,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> operator << (const FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_binary_op<op_lshift,T,T,T>(a0,v1); }
+// no reversed
+
+// PyObject* PyNumber_Rshift(  PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> operator >> (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_rshift,T,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> operator >> (const FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_binary_op<op_rshift,T,T,T>(a0,v1); }
+// no reversed
+
+// PyObject* PyNumber_And(     PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> operator & (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_bitand,T,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> operator & (const FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_binary_op<op_bitand,T,T,T>(a0,v1); }
+template <class T> static FixedArray2D<T> operator & (const T &v1, const FixedArray2D<T> &a0)               { return a0&v1; }
+
+// PyObject* PyNumber_Xor(     PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> operator ^ (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_xor,T,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> operator ^ (const FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_binary_op<op_xor,T,T,T>(a0,v1); }
+template <class T> static FixedArray2D<T> operator ^ (const T &v1, const FixedArray2D<T> &a0)               { return a0^v1; }
+
+// PyObject* PyNumber_Or(      PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> operator | (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_bitor,T,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> operator | (const FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_binary_op<op_bitor,T,T,T>(a0,v1); }
+template <class T> static FixedArray2D<T> operator | (const T &v1, const FixedArray2D<T> &a0)               { return a0|v1; }
+
+
+// PyObject* PyNumber_InPlaceAdd(      PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> & operator += (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_iadd,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> & operator += (FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_ibinary_op<op_iadd,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceSubtract( PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> & operator -= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_isub,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> & operator -= (FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_ibinary_op<op_isub,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceMultiply( PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> & operator *= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_imul,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> & operator *= (FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_ibinary_op<op_imul,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceDivide(   PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> & operator /= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_idiv,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> & operator /= (FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_ibinary_op<op_idiv,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceFloorDivide(      PyObject *o1, PyObject *o2)
+// not implemented
+
+// PyObject* PyNumber_InPlaceTrueDivide(       PyObject *o1, PyObject *o2)
+// not implemented
+
+// PyObject* PyNumber_InPlaceRemainder(        PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> & operator %= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_imod,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> & operator %= (FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_ibinary_op<op_imod,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlacePower(    PyObject *o1, PyObject *o2, PyObject *o3)
+template <class T> static FixedArray2D<T> & ipow_array2d_array2d (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_ipow,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> & ipow_array2d_scalar (FixedArray2D<T> &a0, const T &v1)                { return apply_array2d_scalar_ibinary_op<op_ipow,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceLshift(   PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> & operator <<= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_ilshift,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> & operator <<= (FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_ibinary_op<op_ilshift,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceRshift(   PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> & operator >>= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_irshift,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> & operator >>= (FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_ibinary_op<op_irshift,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceAnd(      PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> & operator &= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_ibitand,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> & operator &= (FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_ibinary_op<op_ibitand,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceXor(      PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> & operator ^= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_ixor,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> & operator ^= (FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_ibinary_op<op_ixor,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceOr(       PyObject *o1, PyObject *o2)
+template <class T> static FixedArray2D<T> & operator |= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_ibitor,T,T>(a0,a1); }
+template <class T> static FixedArray2D<T> & operator |= (FixedArray2D<T> &a0, const T &v1)               { return apply_array2d_scalar_ibinary_op<op_ibitor,T,T>(a0,v1); }
+
+template <class T>
+static void add_arithmetic_math_functions(boost::python::class_<FixedArray2D<T> > &c) {
+    using namespace boost::python;
+    c
+        .def("__add__",&apply_array2d_array2d_binary_op<op_add,T,T,T>)
+        .def("__add__",&apply_array2d_scalar_binary_op<op_add,T,T,T>)
+        .def("__radd__",&apply_array2d_scalar_binary_rop<op_add,T,T,T>)
+        .def("__sub__",&apply_array2d_array2d_binary_op<op_sub,T,T,T>)
+        .def("__sub__",&apply_array2d_scalar_binary_op<op_sub,T,T,T>)
+        .def("__rsub__",&apply_array2d_scalar_binary_op<op_rsub,T,T,T>)
+        .def("__mul__",&apply_array2d_array2d_binary_op<op_mul,T,T,T>)
+        .def("__mul__",&apply_array2d_scalar_binary_op<op_mul,T,T,T>)
+        .def("__rmul__",&apply_array2d_scalar_binary_rop<op_mul,T,T,T>)
+        .def("__div__",&apply_array2d_array2d_binary_op<op_div,T,T,T>)
+        .def("__div__",&apply_array2d_scalar_binary_op<op_div,T,T,T>)
+        .def("__truediv__",&apply_array2d_array2d_binary_op<op_div,T,T,T>)
+        .def("__truediv__",&apply_array2d_scalar_binary_op<op_div,T,T,T>)
+        .def("__neg__",&apply_array2d_unary_op<op_neg,T,T>)
+        .def("__iadd__",&apply_array2d_array2d_ibinary_op<op_iadd,T,T>,return_internal_reference<>())
+        .def("__iadd__",&apply_array2d_scalar_ibinary_op<op_iadd,T,T>,return_internal_reference<>())
+        .def("__isub__",&apply_array2d_array2d_ibinary_op<op_isub,T,T>,return_internal_reference<>())
+        .def("__isub__",&apply_array2d_scalar_ibinary_op<op_isub,T,T>,return_internal_reference<>())
+        .def("__imul__",&apply_array2d_array2d_ibinary_op<op_imul,T,T>,return_internal_reference<>())
+        .def("__imul__",&apply_array2d_scalar_ibinary_op<op_imul,T,T>,return_internal_reference<>())
+        .def("__idiv__",&apply_array2d_array2d_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
+        .def("__idiv__",&apply_array2d_scalar_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
+        .def("__itruediv__",&apply_array2d_array2d_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
+        .def("__itruediv__",&apply_array2d_scalar_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
+        ;
+}
+
+
+template <class T>
+static void add_pow_math_functions(boost::python::class_<FixedArray2D<T> > &c) {
+    using namespace boost::python;
+    c
+        .def("__pow__",&apply_array2d_array2d_binary_op<op_pow,T,T,T>)
+        .def("__pow__",&apply_array2d_scalar_binary_op<op_pow,T,T,T>)
+        .def("__rpow__",&apply_array2d_scalar_binary_rop<op_rpow,T,T,T>)
+        .def("__ipow__",&apply_array2d_array2d_ibinary_op<op_ipow,T,T>,return_internal_reference<>())
+        .def("__ipow__",&apply_array2d_scalar_ibinary_op<op_ipow,T,T>,return_internal_reference<>())
+        ;
+}
+
+template <class T>
+static void add_mod_math_functions(boost::python::class_<FixedArray2D<T> > &c) {
+    using namespace boost::python;
+    c
+        .def("__mod__",&apply_array2d_array2d_binary_op<op_mod,T,T,T>)
+        .def("__mod__",&apply_array2d_scalar_binary_op<op_mod,T,T,T>)
+        .def("__imod__",&apply_array2d_array2d_ibinary_op<op_imod,T,T>,return_internal_reference<>())
+        .def("__imod__",&apply_array2d_scalar_ibinary_op<op_imod,T,T>,return_internal_reference<>())
+        ;
+}
+
+template <class T>
+static void add_shift_math_functions(boost::python::class_<FixedArray2D<T> > &c) {
+    using namespace boost::python;
+    c
+        .def("__lshift__",&apply_array2d_array2d_binary_op<op_lshift,T,T,T>)
+        .def("__lshift__",&apply_array2d_scalar_binary_op<op_lshift,T,T,T>)
+        .def("__ilshift__",&apply_array2d_array2d_ibinary_op<op_ilshift,T,T>,return_internal_reference<>())
+        .def("__ilshift__",&apply_array2d_scalar_ibinary_op<op_ilshift,T,T>,return_internal_reference<>())
+        .def("__rshift__",&apply_array2d_array2d_binary_op<op_rshift,T,T,T>)
+        .def("__rshift__",&apply_array2d_scalar_binary_op<op_rshift,T,T,T>)
+        .def("__irshift__",&apply_array2d_array2d_ibinary_op<op_irshift,T,T>,return_internal_reference<>())
+        .def("__irshift__",&apply_array2d_scalar_ibinary_op<op_irshift,T,T>,return_internal_reference<>())
+        ;
+}
+
+template <class T>
+static void add_bitwise_math_functions(boost::python::class_<FixedArray2D<T> > &c) {
+    using namespace boost::python;
+    c
+        .def("__and__",&apply_array2d_array2d_binary_op<op_bitand,T,T,T>)
+        .def("__and__",&apply_array2d_scalar_binary_op<op_bitand,T,T,T>)
+        .def("__iand__",&apply_array2d_array2d_ibinary_op<op_ibitand,T,T>,return_internal_reference<>())
+        .def("__iand__",&apply_array2d_scalar_ibinary_op<op_ibitand,T,T>,return_internal_reference<>())
+        .def("__or__",&apply_array2d_array2d_binary_op<op_bitor,T,T,T>)
+        .def("__or__",&apply_array2d_scalar_binary_op<op_bitor,T,T,T>)
+        .def("__ior__",&apply_array2d_array2d_ibinary_op<op_ibitor,T,T>,return_internal_reference<>())
+        .def("__ior__",&apply_array2d_scalar_ibinary_op<op_ibitor,T,T>,return_internal_reference<>())
+        .def("__xor__",&apply_array2d_array2d_binary_op<op_xor,T,T,T>)
+        .def("__xor__",&apply_array2d_scalar_binary_op<op_xor,T,T,T>)
+        .def("__ixor__",&apply_array2d_array2d_ibinary_op<op_ixor,T,T>,return_internal_reference<>())
+        .def("__ixor__",&apply_array2d_scalar_ibinary_op<op_ixor,T,T>,return_internal_reference<>())
+        ;
+}
+
+template <class T>
+static void add_comparison_functions(boost::python::class_<FixedArray2D<T> > &c) {
+    using namespace boost::python;
+    c
+        .def("__eq__",&apply_array2d_array2d_binary_op<op_eq,T,T,int>)
+        .def("__eq__",&apply_array2d_scalar_binary_op<op_eq,T,T,int>)
+        .def("__ne__",&apply_array2d_array2d_binary_op<op_ne,T,T,int>)
+        .def("__ne__",&apply_array2d_scalar_binary_op<op_ne,T,T,int>)
+        ;
+}
+
+template <class T>
+static void add_ordered_comparison_functions(boost::python::class_<FixedArray2D<T> > &c) {
+    using namespace boost::python;
+    c
+        .def("__lt__",&apply_array2d_array2d_binary_op<op_lt,T,T,int>)
+        .def("__lt__",&apply_array2d_scalar_binary_op<op_lt,T,T,int>)
+        .def("__gt__",&apply_array2d_array2d_binary_op<op_gt,T,T,int>)
+        .def("__gt__",&apply_array2d_scalar_binary_op<op_gt,T,T,int>)
+        .def("__le__",&apply_array2d_array2d_binary_op<op_le,T,T,int>)
+        .def("__le__",&apply_array2d_scalar_binary_op<op_le,T,T,int>)
+        .def("__ge__",&apply_array2d_array2d_binary_op<op_ge,T,T,int>)
+        .def("__ge__",&apply_array2d_scalar_binary_op<op_ge,T,T,int>)
+        ;
+}
+
+template <class S,class T>
+static void add_explicit_construction_from_type(boost::python::class_<FixedArray2D<T> > &c) {
+    using namespace boost::python;
+    c.def(boost::python::init<FixedArray2D<S> >("copy contents of other array into this one"));
+}
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathFixedArrayTraits.h b/src/python/PyImath/PyImathFixedArrayTraits.h
new file mode 100644 (file)
index 0000000..8b16829
--- /dev/null
@@ -0,0 +1,149 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PYIMATH_FIXEDARRAY_TRAITS_H
+#define _PYIMATH_FIXEDARRAY_TRAITS_H
+
+#include <Python.h>
+#include <ImathVec.h>
+#include <half.h>
+#include <string>
+
+
+namespace PyImath {
+
+//  See https://docs.python.org/2/library/struct.html
+//
+//  Section 7.3.2.2
+//
+static  char       PyFmtStr_int[2] = {'i', '\0'};
+static  char     PyFmtStr_float[2] = {'f', '\0'};
+static  char    PyFmtStr_double[2] = {'d', '\0'};
+static  char      PyFmtStr_bool[2] = {'?', '\0'};
+static  char      PyFmtStr_char[2] = {'b', '\0'};
+static  char     PyFmtStr_short[2] = {'h', '\0'};
+static  char      PyFmtStr_long[2] = {'l', '\0'};
+static  char  PyFmtStr_longlong[2] = {'q', '\0'};
+static  char     PyFmtStr_uchar[2] = {'B', '\0'};
+static  char    PyFmtStr_ushort[2] = {'H', '\0'};
+static  char      PyFmtStr_uint[2] = {'I', '\0'};
+static  char     PyFmtStr_ulong[2] = {'L', '\0'};
+static  char PyFmtStr_ulonglong[2] = {'Q', '\0'};
+static  char      PyFmtStr_half[2] = {'e', '\0'};
+
+
+template <typename T> constexpr  char* PyFormat();
+
+template <> constexpr  char*                PyFormat<int>()  { return PyFmtStr_int;       } 
+template <> constexpr  char*              PyFormat<float>()  { return PyFmtStr_float;     }
+template <> constexpr  char*             PyFormat<double>()  { return PyFmtStr_double;    }
+template <> constexpr  char*               PyFormat<bool>()  { return PyFmtStr_bool;      }
+template <> constexpr  char*               PyFormat<char>()  { return PyFmtStr_char;      }
+template <> constexpr  char*              PyFormat<short>()  { return PyFmtStr_short;     }
+template <> constexpr  char*               PyFormat<long>()  { return PyFmtStr_long;      }
+template <> constexpr  char*          PyFormat<long long>()  { return PyFmtStr_longlong;  }
+template <> constexpr  char*      PyFormat<unsigned char>()  { return PyFmtStr_uchar;     }
+template <> constexpr  char*     PyFormat<unsigned short>()  { return PyFmtStr_ushort;    }
+template <> constexpr  char*       PyFormat<unsigned int>()  { return PyFmtStr_uint;      }
+template <> constexpr  char*      PyFormat<unsigned long>()  { return PyFmtStr_ulong;     }
+template <> constexpr  char* PyFormat<unsigned long long>()  { return PyFmtStr_ulonglong; }
+template <> constexpr  char*               PyFormat<half>()  { return PyFmtStr_half;      }
+
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec2<short> >()    { return PyFmtStr_short;  } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec2<int> >()      { return PyFmtStr_int;    } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec2<int64_t> >()  { return PyFmtStr_long;   } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec2<float> >()    { return PyFmtStr_float;  } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec2<double> >()   { return PyFmtStr_double; } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec3<short> >()    { return PyFmtStr_short;  } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec3<int> >()      { return PyFmtStr_int;    } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec3<int64_t> >()  { return PyFmtStr_long;   } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec3<float> >()    { return PyFmtStr_float;  } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec3<double> >()   { return PyFmtStr_double; } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec4<short> >()    { return PyFmtStr_short;  } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec4<int> >()      { return PyFmtStr_int;    } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec4<int64_t> >()  { return PyFmtStr_long;   } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec4<float> >()    { return PyFmtStr_float;  } 
+template <> constexpr  char*   PyFormat<IMATH_NAMESPACE::Vec4<double> >()   { return PyFmtStr_double; } 
+
+
+template <typename T> struct FixedArrayWidth { static const Py_ssize_t value; };
+
+template <> struct FixedArrayWidth<short>                            { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayWidth<int>                              { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayWidth<int64_t>                          { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayWidth<float>                            { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayWidth<double>                           { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayWidth<unsigned char>                    { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec2<short> >    { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec2<int> >      { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec2<int64_t> >  { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec2<float> >    { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec2<double> >   { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec3<short> >    { static const Py_ssize_t value = 3; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec3<int> >      { static const Py_ssize_t value = 3; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec3<int64_t> >  { static const Py_ssize_t value = 3; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec3<float> >    { static const Py_ssize_t value = 3; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec3<double> >   { static const Py_ssize_t value = 3; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec4<short> >    { static const Py_ssize_t value = 4; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec4<int> >      { static const Py_ssize_t value = 4; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec4<int64_t> >  { static const Py_ssize_t value = 4; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec4<float> >    { static const Py_ssize_t value = 4; };
+template <> struct FixedArrayWidth<IMATH_NAMESPACE::Vec4<double> >   { static const Py_ssize_t value = 4; };
+
+
+template <typename T> struct FixedArrayDimension { static const Py_ssize_t value; };
+
+template <> struct FixedArrayDimension<short>                            { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayDimension<int>                              { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayDimension<int64_t>                          { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayDimension<float>                            { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayDimension<double>                           { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayDimension<unsigned char>                    { static const Py_ssize_t value = 1; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec2<short> >    { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec2<int> >      { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec2<int64_t> >  { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec2<float> >    { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec2<double> >   { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec3<short> >    { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec3<int> >      { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec3<int64_t> >  { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec3<float> >    { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec3<double> >   { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec4<short> >    { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec4<int> >      { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec4<int64_t> >  { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec4<float> >    { static const Py_ssize_t value = 2; };
+template <> struct FixedArrayDimension<IMATH_NAMESPACE::Vec4<double> >   { static const Py_ssize_t value = 2; };
+
+
+template <typename T> struct FixedArrayAtomicSize { static const Py_ssize_t value; };
+
+template <> struct FixedArrayAtomicSize<short>                            { static const Py_ssize_t value = sizeof(short); };
+template <> struct FixedArrayAtomicSize<int>                              { static const Py_ssize_t value = sizeof(int); };
+template <> struct FixedArrayAtomicSize<int64_t>                          { static const Py_ssize_t value = sizeof(int); };
+template <> struct FixedArrayAtomicSize<float>                            { static const Py_ssize_t value = sizeof(float); };
+template <> struct FixedArrayAtomicSize<double>                           { static const Py_ssize_t value = sizeof(double); };
+template <> struct FixedArrayAtomicSize<unsigned char>                    { static const Py_ssize_t value = sizeof(unsigned char); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec2<short> >    { static const Py_ssize_t value = sizeof(short); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec2<int> >      { static const Py_ssize_t value = sizeof(int); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec2<int64_t> >  { static const Py_ssize_t value = sizeof(int64_t); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec2<float> >    { static const Py_ssize_t value = sizeof(float); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec2<double> >   { static const Py_ssize_t value = sizeof(double); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec3<short> >    { static const Py_ssize_t value = sizeof(short); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec3<int> >      { static const Py_ssize_t value = sizeof(int); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec3<int64_t> >  { static const Py_ssize_t value = sizeof(int64_t); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec3<float> >    { static const Py_ssize_t value = sizeof(float); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec3<double> >   { static const Py_ssize_t value = sizeof(double); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec4<short> >    { static const Py_ssize_t value = sizeof(short); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec4<int> >      { static const Py_ssize_t value = sizeof(int); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec4<int64_t> >  { static const Py_ssize_t value = sizeof(int64_t); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec4<float> >    { static const Py_ssize_t value = sizeof(float); };
+template <> struct FixedArrayAtomicSize<IMATH_NAMESPACE::Vec4<double> >   { static const Py_ssize_t value = sizeof(double); };
+
+} // namespace
+
+#endif
diff --git a/src/python/PyImath/PyImathFixedMatrix.h b/src/python/PyImath/PyImathFixedMatrix.h
new file mode 100644 (file)
index 0000000..18bb0a4
--- /dev/null
@@ -0,0 +1,514 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathFixedMatrix_h_
+#define _PyImathFixedMatrix_h_
+
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <iostream>
+#include "PyImathFixedArray.h"
+#include "PyImathOperators.h"
+
+namespace PyImath {
+
+//
+// Utility class for a runtime-specified fixed sized matrix type in python
+//
+template <class T>
+class FixedMatrix
+{
+    T *     _ptr;
+    int     _rows;
+    int     _cols;
+    int     _rowStride;
+    int     _colStride;
+    int *   _refcount; // refcount if allocated, null if externally allocated
+
+  public:
+
+    FixedMatrix(T *ptr, int rows, int cols, int rowStride = 1, int colStride = 1) 
+        : _ptr(ptr), _rows(rows), _cols(cols),
+          _rowStride(rowStride), _colStride(colStride), _refcount(0)
+    {
+        // nothing
+    }
+
+    FixedMatrix(int rows, int cols)
+        : _ptr(new T[rows*cols]), _rows(rows), _cols(cols),
+          _rowStride(1), _colStride(1), _refcount(new int(1))
+    {
+        // nothing
+    }
+
+    FixedMatrix(const FixedMatrix &other)
+        : _ptr(other._ptr), _rows(other._rows), _cols(other._cols),
+          _rowStride(other._rowStride), _colStride(other._colStride),
+          _refcount(other._refcount)
+    {
+        if (_refcount) *_refcount += 1;
+    }
+        
+    const FixedMatrix &
+    operator = (const FixedMatrix &other)
+    {
+        if (&other == this) return *this;
+        unref();
+        _ptr = other._ptr;
+        _rows = other._rows;
+        _cols = other._cols;
+        _rowStride = other._rowStride;
+        _colStride = other._colStride;
+        _refcount = other._refcount;
+
+        if (_refcount) *_refcount += 1;
+        return *this;
+    }
+
+    void
+    unref()
+    {
+        if (_refcount) {
+            *_refcount -= 1;
+            if (*_refcount == 0) {
+                delete [] _ptr;
+                delete _refcount;
+            }
+        }
+        _ptr = 0;
+        _rows = 0;
+        _cols = 0;
+        _rowStride = 0;
+        _colStride = 0;
+        _refcount = 0;
+    }
+
+    ~FixedMatrix()
+    {
+        unref();
+    }
+    
+    Py_ssize_t convert_index(int index) const
+    {
+        if (index < 0) index += _rows;
+        if (index >= _rows || index < 0) {
+            PyErr_SetString(PyExc_IndexError, "Index out of range");
+            boost::python::throw_error_already_set();
+        }
+        return index;
+    }
+
+    void extract_slice_indices(PyObject *index, Py_ssize_t &start, Py_ssize_t &end, Py_ssize_t &step, Py_ssize_t &slicelength) const
+    {
+        slicelength = 0;
+        if (PySlice_Check(index)) {
+#if PY_MAJOR_VERSION > 2
+            PyObject *slice = index;
+#else
+            PySliceObject *slice = reinterpret_cast<PySliceObject *>(index);
+#endif
+            if (PySlice_GetIndicesEx(slice,_rows,&start,&end,&step,&slicelength) == -1) {
+                   boost::python::throw_error_already_set();
+            }
+        } else if (PyInt_Check(index)) {
+            Py_ssize_t i = convert_index(PyInt_AS_LONG(index));
+            start = i; end = i+1; step = 1; slicelength = 1;
+        } else {
+            PyErr_SetString(PyExc_TypeError, "Object is not a slice");
+           boost::python::throw_error_already_set();
+        }
+        //std::cout << "Slice indices are " << start << " " << end << " " << step << " " << slicelength << std::endl;
+    }
+
+    const FixedArray<T> * getitem(int index) const
+    {
+        return new FixedArray<T>(const_cast<T *>(&_ptr[convert_index(index)*_rowStride*_cols*_colStride]),_cols,_colStride);
+    }
+
+    FixedMatrix  getslice(PyObject *index) const
+    {
+        Py_ssize_t start, end, step, slicelength;
+        extract_slice_indices(index,start,end,step,slicelength);
+        FixedMatrix f(slicelength,_cols);
+        for (int i=0; i<slicelength; ++i) {
+            for (int j=0; j<_cols; ++j) {
+                f.element(i,j) = element((start+i*step),j);
+            }
+        }
+        return f;
+    }
+
+    void
+    setitem_scalar(PyObject *index, const T &data)
+    {
+        Py_ssize_t start, end, step, slicelength;
+        extract_slice_indices(index,start,end,step,slicelength);
+        for (int i=0; i<slicelength; ++i) {
+            for (int j = 0; j < _cols; ++j) {
+                element(start+i*step,j) = data;
+            }
+        }
+    }
+
+    void
+    setitem_vector(PyObject *index, const FixedArray<T> &data)
+    {
+        Py_ssize_t start, end, step, slicelength;
+        extract_slice_indices(index,start,end,step,slicelength);
+        if (data.len() != _cols) {
+            PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
+           boost::python::throw_error_already_set();
+        }
+        for (int i=0; i<slicelength; ++i) {
+            for (int j = 0; j < _cols; ++j) {
+                element(start+i*step,j) = data[j];
+            }
+        }
+    }
+
+    void
+    setitem_matrix(PyObject *index, const FixedMatrix &data)
+    {
+        Py_ssize_t start, end, step, slicelength;
+        extract_slice_indices(index,start,end,step,slicelength);
+        
+        // we have a valid range of indices
+        if (data.rows() != slicelength || data.cols() != cols()) {
+            PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
+           boost::python::throw_error_already_set();
+        }
+        for (int i=0; i<slicelength; ++i) {
+            for (int j=0; j<cols(); ++j) {
+                element(start+i*step,j) = data.element(i,j);
+            }
+        }
+    }
+
+    int         rows() const { return _rows; }
+    int         cols() const { return _cols; }
+    int         rowStride() const { return _rowStride; }
+    int         colStride() const { return _colStride; }
+
+    T & element(int i, int j) { return _ptr[i*_rowStride*_cols*_colStride+j*_colStride]; }
+    const T & element(int i, int j) const { return _ptr[i*_rowStride*_cols*_colStride+j*_colStride]; }
+
+    FixedArray<T> operator [] (int i) { return FixedArray<T>(&_ptr[i*_rowStride*_cols*_colStride],_cols,_colStride); }
+    const FixedArray<T> operator [] (int i) const { return FixedArray<T>(const_cast<T *>(&_ptr[i*_rowStride*_cols*_colStride]),_cols,_colStride); }
+
+    static boost::python::class_<FixedMatrix<T> > register_(const char *name, const char *doc)
+    {
+        boost::python::class_<FixedMatrix<T> > c(name,doc, boost::python::init<int,int>("return an uninitialized array of the specified rows and cols"));
+        c
+            .def("__getitem__", &FixedMatrix<T>::getslice)
+            .def("__getitem__", &FixedMatrix<T>::getitem, boost::python::return_internal_reference<>()) 
+            .def("__setitem__", &FixedMatrix<T>::setitem_scalar)
+            .def("__setitem__", &FixedMatrix<T>::setitem_vector)
+            .def("__setitem__", &FixedMatrix<T>::setitem_matrix)
+            .def("__len__",&FixedMatrix<T>::rows)
+            .def("rows",&FixedMatrix<T>::rows)
+            .def("columns",&FixedMatrix<T>::cols)
+            ;
+        return c;
+    }
+
+    template <class T2>
+    int match_dimension(const FixedMatrix<T2> &a1) const
+    {
+        if (rows() != a1.rows() || cols() != a1.cols()) {
+            PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
+           boost::python::throw_error_already_set();
+        }
+        return rows();
+    }
+};
+
+// unary operation application
+template <template <class,class> class Op, class T1, class Ret>
+FixedMatrix<Ret> apply_matrix_unary_op(const FixedMatrix<T1> &a1)
+{
+    int rows = a1.rows();
+    int cols = a1.cols();
+    FixedMatrix<Ret> retval(rows,cols);
+    for (int i=0;i<rows;++i) for (int j=0; j<cols; ++j) {
+        retval.element(i,j) = Op<T1,Ret>::apply(a1.element(i,j));
+    }
+    return retval;
+}
+
+// binary operation application
+template <template <class,class,class> class Op, class T1, class T2, class Ret>
+FixedMatrix<Ret> apply_matrix_matrix_binary_op(const FixedMatrix<T1> &a1, const FixedMatrix<T2> &a2)
+{
+    int rows = a1.match_dimension(a2);
+    int cols = a1.cols();
+    FixedMatrix<Ret> retval(rows,cols);
+    for (int i=0;i<rows;++i) for (int j=0; j<cols; ++j) {
+        retval.element(i,j) = Op<T1,T2,Ret>::apply(a1.element(i,j),a2.element(i,j));
+    }
+    return retval;
+}
+
+template <template <class,class,class> class Op, class T1, class T2, class Ret>
+FixedMatrix<Ret> apply_matrix_scalar_binary_op(const FixedMatrix<T1> &a1, const T2 &a2)
+{
+    int rows = a1.rows();
+    int cols = a1.cols();
+    FixedMatrix<Ret> retval(rows,cols);
+    for (int i=0;i<rows;++i) for (int j=0; j<cols; ++j) {
+        retval.element(i,j) = Op<T1,T2,Ret>::apply(a1.element(i,j),a2);
+    }
+    return retval;
+}
+
+template <template <class,class,class> class Op, class T1, class T2, class Ret>
+FixedMatrix<Ret> apply_matrix_scalar_binary_rop(const FixedMatrix<T1> &a1, const T2 &a2)
+{
+    int rows = a1.rows();
+    int cols = a1.cols();
+    FixedMatrix<Ret> retval(rows,cols);
+    for (int i=0;i<rows;++i) for (int j=0; j<cols; ++j) {
+        retval.element(i,j) = Op<T2,T1,Ret>::apply(a2,a1.element(i,j));
+    }
+    return retval;
+}
+
+// in-place binary operation application
+template <template <class,class> class Op, class T1, class T2>
+FixedMatrix<T1> & apply_matrix_matrix_ibinary_op(FixedMatrix<T1> &a1, const FixedMatrix<T2> &a2)
+{
+    int rows = a1.match_dimension(a2);
+    int cols = a1.cols();
+    for (int i=0;i<rows;++i) for (int j=0; j<cols; ++j) {
+        Op<T1,T2>::apply(a1.element(i,j),a2.element(i,j));
+    }
+    return a1;
+}
+
+// in-place binary operation application
+template <template <class,class> class Op, class T1, class T2>
+FixedMatrix<T1> & apply_matrix_scalar_ibinary_op(FixedMatrix<T1> &a1, const T2 &a2)
+{
+    int rows = a1.rows();
+    int cols = a1.cols();
+    for (int i=0;i<rows;++i) for (int j=0; j<cols; ++j) {
+        Op<T1,T2>::apply(a1.element(i,j),a2);
+    }
+    return a1;
+}
+
+// PyObject* PyNumber_Add(     PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> operator + (const FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_binary_op<op_add,T,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> operator + (const FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_binary_op<op_add,T,T,T>(a0,v1); }
+template <class T> static FixedMatrix<T> operator + (const T &v1, const FixedMatrix<T> &a0)              { return a0+v1; }
+
+// PyObject* PyNumber_Subtract(        PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> operator - (const FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_binary_op<op_sub,T,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> operator - (const FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_binary_op<op_sub,T,T,T>(a0,v1); }
+template <class T> static FixedMatrix<T> operator - (const T &v1, const FixedMatrix<T> &a0)              { return apply_matrix_scalar_binary_op<op_rsub,T,T,T>(a0,v1); }
+
+// PyObject* PyNumber_Multiply(        PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> operator * (const FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_binary_op<op_mul,T,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> operator * (const FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_binary_op<op_mul,T,T,T>(a0,v1); }
+template <class T> static FixedMatrix<T> operator * (const T &v1, const FixedMatrix<T> &a0)              { return a0*v1; }
+
+// PyObject* PyNumber_Divide(  PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> operator / (const FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_binary_op<op_div,T,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> operator / (const FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_binary_op<op_div,T,T,T>(a0,v1); }
+// no reversed scalar/matrix divide - no meaning
+
+// PyObject* PyNumber_FloorDivide(     PyObject *o1, PyObject *o2)
+// PyObject* PyNumber_TrueDivide(      PyObject *o1, PyObject *o2)
+// PyObject* PyNumber_Remainder(       PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> operator % (const FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_binary_op<op_mod,T,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> operator % (const FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_binary_op<op_mod,T,T,T>(a0,v1); }
+// no reversed scalar%matrix remainder - no meaning
+
+// PyObject* PyNumber_Divmod(  PyObject *o1, PyObject *o2)
+
+// PyObject* PyNumber_Power(   PyObject *o1, PyObject *o2, PyObject *o3)
+template <class T> static FixedMatrix<T> pow_matrix_matrix (const FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_binary_op<op_pow,T,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> pow_matrix_scalar (const FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_binary_op<op_pow,T,T,T>(a0,v1); }
+// no reversed scalar/matrix pow - no meaning
+
+// PyObject* PyNumber_Negative(        PyObject *o)
+template <class T> static FixedMatrix<T> operator - (const FixedMatrix<T> &a0) { return apply_matrix_unary_op<op_neg,T,T>(a0); }
+
+// PyObject* PyNumber_Positive(        PyObject *o)
+
+// PyObject* PyNumber_Absolute(        PyObject *o)
+template <class T> static FixedMatrix<T> abs (const FixedMatrix<T> &a0)        { return apply_matrix_unary_op<op_abs,T,T>(a0); }
+
+// PyObject* PyNumber_Invert(  PyObject *o)
+template <class T> static FixedMatrix<T> operator ~ (const FixedMatrix<T> &a0) { return apply_matrix_unary_op<op_inverse,T,T>(a0); }
+
+// PyObject* PyNumber_Lshift(  PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> operator << (const FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_binary_op<op_lshift,T,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> operator << (const FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_binary_op<op_lshift,T,T,T>(a0,v1); }
+// no reversed
+
+// PyObject* PyNumber_Rshift(  PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> operator >> (const FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_binary_op<op_rshift,T,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> operator >> (const FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_binary_op<op_rshift,T,T,T>(a0,v1); }
+// no reversed
+
+// PyObject* PyNumber_And(     PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> operator & (const FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_binary_op<op_bitand,T,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> operator & (const FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_binary_op<op_bitand,T,T,T>(a0,v1); }
+template <class T> static FixedMatrix<T> operator & (const T &v1, const FixedMatrix<T> &a0)              { return a0&v1; }
+
+// PyObject* PyNumber_Xor(     PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> operator ^ (const FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_binary_op<op_xor,T,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> operator ^ (const FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_binary_op<op_xor,T,T,T>(a0,v1); }
+template <class T> static FixedMatrix<T> operator ^ (const T &v1, const FixedMatrix<T> &a0)              { return a0^v1; }
+
+// PyObject* PyNumber_Or(      PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> operator | (const FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_binary_op<op_bitor,T,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> operator | (const FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_binary_op<op_bitor,T,T,T>(a0,v1); }
+template <class T> static FixedMatrix<T> operator | (const T &v1, const FixedMatrix<T> &a0)              { return a0|v1; }
+
+
+// PyObject* PyNumber_InPlaceAdd(      PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> & operator += (FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_ibinary_op<op_iadd,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> & operator += (FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_ibinary_op<op_iadd,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceSubtract( PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> & operator -= (FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_ibinary_op<op_isub,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> & operator -= (FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_ibinary_op<op_isub,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceMultiply( PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> & operator *= (FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_ibinary_op<op_imul,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> & operator *= (FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_ibinary_op<op_imul,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceDivide(   PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> & operator /= (FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_ibinary_op<op_idiv,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> & operator /= (FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_ibinary_op<op_idiv,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceFloorDivide(      PyObject *o1, PyObject *o2)
+// not implemented
+
+// PyObject* PyNumber_InPlaceTrueDivide(       PyObject *o1, PyObject *o2)
+// not implemented
+
+// PyObject* PyNumber_InPlaceRemainder(        PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> & operator %= (FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_ibinary_op<op_imod,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> & operator %= (FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_ibinary_op<op_imod,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlacePower(    PyObject *o1, PyObject *o2, PyObject *o3)
+template <class T> static FixedMatrix<T> & ipow_matrix_matrix (FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_ibinary_op<op_ipow,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> & ipow_matrix_scalar (FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_ibinary_op<op_ipow,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceLshift(   PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> & operator <<= (FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_ibinary_op<op_ilshift,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> & operator <<= (FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_ibinary_op<op_ilshift,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceRshift(   PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> & operator >>= (FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_ibinary_op<op_irshift,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> & operator >>= (FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_ibinary_op<op_irshift,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceAnd(      PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> & operator &= (FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_ibinary_op<op_ibitand,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> & operator &= (FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_ibinary_op<op_ibitand,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceXor(      PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> & operator ^= (FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_ibinary_op<op_ixor,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> & operator ^= (FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_ibinary_op<op_ixor,T,T>(a0,v1); }
+
+// PyObject* PyNumber_InPlaceOr(       PyObject *o1, PyObject *o2)
+template <class T> static FixedMatrix<T> & operator |= (FixedMatrix<T> &a0, const FixedMatrix<T> &a1) { return apply_matrix_matrix_ibinary_op<op_ibitor,T,T>(a0,a1); }
+template <class T> static FixedMatrix<T> & operator |= (FixedMatrix<T> &a0, const T &v1)              { return apply_matrix_scalar_ibinary_op<op_ibitor,T,T>(a0,v1); }
+
+template <class T>
+static void add_arithmetic_math_functions(boost::python::class_<FixedMatrix<T> > &c) {
+    using namespace boost::python;
+    c
+        .def("__add__",&apply_matrix_matrix_binary_op<op_add,T,T,T>)
+        .def("__add__",&apply_matrix_scalar_binary_op<op_add,T,T,T>)
+        .def("__radd__",&apply_matrix_scalar_binary_rop<op_add,T,T,T>)
+        .def("__sub__",&apply_matrix_matrix_binary_op<op_sub,T,T,T>)
+        .def("__sub__",&apply_matrix_scalar_binary_op<op_sub,T,T,T>)
+        .def("__rsub__",&apply_matrix_scalar_binary_op<op_rsub,T,T,T>)
+        .def("__mul__",&apply_matrix_matrix_binary_op<op_mul,T,T,T>)
+        .def("__mul__",&apply_matrix_scalar_binary_op<op_mul,T,T,T>)
+        .def("__rmul__",&apply_matrix_scalar_binary_rop<op_mul,T,T,T>)
+        .def("__div__",&apply_matrix_matrix_binary_op<op_div,T,T,T>)
+        .def("__div__",&apply_matrix_scalar_binary_op<op_div,T,T,T>)
+        .def("__truediv__",&apply_matrix_matrix_binary_op<op_div,T,T,T>)
+        .def("__truediv__",&apply_matrix_scalar_binary_op<op_div,T,T,T>)
+        .def("__neg__",&apply_matrix_unary_op<op_neg,T,T>)
+        .def("__iadd__",&apply_matrix_matrix_ibinary_op<op_iadd,T,T>,return_internal_reference<>())
+        .def("__iadd__",&apply_matrix_scalar_ibinary_op<op_iadd,T,T>,return_internal_reference<>())
+        .def("__isub__",&apply_matrix_matrix_ibinary_op<op_isub,T,T>,return_internal_reference<>())
+        .def("__isub__",&apply_matrix_scalar_ibinary_op<op_isub,T,T>,return_internal_reference<>())
+        .def("__imul__",&apply_matrix_matrix_ibinary_op<op_imul,T,T>,return_internal_reference<>())
+        .def("__imul__",&apply_matrix_scalar_ibinary_op<op_imul,T,T>,return_internal_reference<>())
+        .def("__idiv__",&apply_matrix_matrix_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
+        .def("__idiv__",&apply_matrix_scalar_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
+        .def("__itruediv__",&apply_matrix_matrix_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
+        .def("__itruediv__",&apply_matrix_scalar_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
+        ;
+}
+
+template <class T>
+static void add_pow_math_functions(boost::python::class_<FixedMatrix<T> > &c) {
+    using namespace boost::python;
+    c
+        .def("__pow__",&pow_matrix_scalar<T>)
+        .def("__pow__",&pow_matrix_matrix<T>)
+        .def("__ipow__",&ipow_matrix_scalar<T>,return_internal_reference<>())
+        .def("__ipow__",&ipow_matrix_matrix<T>,return_internal_reference<>())
+        ;
+}
+
+template <class T>
+static void add_mod_math_functions(boost::python::class_<FixedMatrix<T> > &c) {
+    using namespace boost::python;
+    c
+        .def(self % self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self % other<T>())
+        .def(self %= self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self %= other<T>())
+        ;
+}
+
+template <class T>
+static void add_shift_math_functions(boost::python::class_<FixedMatrix<T> > &c) {
+    using namespace boost::python;
+    c
+        .def(self << self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self << other<T>())
+        .def(self <<= self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self <<= other<T>())
+        .def(self >> self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self >> other<T>())
+        .def(self >>= self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self >>= other<T>())
+        ;
+}
+
+template <class T>
+static void add_bitwise_math_functions(boost::python::class_<FixedMatrix<T> > &c) {
+    using namespace boost::python;
+    c
+        .def(self & self)
+        .def(self & other<T>())
+        .def(self &= self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self &= other<T>())
+        .def(self | self)
+        .def(self | other<T>())
+        .def(self |= self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self |= other<T>())
+        .def(self ^ self)
+        .def(self ^ other<T>())
+        .def(self ^= self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self ^= other<T>())
+        ;
+}
+
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathFixedVArray.cpp b/src/python/PyImath/PyImathFixedVArray.cpp
new file mode 100644 (file)
index 0000000..d95cac3
--- /dev/null
@@ -0,0 +1,871 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/shared_array.hpp>
+#include <boost/any.hpp>
+#include <ImathVec.h>
+#include "PyImathExport.h"
+#include "PyImathFixedVArray.h"
+
+namespace PyImath {
+
+template <class T>
+FixedVArray<T>::FixedVArray (std::vector<T>* ptr, Py_ssize_t length,
+                             Py_ssize_t stride, bool writable)
+    : _ptr(ptr), _length(length), _stride(stride), _writable (writable),
+      _handle(), _unmaskedLength(0)
+{
+    if (length < 0)
+    {
+        throw std::invalid_argument("Fixed array length must be non-negative");
+    }
+    if (stride <= 0)
+    {
+        throw std::invalid_argument("Fixed array stride must be positive");
+    }
+
+    // Nothing else to do (pointer given, so we have the data)
+}
+
+template <class T>
+FixedVArray<T>::FixedVArray (std::vector<T>* ptr, Py_ssize_t length,
+                             Py_ssize_t stride, boost::any handle, bool writable)
+    : _ptr(ptr), _length(length), _stride(stride), _writable(writable),
+      _handle(handle), _unmaskedLength(0)
+{
+    if (length < 0)
+    {
+        throw std::invalid_argument("Fixed array length must be non-negative");
+    }
+    if (stride <= 0)
+    {
+        throw std::invalid_argument("Fixed array stride must be positive");
+    }
+
+    // Nothing else to do (pointer given, so we have the data)
+}
+
+template <class T>
+FixedVArray<T>::FixedVArray (const std::vector<T>* ptr, Py_ssize_t length,
+                             Py_ssize_t stride)
+    : _ptr(const_cast<std::vector<T> *>(ptr)), _length(length), _stride(stride),
+      _writable(false), _handle(), _unmaskedLength(0)
+{
+    if (length < 0)
+    {
+        throw std::invalid_argument("Fixed array length must be non-negative");
+    }
+    if (stride <= 0)
+    {
+        throw std::invalid_argument("Fixed array stride must be positive");
+    }
+
+    // Nothing else to do (pointer given, so we have the data)
+}
+
+template <class T>
+FixedVArray<T>::FixedVArray (const std::vector<T>* ptr, Py_ssize_t length,
+                             Py_ssize_t stride, boost::any handle)
+    : _ptr(const_cast<std::vector<T> *>(ptr)), _length(length), _stride(stride),
+      _writable(false), _handle(handle), _unmaskedLength(0)
+{
+    if (length < 0)
+    {
+        throw std::invalid_argument("Fixed array length must be non-negative");
+    }
+    if (stride <= 0)
+    {
+        throw std::invalid_argument("Fixed array stride must be positive");
+    }
+
+    // Nothing else to do (pointer given, so we have the data)
+}
+
+template <class T>
+FixedVArray<T>::FixedVArray(Py_ssize_t length)
+    : _ptr(0), _length(length), _stride(1), _writable(true),
+      _handle(), _unmaskedLength(0)
+{
+    if (length < 0)
+    {
+        throw std::invalid_argument("Fixed array length must be non-negative");
+    }
+
+    boost::shared_array<std::vector<T> > a(new std::vector<T>[length]);
+ // Initial vectors in the array will be zero-length.
+    _handle = a;
+    _ptr = a.get();
+}
+
+template <class T>
+FixedVArray<T>::FixedVArray(const T& initialValue, Py_ssize_t length)
+    : _ptr(0), _length(length), _stride(1), _writable(true),
+      _handle(), _unmaskedLength(0)
+{
+    if (length < 0)
+    {
+        throw std::invalid_argument("Fixed array length must be non-negative");
+    }
+
+    boost::shared_array<std::vector<T> > a(new std::vector<T>[length]);
+    for (Py_ssize_t i = 0; i < length; ++i)
+    {
+        a[i].push_back (initialValue);
+    }
+    _handle = a;
+    _ptr = a.get();
+}
+
+template <class T>
+FixedVArray<T>::FixedVArray(FixedVArray<T>& other, const FixedArray<int>& mask)
+    : _ptr(other._ptr), _stride(other._stride), _writable(other._writable),
+      _handle(other._handle)
+{
+    if (other.isMaskedReference())
+    {
+      throw std::invalid_argument
+            ("Masking an already-masked FixedVArray is not supported yet (SQ27000)");
+    }
+
+    size_t len = (size_t) other.match_dimension (mask);
+    _unmaskedLength = len;
+
+    size_t reduced_len = 0;
+    for (size_t i = 0; i < len; ++i)
+    {
+        if (mask[i])
+        {
+            reduced_len++;
+        }
+    }
+
+    _indices.reset (new size_t[reduced_len]);
+
+    for (size_t i = 0, j = 0; i < len; ++i)
+    {
+        if (mask[i])
+        {
+            _indices[j] = i; // NOSONAR - suppress SonarCloud warning.
+            j++;
+        }
+    }
+
+    _length = reduced_len;
+}
+
+template <class T>
+FixedVArray<T>::FixedVArray(const FixedArray<int>& size, const T& initialValue)
+    : _ptr(nullptr), _length (size.len()), _stride(1),
+      _writable(true), _handle(), _indices(), _unmaskedLength(0)
+{
+    boost::shared_array<std::vector<T> > a(new std::vector<T>[_length]);
+    for (size_t i = 0; i < _length; ++i)
+    {
+        if (size[i] < 0)
+            throw std::invalid_argument("Attempt to create negative FixedVArray element");
+
+        std::vector<T> &v = a[i];
+
+        v.resize (size[i]);
+        std::fill (v.begin(), v.end(), initialValue);
+    }
+    _handle = a;
+    _ptr = a.get();
+}
+
+template <class T>
+FixedVArray<T>::FixedVArray(const FixedVArray<T>& other)
+    : _ptr(other._ptr),
+      _length(other._length),
+      _stride(other._stride),
+      _writable (other._writable),
+      _handle(other._handle),
+      _indices(other._indices),
+      _unmaskedLength(other._unmaskedLength)
+{
+    // Nothing.
+}
+
+template <class T>
+const FixedVArray<T> &
+FixedVArray<T>::operator = (const FixedVArray<T>& other)
+{
+    if (&other == this)
+        return *this;
+
+    _ptr            = other._ptr;
+    _length         = other._length;
+    _stride         = other._stride;
+    _writable       = other._writable;
+    _handle         = other._handle;
+    _unmaskedLength = other._unmaskedLength;
+    _indices        = other._indices;
+
+    return *this;
+}
+
+template <class T>
+FixedVArray<T>::~FixedVArray()
+{
+    // Nothing.
+}
+
+
+template <class T>
+std::vector<T>&
+FixedVArray<T>::operator [] (size_t i)
+{
+    if (!_writable)
+        throw std::invalid_argument("Fixed V-array is read-only.");
+
+    return _ptr[(_indices ? raw_ptr_index(i) : i) * _stride];
+}
+
+template <class T>
+const std::vector<T>&
+FixedVArray<T>::operator [] (size_t i) const
+{
+    return _ptr[(_indices ? raw_ptr_index(i) : i) * _stride];
+}
+
+
+namespace {
+
+//
+// Make an index suitable for indexing into an array in c++
+// from a python index, which can be negative for indexing 
+// relative to the end of an array.
+//
+size_t
+canonical_index (Py_ssize_t index, const size_t& totalLength)
+{
+    if (index < 0)
+    {
+        index += totalLength;
+    }
+    if ((size_t) index >= totalLength || index < 0)
+    {
+        PyErr_SetString (PyExc_IndexError, "Index out of range");
+        boost::python::throw_error_already_set();
+    }
+    return index;  // still a 'virtual' index if this is a masked reference array
+}
+
+void
+extract_slice_indices (PyObject* index, size_t& start, size_t& end,
+                       Py_ssize_t& step, size_t& sliceLength,
+                       const size_t& totalLength)
+{
+    if (PySlice_Check (index))
+    {
+#if PY_MAJOR_VERSION > 2
+        PyObject* slice = index;
+#else
+        PySliceObject* slice = reinterpret_cast<PySliceObject *>(index);
+#endif
+        Py_ssize_t s, e, sl;
+        if (PySlice_GetIndicesEx(slice, totalLength, &s, &e, &step, &sl) == -1)
+        {
+            boost::python::throw_error_already_set();
+        }
+        if (s < 0 || e < -1 || sl < 0)
+        {
+            throw std::domain_error
+                  ("Slice extraction produced invalid start, end, or length indices");
+        }
+
+        start = s;
+        end   = e;
+        sliceLength = sl;
+    }
+    else if (PyInt_Check (index))
+    {
+        size_t i = canonical_index (PyInt_AsSsize_t(index), totalLength);
+        start = i;
+        end   = i + 1;
+        step  = 1;
+        sliceLength = 1;
+    }
+    else
+    {
+        PyErr_SetString (PyExc_TypeError, "Object is not a slice");
+        boost::python::throw_error_already_set();
+    }
+}
+
+} // namespace
+
+
+// this must have a call policy of return_internal_reference
+template <class T>
+FixedArray<T>
+FixedVArray<T>::getitem (Py_ssize_t index)
+{
+    const size_t i = canonical_index (index, _length);
+    std::vector<T>& data = _ptr[(_indices ? raw_ptr_index(i) : i) * _stride];
+    return FixedArray<T>(data.empty() ? nullptr : &data[0], data.size(), 1, _writable);
+}
+
+template <class T>
+FixedVArray<T>
+FixedVArray<T>::getslice (PyObject* index) const
+{
+    size_t start       = 0;
+    size_t end         = 0;
+    size_t sliceLength = 0;
+    Py_ssize_t step;
+    extract_slice_indices (index, start, end, step, sliceLength, _length);
+
+    FixedVArray<T> f(sliceLength);
+
+    if (_indices)
+    {
+        for (size_t i = 0; i < sliceLength; ++i)
+        {
+            f._ptr[i] = _ptr[raw_ptr_index(start + i*step)*_stride];
+        }
+    }
+    else
+    {
+        for (size_t i = 0; i < sliceLength; ++i)
+        {
+            f._ptr[i] = _ptr[(start + i*step)*_stride];
+        }
+    }
+
+    return f;
+}
+
+template <class T>
+FixedVArray<T>
+FixedVArray<T>::getslice_mask (const FixedArray<int>& mask)
+{
+    return FixedVArray<T> (*this, mask);
+}
+
+template <class T>
+void
+FixedVArray<T>::setitem_scalar (PyObject* index, const FixedArray<T>& data)
+{
+    if (!_writable)
+        throw std::invalid_argument ("Fixed V-array is read-only.");
+
+    size_t start       = 0;
+    size_t end         = 0;
+    size_t sliceLength = 0;
+    Py_ssize_t step;
+    extract_slice_indices (index, start, end, step, sliceLength, _length);
+
+    if (_indices)
+    {
+        for (size_t i = 0; i < sliceLength; ++i)
+        {
+            std::vector<T> &d =_ptr[raw_ptr_index(start + i*step)*_stride];
+            if (data.len() != static_cast<Py_ssize_t>(d.size()))
+                throw std::invalid_argument("FixedVArray::setitem: length of data does not match length of array element");
+
+            if (data.isMaskedReference())
+            {
+                for (Py_ssize_t j = 0; j < data.len(); ++j)
+                {
+                    d[j] = data[j];
+                }
+            }
+            else
+            {
+                for (Py_ssize_t j = 0; j < data.len(); ++j)
+                {
+                    d[j] = data.direct_index(j);
+                }
+            }
+        }
+    }
+    else
+    {
+        for (size_t i = 0; i < sliceLength; ++i)
+        {
+            std::vector<T> &d =_ptr[(start + i*step)*_stride];
+            if (data.len() != static_cast<Py_ssize_t>(d.size()))
+                throw std::invalid_argument("FixedVArray::setitem: length of data does not match length of array element");
+
+            if (data.isMaskedReference())
+            {
+                for (Py_ssize_t j = 0; j < data.len(); ++j)
+                {
+                    d[j] = data[j];
+                }
+            }
+            else
+            {
+                for (Py_ssize_t j = 0; j < data.len(); ++j)
+                {
+                    d[j] = data.direct_index(j);
+                }
+            }
+        }
+    } 
+}
+
+template <class T>
+void
+FixedVArray<T>::setitem_scalar_mask (const FixedArray<int>& mask, const FixedArray<T>& data)
+{
+    if (!_writable)
+        throw std::invalid_argument ("Fixed V-array is read-only.");
+
+    size_t len = match_dimension(mask, false);
+
+    if (_indices)
+    {
+        for (size_t i = 0; i < len; ++i)
+        {
+            // We don't need to actually look at 'mask' because
+            // match_dimensions has already forced some expected condition.
+            std::vector<T> &d =_ptr[raw_ptr_index(i)*_stride];
+            if (data.len() != static_cast<Py_ssize_t>(d.size()))
+                throw std::invalid_argument("FixedVArray::setitem: length of data does not match length of array element");
+
+            if (data.isMaskedReference())
+            {
+                for (Py_ssize_t j = 0; j < data.len(); ++j)
+                {
+                    d[j] = data[j];
+                }
+            }
+            else
+            {
+                for (Py_ssize_t j = 0; j < data.len(); ++j)
+                {
+                    d[j] = data.direct_index(j);
+                }
+            }
+        }
+    }
+    else
+    {
+        for (size_t i = 0; i < len; ++i)
+        {
+            if (mask[i])
+            {
+                std::vector<T> &d = _ptr[i*_stride];
+                if (data.len() != static_cast<Py_ssize_t>(d.size()))
+                    throw std::invalid_argument("FixedVArray::setitem: length of data does not match length of array element");
+
+                if (data.isMaskedReference())
+                {
+                    for (Py_ssize_t j = 0; j < data.len(); ++j)
+                    {
+                        d[j] = data[j];
+                    }
+                }
+                else
+                {
+                    for (Py_ssize_t j = 0; j < data.len(); ++j)
+                    {
+                        d[j] = data.direct_index(j);
+                    }
+                }
+            }
+        }
+    }
+}
+template <class T>
+void
+FixedVArray<T>::setitem_vector (PyObject* index, const FixedVArray<T>& data)
+{
+    if (!_writable)
+        throw std::invalid_argument ("Fixed V-array is read-only.");
+
+    size_t start       = 0;
+    size_t end         = 0;
+    size_t sliceLength = 0;
+    Py_ssize_t step;
+    extract_slice_indices (index, start, end, step, sliceLength, _length);
+
+    if ((size_t) data.len() != sliceLength)
+    {
+        PyErr_SetString (PyExc_IndexError,
+                         "Dimensions of source do not match destination");
+        boost::python::throw_error_already_set();
+    }
+
+    if (_indices)
+    {
+        for (size_t i = 0; i < sliceLength; ++i)
+        {
+            _ptr[raw_ptr_index(start + i*step)*_stride] = data[i];
+        }
+    }
+    else
+    {
+        for (size_t i = 0; i < sliceLength; ++i)
+        {
+            _ptr[(start + i*step)*_stride] = data[i];
+        }
+    }
+}
+
+template <class T>
+void
+FixedVArray<T>::setitem_vector_mask (const FixedArray<int>& mask,
+                                     const FixedVArray<T>&  data)
+{
+    if (!_writable)
+        throw std::invalid_argument ("Fixed V-array is read-only.");
+
+    // This restriction could be removed if there is a compelling use-case.
+    if (_indices)
+    {
+        throw std::invalid_argument
+            ("We don't support setting item masks for masked reference arrays");
+    }
+
+    size_t len = match_dimension(mask);
+
+    if ((size_t) data.len() == len)
+    {
+        for (size_t i = 0; i < len; ++i)
+        {
+            if (mask[i])
+            {
+                _ptr[i*_stride] = data[i];
+            }
+        }
+    }
+    else
+    {
+        size_t count = 0;
+        for (size_t i = 0; i < len; ++i)
+        {
+            if (mask[i])
+            {
+                count++;
+            }
+        }
+        if ((size_t) data.len() != count)
+        {
+            throw std::invalid_argument
+                ("Dimensions of source data do not match destination "
+                 "either masked or unmasked");
+        }
+
+        Py_ssize_t dataIndex = 0;
+        for (size_t i = 0; i < len; ++i)
+        {
+            if (mask[i])
+            {
+                _ptr[i*_stride] = data[dataIndex];
+                dataIndex++;
+            }
+        }
+    }
+}
+
+
+template <class T>
+int
+FixedVArray<T>::SizeHelper::getitem (Py_ssize_t index) const
+{
+    size_t i = canonical_index(index, _a._length);
+
+    if (_a._indices)
+    {
+        return _a._ptr[_a.raw_ptr_index(i)*_a._stride].size();
+    }
+
+    return _a._ptr[i*_a._stride].size();
+}
+
+template <class T>
+FixedArray<int>
+FixedVArray<T>::SizeHelper::getitem_slice (PyObject* index) const
+{
+    size_t start       = 0;
+    size_t end         = 0;
+    size_t sliceLength = 0;
+    Py_ssize_t step;
+    extract_slice_indices (index, start, end, step, sliceLength, _a._length);
+
+    FixedArray<int> f(sliceLength);
+
+    if (_a._indices)
+    {
+        for (size_t i = 0; i < sliceLength; ++i)
+        {
+            f.direct_index(i) = _a._ptr[_a.raw_ptr_index(start + i*step)*_a._stride].size();
+        }
+    }
+    else
+    {
+        for (size_t i = 0; i < sliceLength; ++i)
+        {
+            f.direct_index(i) = _a._ptr[(start + i*step)*_a._stride].size();
+        }
+    }
+
+    return f;
+}
+
+template <class T>
+FixedArray<int>
+FixedVArray<T>::SizeHelper::getitem_mask (const FixedArray<int>& mask) const
+{
+    int len = mask.len();
+    if (len != _a.len())
+    {
+        throw std::invalid_argument("Dimensions of mask do not match array");
+    }
+    
+    int count = 0;
+    for (Py_ssize_t i = 0; i < mask.len(); ++i)
+    {
+        if (mask[i]) count += 1;
+    }
+
+    FixedArray<int> f(count);
+    
+    if (_a._indices)
+    {
+        size_t index = 0;
+        for (Py_ssize_t i = 0; i < mask.len(); ++i)
+        {
+            if (mask[i])
+            {
+                f.direct_index(index) = _a._ptr[_a.raw_ptr_index(i)*_a._stride].size();
+                index += 1;
+            }
+        }
+    }
+    else
+    {
+        size_t index = 0;
+        for (Py_ssize_t i = 0; i < mask.len(); ++i)
+        {
+            if (mask[i])
+            {
+                f.direct_index(index) = _a._ptr[i*_a._stride].size();
+                index += 1;
+            }
+        }
+    }
+
+    return f;
+}
+
+
+template <class T>
+void
+FixedVArray<T>::SizeHelper::setitem_scalar (PyObject* index, size_t size)
+{
+    if (!_a.writable())
+        throw std::invalid_argument ("Fixed V-array is read-only.");
+
+    size_t start       = 0;
+    size_t end         = 0;
+    size_t sliceLength = 0;
+    Py_ssize_t step;
+    extract_slice_indices (index, start, end, step, sliceLength, _a._length);
+
+    if (_a._indices)
+    {
+        for (size_t i = 0; i < sliceLength; ++i)
+        {
+            _a._ptr[_a.raw_ptr_index(start + i*step)*_a._stride].resize(size);
+        }
+    }
+    else
+    {
+        for (size_t i = 0; i < sliceLength; ++i)
+        {
+            _a._ptr[(start + i*step)*_a._stride].resize(size);
+        }
+    }
+}
+
+template <class T>
+void
+FixedVArray<T>::SizeHelper::setitem_scalar_mask (const FixedArray<int>& mask, size_t size)
+{
+    if (!_a.writable())
+        throw std::invalid_argument ("Fixed V-array is read-only.");
+
+    size_t len = _a.match_dimension(mask, false);
+
+    if (_a._indices)
+    {
+        for (size_t i = 0; i < len; ++i)
+        {
+            // We don't need to actually look at 'mask' because
+            // match_dimensions has already forced some expected condition.
+            _a._ptr[_a.raw_ptr_index(i)*_a._stride].resize(size);
+        }
+    }
+    else
+    {
+        for (size_t i = 0; i < len; ++i)
+        {
+            if (mask[i])
+            {
+                _a._ptr[i*_a._stride].resize(size);
+            }
+        }
+    }
+}
+
+template <class T>
+void
+FixedVArray<T>::SizeHelper::setitem_vector(PyObject *index, const FixedArray<int> &size)
+{
+    if (!_a.writable())
+        throw std::invalid_argument ("Fixed V-array is read-only.");
+
+    size_t start=0, end=0, slicelength=0;
+    Py_ssize_t step;
+    extract_slice_indices(index,start,end,step,slicelength,_a._length);
+        
+    // we have a valid range of indices
+    if (size.len() != static_cast<Py_ssize_t>(slicelength)) {
+        PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
+        boost::python::throw_error_already_set();
+    }
+
+    if (_a._indices)
+    {
+        for (size_t i=0; i<slicelength; ++i)
+            _a._ptr[_a.raw_ptr_index(start+i*step)*_a._stride].resize(size[i]);
+    }
+    else
+    {
+        for (size_t i=0; i<slicelength; ++i)
+            _a._ptr[(start+i*step)*_a._stride].resize(size[i]);
+    }
+}
+
+template <class T>
+void
+FixedVArray<T>::SizeHelper::setitem_vector_mask(const FixedArray<int> &mask, const FixedArray<int> &size)
+{
+    if (!_a.writable())
+        throw std::invalid_argument ("Fixed V-array is read-only.");
+
+    // We could relax this but this restriction if there's a good
+    // enough reason too.
+
+    if (_a._indices)
+    {
+        throw std::invalid_argument("We don't support setting item masks for masked reference arrays.");
+    }
+
+    Py_ssize_t len = _a.match_dimension(mask);
+    if (size.len() == len)
+    {
+        for (Py_ssize_t i = 0; i < len; ++i)
+            if (mask[i]) _a._ptr[i*_a._stride].resize(size[i]);
+    }
+    else
+    {
+        Py_ssize_t count = 0;
+        for (Py_ssize_t i = 0; i < len; ++i)
+            if (mask[i]) count++;
+
+        if (size.len() != count) {
+            throw std::invalid_argument("Dimensions of source data do not match destination either masked or unmasked");
+        }
+
+        Py_ssize_t sizeIndex = 0;
+        for (Py_ssize_t i = 0; i < len; ++i)
+        {
+            if (mask[i])
+            {
+                _a._ptr[i*_a._stride].resize(size[sizeIndex]);
+                sizeIndex++;
+            }
+        }
+    }
+}
+
+template <class T>
+size_t
+FixedVArray<T>::raw_ptr_index (size_t i) const
+{
+    assert (isMaskedReference());
+    assert (i < _length);
+    assert (_indices[i] >= 0 && _indices[i] < _unmaskedLength);
+
+    return _indices[i];
+}
+
+
+template <class T>
+boost::shared_ptr<typename FixedVArray<T>::SizeHelper>
+FixedVArray<T>::getSizeHelper()
+{
+    return boost::shared_ptr<SizeHelper>(new typename FixedVArray<T>::SizeHelper (*this));
+}
+
+// static
+template <class T>
+boost::python::class_<FixedVArray<T> >
+FixedVArray<T>::register_(const char* doc)
+{
+    boost::python::class_<FixedVArray<T> > fixedVArray_class (name(), doc,
+        boost::python::init<Py_ssize_t>("Construct a variable array of the "
+        "specified length initialized to the default value for the given type"));
+
+    fixedVArray_class
+        .def(boost::python::init<const FixedVArray<T> &>("Construct a variable array with the same values as the given array"))
+        .def(boost::python::init<const T &, Py_ssize_t>("Construct a variable array of the specified length initialized to the specified default value"))
+        .def(boost::python::init<const FixedArray<int> &, const T &>("Construct a variable array with each array size equal to the specified elements and initialized to the specified default value"))
+        .def("__getitem__", &FixedVArray<T>::getslice)
+        .def("__getitem__", &FixedVArray<T>::getslice_mask)
+        .def("__getitem__", &FixedVArray<T>::getitem, boost::python::with_custodian_and_ward_postcall<1,0>())
+
+        .def("__setitem__", &FixedVArray<T>::setitem_scalar)
+        .def("__setitem__", &FixedVArray<T>::setitem_scalar_mask)
+        .def("__setitem__", &FixedVArray<T>::setitem_vector)
+        .def("__setitem__", &FixedVArray<T>::setitem_vector_mask)
+
+        .def("__len__",     &FixedVArray<T>::len)
+        .def("writable",    &FixedVArray<T>::writable)
+        .def("makeReadOnly",&FixedVArray<T>::makeReadOnly)
+        
+        .add_property("size", boost::python::make_function(&FixedVArray<T>::getSizeHelper, boost::python::with_custodian_and_ward_postcall<0,1>()))
+        ;
+
+    {
+        boost::python::scope s(fixedVArray_class);
+
+        boost::python::class_<typename FixedVArray<T>::SizeHelper,boost::noncopyable> sizeHelper_class ("SizeHelper", boost::python::no_init);
+        sizeHelper_class
+            .def("__getitem__", &FixedVArray<T>::SizeHelper::getitem)
+            .def("__getitem__", &FixedVArray<T>::SizeHelper::getitem_mask)
+            .def("__getitem__", &FixedVArray<T>::SizeHelper::getitem_slice)
+
+            .def("__setitem__", &FixedVArray<T>::SizeHelper::setitem_scalar)
+            .def("__setitem__", &FixedVArray<T>::SizeHelper::setitem_scalar_mask)
+            .def("__setitem__", &FixedVArray<T>::SizeHelper::setitem_vector)
+            .def("__setitem__", &FixedVArray<T>::SizeHelper::setitem_vector_mask)
+            ;
+    }
+
+    boost::python::register_ptr_to_python<boost::shared_ptr<typename FixedVArray<T>::SizeHelper> >();
+
+    return fixedVArray_class;
+}
+
+
+// ---- Explicit Class Instantiation ---------------------------------
+
+template class PYIMATH_EXPORT FixedVArray<int>;
+template class PYIMATH_EXPORT FixedVArray<float>;
+template class PYIMATH_EXPORT FixedVArray<Imath::Vec2<int> >;
+template class PYIMATH_EXPORT FixedVArray<Imath::Vec2<float> >;
+
+} // namespace PyImath
diff --git a/src/python/PyImath/PyImathFixedVArray.h b/src/python/PyImath/PyImathFixedVArray.h
new file mode 100644 (file)
index 0000000..8b7ebc4
--- /dev/null
@@ -0,0 +1,203 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathFixedVArray_h_
+#define _PyImathFixedVArray_h_
+
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/any.hpp>
+#include <vector>
+#include "PyImathFixedArray.h"
+
+namespace PyImath {
+
+template <class T>
+class FixedVArray
+{
+    // This class (at least for now) holds a std::vector of 'T' types.
+    // This will give us the 'variable' part of the array.  Generally,
+    // we will initially support only a very small subset of accessor
+    // methods before the semantics are fully defined.  Currently, the
+    // VArray semantics are defined in the 'varraySemantics.txt' file.
+
+    std::vector<T> *  _ptr;
+    size_t            _length;
+    size_t            _stride;
+    bool              _writable;
+
+    // This handle optionally stores a shared_array to allocated array data
+    // so that everything is freed properly on exit.
+    boost::any        _handle;
+
+    boost::shared_array<size_t>  _indices;  // non-NULL if we're a masked reference
+    size_t                       _unmaskedLength;
+
+  public:
+    typedef T  BaseType;
+
+    FixedVArray (std::vector<T>* ptr, Py_ssize_t length,
+                 Py_ssize_t stride = 1, bool writable = true);
+
+    FixedVArray (std::vector<T>* ptr, Py_ssize_t length,
+                 Py_ssize_t stride, boost::any handle, bool writable = true);
+
+    FixedVArray (const std::vector<T>* ptr, Py_ssize_t length,
+                 Py_ssize_t stride = 1);
+
+    FixedVArray (const std::vector<T>* ptr, Py_ssize_t length,
+                 Py_ssize_t stride, boost::any handle);
+
+    explicit FixedVArray (Py_ssize_t length);
+
+    FixedVArray (const T& initialValue, Py_ssize_t length);
+
+    FixedVArray (FixedVArray<T>& f, const FixedArray<int>& mask);
+
+    FixedVArray (const FixedArray<int>& size, const T& initialValue);
+
+    FixedVArray (const FixedVArray<T>& other);
+
+    const FixedVArray&  operator = (const FixedVArray<T>& other);
+
+   ~FixedVArray();
+
+    // ----------------
+
+    const boost::any&  handle() { return _handle; }
+
+    Py_ssize_t  len()      const { return _length;   }
+    size_t      stride()   const { return _stride;   }
+    bool        writable() const { return _writable; }
+
+    // This method is mainly here for use in confidence tests, but there may
+    // be other use-cases where a writable array needs to be made read-only.
+    // Note that we do not provide a 'makeWritable' method here, because that
+    // type of operation shouldn't be allowed.
+    void        makeReadOnly() { _writable = false; }
+
+    bool        isMaskedReference() const { return _indices.get() != 0; }
+    size_t      unmaskedLength()    const { return _unmaskedLength; }
+
+    std::vector<T>&        operator [] (size_t i);
+    const std::vector<T>&  operator [] (size_t i) const;
+
+    // ----------------
+
+    FixedArray<T>   getitem (Py_ssize_t index);
+    FixedVArray<T>  getslice (PyObject* index) const;
+    FixedVArray<T>  getslice_mask (const FixedArray<int>& mask);
+
+    void            setitem_scalar (PyObject* index, const FixedArray<T>& data);
+    void            setitem_scalar_mask (const FixedArray<int>& mask, const FixedArray<T>& data);
+    void            setitem_vector (PyObject* index, const FixedVArray<T>& data);
+    void            setitem_vector_mask (const FixedArray<int>& mask, const FixedVArray<T>& data);
+
+    struct SizeHelper
+    {
+        SizeHelper(FixedVArray &a) : _a(a) {}
+
+        int             getitem(Py_ssize_t index) const;
+        FixedArray<int> getitem_slice(PyObject* index) const;
+        FixedArray<int> getitem_mask(const FixedArray<int>& mask) const;
+
+        void            setitem_scalar (PyObject* index, size_t size);
+        void            setitem_scalar_mask (const FixedArray<int>& mask, size_t size);
+        void            setitem_vector (PyObject* index, const FixedArray<int>& size);
+        void            setitem_vector_mask (const FixedArray<int>& mask, const FixedArray<int>& size);
+
+      private:
+
+        FixedVArray &_a;
+    };
+
+    boost::shared_ptr<SizeHelper> getSizeHelper();
+
+    friend struct SizeHelper;
+
+    // ----------------
+
+    static boost::python::class_<FixedVArray<T> > register_(const char* doc);
+
+    // Instantiations of fixed variable arrays must implement this static member.
+    static const char* name();
+
+    template <class T2>
+    size_t  match_dimension (const FixedArray<T2>& mask,
+                             bool strictComparison = true) const
+    {
+        if (len() == mask.len())
+        {
+            return len();
+        }
+
+        bool throwExc = false;
+        if (strictComparison)
+        {
+            throwExc = true;
+        }
+        else if (_indices)
+        {
+            if (_unmaskedLength != (size_t) mask.len())
+            {
+                throwExc = true;
+            }
+        }
+        else
+        {
+            throwExc = true;
+        }
+
+        if (throwExc)
+        {
+          throw std::invalid_argument("Dimensions of source do not match destination");
+        }
+
+        return len();
+    }
+
+    size_t  match_dimension (const FixedVArray<T>& other,
+                             bool strictComparison = true) const
+    {
+        if (len() == other.len())
+        {
+            return len();
+        }
+
+        bool throwExc = false;
+        if (strictComparison)
+        {
+            throwExc = true;
+        }
+        else if (_indices)
+        {
+            if (_unmaskedLength != (size_t) other.len())
+            {
+                throwExc = true;
+            }
+        }
+        else
+        {
+            throwExc = true;
+        }
+
+        if (throwExc)
+        {
+          throw std::invalid_argument("Dimensions of source do not match destination");
+        }
+
+        return len();
+    }
+
+  protected:
+    size_t  raw_ptr_index (size_t i) const;
+
+};
+
+} // namespace PyImath
+
+#endif // _PyImathFixedVArray_h_
diff --git a/src/python/PyImath/PyImathFrustum.cpp b/src/python/PyImath/PyImathFrustum.cpp
new file mode 100644 (file)
index 0000000..adec117
--- /dev/null
@@ -0,0 +1,494 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/format.hpp>
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathVec.h"
+#include "PyImathFrustum.h"
+#include "PyImathDecorators.h"
+#include "PyImathExport.h"
+
+namespace PyImath{
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct FrustumName {static const char *value;};
+template <> const char *FrustumName<float>::value = "Frustumf";
+template <> const char *FrustumName<double>::value = "Frustumd";
+
+template <class T> struct FrustumTestName {static const char *value;};
+template <> const char *FrustumTestName<float>::value = "FrustumTestf";
+template <> const char *FrustumTestName<double>::value = "FrustumTestd";
+
+
+template <class T>
+static std::string Frustum_repr(const Frustum<T> &f)
+{
+    std::stringstream stream;
+    stream << FrustumName<T>::value << "(" << f.nearPlane() << ", " << f.farPlane() << ", "
+           << f.left() << ", " << f.right() << ", " << f.top() << ", "
+           << f.bottom() << ", " << f.orthographic() << ")";    
+    return stream.str();
+}
+
+template <class T>
+static void
+modifyNearAndFar(Frustum<T> &f, T nearPlane, T farPlane)
+{
+    MATH_EXC_ON;
+    f.modifyNearAndFar (nearPlane, farPlane);
+}
+
+template <class T>
+static T
+fovx(Frustum<T> &f)
+{
+    MATH_EXC_ON;
+    return f.fovx();
+}
+
+template <class T>
+static T
+fovy(Frustum<T> &f)
+{
+    MATH_EXC_ON;
+    return f.fovy();
+}
+
+template <class T>
+static T
+aspect(Frustum<T> &f)
+{
+    MATH_EXC_ON;
+    return f.aspect();
+}
+
+template <class T>
+static Matrix44<T>
+projectionMatrix(Frustum<T> &f)
+{
+    MATH_EXC_ON;
+    return f.projectionMatrix();
+}
+
+template <class T>
+static Frustum<T>
+window (Frustum<T> &f, T l, T r, T b, T t)
+{
+    MATH_EXC_ON;
+    return f.window(l, r, b, t);
+}
+
+template <class T>
+static Line3<T>
+projectScreenToRay (Frustum<T> &f, const Vec2<T> &p)
+{
+    MATH_EXC_ON;
+    return f.projectScreenToRay(p);
+}
+
+template <class T>
+static Line3<T>
+projectScreenToRayTuple(Frustum<T> &f, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 2)
+    {
+        Vec2<T> point;
+        point.x = extract<T>(t[0]);
+        point.y = extract<T>(t[1]);
+        return f.projectScreenToRay(point);
+    }
+    else
+        throw std::invalid_argument ( "projectScreenToRay expects tuple of length 2");
+    
+}
+
+template <class T>
+static Vec2<T>
+projectPointToScreen (Frustum<T> &f, const Vec3<T> &p)
+{
+    MATH_EXC_ON;
+    return f.projectPointToScreen(p);
+}
+
+template <class T>
+static Vec2<T>
+projectPointToScreenTuple(Frustum<T> &f, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> point;
+        point.x = extract<T>(t[0]);
+        point.y = extract<T>(t[1]);
+        point.z = extract<T>(t[2]);
+        return f.projectPointToScreen(point);
+    }
+    else
+        throw std::invalid_argument ( "projectPointToScreen expects tuple of length 3");
+    
+}
+
+template <class T>
+static Vec2<T>
+projectPointToScreenObj(Frustum<T> &f, const object &o)
+{
+    MATH_EXC_ON;
+    Vec3<T> v;
+    if (PyImath::V3<T>::convert (o.ptr(), &v))
+        return f.projectPointToScreen(v);
+    else
+        throw std::invalid_argument ( "projectPointToScreen expects tuple of length 3");
+}
+
+template <class T>
+static T
+ZToDepth(Frustum<T> &f, long z, long min, long max)
+{
+    MATH_EXC_ON;
+    return f.ZToDepth(z, min, max);
+}
+
+template <class T>
+static T
+normalizedZToDepth(Frustum<T> &f, T z)
+{
+    MATH_EXC_ON;
+    return f.normalizedZToDepth(z);
+}
+
+template <class T>
+static long
+DepthToZ(Frustum<T> &f, T depth, long min, long max)
+{
+    MATH_EXC_ON;
+    return f.DepthToZ(depth, min, max);
+}
+
+template <class T>
+static T
+worldRadius(Frustum<T> &f, const Vec3<T> &p, T radius)
+{
+    MATH_EXC_ON;
+    return f.worldRadius(p, radius);
+}
+
+template <class T>
+static T
+worldRadiusTuple(Frustum<T> &f, const tuple &t, T radius)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> point;
+        point.x = extract<T>(t[0]);
+        point.y = extract<T>(t[1]);
+        point.z = extract<T>(t[2]);
+        return f.worldRadius(point, radius);
+    }
+    else
+        throw std::invalid_argument ( "worldRadius expects tuple of length 3");
+}
+
+template <class T>
+static T
+screenRadius(Frustum<T> &f, const Vec3<T> &p, T radius)
+{
+    MATH_EXC_ON;
+    return f.screenRadius(p, radius);
+}
+
+template <class T>
+static T
+screenRadiusTuple(Frustum<T> &f, const tuple &t, T radius)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> point;
+        point.x = extract<T>(t[0]);
+        point.y = extract<T>(t[1]);
+        point.z = extract<T>(t[2]);
+        return f.screenRadius(point, radius);
+    }
+    else
+      throw std::invalid_argument ("screenRadius expects tuple of length 3");
+}
+
+template <class T>
+static void
+planes1(Frustum<T> &f, Plane3<T> *p)
+{
+    MATH_EXC_ON;
+    f.planes(p);
+}
+
+template <class T>
+static void
+planes2(Frustum<T> &f, Plane3<T> *p, const Matrix44<T> &m)
+{
+    MATH_EXC_ON;
+    f.planes(p, m);
+}
+
+template <class T>
+static tuple
+planes3(Frustum<T> &f, const Matrix44<T> &mat)
+{
+    MATH_EXC_ON;
+    IMATH_NAMESPACE::Plane3<T> p[6];
+    f.planes(p,mat);
+    
+    tuple t = make_tuple(p[0],p[1],p[2],p[3],p[4],p[5]);
+    
+    return t;
+}
+
+template <class T>
+static tuple
+planes4(Frustum<T> &f)
+{
+    MATH_EXC_ON;
+    IMATH_NAMESPACE::Plane3<T> p[6];
+    f.planes(p);
+    
+    tuple t = make_tuple(p[0],p[1],p[2],p[3],p[4],p[5]);
+    
+    return t;
+}
+
+template <class T>
+class_<Frustum<T> >
+register_Frustum()
+{
+    void (IMATH_NAMESPACE::Frustum<T>::*set1)(T,T,T,T,T,T,bool) = &IMATH_NAMESPACE::Frustum<T>::set;
+    void (IMATH_NAMESPACE::Frustum<T>::*set2)(T,T,T,T,T)        = &IMATH_NAMESPACE::Frustum<T>::set;
+    const char *name = FrustumName<T>::value;
+    
+    class_< Frustum<T> > frustum_class(name,name,init<Frustum<T> >("copy construction"));
+    frustum_class
+        .def(init<>("Frustum() default construction"))
+        .def(init<T,T,T,T,T,T,bool>("Frustum(nearPlane,farPlane,left,right,top,bottom,ortho) construction"))
+        .def(init<T,T,T,T,T>("Frustum(nearPlane,farPlane,fovx,fovy,aspect) construction"))
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__repr__",&Frustum_repr<T>)
+        .def("set", set1,
+                "F.set(nearPlane, farPlane, left, right, top, bottom, "
+                        "[ortho])\n"
+                        "F.set(nearPlane, farPlane, fovx, fovy, aspect)       "
+                        "         -- sets the entire state of "
+                        "frustum F as specified.  Only one of "
+                        "fovx or fovy may be non-zero.")             
+        .def("set", set2)
+        
+        .def("modifyNearAndFar", &modifyNearAndFar<T>,
+                "F.modifyNearAndFar(nearPlane, farPlane) -- modifies "
+                        "the already-valid frustum F as specified")
+             
+        .def("setOrthographic", &Frustum<T>::setOrthographic,
+                "F.setOrthographic(b) -- modifies the "
+                        "already-valid frustum F to be orthographic "
+                        "or not")
+             
+        .def("nearPlane", &Frustum<T>::nearPlane,
+                "F.nearPlane() -- returns the coordinate of the "
+                        "near clipping plane of frustum F")
+             
+        .def("farPlane", &Frustum<T>::farPlane, 
+                "F.farPlane() -- returns the coordinate of the "
+                        "far clipping plane of frustum F")
+             
+        // The following two functions provide backwards compatibility
+        // with the previous API for this class.
+
+        .def("near", &Frustum<T>::nearPlane,
+                "F.near() -- returns the coordinate of the "
+                        "near clipping plane of frustum F")
+             
+        .def("far", &Frustum<T>::farPlane, 
+                "F.far() -- returns the coordinate of the "
+                        "far clipping plane of frustum F")
+             
+        .def("left", &Frustum<T>::left,
+                "F.left() -- returns the left coordinate of "
+                        "the near clipping window of frustum F")
+             
+        .def("right", &Frustum<T>::right,
+                "F.right() -- returns the right coordinate of "
+                        "the near clipping window of frustum F")
+             
+        .def("top", &Frustum<T>::top,
+                        "F.top() -- returns the top coordinate of "
+                        "the near clipping window of frustum F")
+             
+        .def("bottom", &Frustum<T>::bottom,
+                        "F.bottom() -- returns the bottom coordinate "
+                        "of the near clipping window of frustum F")
+             
+        .def("orthographic", &Frustum<T>::orthographic,
+                "F.orthographic() -- returns whether frustum "
+                        "F is orthographic or not")
+             
+        .def("planes", planes1<T>,
+                        "F.planes([M]) -- returns a sequence of 6 "
+                        "Plane3s, the sides of the frustum F "
+                        "(top, right, bottom, left, nearPlane, farPlane), "
+                        "optionally transformed by the matrix M "
+                        "if specified")
+        .def("planes", planes2<T>)
+        .def("planes", planes3<T>)
+        .def("planes", planes4<T>)
+        
+        .def("fovx", &fovx<T>,
+                "F.fovx() -- derives and returns the "
+                        "x field of view (in radians) for frustum F")
+             
+        .def("fovy", &fovy<T>,
+                "F.fovy() -- derives and returns the "
+                        "y field of view (in radians) for frustum F")
+             
+        .def("aspect", &aspect<T>,
+                "F.aspect() -- derives and returns the "
+                        "aspect ratio for frustum F")
+             
+        .def("projectionMatrix", &projectionMatrix<T>,
+                "F.projectionMatrix() -- derives and returns "
+                        "the projection matrix for frustum F")
+             
+        .def("window", &window<T>,
+                "F.window(l,r,b,t) -- takes a rectangle in "
+                        "the screen space (i.e., -1 <= l <= r <= 1, "
+                        "-1 <= b <= t <= 1) of F and returns a new "
+                        "Frustum whose near clipping-plane window "
+                        "is that rectangle in local space")
+             
+        .def("projectScreenToRay", &projectScreenToRay<T>, 
+                "F.projectScreenToRay(V) -- returns a Line3 "
+                        "through V, a V2 point in screen space")
+             
+        .def("projectScreenToRay", &projectScreenToRayTuple<T>)
+             
+        .def("projectPointToScreen", &projectPointToScreen<T>, 
+                "F.projectPointToScreen(V) -- returns the "
+                        "projection of V3 V into screen space")
+             
+        .def("projectPointToScreen", &projectPointToScreenTuple<T>)
+
+        .def("projectPointToScreen", &projectPointToScreenObj<T>)
+             
+        .def("ZToDepth", &ZToDepth<T>,
+                "F.ZToDepth(z, zMin, zMax) -- returns the "
+                        "depth (Z in the local space of the "
+                        "frustum F) corresponding to z (a result of "
+                        "transformation by F's projection matrix) "
+                        "after normalizing z to be between zMin "
+                        "and zMax")
+             
+        .def("normalizedZToDepth", &normalizedZToDepth<T>,
+                "F.normalizedZToDepth(z) -- returns the "
+                        "depth (Z in the local space of the "
+                        "frustum F) corresponding to z (a result of "
+                        "transformation by F's projection matrix), "
+                        "which is assumed to have been normalized "
+                        "to [-1, 1]")
+             
+        .def("DepthToZ", &DepthToZ<T>,
+                "F.DepthToZ(depth, zMin, zMax) -- converts "
+                        "depth (Z in the local space of the frustum "
+                        "F) to z (a result of  transformation by F's "
+                        "projection matrix) which is normalized to "
+                        "[zMin, zMax]")
+             
+        .def("worldRadius", &worldRadius<T>,
+                "F.worldRadius(V, r) -- returns the radius "
+                        "in F's local space corresponding to the "
+                        "point V and radius r in screen space")
+             
+        .def("worldRadius", &worldRadiusTuple<T>)
+             
+        .def("screenRadius", &screenRadius<T>,
+                "F.screenRadius(V, r) -- returns the radius "
+                        "in screen space corresponding to "
+                        "the point V and radius r in F's local "
+                        "space")
+             
+        .def("screenRadius", &screenRadiusTuple<T>)
+
+        ;
+
+    decoratecopy(frustum_class);
+
+    return frustum_class;
+}
+
+template <class T,class T2>
+struct IsVisibleTask : public Task
+{
+    const IMATH_NAMESPACE::FrustumTest<T>& frustumTest;
+    const PyImath::FixedArray<T2>& points;
+    PyImath::FixedArray<int>& results;
+
+    IsVisibleTask(const IMATH_NAMESPACE::FrustumTest<T>& ft, const PyImath::FixedArray<T2> &p, PyImath::FixedArray<int> &r)
+        : frustumTest(ft), points(p), results(r) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for(size_t p = start; p < end; ++p)
+            results[p] = frustumTest.isVisible(IMATH_NAMESPACE::Vec3<T>(points[p]));
+    }
+};
+
+template <class T,class T2>
+PyImath::FixedArray<int>
+frustumTest_isVisible(IMATH_NAMESPACE::FrustumTest<T>& ft, const PyImath::FixedArray<T2>& points)
+{
+    size_t numPoints = points.len();
+    PyImath::FixedArray<int> mask(numPoints);
+
+    IsVisibleTask<T,T2> task(ft,points,mask);
+    dispatchTask(task,numPoints);
+    return mask;
+}
+
+template <class T>
+class_<FrustumTest<T> >
+register_FrustumTest()
+{
+    const char *name = FrustumTestName<T>::value;
+    
+    bool (FrustumTest<T>::*isVisibleS)(const Sphere3<T> &) const = &FrustumTest<T>::isVisible;
+    bool (FrustumTest<T>::*isVisibleB)(const Box<Vec3<T> > &) const = &FrustumTest<T>::isVisible;
+    bool (FrustumTest<T>::*isVisibleV)(const Vec3<T> &) const = &FrustumTest<T>::isVisible;
+    bool (FrustumTest<T>::*completelyContainsS)(const Sphere3<T> &) const = &FrustumTest<T>::completelyContains;
+    bool (FrustumTest<T>::*completelyContainsB)(const Box<Vec3<T> > &) const = &FrustumTest<T>::completelyContains;
+
+    class_< FrustumTest<T> > frustumtest_class(name,name,init<const IMATH_NAMESPACE::Frustum<T>&,const IMATH_NAMESPACE::Matrix44<T>&>("create a frustum test object from a frustum and transform"));
+    frustumtest_class
+        .def("isVisible",isVisibleS)
+        .def("isVisible",isVisibleB)
+        .def("isVisible",isVisibleV)
+        .def("isVisible",&frustumTest_isVisible<T,IMATH_NAMESPACE::V3f>)
+        .def("completelyContains",completelyContainsS)
+        .def("completelyContains",completelyContainsB)
+        ;
+
+    decoratecopy(frustumtest_class);
+
+    return frustumtest_class;
+}
+
+template PYIMATH_EXPORT class_<Frustum<float> > register_Frustum<float>();
+template PYIMATH_EXPORT class_<Frustum<double> > register_Frustum<double>();
+template PYIMATH_EXPORT class_<FrustumTest<float> > register_FrustumTest<float>();
+template PYIMATH_EXPORT class_<FrustumTest<double> > register_FrustumTest<double>();
+}
diff --git a/src/python/PyImath/PyImathFrustum.h b/src/python/PyImath/PyImathFrustum.h
new file mode 100644 (file)
index 0000000..68e0764
--- /dev/null
@@ -0,0 +1,79 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathFrustum_h_
+#define _PyImathFrustum_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <ImathFrustum.h>
+#include <ImathFrustumTest.h>
+#include "PyImath.h"
+
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Frustum<T> > register_Frustum();
+template <class T> boost::python::class_<IMATH_NAMESPACE::FrustumTest<T> > register_FrustumTest();
+
+//
+
+// Other code in the Zeno code base assumes the existance of a class with the
+// same name as the Imath class, and with static functions wrap() and
+// convert() to produce a PyImath object from an Imath object and vice-versa,
+// respectively.  The class Boost generates from the Imath class does not
+// have these properties, so we define a companion class here.
+// The template argument, T, is the element type (e.g.,float, double).
+
+template <class T>
+class F {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Frustum<T> &f);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Frustum<T> *f);
+};
+
+template <class T>
+PyObject *
+F<T>::wrap (const IMATH_NAMESPACE::Frustum<T> &f)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Frustum<T> >::type converter;
+    PyObject *p = converter (f);
+    return p;
+}
+
+template <class T>
+int
+F<T>::convert (PyObject *p, IMATH_NAMESPACE::Frustum<T> *f)
+{
+    boost::python::extract <IMATH_NAMESPACE::Frustumf> extractorEf (p);
+    if (extractorEf.check())
+    {
+        IMATH_NAMESPACE::Frustumf e = extractorEf();
+        f->set (T(e.nearPlane()), T(e.farPlane()), T(e.left()), T(e.right()),
+                T(e.top()), T(e.bottom()), e.orthographic());
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::Frustumd> extractorEd (p);
+    if (extractorEd.check())
+    {
+        IMATH_NAMESPACE::Frustumd e = extractorEd();
+        f->set (T(e.nearPlane()), T(e.farPlane()), T(e.left()), T(e.right()),
+                T(e.top()), T(e.bottom()), e.orthographic());
+        return 1;
+    }
+
+    return 0;
+}
+
+typedef F<float>       Frustumf;
+typedef F<double>      Frustumd;
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathFun.cpp b/src/python/PyImath/PyImathFun.cpp
new file mode 100644 (file)
index 0000000..f9ba0ca
--- /dev/null
@@ -0,0 +1,242 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include "PyImathFun.h"
+#include "PyImathFunOperators.h"
+#include "PyImathDecorators.h"
+#include "PyImathExport.h"
+#include "PyImathAutovectorize.h"
+
+namespace PyImath {
+
+using namespace boost::python;
+
+namespace
+{
+
+struct RegisterFloatDoubleOps
+{
+    template <typename T>
+    void operator() (T)
+    {
+        // nb: MSVC gets confused about which arg we want (it thinks it
+        // might be boost::arg), so telling it which one explicitly here.
+        typedef boost::python::arg arg;
+
+        generate_bindings<abs_op<T>,boost::mpl::true_>(
+            "abs",
+            "return the absolute value of 'value'",
+            (arg("value")));
+
+        generate_bindings<sign_op<T>,boost::mpl::true_>(
+            "sign",
+            "return 1 or -1 based on the sign of 'value'",
+            (arg("value")));
+
+        generate_bindings<log_op<T>,boost::mpl::true_>(
+            "log",
+            "return the natural log of 'value'",
+            (arg("value")));
+
+        generate_bindings<log10_op<T>,boost::mpl::true_>(
+            "log10",
+            "return the base 10 log of 'value'",
+            (arg("value")));
+
+        generate_bindings<lerp_op<T>,boost::mpl::true_,boost::mpl::true_,boost::mpl::true_>(
+            "lerp",
+            "return the linear interpolation of 'a' to 'b' using parameter 't'",
+            (arg("a"),arg("b"),arg("t")));
+
+        generate_bindings<lerpfactor_op<T>,boost::mpl::true_,boost::mpl::true_,boost::mpl::true_>(
+            "lerpfactor",
+            "return how far m is between a and b, that is return t such that\n"
+            "if:\n"
+            "    t = lerpfactor(m, a, b);\n"
+            "then:\n"
+            "    m = lerp(a, b, t);\n"
+            "\n"
+            "If a==b, return 0.\n",
+            (arg("m"),arg("a"),arg("b")));
+
+        generate_bindings<clamp_op<T>,boost::mpl::true_,boost::mpl::true_,boost::mpl::true_>(
+            "clamp",
+            "return the value clamped to the range [low,high]",
+            (arg("value"),arg("low"),arg("high")));
+
+        generate_bindings<floor_op<T>,boost::mpl::true_>(
+            "floor",
+            "return the closest integer less than or equal to 'value'",
+            (arg("value")));
+
+        generate_bindings<ceil_op<T>,boost::mpl::true_>(
+            "ceil",
+            "return the closest integer greater than or equal to 'value'",
+            (arg("value")));
+
+        generate_bindings<trunc_op<T>,boost::mpl::true_>(
+            "trunc",
+            "return the closest integer with magnitude less than or equal to 'value'",
+            (arg("value")));
+
+        generate_bindings<rgb2hsv_op<T>,boost::mpl::true_>(
+            "rgb2hsv",
+            "return the hsv version of an rgb color",
+            args("rgb"));
+
+        generate_bindings<hsv2rgb_op<T>,boost::mpl::true_>(
+            "hsv2rgb",
+            "return the rgb version of an hsv color",
+            args("hsv"));
+
+        generate_bindings<sin_op<T>,boost::mpl::true_>(
+            "sin",
+            "return the sine of the angle theta",
+            args("theta"));
+
+        generate_bindings<cos_op<T>,boost::mpl::true_>(
+            "cos",
+            "return the cosine of the angle theta",
+            args("theta"));
+
+        generate_bindings<tan_op<T>,boost::mpl::true_>(
+            "tan",
+            "return the tangent of the angle theta",
+            args("theta"));
+
+        generate_bindings<asin_op<T>,boost::mpl::true_>(
+            "asin",
+            "return the arcsine of the value x",
+            args("x"));
+
+        generate_bindings<acos_op<T>,boost::mpl::true_>(
+            "acos",
+            "return the arccosine of the value x",
+            args("x"));
+
+        generate_bindings<atan_op<T>,boost::mpl::true_>(
+            "atan",
+            "return the arctangent of the value x",
+            args("x"));
+
+        generate_bindings<atan2_op<T>,boost::mpl::true_,boost::mpl::true_>(
+            "atan2",
+            "return the arctangent of the coordinate x,y - note the y "
+            "is the first argument for consistency with libm ordering",
+            args("y","x"));
+
+        generate_bindings<sqrt_op<T>,boost::mpl::true_>(
+            "sqrt",
+            "return the square root of x",
+            args("x"));
+
+        generate_bindings<pow_op<T>,boost::mpl::true_,boost::mpl::true_>(
+            "pow",
+            "return x**y",
+            args("x","y"));
+
+        generate_bindings<exp_op<T>,boost::mpl::true_>(
+             "exp",
+             "return exp(x)",
+             args("x"));
+
+        generate_bindings<sinh_op<T>,boost::mpl::true_>(
+             "sinh",
+             "return sinh(x)",
+             args("x"));
+
+        generate_bindings<cosh_op<T>,boost::mpl::true_>(
+             "cosh",
+             "return cosh(x)",
+             args("x"));
+
+        def("cmp", IMATH_NAMESPACE::cmp<T>);
+        def("cmpt", IMATH_NAMESPACE::cmpt<T>);
+        def("iszero", IMATH_NAMESPACE::iszero<T>);
+        def("equal", IMATH_NAMESPACE::equal<T, T, T>);
+    }
+};
+
+} // namespace
+
+void register_functions()
+{
+    //
+    // Utility Functions
+    //
+
+    // nb: MSVC gets confused about which arg we want (it thinks it
+    // might be boost::arg), so telling it which one explicitly here.
+    typedef boost::python::arg arg;
+
+    using fp_types = boost::mpl::vector<float, double>;
+    boost::mpl::for_each<fp_types>(RegisterFloatDoubleOps());
+
+    generate_bindings<abs_op<int>,boost::mpl::true_>(
+        "abs",
+        "return the absolute value of 'value'",
+        (arg("value")));
+    
+    generate_bindings<sign_op<int>,boost::mpl::true_>(
+        "sign",
+        "return 1 or -1 based on the sign of 'value'",
+        (arg("value")));
+    
+    generate_bindings<clamp_op<int>,boost::mpl::true_,boost::mpl::true_,boost::mpl::true_>(
+        "clamp",
+        "return the value clamped to the range [low,high]",
+        (arg("value"),arg("low"),arg("high")));
+
+    generate_bindings<divs_op,boost::mpl::true_,boost::mpl::true_>(
+        "divs",
+        "return x/y where the remainder has the same sign as x:\n"
+        "    divs(x,y) == (abs(x) / abs(y)) * (sign(x) * sign(y))\n",
+        (arg("x"),arg("y")));
+    generate_bindings<mods_op,boost::mpl::true_,boost::mpl::true_>(
+        "mods",
+        "return x%y where the remainder has the same sign as x:\n"
+        "    mods(x,y) == x - y * divs(x,y)\n",
+        (arg("x"),arg("y")));
+
+    generate_bindings<divp_op,boost::mpl::true_,boost::mpl::true_>(
+        "divp",
+        "return x/y where the remainder is always positive:\n"
+        "    divp(x,y) == floor (double(x) / double (y))\n",
+        (arg("x"),arg("y")));
+    generate_bindings<modp_op,boost::mpl::true_,boost::mpl::true_>(
+        "modp",
+        "return x%y where the remainder is always positive:\n"
+        "    modp(x,y) == x - y * divp(x,y)\n",
+        (arg("x"),arg("y")));
+
+    generate_bindings<bias_op,boost::mpl::true_,boost::mpl::true_>(
+         "bias",
+         "bias(x,b) is a gamma correction that remaps the unit interval such that bias(0.5, b) = b.",
+         (arg("x"),arg("b")));
+
+    generate_bindings<gain_op,boost::mpl::true_,boost::mpl::true_>(
+         "gain",
+         "gain(x,g) is a gamma correction that remaps the unit interval with the property that gain(0.5, g) = 0.5.\n"
+         "The gain function can be thought of as two scaled bias curves forming an 'S' shape in the unit interval.",
+         (arg("x"),arg("g")));
+
+    //
+    // Vectorized utility functions
+    // 
+    generate_bindings<rotationXYZWithUpDir_op<float>,boost::mpl::true_,boost::mpl::true_,boost::mpl::true_>(
+        "rotationXYZWithUpDir",
+        "return the XYZ rotation vector that rotates 'fromDir' to 'toDir'"
+        "using the up vector 'upDir'",
+        args("fromDir","toDir","upDir"));
+}
+
+} // namespace PyImath
diff --git a/src/python/PyImath/PyImathFun.h b/src/python/PyImath/PyImathFun.h
new file mode 100644 (file)
index 0000000..0218895
--- /dev/null
@@ -0,0 +1,19 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathFun_h_
+#define _PyImathFun_h_
+
+#include "PyImathExport.h"
+
+namespace PyImath {
+
+PYIMATH_EXPORT void register_functions();
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathFunOperators.h b/src/python/PyImath/PyImathFunOperators.h
new file mode 100644 (file)
index 0000000..f20ca30
--- /dev/null
@@ -0,0 +1,398 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathFunOperators_h_
+#define _PyImathFunOperators_h_
+
+#include <ImathVec.h>
+#include <ImathMatrixAlgo.h>
+#include <ImathColorAlgo.h>
+#include <ImathFun.h>
+#include <cmath>
+
+namespace PyImath {
+
+template <class T>
+struct rotationXYZWithUpDir_op
+{
+    static IMATH_NAMESPACE::Vec3<T>
+    apply(const IMATH_NAMESPACE::Vec3<T> &from, const IMATH_NAMESPACE::Vec3<T> &to, 
+          const IMATH_NAMESPACE::Vec3<T> &up)
+    {
+        IMATH_NAMESPACE::Vec3<T> retval;
+        IMATH_NAMESPACE::extractEulerXYZ(IMATH_NAMESPACE::rotationMatrixWithUpDir(from,to,up),retval);
+        return retval;
+    }
+};
+
+template <class T>
+struct abs_op
+{
+    static T
+    apply(T value)
+    {
+        return IMATH_NAMESPACE::abs<T>(value);
+    }
+};
+
+template <class T>
+struct sign_op
+{
+    static T
+    apply(T value)
+    {
+        return IMATH_NAMESPACE::sign<T>(value);
+    }
+};
+
+template <class T>
+struct log_op
+{
+    static T
+    apply(T value)
+    {
+        return ::log(value);
+    }
+};
+
+template <class T>
+struct log10_op
+{
+    static T
+    apply(T value)
+    {
+        return ::log10(value);
+    }
+};
+
+template <class T>
+struct lerp_op
+{
+    static T
+    apply(T a, T b, T t)
+    {
+        return IMATH_NAMESPACE::lerp<T>(a,b,t);
+    }
+};
+
+template <class T>
+struct ulerp_op
+{
+    static T
+    apply(T a, T b, T t)
+    {
+        return IMATH_NAMESPACE::ulerp<T>(a,b,t);
+    }
+};
+
+template <class T>
+struct lerpfactor_op
+{
+    static T
+    apply(T a, T b, T t)
+    {
+        return IMATH_NAMESPACE::lerpfactor<T>(a,b,t);
+    }
+};
+
+template <class T>
+struct clamp_op
+{
+    static T
+    apply(T value, T low, T high)
+    {
+        return IMATH_NAMESPACE::clamp<T>(value,low,high);
+    }
+};
+
+template <class T>
+struct cmp_op
+{
+    static T
+    apply(T value)
+    {
+        return IMATH_NAMESPACE::cmp<T>(value);
+    }
+};
+
+template <class T>
+struct cmpt_op
+{
+    static T
+    apply(T value)
+    {
+        return IMATH_NAMESPACE::cmpt<T>(value);
+    }
+};
+
+template <class T>
+struct iszero_op
+{
+    static T
+    apply(T value)
+    {
+        return IMATH_NAMESPACE::iszero<T>(value);
+    }
+};
+
+template <class T>
+struct equal_op
+{
+    static T
+    apply(T value)
+    {
+        return IMATH_NAMESPACE::equal<T>(value);
+    }
+};
+
+template <class T>
+struct floor_op
+{
+    static int
+    apply(T value)
+    {
+        return IMATH_NAMESPACE::floor<T>(value);
+    }
+};
+
+template <class T>
+struct ceil_op
+{
+    static int
+    apply(T value)
+    {
+        return IMATH_NAMESPACE::ceil<T>(value);
+    }
+};
+
+template <class T>
+struct trunc_op
+{
+    static int
+    apply(T value)
+    {
+        return IMATH_NAMESPACE::trunc<T>(value);
+    }
+};
+
+struct divs_op
+{
+    static int
+    apply(int x, int y)
+    {
+        return IMATH_NAMESPACE::divs(x,y);
+    }
+};
+
+struct mods_op
+{
+    static int
+    apply(int x, int y)
+    {
+        return IMATH_NAMESPACE::mods(x,y);
+    }
+};
+
+struct divp_op
+{
+    static int
+    apply(int x, int y)
+    {
+        return IMATH_NAMESPACE::divp(x,y);
+    }
+};
+
+struct modp_op
+{
+    static int
+    apply(int x, int y)
+    {
+        return IMATH_NAMESPACE::modp(x,y);
+    }
+};
+
+struct bias_op
+{
+    static inline float
+    apply(float x, float b)
+    {
+        if (b != 0.5f)
+        {
+            static const float inverse_log_half = 1.0f / std::log(0.5f);
+            const float biasPow = std::log(b)*inverse_log_half;
+            return std::pow(x, biasPow);
+        }
+        return x;
+    }
+};
+
+struct gain_op
+{
+    static inline float
+    apply(float x, float g)
+    {
+        if (x < 0.5f)
+            return 0.5f*bias_op::apply(2.0f*x, 1.0f - g);
+        else
+            return 1.0f - 0.5f*bias_op::apply(2.0f - 2.0f*x, 1.0f - g);
+    }
+};
+
+template <class T>
+struct rgb2hsv_op
+{
+    static inline IMATH_NAMESPACE::Vec3<T>
+    apply(const IMATH_NAMESPACE::Vec3<T> &rgb)
+    {
+        return IMATH_NAMESPACE::rgb2hsv(rgb);
+    }
+};
+
+template <class T>
+struct hsv2rgb_op
+{
+    static inline IMATH_NAMESPACE::Vec3<T>
+    apply(const IMATH_NAMESPACE::Vec3<T> &rgb)
+    {
+        return IMATH_NAMESPACE::hsv2rgb(rgb);
+    }
+};
+
+template <class T>
+struct min_op
+{
+    static inline T
+    apply(T x, T y)
+    {
+        return std::min(x,y);
+    }
+};
+
+template <class T>
+struct max_op
+{
+    static inline T
+    apply(T x, T y)
+    {
+        return std::max(x,y);
+    }
+};
+
+template <class T>
+struct sin_op {
+    static inline T
+    apply(T theta)
+    {
+        return std::sin(theta);
+    }
+};
+
+template <class T>
+struct cos_op {
+    static inline T
+    apply(T theta)
+    {
+        return std::cos(theta);
+    }
+};
+
+template <class T>
+struct tan_op {
+    static inline T
+    apply(T theta)
+    {
+        return std::tan(theta);
+    }
+};
+
+template <class T>
+struct asin_op {
+    static inline T
+    apply(T x)
+    {
+        return std::asin(x);
+    }
+};
+
+template <class T>
+struct acos_op {
+    static inline T
+    apply(T x)
+    {
+        return std::acos(x);
+    }
+};
+
+template <class T>
+struct atan_op {
+    static inline float
+    apply(T x)
+    {
+        return std::atan(x);
+    }
+};
+
+template <class T>
+struct atan2_op {
+    static inline T
+    apply(T y, T x)
+    {
+        return std::atan2(y,x);
+    }
+};
+
+template <class T>
+struct sqrt_op {
+    static inline T
+    apply(T x)
+    {
+        return std::sqrt(x);
+    }
+};
+
+template <class T>
+struct pow_op {
+    static inline T
+    apply(T x, T y)
+    {
+        return std::pow(x,y);
+    }
+};
+
+template <class T>
+struct exp_op
+{
+    static inline T
+    apply(T x)
+    {
+        return std::exp(x);
+    }
+};
+
+template <class T>
+struct sinh_op
+{
+    static inline T
+    apply(T x)
+    {
+        return std::sinh(x);
+    }
+};
+
+template <class T>
+struct cosh_op
+{
+    static inline T
+    apply(T x)
+    {
+        return std::cosh(x);
+    }
+};
+
+} // namespace PyImath
+
+#endif // _PyImathFunOperators_h_
diff --git a/src/python/PyImath/PyImathLine.cpp b/src/python/PyImath/PyImathLine.cpp
new file mode 100644 (file)
index 0000000..16a2313
--- /dev/null
@@ -0,0 +1,558 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <ImathLineAlgo.h>
+#include <ImathMatrix.h>
+#include "PyImathLine.h"
+#include "PyImathDecorators.h"
+#include "PyImathExport.h"
+#include "PyImath.h"
+#include "PyImathVec.h"
+#include "PyImathMathExc.h"
+
+
+namespace PyImath{
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct LineName {static const char *value;};
+template <> const char *LineName<float>::value = "Line3f";
+template <> const char *LineName<double>::value = "Line3d";
+
+template <class T>
+static Line3<T> * 
+Line3_construct_default()
+{
+    Vec3<T> point1(T (0), T(0), T(0));
+    Vec3<T> point2(T (1), T(0), T(0));
+    
+    return new Line3<T>(point1, point2);
+}
+
+template <class T>
+static Line3<T> * 
+Line3_tuple_construct(const tuple &t0, const tuple &t1)
+{
+    Vec3<T> v0, v1;
+    if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3)
+    {
+        v0.x = extract<T>(t0[0]);
+        v0.y = extract<T>(t0[1]);
+        v0.z = extract<T>(t0[2]);
+
+        v1.x = extract<T>(t1[0]);
+        v1.y = extract<T>(t1[1]);
+        v1.z = extract<T>(t1[2]);
+        
+        return new Line3<T>(v0, v1);
+    }
+    else
+      throw std::invalid_argument ("Line3 expects tuple of length 3");    
+}
+
+template <class T, class S>
+static Line3<T> *
+Line3_line_construct(const Line3<S> &line)
+{
+    Line3<T> *l = new Line3<T>;
+    l->pos = line.pos;
+    l->dir = line.dir;
+    
+    return l;
+}
+
+template <class T>
+static void
+set1(Line3<T> &line, const Vec3<T> &p0, const Vec3<T> &p1)
+{
+    MATH_EXC_ON;
+    line.set (p0, p1);
+}
+
+template <class T>
+static void
+setTuple(Line3<T> &line, const tuple &t0, const tuple &t1)
+{
+    MATH_EXC_ON;
+    Vec3<T> v0, v1;
+    if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3)
+    {
+        v0.x = extract<T>(t0[0]);
+        v0.y = extract<T>(t0[1]);
+        v0.z = extract<T>(t0[2]);
+
+        v1.x = extract<T>(t1[0]);
+        v1.y = extract<T>(t1[1]);
+        v1.z = extract<T>(t1[2]);
+        
+        line.set(v0, v1);
+    }
+    else
+      throw std::invalid_argument ("Line3 expects tuple of length 3");    
+}
+
+template <class T>
+static Vec3<T>
+pointAt(Line3<T> &line, T t)
+{
+    MATH_EXC_ON;
+    return line.operator()(t);
+}
+
+template <class T>
+static T
+distanceTo1(Line3<T> &line, Vec3<T> &p)
+{
+    MATH_EXC_ON;
+    return line.distanceTo(p);
+}
+
+template <class T>
+static T
+distanceTo2(Line3<T> &line, Line3<T> &other)
+{
+    MATH_EXC_ON;
+    return line.distanceTo(other);
+}
+
+template <class T>
+static T
+distanceToTuple(Line3<T> line, const tuple &t)
+{
+    Vec3<T> v;
+    if(t.attr("__len__")() == 3)
+    {
+        v.x = extract<T>(t[0]);
+        v.y = extract<T>(t[1]);
+        v.z = extract<T>(t[2]);
+        
+        return line.distanceTo(v);
+    }
+    else
+        throw std::invalid_argument ( "Line3 expects tuple of length 3");      
+}
+
+template <class T>
+static Vec3<T>
+closestPointTo1(Line3<T> line, const Vec3<T> &p)
+{
+    MATH_EXC_ON;
+    return line.closestPointTo(p);
+}
+
+template <class T>
+static Vec3<T>
+closestPointTo2(Line3<T> line, const Line3<T> &other)
+{
+    MATH_EXC_ON;
+    return line.closestPointTo(other);
+}
+                     
+template <class T>
+static Vec3<T>
+closestPointToTuple(Line3<T> line, const tuple &t)
+{
+    MATH_EXC_ON;
+    Vec3<T> v;
+    if(t.attr("__len__")() == 3)
+    {
+        v.x = extract<T>(t[0]);
+        v.y = extract<T>(t[1]);
+        v.z = extract<T>(t[2]);
+        
+        return line.closestPointTo(v);
+    }
+    else
+        throw std::invalid_argument ( "Line3 expects tuple of length 3");      
+}
+
+template <class T>
+static Vec3<T>
+getPosition(Line3<T> &line)
+{
+    return line.pos;
+}
+
+template <class T>
+static void
+setPosition(Line3<T> &line, const Vec3<T> &pos)
+{
+    line.pos = pos;
+}
+
+template <class T>
+static void
+setPositionTuple(Line3<T> &line, const tuple &t)
+{
+    Vec3<T> pos;
+    if(t.attr("__len__")() == 3)
+    {
+        pos.x = extract<T>(t[0]);
+        pos.y = extract<T>(t[1]);
+        pos.z = extract<T>(t[2]);
+        
+        line.pos = pos;
+    }
+    else
+        throw std::invalid_argument ( "Line3 expects tuple of length 3");    
+}
+
+template <class T>
+static Vec3<T>
+getDirection(Line3<T> &line)
+{
+    return line.dir;
+}
+
+template <class T>
+static void
+setDirection(Line3<T> &line, const Vec3<T> &dir)
+{
+    MATH_EXC_ON;
+    line.dir = dir.normalized();
+}
+
+template <class T>
+static void
+setDirectionTuple(Line3<T> &line, const tuple &t)
+{
+    MATH_EXC_ON;
+    Vec3<T> dir;
+    if(t.attr("__len__")() == 3)
+    {
+        dir.x = extract<T>(t[0]);
+        dir.y = extract<T>(t[1]);
+        dir.z = extract<T>(t[2]);
+        
+        line.dir = dir.normalized();
+    }
+    else
+        throw std::invalid_argument ( "Line3 expects tuple of length 3");    
+}
+
+template <class T>
+static void
+closestPoints1(Line3<T> &line1, const Line3<T> &line2, Vec3<T> &p0, Vec3<T> &p1)
+{
+    MATH_EXC_ON;
+    IMATH_NAMESPACE::closestPoints(line1, line2, p0, p1);
+}
+
+template <class T>
+static tuple
+closestPoints2(Line3<T> &line1, const Line3<T> &line2)
+{
+    MATH_EXC_ON;
+    Vec3<T> p0, p1;
+    IMATH_NAMESPACE::closestPoints(line1, line2, p0, p1);
+    tuple p0Tuple = make_tuple(p0.x,p0.y,p0.z);
+    tuple p1Tuple = make_tuple(p1.x,p1.y,p1.z);
+
+#if !defined(_MSC_VER) || (_MSC_VER <= 1200)
+    tuple t = make_tuple(p0Tuple, p1Tuple);
+    return t;
+#else
+    list v3;
+    v3.append(p0Tuple);
+    v3.append(p1Tuple);
+    return tuple(v3);
+#endif
+}
+
+template <class T>
+static Vec3<T>
+closestVertex(Line3<T> &line, const Vec3<T> &v0, const Vec3<T> &v1, const Vec3<T> &v2)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::closestVertex(v0, v1, v2, line);
+}
+
+template <class T>
+static Vec3<T>
+closestVertexTuple(Line3<T> &line, const tuple &t0, const tuple &t1, const tuple &t2)
+{
+    MATH_EXC_ON;
+    if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3 && t2.attr("__len__")() == 3)
+    {
+        Vec3<T> v0, v1, v2;
+        v0.x = extract<T>(t0[0]);
+        v0.y = extract<T>(t0[1]);
+        v0.z = extract<T>(t0[2]);
+        
+        v1.x = extract<T>(t1[0]);
+        v1.y = extract<T>(t1[1]);
+        v1.z = extract<T>(t1[2]);
+
+        v2.x = extract<T>(t2[0]);
+        v2.y = extract<T>(t2[1]);
+        v2.z = extract<T>(t2[2]);
+        
+        return IMATH_NAMESPACE::closestVertex(v0, v1, v2, line);
+    }        
+    else
+        throw std::invalid_argument ( "Line3 expects tuple of length 3");      
+}
+
+template <class T>
+static bool
+intersect1(Line3<T> &line, const Vec3<T> &v0, const Vec3<T> &v1, const Vec3<T> &v2, 
+          Vec3<T> &pt, Vec3<T> &barycentric, bool &front)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::intersect(line, v0, v1, v2, pt, barycentric, front);
+}
+
+template <class T>
+static object
+intersect2(Line3<T> &line, const Vec3<T> &v0, const Vec3<T> &v1, const Vec3<T> &v2)
+{    
+    MATH_EXC_ON;
+    Vec3<T> pt, bar;
+    bool front;
+    
+    if(IMATH_NAMESPACE::intersect(line, v0, v1, v2, pt, bar, front))
+    {
+        tuple t = make_tuple(pt, bar, front);
+        return t;
+    }
+    else
+    {
+        return object();
+    }
+}
+
+template <class T>
+static tuple
+intersectTuple(Line3<T> &line, const tuple &t0, const tuple &t1, const tuple &t2)
+{    
+
+    if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3 && t2.attr("__len__")() == 3)
+    {   
+        Vec3<T> v0, v1, v2, pt, bar;
+        bool front;
+        v0.x = extract<T>(t0[0]);
+        v0.y = extract<T>(t0[1]);
+        v0.z = extract<T>(t0[2]);
+        
+        v1.x = extract<T>(t1[0]);
+        v1.y = extract<T>(t1[1]);
+        v1.z = extract<T>(t1[2]);
+
+        v2.x = extract<T>(t2[0]);
+        v2.y = extract<T>(t2[1]);
+        v2.z = extract<T>(t2[2]);
+        
+        if(IMATH_NAMESPACE::intersect(line, v0, v1, v2, pt, bar, front))
+        {
+            tuple t = make_tuple(pt, bar, front);
+            return t;
+        }
+        else
+        {
+            tuple t;
+            return t;
+        }
+    }
+    else
+        throw std::invalid_argument ( "Line3 expects tuple of length 3");
+}
+
+template <class T>
+static Vec3<T>
+rotatePoint(Line3<T> &line, const Vec3<T> &p, const T &r)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::rotatePoint(p, line, r);
+}
+
+template <class T>
+static Vec3<T>
+rotatePointTuple(Line3<T> &line, const tuple &t, const T &r)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> p;
+        p.x = extract<T>(t[0]);
+        p.y = extract<T>(t[1]);
+        p.z = extract<T>(t[2]);
+        
+        return IMATH_NAMESPACE::rotatePoint(p, line, r);
+    }        
+    else
+        throw std::invalid_argument ( "Line3 expects tuple of length 3");      
+}
+
+template <class T>
+static std::string Line3_repr(const Line3<T> &v)
+{
+    typename return_by_value::apply <Vec3<T> >::type converter;
+
+    Vec3<T> v1 = v.pos;
+    Vec3<T> v2 = v.pos + v.dir;
+
+    handle<> v1h (converter (v.pos));
+    handle<> v1Repr (PYUTIL_OBJECT_REPR (v1h.get()));
+    std::string v1ReprStr = extract<std::string> (v1Repr.get());
+
+    handle<> v2h (converter (v.pos + v.dir));
+    handle<> v2Repr (PYUTIL_OBJECT_REPR (v2h.get()));
+    std::string v2ReprStr = extract<std::string> (v2Repr.get());
+
+    std::stringstream stream;
+    stream << LineName<T>::value << "(" << v1ReprStr << ", " << v2ReprStr << ")";
+    return stream.str();
+}
+
+template <class T>
+static bool
+equal(const Line3<T> &l1, const Line3<T> &l2)
+{
+    if(l1.pos == l2.pos && l1.dir == l2.dir)
+        return true;
+    else
+        return false;
+}
+
+template <class T>
+static bool
+notequal(const Line3<T> &l1, const Line3<T> &l2)
+{
+    if(l1.pos != l2.pos || l1.dir != l2.dir)
+        return true;
+    else
+        return false;
+}
+
+template <class T>
+class_<Line3<T> >
+register_Line()
+{
+    const char *name = LineName<T>::value;
+    
+    class_<Line3<T> > line_class(name);
+    line_class
+        .def("__init__", make_constructor(Line3_construct_default<T>), "initialize point to (0,0,0) and direction to (1,0,0)")
+        .def("__init__", make_constructor(Line3_tuple_construct<T>))
+        .def("__init__", make_constructor(Line3_line_construct<T,float>))
+        .def("__init__", make_constructor(Line3_line_construct<T,double>))
+        .def(init<const Vec3<float> &, const Vec3<float> &>("Line3(point1, point2) construction"))
+        .def(init<const Vec3<double> &, const Vec3<double> &>("Line3(point1, point2) construction"))
+        .def(self * Matrix44<T>())
+        .def("__eq__", &equal<T>)
+        .def("__ne__", &notequal<T>)
+        
+        .def_readwrite("pos", &Line3<T>::pos)
+        .def_readwrite("dir", &Line3<T>::dir)
+
+        .def("pos", &getPosition<T>, 
+        "l.pos() -- returns the start point of line l")
+        
+        .def("dir", &getDirection<T>, 
+        "l.dir() -- returns the direction of line l\n")
+        
+        .def("setPos", &setPosition<T>, 
+        "l.setPos(p) -- sets the start point of line l to p")
+        .def("setPos", &setPositionTuple<T>)
+        
+        .def("setDir", &setDirection<T>, 
+        "l.setDir(d) -- sets the direction of line l\n"
+               "to d.normalized().\n")
+        .def("setDir", &setDirectionTuple<T>)
+                                            
+        .def("set", &set1<T>, 
+        "l.set(p1, p2) -- sets the start point\n"
+               "and direction of line l by calling\n"
+        "   l.setPos (p1)\n"
+        "   l.setDir (p2 - p1)\n")
+        
+        .def("set", &setTuple<T>)
+        
+        .def("pointAt", &pointAt<T>,
+        "l.pointAt(t) -- returns l.pos() + t * l.dir()")
+        
+        .def("distanceTo", &distanceTo1<T>, 
+        "l.distanceTo(p) -- returns the distance from\n"
+               "   line l to point p\n")
+                                        
+        .def("distanceTo", &distanceTo2<T>, 
+        "l1.distanceTo(l2) -- returns the distance from\n"
+        "   line l1 to line l2\n")
+        
+        .def("distanceTo", &distanceToTuple<T>)
+                                
+        .def("closestPointTo", &closestPointTo1<T>, 
+        "l.closestPointTo(p) -- returns the point on\n"
+               "   line l that is closest to point p\n"
+        "\n")
+        
+        .def("closestPointTo", &closestPointToTuple<T>)
+        .def("closestPointTo", &closestPointTo2<T>, 
+        "l1.closestPointTo(l2) -- returns the point on\n"
+               "   line l1 that is closest to line l2\n")
+        
+        .def("closestPoints", &closestPoints1<T>, 
+        "l1.closestPoints(l2,p0,p1)")    
+                                            
+        .def("closestPoints", &closestPoints2<T>, 
+        "l1.closestPoints(l2) -- returns a tuple with\n"
+               "two points:\n"
+        "   (l1.closestPoint(l2), l2.closestPoint(l1)\n")
+                                             
+        .def("closestTriangleVertex", &closestVertex<T>, 
+        "l.closestTriangleVertex(v0, v1, v2) -- returns\n"
+               "a copy of v0, v1, or v2, depending on which is\n"
+        "closest to line l.\n")
+        
+        .def("closestTriangleVertex", &closestVertexTuple<T>)
+        .def("intersectWithTriangle", &intersect2<T>)                                             
+        .def("intersectWithTriangle", &intersect1<T>, 
+            "l.intersectWithTriangle(v0, v1, v2) -- computes the\n"
+                       "intersection of line l and triangle (v0, v1, v2).\n"
+                       "\n"
+                       "If the line and the triangle do not intersect,\n"
+                       "None is returned.\n"
+                       ""
+                       "If the line and the triangle intersect, a tuple\n"
+                       "(p, b, f) is returned:\n"
+                       "\n"
+                       "   p  intersection point in 3D space\n"
+                       "\n"
+                       "   b  intersection point in barycentric coordinates\n"
+                       "\n"
+                       "   f  1 if the line hits the triangle from the\n"
+                       "      front (((v2-v1) % (v1-v2)) ^ l.dir() < 0),\n"
+                       "      0 if the line hits the trianble from the\n"
+                       "      back\n"
+                       "\n")
+        .def("intersectWithTriangle", &intersectTuple<T>)
+            
+        .def("rotatePoint", &rotatePoint<T>, 
+            "l.rotatePoint(p,r) -- rotates point p around\n"
+                       "line by angle r (in radians), and returns the\n"
+                       "result (p is not modified)\n")
+        
+        .def("rotatePoint", &rotatePointTuple<T>)
+        .def("__repr__",&Line3_repr<T>)
+        ;
+
+    decoratecopy(line_class);
+
+    return line_class;
+}
+
+template PYIMATH_EXPORT class_<Line3<float> > register_Line<float>();
+template PYIMATH_EXPORT class_<Line3<double> > register_Line<double>();
+
+} // namespace PyImath
+
+
diff --git a/src/python/PyImath/PyImathLine.h b/src/python/PyImath/PyImathLine.h
new file mode 100644 (file)
index 0000000..1b40f1d
--- /dev/null
@@ -0,0 +1,77 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathLine_h_
+#define _PyImathLine_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <ImathLine.h>
+#include "PyImath.h"
+
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Line3<T> > register_Line();
+
+//
+
+// Other code in the Zeno code base assumes the existance of a class with the
+// same name as the Imath class, and with static functions wrap() and
+// convert() to produce a PyImath object from an Imath object and vice-versa,
+// respectively.  The class Boost generates from the Imath class does not
+// have these properties, so we define a companion class here.
+// The template argument, T, is the element type (e.g.,float, double).
+
+template <class T>
+class L3 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Line3<T> &l);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Line3<T> *l);
+};
+
+template <class T>
+PyObject *
+L3<T>::wrap (const IMATH_NAMESPACE::Line3<T> &l)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Line3<T> >::type converter;
+    PyObject *p = converter (l);
+    return p;
+}
+
+template <class T>
+int
+L3<T>::convert (PyObject *p, IMATH_NAMESPACE::Line3<T> *l)
+{
+    boost::python::extract <IMATH_NAMESPACE::Line3f> extractorLf (p);
+    if (extractorLf.check())
+    {
+        IMATH_NAMESPACE::Line3f e = extractorLf();
+        l->pos.setValue (e.pos);
+        l->dir.setValue (e.dir);
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::Line3d> extractorLd (p);
+    if (extractorLd.check())
+    {
+        IMATH_NAMESPACE::Line3d e = extractorLd();
+        l->pos.setValue (e.pos);
+        l->dir.setValue (e.dir);
+        return 1;
+    }
+
+    return 0;
+}
+
+typedef L3<float>      Line3f;
+typedef L3<double>     Line3d;
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathMathExc.h b/src/python/PyImath/PyImathMathExc.h
new file mode 100644 (file)
index 0000000..bb54e37
--- /dev/null
@@ -0,0 +1,21 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathMathExc_h_
+#define _PyImathMathExc_h_
+
+//
+// Note: when PyImath from the v2 release of OpenEXR depended on Iex,
+// the MATH_EXC_ON macro enabled float-point exceptions via the
+// MathExcOn class. This was a compile-time option based on the
+// setting of PYIMATH_ENABLE_EXCEPTIONS. This behavior is now
+// deprecated, hence the empty macro.
+//
+
+#define MATH_EXC_ON
+
+#endif
diff --git a/src/python/PyImath/PyImathMatrix.h b/src/python/PyImath/PyImathMatrix.h
new file mode 100644 (file)
index 0000000..5393054
--- /dev/null
@@ -0,0 +1,206 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathMatrix_h_
+#define _PyImathMatrix_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <ImathMatrix.h>
+#include <ImathMatrixAlgo.h>
+#include "PyImath.h"
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Matrix22<T> > register_Matrix22();
+template <class T> boost::python::class_<IMATH_NAMESPACE::Matrix33<T> > register_Matrix33();
+template <class T> boost::python::class_<IMATH_NAMESPACE::Matrix44<T> > register_Matrix44();
+template <class T> boost::python::class_<FixedArray<IMATH_NAMESPACE::Matrix44<T> > > register_M44Array();
+template <class T> boost::python::class_<FixedArray<IMATH_NAMESPACE::Matrix33<T> > > register_M33Array();
+template <class T> boost::python::class_<FixedArray<IMATH_NAMESPACE::Matrix22<T> > > register_M22Array();
+typedef FixedArray<IMATH_NAMESPACE::Matrix22<float> >  M22fArray;
+typedef FixedArray<IMATH_NAMESPACE::Matrix22<double> >  M22dArray;
+typedef FixedArray<IMATH_NAMESPACE::Matrix33<float> >  M33fArray;
+typedef FixedArray<IMATH_NAMESPACE::Matrix33<double> >  M33dArray;
+typedef FixedArray<IMATH_NAMESPACE::Matrix44<float> >  M44fArray;
+typedef FixedArray<IMATH_NAMESPACE::Matrix44<double> >  M44dArray;
+
+//
+
+// Other code in the Zeno code base assumes the existance of a class with the
+// same name as the Imath class, and with static functions wrap() and
+// convert() to produce a PyImath object from an Imath object and vice-versa,
+// respectively.  The class Boost generates from the Imath class does not
+// have these properties, so we define a companion class here.
+// The template argument, T, is the element type (e.g.,float, double).
+
+template <class T>
+class M22 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Matrix22<T> &m);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Matrix22<T> *m);
+};
+
+template <class T>
+class M33 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Matrix33<T> &m);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Matrix33<T> *m);
+};
+
+template <class T>
+class M44 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Matrix44<T> &m);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Matrix44<T> *m);
+};
+
+template <class T>
+PyObject *
+M22<T>::wrap (const IMATH_NAMESPACE::Matrix22<T> &m)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Matrix22<T> >::type converter;
+    PyObject *p = converter (m);
+    return p;
+}
+
+template <class T>
+PyObject *
+M33<T>::wrap (const IMATH_NAMESPACE::Matrix33<T> &m)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Matrix33<T> >::type converter;
+    PyObject *p = converter (m);
+    return p;
+}
+
+template <class T>
+PyObject *
+M44<T>::wrap (const IMATH_NAMESPACE::Matrix44<T> &m)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Matrix44<T> >::type converter;
+    PyObject *p = converter (m);
+    return p;
+}
+
+template <class T>
+int
+M22<T>::convert (PyObject *p, IMATH_NAMESPACE::Matrix22<T> *m)
+{
+    boost::python::extract <IMATH_NAMESPACE::M22f> extractorMf (p);
+    if (extractorMf.check())
+    {
+        IMATH_NAMESPACE::M22f e = extractorMf();
+        m->setValue (e);
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::M22d> extractorMd (p);
+    if (extractorMd.check())
+    {
+        IMATH_NAMESPACE::M22d e = extractorMd();
+        m->setValue (e);
+        return 1;
+    }
+
+    return 0;
+}
+
+template <class T>
+int
+M33<T>::convert (PyObject *p, IMATH_NAMESPACE::Matrix33<T> *m)
+{
+    boost::python::extract <IMATH_NAMESPACE::M33f> extractorMf (p);
+    if (extractorMf.check())
+    {
+        IMATH_NAMESPACE::M33f e = extractorMf();
+        m->setValue (e);
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::M33d> extractorMd (p);
+    if (extractorMd.check())
+    {
+        IMATH_NAMESPACE::M33d e = extractorMd();
+        m->setValue (e);
+        return 1;
+    }
+
+    return 0;
+}
+
+template <class T>
+int
+M44<T>::convert (PyObject *p, IMATH_NAMESPACE::Matrix44<T> *m)
+{
+    boost::python::extract <IMATH_NAMESPACE::M44f> extractorMf (p);
+    if (extractorMf.check())
+    {
+        IMATH_NAMESPACE::M44f e = extractorMf();
+        m->setValue (e);
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::M44d> extractorMd (p);
+    if (extractorMd.check())
+    {
+        IMATH_NAMESPACE::M44d e = extractorMd();
+        m->setValue (e);
+        return 1;
+    }
+
+    return 0;
+}
+
+template <class Matrix>
+boost::python::tuple
+jacobiEigensolve(const Matrix& m)
+{
+    typedef typename Matrix::BaseType T;
+    typedef typename Matrix::BaseVecType Vec;
+
+    // For the C++ version, we just assume that the passed-in matrix is
+    // symmetric, but we assume that many of our script users are less
+    // sophisticated and might get tripped up by this.  Also, the cost
+    // of doing this check is likely miniscule compared to the Pythonic
+    // overhead.
+
+    // Give a fairly generous tolerance to account for possible epsilon drift:
+    const int d = Matrix::dimensions();
+    const T tol = std::sqrt(std::numeric_limits<T>::epsilon());
+    for (int i = 0; i < d; ++i)
+    {
+        for (int j = i+1; j < d; ++j)
+        {
+            const T Aij = m[i][j],
+                    Aji = m[j][i];
+            if (std::abs(Aij - Aji) >= tol){
+              throw std::invalid_argument
+              ("Symmetric eigensolve requires a symmetric matrix (matrix[i][j] == matrix[j][i]).");
+            }
+        }
+    }
+
+    Matrix tmp = m;
+    Matrix Q;
+    Vec S;
+    IMATH_NAMESPACE::jacobiEigenSolver (tmp, S, Q);
+    return boost::python::make_tuple (Q, S);
+}
+
+typedef M22<float>     M22f;
+typedef M22<double>    M22d;
+
+typedef M33<float>     M33f;
+typedef M33<double>    M33d;
+
+typedef M44<float>     M44f;
+typedef M44<double>    M44d;
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathMatrix22.cpp b/src/python/PyImath/PyImathMatrix22.cpp
new file mode 100644 (file)
index 0000000..5ba6542
--- /dev/null
@@ -0,0 +1,735 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#define BOOST_PYTHON_MAX_ARITY 17
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <boost/python/tuple.hpp>
+#include <boost/python/dict.hpp>
+#include <boost/python/raw_function.hpp>
+#include <ImathVec.h>
+#include <ImathMatrixAlgo.h>
+#include "PyImath.h"
+#include "PyImathVec.h"
+#include "PyImathMathExc.h"
+#include "PyImathMatrix.h"
+#include "PyImathExport.h"
+#include "PyImathDecorators.h"
+
+namespace PyImath {
+
+template<> const char *PyImath::M22fArray::name() { return "M22fArray"; }
+template<> const char *PyImath::M22dArray::name() { return "M22dArray"; }
+
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T, int len>
+struct MatrixRow {
+    explicit MatrixRow(T *data) : _data(data) {}
+    T & operator [] (int i) { return _data[i]; }
+    T *_data;
+
+    static const char *name;
+    static void register_class()
+    {
+        typedef PyImath::StaticFixedArray<MatrixRow,T,len> MatrixRow_helper;
+        class_<MatrixRow> matrixRow_class(name,no_init);
+        matrixRow_class
+            .def("__len__", MatrixRow_helper::len)
+            .def("__getitem__", MatrixRow_helper::getitem,return_value_policy<copy_non_const_reference>())
+            .def("__setitem__", MatrixRow_helper::setitem)
+            ;
+    }
+};
+
+template <> const char *MatrixRow<float,2>::name = "M22fRow";
+template <> const char *MatrixRow<double,2>::name = "M22dRow";
+
+
+template <class Container, class Data, int len>
+struct IndexAccessMatrixRow {
+    typedef MatrixRow<Data,len> result_type;
+    static MatrixRow<Data,len> apply(Container &c, int i) { return MatrixRow<Data,len>(c[i]); }
+};
+
+template <class T> struct Matrix22Name { static const char *value; };
+template<> const char *Matrix22Name<float>::value  = "M22f";
+template<> const char *Matrix22Name<double>::value = "M22d";
+
+template <class T>
+static std::string Matrix22_str(const Matrix22<T> &v)
+{
+    std::stringstream stream;
+    stream << Matrix22Name<T>::value << "(";
+    for (int row = 0; row < 2; row++)
+    {
+        stream << "(";
+       for (int col = 0; col < 2; col++)
+       {
+           stream << v[row][col];
+            stream << (col != 1 ? ", " : "");
+       }
+        stream << ")" << (row != 1 ? ", " : "");
+    }
+    stream << ")";
+    return stream.str();
+}
+
+// Non-specialized repr is same as str
+template <class T>
+static std::string Matrix22_repr(const Matrix22<T> &v)
+{
+    return Matrix22_str(v);
+}
+
+// Specialization for float to full precision
+template <>
+std::string Matrix22_repr(const Matrix22<float> &v)
+{
+    return (boost::format("%s((%.9g, %.9g), (%.9g, %.9g))")
+                        % Matrix22Name<float>::value
+                        % v[0][0] % v[0][1]
+                        % v[1][0] % v[1][1]).str();
+}
+
+// Specialization for double to full precision
+template <>
+std::string Matrix22_repr(const Matrix22<double> &v)
+{
+    return (boost::format("%s((%.17g, %.17g), (%.17g, %.17g))")
+                        % Matrix22Name<double>::value
+                        % v[0][0] % v[0][1]
+                        % v[1][0] % v[1][1]).str();
+}
+
+template <class T>
+static const Matrix22<T> &
+invert22 (Matrix22<T> &m, bool singExc = true)
+{
+    MATH_EXC_ON;
+    return m.invert(singExc);
+}
+
+template <class T>
+static Matrix22<T>
+inverse22 (Matrix22<T> &m, bool singExc = true)
+{
+    MATH_EXC_ON;
+    return m.inverse(singExc);
+}
+
+template <class T, class U>
+static const Matrix22<T> &
+iadd22(Matrix22<T> &m, const Matrix22<U> &m2)
+{
+    MATH_EXC_ON;
+    Matrix22<T> m3;
+    m3.setValue (m2);
+    return m += m3;
+}
+
+template <class T>
+static const Matrix22<T> &
+iadd22T(Matrix22<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    return mat += a;
+}
+
+template <class T>
+static Matrix22<T>
+add22(Matrix22<T> &m, const Matrix22<T> &m2)
+{
+    MATH_EXC_ON;
+    return m + m2;
+}
+
+template <class T, class U>
+static const Matrix22<T> &
+isub22(Matrix22<T> &m, const Matrix22<U> &m2)
+{
+    MATH_EXC_ON;
+    Matrix22<T> m3;
+    m3.setValue (m2);
+    return m -= m3;
+}
+
+template <class T>
+static const Matrix22<T> &
+isub22T(Matrix22<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    return mat -= a;
+}
+
+template <class T>
+static Matrix22<T>
+sub22(Matrix22<T> &m, const Matrix22<T> &m2)
+{
+    MATH_EXC_ON;
+    return m - m2;
+}
+
+template <class T>
+static const Matrix22<T> &
+negate22 (Matrix22<T> &m)
+{
+    MATH_EXC_ON;
+    return m.negate();
+}
+
+template <class T>
+static Matrix22<T>
+neg22 (Matrix22<T> &m)
+{
+    MATH_EXC_ON;
+    return -m;
+}
+
+template <class T>
+static const Matrix22<T> &
+imul22T(Matrix22<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m *= t;
+}
+
+template <class T>
+static Matrix22<T>
+mul22T(Matrix22<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m * t;
+}
+
+template <class T>
+static Matrix22<T>
+rmul22T(Matrix22<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return t * m;
+}
+
+template <class T>
+static const Matrix22<T> &
+idiv22T(Matrix22<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m /= t;
+}
+
+template <class T>
+static Matrix22<T>
+div22T(Matrix22<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m / t;
+}
+
+template <class T>
+void
+outerProduct22(Matrix22<T> &mat, const Vec2<T> &a, const Vec2<T> &b)
+{
+    MATH_EXC_ON;
+    mat = IMATH_NAMESPACE::outerProduct(a,b);
+}
+
+template <class TV,class TM>
+static void
+multDirMatrix22(Matrix22<TM> &mat, const Vec2<TV> &src, Vec2<TV> &dst)
+{
+    MATH_EXC_ON;
+    mat.multDirMatrix(src, dst);    
+}
+
+template <class TV,class TM>
+static Vec2<TV>
+multDirMatrix22_return_value(Matrix22<TM> &mat, const Vec2<TV> &src)
+{
+    MATH_EXC_ON;
+    Vec2<TV> dst;
+    mat.multDirMatrix(src, dst);    
+    return dst;
+}
+
+template <class TV,class TM>
+static FixedArray<Vec2<TV> >
+multDirMatrix22_array(Matrix22<TM> &mat, const FixedArray<Vec2<TV> >&src)
+{
+    MATH_EXC_ON;
+    size_t len = src.len();
+    FixedArray<Vec2<TV> > dst(len);
+    for (size_t i=0; i<len; ++i) mat.multDirMatrix(src[i], dst[i]);    
+    return dst;
+}
+
+template <class T>
+static const Matrix22<T> &
+rotate22(Matrix22<T> &mat, const T &r)
+{
+    MATH_EXC_ON;
+    return mat.rotate(r);    
+}
+
+template <class T>
+static void
+extractEuler(Matrix22<T> &mat, Vec2<T> &dstObj)
+{
+    MATH_EXC_ON;
+    T dst;
+    IMATH_NAMESPACE::extractEuler(mat, dst);
+    dstObj.setValue(dst, T (0));
+}
+
+template <class T>
+static const Matrix22<T> &
+scaleSc22(Matrix22<T> &mat, const T &s)
+{
+    MATH_EXC_ON;
+    Vec2<T> sVec(s, s);
+    return mat.scale(sVec);
+}
+
+template <class T>
+static const Matrix22<T> &
+scaleV22(Matrix22<T> &mat, const Vec2<T> &s)
+{
+    MATH_EXC_ON;
+    return mat.scale(s);
+}
+
+template <class T>
+static const Matrix22<T> &
+scale22Tuple(Matrix22<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 2)
+    {
+        Vec2<T> s;
+        s.x = extract<T>(t[0]);
+        s.y = extract<T>(t[1]);
+        
+        return mat.scale(s);
+    }
+    else
+        throw std::invalid_argument ( "m.scale needs tuple of length 2");
+}
+
+template <class T>
+static const Matrix22<T> &
+setRotation22(Matrix22<T> &mat, const T &r)
+{
+    MATH_EXC_ON;
+    return mat.setRotation(r);    
+}
+
+template <class T>
+static const Matrix22<T> &
+setScaleSc22(Matrix22<T> &mat, const T &s)
+{
+    MATH_EXC_ON;
+    return mat.setScale(s);
+}
+
+template <class T>
+static const Matrix22<T> &
+setScaleV22(Matrix22<T> &mat, const Vec2<T> &s)
+{
+    MATH_EXC_ON;
+    return mat.setScale(s);
+}
+
+template <class T>
+static const Matrix22<T> &
+setScale22Tuple(Matrix22<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 2)
+    {
+        Vec2<T> s;
+        s.x = extract<T>(t[0]);
+        s.y = extract<T>(t[1]);
+        
+        return mat.setScale(s);
+    }
+    else
+        throw std::invalid_argument ( "m.setScale needs tuple of length 2");
+}
+
+template <class T>
+static void
+setValue22(Matrix22<T> &mat, const Matrix22<T> &value)
+{
+    MATH_EXC_ON;
+    mat.setValue(value);
+}
+
+template <class T>
+static Matrix22<T>
+subtractTL22(Matrix22<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    Matrix22<T> m(mat.x);
+    for(int i = 0; i < 2; ++i)
+        for(int j = 0; j < 2; ++j)
+            m.x[i][j] -= a;
+    
+    return m;
+}
+
+template <class T>
+static Matrix22<T>
+subtractTR22(Matrix22<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    Matrix22<T> m(mat.x);
+    for(int i = 0; i < 2; ++i)
+        for(int j = 0; j < 2; ++j)
+            m.x[i][j] = a - m.x[i][j];
+    
+    return m;
+}
+
+
+template <class T>
+static Matrix22<T>
+add22T(Matrix22<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    Matrix22<T> m(mat.x);
+    for(int i = 0; i < 2; ++i)
+        for(int j = 0; j < 2; ++j)
+            m.x[i][j] += a;
+    
+    return m;
+}
+
+template <class S, class T>
+static Matrix22<T>
+mul22(Matrix22<T> &mat1, Matrix22<S> &mat2)
+{
+    MATH_EXC_ON;
+    Matrix22<T> mat2T;
+    mat2T.setValue (mat2);
+    return mat1 * mat2T;
+}
+
+template <class S, class T>
+static Matrix22<T>
+rmul22(Matrix22<T> &mat2, Matrix22<S> &mat1)
+{
+    MATH_EXC_ON;
+    Matrix22<T> mat1T;
+    mat1T.setValue (mat1);
+    return mat1T * mat2;
+}
+
+template <class S, class T>
+static const Matrix22<T> &
+imul22(Matrix22<T> &mat1, Matrix22<S> &mat2)
+{
+    MATH_EXC_ON;
+    Matrix22<T> mat2T;
+    mat2T.setValue (mat2);
+    return mat1 *= mat2T;
+}
+
+template <class T>
+static bool
+lessThan22(Matrix22<T> &mat1, const Matrix22<T> &mat2)
+{
+    for(int i = 0; i < 2; ++i){
+        for(int j = 0; j < 2; ++j){
+            if(mat1[i][j] > mat2[i][j]){
+                return false;
+            }
+        }
+    }
+    
+    return (mat1 != mat2);            
+}
+
+template <class T>
+static bool
+lessThanEqual22(Matrix22<T> &mat1, const Matrix22<T> &mat2)
+{
+    for(int i = 0; i < 2; ++i){
+        for(int j = 0; j < 2; ++j){
+            if(mat1[i][j] > mat2[i][j]){
+                return false;
+            }
+        }
+    }
+    
+    return true;            
+}
+
+template <class T>
+static bool
+greaterThan22(Matrix22<T> &mat1, const Matrix22<T> &mat2)
+{
+    for(int i = 0; i < 2; ++i){
+        for(int j = 0; j < 2; ++j){
+            if(mat1[i][j] < mat2[i][j]){
+                std::cout << mat1[i][j] << " " << mat2[i][j] << std::endl;
+                return false;
+            }
+        }
+    }
+    
+    return (mat1 != mat2);            
+}
+
+template <class T>
+static bool
+greaterThanEqual22(Matrix22<T> &mat1, const Matrix22<T> &mat2)
+{
+    for(int i = 0; i < 2; ++i){
+        for(int j = 0; j < 2; ++j){
+            if(mat1[i][j] < mat2[i][j]){
+                return false;
+            }
+        }
+    }
+    
+    return true;            
+}
+
+BOOST_PYTHON_FUNCTION_OVERLOADS(invert22_overloads, invert22, 1, 2);
+BOOST_PYTHON_FUNCTION_OVERLOADS(inverse22_overloads, inverse22, 1, 2);
+BOOST_PYTHON_FUNCTION_OVERLOADS(outerProduct22_overloads, outerProduct22, 3, 3);
+
+template <class T>
+static Matrix22<T> * Matrix2_tuple_constructor(const tuple &t0, const tuple &t1)
+{
+  if(t0.attr("__len__")() == 2 && t1.attr("__len__")() == 2)
+  {
+      return new Matrix22<T>(extract<T>(t0[0]),  extract<T>(t0[1]),
+                             extract<T>(t1[0]),  extract<T>(t1[1]));
+  }
+  else
+    throw std::invalid_argument  ("Matrix22 takes 2 tuples of length 2");
+}
+
+template <class T, class S>
+static Matrix22<T> *Matrix2_matrix_constructor(const Matrix22<S> &mat)
+{
+    Matrix22<T> *m = new Matrix22<T>;
+    
+    for(int i = 0; i < 2; ++i)
+        for(int j = 0; j < 2; ++j)
+            m->x[i][j] = T (mat.x[i][j]);
+    
+    return m;
+}
+
+template <class T>
+class_<Matrix22<T> >
+register_Matrix22()
+{
+    typedef PyImath::StaticFixedArray<Matrix22<T>,T,2,IndexAccessMatrixRow<Matrix22<T>,T,2> > Matrix22_helper;
+
+    MatrixRow<T,2>::register_class();
+    class_<Matrix22<T> > matrix22_class(Matrix22Name<T>::value, Matrix22Name<T>::value,init<Matrix22<T> >("copy construction"));
+    matrix22_class
+        .def(init<>("initialize to identity"))
+        .def(init<T>("initialize all entries to a single value"))
+        .def(init<T,T,T,T>("make from components"))
+        .def("__init__", make_constructor(Matrix2_tuple_constructor<T>))
+        .def("__init__", make_constructor(Matrix2_matrix_constructor<T,float>))
+        .def("__init__", make_constructor(Matrix2_matrix_constructor<T,double>))
+        
+       //.def_readwrite("x00", &Matrix22<T>::x[0][0])
+       //.def_readwrite("x01", &Matrix22<T>::x[0][1])
+       //.def_readwrite("x02", &Matrix22<T>::x[0][2])
+       //.def_readwrite("x10", &Matrix22<T>::x[1][0])
+       //.def_readwrite("x11", &Matrix22<T>::x[1][1])
+       //.def_readwrite("x12", &Matrix22<T>::x[1][2])
+       //.def_readwrite("x20", &Matrix22<T>::x[2][0])
+       //.def_readwrite("x21", &Matrix22<T>::x[2][1])
+       //.def_readwrite("x22", &Matrix22<T>::x[2][2])
+        .def("baseTypeEpsilon", &Matrix22<T>::baseTypeEpsilon,"baseTypeEpsilon() epsilon value of the base type of the vector")
+        .staticmethod("baseTypeEpsilon")
+        .def("baseTypeMax", &Matrix22<T>::baseTypeMax,"baseTypeMax() max value of the base type of the vector")
+        .staticmethod("baseTypeMax")
+        .def("baseTypeLowest", &Matrix22<T>::baseTypeLowest,"baseTypeLowest() largest negative value of the base type of the vector")
+        .staticmethod("baseTypeLowest")
+        .def("baseTypeSmallest", &Matrix22<T>::baseTypeSmallest,"baseTypeSmallest() smallest value of the base type of the vector")
+        .staticmethod("baseTypeSmallest")
+        .def("equalWithAbsError", &Matrix22<T>::equalWithAbsError,"m1.equalWithAbsError(m2,e) true if the elements "
+             "of v1 and v2 are the same with an absolute error of no more than e, "
+             "i.e., abs(m1[i] - m2[i]) <= e")
+        .def("equalWithRelError", &Matrix22<T>::equalWithRelError,"m1.equalWithAbsError(m2,e) true if the elements "
+             "of m1 and m2 are the same with an absolute error of no more than e, "
+             "i.e., abs(m1[i] - m2[i]) <= e * abs(m1[i])")
+        // need a different version for matrix data access
+        .def("__len__", Matrix22_helper::len)
+        .def("__getitem__", Matrix22_helper::getitem)
+       //.def("__setitem__", Matrix22_helper::setitem)
+        .def("makeIdentity",&Matrix22<T>::makeIdentity,"makeIdentity() make this matrix the identity matrix")
+        .def("transpose",&Matrix22<T>::transpose,return_internal_reference<>(),"transpose() transpose this matrix")
+        .def("transposed",&Matrix22<T>::transposed,"transposed() return a transposed copy of this matrix")
+        .def("invert",&invert22<T>,invert22_overloads("invert() invert this matrix")[return_internal_reference<>()])
+        .def("inverse",&inverse22<T>,inverse22_overloads("inverse() return an inverted copy of this matrix"))
+        .def("determinant",&Matrix22<T>::determinant,"determinant() return the determinant of this matrix")
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__iadd__", &iadd22<T, float>,return_internal_reference<>())
+        .def("__iadd__", &iadd22<T, double>,return_internal_reference<>())
+        .def("__iadd__", &iadd22T<T>,return_internal_reference<>())
+        .def("__add__", &add22<T>)
+        .def("__isub__", &isub22<T, float>,return_internal_reference<>())
+        .def("__isub__", &isub22<T, double>,return_internal_reference<>())
+        .def("__isub__", &isub22T<T>,return_internal_reference<>())
+        .def("__sub__", &sub22<T>)
+        .def("negate",&negate22<T>,return_internal_reference<>(),"negate() negate all entries in this matrix")
+        .def("__neg__", &neg22<T>)
+        .def("__imul__", &imul22T<T>,return_internal_reference<>())
+        .def("__mul__", &mul22T<T>)
+        .def("__rmul__", &rmul22T<T>)
+        .def("__idiv__", &idiv22T<T>,return_internal_reference<>())
+        .def("__itruediv__", &idiv22T<T>,return_internal_reference<>())
+        .def("__div__", &div22T<T>)
+        .def("__truediv__", &div22T<T>)
+        .def("__add__", &add22T<T>)
+        .def("__radd__", &add22T<T>)
+        .def("__sub__", &subtractTL22<T>)
+        .def("__rsub__", &subtractTR22<T>)
+        .def("__mul__", &mul22<float, T>)
+        .def("__mul__", &mul22<double, T>)
+        .def("__rmul__", &rmul22<float, T>)
+        .def("__rmul__", &rmul22<double, T>)
+        .def("__imul__", &imul22<float, T>,return_internal_reference<>())
+        .def("__imul__", &imul22<double, T>,return_internal_reference<>())
+        .def("__lt__", &lessThan22<T>)
+        .def("__le__", &lessThanEqual22<T>)
+        .def("__gt__", &greaterThan22<T>)
+        .def("__ge__", &greaterThanEqual22<T>)
+       //.def(self_ns::str(self))
+        .def("__str__",&Matrix22_str<T>)
+        .def("__repr__",&Matrix22_repr<T>)
+
+         .def("extractEuler", &extractEuler<T>,                                
+              "M.extractEuler(r) -- extracts the "
+                         "rotation component of M into r. "
+              "Assumes that M contains no shear or "
+              "non-uniform scaling; results are "
+              "meaningless if it does.")
+              
+         .def("multDirMatrix", &multDirMatrix22<double,T>, "mult matrix")
+         .def("multDirMatrix", &multDirMatrix22_return_value<double,T>, "mult matrix")
+         .def("multDirMatrix", &multDirMatrix22_array<double,T>, "mult matrix")
+         .def("multDirMatrix", &multDirMatrix22<float,T>, "mult matrix")
+         .def("multDirMatrix", &multDirMatrix22_return_value<float,T>, "mult matrix")
+         .def("multDirMatrix", &multDirMatrix22_array<float,T>, "mult matrix")
+
+         .def("rotate", &rotate22<T>, return_internal_reference<>(),"rotate matrix")
+
+         .def("scale", &scaleSc22<T>, return_internal_reference<>(),"scale matrix")
+         .def("scale", &scaleV22<T>, return_internal_reference<>(),"scale matrix")
+         .def("scale", &scale22Tuple<T>, return_internal_reference<>(),"scale matrix")
+
+         .def("setRotation", &setRotation22<T>, return_internal_reference<>(),"setRotation()")
+         .def("setScale", &setScaleSc22<T>, return_internal_reference<>(),"setScale()")
+         .def("setScale", &setScaleV22<T>, return_internal_reference<>(),"setScale()")
+         .def("setScale", &setScale22Tuple<T>, return_internal_reference<>(),"setScale()")
+
+         .def("setValue", &setValue22<T>, "setValue()")
+         ;
+
+    decoratecopy(matrix22_class);
+
+    return matrix22_class;
+/*
+    const Matrix22 &   operator = (const Matrix22 &v);
+    const Matrix22 &   operator = (T a);
+    T *                        getValue ();
+    const T *          getValue () const;
+    template <class S> void getValue (Matrix22<S> &v) const;
+    template <class S> Matrix22 & setValue (const Matrix22<S> &v);
+    template <class S> Matrix22 & setTheMatrix (const Matrix22<S> &v);
+    template <class S> void multVecMatrix(const Vec2<S> &src, Vec2<S> &dst) const;
+    template <class S> void multDirMatrix(const Vec2<S> &src, Vec2<S> &dst) const;
+    template <class S> const Matrix22 &        setRotation (S r);
+    template <class S> const Matrix22 &        rotate (S r);
+    const Matrix22 &   setScale (T s);
+    template <class S> const Matrix22 &        setScale (const Vec2<S> &s);
+    template <class S> const Matrix22 &        scale (const Vec2<S> &s);
+    template <class S> const Matrix22 &        setTranslation (const Vec2<S> &t);
+    Vec2<T>            translation () const;
+    template <class S> const Matrix22 &        translate (const Vec2<S> &t);
+    template <class S> const Matrix22 &        setShear (const S &h);
+    template <class S> const Matrix22 &        setShear (const Vec2<S> &h);
+    template <class S> const Matrix22 &        shear (const S &xy);
+    template <class S> const Matrix22 &        shear (const Vec2<S> &h);
+*/
+}
+
+template <class T>
+static void
+setM22ArrayItem(FixedArray<IMATH_NAMESPACE::Matrix22<T> > &ma,
+                Py_ssize_t index,
+                const IMATH_NAMESPACE::Matrix22<T> &m)
+{
+    ma[ma.canonical_index(index)] = m;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Matrix22<T> > 
+inverse22_array(FixedArray<IMATH_NAMESPACE::Matrix22<T> >&ma, bool singExc = true)
+{
+  MATH_EXC_ON;
+  size_t len = ma.len();
+  FixedArray<IMATH_NAMESPACE::Matrix22<T> > dst(len);
+  for (size_t i=0; i<len; ++i) dst[i] = ma[i].inverse(singExc);    
+  return dst;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Matrix22<T> > &
+invert22_array(FixedArray<IMATH_NAMESPACE::Matrix22<T> >&ma, bool singExc = true)
+{
+  MATH_EXC_ON;
+  size_t len = ma.len();
+  for (size_t i=0; i<len; ++i) ma[i].invert(singExc);    
+  return ma;
+}
+
+BOOST_PYTHON_FUNCTION_OVERLOADS(invert22_array_overloads, invert22_array, 1, 2);
+BOOST_PYTHON_FUNCTION_OVERLOADS(inverse22_array_overloads, inverse22_array, 1, 2);
+
+template <class T>
+class_<FixedArray<IMATH_NAMESPACE::Matrix22<T> > >
+register_M22Array()
+{
+    class_<FixedArray<IMATH_NAMESPACE::Matrix22<T> > > matrixArray_class = FixedArray<IMATH_NAMESPACE::Matrix22<T> >::register_("Fixed length array of IMATH_NAMESPACE::Matrix22");
+    matrixArray_class
+         .def("__setitem__", &setM22ArrayItem<T>)
+         .def("inverse",&inverse22_array<T>,inverse22_array_overloads("inverse() return an inverted copy of this matrix"))
+         .def("invert",&invert22_array<T>,invert22_array_overloads("invert() invert these matricies")[return_internal_reference<>()])
+        ;
+
+    add_comparison_functions(matrixArray_class);
+
+    return matrixArray_class;
+}
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Matrix22<float> > register_Matrix22<float>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Matrix22<double> > register_Matrix22<double>();
+
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Matrix22<float> > > register_M22Array<float>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Matrix22<double> > > register_M22Array<double>();
+
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Matrix22<float> FixedArrayDefaultValue<IMATH_NAMESPACE::Matrix22<float> >::value() { return IMATH_NAMESPACE::Matrix22<float>(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Matrix22<double> FixedArrayDefaultValue<IMATH_NAMESPACE::Matrix22<double> >::value() { return IMATH_NAMESPACE::Matrix22<double>(); }
+}
diff --git a/src/python/PyImath/PyImathMatrix33.cpp b/src/python/PyImath/PyImathMatrix33.cpp
new file mode 100644 (file)
index 0000000..5285083
--- /dev/null
@@ -0,0 +1,1248 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#define BOOST_PYTHON_MAX_ARITY 17
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <boost/python/tuple.hpp>
+#include <boost/python/dict.hpp>
+#include <boost/python/raw_function.hpp>
+#include <ImathVec.h>
+#include <ImathMatrixAlgo.h>
+#include "PyImathMatrix.h"
+#include "PyImathExport.h"
+#include "PyImathDecorators.h"
+#include "PyImath.h"
+#include "PyImathVec.h"
+#include "PyImathMathExc.h"
+
+namespace PyImath {
+
+template<> const char *PyImath::M33fArray::name() { return "M33fArray"; }
+template<> const char *PyImath::M33dArray::name() { return "M33dArray"; }
+
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T, int len>
+struct MatrixRow {
+    explicit MatrixRow(T *data) : _data(data) {}
+    T & operator [] (int i) { return _data[i]; }
+    T *_data;
+
+    static const char *name;
+    static void register_class()
+    {
+        typedef PyImath::StaticFixedArray<MatrixRow,T,len> MatrixRow_helper;
+        class_<MatrixRow> matrixRow_class(name,no_init);
+        matrixRow_class
+            .def("__len__", MatrixRow_helper::len)
+            .def("__getitem__", MatrixRow_helper::getitem,return_value_policy<copy_non_const_reference>())
+            .def("__setitem__", MatrixRow_helper::setitem)
+            ;
+    }
+};
+
+template <> const char *MatrixRow<float,3>::name = "M33fRow";
+template <> const char *MatrixRow<double,3>::name = "M33dRow";
+
+
+template <class Container, class Data, int len>
+struct IndexAccessMatrixRow {
+    typedef MatrixRow<Data,len> result_type;
+    static MatrixRow<Data,len> apply(Container &c, int i) { return MatrixRow<Data,len>(c[i]); }
+};
+
+template <class T> struct Matrix33Name { static const char *value; };
+template<> const char *Matrix33Name<float>::value  = "M33f";
+template<> const char *Matrix33Name<double>::value = "M33d";
+
+template <class T>
+static std::string Matrix33_str(const Matrix33<T> &v)
+{
+    std::stringstream stream;
+    stream << Matrix33Name<T>::value << "(";
+    for (int row = 0; row < 3; row++)
+    {
+        stream << "(";
+       for (int col = 0; col < 3; col++)
+       {
+           stream << v[row][col];
+            stream << (col != 2 ? ", " : "");
+       }
+        stream << ")" << (row != 2 ? ", " : "");
+    }
+    stream << ")";
+    return stream.str();
+}
+
+// Non-specialized repr is same as str
+template <class T>
+static std::string Matrix33_repr(const Matrix33<T> &v)
+{
+    return Matrix33_str(v);
+}
+
+// Specialization for float to full precision
+template <>
+std::string Matrix33_repr(const Matrix33<float> &v)
+{
+    return (boost::format("%s((%.9g, %.9g, %.9g), (%.9g, %.9g, %.9g), (%.9g, %.9g, %.9g))")
+                        % Matrix33Name<float>::value
+                        % v[0][0] % v[0][1] % v[0][2]
+                        % v[1][0] % v[1][1] % v[1][2]
+                        % v[2][0] % v[2][1] % v[2][2]).str();
+}
+
+// Specialization for double to full precision
+template <>
+std::string Matrix33_repr(const Matrix33<double> &v)
+{
+    return (boost::format("%s((%.17g, %.17g, %.17g), (%.17g, %.17g, %.17g), (%.17g, %.17g, %.17g))")
+                        % Matrix33Name<double>::value
+                        % v[0][0] % v[0][1] % v[0][2]
+                        % v[1][0] % v[1][1] % v[1][2]
+                        % v[2][0] % v[2][1] % v[2][2]).str();
+}
+
+template <class T>
+static const Matrix33<T> &
+invert33 (Matrix33<T> &m, bool singExc = true)
+{
+    MATH_EXC_ON;
+    return m.invert(singExc);
+}
+
+template <class T>
+static Matrix33<T>
+inverse33 (Matrix33<T> &m, bool singExc = true)
+{
+    MATH_EXC_ON;
+    return m.inverse(singExc);
+}
+
+template <class T>
+static const Matrix33<T> &
+gjInvert33 (Matrix33<T> &m, bool singExc = true)
+{
+    MATH_EXC_ON;
+    return m.gjInvert(singExc);
+}
+
+template <class T>
+static Matrix33<T>
+gjInverse33 (Matrix33<T> &m, bool singExc = true)
+{
+    MATH_EXC_ON;
+    return m.gjInverse(singExc);
+}
+
+template <class T, class U>
+static const Matrix33<T> &
+iadd33(Matrix33<T> &m, const Matrix33<U> &m2)
+{
+    MATH_EXC_ON;
+    Matrix33<T> m3;
+    m3.setValue (m2);
+    return m += m3;
+}
+
+template <class T>
+static const Matrix33<T> &
+iadd33T(Matrix33<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    return mat += a;
+}
+
+template <class T>
+static Matrix33<T>
+add33(Matrix33<T> &m, const Matrix33<T> &m2)
+{
+    MATH_EXC_ON;
+    return m + m2;
+}
+
+template <class T, class U>
+static const Matrix33<T> &
+isub33(Matrix33<T> &m, const Matrix33<U> &m2)
+{
+    MATH_EXC_ON;
+    Matrix33<T> m3;
+    m3.setValue (m2);
+    return m -= m3;
+}
+
+template <class T>
+static const Matrix33<T> &
+isub33T(Matrix33<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    return mat -= a;
+}
+
+template <class T>
+static Matrix33<T>
+sub33(Matrix33<T> &m, const Matrix33<T> &m2)
+{
+    MATH_EXC_ON;
+    return m - m2;
+}
+
+template <class T>
+static const Matrix33<T> &
+negate33 (Matrix33<T> &m)
+{
+    MATH_EXC_ON;
+    return m.negate();
+}
+
+template <class T>
+static Matrix33<T>
+neg33 (Matrix33<T> &m)
+{
+    MATH_EXC_ON;
+    return -m;
+}
+
+template <class T>
+static const Matrix33<T> &
+imul33T(Matrix33<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m *= t;
+}
+
+template <class T>
+static Matrix33<T>
+mul33T(Matrix33<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m * t;
+}
+
+template <class T>
+static Matrix33<T>
+rmul33T(Matrix33<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return t * m;
+}
+
+template <class T>
+static const Matrix33<T> &
+idiv33T(Matrix33<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m /= t;
+}
+
+template <class T>
+static Matrix33<T>
+div33T(Matrix33<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m / t;
+}
+
+template <class T>
+static void 
+extractAndRemoveScalingAndShear33(Matrix33<T> &mat, IMATH_NAMESPACE::Vec2<T> &dstScl, IMATH_NAMESPACE::Vec2<T> &dstShr, int exc = 1)
+{
+    MATH_EXC_ON;
+    T dstShrTmp;
+    IMATH_NAMESPACE::extractAndRemoveScalingAndShear(mat, dstScl, dstShrTmp, exc);
+
+    dstShr.setValue(dstShrTmp, T (0));
+}
+
+template <class T>
+static void
+extractEuler(Matrix33<T> &mat, Vec2<T> &dstObj)
+{
+    MATH_EXC_ON;
+    T dst;
+    IMATH_NAMESPACE::extractEuler(mat, dst);
+    dstObj.setValue(dst, T (0));
+}
+
+template <class T>
+static int
+extractSHRT33(Matrix33<T> &mat, Vec2<T> &s, Vec2<T> &h, Vec2<T> &r, Vec2<T> &t, int exc = 1)
+{
+    MATH_EXC_ON;
+    T hTmp, rTmp;
+    
+    int b = IMATH_NAMESPACE::extractSHRT(mat, s, hTmp, rTmp, t, exc);
+    
+    h.setValue(hTmp, T (0));
+    r.setValue(rTmp, T (0));
+    
+    return b;
+}
+
+template <class T>
+static void
+extractScaling33(Matrix33<T> &mat, Vec2<T> &dst, int exc = 1)
+{
+    MATH_EXC_ON;
+    IMATH_NAMESPACE::extractScaling(mat, dst, exc);
+}
+
+template <class T>
+void
+outerProduct33(Matrix33<T> &mat, const Vec3<T> &a, const Vec3<T> &b)
+{
+    MATH_EXC_ON;
+    mat = IMATH_NAMESPACE::outerProduct(a,b);
+}
+
+template <class T>
+static void
+extractScalingAndShear33(Matrix33<T> &mat, Vec2<T> &dstScl, Vec2<T> &dstShr, int exc = 1)
+{
+    MATH_EXC_ON;
+    T dstShrTmp;
+    IMATH_NAMESPACE::extractScalingAndShear(mat, dstScl, dstShrTmp, exc);
+    
+    dstShr.setValue(dstShrTmp, T (0));
+}
+
+template <class TV,class TM>
+static void
+multDirMatrix33(Matrix33<TM> &mat, const Vec2<TV> &src, Vec2<TV> &dst)
+{
+    MATH_EXC_ON;
+    mat.multDirMatrix(src, dst);    
+}
+
+template <class TV,class TM>
+static Vec2<TV>
+multDirMatrix33_return_value(Matrix33<TM> &mat, const Vec2<TV> &src)
+{
+    MATH_EXC_ON;
+    Vec2<TV> dst;
+    mat.multDirMatrix(src, dst);    
+    return dst;
+}
+
+template <class TV,class TM>
+static FixedArray<Vec2<TV> >
+multDirMatrix33_array(Matrix33<TM> &mat, const FixedArray<Vec2<TV> >&src)
+{
+    MATH_EXC_ON;
+    size_t len = src.len();
+    FixedArray<Vec2<TV> > dst(len);
+    for (size_t i=0; i<len; ++i) mat.multDirMatrix(src[i], dst[i]);    
+    return dst;
+}
+
+template <class TV,class TM>
+static void
+multVecMatrix33(Matrix33<TM> &mat, const Vec2<TV> &src, Vec2<TV> &dst)
+{
+    MATH_EXC_ON;
+    mat.multVecMatrix(src, dst);    
+}
+
+template <class TV,class TM>
+static Vec2<TV>
+multVecMatrix33_return_value(Matrix33<TM> &mat, const Vec2<TV> &src)
+{
+    MATH_EXC_ON;
+    Vec2<TV> dst;
+    mat.multVecMatrix(src, dst);    
+    return dst;
+}
+
+template <class TV,class TM>
+static FixedArray<Vec2<TV> >
+multVecMatrix33_array(Matrix33<TM> &mat, const FixedArray<Vec2<TV> >&src)
+{
+    MATH_EXC_ON;
+    size_t len = src.len();
+    FixedArray<Vec2<TV> > dst(len);
+    for (size_t i=0; i<len; ++i) mat.multVecMatrix(src[i], dst[i]);    
+    return dst;
+}
+
+template <class T>
+static int
+removeScaling33(Matrix33<T> &mat, int exc = 1)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::removeScaling(mat, exc);
+}
+
+
+template <class T>
+static int
+removeScalingAndShear33(Matrix33<T> &mat, int exc = 1)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::removeScalingAndShear(mat, exc);
+}
+
+template <class T>
+static const Matrix33<T> &
+rotate33(Matrix33<T> &mat, const T &r)
+{
+    MATH_EXC_ON;
+    return mat.rotate(r);    
+}
+
+
+template <class T>
+static Matrix33<T>
+sansScaling33(const Matrix33<T> &mat, bool exc = true)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::sansScaling(mat, exc);
+}
+
+template <class T>
+static Matrix33<T>
+sansScalingAndShear33(const Matrix33<T> &mat, bool exc = true)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::sansScalingAndShear(mat, exc);
+}
+
+template <class T>
+static const Matrix33<T> &
+scaleSc33(Matrix33<T> &mat, const T &s)
+{
+    MATH_EXC_ON;
+    Vec2<T> sVec(s, s);
+    return mat.scale(sVec);
+}
+
+template <class T>
+static const Matrix33<T> &
+scaleV33(Matrix33<T> &mat, const Vec2<T> &s)
+{
+    MATH_EXC_ON;
+    return mat.scale(s);
+}
+
+template <class T>
+static const Matrix33<T> &
+scale33Tuple(Matrix33<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 2)
+    {
+        Vec2<T> s;
+        s.x = extract<T>(t[0]);
+        s.y = extract<T>(t[1]);
+        
+        return mat.scale(s);
+    }
+    else
+      throw std::domain_error ("m.scale needs tuple of length 2");
+}
+
+template <class T>
+static const Matrix33<T> &
+setRotation33(Matrix33<T> &mat, const T &r)
+{
+    MATH_EXC_ON;
+    return mat.setRotation(r);    
+}
+
+template <class T>
+static const Matrix33<T> &
+setScaleSc33(Matrix33<T> &mat, const T &s)
+{
+    MATH_EXC_ON;
+    return mat.setScale(s);
+}
+
+template <class T>
+static const Matrix33<T> &
+setScaleV33(Matrix33<T> &mat, const Vec2<T> &s)
+{
+    MATH_EXC_ON;
+    return mat.setScale(s);
+}
+
+template <class T>
+static const Matrix33<T> &
+setScale33Tuple(Matrix33<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 2)
+    {
+        Vec2<T> s;
+        s.x = extract<T>(t[0]);
+        s.y = extract<T>(t[1]);
+        
+        return mat.setScale(s);
+    }
+    else
+        throw std::invalid_argument ("m.setScale needs tuple of length 2");
+}
+
+template <class T>
+static const Matrix33<T> &
+setShearSc33(Matrix33<T> &mat, const T &h)
+{
+    MATH_EXC_ON;
+    Vec2<T> hVec(h, T(0));    
+    return mat.setShear(hVec);
+}
+
+template <class T>
+static const Matrix33<T> &
+setShearV33(Matrix33<T> &mat, const Vec2<T> &h)
+{
+    MATH_EXC_ON;
+    return mat.setShear(h);
+}
+
+template <class T>
+static const Matrix33<T> &
+setShear33Tuple(Matrix33<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 2)
+    {
+        Vec2<T> h;
+        h.x = extract<T>(t[0]);
+        h.y = extract<T>(t[1]);
+        
+        return mat.setShear(h);
+    }
+    else
+        throw std::domain_error ("m.shear needs tuple of length 2");
+}
+
+template <class T>
+static const Matrix33<T> &
+setTranslation33(Matrix33<T> &mat, const Vec2<T> &t)
+{
+    MATH_EXC_ON;
+    return mat.setTranslation(t);
+}
+
+template <class T>
+static const Matrix33<T> &
+setTranslation33Tuple(Matrix33<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 2)
+    {
+        Vec2<T> trans;
+        trans.x = extract<T>(t[0]);
+        trans.y = extract<T>(t[1]);
+        
+        return mat.setTranslation(trans);
+    }
+    else
+        throw std::domain_error ("m.translate needs tuple of length 2");
+}
+
+template <class T>
+static const Matrix33<T> &
+setTranslation33Obj(Matrix33<T> &mat, const object &o)
+{
+    MATH_EXC_ON;
+    Vec2<T> v;
+    if (PyImath::V2<T>::convert (o.ptr(), &v))
+    {
+        return mat.setTranslation(v);
+    }
+    else
+    {
+        throw std::invalid_argument ("m.setTranslation expected V2 argument");
+        return mat;
+    }   
+}
+
+template <class T>
+static void
+setValue33(Matrix33<T> &mat, const Matrix33<T> &value)
+{
+    MATH_EXC_ON;
+    mat.setValue(value);
+}
+
+template <class T>
+static const Matrix33<T> &
+shearSc33(Matrix33<T> &mat, const T &h)
+{
+    MATH_EXC_ON;
+    Vec2<T> hVec(h, T (0));
+    
+    return mat.shear(hVec);
+}
+
+template <class T>
+static const Matrix33<T> &
+shearV33(Matrix33<T> &mat, const Vec2<T> &h)
+{
+    MATH_EXC_ON;
+    return mat.shear(h);
+}
+
+template <class T>
+static const Matrix33<T> &
+shear33Tuple(Matrix33<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 2)
+    {
+        Vec2<T> h;
+        h.x = extract<T>(t[0]);
+        h.y = extract<T>(t[1]);
+        
+        return mat.shear(h);
+    }
+    else
+        throw std::domain_error ("m.shear needs tuple of length 2");
+}
+
+template <class T>
+static const Matrix33<T> &
+translate33(Matrix33<T> &mat, const object &t)
+{
+    MATH_EXC_ON;
+    Vec2<T> v;
+    if (PyImath::V2<T>::convert (t.ptr(), &v))
+    {
+        return mat.translate(v);
+    }
+    else
+    {
+      throw std::invalid_argument ("m.translate expected V2 argument");
+        return mat;
+    }   
+}
+
+template <class T>
+static const Matrix33<T> &
+translate33Tuple(Matrix33<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 2)
+    {
+        Vec2<T> trans;
+        trans.x = extract<T>(t[0]);
+        trans.y = extract<T>(t[1]);
+        
+        return mat.translate(trans);
+    }
+    else
+        throw std::domain_error ("m.translate needs tuple of length 2");
+}
+
+template <class T>
+static Matrix33<T>
+subtractTL33(Matrix33<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    Matrix33<T> m(mat.x);
+    for(int i = 0; i < 3; ++i)
+        for(int j = 0; j < 3; ++j)
+            m.x[i][j] -= a;
+    
+    return m;
+}
+
+template <class T>
+static Matrix33<T>
+subtractTR33(Matrix33<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    Matrix33<T> m(mat.x);
+    for(int i = 0; i < 3; ++i)
+        for(int j = 0; j < 3; ++j)
+            m.x[i][j] = a - m.x[i][j];
+    
+    return m;
+}
+
+
+template <class T>
+static Matrix33<T>
+add33T(Matrix33<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    Matrix33<T> m(mat.x);
+    for(int i = 0; i < 3; ++i)
+        for(int j = 0; j < 3; ++j)
+            m.x[i][j] += a;
+    
+    return m;
+}
+
+template <class S, class T>
+static Matrix33<T>
+mul33(Matrix33<T> &mat1, Matrix33<S> &mat2)
+{
+    MATH_EXC_ON;
+    Matrix33<T> mat2T;
+    mat2T.setValue (mat2);
+    return mat1 * mat2T;
+}
+
+template <class S, class T>
+static Matrix33<T>
+rmul33(Matrix33<T> &mat2, Matrix33<S> &mat1)
+{
+    MATH_EXC_ON;
+    Matrix33<T> mat1T;
+    mat1T.setValue (mat1);
+    return mat1T * mat2;
+}
+
+template <class S, class T>
+static const Matrix33<T> &
+imul33(Matrix33<T> &mat1, Matrix33<S> &mat2)
+{
+    MATH_EXC_ON;
+    Matrix33<T> mat2T;
+    mat2T.setValue (mat2);
+    return mat1 *= mat2T;
+}
+
+template <class T>
+static bool
+lessThan33(Matrix33<T> &mat1, const Matrix33<T> &mat2)
+{
+    for(int i = 0; i < 3; ++i){
+        for(int j = 0; j < 3; ++j){
+            if(mat1[i][j] > mat2[i][j]){
+                return false;
+            }
+        }
+    }
+    
+    return (mat1 != mat2);            
+}
+
+template <class T>
+static bool
+lessThanEqual33(Matrix33<T> &mat1, const Matrix33<T> &mat2)
+{
+    for(int i = 0; i < 3; ++i){
+        for(int j = 0; j < 3; ++j){
+            if(mat1[i][j] > mat2[i][j]){
+                return false;
+            }
+        }
+    }
+    
+    return true;            
+}
+
+template <class T>
+static bool
+greaterThan33(Matrix33<T> &mat1, const Matrix33<T> &mat2)
+{
+    for(int i = 0; i < 3; ++i){
+        for(int j = 0; j < 3; ++j){
+            if(mat1[i][j] < mat2[i][j]){
+                std::cout << mat1[i][j] << " " << mat2[i][j] << std::endl;
+                return false;
+            }
+        }
+    }
+    
+    return (mat1 != mat2);            
+}
+
+template <class T>
+static bool
+greaterThanEqual33(Matrix33<T> &mat1, const Matrix33<T> &mat2)
+{
+    for(int i = 0; i < 3; ++i){
+        for(int j = 0; j < 3; ++j){
+            if(mat1[i][j] < mat2[i][j]){
+                return false;
+            }
+        }
+    }
+    
+    return true;            
+}
+
+template <class T>
+static tuple
+singularValueDecomposition33(const Matrix33<T>& m, bool forcePositiveDeterminant = false)
+{
+    IMATH_NAMESPACE::Matrix33<T> U, V;
+    IMATH_NAMESPACE::Vec3<T> S;
+    IMATH_NAMESPACE::jacobiSVD (m, U, S, V, std::numeric_limits<T>::epsilon(), forcePositiveDeterminant);
+    return make_tuple (U, S, V);
+}
+
+BOOST_PYTHON_FUNCTION_OVERLOADS(invert33_overloads, invert33, 1, 2);
+BOOST_PYTHON_FUNCTION_OVERLOADS(inverse33_overloads, inverse33, 1, 2);
+BOOST_PYTHON_FUNCTION_OVERLOADS(gjInvert33_overloads, gjInvert33, 1, 2);
+BOOST_PYTHON_FUNCTION_OVERLOADS(gjInverse33_overloads, gjInverse33, 1, 2);
+BOOST_PYTHON_FUNCTION_OVERLOADS(extractAndRemoveScalingAndShear33_overloads, extractAndRemoveScalingAndShear33, 3, 4)
+BOOST_PYTHON_FUNCTION_OVERLOADS(extractSHRT33_overloads, extractSHRT33, 5, 6)
+BOOST_PYTHON_FUNCTION_OVERLOADS(extractScaling33_overloads, extractScaling33, 2, 3)
+BOOST_PYTHON_FUNCTION_OVERLOADS(extractScalingAndShear33_overloads, extractScalingAndShear33, 3, 4)
+BOOST_PYTHON_FUNCTION_OVERLOADS(removeScaling33_overloads, removeScaling33, 1, 2)
+BOOST_PYTHON_FUNCTION_OVERLOADS(removeScalingAndShear33_overloads, removeScalingAndShear33, 1, 2)
+BOOST_PYTHON_FUNCTION_OVERLOADS(sansScaling33_overloads, sansScaling33, 1, 2)
+BOOST_PYTHON_FUNCTION_OVERLOADS(sansScalingAndShear33_overloads, sansScalingAndShear33, 1, 2)
+BOOST_PYTHON_FUNCTION_OVERLOADS(outerProduct33_overloads, outerProduct33, 3, 3);
+
+template <class T>
+static Matrix33<T> * Matrix3_tuple_constructor(const tuple &t0, const tuple &t1, const tuple &t2)
+{
+  if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3 && t2.attr("__len__")() == 3)
+  {
+      return new Matrix33<T>(extract<T>(t0[0]),  extract<T>(t0[1]),  extract<T>(t0[2]),
+                             extract<T>(t1[0]),  extract<T>(t1[1]),  extract<T>(t1[2]),
+                             extract<T>(t2[0]),  extract<T>(t2[1]),  extract<T>(t2[2]));
+  }
+  else
+      throw std::domain_error ("Matrix33 takes 3 tuples of length 3");
+}
+
+template <class T, class S>
+static Matrix33<T> *Matrix3_matrix_constructor(const Matrix33<S> &mat)
+{
+    Matrix33<T> *m = new Matrix33<T>;
+    
+    for(int i = 0; i < 3; ++i)
+        for(int j = 0; j < 3; ++j)
+            m->x[i][j] = T (mat.x[i][j]);
+    
+    return m;
+}
+
+template <class T>
+class_<Matrix33<T> >
+register_Matrix33()
+{
+    typedef PyImath::StaticFixedArray<Matrix33<T>,T,3,IndexAccessMatrixRow<Matrix33<T>,T,3> > Matrix33_helper;
+
+    MatrixRow<T,3>::register_class();
+    class_<Matrix33<T> > matrix33_class(Matrix33Name<T>::value, Matrix33Name<T>::value,init<Matrix33<T> >("copy construction"));
+    matrix33_class
+        .def(init<>("initialize to identity"))
+        .def(init<T>("initialize all entries to a single value"))
+        .def(init<T,T,T,T,T,T,T,T,T>("make from components"))
+        .def("__init__", make_constructor(Matrix3_tuple_constructor<T>))
+        .def("__init__", make_constructor(Matrix3_matrix_constructor<T,float>))
+        .def("__init__", make_constructor(Matrix3_matrix_constructor<T,double>))
+        
+       //.def_readwrite("x00", &Matrix33<T>::x[0][0])
+       //.def_readwrite("x01", &Matrix33<T>::x[0][1])
+       //.def_readwrite("x02", &Matrix33<T>::x[0][2])
+       //.def_readwrite("x10", &Matrix33<T>::x[1][0])
+       //.def_readwrite("x11", &Matrix33<T>::x[1][1])
+       //.def_readwrite("x12", &Matrix33<T>::x[1][2])
+       //.def_readwrite("x20", &Matrix33<T>::x[2][0])
+       //.def_readwrite("x21", &Matrix33<T>::x[2][1])
+       //.def_readwrite("x22", &Matrix33<T>::x[2][2])
+        .def("baseTypeEpsilon", &Matrix33<T>::baseTypeEpsilon,"baseTypeEpsilon() epsilon value of the base type of the vector")
+        .staticmethod("baseTypeEpsilon")
+        .def("baseTypeMax", &Matrix33<T>::baseTypeMax,"baseTypeMax() max value of the base type of the vector")
+        .staticmethod("baseTypeMax")
+        .def("baseTypeLowest", &Matrix33<T>::baseTypeLowest,"baseTypeLowest() largest negative value of the base type of the vector")
+        .staticmethod("baseTypeLowest")
+        .def("baseTypeSmallest", &Matrix33<T>::baseTypeSmallest,"baseTypeSmallest() smallest value of the base type of the vector")
+        .staticmethod("baseTypeSmallest")
+        .def("equalWithAbsError", &Matrix33<T>::equalWithAbsError,"m1.equalWithAbsError(m2,e) true if the elements "
+             "of v1 and v2 are the same with an absolute error of no more than e, "
+             "i.e., abs(m1[i] - m2[i]) <= e")
+        .def("equalWithRelError", &Matrix33<T>::equalWithRelError,"m1.equalWithAbsError(m2,e) true if the elements "
+             "of m1 and m2 are the same with an absolute error of no more than e, "
+             "i.e., abs(m1[i] - m2[i]) <= e * abs(m1[i])")
+        // need a different version for matrix data access
+        .def("__len__", Matrix33_helper::len)
+        .def("__getitem__", Matrix33_helper::getitem)
+       //.def("__setitem__", Matrix33_helper::setitem)
+        .def("makeIdentity",&Matrix33<T>::makeIdentity,"makeIdentity() make this matrix the identity matrix")
+        .def("transpose",&Matrix33<T>::transpose,return_internal_reference<>(),"transpose() transpose this matrix")
+        .def("transposed",&Matrix33<T>::transposed,"transposed() return a transposed copy of this matrix")
+        .def("invert",&invert33<T>,invert33_overloads("invert() invert this matrix")[return_internal_reference<>()])
+        .def("inverse",&inverse33<T>,inverse33_overloads("inverse() return an inverted copy of this matrix"))
+        .def("gjInvert",&gjInvert33<T>,gjInvert33_overloads("gjInvert() invert this matrix")[return_internal_reference<>()])
+        .def("gjInverse",&gjInverse33<T>,gjInverse33_overloads("gjInverse() return an inverted copy of this matrix"))
+        .def("minorOf",&Matrix33<T>::minorOf,"minorOf() return the matrix minor of the (row,col) element of this matrix")
+        .def("fastMinor",&Matrix33<T>::fastMinor,"fastMinor() return the matrix minor using the specified rows and columns of this matrix")
+        .def("determinant",&Matrix33<T>::determinant,"determinant() return the determinant of this matrix")
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__iadd__", &iadd33<T, float>,return_internal_reference<>())
+        .def("__iadd__", &iadd33<T, double>,return_internal_reference<>())
+        .def("__iadd__", &iadd33T<T>,return_internal_reference<>())
+        .def("__add__", &add33<T>)
+        .def("__isub__", &isub33<T, float>,return_internal_reference<>())
+        .def("__isub__", &isub33<T, double>,return_internal_reference<>())
+        .def("__isub__", &isub33T<T>,return_internal_reference<>())
+        .def("__sub__", &sub33<T>)
+        .def("negate",&negate33<T>,return_internal_reference<>(),"negate() negate all entries in this matrix")
+        .def("__neg__", &neg33<T>)
+        .def("__imul__", &imul33T<T>,return_internal_reference<>())
+        .def("__mul__", &mul33T<T>)
+        .def("__rmul__", &rmul33T<T>)
+        .def("__idiv__", &idiv33T<T>,return_internal_reference<>())
+        .def("__itruediv__", &idiv33T<T>,return_internal_reference<>())
+        .def("__div__", &div33T<T>)
+        .def("__truediv__", &div33T<T>)
+        .def("__add__", &add33T<T>)
+        .def("__radd__", &add33T<T>)
+        .def("__sub__", &subtractTL33<T>)
+        .def("__rsub__", &subtractTR33<T>)
+        .def("__mul__", &mul33<float, T>)
+        .def("__mul__", &mul33<double, T>)
+        .def("__rmul__", &rmul33<float, T>)
+        .def("__rmul__", &rmul33<double, T>)
+        .def("__imul__", &imul33<float, T>,return_internal_reference<>())
+        .def("__imul__", &imul33<double, T>,return_internal_reference<>())
+        .def("__lt__", &lessThan33<T>)
+        .def("__le__", &lessThanEqual33<T>)
+        .def("__gt__", &greaterThan33<T>)
+        .def("__ge__", &greaterThanEqual33<T>)
+       //.def(self_ns::str(self))
+        .def("__str__",&Matrix33_str<T>)
+        .def("__repr__",&Matrix33_repr<T>)
+        .def("extractAndRemoveScalingAndShear", &extractAndRemoveScalingAndShear33<T>, 
+              extractAndRemoveScalingAndShear33_overloads(
+              "M.extractAndRemoveScalingAndShear(scl, shr, "
+              "[exc]) -- extracts the scaling component of "
+              "M into scl and the shearing component of M "
+              "into shr.  Also removes the scaling and "
+              "shearing components from M.  "
+              "Returns 1 unless the scaling component is "
+              "nearly 0, in which case 0 is returned. "
+              "If optional arg. exc == 1, then if the "
+              "scaling component is nearly 0, then MathExc "
+              "is thrown. "))
+             
+         .def("extractEuler", &extractEuler<T>,                                
+              "M.extractEulerZYX(r) -- extracts the "
+                         "rotation component of M into r. "
+              "Assumes that M contains no shear or "
+              "non-uniform scaling; results are "
+              "meaningless if it does.")
+              
+         .def("extractSHRT", &extractSHRT33<T>, extractSHRT33_overloads(                               
+              "M.extractSHRT(Vs, Vh, Vr, Vt, [exc]) -- "
+                 "extracts the scaling component of M into Vs, "
+                         "the shearing component of M in Vh (as XY, "
+                 "XZ, YZ shear factors), the rotation of M "
+                 "into Vr (as Euler angles in the order XYZ), "
+                 "and the translaation of M into Vt. "
+                         "If optional arg. exc == 1, then if the "
+                         "scaling component is nearly 0, then MathExc "
+                         "is thrown. "))
+              
+         .def("extractScaling", &extractScaling33<T>, extractScaling33_overloads("extract scaling"))
+         .def("outerProduct", &outerProduct33<T>, outerProduct33_overloads(
+              "M.outerProduct(Va,Vb) -- "
+                  "Performs the outer product, or tensor product, of two 3D vectors, Va and Vb"))
+
+         .def("extractScalingAndShear", &extractScalingAndShear33<T>, extractScalingAndShear33_overloads("extract scaling"))
+        .def("singularValueDecomposition", &singularValueDecomposition33<T>, 
+             "Decomposes the matrix using the singular value decomposition (SVD) into three\n"
+             "matrices U, S, and V which have the following properties: \n"
+             "  1. U and V are both orthonormal matrices, \n"
+             "  2. S is the diagonal matrix of singular values, \n"
+             "  3. U * S * V.transposed() gives back the original matrix.\n"
+             "The result is returned as a tuple [U, S, V].  Note that since S is diagonal we\n"
+             "don't need to return the entire matrix, so we return it as a three-vector.  \n"
+             "\n"
+             "The 'forcePositiveDeterminant' argument can be used to force the U and V^T to\n"
+             "have positive determinant (that is, to be proper rotation matrices); if\n"
+             "forcePositiveDeterminant is False, then the singular values are guaranteed to\n"
+             "be nonnegative but the U and V matrices might contain negative scale along one\n"
+             "of the axes; if forcePositiveDeterminant is True, then U and V cannot contain\n"
+             "negative scale but S[2] might be negative.  \n"
+             "\n"
+             "Our SVD implementation uses two-sided Jacobi rotations to iteratively\n"
+             "diagonalize the matrix, which should be quite robust and significantly faster\n"
+             "than the more general SVD solver in LAPACK.  \n",
+             args("matrix", "forcePositiveDeterminant"))
+        .def("symmetricEigensolve", &PyImath::jacobiEigensolve<IMATH_NAMESPACE::Matrix33<T> >, 
+             "Decomposes the matrix A using a symmetric eigensolver into matrices Q and S \n"
+             "which have the following properties: \n"
+             "  1. Q is the orthonormal matrix of eigenvectors, \n"
+             "  2. S is the diagonal matrix of eigenvalues, \n"
+             "  3. Q * S * Q.transposed() gives back the original matrix.\n"
+             "\n"
+             "IMPORTANT: It is vital that the passed-in matrix be symmetric, or the result \n"
+             "won't make any sense.  This function will return an error if passed an \n"
+             "unsymmetric matrix.\n"
+             "\n"
+             "The result is returned as a tuple [Q, S].  Note that since S is diagonal \n"
+             "we don't need to return the entire matrix, so we return it as a three-vector. \n"
+             "\n"
+             "Our eigensolver implementation uses one-sided Jacobi rotations to iteratively \n"
+             "diagonalize the matrix, which should be quite robust and significantly faster \n"
+             "than the more general symmetric eigenvalue solver in LAPACK.  \n")
+         .def("multDirMatrix", &multDirMatrix33<double,T>, "mult matrix")
+         .def("multDirMatrix", &multDirMatrix33_return_value<double,T>, "mult matrix")
+         .def("multDirMatrix", &multDirMatrix33_array<double,T>, "mult matrix")
+         .def("multDirMatrix", &multDirMatrix33<float,T>, "mult matrix")
+         .def("multDirMatrix", &multDirMatrix33_return_value<float,T>, "mult matrix")
+         .def("multDirMatrix", &multDirMatrix33_array<float,T>, "mult matrix")
+         .def("multVecMatrix", &multVecMatrix33<double,T>, "mult matrix")
+         .def("multVecMatrix", &multVecMatrix33_return_value<double,T>, "mult matrix")
+         .def("multVecMatrix", &multVecMatrix33_array<double,T>, "mult matrix")
+         .def("multVecMatrix", &multVecMatrix33<float,T>, "mult matrix")
+         .def("multVecMatrix", &multVecMatrix33_return_value<float,T>, "mult matrix")
+         .def("multVecMatrix", &multVecMatrix33_array<float,T>, "mult matrix")
+         .def("removeScaling", &removeScaling33<T>, removeScaling33_overloads("remove scaling"))
+
+         .def("removeScalingAndShear", &removeScalingAndShear33<T>, removeScalingAndShear33_overloads("remove scaling"))
+         .def("sansScaling", &sansScaling33<T>, sansScaling33_overloads("sans scaling"))
+         .def("rotate", &rotate33<T>, return_internal_reference<>(),"rotate matrix")
+
+         .def("sansScalingAndShear", &sansScalingAndShear33<T>, sansScalingAndShear33_overloads("sans scaling and shear"))
+         .def("scale", &scaleSc33<T>, return_internal_reference<>(),"scale matrix")
+         .def("scale", &scaleV33<T>, return_internal_reference<>(),"scale matrix")
+         .def("scale", &scale33Tuple<T>, return_internal_reference<>(),"scale matrix")
+
+         .def("setRotation", &setRotation33<T>, return_internal_reference<>(),"setRotation()")
+         .def("setScale", &setScaleSc33<T>, return_internal_reference<>(),"setScale()")
+         .def("setScale", &setScaleV33<T>, return_internal_reference<>(),"setScale()")
+         .def("setScale", &setScale33Tuple<T>, return_internal_reference<>(),"setScale()")
+
+         .def("setShear", &setShearSc33<T>, return_internal_reference<>(),"setShear()")
+         .def("setShear", &setShearV33<T>, return_internal_reference<>(),"setShear()")
+         .def("setShear", &setShear33Tuple<T>, return_internal_reference<>(),"setShear()")
+         
+         .def("setTranslation", &setTranslation33<T>, return_internal_reference<>(),"setTranslation()")
+         .def("setTranslation", &setTranslation33Tuple<T>, return_internal_reference<>(),"setTranslation()")
+         .def("setTranslation", &setTranslation33Obj<T>, return_internal_reference<>(),"setTranslation()")
+         .def("setValue", &setValue33<T>, "setValue()")
+         .def("shear", &shearSc33<T>, return_internal_reference<>(),"shear()")
+         .def("shear", &shearV33<T>, return_internal_reference<>(),"shear()")
+         .def("shear", &shear33Tuple<T>, return_internal_reference<>(),"shear()")
+         .def("translate", &translate33<T>, return_internal_reference<>(),"translate()")
+         .def("translate", &translate33Tuple<T>, return_internal_reference<>(),"translate()")
+         .def("translation", &Matrix33<T>::translation, "translation()")
+         ;
+
+    decoratecopy(matrix33_class);
+
+    return matrix33_class;
+/*
+    const Matrix33 &   operator = (const Matrix33 &v);
+    const Matrix33 &   operator = (T a);
+    T *                        getValue ();
+    const T *          getValue () const;
+    template <class S> void getValue (Matrix33<S> &v) const;
+    template <class S> Matrix33 & setValue (const Matrix33<S> &v);
+    template <class S> Matrix33 & setTheMatrix (const Matrix33<S> &v);
+    template <class S> void multVecMatrix(const Vec2<S> &src, Vec2<S> &dst) const;
+    template <class S> void multDirMatrix(const Vec2<S> &src, Vec2<S> &dst) const;
+    template <class S> const Matrix33 &        setRotation (S r);
+    template <class S> const Matrix33 &        rotate (S r);
+    const Matrix33 &   setScale (T s);
+    template <class S> const Matrix33 &        setScale (const Vec2<S> &s);
+    template <class S> const Matrix33 &        scale (const Vec2<S> &s);
+    template <class S> const Matrix33 &        setTranslation (const Vec2<S> &t);
+    Vec2<T>            translation () const;
+    template <class S> const Matrix33 &        translate (const Vec2<S> &t);
+    template <class S> const Matrix33 &        setShear (const S &h);
+    template <class S> const Matrix33 &        setShear (const Vec2<S> &h);
+    template <class S> const Matrix33 &        shear (const S &xy);
+    template <class S> const Matrix33 &        shear (const Vec2<S> &h);
+*/
+}
+
+template <class T>
+struct Matrix33Array_Constructor : public Task
+{
+    const FixedArray<T> &a; const FixedArray<T> &b; const FixedArray<T> &c;
+    const FixedArray<T> &d; const FixedArray<T> &e; const FixedArray<T> &f;
+    const FixedArray<T> &g; const FixedArray<T> &h; const FixedArray<T> &i;
+    FixedArray<IMATH_NAMESPACE::Matrix33<T> > &result;
+
+    Matrix33Array_Constructor (const FixedArray<T> &a, const FixedArray<T> &b, const FixedArray<T> &c,
+                               const FixedArray<T> &d, const FixedArray<T> &e, const FixedArray<T> &f,
+                               const FixedArray<T> &g, const FixedArray<T> &h, const FixedArray<T> &i,
+                               FixedArray<IMATH_NAMESPACE::Matrix33<T> > &result)
+        : a (a), b (b), c (c), 
+          d (d), e (e), f (f), 
+          g (g), h (h), i (i), result (result) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t index = start; index < end; ++index)
+        {
+            result[index] = IMATH_NAMESPACE::Matrix33<T>(a[index], b[index], c[index], 
+                                                         d[index], e[index], f[index], 
+                                                         g[index], h[index], i[index]);
+        }
+    }
+};
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Matrix33<T> > *
+M33Array_constructor(const FixedArray<T> &a, const FixedArray<T> &b, const FixedArray<T> &c,
+                     const FixedArray<T> &d, const FixedArray<T> &e, const FixedArray<T> &f,
+                     const FixedArray<T> &g, const FixedArray<T> &h, const FixedArray<T> &i)
+{
+    MATH_EXC_ON;
+    Py_ssize_t len = a.len();
+    if (!( a.len() == len && b.len() == len && c.len() == len && 
+           d.len() == len && e.len() == len && f.len() == len && 
+           g.len() == len && h.len() == len && i.len() == len))
+        throw std::invalid_argument("Dimensions do not match" );
+    FixedArray<IMATH_NAMESPACE::Matrix33<T> >* result =
+        new FixedArray<IMATH_NAMESPACE::Matrix33<T> > (Py_ssize_t(len), UNINITIALIZED);
+
+    Matrix33Array_Constructor<T> task (a, b, c, d, e, f, g, h, i, *result);
+    dispatchTask (task, len);
+    return result;
+}
+
+template <class T>
+static void
+setM33ArrayItem(FixedArray<IMATH_NAMESPACE::Matrix33<T> > &ma,
+                Py_ssize_t index,
+                const IMATH_NAMESPACE::Matrix33<T> &m)
+{
+    ma[ma.canonical_index(index)] = m;
+}
+
+
+template <class T>
+struct M33Array_Inverse : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Matrix33<T> > &mats;
+    FixedArray<IMATH_NAMESPACE::Matrix33<T> >       &result;
+
+    M33Array_Inverse (FixedArray<IMATH_NAMESPACE::Matrix33<T> >        &result,
+                       const FixedArray<IMATH_NAMESPACE::Matrix33<T> > &mats)
+        : mats (mats), result (result) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+            result[i] = mats[i].inverse();
+    } 
+};
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Matrix33<T> >
+M33Array_inverse(const FixedArray<IMATH_NAMESPACE::Matrix33<T> > &ma)
+{
+    MATH_EXC_ON;
+    size_t len = ma.len();
+    FixedArray<IMATH_NAMESPACE::Matrix33<T> > result (len);
+
+    M33Array_Inverse<T> task (result, ma);
+    dispatchTask (task, len);
+
+    return result;
+}
+
+template <class T>
+struct M33Array_RmulVec3 : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Matrix33<T> > &a;
+    const Vec3<T>                                   &v;
+    FixedArray<Vec3<T> >                            &r;
+
+    M33Array_RmulVec3 (const FixedArray<IMATH_NAMESPACE::Matrix33<T> > &a,
+                       const Vec3<T>                                   &v, 
+                       FixedArray<Vec3<T> >                            &r)
+        : a (a), v (v), r (r) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            r[i] = v * a[i];
+        }
+    }
+};
+
+template <class T>
+static FixedArray< Vec3<T> >
+M33Array_rmulVec3 (const FixedArray< IMATH_NAMESPACE::Matrix33<T> > &a, const Vec3<T> &v)
+{
+    MATH_EXC_ON;
+    size_t len = a.len();
+    FixedArray< Vec3<T> > r (Py_ssize_t(len), UNINITIALIZED);
+
+    M33Array_RmulVec3<T> task (a, v, r);
+    dispatchTask (task, len);
+    return r;
+}
+
+template <class T>
+struct M33Array_RmulVec3Array : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Matrix33<T> > &a;
+    const FixedArray<Vec3<T> >                      &b;
+    FixedArray<Vec3<T> >                            &r;
+
+    M33Array_RmulVec3Array (const FixedArray<IMATH_NAMESPACE::Matrix33<T> > &a,
+                            const FixedArray<Vec3<T> >                      &b,
+                            FixedArray<Vec3<T> >                            &r)
+        : a (a), b (b), r (r) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            r[i] = b[i] * a[i];
+        }
+    }
+};
+
+template <class T>
+static FixedArray< Vec3<T> >
+M33Array_rmulVec3Array (const FixedArray< IMATH_NAMESPACE::Matrix33<T> > &a,
+                        const FixedArray< Vec3<T> > &b)
+{
+    MATH_EXC_ON;
+    size_t len = a.match_dimension(b);
+    FixedArray< Vec3<T> > r (Py_ssize_t(len), UNINITIALIZED);
+
+    M33Array_RmulVec3Array<T> task (a, b, r);
+    dispatchTask (task, len);
+    return r;
+}
+
+template <class T>
+class_<FixedArray<IMATH_NAMESPACE::Matrix33<T> > >
+register_M33Array()
+{
+    class_<FixedArray<IMATH_NAMESPACE::Matrix33<T> > > matrixArray_class = FixedArray<IMATH_NAMESPACE::Matrix33<T> >::register_("Fixed length array of IMATH_NAMESPACE::Matrix33");
+    matrixArray_class
+         .def("__init__", make_constructor(M33Array_constructor<T>))
+         .def("__setitem__", &setM33ArrayItem<T>)
+         .def("inverse", &M33Array_inverse<T>,
+             "Return M^-1 for each element M.",
+             (args("vector")))
+         .def("__rmul__", &M33Array_rmulVec3<T>)
+         .def("__rmul__", &M33Array_rmulVec3Array<T>)
+        ;
+
+    add_comparison_functions(matrixArray_class);
+
+    return matrixArray_class;
+}
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Matrix33<float> > register_Matrix33<float>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Matrix33<double> > register_Matrix33<double>();
+
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Matrix33<float> > > register_M33Array<float>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Matrix33<double> > > register_M33Array<double>();
+
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Matrix33<float> FixedArrayDefaultValue<IMATH_NAMESPACE::Matrix33<float> >::value() { return IMATH_NAMESPACE::Matrix33<float>(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Matrix33<double> FixedArrayDefaultValue<IMATH_NAMESPACE::Matrix33<double> >::value() { return IMATH_NAMESPACE::Matrix33<double>(); }
+}
diff --git a/src/python/PyImath/PyImathMatrix44.cpp b/src/python/PyImath/PyImathMatrix44.cpp
new file mode 100644 (file)
index 0000000..ed9c25c
--- /dev/null
@@ -0,0 +1,1507 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#define BOOST_PYTHON_MAX_ARITY 17
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <boost/python/tuple.hpp>
+#include <boost/python/dict.hpp>
+#include <boost/python/raw_function.hpp>
+#include <ImathVec.h>
+#include <ImathMatrixAlgo.h>
+#include "PyImath.h"
+#include "PyImathVec.h"
+#include "PyImathMathExc.h"
+#include "PyImathMatrix.h"
+#include "PyImathExport.h"
+#include "PyImathDecorators.h"
+#include "PyImathTask.h"
+
+namespace PyImath {
+template<> const char PYIMATH_EXPORT *PyImath::M44fArray::name() { return "M44fArray"; }
+template<> const char PYIMATH_EXPORT *PyImath::M44dArray::name() { return "M44dArray"; }
+
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+using namespace PyImath;
+
+template <class T, int len>
+struct MatrixRow {
+    explicit MatrixRow(T *data) : _data(data) {}
+    T & operator [] (int i) { return _data[i]; }
+    T *_data;
+
+    static const char *name;
+    static void register_class()
+    {
+        typedef PyImath::StaticFixedArray<MatrixRow,T,len> MatrixRow_helper;
+        class_<MatrixRow> matrixRow_class(name,no_init);
+        matrixRow_class
+            .def("__len__", MatrixRow_helper::len)
+            .def("__getitem__", MatrixRow_helper::getitem,return_value_policy<copy_non_const_reference>())
+            .def("__setitem__", MatrixRow_helper::setitem)
+            ;
+    }
+};
+
+template <> const char *MatrixRow<float,4>::name = "M44fRow";
+template <> const char *MatrixRow<double,4>::name = "M44dRow";
+
+
+template <class Container, class Data, int len>
+struct IndexAccessMatrixRow {
+    typedef MatrixRow<Data,len> result_type;
+    static MatrixRow<Data,len> apply(Container &c, int i) { return MatrixRow<Data,len>(c[i]); }
+};
+
+template <class T> struct Matrix44Name { static const char *value; };
+template<> const char *Matrix44Name<float>::value  = "M44f";
+template<> const char *Matrix44Name<double>::value = "M44d";
+
+template <class T>
+static std::string Matrix44_str(const Matrix44<T> &v)
+{
+    std::stringstream stream;
+    stream << Matrix44Name<T>::value << "(";
+    for (int row = 0; row < 4; row++)
+    {
+        stream << "(";
+       for (int col = 0; col < 4; col++)
+       {
+           stream << v[row][col];
+            stream << (col != 3 ? ", " : "");
+       }
+        stream << ")" << (row != 3 ? ", " : "");
+    }
+    stream << ")";
+    return stream.str();
+}
+
+// Non-specialized repr is same as str
+template <class T>
+static std::string Matrix44_repr(const Matrix44<T> &v)
+{
+    return Matrix44_str(v);
+}
+
+// Specialization for float to full precision
+template <>
+std::string Matrix44_repr(const Matrix44<float> &v)
+{
+    return (boost::format("%s((%.9g, %.9g, %.9g, %.9g), (%.9g, %.9g, %.9g, %.9g), (%.9g, %.9g, %.9g, %.9g), (%.9g, %.9g, %.9g, %.9g))")
+                        % Matrix44Name<float>::value
+                        % v[0][0] % v[0][1] % v[0][2] % v[0][3]
+                        % v[1][0] % v[1][1] % v[1][2] % v[1][3]
+                        % v[2][0] % v[2][1] % v[2][2] % v[2][3]
+                        % v[3][0] % v[3][1] % v[3][2] % v[3][3]).str();
+}
+
+// Specialization for double to full precision
+template <>
+std::string Matrix44_repr(const Matrix44<double> &v)
+{
+    return (boost::format("%s((%.17g, %.17g, %.17g, %.17g), (%.17g, %.17g, %.17g, %.17g), (%.17g, %.17g, %.17g, %.17g), (%.17g, %.17g, %.17g, %.17g))")
+                        % Matrix44Name<double>::value
+                        % v[0][0] % v[0][1] % v[0][2] % v[0][3]
+                        % v[1][0] % v[1][1] % v[1][2] % v[1][3]
+                        % v[2][0] % v[2][1] % v[2][2] % v[2][3]
+                        % v[3][0] % v[3][1] % v[3][2] % v[3][3]).str();
+}
+
+template <class T>
+static const Matrix44<T> &
+invert44 (Matrix44<T> &m, bool singExc = true)
+{
+    MATH_EXC_ON;
+    return m.invert(singExc);
+}
+
+template <class T>
+static Matrix44<T>
+inverse44 (Matrix44<T> &m, bool singExc = true)
+{
+    MATH_EXC_ON;
+    return m.inverse(singExc);
+}
+
+template <class T>
+static const Matrix44<T> &
+gjInvert44 (Matrix44<T> &m, bool singExc = true)
+{
+    MATH_EXC_ON;
+    return m.gjInvert(singExc);
+}
+
+template <class T>
+static Matrix44<T>
+gjInverse44 (Matrix44<T> &m, bool singExc = true)
+{
+    MATH_EXC_ON;
+    return m.gjInverse(singExc);
+}
+
+template <class T, class U>
+static const Matrix44<T> &
+iadd44(Matrix44<T> &m, const Matrix44<U> &m2)
+{
+    MATH_EXC_ON;
+    Matrix44<T> m3;
+    m3.setValue (m2);
+    return m += m3;
+}
+
+template <class T>
+static const Matrix44<T> &
+iadd44T(Matrix44<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    return mat += a;
+}
+
+template <class T>
+static Matrix44<T>
+add44(Matrix44<T> &m, const Matrix44<T> &m2)
+{
+    MATH_EXC_ON;
+    return m + m2;
+}
+
+template <class T, class U>
+static const Matrix44<T> &
+isub44(Matrix44<T> &m, const Matrix44<U> &m2)
+{
+    MATH_EXC_ON;
+    Matrix44<T> m3;
+    m3.setValue (m2);
+    return m -= m3;
+}
+
+template <class T>
+static const Matrix44<T> &
+isub44T(Matrix44<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    return mat -= a;
+}
+
+template <class T>
+static Matrix44<T>
+sub44(Matrix44<T> &m, const Matrix44<T> &m2)
+{
+    MATH_EXC_ON;
+    return m - m2;
+}
+
+template <class T>
+static const Matrix44<T> &
+negate44 (Matrix44<T> &m)
+{
+    MATH_EXC_ON;
+    return m.negate();
+}
+
+template <class T>
+static Matrix44<T>
+neg44 (Matrix44<T> &m)
+{
+    MATH_EXC_ON;
+    return -m;
+}
+
+template <class T>
+static const Matrix44<T> &
+imul44T(Matrix44<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m *= t;
+}
+
+template <class T>
+static Matrix44<T>
+mul44T(Matrix44<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m * t;
+}
+
+template <class T>
+static Matrix44<T>
+rmul44T(Matrix44<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return t * m;
+}
+
+template <class T>
+static const Matrix44<T> &
+idiv44T(Matrix44<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m /= t;
+}
+
+template <class T>
+static Matrix44<T>
+div44T(Matrix44<T> &m, const T &t)
+{
+    MATH_EXC_ON;
+    return m / t;
+}
+
+template <class T>
+static void 
+extractAndRemoveScalingAndShear44(Matrix44<T> &mat, Vec3<T> &dstScl, Vec3<T> &dstShr, int exc = 1)
+{
+    MATH_EXC_ON;
+    IMATH_NAMESPACE::extractAndRemoveScalingAndShear(mat, dstScl, dstShr, exc);
+}
+
+template <class T>
+static void
+extractEulerXYZ(Matrix44<T> &mat, IMATH_NAMESPACE::Vec3<T> &dst)
+{
+    MATH_EXC_ON;
+    IMATH_NAMESPACE::extractEulerXYZ(mat, dst);
+}
+
+template <class T>
+static void
+extractEulerZYX(Matrix44<T> &mat, IMATH_NAMESPACE::Vec3<T> &dst)
+{
+    MATH_EXC_ON;
+    IMATH_NAMESPACE::extractEulerZYX(mat, dst);
+}
+
+template <class T>
+static int
+extractSHRT44(Matrix44<T> &mat, Vec3<T> &s, Vec3<T> &h, Vec3<T> &r, Vec3<T> &t, int exc = 1)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::extractSHRT(mat, s, h, r, t, exc);
+}
+
+template <class T>
+static void
+extractScaling44(Matrix44<T> &mat, Vec3<T> &dst, int exc = 1)
+{
+    MATH_EXC_ON;
+    IMATH_NAMESPACE::extractScaling(mat, dst, exc);
+}
+
+template <class T>
+static void
+extractScalingAndShear44(Matrix44<T> &mat, Vec3<T> &dstScl, Vec3<T> &dstShr, int exc = 1)
+{
+    MATH_EXC_ON;
+    IMATH_NAMESPACE::extractScalingAndShear(mat, dstScl, dstShr, exc);
+}
+
+template <class TV,class TM>
+static void
+multDirMatrix44(Matrix44<TM> &mat, const Vec3<TV> &src, Vec3<TV> &dst)
+{
+    MATH_EXC_ON;
+    mat.multDirMatrix(src, dst);    
+}
+
+template <class TV,class TM>
+static Vec3<TV>
+multDirMatrix44_return_value(Matrix44<TM> &mat, const Vec3<TV> &src)
+{
+    MATH_EXC_ON;
+    Vec3<TV> dst;
+    mat.multDirMatrix(src, dst);    
+    return dst;
+}
+
+template <class T1, class T2>
+struct op_multDirMatrix {
+
+    static inline void apply(const Matrix44<T2>& m, const Vec3<T1>& src, Vec3<T1>& dst)
+    {
+        m.multDirMatrix(src,dst);
+    }
+};
+
+template <class T1, class T2>
+struct op_multVecMatrix {
+
+    static inline void apply(const Matrix44<T2>& m, const Vec3<T1>& src, Vec3<T1>& dst)
+    {
+        m.multVecMatrix(src,dst);
+    }
+};
+
+template <class T1,class T2, class Op>
+struct MatrixVecTask : public Task
+{
+    const Matrix44<T2> &mat;
+    const FixedArray<Vec3<T1> >& src;
+    FixedArray<Vec3<T1> >& dst;
+
+    MatrixVecTask(const Matrix44<T2> &m, const FixedArray<Vec3<T1> >& s, FixedArray<Vec3<T1> >& d)
+        : mat(m), src(s), dst(d) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for(size_t p = start; p < end; ++p) 
+            Op::apply(mat,src[p],dst[p]);
+    }
+};
+
+template <class TV,class TM>
+static FixedArray<Vec3<TV> >
+multDirMatrix44_array(Matrix44<TM> &mat, const FixedArray<Vec3<TV> >&src)
+{
+    MATH_EXC_ON;
+    size_t len = src.len();
+    FixedArray<Vec3<TV> > dst(len);
+
+    MatrixVecTask<TV,TM,op_multDirMatrix<TV,TM> > task(mat,src,dst);
+    dispatchTask(task,len);
+
+    return dst;
+}
+
+template <class TV,class TM>
+static void
+multVecMatrix44(Matrix44<TM> &mat, const Vec3<TV> &src, Vec3<TV> &dst)
+{
+    MATH_EXC_ON;
+    mat.multVecMatrix(src, dst);    
+}
+
+template <class TV,class TM>
+static Vec3<TV>
+multVecMatrix44_return_value(Matrix44<TM> &mat, const Vec3<TV> &src)
+{
+    MATH_EXC_ON;
+    Vec3<TV> dst;
+    mat.multVecMatrix(src, dst);    
+    return dst;
+}
+
+
+template <class TV,class TM>
+static FixedArray<Vec3<TV> >
+multVecMatrix44_array(Matrix44<TM> &mat, const FixedArray<Vec3<TV> >&src)
+{
+    MATH_EXC_ON;
+    size_t len = src.len();
+    FixedArray<Vec3<TV> > dst(len);
+
+    MatrixVecTask<TV,TM,op_multVecMatrix<TV,TM> > task(mat,src,dst);
+    dispatchTask(task,len);
+
+    return dst;
+}
+
+template <class T>
+static int
+removeScaling44(Matrix44<T> &mat, int exc = 1)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::removeScaling(mat, exc);
+}
+
+template <class T>
+static int
+removeScalingAndShear44(Matrix44<T> &mat, int exc = 1)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::removeScalingAndShear(mat, exc);
+}
+
+template <class T>
+static Matrix44<T>
+sansScaling44(const Matrix44<T> &mat, bool exc = true)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::sansScaling(mat, exc);
+}
+
+template <class T>
+static Matrix44<T>
+sansScalingAndShear44(const Matrix44<T> &mat, bool exc = true)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::sansScalingAndShear(mat, exc);
+}
+
+
+template <class T>
+static const Matrix44<T> &
+scaleSc44(Matrix44<T> &mat, const T &s)
+{
+    MATH_EXC_ON;
+    Vec3<T> sVec(s, s, s);
+    return mat.scale(sVec);
+}
+
+template <class T>
+static const Matrix44<T> &
+scaleV44(Matrix44<T> &mat, const Vec3<T> &s)
+{
+    MATH_EXC_ON;
+    return mat.scale(s);
+}
+
+template <class T>
+static const Matrix44<T> &
+scale44Tuple(Matrix44<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> s;
+        s.x = extract<T>(t[0]);
+        s.y = extract<T>(t[1]);
+        s.z = extract<T>(t[2]);
+        
+        return mat.scale(s);
+    }
+    else
+        throw std::domain_error ("m.scale needs tuple of length 3");
+}
+
+template <class T>
+static const Matrix44<T> &
+rotateV44(Matrix44<T> &mat, const Vec3<T> &r)
+{
+    MATH_EXC_ON;
+    return mat.rotate(r);
+}
+
+template <class T>
+static const Matrix44<T> &
+rotationMatrix44(Matrix44<T> &mat, const object &fromObj, const object &toObj)
+{
+    MATH_EXC_ON;
+    Vec3<T> from, to;
+    if (PyImath::V3<T>::convert (fromObj.ptr(), &from) &&
+        PyImath::V3<T>::convert (toObj.ptr(), &to))
+    {
+        Matrix44<T> rot = IMATH_NAMESPACE::rotationMatrix(from, to);
+        return mat.setValue(rot);
+    }
+    else
+    {
+      throw std::invalid_argument ("m.rotationMatrix expected V3 arguments");
+    }   
+}
+
+template <class T>
+static const Matrix44<T> &
+rotationMatrixWithUp44(Matrix44<T> &mat, const object &fromObj, const object &toObj,
+                       const object &upObj)
+{
+    MATH_EXC_ON;
+    Vec3<T> from, to, up;
+    if (PyImath::V3<T>::convert (fromObj.ptr(), &from) &&
+        PyImath::V3<T>::convert (toObj.ptr(), &to) &
+        PyImath::V3<T>::convert (upObj.ptr(), &up))
+    {
+        Matrix44<T> rot = IMATH_NAMESPACE::rotationMatrixWithUpDir(from, to, up);
+        return mat.setValue(rot);
+    }
+    else
+    {
+      throw std::invalid_argument ("m.rotationMatrix expected V3 arguments");
+    }   
+}
+
+template <class T>
+static const Matrix44<T> &
+setScaleSc44(Matrix44<T> &mat, const T &s)
+{
+    MATH_EXC_ON;
+    return mat.setScale(s);
+}
+
+template <class T>
+static const Matrix44<T> &
+setScaleV44(Matrix44<T> &mat, const Vec3<T> &s)
+{
+    MATH_EXC_ON;
+    return mat.setScale(s);
+}
+
+template <class T>
+static const Matrix44<T> &
+setScale44Tuple(Matrix44<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> s;
+        s.x = extract<T>(t[0]);
+        s.y = extract<T>(t[1]);
+        s.z = extract<T>(t[2]);
+        
+        return mat.setScale(s);
+    }
+    else
+        throw std::domain_error ("m.translate needs tuple of length 3");
+}
+
+
+template <class T>
+static const Matrix44<T> &
+setShearV44(Matrix44<T> &mat, const Vec3<T> &sVec)
+{
+    MATH_EXC_ON;
+    return mat.setShear(sVec);
+}
+
+template <class T>
+static const Matrix44<T> &
+setShearS44(Matrix44<T> &mat, const Shear6<T> &s)
+{
+    MATH_EXC_ON;
+    return mat.setShear(s);
+}
+
+template <class T>
+static const Matrix44<T> &
+setShear44Tuple(Matrix44<T> &mat, const tuple &t)
+{    
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> s;
+        s.x = extract<T>(t[0]);
+        s.y = extract<T>(t[1]);
+        s.z = extract<T>(t[2]);
+        
+        return mat.setShear(s);
+    }
+    else if(t.attr("__len__")() == 6)
+    {
+        Shear6<T> shear;
+        for(int i = 0; i < 6; ++i)
+        {
+            shear[i] = extract<T>(t[i]);
+        }
+        
+        return mat.setShear(shear);
+    }
+    else
+        throw std::domain_error ("m.setShear needs tuple of length 3 or 6");
+}
+
+template <class T>
+static const Matrix44<T> &
+setTranslation44(Matrix44<T> &mat, const Vec3<T> t)
+{
+    MATH_EXC_ON;
+    return mat.setTranslation(t);
+}
+
+template <class T>
+static const Matrix44<T> &
+setTranslation44Tuple(Matrix44<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> trans;
+        trans.x = extract<T>(t[0]);
+        trans.y = extract<T>(t[1]);
+        trans.z = extract<T>(t[2]);
+        
+        return mat.setTranslation(trans);
+    }
+    else
+        throw std::domain_error ("m.translate needs tuple of length 3");
+}
+
+template <class T>
+static const Matrix44<T> &
+setTranslation44Obj(Matrix44<T> &mat, const object &o)
+{
+    MATH_EXC_ON;
+    Vec3<T> v;
+    if (PyImath::V3<T>::convert (o.ptr(), &v))
+    {
+        return mat.setTranslation(v);
+    }
+    else
+    {
+      throw std::invalid_argument ("m.setTranslation expected V3 argument");
+        return mat;
+    }   
+}
+
+template <class T>
+static void
+setValue44(Matrix44<T> &mat, const Matrix44<T> &value)
+{
+    MATH_EXC_ON;
+    mat.setValue(value);
+}
+
+template <class T>
+static const Matrix44<T> &
+shearV44(Matrix44<T> &mat, const Vec3<T> &s)
+{
+    MATH_EXC_ON;
+    IMATH_NAMESPACE::Shear6<T> shear(s[0], s[1], s[2], T (0), T (0), T (0));
+    return mat.shear(shear);
+}
+
+template <class T>
+static const Matrix44<T> &
+shearS44(Matrix44<T> &mat, const Shear6<T> &s)
+{
+    MATH_EXC_ON;
+    return mat.shear(s);
+}
+
+template <class T>
+static const Matrix44<T> &
+shear44Tuple(Matrix44<T> &mat, const tuple &t)
+{    
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> s;
+        s.x = extract<T>(t[0]);
+        s.y = extract<T>(t[1]);
+        s.z = extract<T>(t[2]);
+        Shear6<T> shear(s);
+
+        return mat.shear(shear);
+    }
+    else if(t.attr("__len__")() == 6)
+    {
+        Shear6<T> shear;
+        for(int i = 0; i < 6; ++i)
+        {
+            shear[i] = extract<T>(t[i]);
+        }
+        
+        return mat.shear(shear);
+    }
+    else
+        throw std::domain_error ("m.shear needs tuple of length 3 or 6");
+}
+
+
+template <class T>
+static const Matrix44<T> &
+translate44(Matrix44<T> &mat, const object &t)
+{
+    MATH_EXC_ON;
+    Vec3<T> v;
+    if (PyImath::V3<T>::convert (t.ptr(), &v))
+    {
+        return mat.translate(v);
+    }
+    else
+    {
+      throw std::invalid_argument ("m.translate expected V3 argument");
+        return mat;
+    }   
+}
+template <class T>
+static const Matrix44<T> &
+translate44Tuple(Matrix44<T> &mat, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> trans;
+        trans.x = extract<T>(t[0]);
+        trans.y = extract<T>(t[1]);
+        trans.z = extract<T>(t[2]);
+        
+        return mat.translate(trans);
+    }
+    else
+        throw std::domain_error ("m.translate needs tuple of length 3");
+}
+
+template <class T>
+static Matrix44<T>
+subtractTL44(Matrix44<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    Matrix44<T> m(mat.x);
+    for(int i = 0; i < 4; ++i)
+        for(int j = 0; j < 4; ++j)
+            m.x[i][j] -= a;
+    
+    return m;
+}
+
+template <class T>
+static Matrix44<T>
+subtractTR44(Matrix44<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    Matrix44<T> m(mat.x);
+    for(int i = 0; i < 4; ++i)
+        for(int j = 0; j < 4; ++j)
+            m.x[i][j] = a - m.x[i][j];
+    
+    return m;
+}
+
+
+template <class T>
+static Matrix44<T>
+add44T(Matrix44<T> &mat, T a)
+{
+    MATH_EXC_ON;
+    Matrix44<T> m(mat.x);
+    for(int i = 0; i < 4; ++i)
+        for(int j = 0; j < 4; ++j)
+            m.x[i][j] += a;
+    
+    return m;
+}
+
+template <class S, class T>
+static Matrix44<T>
+mul44(Matrix44<T> &mat1, Matrix44<S> &mat2)
+{
+    MATH_EXC_ON;
+    Matrix44<T> mat2T;
+    mat2T.setValue (mat2);
+    return mat1 * mat2T;
+}
+
+template <class S, class T>
+static Matrix44<T>
+rmul44(Matrix44<T> &mat2, Matrix44<S> &mat1)
+{
+    MATH_EXC_ON;
+    Matrix44<T> mat1T;
+    mat1T.setValue (mat1);
+    return mat1T * mat2;
+}
+
+template <class S, class T>
+static const Matrix44<T> &
+imul44(Matrix44<T> &mat1, Matrix44<S> &mat2)
+{
+    MATH_EXC_ON;
+    Matrix44<T> mat2T;
+    mat2T.setValue (mat2);
+    return mat1 *= mat2T;
+}
+
+template <class T>
+static bool
+lessThan44(Matrix44<T> &mat1, const Matrix44<T> &mat2)
+{
+    for(int i = 0; i < 4; ++i){
+        for(int j = 0; j < 4; ++j){
+            if(mat1[i][j] > mat2[i][j]){
+                return false;
+            }
+        }
+    }
+    
+    return (mat1 != mat2);
+}
+
+template <class T>
+static bool
+lessThanEqual44(Matrix44<T> &mat1, const Matrix44<T> &mat2)
+{
+    for(int i = 0; i < 4; ++i){
+        for(int j = 0; j < 4; ++j){
+            if(mat1[i][j] > mat2[i][j]){
+                return false;
+            }
+        }
+    }
+    
+    return true;
+}
+
+template <class T>
+static bool
+greaterThan44(Matrix44<T> &mat1, const Matrix44<T> &mat2)
+{
+    for(int i = 0; i < 4; ++i){
+        for(int j = 0; j < 4; ++j){
+            if(mat1[i][j] < mat2[i][j]){
+                return false;
+            }
+        }
+    }
+    
+    return (mat1 != mat2);
+}
+
+template <class T>
+static bool
+greaterThanEqual44(Matrix44<T> &mat1, const Matrix44<T> &mat2)
+{
+    for(int i = 0; i < 4; ++i){
+        for(int j = 0; j < 4; ++j){
+            if(mat1[i][j] < mat2[i][j]){
+                return false;
+            }
+        }
+    }
+    
+    return true;
+}
+
+template <class T>
+static tuple
+singularValueDecomposition44(const Matrix44<T>& m, bool forcePositiveDeterminant = false)
+{
+    IMATH_NAMESPACE::Matrix44<T> U, V;
+    IMATH_NAMESPACE::Vec4<T> S;
+    IMATH_NAMESPACE::jacobiSVD (m, U, S, V, std::numeric_limits<T>::epsilon(), forcePositiveDeterminant);
+    return make_tuple (U, S, V);
+}
+
+BOOST_PYTHON_FUNCTION_OVERLOADS(invert44_overloads, invert44, 1, 2);
+BOOST_PYTHON_FUNCTION_OVERLOADS(inverse44_overloads, inverse44, 1, 2);
+BOOST_PYTHON_FUNCTION_OVERLOADS(gjInvert44_overloads, gjInvert44, 1, 2);
+BOOST_PYTHON_FUNCTION_OVERLOADS(gjInverse44_overloads, gjInverse44, 1, 2);
+BOOST_PYTHON_FUNCTION_OVERLOADS(extractAndRemoveScalingAndShear44_overloads, extractAndRemoveScalingAndShear44, 3, 4)
+BOOST_PYTHON_FUNCTION_OVERLOADS(extractSHRT44_overloads, extractSHRT44, 5, 6)
+BOOST_PYTHON_FUNCTION_OVERLOADS(extractScaling44_overloads, extractScaling44, 2, 3)
+BOOST_PYTHON_FUNCTION_OVERLOADS(extractScalingAndShear44_overloads, extractScalingAndShear44, 3, 4)
+BOOST_PYTHON_FUNCTION_OVERLOADS(removeScaling44_overloads, removeScaling44, 1, 2)
+BOOST_PYTHON_FUNCTION_OVERLOADS(removeScalingAndShear44_overloads, removeScalingAndShear44, 1, 2)
+BOOST_PYTHON_FUNCTION_OVERLOADS(sansScaling44_overloads, sansScaling44, 1, 2)
+BOOST_PYTHON_FUNCTION_OVERLOADS(sansScalingAndShear44_overloads, sansScalingAndShear44, 1, 2)
+
+template <class T>
+static Matrix44<T> * Matrix4_tuple_constructor(const tuple &t0, const tuple &t1, const tuple &t2, const tuple &t3)
+{
+  if(t0.attr("__len__")() == 4 && t1.attr("__len__")() == 4 && t2.attr("__len__")() == 4 && t3.attr("__len__")() == 4)
+  {
+      return new Matrix44<T>(extract<T>(t0[0]),  extract<T>(t0[1]),  extract<T>(t0[2]),  extract<T>(t0[3]),
+                             extract<T>(t1[0]),  extract<T>(t1[1]),  extract<T>(t1[2]),  extract<T>(t1[3]),
+                             extract<T>(t2[0]),  extract<T>(t2[1]),  extract<T>(t2[2]),  extract<T>(t2[3]),
+                             extract<T>(t3[0]),  extract<T>(t3[1]),  extract<T>(t3[2]),  extract<T>(t3[3]));
+  }
+  else
+      throw std::domain_error ("Matrix44 takes 4 tuples of length 4");
+}
+
+template <class T, class S>
+static Matrix44<T> *Matrix4_matrix_constructor(const Matrix44<S> &mat)
+{
+    Matrix44<T> *m = new Matrix44<T>;
+    
+    for(int i = 0; i < 4; ++i)
+        for(int j = 0; j < 4; ++j)
+            m->x[i][j] = T (mat.x[i][j]);
+    
+    return m;
+}
+
+
+template <class T>
+class_<Matrix44<T> >
+register_Matrix44()
+{
+    typedef PyImath::StaticFixedArray<Matrix44<T>,T,4,IndexAccessMatrixRow<Matrix44<T>,T,4> > Matrix44_helper;
+
+    MatrixRow<T,4>::register_class();
+
+    class_<Matrix44<T> > matrix44_class(Matrix44Name<T>::value, Matrix44Name<T>::value,init<Matrix44<T> >("copy construction"));
+    matrix44_class
+        .def(init<>("initialize to identity"))
+        .def(init<T>("initialize all entries to a single value"))
+        .def("__init__", make_constructor(Matrix4_tuple_constructor<T>),"tuple constructor1")
+        .def("__init__", make_constructor(Matrix4_matrix_constructor<T,float>))
+        .def("__init__", make_constructor(Matrix4_matrix_constructor<T,double>))
+        
+        .def(init<T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T>("make from components"))
+       //.def_readwrite("x00", &Matrix44<T>::x[0][0])
+       //.def_readwrite("x01", &Matrix44<T>::x[0][1])
+       //.def_readwrite("x02", &Matrix44<T>::x[0][2])
+       //.def_readwrite("x03", &Matrix44<T>::x[0][3])
+       //.def_readwrite("x10", &Matrix44<T>::x[1][0])
+       //.def_readwrite("x11", &Matrix44<T>::x[1][1])
+       //.def_readwrite("x12", &Matrix44<T>::x[1][2])
+       //.def_readwrite("x13", &Matrix44<T>::x[1][3])
+       //.def_readwrite("x20", &Matrix44<T>::x[2][0])
+       //.def_readwrite("x21", &Matrix44<T>::x[2][1])
+       //.def_readwrite("x22", &Matrix44<T>::x[2][2])
+       //.def_readwrite("x23", &Matrix44<T>::x[2][3])
+       //.def_readwrite("x30", &Matrix44<T>::x[3][0])
+       //.def_readwrite("x31", &Matrix44<T>::x[3][1])
+       //.def_readwrite("x32", &Matrix44<T>::x[3][2])
+       //.def_readwrite("x33", &Matrix44<T>::x[3][3])
+        .def("baseTypeEpsilon", &Matrix44<T>::baseTypeEpsilon,"baseTypeEpsilon() epsilon value of the base type of the vector")
+        .staticmethod("baseTypeEpsilon")
+        .def("baseTypeMax", &Matrix44<T>::baseTypeMax,"baseTypeMax() max value of the base type of the vector")
+        .staticmethod("baseTypeMax")
+        .def("baseTypeLowest", &Matrix44<T>::baseTypeLowest,"baseTypeLowest() largest negative value of the base type of the vector")
+        .staticmethod("baseTypeLowest")
+        .def("baseTypeSmallest", &Matrix44<T>::baseTypeSmallest,"baseTypeSmallest() smallest value of the base type of the vector")
+        .staticmethod("baseTypeSmallest")
+        .def("equalWithAbsError", &Matrix44<T>::equalWithAbsError,
+             "m1.equalWithAbsError(m2,e) true if the elements "
+             "of v1 and v2 are the same with an absolute error of no more than e, "
+             "i.e., abs(m1[i] - m2[i]) <= e")
+         
+        .def("equalWithRelError", &Matrix44<T>::equalWithRelError,
+             "m1.equalWithAbsError(m2,e) true if the elements "
+             "of m1 and m2 are the same with an absolute error of no more than e, "
+             "i.e., abs(m1[i] - m2[i]) <= e * abs(m1[i])")
+         
+        // need a different version for matrix data access
+        .def("__len__", Matrix44_helper::len)
+        .def("__getitem__", Matrix44_helper::getitem)
+       //.def("__setitem__", Matrix44_helper::setitem)
+        .def("makeIdentity",&Matrix44<T>::makeIdentity,"makeIdentity() make this matrix the identity matrix")
+        .def("transpose",&Matrix44<T>::transpose,return_internal_reference<>(),"transpose() transpose this matrix")
+        .def("transposed",&Matrix44<T>::transposed,"transposed() return a transposed copy of this matrix")
+        .def("minorOf",&Matrix44<T>::minorOf,"minorOf() return matrix minor of the (row,col) element of this matrix")
+        .def("fastMinor",&Matrix44<T>::fastMinor,"fastMinor() return matrix minor using the specified rows and columns of this matrix")
+        .def("determinant",&Matrix44<T>::determinant,"determinant() return the determinant of this matrix")
+        .def("invert",&invert44<T>,invert44_overloads("invert() invert this matrix")[return_internal_reference<>()])
+        .def("inverse",&inverse44<T>,inverse44_overloads("inverse() return an inverted copy of this matrix"))
+        .def("gjInvert",&gjInvert44<T>,gjInvert44_overloads("gjInvert() invert this matrix")[return_internal_reference<>()])
+        .def("gjInverse",&gjInverse44<T>,gjInverse44_overloads("gjInverse() return an inverted copy of this matrix"))
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__iadd__", &iadd44<T, float>,return_internal_reference<>())
+        .def("__iadd__", &iadd44<T, double>,return_internal_reference<>())
+        .def("__iadd__", &iadd44T<T>,return_internal_reference<>())
+        .def("__add__", &add44<T>)
+        .def("__isub__", &isub44<T, float>,return_internal_reference<>())
+        .def("__isub__", &isub44<T, double>,return_internal_reference<>())
+        .def("__isub__", &isub44T<T>,return_internal_reference<>())
+        .def("__sub__", &sub44<T>)
+        .def("negate",&negate44<T>,return_internal_reference<>(),"negate() negate all entries in this matrix")
+        .def("__neg__", &neg44<T>)
+        .def("__imul__", &imul44T<T>,return_internal_reference<>())
+        .def("__mul__", &mul44T<T>)
+        .def("__rmul__", &rmul44T<T>)
+        .def("__idiv__", &idiv44T<T>,return_internal_reference<>())
+        .def("__itruediv__", &idiv44T<T>,return_internal_reference<>())
+        .def("__div__", &div44T<T>)
+        .def("__truediv__", &div44T<T>)
+        .def("__add__", &add44T<T>)
+        .def("__radd__", &add44T<T>)
+        .def("__sub__", &subtractTL44<T>)
+        .def("__rsub__", &subtractTR44<T>)
+        .def("__mul__", &mul44<float, T>)
+        .def("__mul__", &mul44<double, T>)
+        .def("__rmul__", &rmul44<float, T>)
+        .def("__rmul__", &rmul44<double, T>)
+        .def("__imul__", &imul44<float, T>,return_internal_reference<>())
+        .def("__imul__", &imul44<double, T>,return_internal_reference<>())
+        .def("__lt__", &lessThan44<T>)
+        .def("__gt__", &greaterThan44<T>)
+        .def("__le__", &lessThanEqual44<T>)
+        .def("__ge__", &greaterThanEqual44<T>)
+       //.def(self_ns::str(self))
+           .def("__repr__",&Matrix44_repr<T>)
+    
+        .def("extractAndRemoveScalingAndShear", &extractAndRemoveScalingAndShear44<T>, 
+             extractAndRemoveScalingAndShear44_overloads(                              
+             "M.extractAndRemoveScalingAndShear(scl, shr, "
+             "[exc]) -- extracts the scaling component of "
+             "M into scl and the shearing component of M "
+             "into shr.  Also removes the scaling and "
+             "shearing components from M.  "
+             "Returns 1 unless the scaling component is "
+             "nearly 0, in which case 0 is returned. "
+             "If optional arg. exc == 1, then if the "
+             "scaling component is nearly 0, then MathExc "
+             "is thrown."))
+             
+        .def("extractEulerXYZ", &extractEulerXYZ<T>, "extract Euler")          
+        .def("extractEulerZYX", &extractEulerZYX<T>, "extract Euler")
+          
+        .def("extractSHRT", &extractSHRT44<T>, extractSHRT44_overloads(
+             "M.extractSHRT(Vs, Vh, Vr, Vt, [exc]) -- "
+                "extracts the scaling component of M into Vs, "
+                        "the shearing component of M in Vh (as XY, "
+                "XZ, YZ shear factors), the rotation of M "
+                "into Vr (as Euler angles in the order XYZ), "
+                "and the translaation of M into Vt. "
+                        "If optional arg. exc == 1, then if the "
+             "scaling component is nearly 0, then MathExc "
+             "is thrown. "))
+                
+        .def("extractScaling", &extractScaling44<T>, extractScaling44_overloads("extract scaling"))
+        .def("extractScalingAndShear", &extractScalingAndShear44<T>, extractScalingAndShear44_overloads("extract scaling"))
+        .def("singularValueDecomposition", &singularValueDecomposition44<T>, 
+             "Decomposes the matrix using the singular value decomposition (SVD) into three\n"
+             "matrices U, S, and V which have the following properties: \n"
+             "  1. U and V are both orthonormal matrices, \n"
+             "  2. S is the diagonal matrix of singular values, \n"
+             "  3. U * S * V.transposed() gives back the original matrix.\n"
+             "The result is returned as a tuple [U, S, V].  Note that since S is diagonal we\n"
+             "don't need to return the entire matrix, so we return it as a three-vector.  \n"
+             "\n"
+             "The 'forcePositiveDeterminant' argument can be used to force the U and V^T to\n"
+             "have positive determinant (that is, to be proper rotation matrices); if\n"
+             "forcePositiveDeterminant is False, then the singular values are guaranteed to\n"
+             "be nonnegative but the U and V matrices might contain negative scale along one\n"
+             "of the axes; if forcePositiveDeterminant is True, then U and V cannot contain\n"
+             "negative scale but S[3] might be negative.  \n"
+             "\n"
+             "Our SVD implementation uses two-sided Jacobi rotations to iteratively\n"
+             "diagonalize the matrix, which should be quite robust and significantly faster\n"
+             "than the more general SVD solver in LAPACK.  \n",
+             args("matrix", "forcePositiveDeterminant"))
+        .def("symmetricEigensolve", &PyImath::jacobiEigensolve<IMATH_NAMESPACE::Matrix44<T> >, 
+             "Decomposes the matrix A using a symmetric eigensolver into matrices Q and S \n"
+             "which have the following properties: \n"
+             "  1. Q is the orthonormal matrix of eigenvectors, \n"
+             "  2. S is the diagonal matrix of eigenvalues, \n"
+             "  3. Q.transposed() * S * Q gives back the original matrix.\n"
+             "\n"
+             "IMPORTANT: It is vital that the passed-in matrix be symmetric, or the result \n"
+             "won't make any sense.  This function will return an error if passed an \n"
+             "unsymmetric matrix.\n"
+             "\n"
+             "The result is returned as a tuple [Q, S].  Note that since S is diagonal \n"
+             "we don't need to return the entire matrix, so we return it as a three-vector. \n"
+             "\n"
+             "Our eigensolver implementation uses one-sided Jacobi rotations to iteratively \n"
+             "diagonalize the matrix, which should be quite robust and significantly faster \n"
+             "than the more general symmetric eigenvalue solver in LAPACK.  \n")
+        .def("multDirMatrix", &multDirMatrix44<double,T>, "mult matrix")
+        .def("multDirMatrix", &multDirMatrix44_return_value<double,T>, "mult matrix")
+        .def("multDirMatrix", &multDirMatrix44_array<double,T>, "mult matrix")
+        .def("multDirMatrix", &multDirMatrix44<float,T>, "mult matrix")
+        .def("multDirMatrix", &multDirMatrix44_return_value<float,T>, "mult matrix")
+        .def("multDirMatrix", &multDirMatrix44_array<float,T>, "mult matrix")
+        .def("multVecMatrix", &multVecMatrix44<double,T>, "mult matrix")
+        .def("multVecMatrix", &multVecMatrix44_return_value<double,T>, "mult matrix")
+        .def("multVecMatrix", &multVecMatrix44_array<double,T>, "mult matrix")
+        .def("multVecMatrix", &multVecMatrix44<float,T>, "mult matrix")
+        .def("multVecMatrix", &multVecMatrix44_return_value<float,T>, "mult matrix")
+        .def("multVecMatrix", &multVecMatrix44_array<float,T>, "mult matrix")
+        .def("removeScaling", &removeScaling44<T>, removeScaling44_overloads("remove scaling"))
+        .def("removeScalingAndShear", &removeScalingAndShear44<T>, removeScalingAndShear44_overloads("remove scaling"))
+        .def("sansScaling", &sansScaling44<T>, sansScaling44_overloads("sans scaling"))
+        .def("sansScalingAndShear", &sansScalingAndShear44<T>, sansScalingAndShear44_overloads("sans scaling and shear"))
+        .def("scale", &scaleSc44<T>, return_internal_reference<>(), "scale matrix")
+        .def("scale", &scaleV44<T>, return_internal_reference<>(), "scale matrix")
+        .def("scale", &scale44Tuple<T>, return_internal_reference<>(), "scale matrix")
+        .def("rotate", &rotateV44<T>, return_internal_reference<>(), "rotate matrix")
+        .def("rotationMatrix", &rotationMatrix44<T>, return_internal_reference<>(), "rotationMatrix()")
+        .def("rotationMatrixWithUpDir", &rotationMatrixWithUp44<T>, return_internal_reference<>(), "roationMatrixWithUp()")
+        .def("setScale", &setScaleSc44<T>, return_internal_reference<>(),"setScale()")
+        .def("setScale", &setScaleV44<T>, return_internal_reference<>(),"setScale()")
+        .def("setScale", &setScale44Tuple<T>, return_internal_reference<>(),"setScale()")
+
+        .def("setShear", &setShearV44<T>, return_internal_reference<>(),"setShear()")
+        .def("setShear", &setShearS44<T>, return_internal_reference<>(),"setShear()")
+        .def("setShear", &setShear44Tuple<T>, return_internal_reference<>(),"setShear()")
+        .def("setTranslation", &setTranslation44<T>, return_internal_reference<>(),"setTranslation()")
+        .def("setTranslation", &setTranslation44Tuple<T>, return_internal_reference<>(),"setTranslation()")
+        .def("setTranslation", &setTranslation44Obj<T>, return_internal_reference<>(),"setTranslation()")
+        .def("setValue", &setValue44<T>, "setValue()")
+        .def("shear", &shearV44<T>, return_internal_reference<>(),"shear()")
+        .def("shear", &shearS44<T>, return_internal_reference<>(),"shear()")
+        .def("shear", &shear44Tuple<T>, return_internal_reference<>(),"shear()")
+        .def("translate", &translate44<T>, return_internal_reference<>(),"translate()")
+        .def("translate", &translate44Tuple<T>, return_internal_reference<>(),"translate()")
+        .def("translation", &Matrix44<T>::translation, "translation()")
+
+        ;
+
+    decoratecopy(matrix44_class);
+
+    return matrix44_class;
+/*
+    const Matrix44 &   operator = (const Matrix44 &v);
+    const Matrix44 &   operator = (T a);
+    T *                        getValue ();
+    const T *          getValue () const;
+    template <class S> void getValue (Matrix44<S> &v) const;
+    template <class S> Matrix44 & setValue (const Matrix44<S> &v);
+    template <class S> Matrix44 & setTheMatrix (const Matrix44<S> &v);
+    template <class S> void multVecMatrix(const Vec2<S> &src, Vec2<S> &dst) const;
+    template <class S> void multDirMatrix(const Vec2<S> &src, Vec2<S> &dst) const;
+    template <class S> const Matrix44 &        setRotation (S r);
+    template <class S> const Matrix44 &        rotate (S r);
+    const Matrix44 &   setScale (T s);
+    template <class S> const Matrix44 &        setScale (const Vec2<S> &s);
+    template <class S> const Matrix44 &        scale (const Vec2<S> &s);
+    template <class S> const Matrix44 &        setTranslation (const Vec2<S> &t);
+    Vec2<T>            translation () const;
+    template <class S> const Matrix44 &        translate (const Vec2<S> &t);
+    template <class S> const Matrix44 &        setShear (const S &h);
+    template <class S> const Matrix44 &        setShear (const Vec2<S> &h);
+    template <class S> const Matrix44 &        shear (const S &xy);
+    template <class S> const Matrix44 &        shear (const Vec2<S> &h);
+*/
+}
+
+template <class T>
+struct Matrix44Array_Constructor : public Task
+{
+    const FixedArray<T> &a; const FixedArray<T> &b; const FixedArray<T> &c; const FixedArray<T> &d;
+    const FixedArray<T> &e; const FixedArray<T> &f; const FixedArray<T> &g; const FixedArray<T> &h;
+    const FixedArray<T> &i; const FixedArray<T> &j; const FixedArray<T> &k; const FixedArray<T> &l;
+    const FixedArray<T> &m; const FixedArray<T> &n; const FixedArray<T> &o; const FixedArray<T> &p;
+    FixedArray<IMATH_NAMESPACE::Matrix44<T> > &result;
+
+    Matrix44Array_Constructor (const FixedArray<T> &a, const FixedArray<T> &b, const FixedArray<T> &c, const FixedArray<T> &d,
+                               const FixedArray<T> &e, const FixedArray<T> &f, const FixedArray<T> &g, const FixedArray<T> &h,
+                               const FixedArray<T> &i, const FixedArray<T> &j, const FixedArray<T> &k, const FixedArray<T> &l,
+                               const FixedArray<T> &m, const FixedArray<T> &n, const FixedArray<T> &o, const FixedArray<T> &p,
+                               FixedArray<IMATH_NAMESPACE::Matrix44<T> > &result)
+        : a (a), b (b), c (c), d (d), 
+          e (e), f (f), g (g), h (h), 
+          i (i), j (j), k (k), l (l),
+          m (m), n (n), o (o), p (p), result (result) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t index = start; index < end; ++index)
+        {
+            result[index] = IMATH_NAMESPACE::Matrix44<T>(a[index], b[index], c[index], d[index], 
+                                                         e[index], f[index], g[index], h[index], 
+                                                         i[index], j[index], k[index], l[index],
+                                                         m[index], n[index], o[index], p[index]);
+        }
+    }
+};
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Matrix44<T> > *
+M44Array_constructor(const FixedArray<T> &a, const FixedArray<T> &b, const FixedArray<T> &c, const FixedArray<T> &d, 
+                     const FixedArray<T> &e, const FixedArray<T> &f, const FixedArray<T> &g, const FixedArray<T> &h, 
+                     const FixedArray<T> &i, const FixedArray<T> &j, const FixedArray<T> &k, const FixedArray<T> &l, 
+                     const FixedArray<T> &m, const FixedArray<T> &n, const FixedArray<T> &o, const FixedArray<T> &p)
+{
+    MATH_EXC_ON;
+    Py_ssize_t len = a.len();
+    if (!( a.len() == len && b.len() == len && c.len() == len && d.len() == len && 
+            e.len() == len && f.len() == len && g.len() == len && h.len() == len && 
+            i.len() == len && j.len() == len && k.len() == len && l.len() == len && 
+           m.len() == len && n.len() == len && o.len() == len && p.len() == len))
+        throw std::invalid_argument ("Dimensions do not match" );
+               
+    FixedArray<IMATH_NAMESPACE::Matrix44<T> >* result =
+        new FixedArray<IMATH_NAMESPACE::Matrix44<T> > (Py_ssize_t(len), UNINITIALIZED);
+
+    Matrix44Array_Constructor<T> task (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, *result);
+    dispatchTask (task, len);
+    return result;
+}
+
+template <class T>
+static void
+setM44ArrayItem(FixedArray<IMATH_NAMESPACE::Matrix44<T> > &ma,
+                Py_ssize_t index,
+                const IMATH_NAMESPACE::Matrix44<T> &m)
+{
+    ma[ma.canonical_index(index)] = m;
+}
+
+template <class T>
+struct M44Array_Inverse : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &mats;
+    FixedArray<IMATH_NAMESPACE::Matrix44<T> >       &result;
+
+    M44Array_Inverse (FixedArray<IMATH_NAMESPACE::Matrix44<T> >        &result,
+                       const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &mats)
+        : mats (mats), result (result) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+            result[i] = mats[i].inverse();
+    } 
+};
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Matrix44<T> >
+M44Array_inverse(const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &ma)
+{
+    MATH_EXC_ON;
+    size_t len = ma.len();
+    FixedArray<IMATH_NAMESPACE::Matrix44<T> > result (len);
+
+    M44Array_Inverse<T> task (result, ma);
+    dispatchTask (task, len);
+
+    return result;
+}
+
+template <class T>
+struct M44Array_RmulVec4 : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &a;
+    const Vec4<T>                                   &v;
+    FixedArray<Vec4<T> >                            &r;
+
+    M44Array_RmulVec4 (const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &a,
+                       const Vec4<T>                                   &v, 
+                       FixedArray<Vec4<T> >                            &r)
+        : a (a), v (v), r (r) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            r[i] = v * a[i];
+        }
+    }
+};
+
+template <class T>
+static FixedArray< Vec4<T> >
+M44Array_rmulVec4 (const FixedArray< IMATH_NAMESPACE::Matrix44<T> > &a, const Vec4<T> &v)
+{
+    MATH_EXC_ON;
+    size_t len = a.len();
+    FixedArray< Vec4<T> > r (Py_ssize_t(len), UNINITIALIZED);
+
+    M44Array_RmulVec4<T> task (a, v, r);
+    dispatchTask (task, len);
+    return r;
+}
+
+template <class T>
+struct M44Array_RmulVec4Array : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &a;
+    const FixedArray<Vec4<T> >                      &b;
+    FixedArray<Vec4<T> >                            &r;
+
+    M44Array_RmulVec4Array (const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &a,
+                            const FixedArray<Vec4<T> >                      &b,
+                            FixedArray<Vec4<T> >                            &r)
+        : a (a), b (b), r (r) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            r[i] = b[i] * a[i];
+        }
+    }
+};
+
+template <class T>
+static FixedArray< Vec4<T> >
+M44Array_rmulVec4Array (const FixedArray< IMATH_NAMESPACE::Matrix44<T> > &a,
+                        const FixedArray< Vec4<T> > &b)
+{
+    MATH_EXC_ON;
+    size_t len = a.match_dimension(b);
+    FixedArray< Vec4<T> > r (Py_ssize_t(len), UNINITIALIZED);
+
+    M44Array_RmulVec4Array<T> task (a, b, r);
+    dispatchTask (task, len);
+    return r;
+}
+
+template <class T>
+struct M44Array_RmulVec3ArrayT : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &a;
+    const FixedArray<IMATH_NAMESPACE::Vec3<T> >     &b;
+    FixedArray<IMATH_NAMESPACE::Vec3<T> >           &r;
+
+    M44Array_RmulVec3ArrayT (const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &a,
+                             const FixedArray<IMATH_NAMESPACE::Vec3<T> >     &b,
+                             FixedArray<IMATH_NAMESPACE::Vec3<T> >           &r)
+      : a(a), b(b), r(r) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+            r[i] = b[i] * a[i];
+    }
+};
+
+template <class T>
+FixedArray<Vec3<T> >
+M44Array_rmulVec3ArrayT (const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &a,
+                         const FixedArray<IMATH_NAMESPACE::Vec3<T> >     &b)
+{
+    MATH_EXC_ON;
+    size_t len = a.match_dimension(b);
+    FixedArray< IMATH_NAMESPACE::Vec3<T> > result (Py_ssize_t(len), UNINITIALIZED);
+
+    M44Array_RmulVec3ArrayT<T> task (a, b, result);
+    dispatchTask (task, len);
+
+    return result;
+}
+
+template <class T>
+struct M44Array_Invert : public Task
+{
+    FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m;
+
+    M44Array_Invert (FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m)
+      : m(m) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+            m[i].invert();
+    }
+};
+
+template <class T>
+void
+M44Array_invert (FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m)
+{
+    MATH_EXC_ON;
+    size_t len = m.len();
+
+    M44Array_Invert<T> task (m);
+    dispatchTask (task, len);
+}
+
+template <class T>
+struct M44Array_Transpose : public Task
+{
+    FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m;
+
+    M44Array_Transpose (FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m)
+      : m(m) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+            m[i].transpose();
+    }
+};
+
+template <class T>
+void
+M44Array_transpose (FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m)
+{
+    MATH_EXC_ON;
+    size_t len = m.len();
+
+    M44Array_Transpose<T> task (m);
+    dispatchTask (task, len);
+}
+
+template <class T>
+struct M44Array_MultDirMatrix : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m;
+    const FixedArray<IMATH_NAMESPACE::Vec3<T> >     &v;
+    FixedArray<IMATH_NAMESPACE::Vec3<T> >           &r;
+
+    M44Array_MultDirMatrix (const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m,
+                            const FixedArray<IMATH_NAMESPACE::Vec3<T> >     &v,
+                            FixedArray<IMATH_NAMESPACE::Vec3<T> >           &r)
+      : m(m), v(v), r(r) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+            m[i].multDirMatrix (v[i], r[i]);
+    }
+};
+
+template <class T>
+FixedArray<Vec3<T> >
+M44Array_multDirMatrix (const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m,
+                        const FixedArray<IMATH_NAMESPACE::Vec3<T> >     &v)
+{
+    MATH_EXC_ON;
+    size_t len = m.match_dimension(v);
+    FixedArray<IMATH_NAMESPACE::Vec3<T> > result (Py_ssize_t(len), UNINITIALIZED);
+
+    M44Array_MultDirMatrix<T> task (m, v, result);
+    dispatchTask (task, len);
+
+    return result;
+}
+
+template <class T>
+struct M44Array_MultVecMatrix : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m;
+    const FixedArray<IMATH_NAMESPACE::Vec3<T> >     &v;
+    FixedArray<IMATH_NAMESPACE::Vec3<T> >           &r;
+
+    M44Array_MultVecMatrix (const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m,
+                            const FixedArray<IMATH_NAMESPACE::Vec3<T> >     &v,
+                            FixedArray<IMATH_NAMESPACE::Vec3<T> >           &r)
+      : m(m), v(v), r(r) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+            m[i].multVecMatrix (v[i], r[i]);
+    }
+};
+
+template <class T>
+FixedArray<Vec3<T> >
+M44Array_multVecMatrix (const FixedArray<IMATH_NAMESPACE::Matrix44<T> > &m,
+                        const FixedArray<IMATH_NAMESPACE::Vec3<T> >     &v)
+{
+    MATH_EXC_ON;
+    size_t len = m.match_dimension(v);
+    FixedArray<IMATH_NAMESPACE::Vec3<T> > result (Py_ssize_t(len), UNINITIALIZED);
+
+    M44Array_MultVecMatrix<T> task (m, v, result);
+    dispatchTask (task, len);
+
+    return result;
+}
+
+template <class T>
+class_<FixedArray<IMATH_NAMESPACE::Matrix44<T> > >
+register_M44Array()
+{
+
+    class_<FixedArray<IMATH_NAMESPACE::Matrix44<T> > > matrixArray_class = FixedArray<IMATH_NAMESPACE::Matrix44<T> >::register_("Fixed length array of IMATH_NAMESPACE::Matrix44");
+    matrixArray_class
+         .def("__init__", make_constructor(M44Array_constructor<T>))
+         .def("__setitem__", &setM44ArrayItem<T>)
+         .def("inverse", &M44Array_inverse<T>,
+             "Return M^-1 for each element M.",
+             (args("vector")))
+         .def("invert", &M44Array_invert<T>,
+             "Perform M^-1 in place for each element M.")
+         .def("transpose", &M44Array_transpose<T>,
+             "Perform M^T in place for each element M.")
+         .def("multDirMatrix", &M44Array_multDirMatrix<T>,
+             "Multiply an array of vectors element by element with the matrix array.",
+             (args("vector")))
+         .def("multVecMatrix", &M44Array_multVecMatrix<T>,
+             "Multiply an array of normals element by element with the matrix array.",
+             (args("vector")))
+         .def("__rmul__", &M44Array_rmulVec4<T>)
+         .def("__rmul__", &M44Array_rmulVec4Array<T>)
+         .def("__rmul__", &M44Array_rmulVec3ArrayT<T>)
+        ;
+
+    add_comparison_functions(matrixArray_class);
+
+    return matrixArray_class;
+}
+
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Matrix44<float> > register_Matrix44<float>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Matrix44<double> > register_Matrix44<double>();
+
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Matrix44<float> > > register_M44Array<float>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Matrix44<double> > > register_M44Array<double>();
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Matrix44<float> FixedArrayDefaultValue<IMATH_NAMESPACE::Matrix44<float> >::value() { return IMATH_NAMESPACE::Matrix44<float>(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Matrix44<double> FixedArrayDefaultValue<IMATH_NAMESPACE::Matrix44<double> >::value() { return IMATH_NAMESPACE::Matrix44<double>(); }
+}
diff --git a/src/python/PyImath/PyImathOperators.h b/src/python/PyImath/PyImathOperators.h
new file mode 100644 (file)
index 0000000..7e23bbc
--- /dev/null
@@ -0,0 +1,303 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathOperators_h_
+#define _PyImathOperators_h_
+
+#include "PyImathFixedArray.h"
+#include "PyImathAutovectorize.h"
+
+namespace PyImath {
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_add {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a+b; }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_sub {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a-b; }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_rsub {
+    static inline Ret apply(const T1 &a, const T2 &b) { return b-a; }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_mul {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a*b; }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_div {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a/b; }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_mod {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a%b; }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_pow {
+    static inline Ret apply(const T1 &a, const T2 &b) { return std::pow(a,b); }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_rpow {
+    static inline Ret apply(const T1 &a, const T2 &b) { return std::pow(b,a); }
+};
+
+template <class T1, class Ret=T1>
+struct op_neg {
+    static inline Ret apply(const T1 &a) { return -a; }
+};
+
+template <class T1, class Ret=T1>
+struct op_abs {
+    static inline Ret apply(const T1 &a) { return std::abs(a); }
+};
+
+template <class T1, class Ret=T1>
+struct op_inverse {
+    static inline Ret apply(const T1 &a) { return ~a; }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_lshift {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a << b; }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_rshift {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a >> b; }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_bitand {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a & b; }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_xor {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a ^ b; }
+};
+
+template <class T1, class T2=T1, class Ret=T1>
+struct op_bitor {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a | b; }
+};
+
+template <class T1, class T2=T1>
+struct op_iadd {
+    static inline void apply(T1 &a, const T2 &b) { a += b; }
+};
+
+template <class T1, class T2=T1>
+struct op_isub {
+    static inline void apply(T1 &a, const T2 &b) { a -= b; }
+};
+
+template <class T1, class T2=T1>
+struct op_imul {
+    static inline void apply(T1 &a, const T2 &b) { a *= b; }
+};
+
+template <class T1, class T2=T1>
+struct op_idiv {
+    static inline void apply(T1 &a, const T2 &b) { a /= b; }
+};
+
+template <class T1, class T2=T1>
+struct op_imod {
+    static inline void apply(T1 &a, const T2 &b) { a %= b; }
+};
+
+template <class T1, class T2=T1>
+struct op_ipow {
+    static inline void apply(T1 &a, const T2 &b) { a = std::pow(a,b); }
+};
+
+template <class T1, class T2=T1>
+struct op_ilshift {
+    static inline void apply(T1 &a, const T2 &b) { a <<= b; }
+};
+
+template <class T1, class T2=T1>
+struct op_irshift {
+    static inline void apply(T1 &a, const T2 &b) { a >>= b; }
+};
+
+template <class T1, class T2=T1>
+struct op_ixor {
+    static inline void apply(T1 &a, const T2 &b) { a ^= b; }
+};
+
+template <class T1, class T2=T1>
+struct op_ibitand {
+    static inline void apply(T1 &a, const T2 &b) { a &= b; }
+};
+
+template <class T1, class T2=T1>
+struct op_ibitor {
+    static inline void apply(T1 &a, const T2 &b) { a |= b; }
+};
+
+// the logical function return values default to 'int' for use
+// as mask arrays.
+template <class T1, class T2=T1, class Ret=int>
+struct op_lt {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a < b; }
+};
+
+template <class T1, class T2=T1, class Ret=int>
+struct op_gt {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a > b; }
+};
+
+template <class T1, class T2=T1, class Ret=int>
+struct op_le {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a <= b; }
+};
+
+template <class T1, class T2=T1, class Ret=int>
+struct op_ge {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a >= b; }
+};
+
+template <class T1, class T2=T1, class Ret=int>
+struct op_eq {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a == b; }
+};
+
+template <class T1, class T2=T1, class Ret=int>
+struct op_ne {
+    static inline Ret apply(const T1 &a, const T2 &b) { return a != b; }
+};
+
+template <class T>
+static T fa_reduce(const FixedArray<T> &a) {
+    T tmp(T(0)); // should use default construction but V3f doens't initialize
+    size_t len = a.len();
+    for (size_t i=0; i < len; ++i) tmp += a[i];
+    return tmp;
+}
+
+template <class T>
+static T fa_min(const FixedArray<T> &a) {
+    T tmp(T(0));
+    size_t len = a.len();
+    if (len > 0)
+        tmp = a[0];
+    for (size_t i=1; i < len; ++i)
+        if (a[i] < tmp)
+            tmp = a[i];
+    return tmp;
+}
+
+template <class T>
+static T fa_max(const FixedArray<T> &a) {
+    T tmp(T(0));
+    size_t len = a.len();
+    if (len > 0)
+        tmp = a[0];
+    for (size_t i=1; i < len; ++i)
+        if (a[i] > tmp)
+            tmp = a[i];
+    return tmp;
+}
+
+template <class T>
+static void add_arithmetic_math_functions(boost::python::class_<FixedArray<T> > &c) {
+    using boost::mpl::true_;
+    using boost::mpl::false_;
+    generate_member_bindings<op_add<T>, true_ >(c,"__add__", "self+x", boost::python::args("x"));
+    generate_member_bindings<op_add<T>, false_>(c,"__radd__","x+self", boost::python::args("x"));
+    generate_member_bindings<op_sub<T>, true_ >(c,"__sub__", "self-x", boost::python::args("x"));
+    generate_member_bindings<op_rsub<T>,false_>(c,"__rsub__","x-self", boost::python::args("x"));
+    generate_member_bindings<op_mul<T>, true_ >(c,"__mul__", "self*x", boost::python::args("x"));
+    generate_member_bindings<op_mul<T>, false_>(c,"__rmul__","x*self", boost::python::args("x"));
+    generate_member_bindings<op_div<T>, true_ >(c,"__div__", "self/x", boost::python::args("x"));
+    generate_member_bindings<op_div<T>, true_ >(c,"__truediv__", "self/x", boost::python::args("x"));
+    generate_member_bindings<op_neg<T> >(c,"__neg__", "-x");
+    generate_member_bindings<op_iadd<T>,true_ >(c,"__iadd__","self+=x",boost::python::args("x"));
+    generate_member_bindings<op_isub<T>,true_ >(c,"__isub__","self-=x",boost::python::args("x"));
+    generate_member_bindings<op_imul<T>,true_ >(c,"__imul__","self*=x",boost::python::args("x"));
+    generate_member_bindings<op_idiv<T>,true_ >(c,"__idiv__","self/=x",boost::python::args("x"));
+    generate_member_bindings<op_idiv<T>,true_ >(c,"__itruediv__","self/=x",boost::python::args("x"));
+
+    c.def("reduce",&fa_reduce<T>);
+}
+
+template <class T>
+static void add_reduction_functions(boost::python::class_<FixedArray<T> > &c) {
+    c.def("min",&fa_min<T>);
+    c.def("max",&fa_max<T>);
+}
+
+template <class T>
+static void add_pow_math_functions(boost::python::class_<FixedArray<T> > &c) {
+    using boost::mpl::true_;
+    using boost::mpl::false_;
+    generate_member_bindings<op_pow<T>, true_ >(c,"__pow__", "self**x", boost::python::args("x"));
+    generate_member_bindings<op_rpow<T>,false_>(c,"__rpow__","x**self", boost::python::args("x"));
+    generate_member_bindings<op_ipow<T>,true_ >(c,"__ipow__","x**=self",boost::python::args("x"));
+}
+
+template <class T>
+static void add_mod_math_functions(boost::python::class_<FixedArray<T> > &c) {
+    using boost::mpl::true_;
+    generate_member_bindings<op_mod<T>, true_>(c,"__mod__", "self%x", boost::python::args("x"));
+    generate_member_bindings<op_imod<T>,true_>(c,"__imod__","self%=x",boost::python::args("x"));
+}
+
+template <class T>
+static void add_shift_math_functions(boost::python::class_<FixedArray<T> > &c) {
+    using boost::mpl::true_;
+    generate_member_bindings<op_lshift<T>, true_>(c,"__lshift__", "self<<x", boost::python::args("x"));
+    generate_member_bindings<op_ilshift<T>,true_>(c,"__ilshift__","self<<=x",boost::python::args("x"));
+    generate_member_bindings<op_rshift<T>, true_>(c,"__rshift__", "self>>x", boost::python::args("x"));
+    generate_member_bindings<op_irshift<T>,true_>(c,"__irshift__","self>>=x",boost::python::args("x"));
+}
+
+template <class T>
+static void add_bitwise_math_functions(boost::python::class_<FixedArray<T> > &c) {
+    using boost::mpl::true_;
+    generate_member_bindings<op_bitand<T>, true_>(c,"__and__", "self&x", boost::python::args("x"));
+    generate_member_bindings<op_ibitand<T>,true_>(c,"__iand__","self&=x",boost::python::args("x"));
+    generate_member_bindings<op_bitor<T>,  true_>(c,"__or__",  "self|x", boost::python::args("x"));
+    generate_member_bindings<op_ibitor<T>, true_>(c,"__ior__", "self|=x",boost::python::args("x"));
+    generate_member_bindings<op_xor<T>,    true_>(c,"__xor__", "self^x", boost::python::args("x"));
+    generate_member_bindings<op_ixor<T>,   true_>(c,"__ixor__","self^=x",boost::python::args("x"));
+}
+
+template <class T>
+static void add_comparison_functions(boost::python::class_<FixedArray<T> > &c) {
+    using boost::mpl::true_;
+    generate_member_bindings<op_eq<T>, true_>(c,"__eq__","self==x",boost::python::args("x"));
+    generate_member_bindings<op_ne<T>, true_>(c,"__ne__","self!=x",boost::python::args("x"));
+}
+
+template <class T>
+static void add_ordered_comparison_functions(boost::python::class_<FixedArray<T> > &c) {
+    using boost::mpl::true_;
+    generate_member_bindings<op_lt<T>, true_>(c,"__lt__","self<x", boost::python::args("x"));
+    generate_member_bindings<op_le<T>, true_>(c,"__le__","self<=x",boost::python::args("x"));
+    generate_member_bindings<op_gt<T>, true_>(c,"__gt__","self>x", boost::python::args("x"));
+    generate_member_bindings<op_ge<T>, true_>(c,"__ge__","self>=x",boost::python::args("x"));
+}
+
+template <class S,class T>
+static void add_explicit_construction_from_type(boost::python::class_<FixedArray<T> > &c) {
+    using namespace boost::python;
+    c.def(init<FixedArray<S> >("copy contents of other array into this one"));
+}
+
+}
+
+#endif // _PyImathOperators_h_
diff --git a/src/python/PyImath/PyImathPlane.cpp b/src/python/PyImath/PyImathPlane.cpp
new file mode 100644 (file)
index 0000000..d9da45c
--- /dev/null
@@ -0,0 +1,580 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include "PyImath.h"
+#include "PyImathVec.h"
+#include "PyImathMathExc.h"
+#include "PyImathPlane.h"
+#include "PyImathDecorators.h"
+#include "PyImathExport.h"
+
+namespace PyImath{
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct PlaneName {static const char *value;};
+template <> const char *PlaneName<float>::value = "Plane3f";
+template <> const char *PlaneName<double>::value = "Plane3d";
+
+template <class T>
+static Plane3<T> *Plane3_construct_default()
+{
+    Vec3<T> normal(T (1), T (0), T (0));
+    return new Plane3<T>(normal, T (0));
+}
+
+template <class T>
+static Plane3<T> *Plane3_plane_construct(const object &planeObj)
+{
+    MATH_EXC_ON;
+    extract < Plane3<float> > ef (planeObj);
+    extract < Plane3<double> > ed (planeObj);
+
+    Plane3<T> *p = 0;
+
+    if (ef.check())
+    {
+        Plane3<float> efp = ef();
+        p = new Plane3<T>;
+        p->normal = efp.normal;
+        p->distance = efp.distance;
+    }
+
+    else if (ed.check())
+    {
+        Plane3<double> edp = ed();
+        p = new Plane3<T>;
+        p->normal = edp.normal;
+        p->distance = edp.distance;
+    }
+
+    else
+    {
+      throw std::invalid_argument ("invalid parameter passed to Plane constructor");
+    }
+    
+    return p;
+}
+
+template <class T>
+static Plane3<T> *Plane3_tuple_constructor1(const tuple &t, T distance)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> normal;
+        normal.x = extract<T>(t[0]);
+        normal.y = extract<T>(t[1]);
+        normal.z = extract<T>(t[2]);
+        
+        return new Plane3<T>(normal, distance);
+    }
+    else
+        throw std::domain_error ("Plane3 expects tuple of length 3");
+}
+
+template <class T>
+static Plane3<T> *Plane3_tuple_constructor2(const tuple &t0, const tuple &t1)
+{
+    MATH_EXC_ON;
+    if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3)
+    {
+        Vec3<T> point, normal;
+        point.x = extract<T>(t0[0]);
+        point.y = extract<T>(t0[1]);
+        point.z = extract<T>(t0[2]);
+        
+        normal.x = extract<T>(t1[0]);
+        normal.y = extract<T>(t1[1]);
+        normal.z = extract<T>(t1[2]);
+        
+        return new Plane3<T>(point, normal);
+    }
+    else
+        throw std::domain_error ("Plane3 expects tuples of length 3");
+}
+
+template <class T>
+static Plane3<T> *Plane3_tuple_constructor3(const tuple &t0, const tuple &t1, const tuple &t2)
+{
+    MATH_EXC_ON;
+    if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3 && t2.attr("__len__")() == 3)
+    {
+        Vec3<T> point0, point1, point2;
+        point0.x = extract<T>(t0[0]);
+        point0.y = extract<T>(t0[1]);
+        point0.z = extract<T>(t0[2]);
+        
+        point1.x = extract<T>(t1[0]);
+        point1.y = extract<T>(t1[1]);
+        point1.z = extract<T>(t1[2]);
+
+        point2.x = extract<T>(t2[0]);
+        point2.y = extract<T>(t2[1]);
+        point2.z = extract<T>(t2[2]); 
+        
+        return new Plane3<T>(point0, point1, point2);
+    }
+    else
+        throw std::domain_error ("Plane3 expects tuple of length 3");
+}
+
+template <class T>
+static Plane3<T>
+mul (const Plane3<T> &plane, const Matrix44<T> &M)
+{
+    MATH_EXC_ON;
+    return plane * M;
+}
+
+template <class T>
+static void
+set1 (Plane3<T> &plane, const Vec3<T> &v, T t)
+{
+    MATH_EXC_ON;
+    plane.set (v, t);
+}
+
+template <class T>
+static void
+set2 (Plane3<T> &plane, const Vec3<T> &v1, const Vec3<T> &v2)
+{
+    MATH_EXC_ON;
+    plane.set (v1, v2);
+}
+
+template <class T>
+static void
+set3 (Plane3<T> &plane, const Vec3<T> &v1, const Vec3<T> &v2, const Vec3<T> &v3)
+{
+    MATH_EXC_ON;
+    plane.set (v1, v2, v3);
+}
+
+template <class T>
+static std::string Plane3_str(const Plane3<T> &plane)
+{
+    std::stringstream stream;
+
+    typename return_by_value::apply <Vec3<float> >::type converter;
+    handle<> normH (converter (plane.normal));
+    handle<> normRepr (PYUTIL_OBJECT_REPR (normH.get()));
+    std::string normalReprStr = extract<std::string> (normRepr.get());
+
+    stream << PlaneName<T>::value << "(" << normalReprStr << ", " 
+           << plane.distance << ")";
+    return stream.str();
+}
+
+// Non-specialized repr is same as str
+template <class T>
+static std::string Plane3_repr(const Plane3<T> &plane)
+{
+    return Plane3_str(plane);
+}
+
+// Specialization for float to full precision
+template <>
+std::string Plane3_repr(const Plane3<float> &plane)
+{
+    typename return_by_value::apply <Vec3<float> >::type converter;
+
+    handle<> normH (converter (plane.normal));
+    handle<> normRepr (PYUTIL_OBJECT_REPR (normH.get()));
+    std::string normalReprStr = extract<std::string> (normRepr.get());
+
+    return (boost::format("%s(%s, %.9g)")
+                        % PlaneName<float>::value
+                        % normalReprStr.c_str()
+                        % plane.distance).str();
+}
+
+// Specialization for double to full precision
+template <>
+std::string Plane3_repr(const Plane3<double> &plane)
+{
+    typename return_by_value::apply <Vec3<double> >::type converter;
+
+    handle<> normH (converter (plane.normal));
+    handle<> normRepr (PYUTIL_OBJECT_REPR (normH.get()));
+    std::string normalReprStr = extract<std::string> (normRepr.get());
+
+    return (boost::format("%s(%s, %.17g)")
+                        % PlaneName<double>::value
+                        % normalReprStr.c_str()
+                        % plane.distance).str();
+}
+
+
+template <class T>
+static T
+distance(Plane3<T> &plane)
+{
+    return plane.distance;
+}
+
+template <class T>
+static Vec3<T>
+normal(Plane3<T> &plane)
+{
+    return plane.normal;
+}
+
+template <class T>
+static void
+setNormal(Plane3<T> &plane, const Vec3<T> &normal)
+{
+    MATH_EXC_ON;
+    plane.normal = normal.normalized();
+}
+
+template <class T>
+static void
+setDistance(Plane3<T> &plane, const T &distance)
+{
+    plane.distance = distance;
+}
+
+template <class T, class S>
+static object intersectT(const Plane3<T> &plane, const Line3<S> &line)
+{
+    MATH_EXC_ON;
+    T param;
+    Line3<T> l;
+    l.pos = line.pos;
+    l.dir = line.dir;
+
+    if(plane.intersectT(l, param))
+        return object(param);
+    
+    return object();
+}
+
+template <class T>
+static bool
+intersect2(const Plane3<T> &plane, const Line3<T> &line, Vec3<T> &intersection)
+{
+    MATH_EXC_ON;
+    return plane.intersect(line, intersection);
+}
+
+template <class T, class S>
+static object
+intersect1(const Plane3<T> &plane, const Line3<S> &line)
+{
+    MATH_EXC_ON;
+    Vec3<T> intersection;
+    Line3<T> l;
+    l.pos = line.pos;
+    l.dir = line.dir;
+    if(plane.intersect(l, intersection))
+        return object(intersection);
+    
+    return object();
+    
+}
+
+template <class T>
+static void
+setTuple1(Plane3<T> &plane, const tuple &t, T distance)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> normal;
+        normal.x = extract<T>(t[0]);
+        normal.y = extract<T>(t[1]);
+        normal.z = extract<T>(t[2]);
+        
+        plane.set(normal, distance);
+    }
+    else
+        throw std::domain_error ("Plane3 expects tuple of length 3");    
+}
+
+template <class T>
+static void
+setTuple2(Plane3<T> &plane, const tuple &t0, const tuple &t1)
+{
+    MATH_EXC_ON;
+    if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3)
+    {
+        Vec3<T> point, normal;
+        point.x = extract<T>(t0[0]);
+        point.y = extract<T>(t0[1]);
+        point.z = extract<T>(t0[2]);
+        
+        normal.x = extract<T>(t1[0]);
+        normal.y = extract<T>(t1[1]);
+        normal.z = extract<T>(t1[2]);
+        
+        plane.set(point, normal);
+    }
+    else
+        throw std::domain_error ("Plane3 expects tuples of length 3");
+}
+
+template <class T>
+static void
+setTuple3(Plane3<T> &plane, const tuple &t0, const tuple &t1, const tuple &t2)
+{
+    MATH_EXC_ON;
+    if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3 && t2.attr("__len__")() == 3)
+    {
+        Vec3<T> point0, point1, point2;
+        point0.x = extract<T>(t0[0]);
+        point0.y = extract<T>(t0[1]);
+        point0.z = extract<T>(t0[2]);
+        
+        point1.x = extract<T>(t1[0]);
+        point1.y = extract<T>(t1[1]);
+        point1.z = extract<T>(t1[2]);
+
+        point2.x = extract<T>(t2[0]);
+        point2.y = extract<T>(t2[1]);
+        point2.z = extract<T>(t2[2]); 
+        
+        plane.set(point0, point1, point2);
+    }
+    else
+        throw std::domain_error ("Plane3 expects tuple of length 3");
+}
+
+template <class T>
+static Vec3<T>
+reflectPoint(Plane3<T> &plane, const Vec3<T> &p)
+{
+    MATH_EXC_ON;
+    return plane.reflectPoint(p);
+}
+
+template <class T>
+static Vec3<T>
+reflectPointTuple(Plane3<T> &plane, const tuple &t)
+{
+    MATH_EXC_ON;
+    Vec3<T> point;
+    if(t.attr("__len__")() == 3)
+    {
+        point.x = extract<T>(t[0]);
+        point.y = extract<T>(t[1]);
+        point.z = extract<T>(t[2]); 
+        
+        return plane.reflectPoint(point);
+    }
+    else
+        throw std::domain_error ("Plane3 expects tuple of length 3");
+}
+
+template <class T>
+static T
+distanceTo(Plane3<T> &plane, const Vec3<T> &v)
+{
+    MATH_EXC_ON;
+    return plane.distanceTo(v);
+}
+
+template <class T>
+static T
+distanceToTuple(Plane3<T> &plane, const tuple &t)
+{
+    MATH_EXC_ON;
+    Vec3<T> point;
+    if(t.attr("__len__")() == 3)
+    {
+        point.x = extract<T>(t[0]);
+        point.y = extract<T>(t[1]);
+        point.z = extract<T>(t[2]); 
+        
+        return plane.distanceTo(point);
+    }
+    else
+        throw std::domain_error ("Plane3 expects tuple of length 3");    
+}
+
+template <class T>
+static Vec3<T>
+reflectVector(Plane3<T> &plane, const Vec3<T> &v)
+{
+    MATH_EXC_ON;
+    return plane.reflectVector(v);
+}
+
+template <class T>
+static Vec3<T>
+reflectVectorTuple(Plane3<T> &plane, const tuple &t)
+{
+    MATH_EXC_ON;
+    Vec3<T> point;
+    if(t.attr("__len__")() == 3)
+    {
+        point.x = extract<T>(t[0]);
+        point.y = extract<T>(t[1]);
+        point.z = extract<T>(t[2]); 
+        
+        return plane.reflectVector(point);
+    }
+    else
+        throw std::domain_error ("Plane3 expects tuple of length 3");
+}
+
+template <class T>
+static bool
+equal(const Plane3<T> &p1, const Plane3<T> &p2)
+{
+    if(p1.normal == p2.normal && p1.distance == p2.distance)
+        return true;
+    else
+        return false;
+}
+
+template <class T>
+static bool
+notequal(const Plane3<T> &p1, const Plane3<T> &p2)
+{
+    if(p1.normal != p2.normal || p1.distance != p2.distance)
+        return true;
+    else
+        return false;
+}
+
+template <class T>
+static Plane3<T>
+negate(const Plane3<T> &plane)
+{
+    MATH_EXC_ON;
+    Plane3<T> p;
+    p.set(-plane.normal, -plane.distance);
+    
+    return p;
+}
+
+
+
+template <class T>
+class_<Plane3<T> >
+register_Plane()
+{
+    const char *name = PlaneName<T>::value;
+    
+    class_< Plane3<T> > plane_class(name);
+    plane_class
+        .def("__init__",make_constructor(Plane3_construct_default<T>),"initialize normal to  (1,0,0), distance to 0")
+        .def("__init__",make_constructor(Plane3_tuple_constructor1<T>))
+        .def("__init__",make_constructor(Plane3_tuple_constructor2<T>))
+        .def("__init__",make_constructor(Plane3_tuple_constructor3<T>))
+        .def("__init__",make_constructor(Plane3_plane_construct<T>))
+        .def(init<const Vec3<T> &, T>("Plane3(normal, distance) construction"))
+        .def(init<const Vec3<T> &, const Vec3<T> &>("Plane3(point, normal) construction"))
+        .def(init<const Vec3<T> &, const Vec3<T> &, const Vec3<T> &>("Plane3(point1, point2, point3) construction"))
+        .def("__eq__", &equal<T>)
+        .def("__ne__", &notequal<T>)
+        .def("__mul__", &mul<T>)
+        .def("__neg__", &negate<T>)
+        .def("__str__", &Plane3_str<T>)
+        .def("__repr__", &Plane3_repr<T>)
+        
+        .def_readwrite("normal", &Plane3<T>::normal)
+        .def_readwrite("distance", &Plane3<T>::distance)
+        
+        .def("normal", &normal<T>, "normal()",
+             "pl.normal() -- returns the normal of plane pl")
+             
+        .def("distance", &distance<T>, "distance()",
+                "pl.distance() -- returns the signed distance\n"
+                        "of plane pl from the coordinate origin")
+        
+        .def("setNormal", &setNormal<T>, "setNormal()",
+                "pl.setNormal(n) -- sets the normal of plane\n"
+                        "pl to n.normalized()")
+             
+        .def("setDistance", &setDistance<T>, "setDistance()",
+                "pl.setDistance(d) -- sets the signed distance\n"
+                        "of plane pl from the coordinate origin to d")
+             
+        .def("set", &set1<T>, "set()",
+                "pl.set(n,d) -- sets the normal and the signed\n"
+                        "   distance of plane pl to n and d\n"
+                        "\n"
+                        "pl.set(p,n) -- sets the normal of plane pl to\n"
+                        "   n.normalized() and adjusts the distance of\n"
+                        "   pl from the coordinate origin so that pl\n"
+                        "   passes through point p\n"
+                        "\n"
+                        "pl.set(p1,p2,p3) -- sets the normal of plane pl\n"
+                        "   to (p2-p1)%(p3-p1)).normalized(), and adjusts\n"
+                        "   the distance of pl from the coordinate origin\n"
+                        "   so that pl passes through points p1, p2 and p3")
+             
+        .def("set", &set2<T>, "set()")
+        .def("set", &set3<T>, "set()")
+        
+        .def("set", &setTuple1<T>, "set()")
+        .def("set", &setTuple2<T>, "set()")
+        .def("set", &setTuple3<T>, "set()")        
+        
+        .def("intersect", &intersect2<T>,
+                "pl.intersect(ln, pt) -- returns true if the line intersects\n"
+             "the plane, false if it doesn't.  The point where plane\n"
+                        "pl and line ln intersect is stored in pt")
+             
+        .def("intersect", &intersect1<T,float>,
+                "pl.intersect(ln) -- returns the point where plane\n"
+                        "pl and line ln intersect, or None if pl and ln do\n"
+                        "not intersect")
+        .def("intersect", &intersect1<T,double>,
+                "pl.intersect(ln) -- returns the point where plane\n"
+                        "pl and line ln intersect, or None if pl and ln do\n"
+                        "not intersect")
+             
+        .def("intersectT", &intersectT<T, float>,
+             "pl.intersectT(ln) -- computes the intersection,\n"
+                        "i, of plane pl and line ln, and returns t, so that\n"
+                        "ln.pos() + t * ln.dir() == i.\n"
+                        "If pl and ln do not intersect, pl.intersectT(ln)\n"
+                        "returns None.\n") 
+             
+        .def("intersectT", &intersectT<T,double>)
+             
+        .def("distanceTo", &distanceTo<T>, "distanceTo()",
+                "pl.distanceTo(p) -- returns the signed distance\n"
+                        "between plane pl and point p (positive if p is\n"
+                        "on the side of pl where the pl's normal points)\n")
+        
+        .def("distanceTo", &distanceToTuple<T>)
+             
+        .def("reflectPoint", &reflectPoint<T>, "reflectPoint()",
+                "pl.reflectPoint(p) -- returns the image,\n"
+                        "q, of point p after reflection on plane pl:\n"
+                        "the distance between p and q is twice the\n"
+                        "distance between p and pl, and the line from\n"
+                        "p to q is parallel to pl's normal.")
+             
+        .def("reflectPoint", &reflectPointTuple<T>)
+             
+        .def("reflectVector", &reflectVector<T>, "reflectVector()",
+                "pl.reflectVector(v) -- returns the direction\n"
+                        "of a ray with direction v after reflection on\n"
+                        "plane pl")
+        .def("reflectVector", &reflectVectorTuple<T>)
+        
+        ;
+
+    decoratecopy(plane_class);
+
+    return plane_class;
+}
+
+template PYIMATH_EXPORT class_<Plane3<float> > register_Plane<float>();
+template PYIMATH_EXPORT class_<Plane3<double> > register_Plane<double>();
+
+} //namespace PyIMath
diff --git a/src/python/PyImath/PyImathPlane.h b/src/python/PyImath/PyImathPlane.h
new file mode 100644 (file)
index 0000000..28e9548
--- /dev/null
@@ -0,0 +1,77 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathPlane_h_
+#define _PyImathPlane_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <ImathPlane.h>
+#include "PyImath.h"
+
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Plane3<T> > register_Plane();
+
+//
+
+// Other code in the Zeno code base assumes the existance of a class with the
+// same name as the Imath class, and with static functions wrap() and
+// convert() to produce a PyImath object from an Imath object and vice-versa,
+// respectively.  The class Boost generates from the Imath class does not
+// have these properties, so we define a companion class here.
+// The template argument, T, is the element type (e.g.,float, double).
+
+template <class T>
+class P3 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Plane3<T> &pl);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Plane3<T> *pl);
+};
+
+template <class T>
+PyObject *
+P3<T>::wrap (const IMATH_NAMESPACE::Plane3<T> &pl)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Plane3<T> >::type converter;
+    PyObject *p = converter (pl);
+    return p;
+}
+
+template <class T>
+int
+P3<T>::convert (PyObject *p, IMATH_NAMESPACE::Plane3<T> *pl)
+{
+    boost::python::extract <IMATH_NAMESPACE::Plane3f> extractorPf (p);
+    if (extractorPf.check())
+    {
+        IMATH_NAMESPACE::Plane3f e = extractorPf();
+        pl->normal.setValue (e.normal);
+        pl->distance = T(e.distance);
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::Plane3d> extractorPd (p);
+    if (extractorPd.check())
+    {
+        IMATH_NAMESPACE::Plane3d e = extractorPd();
+        pl->normal.setValue (e.normal);
+        pl->distance = T(e.distance);
+        return 1;
+    }
+
+    return 0;
+}
+
+typedef P3<float>      Plane3f;
+typedef P3<double>     Plane3d;
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathQuat.cpp b/src/python/PyImath/PyImathQuat.cpp
new file mode 100644 (file)
index 0000000..413acc5
--- /dev/null
@@ -0,0 +1,1124 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <ImathVec.h>
+#include <ImathMatrixAlgo.h>
+#include <ImathEuler.h>
+#include "PyImathQuat.h"
+#include "PyImathExport.h"
+#include "PyImathDecorators.h"
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathOperators.h"
+#include "PyImathQuatOperators.h"
+
+// XXX incomplete array wrapping, docstrings missing
+
+namespace PyImath {
+template <> const char *PyImath::QuatfArray::name() { return "QuatfArray"; }
+template <> const char *PyImath::QuatdArray::name() { return "QuatdArray"; }
+}
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct QuatName { static const char *value; };
+template<> const char *QuatName<float>::value  = "Quatf";
+template<> const char *QuatName<double>::value = "Quatd";
+
+template <class T>
+static std::string Quat_str(const Quat<T> &v)
+{
+    std::stringstream stream;
+    stream << QuatName<T>::value << "(" << v[0] << ", " << v[1] << ", " 
+           << v[2] << ", " << v[3] << ")";
+    return stream.str();
+}
+
+// Non-specialized repr is same as str
+template <class T>
+static std::string Quat_repr(const Quat<T> &v)
+{
+    return Quat_str(v);
+}
+
+// Specialization for float to full precision
+template <>
+std::string Quat_repr(const Quat<float> &v)
+{
+    return (boost::format("%s(%.9g, %.9g, %.9g, %.9g)")
+                        % QuatName<float>::value
+                        % v[0] % v[1] % v[2] % v[3]).str();
+}
+
+// Specialization for double to full precision
+template <>
+std::string Quat_repr(const Quat<double> &v)
+{
+    return (boost::format("%s(%.17g, %.17g, %.17g, %.17g)")
+                        % QuatName<double>::value
+                        % v[0] % v[1] % v[2] % v[3]).str();
+}
+
+
+template <class T>
+static Quat<T> &
+invert(Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return quat.invert();
+}
+
+template <class T>
+static Quat<T> 
+inverse(Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return quat.inverse();
+}
+
+template <class T>
+static Quat<T> &
+normalize(Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return quat.normalize();
+}
+
+template <class T>
+static Quat<T> 
+normalized(Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return quat.normalized();
+}
+
+template <class T>
+static T
+length (Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return quat.length();
+}
+
+template <class T>
+static Vec3<T>
+rotateVector(const Quat<T> &quat, const Vec3<T> &original)
+{
+    MATH_EXC_ON;
+    return quat.rotateVector(original);
+}
+
+template <class T>
+static Quat<T> &
+setAxisAngle(Quat<T> &quat, const Vec3<T> &axis, T radians)
+{
+    MATH_EXC_ON;
+    return quat.setAxisAngle(axis, radians);
+}
+
+template <class T>
+static Quat<T> &
+setRotation(Quat<T> &quat, const Vec3<T> &from, const Vec3<T> &to)
+{
+    MATH_EXC_ON;
+    return quat.setRotation(from, to);
+}
+
+template <class T>
+static T
+angle (Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return quat.angle();
+}
+
+template <class T>
+static Vec3<T>
+axis (Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return quat.axis();
+}
+
+template <class T>
+static Matrix33<T>
+toMatrix33 (Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return quat.toMatrix33();
+}
+
+template <class T>
+static Matrix44<T>
+toMatrix44 (Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return quat.toMatrix44();
+}
+
+template <class T>
+static Quat<T> 
+log(Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return quat.log();
+}
+
+template <class T>
+static Quat<T> 
+exp(Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return quat.exp();
+}
+
+template <class T>
+static void
+setR(Quat<T> &quat, const double &r)
+{
+    quat.r = r;
+}
+
+template <class T>
+static void
+setV(Quat<T> &quat, const Vec3<T> &v)
+{
+    quat.v = v;
+}
+
+template <class T>
+static void
+extract(Quat<T> &quat, const Matrix44<T> &mat)
+{
+    MATH_EXC_ON;
+    Quat<T> q = IMATH_NAMESPACE::extractQuat(mat);
+    quat.r = q.r;
+    quat.v = q.v;
+}
+
+template <class T>
+static T scalar(Quat<T> &quat)
+{
+    return quat.r;
+}
+
+template <class T>
+static Vec3<T> vector(Quat<T> &quat)
+{
+    return quat.v;
+}
+
+template <class T>
+static Quat<T>
+slerp(const Quat<T> &quat, const Quat<T> &other, T t)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::slerp (quat, other, t);
+}
+
+template <class T>
+static Quat<T>
+slerpShortestArc(const Quat<T>& quat, const Quat<T>& other, T t)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::slerpShortestArc (quat, other, t);
+}
+
+template <class T>
+static const Quat<T> &
+imul (Quat<T> &quat, const Quat<T> &other)
+{
+    MATH_EXC_ON;
+    return quat *= other;
+}
+
+template <class T>
+static const Quat<T> &
+imulT (Quat<T> &quat, T t)
+{
+    MATH_EXC_ON;
+    return quat *= t;
+}
+
+template <class T>
+static const Quat<T> &
+idiv (Quat<T> &quat, const Quat<T> &other)
+{
+    MATH_EXC_ON;
+    return quat /= other;
+}
+
+template <class T>
+static const Quat<T> &
+idivT (Quat<T> &quat, T t)
+{
+    MATH_EXC_ON;
+    return quat /= t;
+}
+
+template <class T>
+static const Quat<T> &
+iadd (Quat<T> &quat, const Quat<T> &other)
+{
+    MATH_EXC_ON;
+    return quat += other;
+}
+
+template <class T>
+static const Quat<T> &
+isub (Quat<T> &quat, const Quat<T> &other)
+{
+    MATH_EXC_ON;
+    return quat -= other;
+}
+
+template <class T>
+static Matrix33<T>
+rmulM33(Quat<T> &quat, Matrix33<T> &m)
+{
+    MATH_EXC_ON;
+    return m * quat;
+}
+
+template <class T>
+static Matrix33<T>
+mulM33(Quat<T> &quat, Matrix33<T> &m)
+{
+    MATH_EXC_ON;
+    return quat * m;
+}
+
+template <class T>
+static Quat<T>
+mul(Quat<T> &quat, Quat<T> &other)
+{
+    MATH_EXC_ON;
+    return quat * other;
+}
+
+template <class T>
+static Quat<T>
+div(Quat<T> &quat, Quat<T> &other)
+{
+    MATH_EXC_ON;
+    return quat / other;
+}
+
+template <class T>
+static Quat<T>
+divT(Quat<T> &quat, T t)
+{
+    MATH_EXC_ON;
+    return quat / t;
+}
+
+template <class T>
+static Quat<T>
+mulT(Quat<T> &quat, T t)
+{
+    MATH_EXC_ON;
+    return quat * t;
+}
+
+template <class T>
+static Quat<T>
+add(Quat<T> &quat, Quat<T> &other)
+{
+    MATH_EXC_ON;
+    return quat + other;
+}
+
+template <class T>
+static Quat<T>
+sub(Quat<T> &quat, Quat<T> &other)
+{
+    MATH_EXC_ON;
+    return quat - other;
+}
+
+template <class T>
+static Quat<T>
+neg(Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return -quat;
+}
+
+template <class T>
+static Quat<T>
+conj(Quat<T> &quat)
+{
+    MATH_EXC_ON;
+    return ~quat;
+}
+
+template <class T>
+static T
+dot(Quat<T> &quat, Quat<T> &other)
+{
+    MATH_EXC_ON;
+    return quat ^ other;
+}
+
+template <class T>
+static Vec3<T>
+rmulVec3(Quat<T> &quat, const Vec3<T> &v)
+{
+    MATH_EXC_ON;
+    return v * quat.toMatrix44();
+}
+
+template <class T>
+static FixedArray< Vec3<T> >
+rmulVec3Array(Quat<T> &quat, const FixedArray< Vec3<T> > &a)
+{
+    MATH_EXC_ON;
+    Matrix44<T> m = quat.toMatrix44();
+    size_t len = a.len();
+    FixedArray< Vec3<T> > r(len);
+    for (size_t i = 0; i < len; i++)
+        r[i] = a[i] * m;
+    return r;
+}
+
+template <class T>
+static Quat<T> *
+quatConstructor1(const Euler<T> &euler)
+{
+    MATH_EXC_ON;
+    return new Quat<T>(euler.toQuat());
+}
+
+template <class T>
+static Quat<T> *
+quatConstructor2(const Matrix33<T> &mat)
+{
+    MATH_EXC_ON;
+    return new Quat<T>(Euler<T>(mat).toQuat());
+}
+
+template <class T>
+static Quat<T> *
+quatConstructor3(const Matrix44<T> &mat)
+{
+    MATH_EXC_ON;
+    return new Quat<T>(Euler<T>(mat).toQuat());
+}
+
+template <class T>
+class_<Quat<T> >
+register_Quat()
+{
+    class_<Quat<T> > quat_class(QuatName<T>::value, QuatName<T>::value,init<Quat<T> >("copy construction"));
+    quat_class
+        .def(init<>("imath Quat initialization") )
+        .def(init<Quat<float> >("imath Quat copy initialization") )
+        .def(init<Quat<double> >("imath Quat copy initialization") )
+        .def(init<T,T,T,T>("make Quat from components") )
+        .def(init<T, Vec3<T> >("make Quat from components") )
+        .def("__init__", make_constructor(quatConstructor1<T>))
+        .def("__init__", make_constructor(quatConstructor2<T>))
+        .def("__init__", make_constructor(quatConstructor3<T>))
+        .def("identity",&Quat<T>::identity)
+        .def("invert",&invert<T>,return_internal_reference<>(),
+                "q.invert() -- inverts quaternion q\n"
+                        "(modifying q); returns q")
+             
+        .def("inverse",&inverse<T>,
+                "q.inverse() -- returns the inverse of\n"
+                        "quaternion q; q is not modified\n")
+             
+        .def("normalize",&normalize<T>,return_internal_reference<>(),
+                "q.normalize() -- normalizes quaternion q\n"
+                        "(modifying q); returns q")
+            
+        .def("normalized",&normalized<T>,
+                "q.normalized() -- returns a normalized version\n"
+                        "of quaternion q; q is not modified\n")
+             
+        .def("length",&length<T>)
+
+        .def("rotateVector",&rotateVector<T>,
+                       "q.rotateVector(orig) -- Given a vector orig,\n"
+                        "   calculate orig' = q x orig x q*\n\n"
+                        "   Assumes unit quaternions")
+             
+        .def("setAxisAngle",&setAxisAngle<T>,return_internal_reference<>(),
+                       "q.setAxisAngle(x,r) -- sets the value of\n"
+                       "quaternion q so that q represents a rotation\n"
+                       "of r radians around axis x")
+             
+        .def("setRotation",&setRotation<T>,return_internal_reference<>(),
+                "q.setRotation(v,w) -- sets the value of\n"
+                        "quaternion q so that rotating vector v by\n"
+                        "q produces vector w")
+             
+        .def("angle",&angle<T>,
+                "q.angle() -- returns the rotation angle\n"
+                        "(in radians) represented by quaternion q")
+             
+        .def("axis",&axis<T>,
+                "q.axis() -- returns the rotation axis\n"
+                        "represented by quaternion q")
+             
+        .def("toMatrix33",&toMatrix33<T>,
+             "q.toMatrix33() -- returns a 3x3 matrix that\n"
+                        "represents the same rotation as quaternion q")
+             
+        .def("toMatrix44",&toMatrix44<T>,
+                "q.toMatrix44() -- returns a 4x4 matrix that\n"
+                        "represents the same rotation as quaternion q")
+             
+        .def("log",&log<T>)
+        .def("exp",&exp<T>)
+        .def_readwrite("v",&Quat<T>::v)                       
+        .def_readwrite("r",&Quat<T>::r)
+        .def("v", &vector<T>,
+                         "q.v() -- returns the v (vector) component\n"
+                         "of quaternion q")
+              
+        .def("r", &scalar<T>,
+                "q.r() -- returns the r (scalar) component\n"
+                        "of quaternion q")
+                       
+        .def("setR", &setR<T>,
+                "q.setR(s) -- sets the r (scalar) component\n"
+                        "of quaternion q to s")
+             
+        .def("setV", &setV<T>,
+                "q.setV(w) -- sets the v (vector) component\n"
+                        "of quaternion q to w")
+             
+        .def("extract", &extract<T>,
+                "q.extract(m) -- extracts the rotation component\n"
+                        "from 4x4 matrix m and stores the result in q")
+             
+        .def("slerp", &slerp<T>,
+                "q.slerp(p,t) -- performs sperical linear\n"
+                        "interpolation between quaternions q and p:\n"
+                        "q.slerp(p,0) returns q; q.slerp(p,1) returns p.\n"
+                        "q and p must be normalized\n")
+
+        .def("slerpShortestArc", &slerpShortestArc<T>,
+                "q.slerpShortestArc(p,t) -- performs spherical linear\n"
+                         "interpolation along the shortest arc between\n"
+                         "quaternions q and either p or -p, whichever is\n"
+                         "closer. q and p must be normalized\n")
+             
+        .def("__str__",Quat_str<T>)
+        .def("__repr__",Quat_repr<T>)
+        .def ("__imul__", &imul<T>, return_internal_reference<>())
+        .def ("__imul__", &imulT<T>, return_internal_reference<>())
+        .def ("__idiv__", idiv<T>, return_internal_reference<>())
+        .def ("__idiv__", &idivT<T>, return_internal_reference<>())
+        .def ("__itruediv__", idiv<T>, return_internal_reference<>())
+        .def ("__itruediv__", &idivT<T>, return_internal_reference<>())
+        .def ("__iadd__", &iadd<T>, return_internal_reference<>())
+        .def ("__isub__", &isub<T>, return_internal_reference<>())
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def ("__rmul__", &rmulM33<T>)
+        .def ("__mul__", &mulM33<T>)
+        .def ("__mul__", &mul<T>)
+        .def ("__div__", &div<T>)
+        .def ("__div__", &divT<T>)
+        .def ("__truediv__", &div<T>)
+        .def ("__truediv__", &divT<T>)
+        .def ("__mul__", &mulT<T>)
+        .def ("__rmul__", &mulT<T>)
+        .def ("__add__", &add<T>)
+        .def ("__sub__", &sub<T>)
+        .def ("__neg__", &neg<T>)
+        .def ("__invert__", &conj<T>)
+        .def ("__xor__", &dot<T>)
+        .def ("__rmul__", &rmulVec3<T>)
+        .def ("__rmul__", &rmulVec3Array<T>)
+        ;
+
+    decoratecopy(quat_class);
+
+    return quat_class;
+}
+
+// XXX fixme - template this
+// really this should get generated automatically...
+
+template <class T,int index>
+static FixedArray<T>
+QuatArray_get(FixedArray<IMATH_NAMESPACE::Quat<T> > &qa)
+{
+    return FixedArray<T>(&(qa.unchecked_index(0).r) + index,
+                         qa.len(), 4*qa.stride(), qa.handle(), qa.writable());
+}
+
+template <class T>
+struct QuatArray_SetRotationTask : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Vec3<T> > &from;
+    const FixedArray<IMATH_NAMESPACE::Vec3<T> > &to;
+    FixedArray<IMATH_NAMESPACE::Quat<T> >       &result;
+
+    QuatArray_SetRotationTask (const FixedArray<IMATH_NAMESPACE::Vec3<T> > &fromIn,
+                               const FixedArray<IMATH_NAMESPACE::Vec3<T> > &toIn,
+                               FixedArray<IMATH_NAMESPACE::Quat<T> >       &resultIn)
+        : from (fromIn), to (toIn), result (resultIn) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+            result[i].setRotation (from[i], to[i]);
+    }
+};
+
+template <class T> static void
+QuatArray_setRotation (FixedArray<IMATH_NAMESPACE::Quat<T> > &va,
+                       const FixedArray<IMATH_NAMESPACE::Vec3<T> > &from,
+                       const FixedArray<IMATH_NAMESPACE::Vec3<T> > &to)
+{
+    MATH_EXC_ON;
+    size_t len = va.match_dimension(from); 
+    va.match_dimension(to); 
+
+    // Validate that 'va' is writable before entering the thread-task.
+    if (!va.writable())
+        throw std::invalid_argument ("Input fixed array is read-only.");
+
+    QuatArray_SetRotationTask<T> task (from, to, va);
+    dispatchTask (task, len);
+}
+
+template <class T>
+struct QuatArray_OrientToVectors : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Vec3<T> > &forward;
+    const FixedArray<IMATH_NAMESPACE::Vec3<T> > &up;
+    FixedArray<IMATH_NAMESPACE::Quat<T> >       &result;
+    bool alignForward;
+
+    QuatArray_OrientToVectors (const FixedArray<IMATH_NAMESPACE::Vec3<T> > &forwardIn,
+                               const FixedArray<IMATH_NAMESPACE::Vec3<T> > &upIn,
+                               FixedArray<IMATH_NAMESPACE::Quat<T> >       &resultIn,
+                               bool alignForwardIn)
+        : forward (forwardIn), up (upIn), result (resultIn),
+          alignForward (alignForwardIn) {}
+
+    void execute (size_t start, size_t end)
+    {
+        Vec3<T> f(0), u(0);
+        Euler<T> eu(0,0,0);
+        const Vec3<T> fRef(1,0,0);
+
+        for (size_t i = start; i < end; ++i)
+        {
+            if (alignForward)
+            {
+                f = forward[i].normalized();
+                u = up[i] - f.dot(up[i])*f;
+                u.normalize();
+            }
+            else
+            {
+                u = up[i].normalized();
+                f = forward[i] - u.dot(forward[i])*u;
+                f.normalize();
+            }
+
+            extractEulerXYZ (rotationMatrixWithUpDir (fRef, f, u), eu);
+            result[i] = eu.toQuat();
+        }
+    }
+};
+
+template <class T> static void
+QuatArray_orientToVectors (FixedArray<IMATH_NAMESPACE::Quat<T> >       &va,
+                           const FixedArray<IMATH_NAMESPACE::Vec3<T> > &forward,
+                           const FixedArray<IMATH_NAMESPACE::Vec3<T> > &up,
+                           bool alignForward)
+{
+    MATH_EXC_ON;
+    size_t len = va.match_dimension(forward);
+    va.match_dimension(up);
+
+    // Validate that 'va' is writable before entering the thread-task.
+    if (!va.writable())
+        throw std::invalid_argument ("Input fixed array is read-only.");
+
+    QuatArray_OrientToVectors<T> task (forward, up, va, alignForward);
+    dispatchTask (task, len);
+}
+
+template <class T>
+struct QuatArray_Axis : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Quat<T> > &va;
+    FixedArray<IMATH_NAMESPACE::Vec3<T> >       &result;
+
+    QuatArray_Axis (const FixedArray<IMATH_NAMESPACE::Quat<T> > &vaIn,
+                    FixedArray<IMATH_NAMESPACE::Vec3<T> >       &resultIn)
+        : va (vaIn), result (resultIn) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+            result[i] = va[i].axis(); 
+    } 
+};
+
+template <class T> static FixedArray<IMATH_NAMESPACE::Vec3<T> >
+QuatArray_axis(const FixedArray<IMATH_NAMESPACE::Quat<T> > &va)
+{
+    MATH_EXC_ON;
+    size_t len = va.len(); 
+    FixedArray<IMATH_NAMESPACE::Vec3<T> > retval (Py_ssize_t(len), UNINITIALIZED);
+
+    QuatArray_Axis<T> task (va, retval);
+    dispatchTask (task, len);
+    return retval;
+}
+
+template <class T>
+struct QuatArray_Angle : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Quat<T> > &va;
+    FixedArray<T>                               &result;
+
+    QuatArray_Angle (const FixedArray<IMATH_NAMESPACE::Quat<T> > &vaIn,
+                     FixedArray<T>                               &resultIn)
+        : va (vaIn), result (resultIn) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+            result[i] = va[i].angle(); 
+    } 
+};
+
+
+template <class T> static FixedArray<T>
+QuatArray_angle(const FixedArray<IMATH_NAMESPACE::Quat<T> > &va)
+{
+    MATH_EXC_ON;
+    size_t len = va.len(); 
+    FixedArray<T> retval (Py_ssize_t(len), UNINITIALIZED);
+
+    QuatArray_Angle<T> task (va, retval);
+    dispatchTask (task, len);
+    return retval;
+}
+
+template <class T>
+struct QuatArray_RmulVec3 : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Quat<T> > &a;
+    const Vec3<T>                               &v;
+    FixedArray<Vec3<T> >                        &r;
+
+    QuatArray_RmulVec3 (const FixedArray<IMATH_NAMESPACE::Quat<T> > &aIn,
+                        const Vec3<T> &vIn, FixedArray<Vec3<T> > &rIn)
+        : a (aIn), v (vIn), r (rIn) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            Matrix44<T> m = a[i].toMatrix44();
+            r[i] = v * m;
+        }
+    }
+};
+
+template <class T>
+static FixedArray< Vec3<T> >
+QuatArray_rmulVec3 (const FixedArray< IMATH_NAMESPACE::Quat<T> > &a, const Vec3<T> &v)
+{
+    MATH_EXC_ON;
+    size_t len = a.len();
+    FixedArray< Vec3<T> > r (Py_ssize_t(len), UNINITIALIZED);
+
+    QuatArray_RmulVec3<T> task (a, v, r);
+    dispatchTask (task, len);
+    return r;
+}
+
+template <class T>
+struct QuatArray_RmulVec3Array : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Quat<T> > &a;
+    const FixedArray<Vec3<T> >                  &b;
+    FixedArray<Vec3<T> >                        &r;
+
+    QuatArray_RmulVec3Array (const FixedArray<IMATH_NAMESPACE::Quat<T> > &aIn,
+                             const FixedArray<Vec3<T> > &bIn,
+                             FixedArray<Vec3<T> > &rIn)
+        : a (aIn), b (bIn), r (rIn) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            Matrix44<T> m = a[i].toMatrix44();
+            r[i] = b[i] * m;
+        }
+    }
+};
+
+template <class T>
+static FixedArray< Vec3<T> >
+QuatArray_rmulVec3Array (const FixedArray< IMATH_NAMESPACE::Quat<T> > &a,
+                         const FixedArray< Vec3<T> > &b)
+{
+    MATH_EXC_ON;
+    size_t len = a.match_dimension(b);
+    FixedArray< Vec3<T> > r (Py_ssize_t(len), UNINITIALIZED);
+
+    QuatArray_RmulVec3Array<T> task (a, b, r);
+    dispatchTask (task, len);
+    return r;
+}
+
+template <class T>
+struct QuatArray_SetAxisAngle : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Vec3<T> > &axis;
+    const FixedArray<T>                         &angles;
+    FixedArray<IMATH_NAMESPACE::Quat<T> >       &quats;
+
+    QuatArray_SetAxisAngle (const FixedArray<IMATH_NAMESPACE::Vec3<T> > &axisIn,
+                            const FixedArray<T>                         &anglesIn,
+                            FixedArray<IMATH_NAMESPACE::Quat<T> >       &quatsIn)
+        : axis (axisIn), angles (anglesIn), quats (quatsIn) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            quats[i].setAxisAngle (axis[i], angles[i]);
+        }
+    }
+};
+
+template <class T>
+static FixedArray< IMATH_NAMESPACE::Quat<T> > &
+QuatArray_setAxisAngle (FixedArray< IMATH_NAMESPACE::Quat<T> > &quats,
+                        const FixedArray< IMATH_NAMESPACE::Vec3<T> > &axis,
+                        const FixedArray<T> &angles)
+{
+    MATH_EXC_ON;
+    size_t len = quats.match_dimension(axis);
+    quats.match_dimension(angles);
+
+    // Validate that 'va' is writable before entering the thread-task.
+    if (!quats.writable())
+        throw std::invalid_argument ("Input fixed array is read-only.");
+
+    QuatArray_SetAxisAngle<T> task (axis, angles, quats);
+    dispatchTask (task, len);
+    return quats;
+}
+
+template <class T>
+struct QuatArray_RotateVector : public Task
+{
+    FixedArray<IMATH_NAMESPACE::Vec3<T> >       &result;
+    const FixedArray<IMATH_NAMESPACE::Vec3<T> > &vectors;
+    const FixedArray<IMATH_NAMESPACE::Quat<T> > &quats;
+
+    QuatArray_RotateVector (FixedArray<IMATH_NAMESPACE::Vec3<T> >       &resultIn,
+                            const FixedArray<IMATH_NAMESPACE::Vec3<T> > &vectorsIn,
+                            const FixedArray<IMATH_NAMESPACE::Quat<T> > &quatsIn)
+        : result (resultIn), vectors (vectorsIn), quats (quatsIn) {}
+
+    void execute(size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            result[i] = quats[i].rotateVector (vectors[i]);
+        }
+    }
+};
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Vec3<T> >
+QuatArray_rotateVector (const FixedArray< IMATH_NAMESPACE::Quat<T> > &quats,
+                        const FixedArray< IMATH_NAMESPACE::Vec3<T> > &vectors)
+{
+    MATH_EXC_ON;
+    size_t len = quats.match_dimension(vectors);
+    FixedArray< IMATH_NAMESPACE::Vec3<T> > result (len);
+
+    QuatArray_RotateVector<T> task (result, vectors, quats);
+    dispatchTask (task, len);
+    return result;
+}
+
+template <class T>
+struct QuatArray_Inverse : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Quat<T> > &quats;
+    FixedArray<IMATH_NAMESPACE::Quat<T> >       &result;
+
+    QuatArray_Inverse (FixedArray<IMATH_NAMESPACE::Quat<T> >       &resultIn,
+                       const FixedArray<IMATH_NAMESPACE::Quat<T> > &quatsIn)
+        : quats (quatsIn), result (resultIn) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+            result[i] = quats[i].inverse();
+    } 
+};
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Quat<T> >
+QuatArray_inverse(const FixedArray<IMATH_NAMESPACE::Quat<T> > &quats)
+{
+    MATH_EXC_ON;
+    size_t len = quats.len();
+    FixedArray<IMATH_NAMESPACE::Quat<T> > result (len);
+
+    QuatArray_Inverse<T> task (result, quats);
+    dispatchTask (task, len);
+
+    return result;
+}
+
+template <class T>
+struct QuatArray_SetEulerXYZ : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Vec3<T> > &rot;
+    FixedArray<IMATH_NAMESPACE::Quat<T> >       &quats;
+
+    QuatArray_SetEulerXYZ (const FixedArray<IMATH_NAMESPACE::Vec3<T> > &rotIn,
+                           FixedArray<IMATH_NAMESPACE::Quat<T> >       &quatsIn)
+        : rot (rotIn), quats (quatsIn) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            Eulerf e(rot[i]);
+            quats[i] = e.toQuat();
+        }
+    }
+};
+
+template <class T>
+static void
+QuatArray_setEulerXYZ (FixedArray< IMATH_NAMESPACE::Quat<T> > &quats,
+                       const FixedArray< IMATH_NAMESPACE::Vec3<T> > &rot)
+{
+    MATH_EXC_ON;
+    size_t len = quats.match_dimension(rot);
+
+    // Validate that 'va' is writable before entering the thread-task.
+    if (!quats.writable())
+        throw std::invalid_argument ("Input fixed array is read-only.");
+
+    QuatArray_SetEulerXYZ<T> task (rot, quats);
+    dispatchTask (task, len);
+}
+
+template <class T>
+struct QuatArray_Mul : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Quat<T> > &q1;
+    const FixedArray<IMATH_NAMESPACE::Quat<T> > &q2;
+    FixedArray<IMATH_NAMESPACE::Quat<T> >       &result;
+
+    QuatArray_Mul (const FixedArray<IMATH_NAMESPACE::Quat<T> > &q1In,
+                   const FixedArray<IMATH_NAMESPACE::Quat<T> > &q2In,
+                   FixedArray<IMATH_NAMESPACE::Quat<T> >       &resultIn)
+        : q1 (q1In), q2 (q2In), result (resultIn) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            result[i] = q1[i] * q2[i];
+        }
+    }
+};
+
+template <class T>
+static FixedArray< IMATH_NAMESPACE::Quat<T> >
+QuatArray_mul(const FixedArray< IMATH_NAMESPACE::Quat<T> > &q1,
+              const FixedArray< IMATH_NAMESPACE::Quat<T> > &q2)
+{
+    MATH_EXC_ON;
+    size_t len = q1.match_dimension(q2);
+    FixedArray< IMATH_NAMESPACE::Quat<T> > result (Py_ssize_t(len), UNINITIALIZED);
+
+    QuatArray_Mul<T> task (q1, q2, result);
+    dispatchTask (task, len);
+    return result;
+}
+
+template <class T>
+struct QuatArray_QuatConstructor1 : public Task
+{
+    const FixedArray<IMATH_NAMESPACE::Euler<T> > &euler;
+    FixedArray<IMATH_NAMESPACE::Quat<T> >        &result;
+
+    QuatArray_QuatConstructor1 (const FixedArray<IMATH_NAMESPACE::Euler<T> > &eulerIn,
+                                FixedArray<IMATH_NAMESPACE::Quat<T> >        &resultIn)
+        : euler (eulerIn), result (resultIn) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            result[i] = euler[i].toQuat();
+        }
+    }
+};
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Quat<T> > *
+QuatArray_quatConstructor1(const FixedArray<IMATH_NAMESPACE::Euler<T> > &e)
+{
+    MATH_EXC_ON;
+    size_t len = e.len();
+    FixedArray<IMATH_NAMESPACE::Quat<T> >* result =
+        new FixedArray<IMATH_NAMESPACE::Quat<T> > (Py_ssize_t(len), UNINITIALIZED);
+
+    QuatArray_QuatConstructor1<T> task (e, *result);
+    dispatchTask (task, len);
+    return result;
+}
+
+template <class T>
+struct QuatArray_ExtractTask : public Task
+{
+    const FixedArray<Matrix44<double> >    &m;
+    FixedArray<IMATH_NAMESPACE::Quat<T> >  &result;
+
+    QuatArray_ExtractTask (const FixedArray<Matrix44<double> >    &mIn,
+                           FixedArray<IMATH_NAMESPACE::Quat<T> >  &resultIn)
+        : m (mIn), result (resultIn) {}
+
+    void execute (size_t start, size_t end)
+    {
+        for (size_t i = start; i < end; ++i)
+        {
+            result[i] = IMATH_NAMESPACE::extractQuat (m[i]);
+        }
+    }
+};
+
+template <class T>
+static void
+QuatArray_extract(FixedArray<IMATH_NAMESPACE::Quat<T> > &q,
+                  const FixedArray<Matrix44<double> >   &m)
+{
+    MATH_EXC_ON;
+    const size_t len = q.match_dimension(m);
+
+    QuatArray_ExtractTask<T> task (m, q);
+    dispatchTask (task, len);
+}
+
+template <class T>
+class_<FixedArray<IMATH_NAMESPACE::Quat<T> > >
+register_QuatArray()
+{
+    using boost::mpl::true_;
+    using boost::mpl::false_;
+
+    typedef IMATH_NAMESPACE::Quat<T>   QuatT;
+
+    class_<FixedArray<QuatT> > quatArray_class = FixedArray<QuatT>::register_("Fixed length array of IMATH_NAMESPACE::Quat");
+    quatArray_class
+        .add_property("r",&QuatArray_get<T,0>)
+        .add_property("x",&QuatArray_get<T,1>)
+        .add_property("y",&QuatArray_get<T,2>)
+        .add_property("z",&QuatArray_get<T,3>)
+        .def("setRotation", &QuatArray_setRotation<T>,
+             "set rotation angles for each quat",
+             (args("from", "to")))
+        .def("orientToVectors", &QuatArray_orientToVectors<T>,
+             "Sets the orientations to match the given forward and up vectors, "
+             "matching the forward vector exactly if 'alignForward' is True, matching "
+             "the up vector exactly if 'alignForward' is False.  If the vectors are "
+             "already orthogonal, both vectors will be matched exactly.",
+             (args("forward", "up", "alignForward")))
+        .def("extract", &QuatArray_extract<T>,
+             "Extract the rotation component of an M44d and return it as a quaternion.",
+             (args("lxform")))
+        .def("axis", &QuatArray_axis<T>,
+             "get rotation axis for each quat")
+        .def("angle", &QuatArray_angle<T>,
+             "get rotation angle about the axis returned by axis() for each quat")
+        .def("setAxisAngle", &QuatArray_setAxisAngle<T>,
+             "set the quaternion arrays from a given axis and angle",
+             (args("axis", "angle")), return_value_policy<copy_non_const_reference>())
+        .def("setEulerXYZ", &QuatArray_setEulerXYZ<T>,
+             "set the quaternion arrays from a given euler XYZ angle vector",
+             (args("euler")))
+        .def("rotateVector", &QuatArray_rotateVector<T>,
+             "Rotate the supplied vectors by the quaternions.  Assumes quaternions are normalized.",
+             (args("vector")))
+        .def("inverse", &QuatArray_inverse<T>,
+             "Return 1/Q for each quaternion.",
+             (args("QuatArray")))
+        .def("__rmul__", &QuatArray_rmulVec3<T>)
+        .def("__rmul__", &QuatArray_rmulVec3Array<T>)
+        .def("__init__", make_constructor(QuatArray_quatConstructor1<T>))
+        ;
+
+    generate_member_bindings<op_quatDot<QuatT>, true_>
+        (quatArray_class, "dot",
+         "Return the element-by-element Euclidean inner product",
+         args("qB"));
+    generate_member_bindings<op_quatDot<QuatT>, true_>
+        (quatArray_class, "euclideanInnerProduct",
+         "Return the element-by-element Euclidean inner product",
+         args("qB"));
+    generate_member_bindings<op_quatNormalize<QuatT> >
+        (quatArray_class, "normalize",
+         "Normalize each quaternion in the array");
+    generate_member_bindings<op_quatNormalized<QuatT> >
+        (quatArray_class, "normalized",
+         "Return a new quaternion array with unit quaternions.");
+
+    generate_member_bindings<op_neg<QuatT> >
+        (quatArray_class, "__neg__" , "-self");
+    generate_member_bindings<op_mul<QuatT,QuatT>, true_ >
+        (quatArray_class, "__mul__",  "self * qB", args("qB"));
+    generate_member_bindings<op_mul<QuatT,T>, false_ >
+        (quatArray_class, "__mul__",  "self * x",  args("x"));
+    generate_member_bindings<op_mul<QuatT,T>, false_ >
+        (quatArray_class, "__rmul__", "self * x",  args("x"));
+    generate_member_bindings<op_quatDot<QuatT>, true_ >
+        (quatArray_class, "__xor__",  "self.dot(qB)",  args("qB"));
+
+    generate_member_bindings<op_quatSlerp<QuatT>, true_, false_ >
+        (quatArray_class,
+         "slerp",
+         "Return the element-by-element shortest arc spherical linear interpolation between self and B.",
+         args("qB", "t"));
+
+    add_comparison_functions(quatArray_class);
+    decoratecopy(quatArray_class);
+
+    return quatArray_class;
+}
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Quat<float> > register_Quat<float>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Quat<double> > register_Quat<double>();
+                
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Quat<float> > > register_QuatArray<float>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Quat<double> > > register_QuatArray<double>();
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Quat<float> FixedArrayDefaultValue<IMATH_NAMESPACE::Quat<float> >::value() { return IMATH_NAMESPACE::Quat<float>(); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Quat<double> FixedArrayDefaultValue<IMATH_NAMESPACE::Quat<double> >::value() { return IMATH_NAMESPACE::Quat<double>(); }
+}
diff --git a/src/python/PyImath/PyImathQuat.h b/src/python/PyImath/PyImathQuat.h
new file mode 100644 (file)
index 0000000..0d4742f
--- /dev/null
@@ -0,0 +1,120 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathQuat_h_
+#define _PyImathQuat_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <ImathQuat.h>
+#include <ImathVec.h>
+#include "PyImath.h"
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Quat<T> > register_Quat();
+template <class T> boost::python::class_<PyImath::FixedArray<IMATH_NAMESPACE::Quat<T> > > register_QuatArray();
+typedef FixedArray<IMATH_NAMESPACE::Quatf>  QuatfArray;
+typedef FixedArray<IMATH_NAMESPACE::Quatd>  QuatdArray;
+
+}
+
+template <class T> inline IMATH_NAMESPACE::Vec3<T> operator * (const IMATH_NAMESPACE::Vec3<T> &v, const IMATH_NAMESPACE::Quat<T> &q) { return v * q.toMatrix33(); }
+
+template <class T> static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> >
+operator *(const IMATH_NAMESPACE::Vec3<T> &va, const PyImath::FixedArray<IMATH_NAMESPACE::Quat<T> > &vb)
+{ size_t len = vb.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i = 0; i < len; ++i) f[i] = va * vb[i]; return f; }
+
+template <class T> static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> >
+operator *(const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &va, const IMATH_NAMESPACE::Quat<T> &vb)
+{ size_t len = va.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i = 0; i < len; ++i) f[i] = va[i] * vb; return f; }
+
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> >
+operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &va, const PyImath::FixedArray<IMATH_NAMESPACE::Quat<T> > &vb)
+{ size_t len = va.match_dimension(vb); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i = 0; i < len; ++i) f[i] = va[i] * vb[i]; return f; }
+
+//
+
+namespace PyImath {
+
+// Other code in the Zeno code base assumes the existance of a class with the
+// same name as the Imath class, and with static functions wrap() and
+// convert() to produce a PyImath object from an Imath object and vice-versa,
+// respectively.  The class Boost generates from the Imath class does not
+// have these properties, so we define a companion class here.
+// The template argument, T, is the element type (e.g.,float, double).
+
+template <class T>
+class Q {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Quat<T> &q);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Quat<T> *q);
+};
+
+template <class T>
+PyObject *
+Q<T>::wrap (const IMATH_NAMESPACE::Quat<T> &q)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Quat<T> >::type converter;
+    PyObject *p = converter (q);
+    return p;
+}
+
+template <class T>
+int
+Q<T>::convert (PyObject *p, IMATH_NAMESPACE::Quat<T> *q)
+{
+    boost::python::extract <IMATH_NAMESPACE::Quatf> extractorQf (p);
+    if (extractorQf.check())
+    {
+        IMATH_NAMESPACE::Quatf qf = extractorQf();
+        q->r = T(qf.r);
+        q->v.setValue (qf.v);
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::Quatd> extractorQd (p);
+    if (extractorQd.check())
+    {
+        IMATH_NAMESPACE::Quatd qd = extractorQd();
+        q->r = T(qd.r);
+        q->v.setValue (qd.v);
+        return 1;
+    }
+
+    boost::python::extract <boost::python::tuple> extractorTuple (p);
+    if (extractorTuple.check())
+    {
+        boost::python::tuple t = extractorTuple();
+        if (t.attr ("__len__") () == 4)
+        {
+            // Extracting the tuple elements as doubles and casting them to
+            // Ts in setValue() works better than extracting them as Ts from
+            // the start.  
+
+            double r = boost::python::extract <double> (t[0]);
+            double x = boost::python::extract <double> (t[1]);
+            double y = boost::python::extract <double> (t[2]);
+            double z = boost::python::extract <double> (t[3]);
+            q->r = T(r);
+            q->v.setValue (T(x), T(y), T(z));
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+typedef Q<float>       Quatf;
+typedef Q<double>      Quatd;
+
+}
+
+
+#endif
diff --git a/src/python/PyImath/PyImathQuatOperators.h b/src/python/PyImath/PyImathQuatOperators.h
new file mode 100644 (file)
index 0000000..9ee235a
--- /dev/null
@@ -0,0 +1,42 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathQuatOperators_h_
+#define _PyImathQuatOperators_h_
+
+#include <ImathQuat.h>
+
+namespace PyImath {
+
+template <class T>
+struct op_quatDot {
+    static inline typename T::BaseType apply (const T &self, const T &qB)
+    { return self.euclideanInnerProduct (qB); }
+};
+
+template <class T>
+struct op_quatNormalize {
+    static inline void apply (T &self)
+    { self.normalize(); }
+};
+
+template <class T>
+struct op_quatNormalized {
+    static inline T apply (const T &self)
+    { return self.normalized(); }
+};
+
+template <class T>
+struct op_quatSlerp {
+    static inline T apply (const T &self, const T &qB, const typename T::BaseType t)
+        { return Imath::slerpShortestArc (self, qB, t); }
+};
+
+
+}  // namespace PyImath
+
+#endif // _PyImathQuatOperators_h_
diff --git a/src/python/PyImath/PyImathRandom.cpp b/src/python/PyImath/PyImathRandom.cpp
new file mode 100644 (file)
index 0000000..3ff1b0d
--- /dev/null
@@ -0,0 +1,327 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/format.hpp>
+#include <boost/python/make_constructor.hpp>
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathFixedArray.h"
+#include "PyImathRandom.h"
+#include "PyImathDecorators.h"
+
+namespace PyImath{
+using namespace boost::python;
+
+template <class Rand, class T>
+static T
+nextf2 (Rand &rand, T min, T max)
+{
+    MATH_EXC_ON;
+    return rand.nextf(min, max);
+}
+
+template <class Rand>
+static float
+nextGauss (Rand &rand)
+{
+    MATH_EXC_ON;
+    return gaussRand(rand);
+}
+
+template <class T, class Rand>
+static IMATH_NAMESPACE::Vec3<T> nextGaussSphere(Rand &rand, const IMATH_NAMESPACE::Vec3<T> &v)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::gaussSphereRand<IMATH_NAMESPACE::Vec3<T>,Rand>(rand);
+}
+template <class T, class Rand>
+static IMATH_NAMESPACE::Vec2<T> nextGaussSphere(Rand &rand, const IMATH_NAMESPACE::Vec2<T> &v)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::gaussSphereRand<IMATH_NAMESPACE::Vec2<T>,Rand>(rand);
+}
+
+template <class T, class Rand>
+static IMATH_NAMESPACE::Vec3<T> nextHollowSphere(Rand &rand, const IMATH_NAMESPACE::Vec3<T> &v)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::hollowSphereRand<IMATH_NAMESPACE::Vec3<T>,Rand>(rand);
+}
+
+template <class T, class Rand>
+static IMATH_NAMESPACE::Vec2<T> nextHollowSphere(Rand &rand, const IMATH_NAMESPACE::Vec2<T> &v)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::hollowSphereRand<IMATH_NAMESPACE::Vec2<T>,Rand>(rand);
+}
+
+template <class T, class Rand>
+static IMATH_NAMESPACE::Vec3<T> nextSolidSphere(Rand &rand, const IMATH_NAMESPACE::Vec3<T> &v)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::solidSphereRand<IMATH_NAMESPACE::Vec3<T>,Rand>(rand);
+}
+
+template <class T, class Rand>
+static IMATH_NAMESPACE::Vec2<T> nextSolidSphere(Rand &rand, const IMATH_NAMESPACE::Vec2<T> &v)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::solidSphereRand<IMATH_NAMESPACE::Vec2<T>,Rand>(rand);
+}
+
+template <class Rand>
+static Rand *Rand_constructor1(unsigned long int seed)
+{
+    return new Rand(seed);
+}
+
+template <class Rand>
+static Rand *Rand_constructor2(Rand rand)
+{
+    Rand *r = new Rand();
+    *r = rand;
+    
+    return r;
+}
+
+template <class T, class Rand>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> >
+hollowSphereRand(Rand &rand, int num)
+{
+    MATH_EXC_ON;
+    PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> >  retval(num);
+    for (int i=0; i<num; ++i) {
+        retval[i] = IMATH_NAMESPACE::hollowSphereRand<IMATH_NAMESPACE::Vec3<T>,Rand>(rand);
+    }
+    return retval;
+}
+
+template <class T, class Rand>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> >
+solidSphereRand(Rand &rand, int num)
+{
+    MATH_EXC_ON;
+    PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> >  retval(num);
+    for (int i=0; i<num; ++i) {
+        retval[i] = IMATH_NAMESPACE::solidSphereRand<IMATH_NAMESPACE::Vec3<T>,Rand>(rand);
+    }
+    return retval;
+}
+
+PYIMATH_EXPORT
+class_<IMATH_NAMESPACE::Rand32>
+register_Rand32()
+{
+    float (IMATH_NAMESPACE::Rand32::*nextf1)(void) = &IMATH_NAMESPACE::Rand32::nextf;
+    
+    IMATH_NAMESPACE::Vec3<float> (*nextGaussSphere1)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec3<float> &v) = &nextGaussSphere<float,IMATH_NAMESPACE::Rand32>;
+    IMATH_NAMESPACE::Vec3<double> (*nextGaussSphere2)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec3<double> &v) = &nextGaussSphere<double,IMATH_NAMESPACE::Rand32>;
+    IMATH_NAMESPACE::Vec2<float> (*nextGaussSphere3)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec2<float> &v) = &nextGaussSphere<float,IMATH_NAMESPACE::Rand32>;
+    IMATH_NAMESPACE::Vec2<double> (*nextGaussSphere4)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec2<double> &v) = &nextGaussSphere<double,IMATH_NAMESPACE::Rand32>;
+    
+    IMATH_NAMESPACE::Vec3<float> (*nextHollowSphere1)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec3<float> &v) = &nextHollowSphere<float,IMATH_NAMESPACE::Rand32>;
+    IMATH_NAMESPACE::Vec3<double> (*nextHollowSphere2)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec3<double> &v) = &nextHollowSphere<double,IMATH_NAMESPACE::Rand32>;
+    IMATH_NAMESPACE::Vec2<float> (*nextHollowSphere3)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec2<float> &v) = &nextHollowSphere<float,IMATH_NAMESPACE::Rand32>;
+    IMATH_NAMESPACE::Vec2<double> (*nextHollowSphere4)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec2<double> &v) = &nextHollowSphere<double,IMATH_NAMESPACE::Rand32>;
+
+    IMATH_NAMESPACE::Vec3<float> (*nextSolidSphere1)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec3<float> &v) = &nextSolidSphere<float,IMATH_NAMESPACE::Rand32>;
+    IMATH_NAMESPACE::Vec3<double> (*nextSolidSphere2)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec3<double> &v) = &nextSolidSphere<double,IMATH_NAMESPACE::Rand32>;
+    IMATH_NAMESPACE::Vec2<float> (*nextSolidSphere3)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec2<float> &v) = &nextSolidSphere<float,IMATH_NAMESPACE::Rand32>;
+    IMATH_NAMESPACE::Vec2<double> (*nextSolidSphere4)(IMATH_NAMESPACE::Rand32 &, const IMATH_NAMESPACE::Vec2<double> &v) = &nextSolidSphere<double,IMATH_NAMESPACE::Rand32>;
+    
+    class_< IMATH_NAMESPACE::Rand32 > rand32_class("Rand32");
+    rand32_class
+        .def(init<>("default construction"))
+        .def("__init__", make_constructor(Rand_constructor1<IMATH_NAMESPACE::Rand32>))
+        .def("__init__", make_constructor(Rand_constructor2<IMATH_NAMESPACE::Rand32>))
+        .def("init", &IMATH_NAMESPACE::Rand32::init,
+             "r.init(i) -- initialize with integer "
+                        "seed i")
+             
+        .def("nexti", &IMATH_NAMESPACE::Rand32::nexti,
+                "r.nexti() -- return the next integer "
+                        "value in the uniformly-distributed "
+                        "sequence")
+        .def("nextf", nextf1,
+                "r.nextf() -- return the next floating-point "
+                        "value in the uniformly-distributed "
+                        "sequence\n"
+             
+                "r.nextf(float, float) -- return the next floating-point "
+                        "value in the uniformly-distributed "
+                        "sequence")             
+        .def("nextf", &nextf2 <IMATH_NAMESPACE::Rand32, float>)
+             
+        .def("nextb", &IMATH_NAMESPACE::Rand32::nextb,
+                    "r.nextb() -- return the next boolean "
+                        "value in the uniformly-distributed "
+                        "sequence")
+
+        .def("nextGauss", &nextGauss<IMATH_NAMESPACE::Rand32>,
+                "r.nextGauss() -- returns the next "
+                        "floating-point value in the normally "
+                        "(Gaussian) distributed sequence")
+             
+        .def("nextGaussSphere", nextGaussSphere1, 
+                        "r.nextGaussSphere(v) -- returns the next "
+                        "point whose distance from the origin "
+                        "has a normal (Gaussian) distribution with "
+                        "mean 0 and variance 1.  The vector "
+                        "argument, v, specifies the dimension "
+                        "and number type.")             
+        .def("nextGaussSphere", nextGaussSphere2)             
+        .def("nextGaussSphere", nextGaussSphere3)             
+        .def("nextGaussSphere", nextGaussSphere4)
+        
+        .def("nextHollowSphere", nextHollowSphere1,
+                "r.nextHollowSphere(v) -- return the next "
+                        "point uniformly distributed on the surface "
+                        "of a sphere of radius 1 centered at the "
+                        "origin.  The vector argument, v, specifies "
+                        "the dimension and number type.")             
+        .def("nextHollowSphere", nextHollowSphere2)             
+        .def("nextHollowSphere", nextHollowSphere3)             
+        .def("nextHollowSphere", nextHollowSphere4)
+
+        .def("nextSolidSphere", nextSolidSphere1,
+                "r.nextSolidSphere(v) -- return the next "
+                        "point uniformly distributed in a sphere "
+                        "of radius 1 centered at the origin.  The "
+                        "vector argument, v, specifies the "
+                        "dimension and number type.")             
+        .def("nextSolidSphere", nextSolidSphere2)             
+        .def("nextSolidSphere", nextSolidSphere3)             
+        .def("nextSolidSphere", nextSolidSphere4)    
+        ;
+
+    def("hollowSphereRand",&hollowSphereRand<float,IMATH_NAMESPACE::Rand32>,"hollowSphereRand(randObj,num) return XYZ vectors uniformly "
+        "distributed across the surface of a sphere generated from the given Rand32 object",
+        args("randObj","num"));
+        
+    def("solidSphereRand",&solidSphereRand<float,IMATH_NAMESPACE::Rand32>,"solidSphereRand(randObj,num) return XYZ vectors uniformly "
+        "distributed through the volume of a sphere generated from the given Rand32 object",
+        args("randObj","num"));
+
+    decoratecopy(rand32_class);
+
+    return rand32_class;
+}
+
+PYIMATH_EXPORT
+class_<IMATH_NAMESPACE::Rand48>
+register_Rand48()
+{
+    double (IMATH_NAMESPACE::Rand48::*nextf1)(void) = &IMATH_NAMESPACE::Rand48::nextf;
+    
+    IMATH_NAMESPACE::Vec3<float> (*nextGaussSphere1)(IMATH_NAMESPACE::Rand48 &, const IMATH_NAMESPACE::Vec3<float> &v) = &nextGaussSphere<float,IMATH_NAMESPACE::Rand48>;
+    IMATH_NAMESPACE::Vec3<double> (*nextGaussSphere2)(IMATH_NAMESPACE::Rand48 &, const IMATH_NAMESPACE::Vec3<double> &v) = &nextGaussSphere<double,IMATH_NAMESPACE::Rand48>;
+    IMATH_NAMESPACE::Vec2<float> (*nextGaussSphere3)(IMATH_NAMESPACE::Rand48&, const IMATH_NAMESPACE::Vec2<float> &v) = &nextGaussSphere<float,IMATH_NAMESPACE::Rand48>;
+    IMATH_NAMESPACE::Vec2<double> (*nextGaussSphere4)(IMATH_NAMESPACE::Rand48 &, const IMATH_NAMESPACE::Vec2<double> &v) = &nextGaussSphere<double,IMATH_NAMESPACE::Rand48>;
+    
+    IMATH_NAMESPACE::Vec3<float> (*nextHollowSphere1)(IMATH_NAMESPACE::Rand48 &, const IMATH_NAMESPACE::Vec3<float> &v) = &nextHollowSphere<float,IMATH_NAMESPACE::Rand48>;
+    IMATH_NAMESPACE::Vec3<double> (*nextHollowSphere2)(IMATH_NAMESPACE::Rand48 &, const IMATH_NAMESPACE::Vec3<double> &v) = &nextHollowSphere<double,IMATH_NAMESPACE::Rand48>;
+    IMATH_NAMESPACE::Vec2<float> (*nextHollowSphere3)(IMATH_NAMESPACE::Rand48 &, const IMATH_NAMESPACE::Vec2<float> &v) = &nextHollowSphere<float,IMATH_NAMESPACE::Rand48>;
+    IMATH_NAMESPACE::Vec2<double> (*nextHollowSphere4)(IMATH_NAMESPACE::Rand48 &, const IMATH_NAMESPACE::Vec2<double> &v) = &nextHollowSphere<double,IMATH_NAMESPACE::Rand48>;
+
+    IMATH_NAMESPACE::Vec3<float> (*nextSolidSphere1)(IMATH_NAMESPACE::Rand48 &, const IMATH_NAMESPACE::Vec3<float> &v) = &nextSolidSphere<float,IMATH_NAMESPACE::Rand48>;
+    IMATH_NAMESPACE::Vec3<double> (*nextSolidSphere2)(IMATH_NAMESPACE::Rand48 &, const IMATH_NAMESPACE::Vec3<double> &v) = &nextSolidSphere<double,IMATH_NAMESPACE::Rand48>;
+    IMATH_NAMESPACE::Vec2<float> (*nextSolidSphere3)(IMATH_NAMESPACE::Rand48&, const IMATH_NAMESPACE::Vec2<float> &v) = &nextSolidSphere<float,IMATH_NAMESPACE::Rand48>;
+    IMATH_NAMESPACE::Vec2<double> (*nextSolidSphere4)(IMATH_NAMESPACE::Rand48 &, const IMATH_NAMESPACE::Vec2<double> &v) = &nextSolidSphere<double,IMATH_NAMESPACE::Rand48>;
+   
+    class_< IMATH_NAMESPACE::Rand48 > rand48_class("Rand48");
+    rand48_class
+        .def(init<>("default construction"))
+        .def("__init__", make_constructor(Rand_constructor1<IMATH_NAMESPACE::Rand48>))
+        .def("__init__", make_constructor(Rand_constructor2<IMATH_NAMESPACE::Rand48>))
+        .def("init", &IMATH_NAMESPACE::Rand48::init,
+             "r.init(i) -- initialize with integer "
+                        "seed i")
+             
+        .def("nexti", &IMATH_NAMESPACE::Rand48::nexti,
+                "r.nexti() -- return the next integer "
+                        "value in the uniformly-distributed "
+                        "sequence")
+             
+        .def("nextf", nextf1,
+                "r.nextf() -- return the next double "
+                        "value in the uniformly-distributed "
+                        "sequence\n"
+             
+                "r.nextf(double,double) -- return the next double "
+                        "value in the uniformly-distributed "
+                        "sequence")             
+        .def("nextf", &nextf2 <IMATH_NAMESPACE::Rand48, double>)
+             
+        .def("nextb", &IMATH_NAMESPACE::Rand48::nextb,
+                    "r.nextb() -- return the next boolean "
+                        "value in the uniformly-distributed "
+                        "sequence")
+        .def("nextGauss", &nextGauss<IMATH_NAMESPACE::Rand48>,
+                "r.nextGauss() -- returns the next "
+                        "floating-point value in the normally "
+                        "(Gaussian) distributed sequence")
+             
+        .def("nextGaussSphere", nextGaussSphere1, 
+                        "r.nextGaussSphere(v) -- returns the next "
+                        "point whose distance from the origin "
+                        "has a normal (Gaussian) distribution with "
+                        "mean 0 and variance 1.  The vector "
+                        "argument, v, specifies the dimension "
+                        "and number type.")             
+        .def("nextGaussSphere", nextGaussSphere2)             
+        .def("nextGaussSphere", nextGaussSphere3)             
+        .def("nextGaussSphere", nextGaussSphere4)
+        
+        .def("nextHollowSphere", nextHollowSphere1,
+                "r.nextHollowSphere(v) -- return the next "
+                        "point uniformly distributed on the surface "
+                        "of a sphere of radius 1 centered at the "
+                        "origin.  The vector argument, v, specifies "
+                        "the dimension and number type.")             
+        .def("nextHollowSphere", nextHollowSphere2)             
+        .def("nextHollowSphere", nextHollowSphere3)             
+        .def("nextHollowSphere", nextHollowSphere4)
+
+        .def("nextSolidSphere", nextSolidSphere1,
+                "r.nextSolidSphere(v) -- return the next "
+                        "point uniformly distributed in a sphere "
+                        "of radius 1 centered at the origin.  The "
+                        "vector argument, v, specifies the "
+                        "dimension and number type.")             
+        .def("nextSolidSphere", nextSolidSphere2)             
+        .def("nextSolidSphere", nextSolidSphere3)             
+        .def("nextSolidSphere", nextSolidSphere4) 
+        ;
+
+    decoratecopy(rand48_class);
+
+    return rand48_class;
+}
+
+//
+
+PyObject *
+Rand32::wrap (const IMATH_NAMESPACE::Rand32 &r)
+{
+    boost::python::return_by_value::apply <IMATH_NAMESPACE::Rand32>::type converter;
+    PyObject *p = converter (r);
+    return p;
+}
+
+PyObject *
+Rand48::wrap (const IMATH_NAMESPACE::Rand48 &r)
+{
+    boost::python::return_by_value::apply <IMATH_NAMESPACE::Rand48>::type converter;
+    PyObject *p = converter (r);
+    return p;
+}
+
+} //namespace PyIMath
diff --git a/src/python/PyImath/PyImathRandom.h b/src/python/PyImath/PyImathRandom.h
new file mode 100644 (file)
index 0000000..8ed9417
--- /dev/null
@@ -0,0 +1,36 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathRandom_h_
+#define _PyImathRandom_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <ImathRandom.h>
+#include "PyImathExport.h"
+
+namespace PyImath {
+
+PYIMATH_EXPORT boost::python::class_<IMATH_NAMESPACE::Rand32> register_Rand32();
+PYIMATH_EXPORT boost::python::class_<IMATH_NAMESPACE::Rand48> register_Rand48();
+
+class PYIMATH_EXPORT Rand32
+{
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Rand32 &r);
+};
+
+class PYIMATH_EXPORT Rand48
+{
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Rand48 &r);
+};
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathShear.cpp b/src/python/PyImath/PyImathShear.cpp
new file mode 100644 (file)
index 0000000..ca6b790
--- /dev/null
@@ -0,0 +1,558 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathShear.h"
+#include "PyImathPlane.h"
+#include "PyImathDecorators.h"
+#include "PyImathExport.h"
+
+
+namespace PyImath{
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct ShearName {static const char *value;};
+template <> const char *ShearName<float>::value = "Shear6f";
+template <> const char *ShearName<double>::value = "Shear6d";
+
+template <class T>
+static std::string Shear_str(const Shear6<T> &v)
+{
+    std::stringstream stream;
+    stream << ShearName<T>::value << "(" 
+           << v[0] << ", " << v[1] << ", " << v[2] << ", "
+           << v[3] << ", " << v[4] << ", " << v[5] << ")";
+    return stream.str();
+}
+
+// Non-specialized repr is same as str
+template <class T>
+static std::string Shear_repr(const Shear6<T> &v)
+{
+    return Shear_str(v);
+}
+
+// Specialization for float to full precision
+template <>
+std::string Shear_repr(const Shear6<float> &v)
+{
+    return (boost::format("%s(%.9g, %.9g, %.9g, %.9g, %.9g, %.9g)")
+                        % ShearName<float>::value
+                        % v[0] % v[1] % v[2]
+                        % v[3] % v[4] % v[5]).str();
+}
+
+// Specialization for double to full precision
+template <>
+std::string Shear_repr(const Shear6<double> &v)
+{
+    return (boost::format("%s(%.17g, %.17g, %.17g, %.17g, %.17g, %.17g)")
+                        % ShearName<double>::value
+                        % v[0] % v[1] % v[2]
+                        % v[3] % v[4] % v[5]).str();
+}
+
+template <class T>
+static Shear6<T> * shearTupleConstructor(tuple t)
+{
+    if(t.attr("__len__")() == 3){
+        return new Shear6<T>(extract<T>(t[0]), extract<T>(t[1]), extract<T>(t[2]),
+                             T(0), T(0), T(0));
+    }
+    else if(t.attr("__len__")() == 6){
+        return new Shear6<T>(extract<T>(t[0]), extract<T>(t[1]), extract<T>(t[2]),
+                             extract<T>(t[3]), extract<T>(t[4]), extract<T>(t[5]));        
+    }
+    else
+      throw std::invalid_argument ("Shear6 expects tuple of length 3 or 6");
+}
+
+template <class T>
+static Shear6<T> * shearConstructor1(T a)
+{
+    return new Shear6<T>(a, a, a, a, a, a);
+}
+
+template <class T, class S>
+static Shear6<T> * shearConversionConstructor(const Shear6<S> &shear)
+{
+    Shear6<T> *s = new Shear6<T>;
+    *s = shear;
+    return s;
+}
+
+template <class T>
+static const Shear6<T> &
+iadd(Shear6<T> &shear, const Shear6<T> &other)
+{
+    MATH_EXC_ON;
+    return shear += other;
+}
+
+template <class T>
+static Shear6<T>
+add(const Shear6<T> &shear, const Shear6<T> &other)
+{
+    MATH_EXC_ON;
+    return shear + other;
+}
+
+template <class T>
+static const Shear6<T> &
+isub(Shear6<T> &shear, const Shear6<T> &other)
+{
+    MATH_EXC_ON;
+    return shear -= other;
+}
+
+template <class T>
+static Shear6<T>
+sub(const Shear6<T> &shear, const Shear6<T> &other)
+{
+    MATH_EXC_ON;
+    return shear - other;
+}
+
+template <class T>
+static Shear6<T>
+neg(const Shear6<T> &shear)
+{
+    MATH_EXC_ON;
+    return -shear;
+}
+
+template <class T>
+static const Shear6<T> &
+imul(Shear6<T> &shear, const Shear6<T> &other)
+{
+    MATH_EXC_ON;
+    return shear *= other;
+}
+
+template <class T>
+static const Shear6<T> &
+imulT(Shear6<T> &shear, T t)
+{
+    MATH_EXC_ON;
+    return shear *= t;
+}
+
+template <class T>
+static Shear6<T>
+mul(const Shear6<T> &shear, const Shear6<T> &other)
+{
+    MATH_EXC_ON;
+    return shear * other;
+}
+
+template <class T>
+static Shear6<T>
+mulT(const Shear6<T> &shear, T t)
+{
+    MATH_EXC_ON;
+    return shear * t;
+}
+
+template <class T>
+static const Shear6<T> &
+idiv(Shear6<T> &shear, const Shear6<T> &other)
+{
+    MATH_EXC_ON;
+    return shear /= other;
+}
+
+template <class T>
+static const Shear6<T> &
+idivT(Shear6<T> &shear, T t)
+{
+    MATH_EXC_ON;
+    return shear /= t;
+}
+
+template <class T>
+static Shear6<T>
+div(const Shear6<T> &shear, const Shear6<T> &other)
+{
+    MATH_EXC_ON;
+    return shear / other;
+}
+
+template <class T>
+static Shear6<T>
+divT(const Shear6<T> &shear, T t)
+{
+    MATH_EXC_ON;
+    return shear / t;
+}
+
+template <class T>
+static Shear6<T>
+subtract1(Shear6<T> &v, tuple t)
+{
+    MATH_EXC_ON;
+    Shear6<T> w;
+    
+    if(t.attr("__len__")() == 6){
+        w[0] = v[0] - extract<T>(t[0]);
+        w[1] = v[1] - extract<T>(t[1]);   
+        w[2] = v[2] - extract<T>(t[2]);
+        w[3] = v[3] - extract<T>(t[3]);
+        w[4] = v[4] - extract<T>(t[4]);   
+        w[5] = v[5] - extract<T>(t[5]);
+    }        
+    else
+        throw std::domain_error ("tuple must have length of 6");
+    
+    return w;
+}
+
+template <class T>
+static Shear6<T>
+subtract2(Shear6<T> &v, tuple t)
+{
+    MATH_EXC_ON;
+    Shear6<T> w;
+    
+    if(t.attr("__len__")() == 6){
+        w[0] = extract<T>(t[0]) - v[0];
+        w[1] = extract<T>(t[1]) - v[1];   
+        w[2] = extract<T>(t[2]) - v[2];
+        w[3] = extract<T>(t[3]) - v[3];
+        w[4] = extract<T>(t[4]) - v[4];   
+        w[5] = extract<T>(t[5]) - v[5];
+    }        
+    else
+        throw std::domain_error ("tuple must have length of 6");
+    
+    return w;
+}
+
+template <class T>
+static Shear6<T>
+subtractT1(Shear6<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Shear6<T> w;
+    
+    w[0] = v[0] - a;
+    w[1] = v[1] - a;   
+    w[2] = v[2] - a;
+    w[3] = v[3] - a;
+    w[4] = v[4] - a;   
+    w[5] = v[5] - a;
+
+    return w;
+}
+
+template <class T>
+static Shear6<T>
+subtractT2(Shear6<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Shear6<T> w;
+
+     w[0] = a - v[0];
+     w[1] = a - v[1];   
+     w[2] = a - v[2];
+     w[3] = a - v[3];
+     w[4] = a - v[4];   
+     w[5] = a - v[5];
+
+    return w;
+}
+
+
+template <class T>
+static Shear6<T>
+addTuple(Shear6<T> &v, tuple t)
+{
+    MATH_EXC_ON;
+    Shear6<T> w;
+    
+    if(t.attr("__len__")() == 6){
+        w[0] = v[0] + extract<T>(t[0]);
+        w[1] = v[1] + extract<T>(t[1]);   
+        w[2] = v[2] + extract<T>(t[2]);
+        w[3] = v[3] + extract<T>(t[3]);
+        w[4] = v[4] + extract<T>(t[4]);   
+        w[5] = v[5] + extract<T>(t[5]);
+    }        
+    else
+        throw std::domain_error ("tuple must have length of 6");
+    
+    return w;
+}
+
+template <class T>
+static Shear6<T>
+addT(Shear6<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Shear6<T> w;
+
+     w[0] = v[0] + a;
+     w[1] = v[1] + a;   
+     w[2] = v[2] + a;
+     w[3] = v[3] + a;
+     w[4] = v[4] + a;   
+     w[5] = v[5] + a;
+    
+    return w;
+}
+
+template <class T>
+static Shear6<T>
+multTuple(Shear6<T> &v, tuple t)
+{
+    MATH_EXC_ON;
+    Shear6<T> w;
+    
+    if(t.attr("__len__")() == 6){
+        w[0] = v[0] * extract<T>(t[0]);
+        w[1] = v[1] * extract<T>(t[1]);   
+        w[2] = v[2] * extract<T>(t[2]);
+        w[3] = v[3] * extract<T>(t[3]);
+        w[4] = v[4] * extract<T>(t[4]);   
+        w[5] = v[5] * extract<T>(t[5]);
+    }        
+    else
+        throw std::domain_error ("tuple must have length of 6");
+    
+    return w;
+}
+
+template <class T>
+static Shear6<T>
+rdiv(Shear6<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Shear6<T> w;
+    
+    if(v != Shear6<T>()){
+        w[0] = a/v[0];
+        w[1] = a/v[1];
+        w[2] = a/v[2];
+        w[3] = a/v[3];
+        w[4] = a/v[4];
+        w[5] = a/v[5];
+    }
+    else
+        throw std::domain_error ("Division by Zero");
+    
+    return w;
+}
+
+template <class T>
+static Shear6<T>
+divTuple(Shear6<T> &v, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() != 6)
+        throw std::domain_error ("Shear6 expects tuple of length 6");
+    
+    Shear6<T> w;
+    for(int i = 0; i < 6; ++i)
+    {
+        T a = extract<T>(t[i]);
+        if(a != T (0))
+            w[i] = v[i] / a;
+        else
+            throw std::domain_error ("Division by Zero"); 
+    }
+    
+    return w;
+}
+
+template <class T>
+static Shear6<T>
+rdivTuple(Shear6<T> &v, const tuple &t)
+{
+    MATH_EXC_ON;
+    if(t.attr("__len__")() != 6)
+        throw std::domain_error ("Shear6 expects tuple of length 6");
+    
+    Shear6<T> w;
+    for(int i = 0; i < 6; ++i)
+    {
+        T a = extract<T>(t[i]);
+        if(v[i] != T (0))
+            w[i] = a / v[i];
+        else
+            throw std::domain_error ("Division by Zero"); 
+    }
+    
+    return w;
+}
+
+template <class T>
+static bool
+lessThan(Shear6<T> &v, const Shear6<T> &w)
+{
+    bool isLessThan = (v[0] <= w[0] && v[1] <= w[1] && v[2] <= w[2] 
+                    && v[3] <= w[3] && v[4] <= w[4] && v[5] <= w[5])
+                    && v != w;
+                   
+   return isLessThan;
+}
+
+template <class T>
+static bool
+greaterThan(Shear6<T> &v, const Shear6<T> &w)
+{
+    bool isGreaterThan = (v[0] >= w[0] && v[1] >= w[1] && v[2] >= w[2] 
+                       && v[3] >= w[3] && v[4] >= w[4] && v[5] >= w[5])
+                       && v != w;
+                   
+   return isGreaterThan;
+}
+
+template <class T>
+static bool
+lessThanEqual(Shear6<T> &v, const Shear6<T> &w)
+{
+    bool isLessThanEqual = (v[0] <= w[0] && v[1] <= w[1] && v[2] <= w[2] 
+                         && v[3] <= w[3] && v[4] <= w[4] && v[5] <= w[5]);
+                   
+   return isLessThanEqual;
+}
+
+template <class T>
+static bool
+greaterThanEqual(Shear6<T> &v, const Shear6<T> &w)
+{
+    bool isGreaterThanEqual = (v[0] >= w[0] && v[1] >= w[1] && v[2] >= w[2] 
+                            && v[3] >= w[3] && v[4] >= w[4] && v[5] >= w[5]);
+                   
+   return isGreaterThanEqual;
+}
+
+template <class T>
+static T
+getitem(Shear6<T> &shear, int i)
+{
+    return shear[i];
+}
+
+template <class T>
+static void
+setitem(Shear6<T> &shear, int i, T a)
+{
+    if(i < 0 || i > 5)
+        throw std::domain_error ("Index out of range");
+    
+    shear[i] = a;
+}
+
+template <class T>
+static int
+len(Shear6<T> &shear)
+{
+    return 6;
+}
+
+
+
+template <class T>
+class_<Shear6<T> >
+register_Shear()
+{
+    const char *name = ShearName<T>::value;
+    
+    void (IMATH_NAMESPACE::Shear6<T>::*setValue1)(T,T,T,T,T,T) = &IMATH_NAMESPACE::Shear6<T>::setValue;
+    void (IMATH_NAMESPACE::Shear6<T>::*setValue2)(const Shear6<T> &) = &IMATH_NAMESPACE::Shear6<T>::setValue;
+    void (IMATH_NAMESPACE::Shear6<T>::*getValue1)(Shear6<T> &) const = &IMATH_NAMESPACE::Shear6<T>::getValue;
+    
+    class_<Shear6<T> > shear_class(name, name, init<Shear6<T> >("copy construction"));
+    shear_class
+        .def(init<>("default construction: (0 0 0 0 0 0)"))
+        .def(init<T,T,T>("Shear(XY,XZ,YZ) construction: (XY XZ YZ 0 0 0)"))
+        .def(init<const Vec3<float> &>("Shear(v) construction: (v.x v.y v.z 0 0 0)"))
+        .def(init<const Vec3<double> &>("Shear(v) construction: (v.x v.y v.z 0 0 0)"))
+        .def(init<const Vec3<int> &>("Shear(v) construction: (v.x v.y v.z 0 0 0)"))
+        .def(init<T,T,T,T,T,T>("Shear(XY, XZ, YZ, YX, ZX, ZY) construction"))
+        .def("__init__", make_constructor(shearConstructor1<T>))
+        .def("__init__", make_constructor(shearTupleConstructor<T>),"Construction from tuple")
+        .def("__init__", make_constructor(shearConversionConstructor<T,float>))
+        .def("__init__", make_constructor(shearConversionConstructor<T,double>))
+        .def("__init__", make_constructor(shearConversionConstructor<T,int>))
+        .def("__iadd__",&iadd<T>,return_internal_reference<>())
+        .def("__add__",&add<T>)
+        .def("__isub__",&isub<T>,return_internal_reference<>())
+        .def("__sub__",&sub<T>)
+        .def("__neg__",&neg<T>)
+        .def("__imul__",&imul<T>,return_internal_reference<>())
+        .def("__imul__",&imulT<T>,return_internal_reference<>())
+        .def("__mul__",&mul<T>)
+        .def("__mul__",&mulT<T>)
+        .def("__rmul__",&mulT<T>)
+        .def("__idiv__",&idiv<T>,return_internal_reference<>())
+        .def("__idiv__",&idivT<T>,return_internal_reference<>())
+        .def("__itruediv__",&idiv<T>,return_internal_reference<>())
+        .def("__itruediv__",&idivT<T>,return_internal_reference<>())
+        .def("__div__",&div<T>)
+        .def("__div__",&divT<T>)
+        .def("__truediv__",&div<T>)
+        .def("__truediv__",&divT<T>)
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__str__",&Shear_str<T>)
+        .def("__repr__",&Shear_repr<T>)
+        .def("setValue", setValue1)
+        .def("setValue", setValue2)
+        .def("getValue", getValue1)
+        .def("negate", &Shear6<T>::negate, return_internal_reference<>())
+        .def("baseTypeLowest", &Shear6<T>::baseTypeLowest)
+        .staticmethod("baseTypeLowest")
+        .def("baseTypeMax", &Shear6<T>::baseTypeMax)
+        .staticmethod("baseTypeMax")
+        .def("baseTypeSmallest", &Shear6<T>::baseTypeSmallest)
+        .staticmethod("baseTypeSmallest")
+        .def("baseTypeEpsilon", &Shear6<T>::baseTypeEpsilon)
+        .staticmethod("baseTypeEpsilon")
+        .def("equalWithAbsError", &Shear6<T>::equalWithAbsError)
+        .def("equalWithRelError", &Shear6<T>::equalWithRelError)
+        .def("__sub__", &subtract1<T>)
+        .def("__sub__", &subtractT1<T>)
+        .def("__rsub__", &subtract2<T>)
+        .def("__rsub__", &subtractT2<T>)
+        .def("__add__", &addTuple<T>)
+        .def("__add__", &addT<T>)
+        .def("__radd__", &addTuple<T>)
+        .def("__radd__", &addT<T>)
+        .def("__mul__", &multTuple<T>)
+        .def("__rmul__", &multTuple<T>)
+        .def("__div__", &divTuple<T>)
+        .def("__truediv__", &divTuple<T>)
+        .def("__rdiv__", &rdiv<T>)
+        .def("__rdiv__", &rdivTuple<T>)
+        .def("__rtruediv__", &rdiv<T>)
+        .def("__rtruediv__", &rdivTuple<T>)
+        .def("__lt__", &lessThan<T>)
+        .def("__gt__", &greaterThan<T>)
+        .def("__le__", &lessThanEqual<T>)
+        .def("__ge__", &greaterThanEqual<T>)
+        .def("__getitem__", &getitem<T>)
+        .def("__setitem__", &setitem<T>)
+        .def("__len__", &len<T>)
+        ;
+
+    decoratecopy(shear_class);
+
+    return shear_class;
+}
+
+template PYIMATH_EXPORT class_<Shear6<float> > register_Shear();
+template PYIMATH_EXPORT class_<Shear6<double> > register_Shear();
+
+}//namespace PyIMath
diff --git a/src/python/PyImath/PyImathShear.h b/src/python/PyImath/PyImathShear.h
new file mode 100644 (file)
index 0000000..06596dd
--- /dev/null
@@ -0,0 +1,128 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathShear_h_
+#define _PyImathShear_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <ImathShear.h>
+
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Shear6<T> > register_Shear();
+
+//
+
+// Other code in the Zeno code base assumes the existance of a class with the
+// same name as the Imath class, and with static functions wrap() and
+// convert() to produce a PyImath object from an Imath object and vice-versa,
+// respectively.  The class Boost generates from the Imath class does not
+// have these properties, so we define a companion class here.
+// The template argument, T, is the element type (e.g.,float, double).
+
+template <class T>
+class S6 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Shear6<T> &s);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Shear6<T> *s);
+};
+
+template <class T>
+PyObject *
+S6<T>::wrap (const IMATH_NAMESPACE::Shear6<T> &s)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Shear6<T> >::type converter;
+    PyObject *p = converter (s);
+    return p;
+}
+
+template <class T>
+int
+S6<T>::convert (PyObject *p, IMATH_NAMESPACE::Shear6<T> *s)
+{
+    boost::python::extract <IMATH_NAMESPACE::Shear6f> extractorShear6f (p);
+    if (extractorShear6f.check())
+    {
+        IMATH_NAMESPACE::Shear6f s6f = extractorShear6f();
+       float xy, xz, yz, yx, zx, zy;
+       s6f.getValue (xy, xz, yz, yx, zx, zy);
+       s->setValue(T(xy), T(xz), T(yz), T(yx), T(zx), T(zy));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::Shear6d> extractorShear6d (p);
+    if (extractorShear6d.check())
+    {
+        IMATH_NAMESPACE::Shear6d s6d = extractorShear6d();
+       double xy, xz, yz, yx, zx, zy;
+       s6d.getValue (xy, xz, yz, yx, zx, zy);
+       s->setValue(T(xy), T(xz), T(yz), T(yx), T(zx), T(zy));
+        return 1;
+    }
+
+    boost::python::extract <boost::python::tuple> extractorTuple (p);
+    if (extractorTuple.check())
+    {
+        boost::python::tuple t = extractorTuple();
+        if (t.attr ("__len__") () == 3)
+        {
+            double xy = boost::python::extract <double> (t[0]);
+            double xz = boost::python::extract <double> (t[1]);
+            double yz = boost::python::extract <double> (t[2]);
+            s->setValue (T(xy), T(xz), T(yz), T(0), T(0), T(0));
+            return 1;
+        }
+
+        else if (t.attr ("__len__") () == 6)
+        {
+            double xy = boost::python::extract <double> (t[0]);
+            double xz = boost::python::extract <double> (t[1]);
+            double yz = boost::python::extract <double> (t[2]);
+            double yx = boost::python::extract <double> (t[3]);
+            double zx = boost::python::extract <double> (t[4]);
+            double zy = boost::python::extract <double> (t[5]);
+            s->setValue (T(xy), T(xz), T(yz), T(yx), T(zx), T(zy));
+            return 1;
+        }
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V3i> extractorV3i (p);
+    if (extractorV3i.check())
+    {
+        IMATH_NAMESPACE::V3i v3i = extractorV3i();
+        s->setValue (T(v3i[0]), T(v3i[1]), T(v3i[2]), T(0), T(0), T(0));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V3f> extractorV3f (p);
+    if (extractorV3f.check())
+    {
+        IMATH_NAMESPACE::V3f v3f = extractorV3f();
+        s->setValue (T(v3f[0]), T(v3f[1]), T(v3f[2]), T(0), T(0), T(0));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V3d> extractorV3d (p);
+    if (extractorV3d.check())
+    {
+        IMATH_NAMESPACE::V3d v3d = extractorV3d();
+        s->setValue (T(v3d[0]), T(v3d[1]), T(v3d[2]), T(0), T(0), T(0));
+        return 1;
+    }
+
+    return 0;
+}
+
+typedef S6<float>      Shear6f;
+typedef S6<double>     Shear6d;
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathStringArray.cpp b/src/python/PyImath/PyImathStringArray.cpp
new file mode 100644 (file)
index 0000000..a049ff7
--- /dev/null
@@ -0,0 +1,358 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathStringArrayRegister.h"
+#include "PyImathStringArray.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+
+using namespace boost::python;
+
+template<class T>
+StringArrayT<T>* StringArrayT<T>::createDefaultArray(size_t length)
+{
+    return StringArrayT<T>::createUniformArray(T(), length);
+}
+
+template<class T>
+StringArrayT<T>* StringArrayT<T>::createUniformArray(const T& initialValue, size_t length)
+{
+    typedef boost::shared_array<StringTableIndex> StringTableIndexArrayPtr;
+    typedef boost::shared_ptr<StringTableT<T> > StringTablePtr;
+
+    BOOST_STATIC_ASSERT(boost::is_pod<StringTableIndex>::value);
+
+    StringTableIndexArrayPtr indexArray(reinterpret_cast<StringTableIndex*>(new char[sizeof(StringTableIndex)*length]));
+    StringTablePtr table(new StringTableT<T>);
+
+    const StringTableIndex index = table->intern(initialValue);
+
+    for(size_t i=0; i<length; ++i)
+        indexArray[i] = index;
+
+    return new StringArrayT<T>(*table, indexArray.get(), length, 1, indexArray, boost::any(table));
+}
+
+template<class T>
+StringArrayT<T>* StringArrayT<T>::createFromRawArray(const T* rawArray, size_t length, bool writable)
+{
+    typedef boost::shared_array<StringTableIndex> StringTableIndexArrayPtr;
+    typedef boost::shared_ptr<StringTableT<T> > StringTablePtr;
+
+    BOOST_STATIC_ASSERT(boost::is_pod<StringTableIndex>::value);
+
+    StringTableIndexArrayPtr indexArray(reinterpret_cast<StringTableIndex*>(new char[sizeof(StringTableIndex)*length]));
+    StringTablePtr table(new StringTableT<T>);
+
+    for(size_t i=0; i<length; ++i)
+        indexArray[i] = table->intern(rawArray[i]);
+
+    return new StringArrayT<T>(*table, indexArray.get(), length, 1, indexArray, table, writable);
+}
+
+template<class T>
+StringArrayT<T>::StringArrayT(StringTableT<T> &table, StringTableIndex *ptr, size_t length,
+                              size_t stride, boost::any tableHandle, bool writable)
+    : super(ptr,length,stride,writable), _table(table), _tableHandle(tableHandle)
+{
+    // nothing
+}
+
+template<class T>
+StringArrayT<T>::StringArrayT(StringTableT<T> &table, StringTableIndex *ptr, size_t length,
+                              size_t stride, boost::any handle, boost::any tableHandle, bool writable)
+    : super(ptr,length,stride,handle,writable), _table(table), _tableHandle(tableHandle)
+{
+    // nothing
+}
+
+template<class T>
+StringArrayT<T>::StringArrayT(const StringTableT<T> &table, const StringTableIndex *ptr,
+                              size_t length, size_t stride, boost::any tableHandle)
+    : super(ptr,length,stride), _table(const_cast<StringTableT<T> &>(table)),
+                                _tableHandle(tableHandle)
+{
+    // nothing
+}
+
+template<class T>
+StringArrayT<T>::StringArrayT(const StringTableT<T> &table, const StringTableIndex *ptr,
+                              size_t length, size_t stride, boost::any handle, boost::any tableHandle)
+    : super(ptr,length,stride,handle), _table(const_cast<StringTableT<T> &>(table)),
+                                       _tableHandle(tableHandle)
+{
+    // nothing
+}
+
+template<class T>
+StringArrayT<T>::StringArrayT(StringArrayT& s, const FixedArray<int>& mask)
+    : super(s, mask),
+      _table(s._table),
+      _tableHandle(s._tableHandle)
+{
+}
+
+template<class T>
+StringArrayT<T>*
+StringArrayT<T>::getslice_string(PyObject *index) const
+{
+    typedef boost::shared_array<StringTableIndex> StringTableIndexArrayPtr;
+    typedef boost::shared_ptr<StringTableT<T> > StringTablePtr;
+
+    BOOST_STATIC_ASSERT(boost::is_pod<StringTableIndex>::value);
+
+    size_t start=0, end=0, slicelength=0;
+    Py_ssize_t step;
+    extract_slice_indices(index,start,end,step,slicelength);
+
+    StringTableIndexArrayPtr indexArray(reinterpret_cast<StringTableIndex*>(new char[sizeof(StringTableIndex)*slicelength]));
+    StringTablePtr table(new StringTableT<T>);
+
+    for(size_t i=0; i<slicelength; ++i)
+        indexArray[i] = table->intern(getitem_string(start+i*step));
+
+    return new StringArrayT<T>(*table, indexArray.get(), slicelength, 1, indexArray, boost::any(table));
+}
+
+template<class T>
+StringArrayT<T>*
+StringArrayT<T>::getslice_mask_string(const FixedArray<int>& mask)
+{
+    return new StringArrayT(*this, mask);
+}
+
+template<class T>
+void
+StringArrayT<T>::setitem_string_scalar(PyObject *index, const T &data)
+{
+    if (!writable())
+        throw std::invalid_argument("Fixed string-array is read-only.");
+
+    size_t start=0, end=0, slicelength=0;
+    Py_ssize_t step;
+    extract_slice_indices(index,start,end,step,slicelength);
+    StringTableIndex di = _table.intern(data);
+    for (size_t i=0; i<slicelength; ++i) {
+        (*this)[start+i*step] = di;
+    }
+}
+
+template<class T>
+void
+StringArrayT<T>::setitem_string_scalar_mask(const FixedArray<int> &mask, const T &data)
+{
+    if (!writable())
+        throw std::invalid_argument("Fixed string-array is read-only.");
+
+    size_t len = match_dimension(mask);
+    StringTableIndex di = _table.intern(data);
+    for (size_t i=0; i<len; ++i) {
+        if (mask[i]) (*this)[i] = di;
+    }
+}
+
+template<class T>
+void
+StringArrayT<T>::setitem_string_vector(PyObject *index, const StringArrayT<T> &data)
+{
+    if (!writable())
+        throw std::invalid_argument("Fixed string-array is read-only.");
+
+    size_t start=0, end=0, slicelength=0;
+    Py_ssize_t step;
+    extract_slice_indices(index,start,end,step,slicelength);
+        
+    // we have a valid range of indices
+    if ((size_t) data.len() != slicelength) {
+        PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
+        throw_error_already_set();
+    }
+    for (size_t i=0; i<slicelength; ++i) {
+        StringTableIndex di = _table.intern(data._table.lookup(data[i]));
+        (*this)[start+i*step] = di;
+    }
+}
+
+template<class T>
+void
+StringArrayT<T>::setitem_string_vector_mask(const FixedArray<int> &mask, const StringArrayT<T> &data)
+{
+    if (!writable())
+        throw std::invalid_argument("Fixed string-array is read-only.");
+
+    size_t len = match_dimension(mask);
+    if ((size_t) data.len() == len) {
+        for (size_t i=0; i<len; ++i) {
+            if (mask[i]) {
+                StringTableIndex di = _table.intern(data._table.lookup(data[i]));
+                (*this)[i] = di;
+            }
+        }
+    } else {
+        size_t count = 0;
+        for (size_t i=0; i<len; ++i) {
+            if (mask[i]) count += 1;
+        }
+
+        if ((size_t) data.len() != count) {
+            PyErr_SetString(PyExc_IndexError, "Dimensions of source data do not match destination either masked or unmasked");
+            throw_error_already_set();
+        }
+            
+        size_t dataIndex = 0;
+        for (size_t i=0; i<len; ++i) {
+            if (mask[i]) {
+                StringTableIndex di = _table.intern(data._table.lookup(data[dataIndex]));
+                (*this)[i] = di;
+                dataIndex += 1;
+            }
+        }
+    }
+}
+
+template<class T>
+FixedArray<int> operator == (const StringArrayT<T> &a0, const StringArrayT<T> &a1) {
+    size_t len = a0.match_dimension(a1);
+    FixedArray<int> f(len);
+    const StringTableT<T> &t0 = a0.stringTable();
+    const StringTableT<T> &t1 = a1.stringTable();
+    for (size_t i=0;i<len;++i) {
+     f[i] = t0.lookup(a0[i])==t1.lookup(a1[i]); 
+    }
+    return f;
+}
+
+template<class T>
+FixedArray<int> operator == (const StringArrayT<T> &a0, const T &v1) {
+    size_t len = a0.len();
+    FixedArray<int> f(len);
+    const StringTableT<T> &t0 = a0.stringTable();
+    if (t0.hasString(v1)) {
+        StringTableIndex v1i = t0.lookup(v1);
+        for (size_t i=0;i<len;++i) {
+            f[i] = a0[i]==v1i;
+        }
+    } else {
+        for (size_t i=0;i<len;++i) {
+            f[i] = 0;
+        }
+    }
+    return f;
+}
+
+template<class T>
+FixedArray<int> operator == (const T &v1,const StringArrayT<T> &a0) {
+    return a0 == v1;
+}
+
+template<class T>
+FixedArray<int> operator != (const StringArrayT<T> &a0, const StringArrayT<T> &a1) {
+    size_t len = a0.match_dimension(a1);
+    FixedArray<int> f(len);
+    const StringTableT<T> &t0 = a0.stringTable();
+    const StringTableT<T> &t1 = a1.stringTable();
+    for (size_t i=0;i<len;++i) {
+        f[i] = t0.lookup(a0[i])!=t1.lookup(a1[i]); 
+    }
+    return f;
+}
+
+template<class T>
+FixedArray<int> operator != (const StringArrayT<T> &a0, const T &v1) {
+    size_t len = a0.len();
+    FixedArray<int> f(len);
+    const StringTableT<T> &t0 = a0.stringTable();
+    if (t0.hasString(v1)) {
+        StringTableIndex v1i = t0.lookup(v1);
+        for (size_t i=0;i<len;++i) {
+            f[i] = a0[i]!=v1i;
+        }
+    } else {
+        for (size_t i=0;i<len;++i) {
+            f[i] = 1;
+        }
+    }
+    return f;
+}
+
+template<class T>
+FixedArray<int> operator != (const T &v1,const StringArrayT<T> &a0) {
+    return a0 != v1;
+}
+
+template<> PYIMATH_EXPORT StringTableIndex FixedArrayDefaultValue<StringTableIndex>::value() { return StringTableIndex(0); }
+template<> PYIMATH_EXPORT const char*      FixedArray<StringTableIndex>::name() { return "StringTableArray"; }
+
+template class PYIMATH_EXPORT StringArrayT<std::string>;
+template class PYIMATH_EXPORT StringArrayT<std::wstring>;
+
+template FixedArray<int> operator == (const StringArray& a0, const StringArray& a1);
+template FixedArray<int> operator == (const StringArray& a0, const std::string& v1);
+template FixedArray<int> operator == (const std::string& a0, const StringArray& v1);
+template FixedArray<int> operator != (const StringArray& a0, const StringArray& a1);
+template FixedArray<int> operator != (const StringArray& a0, const std::string& v1);
+template FixedArray<int> operator != (const std::string& a0, const StringArray& v1);
+
+template FixedArray<int> operator == (const WstringArray& a0, const WstringArray& a1);
+template FixedArray<int> operator == (const WstringArray& a0, const std::wstring& v1);
+template FixedArray<int> operator == (const std::wstring& a0, const WstringArray& v1);
+template FixedArray<int> operator != (const WstringArray& a0, const WstringArray& a1);
+template FixedArray<int> operator != (const WstringArray& a0, const std::wstring& v1);
+template FixedArray<int> operator != (const std::wstring& a0, const WstringArray& v1);
+
+void register_StringArrays()
+{
+    typedef StringArrayT<std::string> StringArray;
+    typedef StringArrayT<std::wstring> WstringArray;
+    
+    class_<StringArray> string_array_class =
+        class_<StringArray>("StringArray",no_init);
+    string_array_class
+        .def("__init__", make_constructor(StringArray::createDefaultArray))
+        .def("__init__", make_constructor(StringArray::createUniformArray))
+        .def("__getitem__", &StringArray::getslice_string, return_value_policy<manage_new_object>()) 
+        .def("__getitem__", &StringArray::getitem_string)
+        .def("__getitem__", &StringArray::getslice_mask_string, return_value_policy<manage_new_object>())
+        .def("__setitem__", &StringArray::setitem_string_scalar)
+        .def("__setitem__", &StringArray::setitem_string_scalar_mask)
+        .def("__setitem__", &StringArray::setitem_string_vector)
+        .def("__setitem__", &StringArray::setitem_string_vector_mask)
+        .def("__len__",     &StringArray::len)
+        .def("writable",    &StringArray::writable)
+        .def("makeReadOnly",&StringArray::makeReadOnly)
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self == other<std::string>())
+        .def(other<std::string>() == self)
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != other<std::string>())
+        .def(other<std::string>() != self)
+        ;
+
+    class_<WstringArray> wstring_array_class =
+        class_<WstringArray>("WstringArray",no_init);
+    wstring_array_class
+        .def("__init__", make_constructor(WstringArray::createDefaultArray))
+        .def("__init__", make_constructor(WstringArray::createUniformArray))
+        .def("__getitem__", &WstringArray::getslice_string, return_value_policy<manage_new_object>()) 
+        .def("__getitem__", &WstringArray::getitem_string)
+        .def("__getitem__", &WstringArray::getslice_mask_string, return_value_policy<manage_new_object>())
+        .def("__setitem__", &WstringArray::setitem_string_scalar)
+        .def("__setitem__", &WstringArray::setitem_string_scalar_mask)
+        .def("__setitem__", &WstringArray::setitem_string_vector)
+        .def("__setitem__", &WstringArray::setitem_string_vector_mask)
+        .def("__len__",&WstringArray::len)
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self == other<std::wstring>())
+        .def(other<std::wstring>() == self)
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != other<std::wstring>())
+        .def(other<std::wstring>() != self)
+        ;
+}
+
+} // namespace PyImath
diff --git a/src/python/PyImath/PyImathStringArray.h b/src/python/PyImath/PyImathStringArray.h
new file mode 100644 (file)
index 0000000..f4d882d
--- /dev/null
@@ -0,0 +1,90 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathStringArray_h_
+#define _PyImathStringArray_h_
+
+#include "PyImathFixedArray.h"
+#include "PyImathStringTable.h"
+
+//
+// A fixed lengy array class for string and wide string type in python.
+// The implementation of StringArray is does not follow other FixeArray
+// types. StringArray de-duplicate repeated strings using StringTable
+// internally for compact memory usage.
+//
+namespace PyImath {
+
+template <class T>
+class StringArrayT : public FixedArray<StringTableIndex>
+{
+  public:
+    typedef T   BaseType;
+    typedef FixedArray<StringTableIndex> super;
+
+    static StringArrayT<T>* createDefaultArray(size_t length);
+    static StringArrayT<T>* createUniformArray(const T& initialValue, size_t length);
+    static StringArrayT<T>* createFromRawArray(const T* rawArray, size_t length,
+                                               bool writable = true);
+
+    StringArrayT(StringTableT<T> &table, StringTableIndex *ptr, size_t length,
+                 size_t stride = 1, boost::any tableHandle = boost::any(),
+                 bool writable = true);
+
+    StringArrayT(StringTableT<T> &table, StringTableIndex *ptr, size_t length,
+                 size_t stride, boost::any handle, boost::any tableHandle = boost::any(),
+                 bool writable = true);
+
+    StringArrayT(const StringTableT<T> &table, const StringTableIndex *ptr, size_t length,
+                 size_t stride = 1, boost::any tableHandle = boost::any());
+
+    StringArrayT(const StringTableT<T> &table, const StringTableIndex *ptr, size_t length,
+                 size_t stride, boost::any handle, boost::any tableHandle = boost::any());
+
+    StringArrayT(StringArrayT& s, const FixedArray<int>& mask);
+
+    const StringTableT<T> & stringTable() const { return _table; }
+
+    T  getitem_string(Py_ssize_t index) const {return _table.lookup(getitem(index)); }
+    StringArrayT* getslice_string(PyObject *index) const;
+    StringArrayT* getslice_mask_string(const FixedArray<int>& mask);
+
+    void setitem_string_scalar(PyObject *index, const T &data);
+
+    void setitem_string_scalar_mask(const FixedArray<int> &mask, const T &data);
+    void setitem_string_vector(PyObject *index, const StringArrayT<T> &data);
+    void setitem_string_vector_mask(const FixedArray<int> &mask, const StringArrayT<T> &data);
+
+  private:
+    typedef StringArrayT<T>     this_type;
+
+    StringTableT<T>             &_table;
+    // StringArray can borrow a string table from somewhere else or maintain 
+    // its own string table. This handle optionally stores a shared pointer to 
+    // a allocated StringTable class instance
+    boost::any                  _tableHandle;
+};
+
+template<class T>
+FixedArray<int> operator == (const StringArrayT<T> &a0, const StringArrayT<T> &a1); 
+template<class T>
+FixedArray<int> operator == (const StringArrayT<T> &a0, const T &v1);
+template<class T>
+FixedArray<int> operator == (const T &v1,const StringArrayT<T> &a0);
+template<class T>
+FixedArray<int> operator != (const StringArrayT<T> &a0, const StringArrayT<T> &a1);
+template<class T>
+FixedArray<int> operator != (const StringArrayT<T> &a0, const T &v1);
+template<class T>
+FixedArray<int> operator != (const T &v1,const StringArrayT<T> &a0);
+
+typedef StringArrayT<std::string> StringArray;
+typedef StringArrayT<std::wstring> WstringArray;
+
+} // namespace PyImath
+
+#endif
diff --git a/src/python/PyImath/PyImathStringArrayRegister.h b/src/python/PyImath/PyImathStringArrayRegister.h
new file mode 100644 (file)
index 0000000..0181525
--- /dev/null
@@ -0,0 +1,19 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathStringArrayRegister_h_
+#define _PyImathStringArrayRegister_h_
+
+#include "PyImathExport.h"
+
+namespace PyImath {
+
+PYIMATH_EXPORT void register_StringArrays();
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathStringTable.cpp b/src/python/PyImath/PyImathStringTable.cpp
new file mode 100644 (file)
index 0000000..af385bc
--- /dev/null
@@ -0,0 +1,99 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <limits>
+#include <stdexcept>
+#include "PyImathExport.h"
+#include "PyImathStringTable.h"
+
+namespace PyImath {
+
+template<class T>
+StringTableIndex
+StringTableT<T>::lookup(const T &s) const
+{
+    typedef typename Table::template nth_index<1>::type StringSet;
+    const StringSet &strings = _table.template get<1>();
+
+    typename StringSet::const_iterator it = strings.find(s);
+    if (it == strings.end()) {
+      throw std::domain_error ("String table access out of bounds");
+    }
+
+    return it->i;
+}
+
+template<class T>
+const T &
+StringTableT<T>::lookup(StringTableIndex index) const
+{
+    typedef typename Table::template nth_index<0>::type IndexSet;
+    const IndexSet &indices = _table.template get<0>();
+
+    typename IndexSet::const_iterator it = indices.find(index);
+    if (it == indices.end()) {
+      throw std::domain_error ("String table access out of bounds");
+    }
+
+    return it->s;
+}
+
+template<class T>
+StringTableIndex
+StringTableT<T>::intern(const T &s)
+{
+    typedef typename Table::template nth_index<1>::type StringSet;
+    const StringSet &strings = _table.template get<1>();
+
+    typename StringSet::const_iterator it = strings.find(s);
+    if (it == strings.end()) {
+        size_t next_index = _table.size();
+        if (next_index > std::numeric_limits<StringTableIndex::index_type>::max()) {
+          throw std::domain_error ("Unable to intern string - string table would exceed maximum size");
+        }
+        StringTableIndex index = StringTableIndex(StringTableIndex::index_type(next_index));
+        _table.insert(StringTableEntry<T>(index,s));
+        return index;
+    }
+
+    return it->i;
+}
+
+template<class T>
+size_t
+StringTableT<T>::size() const
+{
+    return _table.size();
+}
+
+template<class T>
+bool
+StringTableT<T>::hasString(const T &s) const
+{
+    typedef typename Table::template nth_index<1>::type StringSet;
+    const StringSet &strings = _table.template get<1>();
+    return strings.find(s) != strings.end();
+}
+
+template<class T>
+bool
+StringTableT<T>::hasStringIndex(const StringTableIndex &s) const
+{
+    typedef typename Table::template nth_index<0>::type IndexSet;
+    const IndexSet &indices = _table.template get<0>();
+    return indices.find(s) != indices.end();
+}
+
+namespace {
+template class PYIMATH_EXPORT StringTableDetailT<std::string>;
+template class PYIMATH_EXPORT StringTableDetailT<std::wstring>;
+}
+
+template class PYIMATH_EXPORT StringTableT<std::string>;
+template class PYIMATH_EXPORT StringTableT<std::wstring>;
+
+} // namespace PyImath
diff --git a/src/python/PyImath/PyImathStringTable.h b/src/python/PyImath/PyImathStringTable.h
new file mode 100644 (file)
index 0000000..687cb3d
--- /dev/null
@@ -0,0 +1,147 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathStringTable_h_
+#define _PyImathStringTable_h_
+
+#include <string>
+#include <stdint.h>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/identity.hpp>
+#include <boost/multi_index/member.hpp>
+
+namespace PyImath {
+
+// define a separate index type so as not to have
+// any confusion between ints and indices
+struct StringTableIndex
+{
+  public:
+    typedef uint32_t index_type;
+
+    // the default constructor was a private member before to prevent
+    // the empty instantiation. But, it became public now to resolve 
+    // a linking error on windows platform. PyImathStringArray is
+    // exposed with PYIMATH_EXPORT, This causes to expose all the members
+    // of PyImathFixedArray<StringTableIndex> also.
+    
+    StringTableIndex() : _index(0) {}
+    StringTableIndex (const StringTableIndex &si) : _index (si._index) {}
+    explicit StringTableIndex (index_type i) : _index (i) {}
+    ~StringTableIndex() = default;
+    
+    const StringTableIndex & operator = (const StringTableIndex &si)
+    { 
+        if (&si != this)
+            _index = si._index;
+        
+        return *this;
+    }
+
+    bool operator == (const StringTableIndex &si) const
+    { 
+        return _index == si._index;
+    }
+
+    bool operator != (const StringTableIndex &si) const
+    {
+        return _index != si._index;
+    }
+
+    // operator less for sorting
+    bool operator < (const StringTableIndex &si) const
+    {
+        return _index < si._index;
+    }
+
+    index_type index() const { return _index; }
+
+  private:
+    index_type _index;
+};
+
+} // namespace PyImath
+
+// Add a type trait for string indices to allow use in an AlignedArray
+namespace boost {
+    template <> struct is_pod< ::PyImath::StringTableIndex>
+    {
+        BOOST_STATIC_CONSTANT(bool,value=true); 
+    };
+} // namespace boost
+
+namespace PyImath {
+
+//
+// A string table entry containing a unique index and string
+template<class T>
+struct StringTableEntry
+{
+    StringTableEntry(StringTableIndex ii,const T &ss) : i(ii), s(ss) {}
+    StringTableIndex i;
+    T                s;
+};
+
+namespace {
+
+using boost::multi_index_container;
+using namespace boost::multi_index;
+
+//
+// A map data structure for string strings.
+// It exposes two index types : StringTableIndex and string
+//
+template<class T>
+class StringTableDetailT {
+    public:
+    typedef boost::multi_index_container<
+        StringTableEntry<T>,
+        indexed_by<
+            ordered_unique<member<StringTableEntry<T>,StringTableIndex,&StringTableEntry<T>::i> >,
+            ordered_unique<member<StringTableEntry<T>,T,&StringTableEntry<T>::s> >
+        > 
+    > StringTableContainer;
+};
+
+} // namespace
+
+typedef StringTableDetailT<std::string> StringTableDetail;
+typedef StringTableDetailT<std::wstring> WStringTableDetail;
+
+//
+// Storage class for storing unique string elements.
+//
+//
+template<class T>
+class StringTableT
+{
+  public:
+
+    // look up a string table entry either by value or index
+    StringTableIndex    lookup(const T &s) const;
+    const T &           lookup(StringTableIndex index) const;
+
+    // return the index to a string table entry, adding if not found
+    StringTableIndex    intern(const T &i);
+
+    size_t              size() const;
+    bool                hasString(const T &s) const;
+    bool                hasStringIndex(const StringTableIndex &s) const;
+    
+  private:
+
+    typedef typename StringTableDetailT<T>::StringTableContainer Table;
+    Table _table;
+};
+
+typedef StringTableT<std::string> StringTable;
+typedef StringTableT<std::wstring> WStringTable;
+
+} // namespace PyImath
+
+#endif
diff --git a/src/python/PyImath/PyImathTask.cpp b/src/python/PyImath/PyImathTask.cpp
new file mode 100644 (file)
index 0000000..bf3ad7a
--- /dev/null
@@ -0,0 +1,58 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathTask.h"
+
+namespace PyImath {
+
+static WorkerPool *_currentPool = nullptr;
+
+// Its not worth dispatching parallel tasks unless the iteration count
+// is high enough.  The time to create and launch parallel tasks takes
+// longer than to just do the iterations directly.  This value of '200'
+// is actually very conservative; in some tests, this number should
+// probably be in the thousands.
+static const size_t _minIterations = 200;
+
+WorkerPool *
+WorkerPool::currentPool()
+{
+    return _currentPool;
+}
+
+void
+WorkerPool::setCurrentPool(WorkerPool *pool)
+{
+    _currentPool = pool;
+}
+
+void
+dispatchTask(Task &task,size_t length)
+{
+    if (length > _minIterations)
+    {
+        WorkerPool *curpool = WorkerPool::currentPool();
+        if (curpool && !curpool->inWorkerThread())
+        {
+            curpool->dispatch(task,length);
+            return;
+        }
+    }
+    task.execute(0,length,0);
+}
+
+
+size_t
+workers()
+{
+    WorkerPool *curpool = WorkerPool::currentPool();
+    if (curpool && !curpool->inWorkerThread())
+        return curpool->workers();
+    return 1;
+}
+
+}
diff --git a/src/python/PyImath/PyImathTask.h b/src/python/PyImath/PyImathTask.h
new file mode 100644 (file)
index 0000000..6a6f03c
--- /dev/null
@@ -0,0 +1,39 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathTask_h_
+#define _PyImathTask_h_
+
+#include <cstddef>
+#include "PyImathExport.h"
+
+namespace PyImath {
+
+struct Task
+{
+    PYIMATH_EXPORT virtual ~Task() {}
+    PYIMATH_EXPORT virtual void execute(size_t start,size_t end) = 0;
+    PYIMATH_EXPORT virtual void execute(size_t start,size_t end, int tid) {execute(start,end);}
+};
+
+struct WorkerPool
+{
+    PYIMATH_EXPORT virtual ~WorkerPool() {}
+    PYIMATH_EXPORT virtual size_t workers() const = 0;
+    PYIMATH_EXPORT virtual void dispatch(Task &task,size_t length) = 0;
+    PYIMATH_EXPORT virtual bool inWorkerThread() const = 0;
+
+    PYIMATH_EXPORT static WorkerPool *currentPool();
+    PYIMATH_EXPORT static void setCurrentPool(WorkerPool *pool);
+};
+
+PYIMATH_EXPORT void dispatchTask(Task &task,size_t length);
+PYIMATH_EXPORT size_t workers();
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathUtil.cpp b/src/python/PyImath/PyImathUtil.cpp
new file mode 100644 (file)
index 0000000..0b8e67b
--- /dev/null
@@ -0,0 +1,70 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <pystate.h>
+#include "PyImathUtil.h"
+
+namespace PyImath {
+
+PyAcquireLock::PyAcquireLock()
+{
+    _gstate = PyGILState_Ensure();
+}
+
+PyAcquireLock::~PyAcquireLock()
+{
+    PyGILState_Release(_gstate);
+}
+
+#ifdef PLATFORM_LINUX
+// On Windows, this extern is not needed and produces a symbol mismatch at link time.
+// We should verify that it's still needed on Linux for Python 2.6.
+extern "C" PyThreadState *_PyThreadState_Current;
+#endif
+
+static bool
+pyHaveLock()
+{
+#if PY_MAJOR_VERSION > 2
+    return PyGILState_Check() != 0;
+#else
+    // This is very much dependent on the current Python
+    // implementation of this functionality.  If we switch versions of
+    // Python and the implementation changes, we'll have to change
+    // this code as well and introduce a #define for the Python
+    // version.
+    
+    if (!Py_IsInitialized())
+      throw std::invalid_argument ("PyReleaseLock called without the interpreter initialized");
+
+    PyThreadState *myThreadState = PyGILState_GetThisThreadState();
+
+    // If the interpreter is initialized the gil is held if the
+    // current thread's thread state is the current thread state
+    return myThreadState != 0 && myThreadState == _PyThreadState_Current;
+#endif
+}
+
+PyReleaseLock::PyReleaseLock()
+{
+    // only call PyEval_SaveThread if we have the interpreter lock held,
+    // otherwise PyReleaseLock is a no-op.
+    if (pyHaveLock())
+        _save = PyEval_SaveThread();
+    else
+        _save = 0;
+}
+
+PyReleaseLock::~PyReleaseLock()
+{
+    if (_save != 0)
+        PyEval_RestoreThread(_save);
+}
+
+} // namespace PyImath
diff --git a/src/python/PyImath/PyImathUtil.h b/src/python/PyImath/PyImathUtil.h
new file mode 100644 (file)
index 0000000..52a1fbd
--- /dev/null
@@ -0,0 +1,207 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef INCLUDED_PYIMATHUTIL_H
+#define INCLUDED_PYIMATHUTIL_H
+
+//----------------------------------------------------------------------------
+//
+//     PyImathUtil.h -- miscellaneous classes, functions
+//     and macros that are useful for Python wrapping
+//     of C++ objects.
+//
+//----------------------------------------------------------------------------
+
+#include <Python.h>
+#include "PyImathExport.h"
+#include <PyImathAPI.h>
+
+namespace PyImath {
+
+
+/**
+ * PyAcquireLock ensures that python is prepared for multi-threaded use and
+ * ensures that this thread has the global lock.
+ *
+ * This object must be instantiated (and continue to be in scope) during all
+ * threaded api calls.  It assumes the python interpretter is instantiated and
+ * multithreading is enabled.
+ * 
+ * Note: this is not compatible with additional interpreters (calls to
+ * Py_NewInterpreter()); 
+ */
+class PyAcquireLock
+{
+  public:
+    PYIMATH_EXPORT PyAcquireLock();
+    PYIMATH_EXPORT ~PyAcquireLock();
+
+    PYIMATH_EXPORT PyAcquireLock(const PyAcquireLock& other) = delete;
+    PYIMATH_EXPORT PyAcquireLock & operator = (PyAcquireLock& other) = delete;
+    PYIMATH_EXPORT PyAcquireLock(PyAcquireLock&& other) = delete;
+    PYIMATH_EXPORT PyAcquireLock & operator = (PyAcquireLock&& other) = delete;
+    
+  private:
+    PyGILState_STATE _gstate;
+};
+
+
+/**
+ * This object causes the python global lock to be released for the duration
+ * of it's existence.
+ *
+ * This object should be instantiated (and continue to be in scope) in thread-
+ * safe c++ functions called from python.  This call is designed to be
+ * instantiated while an AcquireLock is in effect (nested).
+ *
+ */
+class PyReleaseLock
+{
+  public:
+    PYIMATH_EXPORT PyReleaseLock();
+    PYIMATH_EXPORT ~PyReleaseLock();
+    PYIMATH_EXPORT PyReleaseLock(const PyReleaseLock& other) = delete;
+    PYIMATH_EXPORT PyReleaseLock & operator = (PyReleaseLock& other) = delete;
+    PYIMATH_EXPORT PyReleaseLock(PyReleaseLock&& other) = delete;
+    PYIMATH_EXPORT PyReleaseLock & operator = (PyReleaseLock&& other) = delete;
+
+  private:
+    PyThreadState *_save;
+
+};
+
+/**
+ * This object is safe object wrapper intended to use with boost python objects.
+ *
+ * This object correctly acquires the python lock for creation, copying and
+ * desctruction of the given object.
+ *
+ */
+template <class T>
+class PySafeObject
+{
+  public:
+    PySafeObject()
+        : _object(0)
+    {
+        PyAcquireLock pylock;
+        _object = new T();
+    }
+
+    PySafeObject(const T &value)
+        : _object(0)
+    {
+        PyAcquireLock pylock;
+        _object = new T(value);
+    }
+
+    ~PySafeObject()
+    {
+        PyAcquireLock pylock;
+        delete _object;
+        _object = 0;
+    }
+
+    PySafeObject(const PySafeObject &other)
+        : _object(0)
+    {
+        PyAcquireLock pylock;
+        _object = new T(*other._object);
+    }
+
+    const PySafeObject &
+    operator = (const PySafeObject &other)
+    {
+        if (&other == this) return *this;
+        PyAcquireLock pylock;
+        *_object = *other._object;
+        return *this;
+    }
+
+    bool
+    operator == (const PySafeObject &other) const
+    {
+        if (&other == this) return true;
+        PyAcquireLock pylock;
+        return *_object == *other._object;
+    }
+
+    bool
+    operator != (const PySafeObject &other) const
+    {
+        if (&other == this) return false;
+        PyAcquireLock pylock;
+        return *_object != *other._object;
+    }
+
+    T & get() { return *_object; }
+    const T & get() const { return *_object; }
+
+  private:
+
+    T *_object;
+};
+
+/**
+ * A special selectable postcall policy used in python wrappings.
+ *
+ * It expects the initial result to be a touple where the first
+ * object represents an integer value 0, 1, 2 which corresponds
+ * to which of the templated call polices should be applied.
+ *
+ * This postcall policy is modeled after a similar one defined 
+ * in PyGeomParticleUtil.h of the PyGeomParticle project.
+ *
+ */
+template <class policy0, class policy1, class policy2>
+struct selectable_postcall_policy_from_tuple : policy0
+{
+    static PyObject *
+    postcall (PyObject* args, PyObject* result)
+    {
+        if (!PyTuple_Check (result))
+        {
+            PyErr_SetString (PyExc_TypeError,
+                             "selectable_postcall: retval was not a tuple");
+            return 0;
+        }
+        if (PyTuple_Size(result) != 2)
+        {
+            PyErr_SetString (PyExc_IndexError,
+                             "selectable_postcall: retval was not a tuple of length 2");
+            return 0;
+        }
+
+        // borrowed references within the tuple
+        PyObject* object0 = PyTuple_GetItem (result, 0);  // 'Choice' integer
+        PyObject* object1 = PyTuple_GetItem (result, 1);  // The actual object
+
+        if (!PyInt_Check (object0))
+        {
+            PyErr_SetString (PyExc_TypeError,
+                             "selectable_postcall: tuple item 0 was not an integer choice");
+            return 0;
+        }
+
+        const long usePolicy = PyInt_AsLong (object0);
+
+        // ensure correct reference count for returned object and decref the tuple
+        Py_INCREF (object1);
+        Py_DECREF (result );
+
+        if (usePolicy <= 0)
+            return policy0::postcall (args, object1);
+        else if (usePolicy == 1)
+            return policy1::postcall (args, object1);
+        else  // usePolicy >= 2
+            return policy2::postcall (args, object1);
+    }
+};
+
+} // namespace PyImath
+
+#endif
diff --git a/src/python/PyImath/PyImathVec.h b/src/python/PyImath/PyImathVec.h
new file mode 100644 (file)
index 0000000..1d275a2
--- /dev/null
@@ -0,0 +1,465 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathVec_h_
+#define _PyImathVec_h_
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <ImathVec.h>
+#include "PyImath.h"
+#include "PyImathFixedArray.h"
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Vec2<T> > register_Vec2();
+template <class T> boost::python::class_<FixedArray<IMATH_NAMESPACE::Vec2<T> > > register_Vec2Array();
+typedef FixedArray<IMATH_NAMESPACE::V2s>   V2sArray;
+typedef FixedArray<IMATH_NAMESPACE::V2i>   V2iArray;
+typedef FixedArray<IMATH_NAMESPACE::V2i64> V2i64Array;
+typedef FixedArray<IMATH_NAMESPACE::V2f>   V2fArray;
+typedef FixedArray<IMATH_NAMESPACE::V2d>   V2dArray;
+
+// TODO: template <class T> class Vec2Array : public FixedArray<IMATH_NAMESPACE::Vec2<T> >
+
+}
+
+// define vector*float array multiplication
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a0, T v1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*v1; return f;
+}
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator * (T v0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a1) { return a1*v0; }
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a0, const PyImath::FixedArray<T> &a1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*a1[i]; return f;
+}
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator * (const PyImath::FixedArray<T> &a0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a1) {
+    return a1*a0;
+}
+
+// define vector/float array division
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a0, T v1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/v1; return f;
+}
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a0, const PyImath::FixedArray<T> &a1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/a1[i]; return f;
+}
+
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Vec3<T> > register_Vec3();
+template <class T> boost::python::class_<FixedArray<IMATH_NAMESPACE::Vec3<T> > > register_Vec3Array();
+typedef FixedArray<IMATH_NAMESPACE::Vec3<unsigned char> >  V3cArray;
+typedef FixedArray<IMATH_NAMESPACE::V3s>   V3sArray;
+typedef FixedArray<IMATH_NAMESPACE::V3i>   V3iArray;
+typedef FixedArray<IMATH_NAMESPACE::V3i64> V3i64Array;
+typedef FixedArray<IMATH_NAMESPACE::V3f>   V3fArray;
+typedef FixedArray<IMATH_NAMESPACE::V3d>   V3dArray;
+
+// TODO: template <class T> class Vec3Array : public FixedArray<IMATH_NAMESPACE::Vec3<T> >
+}
+
+// define vector*float array multiplication
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a0, T v1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*v1; return f;
+}
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (T v0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a1) { return a1*v0; }
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a0, const PyImath::FixedArray<T> &a1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*a1[i]; return f;
+}
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (const PyImath::FixedArray<T> &a0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a1) {
+    return a1*a0;
+}
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &va, const IMATH_NAMESPACE::M44f &m) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = va.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i = 0; i < len; ++i) f[i] = va[i] * m; return f;
+}
+
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &va, const IMATH_NAMESPACE::M44d &m) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = va.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i = 0; i < len; ++i) f[i] = va[i] * m; return f;
+}
+
+// define vector/float array division
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a0, T v1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/v1; return f;
+}
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a0, const PyImath::FixedArray<T> &a1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/a1[i]; return f;
+}
+
+namespace PyImath {
+
+template <class T> boost::python::class_<IMATH_NAMESPACE::Vec4<T> > register_Vec4();
+template <class T> boost::python::class_<PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > > register_Vec4Array();
+typedef FixedArray<IMATH_NAMESPACE::Vec4<unsigned char> >  V4cArray;
+typedef FixedArray<IMATH_NAMESPACE::V4s>   V4sArray;
+typedef FixedArray<IMATH_NAMESPACE::V4i>   V4iArray;
+typedef FixedArray<IMATH_NAMESPACE::V4i64> V4i64Array;
+typedef FixedArray<IMATH_NAMESPACE::V4f>   V4fArray;
+typedef FixedArray<IMATH_NAMESPACE::V4d>   V4dArray;
+
+// TODO: template <class T> class Vec3Array : public FixedArray<IMATH_NAMESPACE::Vec3<T> >
+}
+
+// define vector*float array multiplication
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a0, T v1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*v1; return f;
+}
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (T v0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a1) { return a1*v0; }
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a0, const PyImath::FixedArray<T> &a1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*a1[i]; return f;
+}
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (const PyImath::FixedArray<T> &a0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a1) {
+    return a1*a0;
+}
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &va, const IMATH_NAMESPACE::M44f &m) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = va.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i = 0; i < len; ++i) f[i] = va[i] * m; return f;
+}
+
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &va, const IMATH_NAMESPACE::M44d &m) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = va.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i = 0; i < len; ++i) f[i] = va[i] * m; return f;
+}
+
+// define vector/float array division
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a0, T v1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/v1; return f;
+}
+template <class T>
+static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a0, const PyImath::FixedArray<T> &a1) {
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/a1[i]; return f;
+}
+
+
+//
+
+namespace PyImath {
+
+// Other code in the Zeno code base assumes the existance of a class with the
+// same name as the Imath class, and with static functions wrap() and
+// convert() to produce a PyImath object from an Imath object and vice-versa,
+// respectively.  The class Boost generates from the Imath class does not
+// have these properties, so we define a companion class here.
+// The template argument, T, is the element type for the vector (e.g., int,
+// float, double).
+
+template <class T>
+class V2 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Vec2<T> &v);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Vec2<T> *v);
+};
+
+template <class T>
+class V3 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Vec3<T> &v);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Vec3<T> *v);
+};
+
+template <class T>
+class V4 {
+  public:
+    static PyObject *  wrap (const IMATH_NAMESPACE::Vec4<T> &v);
+    static int         convert (PyObject *p, IMATH_NAMESPACE::Vec4<T> *v);
+};
+
+template <class T>
+PyObject *
+V2<T>::wrap (const IMATH_NAMESPACE::Vec2<T> &v)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Vec2<T> >::type converter;
+    PyObject *p = converter (v);
+    return p;
+}
+
+template <class T>
+PyObject *
+V3<T>::wrap (const IMATH_NAMESPACE::Vec3<T> &v)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Vec3<T> >::type converter;
+    PyObject *p = converter (v);
+    return p;
+}
+
+template <class T>
+PyObject *
+V4<T>::wrap (const IMATH_NAMESPACE::Vec4<T> &v)
+{
+    typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Vec4<T> >::type converter;
+    PyObject *p = converter (v);
+    return p;
+}
+
+template <class T>
+int
+V2<T>::convert (PyObject *p, IMATH_NAMESPACE::Vec2<T> *v)
+{
+    boost::python::extract <IMATH_NAMESPACE::V2i> extractorV2i (p);
+    if (extractorV2i.check())
+    {
+        IMATH_NAMESPACE::V2i v2i = extractorV2i();
+        v->setValue (T(v2i[0]), T(v2i[1]));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V2i64> extractorV2i64 (p);
+    if (extractorV2i64.check())
+    {
+        IMATH_NAMESPACE::V2i64 v2i64 = extractorV2i64();
+        v->setValue (T(v2i64[0]), T(v2i64[1]));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V2f> extractorV2f (p);
+    if (extractorV2f.check())
+    {
+        IMATH_NAMESPACE::V2f v2f = extractorV2f();
+        v->setValue (T(v2f[0]), T(v2f[1]));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V2d> extractorV2d (p);
+    if (extractorV2d.check())
+    {
+        IMATH_NAMESPACE::V2d v2d = extractorV2d();
+        v->setValue (T(v2d[0]), T(v2d[1]));
+        return 1;
+    }
+
+    boost::python::extract <boost::python::tuple> extractorTuple (p);
+    if (extractorTuple.check())
+    {
+        boost::python::tuple t = extractorTuple();
+        if (t.attr ("__len__") () == 2)
+        {
+            // Extracting the tuple elements as doubles and casting them to
+            // Ts in setValue() works better than extracting them as Ts from
+            // the start.  Extracting them as Ts can fail in certain
+            // circumstances if T is int and the tuples elemnts are floats.
+            // In particular, this kind of failure occurs in PyImathBox.h,
+            // when Box2<int>::convert() is passed a tuple of two tuples of
+            // floats. 
+
+            double a = boost::python::extract <double> (t[0]);
+            double b = boost::python::extract <double> (t[1]);
+            v->setValue (T(a), T(b));
+            return 1;
+        }
+    }
+
+    boost::python::extract <boost::python::list> extractorList (p);
+    if (extractorList.check())
+    {
+        boost::python::list l = extractorList();
+        if (l.attr ("__len__") () == 2)
+        {
+            boost::python::extract <double> extractor0 (l[0]);
+            boost::python::extract <double> extractor1 (l[1]);
+            if (extractor0.check() && extractor1.check())
+            {
+                v->setValue (T(extractor0()), T(extractor1()));
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+template <class T>
+int
+V3<T>::convert (PyObject *p, IMATH_NAMESPACE::Vec3<T> *v)
+{
+    boost::python::extract <IMATH_NAMESPACE::V3i> extractorV3i (p);
+    if (extractorV3i.check())
+    {
+        IMATH_NAMESPACE::V3i v3i = extractorV3i();
+        v->setValue (T(v3i[0]), T(v3i[1]), T(v3i[2]));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V3i64> extractorV3i64 (p);
+    if (extractorV3i64.check())
+    {
+        IMATH_NAMESPACE::V3i64 v3i64 = extractorV3i64();
+        v->setValue (T(v3i64[0]), T(v3i64[1]), T(v3i64[2]));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V3f> extractorV3f (p);
+    if (extractorV3f.check())
+    {
+        IMATH_NAMESPACE::V3f v3f = extractorV3f();
+        v->setValue (T(v3f[0]), T(v3f[1]), T(v3f[2]));
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V3d> extractorV3d (p);
+    if (extractorV3d.check())
+    {
+        IMATH_NAMESPACE::V3d v3d = extractorV3d();
+        v->setValue (T(v3d[0]), T(v3d[1]), T(v3d[2]));
+        return 1;
+    }
+
+    boost::python::extract <boost::python::tuple> extractorTuple (p);
+    if (extractorTuple.check())
+    {
+        boost::python::tuple t = extractorTuple();
+        if (t.attr ("__len__") () == 3)
+        {
+            // See the comment in V2<T>::convert().
+
+            double a = boost::python::extract <double> (t[0]);
+            double b = boost::python::extract <double> (t[1]);
+            double c = boost::python::extract <double> (t[2]);
+            v->setValue (T(a), T(b), T(c));
+            return 1;
+        }
+    }
+
+    boost::python::extract <boost::python::list> extractorList (p);
+    if (extractorList.check())
+    {
+        boost::python::list l = extractorList();
+        if (l.attr ("__len__") () == 3)
+        {
+            boost::python::extract <double> extractor0 (l[0]);
+            boost::python::extract <double> extractor1 (l[1]);
+            boost::python::extract <double> extractor2 (l[2]);
+            if (extractor0.check() && extractor1.check() &&
+                extractor2.check())
+            {
+                v->setValue (T(extractor0()), T(extractor1()),
+                             T(extractor2()));
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+template <class T>
+int
+V4<T>::convert (PyObject *p, IMATH_NAMESPACE::Vec4<T> *v)
+{
+    boost::python::extract <IMATH_NAMESPACE::V4i> extractorV4i (p);
+    if (extractorV4i.check())
+    {
+        IMATH_NAMESPACE::V4i v4i = extractorV4i();
+        *v = IMATH_NAMESPACE::Vec4<T>(v4i);
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V4f> extractorV4f (p);
+    if (extractorV4f.check())
+    {
+        IMATH_NAMESPACE::V4f v4f = extractorV4f();
+        *v = IMATH_NAMESPACE::Vec4<T>(v4f);
+        return 1;
+    }
+
+    boost::python::extract <IMATH_NAMESPACE::V4d> extractorV4d (p);
+    if (extractorV4d.check())
+    {
+        IMATH_NAMESPACE::V4d v4d = extractorV4d();
+        *v = IMATH_NAMESPACE::Vec4<T>(v4d);
+        return 1;
+    }
+
+    boost::python::extract <boost::python::tuple> extractorTuple (p);
+    if (extractorTuple.check())
+    {
+        boost::python::tuple t = extractorTuple();
+        if (t.attr ("__len__") () == 4)
+        {
+            // See the comment in V2<T>::convert().
+
+            double a = boost::python::extract <double> (t[0]);
+            double b = boost::python::extract <double> (t[1]);
+            double c = boost::python::extract <double> (t[2]);
+            double d = boost::python::extract <double> (t[3]);
+            *v = IMATH_NAMESPACE::Vec4<T>(T(a), T(b), T(c), T(d));
+            return 1;
+        }
+    }
+
+    boost::python::extract <boost::python::list> extractorList (p);
+    if (extractorList.check())
+    {
+        boost::python::list l = extractorList();
+        if (l.attr ("__len__") () == 4)
+        {
+            boost::python::extract <double> extractor0 (l[0]);
+            boost::python::extract <double> extractor1 (l[1]);
+            boost::python::extract <double> extractor2 (l[2]);
+            boost::python::extract <double> extractor3 (l[3]);
+            if (extractor0.check() && extractor1.check() &&
+                extractor2.check() && extractor3.check())
+            {
+                *v = IMATH_NAMESPACE::Vec4<T>(T(extractor0()), T(extractor1()),
+                             T(extractor2()), T(extractor3()));
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+typedef V2<int>                V2i;
+typedef V2<float>      V2f;
+typedef V2<double>     V2d;
+typedef V3<int>                V3i;
+typedef V3<float>      V3f;
+typedef V3<double>     V3d;
+typedef V4<int>                V4i;
+typedef V4<float>      V4f;
+typedef V4<double>     V4d;
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathVec2Impl.h b/src/python/PyImath/PyImathVec2Impl.h
new file mode 100644 (file)
index 0000000..36effb2
--- /dev/null
@@ -0,0 +1,1207 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathVec2Impl_h_
+#define _PyImathVec2Impl_h_
+
+//
+// This .C file was turned into a header file so that instantiations
+// of the various V2* types can be spread across multiple files in
+// order to work around MSVC limitations.
+//
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <boost/cast.hpp>
+#include <ImathVec.h>
+#include <ImathVecAlgo.h>
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathBox.h"
+#include "PyImathVec.h"
+#include "PyImathDecorators.h"
+#include "PyImathOperators.h"
+#include "PyImathVecOperators.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct Vec2Name { static const char *value; };
+
+// create a new default constructor that initializes Vec2<T> to zero.
+template <class T>
+static Vec2<T> * Vec2_construct_default()
+{
+    return new Vec2<T>(T(0),T(0));
+}
+
+template <class T,class BoostPyType>
+static Vec2<T> * Vec2_tuple_constructor(const BoostPyType &t)
+{
+    if(t.attr("__len__")() == 1)
+        return new Vec2<T>(extract<T>(t[0]), extract<T>(t[0]));
+    else if(t.attr("__len__")() == 2)
+        return new Vec2<T>(extract<T>(t[0]), extract<T>(t[1]));
+    else
+      throw std::invalid_argument ("Vec2 constructor expects tuple of length 1 or 2");
+}
+
+template <class T>
+static Vec2<T> * Vec2_object_constructor1(const object &obj)
+{
+    Vec2<T> w;
+    extract<Vec2<int> >     e1(obj);
+    extract<Vec2<float> >   e2(obj);
+    extract<Vec2<double> >  e3(obj);
+    extract<tuple>          e4(obj);
+    extract<double>         e5(obj);
+    extract<list>           e6(obj);
+    
+    if(e1.check()){ w = e1(); }
+    else if(e2.check()) { w = e2(); }
+    else if(e3.check()) { w = e3(); }
+    else if(e4.check())
+    {
+        tuple t = e4();
+        if(t.attr("__len__")() == 2)
+        {
+            w.x = extract<T>(t[0]);
+            w.y = extract<T>(t[1]);
+        }
+        else
+            throw std::invalid_argument ("tuple must have length of 2");
+    }
+    else if(e5.check()) { T a = e5(); w.setValue(a, a); }
+    else if(e6.check())
+    {
+        list l = e6();
+        if(l.attr("__len__")() == 2)
+        {
+            w.x = extract<T>(l[0]);
+            w.y = extract<T>(l[1]);
+        }
+        else
+            throw std::invalid_argument ("list must have length of 2");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to Vec2 constructor");
+    
+    Vec2<T> *v = new Vec2<T>;
+    *v = w;
+    
+    return v;
+
+}
+
+template <class T>
+static Vec2<T> * Vec2_object_constructor2(const object &obj1, const object &obj2)
+{
+    extract<double> e1(obj1);
+    extract<double> e2(obj2);
+    
+    Vec2<T> *v = new Vec2<T>;
+    
+    if(e1.check()) { v->x = boost::numeric_cast<T>(e1());}
+    else { throw std::invalid_argument ("invalid parameters passed to Vec2 constructor"); }
+    
+    if(e2.check()) { v->y = boost::numeric_cast<T>(e2());}
+    else { throw std::invalid_argument ("invalid parameters passed to Vec2 constructor"); }    
+    
+    return v;
+}
+
+// Implementations of str and repr are same here,
+// but we'll specialize repr for float and double to make them exact.
+template <class T>
+static std::string Vec2_str(const Vec2<T> &v)
+{
+    std::stringstream stream;
+    stream << Vec2Name<T>::value << "(" << v.x << ", " << v.y << ")";
+    return stream.str();
+}
+template <class T>
+static std::string Vec2_repr(const Vec2<T> &v)
+{
+    std::stringstream stream;
+    stream << Vec2Name<T>::value << "(" << v.x << ", " << v.y << ")";
+    return stream.str();
+}
+
+template <class T>
+static T
+Vec2_cross(const IMATH_NAMESPACE::Vec2<T> &v, const IMATH_NAMESPACE::Vec2<T> &other) 
+{ 
+    MATH_EXC_ON;
+    return v.cross(other);
+}
+
+template <class T>
+static FixedArray<T>
+Vec2_cross_Vec2Array(const IMATH_NAMESPACE::Vec2<T> &va, const FixedArray<IMATH_NAMESPACE::Vec2<T> > &vb) 
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = vb.len(); 
+    FixedArray<T> f(len); 
+    for (size_t i = 0; i < len; ++i) 
+        f[i] = va.cross(vb[i]); 
+    return f; 
+}
+
+template <class T>
+static T
+Vec2_dot(const IMATH_NAMESPACE::Vec2<T> &v, const IMATH_NAMESPACE::Vec2<T> &other) 
+{ 
+    MATH_EXC_ON;
+    return v.dot(other);
+}
+
+template <class T>
+static FixedArray<T>
+Vec2_dot_Vec2Array(const IMATH_NAMESPACE::Vec2<T> &va, const FixedArray<IMATH_NAMESPACE::Vec2<T> > &vb) 
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = vb.len(); 
+    FixedArray<T> f(len); 
+    for (size_t i = 0; i < len; ++i) 
+        f[i] = va.dot(vb[i]); 
+    return f; 
+}
+
+template <class T>
+static T
+Vec2_length(const IMATH_NAMESPACE::Vec2<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.length();
+}
+
+template <class T>
+static T
+Vec2_length2(const IMATH_NAMESPACE::Vec2<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.length2();
+}
+
+template <class T>
+static const Vec2<T> &
+Vec2_normalize(IMATH_NAMESPACE::Vec2<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalize();
+}
+
+template <class T>
+static const Vec2<T> &
+Vec2_normalizeExc(IMATH_NAMESPACE::Vec2<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizeExc();
+}
+
+template <class T>
+static const Vec2<T> &
+Vec2_normalizeNonNull(IMATH_NAMESPACE::Vec2<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizeNonNull();
+}
+
+template <class T>
+static Vec2<T>
+Vec2_normalized(const IMATH_NAMESPACE::Vec2<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalized();
+}
+
+template <class T>
+static Vec2<T>
+Vec2_normalizedExc(const IMATH_NAMESPACE::Vec2<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizedExc();
+}
+
+template <class T>
+static Vec2<T>
+Vec2_normalizedNonNull(const IMATH_NAMESPACE::Vec2<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizedNonNull();
+}
+
+template <class T>
+static Vec2<T>
+closestVertex(Vec2<T> &p, const Vec2<T> &v0, const Vec2<T> &v1, const Vec2<T> &v2)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::closestVertex(v0, v1, v2, p);
+}
+
+template <class T>
+static const Vec2<T> &
+Vec2_negate(IMATH_NAMESPACE::Vec2<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.negate();
+}
+
+template <class T>
+static Vec2<T>
+orthogonal(const Vec2<T> &v, const Vec2<T> &v0)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::orthogonal(v, v0);
+}
+
+template <class T>
+static Vec2<T>
+project(const Vec2<T> &v, const Vec2<T> &v0)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::project(v0, v);
+}
+
+template <class T>
+static Vec2<T>
+reflect(const Vec2<T> &v, const Vec2<T> &v0)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::reflect(v, v0);
+}
+
+template <class T>
+static void
+setValue(Vec2<T> &v, T a, T b)
+{
+    v.x = a;
+    v.y = b;
+}
+
+template <class T>
+static Vec2<T>
+Vec2_add (const Vec2<T> &v, const Vec2<T> &w)
+{
+    MATH_EXC_ON;
+    return v + w;
+}
+
+template <class T>
+static Vec2<T>
+Vec2_sub (const Vec2<T> &v, const Vec2<T> &w)
+{
+    MATH_EXC_ON;
+    return v - w;
+}
+
+template <class T>
+static Vec2<T>
+Vec2_neg (const Vec2<T> &v)
+{
+    MATH_EXC_ON;
+    return -v;
+}
+
+template <class T, class U>
+static Vec2<T>
+Vec2_mul (const Vec2<T> &v, const Vec2<U> &w)
+{
+    MATH_EXC_ON;
+    Vec2<T> w2 (w);
+    return v * w2;
+}
+
+template <class T>
+static Vec2<T>
+Vec2_mulT (const Vec2<T> &v, T t)
+{
+    MATH_EXC_ON;
+    return v * t;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Vec2<T> >
+Vec2_mulTArray (const Vec2<T> &v, const FixedArray<T> &t)
+{
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = t.len();
+    FixedArray<IMATH_NAMESPACE::Vec2<T> > retval(len);
+    for (size_t i=0; i<len; ++i) retval[i] = v*t[i];
+    return retval;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Vec2<T> >
+Vec2_rmulTArray (const Vec2<T> &v, const FixedArray<T> &t)
+{
+    return Vec2_mulTArray(v,t);
+}
+
+template <class T,class S>
+static Vec2<T>
+Vec2_div (Vec2<T> &v, Vec2<S> &w)
+{
+    MATH_EXC_ON;
+    return v / w;
+}
+
+template <class T>
+static Vec2<T>
+Vec2_rmulT (Vec2<T> &v, T t)
+{
+    MATH_EXC_ON;
+    return t * v;
+}
+
+template <class T, class U>
+static const Vec2<T> &
+Vec2_imulV(Vec2<T> &v, const Vec2<U> &w)
+{
+    MATH_EXC_ON;
+    return v *= w;
+}
+
+template <class T>
+static const Vec2<T> &
+Vec2_imulT(IMATH_NAMESPACE::Vec2<T> &v, T t) 
+{ 
+    MATH_EXC_ON;
+    return v *= t;
+}
+
+template <class T, class U>
+static Vec2<T>
+Vec2_mulM22 (Vec2<T> &v, const Matrix22<U> &m)
+{
+    MATH_EXC_ON;
+    return v * m;
+}
+
+template <class T, class U>
+static Vec2<T>
+Vec2_mulM33 (Vec2<T> &v, const Matrix33<U> &m)
+{
+    MATH_EXC_ON;
+    return v * m;
+}
+
+template <class T>
+static const Vec2<T> &
+Vec2_idivObj(IMATH_NAMESPACE::Vec2<T> &v, const object &o) 
+{ 
+    MATH_EXC_ON;
+    Vec2<T> v2;
+    if (PyImath::V2<T>::convert (o.ptr(), &v2))
+    {
+        return v /= v2;
+    }
+    else
+    {
+        extract<double> e(o);
+        if (e.check())
+            return v /= e();
+        else
+            throw std::invalid_argument ("V2 division expects an argument"
+                   "convertible to a V2");
+    }
+}
+
+template <class T>
+static Vec2<T>
+Vec2_subT(const Vec2<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec2<T> w;
+    w.setValue(v.x - a, v.y - a);
+    return w;
+}
+
+template <class T,class BoostPyType>
+static Vec2<T>
+Vec2_subTuple(const Vec2<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec2<T> w;
+    
+    if(t.attr("__len__")() == 2)
+    {
+        w.x = v.x - extract<T>(t[0]);
+        w.y = v.y - extract<T>(t[1]);
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 2");
+    
+    return w;
+}
+
+template <class T>
+static Vec2<T>
+Vec2_rsubT(const Vec2<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec2<T> w;
+    w.setValue(a - v.x, a - v.y);
+    return w;
+}
+
+template <class T,class BoostPyType>
+static Vec2<T>
+Vec2_rsubTuple(const Vec2<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec2<T> w;
+    
+    if(t.attr("__len__")() == 2)
+    {
+        w.x = extract<T>(t[0]) - v.x;
+        w.y = extract<T>(t[1]) - v.y;
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 2");
+    
+    return w;
+}
+
+template <class T,class BoostPyType>
+static Vec2<T>
+Vec2_addTuple(const Vec2<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec2<T> w;
+    
+    if(t.attr("__len__")() == 2)
+    {
+        w.x = v.x + extract<T>(t[0]);
+        w.y = v.y + extract<T>(t[1]);
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 2");
+    
+    return w;
+}
+
+template <class T>
+static Vec2<T>
+Vec2_addT(const Vec2<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec2<T> w;
+    w.setValue(v.x + a, v.y + a);
+    return w;
+}
+
+template <class T, class U>
+static Vec2<T>
+Vec2_addV(const Vec2<T> &v, const Vec2<U> &w)
+{
+    MATH_EXC_ON;
+    return v + w;
+}
+
+template <class T, class U>
+static const Vec2<T> &
+Vec2_iaddV(Vec2<T> &v, const Vec2<U> &w)
+{
+    MATH_EXC_ON;
+    return v += w;
+}
+
+template <class T, class U>
+static Vec2<T>
+Vec2_subV(const Vec2<T> &v, const Vec2<U> &w)
+{
+    MATH_EXC_ON;
+    return v - w;
+}
+
+template <class T, class U>
+static const Vec2<T> &
+Vec2_isubV(Vec2<T> &v, const Vec2<U> &w)
+{
+    MATH_EXC_ON;
+    return v -= w;
+}
+
+template <class T,class BoostPyType>
+static Vec2<T>
+Vec2_mulTuple(const Vec2<T> &v, BoostPyType t)
+{
+    MATH_EXC_ON;
+    Vec2<T> w;
+    
+    if(t.attr("__len__")() == 1){
+        w.x = v.x*extract<T>(t[0]);
+        w.y = v.y*extract<T>(t[0]);
+    }        
+    else if(t.attr("__len__")() == 2){
+        w.x = v.x*extract<T>(t[0]);
+        w.y = v.y*extract<T>(t[1]);
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 1 or 2");
+    
+    return w;
+}
+
+template <class T, class U>
+static const Vec2<T> &
+Vec2_imulM22 (Vec2<T> &v, const Matrix22<U> &m)
+{
+    MATH_EXC_ON;
+    return v *= m;
+}
+
+template <class T, class U>
+static const Vec2<T> &
+Vec2_imulM33 (Vec2<T> &v, const Matrix33<U> &m)
+{
+    MATH_EXC_ON;
+    return v *= m;
+}
+
+template <class T,class BoostPyType>
+static Vec2<T>
+Vec2_divTuple(const Vec2<T> &v, const BoostPyType &t)
+{
+    if(t.attr("__len__")() == 2)
+    {
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        if(x != T(0) && y != T(0))
+            return Vec2<T>(v.x / x, v.y / y);
+        else
+          throw std::domain_error ("Division by zero");
+    }
+    else
+        throw std::invalid_argument ("Vec2 expects tuple of length 2");
+}
+
+template <class T,class BoostPyType>
+static Vec2<T>
+Vec2_rdivTuple(const Vec2<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec2<T> w;
+    if(t.attr("__len__")() == 2)
+    {
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+            
+        if(v.x != T(0) && v.y != T(0)){
+            w.setValue(x / v.x, y / v.y);
+        }
+        else
+            throw std::domain_error ("Division by zero");
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 2");
+    
+    return w;
+}
+
+template <class T>
+static Vec2<T>
+Vec2_divT(const Vec2<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec2<T> w;
+    if(a != T(0)){
+        w.setValue(v.x / a, v.y / a);
+    }
+    else
+        throw std::domain_error ("Division by zero");
+
+    return w;
+}
+
+template <class T>
+static Vec2<T>
+Vec2_rdivT(const Vec2<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec2<T> w;
+    if(v.x != T(0) && v.y != T(0)){
+        w.setValue(a / v.x, a / v.y);
+    }
+    else
+        throw std::domain_error ("Division by zero");
+
+    return w;
+}
+
+template <class T>
+static bool
+lessThan(const Vec2<T> &v, const object &obj)
+{
+    extract<Vec2<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec2<T> w;
+    if(e1.check())
+    {
+        w = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        if(t.attr("__len__")() == 2){
+            T x = extract<T>(t[0]);
+            T y = extract<T>(t[1]);
+            w.setValue(x,y);
+        }
+        else
+           throw std::invalid_argument ("Vec2 expects tuple of length 2");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator <");
+    
+    bool isLessThan = (v.x <= w.x && v.y <= w.y)
+                    && v != w;
+    
+    return isLessThan;
+}
+
+template <class T>
+static bool
+greaterThan(const Vec2<T> &v, const object &obj)
+{
+    extract<Vec2<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec2<T> w;
+    if(e1.check())
+    {
+        w = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        if(t.attr("__len__")() == 2){
+            T x = extract<T>(t[0]);
+            T y = extract<T>(t[1]);
+            w.setValue(x,y);
+        }
+        else
+           throw std::invalid_argument ("Vec2 expects tuple of length 2");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator >");
+    
+    bool isGreaterThan = (v.x >= w.x && v.y >= w.y)
+                       && v != w;
+
+    return isGreaterThan;
+}
+
+template <class T>
+static bool
+lessThanEqual(const Vec2<T> &v, const object &obj)
+{
+    extract<Vec2<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec2<T> w;
+    if(e1.check())
+    {
+        w = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        if(t.attr("__len__")() == 2){
+            T x = extract<T>(t[0]);
+            T y = extract<T>(t[1]);
+            w.setValue(x,y);
+        }
+        else
+           throw std::invalid_argument ("Vec2 expects tuple of length 2");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator <=");
+    
+    bool isLessThanEqual = (v.x <= w.x && v.y <= w.y);
+                   
+    return isLessThanEqual;
+}
+
+template <class T>
+static bool
+greaterThanEqual(const Vec2<T> &v, const object &obj)
+{
+    extract<Vec2<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec2<T> w;
+    if(e1.check())
+    {
+        w = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        if(t.attr("__len__")() == 2){
+            T x = extract<T>(t[0]);
+            T y = extract<T>(t[1]);
+            w.setValue(x,y);
+        }
+        else
+           throw std::invalid_argument ("Vec2 expects tuple of length 2"); 
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator >=");
+    
+    bool isGreaterThanEqual = (v.x >= w.x && v.y >= w.y);
+
+    return isGreaterThanEqual;
+}
+
+template <class T,class BoostPyType>
+static void
+setItemTuple(FixedArray<IMATH_NAMESPACE::Vec2<T> > &va, Py_ssize_t index, const BoostPyType &t)
+{
+    if(t.attr("__len__")() == 2)
+    {
+        Vec2<T> v;
+        v.x = extract<T>(t[0]);
+        v.y = extract<T>(t[1]);
+        va[va.canonical_index(index)] = v;
+    }
+    else
+        throw std::invalid_argument ("tuple of length 2 expected");
+}
+
+template <class T>
+static bool
+equalWithAbsErrorObj(const Vec2<T> &v, const object &obj1, const object &obj2)
+{    
+    extract<Vec2<int> >    e1(obj1);
+    extract<Vec2<float> >  e2(obj1);
+    extract<Vec2<double> > e3(obj1);
+    
+    extract<tuple>         e4(obj1);
+    extract<double>        e5(obj2);
+    
+    Vec2<T> w;
+    if(e1.check())      { w = e1(); }
+    else if(e2.check()) { w = e2(); }
+    else if(e3.check()) { w = e3(); }
+    else if(e4.check())
+    {    
+        tuple t = e4();
+        if(t.attr("__len__")() == 2)
+        {
+            w.x = extract<T>(t[0]);
+            w.y = extract<T>(t[1]);
+        }
+        else
+            throw std::invalid_argument ("tuple of length 2 expected");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithAbsError");
+    
+    if(e5.check())      { return v.equalWithAbsError(w, e5()); }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithAbsError");
+}
+
+template <class T>
+static bool
+equalWithRelErrorObj(const Vec2<T> &v, const object &obj1, const object &obj2)
+{    
+    extract<Vec2<int> >    e1(obj1);
+    extract<Vec2<float> >  e2(obj1);
+    extract<Vec2<double> > e3(obj1);
+    
+    extract<tuple>         e4(obj1);
+    extract<double>        e5(obj2);
+    
+    Vec2<T> w;
+    if(e1.check())      { w = e1(); }
+    else if(e2.check()) { w = e2(); }
+    else if(e3.check()) { w = e3(); }
+    else if(e4.check())
+    {    
+        tuple t = e4();
+        if(t.attr("__len__")() == 2)
+        {
+            w.x = extract<T>(t[0]);
+            w.y = extract<T>(t[1]);
+        }
+        else
+            throw std::invalid_argument ("tuple of length 2 expected");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithRelError");
+    
+    if(e5.check())      { return v.equalWithRelError(w, e5()); }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithRelError");
+    
+}
+
+/*
+template <class T>
+static bool
+equalWithAbsErrorTuple(Vec2<T> &v, const tuple &t, T e)
+{
+    Vec2<T> w;
+    if(t.attr("__len__")() == 2)
+    {
+        w.x = extract<T>(t[0]);
+        w.y = extract<T>(t[1]);
+    }
+    else
+        throw std::invalid_argument ("tuple of length 2 expected");
+    
+    return v.equalWithAbsError(w, e);
+}
+
+template <class T>
+static bool
+equalWithRelErrorTuple(Vec2<T> &v, const tuple &t, T e)
+{
+    std::cout << "RelError Tuple called" << std::endl;
+    Vec2<T> w;
+    if(t.attr("__len__")() == 2)
+    {
+        w.x = extract<T>(t[0]);
+        w.y = extract<T>(t[1]);
+    }
+    else
+        throw std::invalid_argument ("tuple of length 2 expected");
+    
+    return v.equalWithRelError(w, e);
+}
+*/
+template <class T,class BoostPyType>
+static bool
+equal(const Vec2<T> &v, const BoostPyType &t)
+{
+    Vec2<T> w;
+    if(t.attr("__len__")() == 2)
+    {
+        w.x = extract<T>(t[0]);
+        w.y = extract<T>(t[1]);
+        
+        return (v == w);
+    }
+    else
+        throw std::invalid_argument ("tuple of length 2 expected");    
+}
+
+template <class T,class BoostPyType>
+static bool
+notequal(const Vec2<T> &v, const BoostPyType &t)
+{
+    Vec2<T> w;
+    if(t.attr("__len__")() == 2)
+    {
+        w.x = extract<T>(t[0]);
+        w.y = extract<T>(t[1]);
+        
+        return (v != w);
+    }
+    else
+        throw std::invalid_argument ("tuple of length 2 expected");    
+}
+
+
+
+// Trick to register methods for float-only-based vectors
+template <class T, IMATH_ENABLE_IF(!std::is_integral<T>::value)>
+void register_Vec2_floatonly(class_<Vec2<T>>& vec2_class)
+{
+   vec2_class
+        .def("length", &Vec2_length<T>,"length() magnitude of the vector")
+        .def("normalize", &Vec2_normalize<T>,return_internal_reference<>(),
+             "v.normalize() destructively normalizes v and returns a reference to it")
+        .def("normalizeExc", &Vec2_normalizeExc<T>,return_internal_reference<>(),
+             "v.normalizeExc() destructively normalizes V and returns a reference to it, throwing an exception if length() == 0")
+        .def("normalizeNonNull", &Vec2_normalizeNonNull<T>,return_internal_reference<>(),
+             "v.normalizeNonNull() destructively normalizes V and returns a reference to it, faster if lngth() != 0")
+        .def("normalized", &Vec2_normalized<T>, "v.normalized() returns a normalized copy of v")
+        .def("normalizedExc", &Vec2_normalizedExc<T>, "v.normalizedExc() returns a normalized copy of v, throwing an exception if length() == 0")
+        .def("normalizedNonNull", &Vec2_normalizedNonNull<T>, "v.normalizedNonNull() returns a normalized copy of v, faster if lngth() != 0")
+        .def("orthogonal", &orthogonal<T>)
+        .def("project", &project<T>)
+        .def("reflect", &reflect<T>)
+        ;
+}
+
+template <class T, IMATH_ENABLE_IF(std::is_integral<T>::value)>
+void register_Vec2_floatonly(class_<Vec2<T>>& vec2_class)
+{
+}
+
+
+
+template <class T>
+class_<Vec2<T> >
+register_Vec2()
+{
+    typedef PyImath::StaticFixedArray<Vec2<T>,T,2> Vec2_helper;
+
+    class_<Vec2<T> > vec2_class(Vec2Name<T>::value, Vec2Name<T>::value,init<Vec2<T> >("copy construction"));
+    vec2_class
+        .def("__init__",make_constructor(Vec2_construct_default<T>),"initialize to (0,0)")
+        .def("__init__",make_constructor(Vec2_object_constructor1<T>))
+        .def("__init__",make_constructor(Vec2_object_constructor2<T>))
+        .def_readwrite("x", &Vec2<T>::x)
+        .def_readwrite("y", &Vec2<T>::y)
+        .def("baseTypeEpsilon", &Vec2<T>::baseTypeEpsilon,"baseTypeEpsilon() epsilon value of the base type of the vector")
+        .staticmethod("baseTypeEpsilon")
+        .def("baseTypeMax", &Vec2<T>::baseTypeMax,"baseTypeMax() max value of the base type of the vector")
+        .staticmethod("baseTypeMax")
+        .def("baseTypeLowest", &Vec2<T>::baseTypeLowest,"baseTypeLowest() largest negative value of the base type of the vector")
+        .staticmethod("baseTypeLowest")
+        .def("baseTypeSmallest", &Vec2<T>::baseTypeSmallest,"baseTypeSmallest() smallest value of the base type of the vector")
+        .staticmethod("baseTypeSmallest")
+        .def("cross", &Vec2_cross<T>,"v1.cross(v2) right handed cross product")
+        .def("cross", &Vec2_cross_Vec2Array<T>,"v1.cross(v2) right handed array cross product")
+        .def("dimensions", &Vec2<T>::dimensions,"dimensions() number of dimensions in the vector")
+        .staticmethod("dimensions")
+        .def("dot", &Vec2_dot<T>,"v1.dot(v2) inner product of the two vectors")
+        .def("dot", &Vec2_dot_Vec2Array<T>,"v1.dot(v2) array inner product")
+        .def("equalWithAbsError", &Vec2<T>::equalWithAbsError,
+             "v1.equalWithAbsError(v2) true if the elements "
+             "of v1 and v2 are the same with an absolute error of no more than e, "
+             "i.e., abs(v1[i] - v2[i]) <= e")
+        .def("equalWithAbsError", &equalWithAbsErrorObj<T>)
+
+        .def("equalWithRelError", &Vec2<T>::equalWithRelError,
+             "v1.equalWithAbsError(v2) true if the elements "
+             "of v1 and v2 are the same with an absolute error of no more than e, "
+             "i.e., abs(v1[i] - v2[i]) <= e * abs(v1[i])")
+        .def("equalWithRelError", &equalWithRelErrorObj<T>)
+
+        .def("length2", &Vec2_length2<T>,"length2() square magnitude of the vector")
+        .def("__len__", Vec2_helper::len)
+        .def("__getitem__", Vec2_helper::getitem,return_value_policy<copy_non_const_reference>())
+        .def("__setitem__", Vec2_helper::setitem)
+        .def("closestVertex", &closestVertex<T>)
+        .def("negate", &Vec2_negate<T>, return_internal_reference<>())
+        .def("setValue", &setValue<T>)
+        .def("__neg__", &Vec2_neg<T>)
+        .def("__mul__", &Vec2_mul<T, int>)
+        .def("__mul__", &Vec2_mul<T, float>)
+        .def("__mul__", &Vec2_mul<T, double>)
+        .def("__mul__", &Vec2_mulT<T>)
+        .def("__mul__", &Vec2_mulTArray<T>)
+        .def("__mul__", &Vec2_mulTuple<T,tuple>)
+        .def("__mul__", &Vec2_mulTuple<T,list>)
+        .def("__rmul__", &Vec2_rmulT<T>)
+        .def("__rmul__", &Vec2_rmulTArray<T>)
+        .def("__rmul__", &Vec2_mulTuple<T,tuple>)
+        .def("__rmul__", &Vec2_mulTuple<T,list>)
+        .def("__imul__", &Vec2_imulV<T, int>,return_internal_reference<>())
+        .def("__imul__", &Vec2_imulV<T, float>,return_internal_reference<>())
+        .def("__imul__", &Vec2_imulV<T, double>,return_internal_reference<>())
+        .def("__imul__", &Vec2_imulT<T>,return_internal_reference<>())
+        .def(self * self)
+        .def("__mul__", &Vec2_mulM22<T, float>)
+        .def("__mul__", &Vec2_mulM22<T, double>)
+        .def("__mul__", &Vec2_mulM33<T, float>)
+        .def("__mul__", &Vec2_mulM33<T, double>)
+        .def("__imul__", &Vec2_imulM22<T, float>, return_internal_reference<>())
+        .def("__imul__", &Vec2_imulM22<T, double>, return_internal_reference<>())
+        .def("__imul__", &Vec2_imulM33<T, float>, return_internal_reference<>())
+        .def("__imul__", &Vec2_imulM33<T, double>, return_internal_reference<>())
+        .def(self / self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__div__", &Vec2_div<T,int>)
+        .def("__div__", &Vec2_div<T,float>)
+        .def("__div__", &Vec2_div<T,double>)
+        .def("__div__", &Vec2_divTuple<T,tuple>)
+        .def("__div__", &Vec2_divTuple<T,list>)
+        .def("__div__", &Vec2_divT<T>)
+        .def("__truediv__", &Vec2_div<T,int>)
+        .def("__truediv__", &Vec2_div<T,float>)
+        .def("__truediv__", &Vec2_div<T,double>)
+        .def("__truediv__", &Vec2_divTuple<T,tuple>)
+        .def("__truediv__", &Vec2_divTuple<T,list>)
+        .def("__truediv__", &Vec2_divT<T>)
+        .def("__rdiv__", &Vec2_rdivTuple<T,tuple>)
+        .def("__rdiv__", &Vec2_rdivTuple<T,list>)
+        .def("__rdiv__", &Vec2_rdivT<T>)
+        .def("__rtruediv__", &Vec2_rdivTuple<T,tuple>)
+        .def("__rtruediv__", &Vec2_rdivTuple<T,list>)
+        .def("__rtruediv__", &Vec2_rdivT<T>)
+        .def("__idiv__", &Vec2_idivObj<T>,return_internal_reference<>())
+        .def("__itruediv__", &Vec2_idivObj<T>,return_internal_reference<>())
+        .def("__xor__", &Vec2_dot<T>)
+        .def("__mod__", &Vec2_cross<T>)
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__eq__", &equal<T,tuple>)
+        .def("__ne__", &notequal<T,tuple>)
+        .def("__add__", &Vec2_add<T>)
+        .def("__add__", &Vec2_addV<T, int>)
+        .def("__add__", &Vec2_addV<T, float>)
+        .def("__add__", &Vec2_addV<T, double>)
+        .def("__add__", &Vec2_addT<T>)
+        .def("__add__", &Vec2_addTuple<T,tuple>)
+        .def("__add__", &Vec2_addTuple<T,list>)
+        .def("__radd__", &Vec2_add<T>)
+        .def("__radd__", &Vec2_addT<T>)
+        .def("__radd__", &Vec2_addTuple<T,tuple>)
+        .def("__radd__", &Vec2_addTuple<T,list>)
+        .def("__iadd__", &Vec2_iaddV<T, int>, return_internal_reference<>())
+        .def("__iadd__", &Vec2_iaddV<T, float>, return_internal_reference<>())
+        .def("__iadd__", &Vec2_iaddV<T, double>, return_internal_reference<>())
+        .def("__sub__", &Vec2_sub<T>)
+        .def("__sub__", &Vec2_subV<T, int>)
+        .def("__sub__", &Vec2_subV<T, float>)
+        .def("__sub__", &Vec2_subV<T, double>)
+        .def("__sub__", &Vec2_subT<T>)
+        .def("__sub__", &Vec2_subTuple<T,tuple>)
+        .def("__sub__", &Vec2_subTuple<T,list>)
+        .def("__rsub__", &Vec2_rsubT<T>)
+        .def("__rsub__", &Vec2_rsubTuple<T,tuple>)
+        .def("__rsub__", &Vec2_rsubTuple<T,list>)
+        .def("__isub__", &Vec2_isubV<T, int>, return_internal_reference<>())
+        .def("__isub__", &Vec2_isubV<T, float>, return_internal_reference<>())
+        .def("__isub__", &Vec2_isubV<T, double>, return_internal_reference<>())
+        .def("__lt__", &lessThan<T>)
+        .def("__gt__", &greaterThan<T>)
+        .def("__le__", &lessThanEqual<T>)
+        .def("__ge__", &greaterThanEqual<T>)
+       //.def(self_ns::str(self))
+       .def("__str__",&Vec2_str<T>)
+       .def("__repr__",&Vec2_repr<T>)
+        ;
+
+    register_Vec2_floatonly<T>(vec2_class);
+
+    decoratecopy(vec2_class);
+
+    //add_swizzle2_operators(v2f_class);
+    return vec2_class;
+}
+
+// XXX fixme - template this
+// really this should get generated automatically...
+
+template <class T,int index>
+static FixedArray<T>
+Vec2Array_get(FixedArray<IMATH_NAMESPACE::Vec2<T> > &va)
+{
+    return FixedArray<T>(&(va.unchecked_index(0)[index]),
+                         va.len(), 2*va.stride(), va.handle(), va.writable());
+}
+
+template <class T>
+static IMATH_NAMESPACE::Vec2<T>
+Vec2Array_min(const FixedArray<IMATH_NAMESPACE::Vec2<T> > &a)
+{
+    Vec2<T> tmp(Vec2<T>(0));
+    size_t len = a.len();
+    if (len > 0)
+        tmp = a[0];
+    for (size_t i=1; i < len; ++i)
+    {
+        if (a[i].x < tmp.x)
+            tmp.x = a[i].x;
+        if (a[i].y < tmp.y)
+            tmp.y = a[i].y;
+    }
+    return tmp;
+}
+
+template <class T>
+static IMATH_NAMESPACE::Vec2<T>
+Vec2Array_max(const FixedArray<IMATH_NAMESPACE::Vec2<T> > &a)
+{
+    Vec2<T> tmp(Vec2<T>(0));
+    size_t len = a.len();
+    if (len > 0)
+        tmp = a[0];
+    for (size_t i=1; i < len; ++i)
+    {
+        if (a[i].x > tmp.x)
+            tmp.x = a[i].x;
+        if (a[i].y > tmp.y)
+            tmp.y = a[i].y;
+    }
+    return tmp;
+}
+
+template <class T>
+static IMATH_NAMESPACE::Box<IMATH_NAMESPACE::Vec2<T> >
+Vec2Array_bounds(const FixedArray<IMATH_NAMESPACE::Vec2<T> > &a)
+{
+    Box<Vec2<T> > tmp;
+    size_t len = a.len();
+    for (size_t i=0; i < len; ++i)
+        tmp.extendBy(a[i]);
+    return tmp;
+}
+
+
+// Trick to register methods for float-only-based vectors
+template <class T, IMATH_ENABLE_IF(!std::is_integral<T>::value)>
+void register_Vec2Array_floatonly(class_<FixedArray<Vec2<T>>>& vec2Array_class)
+{
+    generate_member_bindings<op_vecLength<IMATH_NAMESPACE::Vec2<T> >     >(vec2Array_class,"length","");
+    generate_member_bindings<op_vecNormalize<IMATH_NAMESPACE::Vec2<T> >  >(vec2Array_class,"normalize","");
+    generate_member_bindings<op_vecNormalized<IMATH_NAMESPACE::Vec2<T> > >(vec2Array_class,"normalized","");
+    generate_member_bindings<op_vecNormalizeExc<IMATH_NAMESPACE::Vec2<T> >  >(vec2Array_class,"normalizeExc","");
+    generate_member_bindings<op_vecNormalizedExc<IMATH_NAMESPACE::Vec2<T> > >(vec2Array_class,"normalizedExc","");
+}
+
+template <class T, IMATH_ENABLE_IF(std::is_integral<T>::value)>
+void register_Vec2Array_floatonly(class_<FixedArray<Vec2<T>>>& vec2Array_class)
+{
+}
+
+
+
+template <class T>
+class_<FixedArray<IMATH_NAMESPACE::Vec2<T> > >
+register_Vec2Array()
+{
+    using boost::mpl::true_;
+    using boost::mpl::false_;
+
+    class_<FixedArray<IMATH_NAMESPACE::Vec2<T> > > vec2Array_class = FixedArray<IMATH_NAMESPACE::Vec2<T> >::register_("Fixed length array of IMATH_NAMESPACE::Vec2");
+    vec2Array_class
+        .add_property("x",&Vec2Array_get<T,0>)
+        .add_property("y",&Vec2Array_get<T,1>)
+        .def("__setitem__", &setItemTuple<T,tuple>)
+        .def("__setitem__", &setItemTuple<T,list>)
+        .def("min", &Vec2Array_min<T>)
+        .def("max", &Vec2Array_max<T>)
+        .def("bounds", &Vec2Array_bounds<T>)
+        ;
+
+    add_arithmetic_math_functions(vec2Array_class);
+    add_comparison_functions(vec2Array_class);
+
+    register_Vec2Array_floatonly(vec2Array_class);
+    generate_member_bindings<op_vecLength2<IMATH_NAMESPACE::Vec2<T> >    >(vec2Array_class,"length2","");
+    generate_member_bindings<op_vec2Cross<T>,           true_>(vec2Array_class,"cross","return the cross product of (self,x)",boost::python::args("x"));
+    generate_member_bindings<op_vecDot<IMATH_NAMESPACE::Vec2<T> >,true_>(vec2Array_class,"dot","return the inner product of (self,x)",boost::python::args("x"));
+
+    generate_member_bindings<op_mul<IMATH_NAMESPACE::Vec2<T>,T>,  true_>(vec2Array_class,"__mul__" ,"self*x", boost::python::args("x"));
+    generate_member_bindings<op_mul<IMATH_NAMESPACE::Vec2<T>,T>,  true_>(vec2Array_class,"__rmul__","x*self", boost::python::args("x"));
+    generate_member_bindings<op_imul<IMATH_NAMESPACE::Vec2<T>,T>, true_>(vec2Array_class,"__imul__","self*=x",boost::python::args("x"));
+    generate_member_bindings<op_div<IMATH_NAMESPACE::Vec2<T>,T>,  true_>(vec2Array_class,"__div__" ,"self/x", boost::python::args("x"));
+    generate_member_bindings<op_div<IMATH_NAMESPACE::Vec2<T>,T>,  true_>(vec2Array_class,"__truediv__" ,"self/x", boost::python::args("x"));
+    generate_member_bindings<op_idiv<IMATH_NAMESPACE::Vec2<T>,T>, true_>(vec2Array_class,"__idiv__","self/=x",boost::python::args("x"));
+    generate_member_bindings<op_idiv<IMATH_NAMESPACE::Vec2<T>,T>, true_>(vec2Array_class,"__itruediv__","self/=x",boost::python::args("x"));
+
+    decoratecopy(vec2Array_class);
+
+    return vec2Array_class;
+}
+
+}
+
+#endif
diff --git a/src/python/PyImath/PyImathVec2fd.cpp b/src/python/PyImath/PyImathVec2fd.cpp
new file mode 100644 (file)
index 0000000..d872adc
--- /dev/null
@@ -0,0 +1,46 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathVec2Impl.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+template <> const char *PyImath::V2fArray::name() { return "V2fArray"; }
+template <> const char *PyImath::V2dArray::name() { return "V2dArray"; }
+
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template<> const char *Vec2Name<float>::value  = "V2f";
+template<> const char *Vec2Name<double>::value = "V2d";
+
+// Specialization for float to full precision
+template <>
+std::string Vec2_repr(const Vec2<float> &v)
+{
+    return (boost::format("%s(%.9g, %.9g)")
+                        % Vec2Name<float>::value % v.x % v.y).str();
+}
+
+// Specialization for double to full precision
+template <>
+std::string Vec2_repr(const Vec2<double> &v)
+{
+    return (boost::format("%s(%.17g, %.17g)")
+                        % Vec2Name<double>::value % v.x % v.y).str();
+}
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec2<float> > register_Vec2<float>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec2<double> > register_Vec2<double>();
+                
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec2<float> > > register_Vec2Array<float>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec2<double> > > register_Vec2Array<double>();
+
+template<> IMATH_NAMESPACE::Vec2<float> PYIMATH_EXPORT FixedArrayDefaultValue<IMATH_NAMESPACE::Vec2<float> >::value() { return IMATH_NAMESPACE::Vec2<float>(0,0); }
+template<> IMATH_NAMESPACE::Vec2<double> PYIMATH_EXPORT FixedArrayDefaultValue<IMATH_NAMESPACE::Vec2<double> >::value() { return IMATH_NAMESPACE::Vec2<double>(0,0); }
+}
+
diff --git a/src/python/PyImath/PyImathVec2si.cpp b/src/python/PyImath/PyImathVec2si.cpp
new file mode 100644 (file)
index 0000000..796e781
--- /dev/null
@@ -0,0 +1,34 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathVec2Impl.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+template <> const char *PyImath::V2sArray::name()   { return "V2sArray"; }
+template <> const char *PyImath::V2iArray::name()   { return "V2iArray"; }
+template <> const char *PyImath::V2i64Array::name() { return "V2i64Array"; }
+
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template<> const char *Vec2Name<short>::value   = "V2s";
+template<> const char *Vec2Name<int>::value     = "V2i";
+template<> const char *Vec2Name<int64_t>::value = "V2i64";
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec2<short> >   register_Vec2<short>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec2<int> >     register_Vec2<int>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec2<int64_t> > register_Vec2<int64_t>();
+                
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec2<short> > >   register_Vec2Array<short>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec2<int> > >     register_Vec2Array<int>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec2<int64_t> > > register_Vec2Array<int64_t>();
+
+template<> IMATH_NAMESPACE::Vec2<short>   PYIMATH_EXPORT FixedArrayDefaultValue<IMATH_NAMESPACE::Vec2<short> >::value()   { return IMATH_NAMESPACE::Vec2<short>(0,0); }
+template<> IMATH_NAMESPACE::Vec2<int>     PYIMATH_EXPORT FixedArrayDefaultValue<IMATH_NAMESPACE::Vec2<int> >::value()     { return IMATH_NAMESPACE::Vec2<int>(0,0); }
+template<> IMATH_NAMESPACE::Vec2<int64_t> PYIMATH_EXPORT FixedArrayDefaultValue<IMATH_NAMESPACE::Vec2<int64_t> >::value() { return IMATH_NAMESPACE::Vec2<int64_t>(0,0); }
+}
diff --git a/src/python/PyImath/PyImathVec3ArrayImpl.h b/src/python/PyImath/PyImathVec3ArrayImpl.h
new file mode 100644 (file)
index 0000000..b73e416
--- /dev/null
@@ -0,0 +1,178 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathVec3ArrayImpl_h_
+#define _PyImathVec3ArrayImpl_h_
+
+//
+// This .C file was turned into a header file so that instantiations
+// of the various V3* types can be spread across multiple files in
+// order to work around MSVC limitations.
+//
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <ImathVec.h>
+#include <ImathVecAlgo.h>
+#include "PyImath.h"
+#include "PyImathBox.h"
+#include "PyImathVec.h"
+#include "PyImathDecorators.h"
+#include "PyImathMathExc.h"
+#include "PyImathOperators.h"
+#include "PyImathVecOperators.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+// XXX fixme - template this
+// really this should get generated automatically...
+
+template <class T,int index>
+static FixedArray<T>
+Vec3Array_get(FixedArray<IMATH_NAMESPACE::Vec3<T> > &va)
+{
+    return FixedArray<T>(&(va.unchecked_index(0)[index]),
+                         va.len(), 3*va.stride(), va.handle(), va.writable());
+}
+
+template <class T>
+static void
+setItemTuple(FixedArray<IMATH_NAMESPACE::Vec3<T> > &va, Py_ssize_t index, const tuple &t)
+{
+    if(t.attr("__len__")() == 3)
+    {
+        Vec3<T> v;
+        v.x = extract<T>(t[0]);
+        v.y = extract<T>(t[1]);
+        v.z = extract<T>(t[2]);
+        va[va.canonical_index(index)] = v;
+    }
+    else
+      throw std::invalid_argument ("tuple of length 3 expected");
+}
+
+template <class T>
+static IMATH_NAMESPACE::Vec3<T>
+Vec3Array_min(const FixedArray<IMATH_NAMESPACE::Vec3<T> > &a)
+{
+    Vec3<T> tmp(Vec3<T>(0));
+    size_t len = a.len();
+    if (len > 0)
+        tmp = a[0];
+    for (size_t i=1; i < len; ++i)
+    {
+        if (a[i].x < tmp.x)
+            tmp.x = a[i].x;
+        if (a[i].y < tmp.y)
+            tmp.y = a[i].y;
+        if (a[i].z < tmp.z)
+            tmp.z = a[i].z;
+    }
+    return tmp;
+}
+
+template <class T>
+static IMATH_NAMESPACE::Vec3<T>
+Vec3Array_max(const FixedArray<IMATH_NAMESPACE::Vec3<T> > &a)
+{
+    Vec3<T> tmp(Vec3<T>(0));
+    size_t len = a.len();
+    if (len > 0)
+        tmp = a[0];
+    for (size_t i=1; i < len; ++i)
+    {
+        if (a[i].x > tmp.x)
+            tmp.x = a[i].x;
+        if (a[i].y > tmp.y)
+            tmp.y = a[i].y;
+        if (a[i].z > tmp.z)
+            tmp.z = a[i].z;
+    }
+    return tmp;
+}
+
+template <class T>
+static IMATH_NAMESPACE::Box<IMATH_NAMESPACE::Vec3<T> >
+Vec3Array_bounds(const FixedArray<IMATH_NAMESPACE::Vec3<T> > &a)
+{
+    Box<Vec3<T> > tmp;
+    size_t len = a.len();
+    for (size_t i=0; i < len; ++i)
+        tmp.extendBy(a[i]);
+    return tmp;
+}
+
+
+// Trick to register methods for float-only-based vectors
+template <class T, IMATH_ENABLE_IF(!std::is_integral<T>::value)>
+void register_Vec3Array_floatonly(class_<FixedArray<Vec3<T>>>& vec3Array_class)
+{
+    generate_member_bindings<op_vecLength<IMATH_NAMESPACE::Vec3<T> >     >(vec3Array_class,"length","");
+    generate_member_bindings<op_vecNormalize<IMATH_NAMESPACE::Vec3<T> >  >(vec3Array_class,"normalize","");
+    generate_member_bindings<op_vecNormalized<IMATH_NAMESPACE::Vec3<T> > >(vec3Array_class,"normalized","");
+    generate_member_bindings<op_vecNormalizeExc<IMATH_NAMESPACE::Vec3<T> >  >(vec3Array_class,"normalizeExc","");
+    generate_member_bindings<op_vecNormalizedExc<IMATH_NAMESPACE::Vec3<T> > >(vec3Array_class,"normalizedExc","");
+}
+
+template <class T, IMATH_ENABLE_IF(std::is_integral<T>::value)>
+void register_Vec3Array_floatonly(class_<FixedArray<Vec3<T>>>& vec3Array_class)
+{
+}
+
+
+
+template <class T>
+class_<FixedArray<IMATH_NAMESPACE::Vec3<T> > >
+register_Vec3Array()
+{
+    using boost::mpl::true_;
+    using boost::mpl::false_;
+
+    class_<FixedArray<IMATH_NAMESPACE::Vec3<T> > > vec3Array_class = FixedArray<IMATH_NAMESPACE::Vec3<T> >::register_("Fixed length array of IMATH_NAMESPACE::Vec3");
+    vec3Array_class
+        .add_property("x",&Vec3Array_get<T,0>)
+        .add_property("y",&Vec3Array_get<T,1>)
+        .add_property("z",&Vec3Array_get<T,2>)
+        .def("__setitem__", &setItemTuple<T>)
+        .def("min", &Vec3Array_min<T>)
+        .def("max", &Vec3Array_max<T>)
+        .def("bounds", &Vec3Array_bounds<T>)
+        ;
+
+    add_arithmetic_math_functions(vec3Array_class);
+    add_comparison_functions(vec3Array_class);
+
+    register_Vec3Array_floatonly(vec3Array_class);
+    generate_member_bindings<op_vecLength2<IMATH_NAMESPACE::Vec3<T> >    >(vec3Array_class,"length2","");
+
+    generate_member_bindings<op_vec3Cross<T>,           true_>(vec3Array_class,"cross","return the cross product of (self,x)",boost::python::args("x"));
+    generate_member_bindings<op_vecDot<IMATH_NAMESPACE::Vec3<T> >,true_>(vec3Array_class,"dot","return the inner product of (self,x)",boost::python::args("x"));
+
+    generate_member_bindings<op_mul<IMATH_NAMESPACE::Vec3<T>,T>,  true_>(vec3Array_class,"__mul__" ,"self*x", boost::python::args("x"));
+    generate_member_bindings<op_mul<IMATH_NAMESPACE::Vec3<T>,IMATH_NAMESPACE::M44f>,false_>(vec3Array_class,"__mul__" ,"self*x", boost::python::args("x"));
+    generate_member_bindings<op_mul<IMATH_NAMESPACE::Vec3<T>,IMATH_NAMESPACE::M44d>,false_>(vec3Array_class,"__mul__" ,"self*x", boost::python::args("x"));
+
+    generate_member_bindings<op_mul<IMATH_NAMESPACE::Vec3<T>,T>,  true_>(vec3Array_class,"__rmul__","x*self", boost::python::args("x"));
+    generate_member_bindings<op_imul<IMATH_NAMESPACE::Vec3<T>,T>, true_>(vec3Array_class,"__imul__","self*=x",boost::python::args("x"));
+    generate_member_bindings<op_div<IMATH_NAMESPACE::Vec3<T>,T>,  true_>(vec3Array_class,"__div__" ,"self/x", boost::python::args("x"));
+    generate_member_bindings<op_div<IMATH_NAMESPACE::Vec3<T>,T>,  true_>(vec3Array_class,"__truediv__" ,"self/x", boost::python::args("x"));
+    generate_member_bindings<op_idiv<IMATH_NAMESPACE::Vec3<T>,T>, true_>(vec3Array_class,"__idiv__","self/=x",boost::python::args("x"));
+    generate_member_bindings<op_idiv<IMATH_NAMESPACE::Vec3<T>,T>, true_>(vec3Array_class,"__itruediv__","self/=x",boost::python::args("x"));
+
+    decoratecopy(vec3Array_class);
+
+    return vec3Array_class;
+}
+
+}  // namespace PyImath
+
+#endif   // _PyImathVec3ArrayImpl_h_
diff --git a/src/python/PyImath/PyImathVec3Impl.h b/src/python/PyImath/PyImathVec3Impl.h
new file mode 100644 (file)
index 0000000..c2b0750
--- /dev/null
@@ -0,0 +1,1046 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathVec3Impl_h_
+#define _PyImathVec3Impl_h_
+
+//
+// This .C file was turned into a header file so that instantiations
+// of the various V3* types can be spread across multiple files in
+// order to work around MSVC limitations.
+//
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <ImathVec.h>
+#include <ImathVecAlgo.h>
+#include "PyImath.h"
+#include "PyImathMathExc.h"
+#include "PyImathVec.h"
+#include "PyImathDecorators.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct Vec3Name      { static const char *value(); };
+
+// create a new default constructor that initializes Vec3<T> to zero.
+template <class T>
+static Vec3<T> * Vec3_construct_default()
+{
+    return new Vec3<T>(T(0),T(0),T(0));
+}
+
+template <class T>
+static Vec3<T> * Vec3_object_constructor1(const object &obj)
+{
+    Vec3<T> w;
+    extract<Vec3<int> >     e1(obj);
+    extract<Vec3<float> >   e2(obj);
+    extract<Vec3<double> >  e3(obj);
+    extract<tuple>          e4(obj);
+    extract<double>         e5(obj);
+    extract<list>           e6(obj);
+    
+    if(e1.check())      { w = e1(); }
+    else if(e2.check()) { w = e2(); }
+    else if(e3.check()) { w = e3(); }
+    else if(e4.check())
+    {
+        tuple t = e4();
+        if(t.attr("__len__")() == 3)
+        {
+            w.x = extract<T>(t[0]);
+            w.y = extract<T>(t[1]);
+            w.z = extract<T>(t[2]);
+        }
+        else
+            throw std::invalid_argument ("tuple must have length of 3");
+        
+    }
+    else if(e5.check()) { T a = e5(); w.setValue(a, a, a); }
+    else if(e6.check())
+    {
+        list l = e6();
+        if(l.attr("__len__")() == 3)
+        {
+            w.x = extract<T>(l[0]);
+            w.y = extract<T>(l[1]);
+            w.z = extract<T>(l[2]);
+        }
+        else
+            throw std::invalid_argument ("list must have length of 3");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to Vec3 constructor");
+    
+    Vec3<T> *v = new Vec3<T>;
+    *v = w;
+    
+    return v;
+
+}
+
+template <class T>
+static Vec3<T> * Vec3_object_constructor2(const object &obj1, const object &obj2, const object &obj3)
+{
+    extract<double>    e1(obj1);
+    extract<double>    e2(obj2);
+    extract<double>    e3(obj3);
+    Vec3<T> *v = new Vec3<T>;
+    
+    if(e1.check()) { v->x = e1();}
+    else { throw std::invalid_argument ("invalid parameters passed to Vec3 constructor"); }
+    
+    if(e2.check()) { v->y = e2();}
+    else { throw std::invalid_argument ("invalid parameters passed to Vec3 constructor"); }    
+
+    if(e3.check()) { v->z = e3();}
+    else { throw std::invalid_argument ("invalid parameters passed to Vec3 constructor"); } 
+    
+    return v;
+}
+
+
+
+// Implementations of str and repr are same here,
+// but we'll specialize repr for float and double to make them exact.
+template <class T>
+static std::string Vec3_str(const Vec3<T> &v)
+{
+    std::stringstream stream;
+    stream << Vec3Name<T>::value() << "(" << v.x << ", " << v.y << ", " << v.z << ")";
+    return stream.str();
+}
+template <class T>
+static std::string Vec3_repr(const Vec3<T> &v)
+{
+    std::stringstream stream;
+    stream << Vec3Name<T>::value() << "(" << v.x << ", " << v.y << ", " << v.z << ")";
+    return stream.str();
+}
+
+template <class T>
+static IMATH_NAMESPACE::Vec3<T>
+Vec3_cross(const IMATH_NAMESPACE::Vec3<T> &v, const IMATH_NAMESPACE::Vec3<T> &other) 
+{ 
+    MATH_EXC_ON;
+    return v.cross(other);
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Vec3<T> >
+Vec3_cross_Vec3Array(const IMATH_NAMESPACE::Vec3<T> &va, const FixedArray<IMATH_NAMESPACE::Vec3<T> > &vb) 
+{ 
+    MATH_EXC_ON;
+    size_t len = vb.len(); 
+    FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); 
+    for (size_t i = 0; i < len; ++i) 
+        f[i] = va.cross(vb[i]); 
+    return f; 
+}
+
+template <class T>
+static T
+Vec3_dot(const IMATH_NAMESPACE::Vec3<T> &v, const IMATH_NAMESPACE::Vec3<T> &other) 
+{ 
+    MATH_EXC_ON;
+    return v.dot(other);
+}
+
+template <class T>
+static FixedArray<T>
+Vec3_dot_Vec3Array(const IMATH_NAMESPACE::Vec3<T> &va, const FixedArray<IMATH_NAMESPACE::Vec3<T> > &vb) 
+{ 
+    MATH_EXC_ON;
+    size_t len = vb.len(); 
+    FixedArray<T> f(len); 
+    for (size_t i = 0; i < len; ++i) 
+        f[i] = va.dot(vb[i]); 
+    return f; 
+}
+
+template <class T>
+static T
+Vec3_length(const IMATH_NAMESPACE::Vec3<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.length();
+}
+
+template <class T>
+static T
+Vec3_length2(const IMATH_NAMESPACE::Vec3<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.length2();
+}
+
+template <class T>
+static const Vec3<T> &
+Vec3_normalize(IMATH_NAMESPACE::Vec3<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalize();
+}
+
+template <class T>
+static const Vec3<T> &
+Vec3_normalizeExc(IMATH_NAMESPACE::Vec3<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizeExc();
+}
+
+template <class T>
+static const Vec3<T> &
+Vec3_normalizeNonNull(IMATH_NAMESPACE::Vec3<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizeNonNull();
+}
+
+template <class T>
+static Vec3<T>
+Vec3_normalized(const IMATH_NAMESPACE::Vec3<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalized();
+}
+
+template <class T>
+static Vec3<T>
+Vec3_normalizedExc(const IMATH_NAMESPACE::Vec3<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizedExc();
+}
+
+template <class T>
+static Vec3<T>
+Vec3_normalizedNonNull(const IMATH_NAMESPACE::Vec3<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizedNonNull();
+}
+
+template <class T>
+static Vec3<T>
+closestVertex(Vec3<T> &p, const Vec3<T> &v0, const Vec3<T> &v1, const Vec3<T> &v2)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::closestVertex(v0, v1, v2, p);
+}
+
+template <class T>
+static const Vec3<T> &
+Vec3_negate(IMATH_NAMESPACE::Vec3<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.negate();
+}
+
+template <class T>
+static Vec3<T>
+orthogonal(const Vec3<T> &v, const Vec3<T> &v0)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::orthogonal(v, v0);
+}
+
+template <class T>
+static Vec3<T>
+project(const Vec3<T> &v, const Vec3<T> &v0)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::project(v0, v);
+}
+
+template <class T>
+static Vec3<T>
+reflect(const Vec3<T> &v, const Vec3<T> &v0)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::reflect(v, v0);
+}
+
+template <class T>
+static void
+setValue(Vec3<T> &v, T a, T b, T c)
+{
+    v.x = a;
+    v.y = b;
+    v.z = c;
+}
+
+template <class T>
+static Vec3<T>
+Vec3_add (const Vec3<T> &v, const Vec3<T> &w)
+{
+    MATH_EXC_ON;
+    return v + w;
+}
+
+template <class T>
+static Vec3<T>
+Vec3_sub (const Vec3<T> &v, const Vec3<T> &w)
+{
+    MATH_EXC_ON;
+    return v - w;
+}
+
+template <class T>
+static Vec3<T>
+Vec3_neg (const Vec3<T> &v)
+{
+    MATH_EXC_ON;
+    return -v;
+}
+
+template <class T, class U>
+static Vec3<T>
+Vec3_mul (const Vec3<T> &v, Vec3<U> &w)
+{
+    MATH_EXC_ON;
+    Vec3<T> w2 (w);
+    return v * w2;
+}
+
+template <class T>
+static Vec3<T>
+Vec3_mulT (const Vec3<T> &v, T t)
+{
+    MATH_EXC_ON;
+    return v * t;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Vec3<T> >
+Vec3_mulTArray (const Vec3<T> &v, const FixedArray<T> &t)
+{
+    MATH_EXC_ON;
+    size_t len = t.len();
+    FixedArray<IMATH_NAMESPACE::Vec3<T> > retval(len);
+    for (size_t i=0; i<len; ++i) retval[i] = v*t[i];
+    return retval;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Vec3<T> >
+Vec3_rmulTArray (const Vec3<T> &v, const FixedArray<T> &t)
+{
+    return Vec3_mulTArray(v,t);
+}
+
+template <class T,class S>
+static Vec3<T>
+Vec3_div (Vec3<T> &v, Vec3<S> &w)
+{
+    MATH_EXC_ON;
+    return v / w;
+}
+
+template <class T>
+static Vec3<T>
+Vec3_rmulT (Vec3<T> &v, T t)
+{
+    MATH_EXC_ON;
+    return t * v;
+}
+
+template <class T, class U>
+static const Vec3<T> &
+Vec3_imulV(Vec3<T> &v, const Vec3<U> &w)
+{
+    MATH_EXC_ON;
+    return v *= w;
+}
+
+template <class T>
+static const Vec3<T> &
+Vec3_imulT(IMATH_NAMESPACE::Vec3<T> &v, T t) 
+{ 
+    MATH_EXC_ON;
+    return v *= t;
+}
+
+template <class T, class U>
+static Vec3<T>
+Vec3_mulM33 (Vec3<T> &v, const Matrix33<U> &m)
+{
+    MATH_EXC_ON;
+    return v * m;
+}
+
+template <class T, class U>
+static Vec3<T>
+Vec3_mulM44 (Vec3<T> &v, const Matrix44<U> &m)
+{
+    MATH_EXC_ON;
+    return v * m;
+}
+
+template <class T>
+static const Vec3<T> &
+Vec3_idivObj(IMATH_NAMESPACE::Vec3<T> &v, const object &o) 
+{ 
+    MATH_EXC_ON;
+    Vec3<T> v2;
+    if (PyImath::V3<T>::convert (o.ptr(), &v2))
+    {
+        return v /= v2;
+    }
+    else
+    {
+        extract<double> e(o);
+        if (e.check())
+            return v /= e();
+        else
+          throw std::invalid_argument ("V3 division expects an argument"
+                   "convertible to a V3");
+    }
+}
+
+template <class T>
+static Vec3<T>
+Vec3_subT(const Vec3<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec3<T> w;
+    w.setValue(v.x - a, v.y - a, v.z - a);
+    return w;
+}
+
+template <class T,class BoostPyType>
+static Vec3<T>
+Vec3_subTuple(const Vec3<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec3<T> w;
+    
+    if(t.attr("__len__")() == 3)
+    {
+        w.x = v.x - extract<T>(t[0]);
+        w.y = v.y - extract<T>(t[1]);
+        w.z = v.z - extract<T>(t[2]);
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 3");
+    
+    return w;
+}
+
+template <class T>
+static Vec3<T>
+Vec3_rsubT(const Vec3<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec3<T> w;
+    w.setValue(a - v.x, a - v.y, a - v.z);
+    return w;
+}
+
+template <class T, class BoostPyType>
+static Vec3<T>
+Vec3_rsubTuple(const Vec3<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec3<T> w;
+    
+    if(t.attr("__len__")() == 3)
+    {
+        w.x = extract<T>(t[0]) - v.x;
+        w.y = extract<T>(t[1]) - v.y;
+        w.z = extract<T>(t[2]) - v.z;
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 3");
+    
+    return w;
+}
+
+template <class T, class BoostPyType>
+static Vec3<T>
+Vec3_addTuple(const Vec3<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec3<T> w;
+    
+    if(t.attr("__len__")() == 3)
+    {
+        w.x = v.x + extract<T>(t[0]);
+        w.y = v.y + extract<T>(t[1]);
+        w.z = v.z + extract<T>(t[2]);
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 3");
+    
+    return w;
+}
+
+template <class T>
+static Vec3<T>
+Vec3_addT(const Vec3<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec3<T> w;
+    w.setValue(v.x + a, v.y + a, v.z + a);
+    return w;
+}
+
+template <class T, class U>
+static Vec3<T>
+Vec3_addV(const Vec3<T> &v, const Vec3<U> &w)
+{
+    MATH_EXC_ON;
+    return v + w;
+}
+
+template <class T, class U>
+static const Vec3<T> &
+Vec3_iaddV(Vec3<T> &v, const Vec3<U> &w)
+{
+    MATH_EXC_ON;
+    return v += w;
+}
+
+template <class T, class U>
+static Vec3<T>
+Vec3_subV(const Vec3<T> &v, const Vec3<U> &w)
+{
+    MATH_EXC_ON;
+    return v - w;
+}
+
+template <class T, class U>
+static const Vec3<T> &
+Vec3_isubV(Vec3<T> &v, const Vec3<U> &w)
+{
+    MATH_EXC_ON;
+    return v -= w;
+}
+
+template <class T>
+static Vec3<T>
+mult(const Vec3<T> &v, tuple t)
+{
+    MATH_EXC_ON;
+    Vec3<T> w;
+    
+    if(t.attr("__len__")() == 1){
+        w.x = v.x*extract<T>(t[0]);
+        w.y = v.y*extract<T>(t[0]);
+        w.z = v.z*extract<T>(t[0]);
+    }        
+    else if(t.attr("__len__")() == 3){
+        w.x = v.x*extract<T>(t[0]);
+        w.y = v.y*extract<T>(t[1]);
+        w.z = v.z*extract<T>(t[2]);
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 1 or 3");
+    
+    return w;
+}
+
+template <class T, class U>
+static const Vec3<T> &
+Vec3_imulM44 (Vec3<T> &v, const Matrix44<U> &m)
+{
+    MATH_EXC_ON;
+    return v *= m;
+}
+
+template <class T, class BoostPyType>
+static Vec3<T>
+Vec3_divTuple(const Vec3<T> &v, const BoostPyType &t)
+{
+    if(t.attr("__len__")() == 3)
+    {
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+        if(x != T(0) && y != T(0) && z != T(0))
+            return Vec3<T>(v.x / x, v.y / y, v.z / z);
+        else
+          throw std::domain_error ("Division by zero");
+    }
+    else
+        throw std::invalid_argument ("Vec3 expects tuple of length 3");
+}
+
+template <class T, class BoostPyType>
+static Vec3<T>
+Vec3_rdivTuple(const Vec3<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec3<T> w;
+    if(t.attr("__len__")() == 3)
+    {
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+            
+        if(v.x != T(0) && v.y != T(0) && v.z != T(0)){
+            w.setValue(x / v.x, y / v.y, z / v.z);
+        }
+        else
+          throw std::domain_error ("Division by zero");
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 3");
+    
+    return w;
+}
+
+template <class T>
+static Vec3<T>
+Vec3_divT(const Vec3<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec3<T> w;
+    if(a != T(0)){
+        w.setValue(v.x / a, v.y / a, v.z / a);
+    }
+    else
+      throw std::domain_error ("Division by zero");
+
+    return w;
+}
+
+template <class T>
+static Vec3<T>
+Vec3_rdivT(const Vec3<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec3<T> w;
+    if(v.x != T(0) && v.y != T(0) && v.z != T(0)){
+        w.setValue(a / v.x, a / v.y, a / v.z);
+    }
+    else
+      throw std::domain_error ("Division by zero");
+
+    return w;
+}
+
+template <class T>
+static Vec3<T>
+Vec3_Vec3_mulT(const Vec3<T>& v, const Vec3<T>& w)
+{
+    MATH_EXC_ON;
+    return v*w;
+}
+
+template <class T>
+static Vec3<T>
+Vec3_Vec3_divT(const Vec3<T>& v, const Vec3<T>& w)
+{
+    MATH_EXC_ON;
+    return v/w;
+}
+
+template <class T>
+static bool
+lessThan(const Vec3<T> &v, const object &obj)
+{
+    extract<Vec3<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec3<T> w;
+    if(e1.check())
+    {
+        w = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+        w.setValue(x,y,z);
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator <");
+    
+    bool isLessThan = (v.x <= w.x && v.y <= w.y && v.z <= w.z)
+                    && v != w;
+    
+    return isLessThan;
+}
+
+template <class T>
+static bool
+greaterThan(const Vec3<T> &v, const object &obj)
+{
+    extract<Vec3<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec3<T> w;
+    if(e1.check())
+    {
+        w = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+        w.setValue(x,y,z);
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator >");
+    
+    bool isGreaterThan = (v.x >= w.x && v.y >= w.y && v.z >= w.z)
+                       && v != w;
+
+    return isGreaterThan;
+}
+
+template <class T>
+static bool
+lessThanEqual(const Vec3<T> &v, const object &obj)
+{
+    extract<Vec3<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec3<T> w;
+    if(e1.check())
+    {
+        w = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+        w.setValue(x,y,z);
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator <=");
+    
+    bool isLessThanEqual = (v.x <= w.x && v.y <= w.y && v.z <= w.z);
+                   
+    return isLessThanEqual;
+}
+
+template <class T>
+static bool
+greaterThanEqual(const Vec3<T> &v, const object &obj)
+{
+    extract<Vec3<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec3<T> w;
+    if(e1.check())
+    {
+        w = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+        w.setValue(x,y,z);
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator >=");
+    
+    bool isGreaterThanEqual = (v.x >= w.x && v.y >= w.y && v.z >= w.z);
+
+    return isGreaterThanEqual;
+}
+
+
+template <class T>
+static bool
+equalWithAbsErrorObj(const Vec3<T> &v, const object &obj1, const object &obj2)
+{    
+    extract<Vec3<int> >    e1(obj1);
+    extract<Vec3<float> >  e2(obj1);
+    extract<Vec3<double> > e3(obj1);
+    
+    extract<tuple>         e4(obj1);
+    extract<double>        e5(obj2);
+    
+    Vec3<T> w;
+    if(e1.check())      { w = e1(); }
+    else if(e2.check()) { w = e2(); }
+    else if(e3.check()) { w = e3(); }
+    else if(e4.check())
+    {    
+        tuple t = e4();
+        if(t.attr("__len__")() == 3)
+        {
+            w.x = extract<T>(t[0]);
+            w.y = extract<T>(t[1]);
+            w.z = extract<T>(t[2]);
+        }
+        else
+            throw std::invalid_argument ("tuple of length 3 expected");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithAbsError");
+    
+    if(e5.check())      { return v.equalWithAbsError(w, e5()); }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithAbsError");
+}
+
+template <class T>
+static bool
+equalWithRelErrorObj(const Vec3<T> &v, const object &obj1, const object &obj2)
+{    
+    extract<Vec3<int> >    e1(obj1);
+    extract<Vec3<float> >  e2(obj1);
+    extract<Vec3<double> > e3(obj1);
+    
+    extract<tuple>         e4(obj1);    
+    extract<double>        e5(obj2);
+    
+    Vec3<T> w;
+    if(e1.check())      { w = e1(); }
+    else if(e2.check()) { w = e2(); }
+    else if(e3.check()) { w = e3(); }
+    else if(e4.check())
+    {    
+        tuple t = e4();
+        if(t.attr("__len__")() == 3)
+        {
+            w.x = extract<T>(t[0]);
+            w.y = extract<T>(t[1]);
+            w.z = extract<T>(t[2]);
+        }
+        else
+            throw std::invalid_argument ("tuple of length 3 expected");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithRelError");
+    
+    if(e5.check())      { return v.equalWithRelError(w, e5()); }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithRelError");    
+    
+}
+
+
+template <class T>
+static bool
+equal(const Vec3<T> &v, const tuple &t)
+{
+    Vec3<T> w;
+    if(t.attr("__len__")() == 3)
+    {
+        w.x = extract<T>(t[0]);
+        w.y = extract<T>(t[1]);
+        w.z = extract<T>(t[2]);
+        
+        return (v == w);
+    }
+    else
+        throw std::invalid_argument ("tuple of length 3 expected");    
+}
+
+template <class T>
+static bool
+notequal(const Vec3<T> &v, const tuple &t)
+{
+    Vec3<T> w;
+    if(t.attr("__len__")() == 3)
+    {
+        w.x = extract<T>(t[0]);
+        w.y = extract<T>(t[1]);
+        w.z = extract<T>(t[2]);
+        
+        return (v != w);
+    }
+    else
+        throw std::invalid_argument ("tuple of length 3 expected");    
+}
+
+
+
+// Trick to register methods for float-only-based vectors
+template <class T, IMATH_ENABLE_IF(!std::is_integral<T>::value)>
+void register_Vec3_floatonly(class_<Vec3<T>>& vec3_class)
+{
+   vec3_class
+        .def("length", &Vec3_length<T>,"length() magnitude of the vector")
+        .def("normalize", &Vec3_normalize<T>,return_internal_reference<>(),
+             "v.normalize() destructively normalizes v and returns a reference to it")
+        .def("normalizeExc", &Vec3_normalizeExc<T>,return_internal_reference<>(),
+             "v.normalizeExc() destructively normalizes V and returns a reference to it, throwing an exception if length() == 0")
+        .def("normalizeNonNull", &Vec3_normalizeNonNull<T>,return_internal_reference<>(),
+             "v.normalizeNonNull() destructively normalizes V and returns a reference to it, faster if lngth() != 0")
+        .def("normalized", &Vec3_normalized<T>, "v.normalized() returns a normalized copy of v")
+        .def("normalizedExc", &Vec3_normalizedExc<T>, "v.normalizedExc() returns a normalized copy of v, throwing an exception if length() == 0")
+        .def("normalizedNonNull", &Vec3_normalizedNonNull<T>, "v.normalizedNonNull() returns a normalized copy of v, faster if lngth() != 0")
+        .def("orthogonal", &orthogonal<T>)
+        .def("project", &project<T>)
+        .def("reflect", &reflect<T>)
+        ;
+}
+
+template <class T, IMATH_ENABLE_IF(std::is_integral<T>::value)>
+void register_Vec3_floatonly(class_<Vec3<T>>& vec2_class)
+{
+}
+
+
+
+template <class T>
+class_<Vec3<T> >
+register_Vec3()
+{
+    typedef PyImath::StaticFixedArray<Vec3<T>,T,3> Vec3_helper;
+
+    class_<Vec3<T> > vec3_class(Vec3Name<T>::value(), Vec3Name<T>::value(),init<Vec3<T> >("copy construction"));
+    vec3_class
+        .def("__init__",make_constructor(Vec3_construct_default<T>),"initialize to (0,0,0)")
+        .def("__init__",make_constructor(Vec3_object_constructor1<T>))
+        .def("__init__",make_constructor(Vec3_object_constructor2<T>))
+        .def_readwrite("x", &Vec3<T>::x)
+        .def_readwrite("y", &Vec3<T>::y)
+        .def_readwrite("z", &Vec3<T>::z)
+       .def("baseTypeEpsilon", &Vec3<T>::baseTypeEpsilon,"baseTypeEpsilon() epsilon value of the base type of the vector")
+        .staticmethod("baseTypeEpsilon")
+       .def("baseTypeMax", &Vec3<T>::baseTypeMax,"baseTypeMax() max value of the base type of the vector")
+        .staticmethod("baseTypeMax")
+       .def("baseTypeLowest", &Vec3<T>::baseTypeLowest,"baseTypeLowest() largest negative value of the base type of the vector")
+        .staticmethod("baseTypeLowest")
+       .def("baseTypeSmallest", &Vec3<T>::baseTypeSmallest,"baseTypeSmallest() smallest value of the base type of the vector")
+        .staticmethod("baseTypeSmallest")
+       .def("cross", &Vec3_cross<T>,"v1.cross(v2) right handed cross product")
+       .def("cross", &Vec3_cross_Vec3Array<T>,"v1.cross(v2) right handed array cross product")
+       .def("dimensions", &Vec3<T>::dimensions,"dimensions() number of dimensions in the vector")
+        .staticmethod("dimensions")
+       .def("dot", &Vec3_dot<T>,"v1.dot(v2) inner product of the two vectors")
+       .def("dot", &Vec3_dot_Vec3Array<T>,"v1.dot(v2) array inner product")
+    
+       .def("equalWithAbsError", &Vec3<T>::equalWithAbsError,
+         "v1.equalWithAbsError(v2) true if the elements "
+         "of v1 and v2 are the same with an absolute error of no more than e, "
+         "i.e., abs(v1[i] - v2[i]) <= e")
+        .def("equalWithAbsError", &equalWithAbsErrorObj<T>)
+             
+       .def("equalWithRelError", &Vec3<T>::equalWithRelError,
+         "v1.equalWithAbsError(v2) true if the elements "
+         "of v1 and v2 are the same with an absolute error of no more than e, "
+         "i.e., abs(v1[i] - v2[i]) <= e * abs(v1[i])")
+        .def("equalWithRelError", &equalWithRelErrorObj<T>)
+         
+       .def("length2", &Vec3_length2<T>,"length2() square magnitude of the vector")
+       .def("__len__", Vec3_helper::len)
+       .def("__getitem__", Vec3_helper::getitem,return_value_policy<copy_non_const_reference>())
+       .def("__setitem__", Vec3_helper::setitem)
+        .def("closestVertex", &closestVertex<T>)
+        .def("negate", &Vec3_negate<T>, return_internal_reference<>())
+        .def("setValue", &setValue<T>)    
+        .def("__neg__", &Vec3_neg<T>)
+        .def("__mul__", &Vec3_mul<T, int>)
+        .def("__mul__", &Vec3_mul<T, float>)
+        .def("__mul__", &Vec3_mul<T, double>)
+        .def("__mul__", &Vec3_mulT<T>)
+        .def("__mul__", &Vec3_mulTArray<T>)
+        .def("__rmul__", &Vec3_rmulT<T>)
+        .def("__rmul__", &Vec3_rmulTArray<T>)
+        .def("__imul__", &Vec3_imulV<T, int>,return_internal_reference<>())
+        .def("__imul__", &Vec3_imulV<T, float>,return_internal_reference<>())
+        .def("__imul__", &Vec3_imulV<T, double>,return_internal_reference<>())
+        .def("__imul__", &Vec3_imulT<T>,return_internal_reference<>())
+        .def("__div__", &Vec3_Vec3_divT<T>)
+        .def("__truediv__", &Vec3_Vec3_divT<T>)
+        .def("__mul__", &Vec3_mulM33<T, float>)
+        .def("__mul__", &Vec3_mulM33<T, double>)
+        .def("__mul__", &Vec3_mulM44<T, float>)
+        .def("__mul__", &Vec3_mulM44<T, double>)
+        .def("__mul__", &Vec3_Vec3_mulT<T>)
+        .def("__div__", &Vec3_div<T,int>)
+        .def("__div__", &Vec3_div<T,float>)
+        .def("__div__", &Vec3_div<T,double>)
+        .def("__div__", &Vec3_divTuple<T,tuple>)
+        .def("__div__", &Vec3_divTuple<T,list>)
+        .def("__div__", &Vec3_divT<T>)
+        .def("__truediv__", &Vec3_div<T,int>)
+        .def("__truediv__", &Vec3_div<T,float>)
+        .def("__truediv__", &Vec3_div<T,double>)
+        .def("__truediv__", &Vec3_divTuple<T,tuple>)
+        .def("__truediv__", &Vec3_divTuple<T,list>)
+        .def("__truediv__", &Vec3_divT<T>)
+        .def("__rdiv__", &Vec3_rdivTuple<T,tuple>)
+        .def("__rdiv__", &Vec3_rdivTuple<T,list>)
+        .def("__rdiv__", &Vec3_rdivT<T>)
+        .def("__rtruediv__", &Vec3_rdivTuple<T,tuple>)
+        .def("__rtruediv__", &Vec3_rdivTuple<T,list>)
+        .def("__rtruediv__", &Vec3_rdivT<T>)
+        .def("__idiv__", &Vec3_idivObj<T>,return_internal_reference<>())
+        .def("__itruediv__", &Vec3_idivObj<T>,return_internal_reference<>())
+        .def("__xor__", &Vec3_dot<T>)
+        .def("__mod__", &Vec3_cross<T>)
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__add__", &Vec3_add<T>)
+        .def("__add__", &Vec3_addV<T, int>)
+        .def("__add__", &Vec3_addV<T, float>)
+        .def("__add__", &Vec3_addV<T, double>)
+        .def("__add__", &Vec3_addT<T>)
+        .def("__add__", &Vec3_addTuple<T,tuple>)
+        .def("__add__", &Vec3_addTuple<T,list>)
+        .def("__radd__", &Vec3_addT<T>)
+        .def("__radd__", &Vec3_addTuple<T,tuple>)
+        .def("__radd__", &Vec3_addTuple<T,list>)
+        .def("__radd__", &Vec3_add<T>)
+        .def("__iadd__", &Vec3_iaddV<T, int>, return_internal_reference<>())
+        .def("__iadd__", &Vec3_iaddV<T, float>, return_internal_reference<>())
+        .def("__iadd__", &Vec3_iaddV<T, double>, return_internal_reference<>())
+        .def("__sub__", &Vec3_sub<T>)
+        .def("__sub__", &Vec3_subV<T, int>)
+        .def("__sub__", &Vec3_subV<T, float>)
+        .def("__sub__", &Vec3_subV<T, double>)
+        .def("__sub__", &Vec3_subT<T>)
+        .def("__sub__", &Vec3_subTuple<T,tuple>)
+        .def("__sub__", &Vec3_subTuple<T,list>)
+        .def("__rsub__", &Vec3_rsubT<T>)
+        .def("__rsub__", &Vec3_rsubTuple<T,tuple>)
+        .def("__rsub__", &Vec3_rsubTuple<T,list>)
+        .def("__isub__", &Vec3_isubV<T, int>, return_internal_reference<>())
+        .def("__isub__", &Vec3_isubV<T, float>, return_internal_reference<>())
+        .def("__isub__", &Vec3_isubV<T, double>, return_internal_reference<>())
+        .def("__mul__", &mult<T>)
+        .def("__rmul__", &mult<T>)
+        .def("__imul__", &Vec3_imulM44<T, float>, return_internal_reference<>())
+        .def("__imul__", &Vec3_imulM44<T, double>, return_internal_reference<>())
+        .def("__lt__", &lessThan<T>)
+        .def("__gt__", &greaterThan<T>)
+        .def("__le__", &lessThanEqual<T>)
+        .def("__ge__", &greaterThanEqual<T>)
+        .def("__eq__", &equal<T>)
+        .def("__ne__", &notequal<T>)
+       //.def(self_ns::str(self))
+       .def("__str__",&Vec3_str<T>)
+       .def("__repr__",&Vec3_repr<T>)
+        ;
+
+    register_Vec3_floatonly<T>(vec3_class);
+
+    decoratecopy(vec3_class);
+
+    //add_swizzle3_operators(v3f_class);
+    return vec3_class;
+}
+
+
+
+}  // namespace PyImath
+
+#endif    // _PyImathVec3Impl_h_
diff --git a/src/python/PyImath/PyImathVec3fd.cpp b/src/python/PyImath/PyImathVec3fd.cpp
new file mode 100644 (file)
index 0000000..33a6ada
--- /dev/null
@@ -0,0 +1,46 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathVec3Impl.h"
+#include "PyImathVec3ArrayImpl.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+template <> const char *PyImath::V3fArray::name() { return "V3fArray"; }
+template <> const char *PyImath::V3dArray::name() { return "V3dArray"; }
+
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template<> const char *Vec3Name<float>::value() { return "V3f"; }
+template<> const char *Vec3Name<double>::value() { return "V3d"; }
+
+// Specialization for float to full precision
+template <>
+std::string Vec3_repr(const Vec3<float> &v)
+{
+    return (boost::format("%s(%.9g, %.9g, %.9g)")
+                        % Vec3Name<float>::value() % v.x % v.y % v.z).str();
+}
+
+// Specialization for double to full precision
+template <>
+std::string Vec3_repr(const Vec3<double> &v)
+{
+    return (boost::format("%s(%.17g, %.17g, %.17g)")
+                        % Vec3Name<double>::value() % v.x % v.y % v.z).str();
+}
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec3<float> > register_Vec3<float>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec3<double> > register_Vec3<double>();
+                
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec3<float> > > register_Vec3Array<float>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec3<double> > > register_Vec3Array<double>();
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec3<float> PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Vec3<float> >::value() { return IMATH_NAMESPACE::Vec3<float>(0,0,0); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec3<double> PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Vec3<double> >::value() { return IMATH_NAMESPACE::Vec3<double>(0,0,0); }
+}
diff --git a/src/python/PyImath/PyImathVec3si.cpp b/src/python/PyImath/PyImathVec3si.cpp
new file mode 100644 (file)
index 0000000..517b4ae
--- /dev/null
@@ -0,0 +1,31 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathVec3Impl.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+template <> const char *PyImath::V3cArray::name()   { return "V3cArray"; }
+template <> const char *PyImath::V3sArray::name()   { return "V3sArray"; }
+template <> const char *PyImath::V3iArray::name()   { return "V3iArray"; }
+template <> const char *PyImath::V3i64Array::name() { return "V3i64Array"; }
+
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template<> const char *Vec3Name<unsigned char>::value() { return "V3c"; }
+template<> const char *Vec3Name<short>::value()         { return "V3s"; }
+template<> const char *Vec3Name<int>::value()           { return "V3i"; }
+template<> const char *Vec3Name<int64_t>::value()       { return "V3i64"; }
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec3<unsigned char> > register_Vec3<unsigned char>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec3<short> >         register_Vec3<short>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec3<int> >           register_Vec3<int>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec3<int64_t> >       register_Vec3<int64_t>();
+
+}
+
diff --git a/src/python/PyImath/PyImathVec3siArray.cpp b/src/python/PyImath/PyImathVec3siArray.cpp
new file mode 100644 (file)
index 0000000..33ec25f
--- /dev/null
@@ -0,0 +1,24 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathVec3ArrayImpl.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec3<unsigned char> > > register_Vec3Array<unsigned char>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec3<short> > > register_Vec3Array<short>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec3<int> > > register_Vec3Array<int>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec3<int64_t> > > register_Vec3Array<int64_t>();
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec3<unsigned char> PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Vec3<unsigned char> >::value() { return IMATH_NAMESPACE::Vec3<unsigned char>(0,0,0); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec3<short>         PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Vec3<short> >::value() { return IMATH_NAMESPACE::Vec3<short>(0,0,0); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec3<int>           PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Vec3<int> >::value() { return IMATH_NAMESPACE::Vec3<int>(0,0,0); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec3<int64_t>       PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Vec3<int64_t> >::value() { return IMATH_NAMESPACE::Vec3<int64_t>(0,0,0); }
+}
diff --git a/src/python/PyImath/PyImathVec4ArrayImpl.h b/src/python/PyImath/PyImathVec4ArrayImpl.h
new file mode 100644 (file)
index 0000000..5cd861b
--- /dev/null
@@ -0,0 +1,165 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathVec4ArrayImpl_h_
+#define _PyImathVec4ArrayImpl_h_
+
+//
+// This .C file was turned into a header file so that instantiations
+// of the various V4* types can be spread across multiple files in
+// order to work around MSVC limitations.
+//
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <ImathVec.h>
+#include <ImathVecAlgo.h>
+#include "PyImath.h"
+#include "PyImathVec.h"
+#include "PyImathDecorators.h"
+#include "PyImathMathExc.h"
+#include "PyImathOperators.h"
+#include "PyImathVecOperators.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+// XXX fixme - template this
+// really this should get generated automatically...
+
+template <class T,int index>
+static FixedArray<T>
+Vec4Array_get(FixedArray<IMATH_NAMESPACE::Vec4<T> > &va)
+{
+    return FixedArray<T>(&(va.unchecked_index(0)[index]),
+                         va.len(), 4*va.stride(), va.handle(), va.writable());
+}
+
+template <class T>
+static void
+setItemTuple(FixedArray<IMATH_NAMESPACE::Vec4<T> > &va, Py_ssize_t index, const tuple &t)
+{
+    if(t.attr("__len__")() == 4)
+    {
+        Vec4<T> v;
+        v.x = extract<T>(t[0]);
+        v.y = extract<T>(t[1]);
+        v.z = extract<T>(t[2]);
+        v.w = extract<T>(t[3]);
+
+        va[va.canonical_index(index)] = v;
+    }
+    else
+      throw std::invalid_argument ("tuple of length 4 expected");
+}
+
+template <class T>
+static IMATH_NAMESPACE::Vec4<T>
+Vec4Array_min(const FixedArray<IMATH_NAMESPACE::Vec4<T> > &a) {
+    Vec4<T> tmp(Vec4<T>(0));
+    size_t len = a.len();
+    if (len > 0)
+        tmp = a[0];
+    for (size_t i=1; i < len; ++i)
+    {
+        if (a[i].x < tmp.x)
+            tmp.x = a[i].x;
+        if (a[i].y < tmp.y)
+            tmp.y = a[i].y;
+        if (a[i].z < tmp.z)
+            tmp.z = a[i].z;
+        if (a[i].w < tmp.w)
+            tmp.w = a[i].w;
+    }
+    return tmp;
+}
+
+template <class T>
+static IMATH_NAMESPACE::Vec4<T>
+Vec4Array_max(const FixedArray<IMATH_NAMESPACE::Vec4<T> > &a)
+{
+    Vec4<T> tmp(Vec4<T>(0));
+    size_t len = a.len();
+    if (len > 0)
+        tmp = a[0];
+    for (size_t i=1; i < len; ++i)
+    {
+        if (a[i].x > tmp.x)
+            tmp.x = a[i].x;
+        if (a[i].y > tmp.y)
+            tmp.y = a[i].y;
+        if (a[i].z > tmp.z)
+            tmp.z = a[i].z;
+        if (a[i].w > tmp.w)
+            tmp.w = a[i].w;
+    }
+    return tmp;
+}
+
+
+// Trick to register methods for float-only-based vectors
+template <class T, IMATH_ENABLE_IF(!std::is_integral<T>::value)>
+void register_Vec4Array_floatonly(class_<FixedArray<Vec4<T>>>& vec4Array_class)
+{
+    generate_member_bindings<op_vecLength<IMATH_NAMESPACE::Vec4<T> >     >(vec4Array_class,"length","");
+    generate_member_bindings<op_vecNormalize<IMATH_NAMESPACE::Vec4<T> >  >(vec4Array_class,"normalize","");
+    generate_member_bindings<op_vecNormalized<IMATH_NAMESPACE::Vec4<T> > >(vec4Array_class,"normalized","");
+    generate_member_bindings<op_vecNormalizeExc<IMATH_NAMESPACE::Vec4<T> >  >(vec4Array_class,"normalizeExc","");
+    generate_member_bindings<op_vecNormalizedExc<IMATH_NAMESPACE::Vec4<T> > >(vec4Array_class,"normalizedExc","");
+}
+
+template <class T, IMATH_ENABLE_IF(std::is_integral<T>::value)>
+void register_Vec4Array_floatonly(class_<FixedArray<Vec4<T>>>& vec4Array_class)
+{
+}
+
+
+
+template <class T>
+class_<FixedArray<IMATH_NAMESPACE::Vec4<T> > >
+register_Vec4Array()
+{
+    using boost::mpl::true_;
+
+    class_<FixedArray<IMATH_NAMESPACE::Vec4<T> > > vec4Array_class = FixedArray<IMATH_NAMESPACE::Vec4<T> >::register_("Fixed length array of IMATH_NAMESPACE::Vec4");
+    vec4Array_class
+        .add_property("x",&Vec4Array_get<T,0>)
+        .add_property("y",&Vec4Array_get<T,1>)
+        .add_property("z",&Vec4Array_get<T,2>)
+        .add_property("w",&Vec4Array_get<T,3>)
+        .def("__setitem__", &setItemTuple<T>)
+        .def("min", &Vec4Array_min<T>)
+        .def("max", &Vec4Array_max<T>)
+        ;
+
+    add_arithmetic_math_functions(vec4Array_class);
+    add_comparison_functions(vec4Array_class);
+
+    register_Vec4Array_floatonly(vec4Array_class);
+    generate_member_bindings<op_vecLength2<IMATH_NAMESPACE::Vec4<T> >    >(vec4Array_class,"length2","");
+    generate_member_bindings<op_vecDot<IMATH_NAMESPACE::Vec4<T> >,true_>(vec4Array_class,"dot","return the inner product of (self,x)",boost::python::args("x"));
+    generate_member_bindings<op_mul<IMATH_NAMESPACE::Vec4<T>,T>,  true_>(vec4Array_class,"__mul__" ,"self*x", boost::python::args("x"));
+    generate_member_bindings<op_mul<IMATH_NAMESPACE::Vec4<T>,T>,  true_>(vec4Array_class,"__rmul__","x*self", boost::python::args("x"));
+    generate_member_bindings<op_imul<IMATH_NAMESPACE::Vec4<T>,T>, true_>(vec4Array_class,"__imul__","self*=x",boost::python::args("x"));
+    generate_member_bindings<op_div<IMATH_NAMESPACE::Vec4<T>,T>,  true_>(vec4Array_class,"__div__" ,"self/x", boost::python::args("x"));
+    generate_member_bindings<op_div<IMATH_NAMESPACE::Vec4<T>,T>,  true_>(vec4Array_class,"__truediv__" ,"self/x", boost::python::args("x"));
+    generate_member_bindings<op_idiv<IMATH_NAMESPACE::Vec4<T>,T>, true_>(vec4Array_class,"__idiv__","self/=x",boost::python::args("x"));
+    generate_member_bindings<op_idiv<IMATH_NAMESPACE::Vec4<T>,T>, true_>(vec4Array_class,"__itruediv__","self/=x",boost::python::args("x"));
+
+    decoratecopy(vec4Array_class);
+
+    return vec4Array_class;
+}
+
+
+}  // namespace PyImath
+
+#endif   // _PyImathVec4ArrayImpl_h_
diff --git a/src/python/PyImath/PyImathVec4Impl.h b/src/python/PyImath/PyImathVec4Impl.h
new file mode 100644 (file)
index 0000000..aea9b79
--- /dev/null
@@ -0,0 +1,1021 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathVec3Impl_h_
+#define _PyImathVec3Impl_h_
+
+//
+// This .C file was turned into a header file so that instantiations
+// of the various V3* types can be spread across multiple files in
+// order to work around MSVC limitations.
+//
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <ImathVec.h>
+#include <ImathVecAlgo.h>
+#include "PyImath.h"
+#include "PyImathVec.h"
+#include "PyImathDecorators.h"
+#include "PyImathMathExc.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template <class T> struct Vec4Name      { static const char *value(); };
+
+// create a new default constructor that initializes Vec3<T> to zero.
+template <class T>
+static Vec4<T> * Vec4_construct_default()
+{
+    return new Vec4<T>(T(0),T(0),T(0),T(0));
+}
+
+template <class T>
+static Vec4<T> * Vec4_object_constructor1(const object &obj)
+{
+    Vec4<T> res;
+    extract<Vec4<int> >     e1(obj);
+    extract<Vec4<float> >   e2(obj);
+    extract<Vec4<double> >  e3(obj);
+    extract<tuple>          e4(obj);
+    extract<double>         e5(obj);
+    extract<list>           e6(obj);
+    
+    if(e1.check())      { res = e1(); }
+    else if(e2.check()) { res = e2(); }
+    else if(e3.check()) { res = e3(); }
+    else if(e4.check())
+    {
+        tuple t = e4();
+        if(t.attr("__len__")() == 4)
+        {
+            res.x = extract<T>(t[0]);
+            res.y = extract<T>(t[1]);
+            res.z = extract<T>(t[2]);
+            res.w = extract<T>(t[3]);
+        }
+        else
+            throw std::invalid_argument ("tuple must have length of 4");
+        
+    }
+    else if(e5.check()) { T a = (T) e5(); res = IMATH_NAMESPACE::Vec4<T>(a, a, a, a); }
+    else if(e6.check())
+    {
+        list l = e6();
+        if(l.attr("__len__")() == 4)
+        {
+            res.x = extract<T>(l[0]);
+            res.y = extract<T>(l[1]);
+            res.z = extract<T>(l[2]);
+            res.w = extract<T>(l[3]);
+        }
+        else
+            throw std::invalid_argument ("list must have length of 4");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to Vec4 constructor");
+    
+    Vec4<T> *v = new Vec4<T>;
+    *v = res;
+    
+    return v;
+
+}
+
+template <class T>
+static Vec4<T> * Vec4_object_constructor2(const object &obj1, const object &obj2, const object &obj3, const object& obj4)
+{
+    extract<double>    e1(obj1);
+    extract<double>    e2(obj2);
+    extract<double>    e3(obj3);
+    extract<double>    e4(obj4);
+    Vec4<T> *v = new Vec4<T>;
+    
+    if(e1.check()) { v->x = (T) e1();}
+    else { throw std::invalid_argument ("invalid parameters passed to Vec4 constructor"); }
+    
+    if(e2.check()) { v->y = (T) e2();}
+    else { throw std::invalid_argument ("invalid parameters passed to Vec4 constructor"); }    
+
+    if(e3.check()) { v->z = (T) e3();}
+    else { throw std::invalid_argument ("invalid parameters passed to Vec4 constructor"); } 
+
+    if(e4.check()) { v->w = (T) e4();}
+    else { throw std::invalid_argument ("invalid parameters passed to Vec4 constructor"); } 
+    
+    return v;
+}
+
+
+
+// Implementations of str and repr are same here,
+// but we'll specialize repr for float and double to make them exact.
+template <class T>
+static std::string Vec4_str(const Vec4<T> &v)
+{
+    std::stringstream stream;
+    stream << Vec4Name<T>::value() << "(" << v.x << ", " << v.y << ", " << v.z << ", " << v.w << ")";
+    return stream.str();
+}
+template <class T>
+static std::string Vec4_repr(const Vec4<T> &v)
+{
+    std::stringstream stream;
+    stream << Vec4Name<T>::value() << "(" << v.x << ", " << v.y << ", " << v.z << ", " << v.w << ")";
+    return stream.str();
+}
+
+template <class T>
+static T
+Vec4_dot(const IMATH_NAMESPACE::Vec4<T> &v, const IMATH_NAMESPACE::Vec4<T> &other) 
+{ 
+    MATH_EXC_ON;
+    return v.dot(other);
+}
+
+template <class T>
+static FixedArray<T>
+Vec4_dot_Vec4Array(const IMATH_NAMESPACE::Vec4<T> &va, const FixedArray<IMATH_NAMESPACE::Vec4<T> > &vb) 
+{ 
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = vb.len(); 
+    FixedArray<T> f(len); 
+    for (size_t i = 0; i < len; ++i) 
+        f[i] = va.dot(vb[i]); 
+    return f; 
+}
+
+template <class T>
+static T
+Vec4_length(const IMATH_NAMESPACE::Vec4<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.length();
+}
+
+template <class T>
+static T
+Vec4_length2(const IMATH_NAMESPACE::Vec4<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.length2();
+}
+
+template <class T>
+static const Vec4<T> &
+Vec4_normalize(IMATH_NAMESPACE::Vec4<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalize();
+}
+
+template <class T>
+static const Vec4<T> &
+Vec4_normalizeExc(IMATH_NAMESPACE::Vec4<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizeExc();
+}
+
+template <class T>
+static const Vec4<T> &
+Vec4_normalizeNonNull(IMATH_NAMESPACE::Vec4<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizeNonNull();
+}
+
+template <class T>
+static Vec4<T>
+Vec4_normalized(const IMATH_NAMESPACE::Vec4<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalized();
+}
+
+template <class T>
+static Vec4<T>
+Vec4_normalizedExc(const IMATH_NAMESPACE::Vec4<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizedExc();
+}
+
+template <class T>
+static Vec4<T>
+Vec4_normalizedNonNull(const IMATH_NAMESPACE::Vec4<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.normalizedNonNull();
+}
+
+template <class T>
+static const Vec4<T> &
+Vec4_negate(IMATH_NAMESPACE::Vec4<T> &v) 
+{ 
+    MATH_EXC_ON;
+    return v.negate();
+}
+
+template <class T>
+static Vec4<T>
+orthogonal(const Vec4<T> &v, const Vec4<T> &v0)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::orthogonal(v, v0);
+}
+
+template <class T>
+static Vec4<T>
+project(const Vec4<T> &v, const Vec4<T> &v0)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::project(v0, v);
+}
+
+template <class T>
+static Vec4<T>
+reflect(const Vec4<T> &v, const Vec4<T> &v0)
+{
+    MATH_EXC_ON;
+    return IMATH_NAMESPACE::reflect(v, v0);
+}
+
+template <class T>
+static void
+setValue(Vec4<T> &v, T a, T b, T c, T d)
+{
+    v.x = a;
+    v.y = b;
+    v.z = c;
+    v.w = d;
+}
+
+template <class T>
+static Vec4<T>
+Vec4_add (const Vec4<T> &v, const Vec4<T> &w)
+{
+    MATH_EXC_ON;
+    return v + w;
+}
+
+template <class T>
+static Vec4<T>
+Vec4_sub (const Vec4<T> &v, const Vec4<T> &w)
+{
+    MATH_EXC_ON;
+    return v - w;
+}
+
+template <class T>
+static Vec4<T>
+Vec4_neg (const Vec4<T> &v)
+{
+    MATH_EXC_ON;
+    return -v;
+}
+
+template <class T, class U>
+static Vec4<T>
+Vec4_mul (const Vec4<T> &v, Vec4<U> &w)
+{
+    MATH_EXC_ON;
+    Vec4<T> w2 (w);
+    return v * w2;
+}
+
+template <class T>
+static Vec4<T>
+Vec4_mulT (const Vec4<T> &v, T t)
+{
+    MATH_EXC_ON;
+    return v * t;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Vec4<T> >
+Vec4_mulTArray (const Vec4<T> &v, const FixedArray<T> &t)
+{
+    PY_IMATH_LEAVE_PYTHON;
+    size_t len = t.len();
+    FixedArray<IMATH_NAMESPACE::Vec4<T> > retval(len);
+    for (size_t i=0; i<len; ++i) retval[i] = v*t[i];
+    return retval;
+}
+
+template <class T>
+static FixedArray<IMATH_NAMESPACE::Vec4<T> >
+Vec4_rmulTArray (const Vec4<T> &v, const FixedArray<T> &t)
+{
+    return Vec4_mulTArray(v,t);
+}
+
+template <class T,class S>
+static Vec4<T>
+Vec4_div (Vec4<T> &v, Vec4<S> &w)
+{
+    MATH_EXC_ON;
+    return v / w;
+}
+
+template <class T>
+static Vec4<T>
+Vec4_rmulT (Vec4<T> &v, T t)
+{
+    MATH_EXC_ON;
+    return t * v;
+}
+
+template <class T, class U>
+static const Vec4<T> &
+Vec4_imulV(Vec4<T> &v, const Vec4<U> &w)
+{
+    MATH_EXC_ON;
+    return v *= w;
+}
+
+template <class T>
+static const Vec4<T> &
+Vec4_imulT(IMATH_NAMESPACE::Vec4<T> &v, T t) 
+{ 
+    MATH_EXC_ON;
+    return v *= t;
+}
+
+template <class T, class U>
+static Vec4<T>
+Vec4_mulM44 (Vec4<T> &v, const Matrix44<U> &m)
+{
+    MATH_EXC_ON;
+    return v * m;
+}
+
+template <class T>
+static const Vec4<T> &
+Vec4_idivObj(IMATH_NAMESPACE::Vec4<T> &v, const object &o) 
+{ 
+    MATH_EXC_ON;
+    Vec4<T> v2;
+    if (PyImath::V4<T>::convert (o.ptr(), &v2))
+    {
+        return v /= v2;
+    }
+    else
+    {
+        extract<double> e(o);
+        if (e.check())
+            return v /= (T) e();
+        else
+            throw std::invalid_argument ("V4 division expects an argument "
+                   "convertible to a V4");
+    }
+}
+
+template <class T>
+static Vec4<T>
+Vec4_subT(const Vec4<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec4<T> w;
+    setValue(w, (T) (v.x - a), (T) (v.y - a), (T) (v.z - a), (T) (v.w - a));
+    return w;
+}
+
+template <class T,class BoostPyType>
+static Vec4<T>
+Vec4_subTuple(const Vec4<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec4<T> w;
+    
+    if(t.attr("__len__")() == 4)
+    {
+        w.x = v.x - extract<T>(t[0]);
+        w.y = v.y - extract<T>(t[1]);
+        w.z = v.z - extract<T>(t[2]);
+        w.w = v.w - extract<T>(t[3]);
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 4");
+    
+    return w;
+}
+
+template <class T>
+static Vec4<T>
+Vec4_rsubT(const Vec4<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec4<T> w(a - v.x, a - v.y, a - v.z, a - v.w);
+    return w;
+}
+
+template <class T, class BoostPyType>
+static Vec4<T>
+Vec4_rsubTuple(const Vec4<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec4<T> w;
+    
+    if(t.attr("__len__")() == 4)
+    {
+        w.x = extract<T>(t[0]) - v.x;
+        w.y = extract<T>(t[1]) - v.y;
+        w.z = extract<T>(t[2]) - v.z;
+        w.w = extract<T>(t[3]) - v.w;
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 4");
+    
+    return w;
+}
+
+template <class T, class BoostPyType>
+static Vec4<T>
+Vec4_addTuple(const Vec4<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec4<T> w;
+    
+    if(t.attr("__len__")() == 4)
+    {
+        w.x = v.x + extract<T>(t[0]);
+        w.y = v.y + extract<T>(t[1]);
+        w.z = v.z + extract<T>(t[2]);
+        w.w = v.w + extract<T>(t[3]);
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 4");
+    
+    return w;
+}
+
+template <class T>
+static Vec4<T>
+Vec4_addT(const Vec4<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec4<T> w;
+    setValue(w, (T) (v.x + a), (T) (v.y + a), (T) (v.z + a), (T) (v.w + a));
+    return w;
+}
+
+template <class T, class U>
+static Vec4<T>
+Vec4_addV(const Vec4<T> &v, const Vec4<U> &w)
+{
+    MATH_EXC_ON;
+    return v + w;
+}
+
+template <class T, class U>
+static const Vec4<T> &
+Vec4_iaddV(Vec4<T> &v, const Vec4<U> &w)
+{
+    MATH_EXC_ON;
+    return v += w;
+}
+
+template <class T, class U>
+static Vec4<T>
+Vec4_subV(const Vec4<T> &v, const Vec4<U> &w)
+{
+    MATH_EXC_ON;
+    return v - w;
+}
+
+template <class T, class U>
+static const Vec4<T> &
+Vec4_isubV(Vec4<T> &v, const Vec4<U> &w)
+{
+    MATH_EXC_ON;
+    return v -= w;
+}
+
+template <class T>
+static Vec4<T>
+mult(const Vec4<T> &v, tuple t)
+{
+    MATH_EXC_ON;
+    Vec4<T> w;
+    
+    if(t.attr("__len__")() == 1){
+        w.x = v.x*extract<T>(t[0]);
+        w.y = v.y*extract<T>(t[0]);
+        w.z = v.z*extract<T>(t[0]);
+        w.w = v.w*extract<T>(t[0]);
+    }        
+    else if(t.attr("__len__")() == 4){
+        w.x = v.x*extract<T>(t[0]);
+        w.y = v.y*extract<T>(t[1]);
+        w.z = v.z*extract<T>(t[2]);
+        w.w = v.w*extract<T>(t[3]);
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 1 or 4");
+    
+    return w;
+}
+
+template <class T, class U>
+static const Vec4<T> &
+Vec4_imulM44 (Vec4<T> &v, const Matrix44<U> &m)
+{
+    MATH_EXC_ON;
+    return v *= m;
+}
+
+template <class T, class BoostPyType>
+static Vec4<T>
+Vec4_divTuple(const Vec4<T> &v, const BoostPyType &t)
+{
+    if(t.attr("__len__")() == 4)
+    {
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+        T w = extract<T>(t[3]);
+        if(x != T(0) && y != T(0) && z != T(0) && w != T(0))
+            return Vec4<T>(v.x / x, v.y / y, v.z / z, v.w / w);
+        else
+            throw std::domain_error ("Division by zero");
+    }
+    else
+        throw std::invalid_argument ("Vec4 expects tuple of length 4");
+}
+
+template <class T, class BoostPyType>
+static Vec4<T>
+Vec4_rdivTuple(const Vec4<T> &v, const BoostPyType &t)
+{
+    MATH_EXC_ON;
+    Vec4<T> res;
+    if(t.attr("__len__")() == 4)
+    {
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+        T w = extract<T>(t[3]);
+            
+        if(v.x != T(0) && v.y != T(0) && v.z != T(0) && v.w != T(0)){
+            setValue(res, (T) (x / v.x), (T) (y / v.y), (T) (z / v.z), (T) (w / v.w));
+        }
+        else
+            throw std::domain_error ("Division by zero");
+    }
+    else
+        throw std::invalid_argument ("tuple must have length of 4");
+    
+    return res;
+}
+
+template <class T>
+static Vec4<T>
+Vec4_divT(const Vec4<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec4<T> res;
+    if(a != T(0)){
+        setValue(res, (T) (v.x / a), (T) (v.y / a), (T) (v.z / a), (T) (v.w / a));
+    }
+    else
+        throw std::domain_error ("Division by zero");
+
+    return res;
+}
+
+template <class T>
+static Vec4<T>
+Vec4_rdivT(const Vec4<T> &v, T a)
+{
+    MATH_EXC_ON;
+    Vec4<T> res;
+    if(v.x != T(0) && v.y != T(0) && v.z != T(0) && v.w != T(0)){
+        setValue(res, (T) (a / v.x), (T) (a / v.y), (T) (a / v.z), (T) (a / v.w));
+    }
+    else
+        throw std::domain_error ("Division by zero");
+
+    return res;
+}
+
+template <class T>
+static Vec4<T>
+Vec4_Vec4_mulT(const Vec4<T>& v, const Vec4<T>& w)
+{
+    MATH_EXC_ON;
+    return v*w;
+}
+
+template <class T>
+static Vec4<T>
+Vec4_Vec4_divT(const Vec4<T>& v, const Vec4<T>& w)
+{
+    MATH_EXC_ON;
+    return v/w;
+}
+
+template <class T>
+static bool
+lessThan(const Vec4<T> &v, const object &obj)
+{
+    extract<Vec4<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec4<T> res;
+    if(e1.check())
+    {
+        res = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+        T w = extract<T>(t[3]);
+        setValue(res,x,y,z,w);
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator <");
+    
+    bool isLessThan = (v.x <= res.x && v.y <= res.y && v.z <= res.z && v.w <= res.w)
+                    && v != res;
+    
+    return isLessThan;
+}
+
+template <class T>
+static bool
+greaterThan(const Vec4<T> &v, const object &obj)
+{
+    extract<Vec4<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec4<T> res;
+    if(e1.check())
+    {
+        res = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+        T w = extract<T>(t[3]);
+        setValue(res,x,y,z,w);
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator >");
+    
+    bool isGreaterThan = (v.x >= res.x && v.y >= res.y && v.z >= res.z && v.w >= res.w)
+                       && v != res;
+
+    return isGreaterThan;
+}
+
+template <class T>
+static bool
+lessThanEqual(const Vec4<T> &v, const object &obj)
+{
+    extract<Vec4<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec4<T> res;
+    if(e1.check())
+    {
+        res = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+        T w = extract<T>(t[2]);
+        setValue(res,x,y,z,w);
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator <=");
+    
+    bool isLessThanEqual = (v.x <= res.x && v.y <= res.y && v.z <= res.z && v.w <= res.w);
+                   
+    return isLessThanEqual;
+}
+
+template <class T>
+static bool
+greaterThanEqual(const Vec4<T> &v, const object &obj)
+{
+    extract<Vec4<T> > e1(obj);
+    extract<tuple> e2(obj);
+    
+    Vec4<T> res;
+    if(e1.check())
+    {
+        res = e1();
+    }
+    else if(e2.check())
+    {
+        tuple t = e2();
+        T x = extract<T>(t[0]);
+        T y = extract<T>(t[1]);
+        T z = extract<T>(t[2]);
+        T w = extract<T>(t[3]);
+        setValue(res,x,y,z,w);
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to operator >=");
+    
+    bool isGreaterThanEqual = (v.x >= res.x && v.y >= res.y && v.z >= res.z && v.w >= res.w);
+
+    return isGreaterThanEqual;
+}
+
+
+template <class T>
+static bool
+equalWithAbsErrorObj(const Vec4<T> &v, const object &obj1, const object &obj2)
+{    
+    extract<Vec4<int> >    e1(obj1);
+    extract<Vec4<float> >  e2(obj1);
+    extract<Vec4<double> > e3(obj1);
+    
+    extract<tuple>         e4(obj1);
+    extract<double>        e5(obj2);
+    
+    Vec4<T> res;
+    if(e1.check())      { res = e1(); }
+    else if(e2.check()) { res = e2(); }
+    else if(e3.check()) { res = e3(); }
+    else if(e4.check())
+    {    
+        tuple t = e4();
+        if(t.attr("__len__")() == 4)
+        {
+            res.x = extract<T>(t[0]);
+            res.y = extract<T>(t[1]);
+            res.z = extract<T>(t[2]);
+            res.z = extract<T>(t[3]);
+        }
+        else
+            throw std::invalid_argument ("tuple of length 4 expected");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithAbsError");
+    
+    if(e5.check())      { return v.equalWithAbsError(res, (T) e5()); }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithAbsError");
+}
+
+template <class T>
+static bool
+equalWithRelErrorObj(const Vec4<T> &v, const object &obj1, const object &obj2)
+{    
+    extract<Vec4<int> >    e1(obj1);
+    extract<Vec4<float> >  e2(obj1);
+    extract<Vec4<double> > e3(obj1);
+    
+    extract<tuple>         e4(obj1);    
+    extract<double>        e5(obj2);
+    
+    Vec4<T> res;
+    if(e1.check())      { res = e1(); }
+    else if(e2.check()) { res = e2(); }
+    else if(e3.check()) { res = e3(); }
+    else if(e4.check())
+    {    
+        tuple t = e4();
+        if(t.attr("__len__")() == 4)
+        {
+            res.x = extract<T>(t[0]);
+            res.y = extract<T>(t[1]);
+            res.z = extract<T>(t[2]);
+            res.w = extract<T>(t[3]);
+        }
+        else
+            throw std::invalid_argument ("tuple of length 4 expected");
+    }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithRelError");
+    
+    if(e5.check())      { return v.equalWithRelError(res, (T) e5()); }
+    else
+        throw std::invalid_argument ("invalid parameters passed to equalWithRelError");    
+    
+}
+
+
+template <class T>
+static bool
+equal(const Vec4<T> &v, const tuple &t)
+{
+    Vec4<T> res;
+    if(t.attr("__len__")() == 4)
+    {
+        res.x = extract<T>(t[0]);
+        res.y = extract<T>(t[1]);
+        res.z = extract<T>(t[2]);
+        res.w = extract<T>(t[3]);
+        
+        return (v == res);
+    }
+    else
+        throw std::invalid_argument ("tuple of length 4 expected");    
+}
+
+template <class T>
+static bool
+notequal(const Vec4<T> &v, const tuple &t)
+{
+    Vec4<T> res;
+    if(t.attr("__len__")() == 4)
+    {
+        res.x = extract<T>(t[0]);
+        res.y = extract<T>(t[1]);
+        res.z = extract<T>(t[2]);
+        res.w = extract<T>(t[3]);
+        
+        return (v != res);
+    }
+    else
+        throw std::invalid_argument ("tuple of length 4 expected");    
+}
+
+// Trick to register methods for float-only-based vectors
+template <class T, IMATH_ENABLE_IF(!std::is_integral<T>::value)>
+void register_Vec4_floatonly(class_<Vec4<T>>& vec4_class)
+{
+   vec4_class
+        .def("length", &Vec4_length<T>,"length() magnitude of the vector")
+        .def("normalize", &Vec4_normalize<T>,return_internal_reference<>(),
+             "v.normalize() destructively normalizes v and returns a reference to it")
+        .def("normalizeExc", &Vec4_normalizeExc<T>,return_internal_reference<>(),
+             "v.normalizeExc() destructively normalizes V and returns a reference to it, throwing an exception if length() == 0")
+        .def("normalizeNonNull", &Vec4_normalizeNonNull<T>,return_internal_reference<>(),
+             "v.normalizeNonNull() destructively normalizes V and returns a reference to it, faster if lngth() != 0")
+        .def("normalized", &Vec4_normalized<T>, "v.normalized() returns a normalized copy of v")
+        .def("normalizedExc", &Vec4_normalizedExc<T>, "v.normalizedExc() returns a normalized copy of v, throwing an exception if length() == 0")
+        .def("normalizedNonNull", &Vec4_normalizedNonNull<T>, "v.normalizedNonNull() returns a normalized copy of v, faster if lngth() != 0")
+        .def("orthogonal", &orthogonal<T>)
+        .def("project", &project<T>)
+        .def("reflect", &reflect<T>)
+        ;
+}
+
+template <class T, IMATH_ENABLE_IF(std::is_integral<T>::value)>
+void register_Vec4_floatonly(class_<Vec4<T>>& vec4_class)
+{
+}
+
+template <class T>
+class_<Vec4<T> >
+register_Vec4()
+{
+    typedef PyImath::StaticFixedArray<Vec4<T>,T,4> Vec4_helper;
+    class_<Vec4<T> > vec4_class(Vec4Name<T>::value(), Vec4Name<T>::value(),init<Vec4<T> >("copy construction"));
+    vec4_class
+        .def("__init__",make_constructor(Vec4_construct_default<T>),"initialize to (0,0,0,0)")
+        .def("__init__",make_constructor(Vec4_object_constructor1<T>))
+        .def("__init__",make_constructor(Vec4_object_constructor2<T>))
+        .def_readwrite("x", &Vec4<T>::x)
+        .def_readwrite("y", &Vec4<T>::y)
+        .def_readwrite("z", &Vec4<T>::z)
+        .def_readwrite("w", &Vec4<T>::w)
+       .def("baseTypeEpsilon", &Vec4<T>::baseTypeEpsilon,"baseTypeEpsilon() epsilon value of the base type of the vector")
+        .staticmethod("baseTypeEpsilon")
+       .def("baseTypeMax", &Vec4<T>::baseTypeMax,"baseTypeMax() max value of the base type of the vector")
+        .staticmethod("baseTypeMax")
+       .def("baseTypeLowest", &Vec4<T>::baseTypeLowest,"baseTypeLowest() largest negative value of the base type of the vector")
+        .staticmethod("baseTypeLowest")
+       .def("baseTypeSmallest", &Vec4<T>::baseTypeSmallest,"baseTypeSmallest() smallest value of the base type of the vector")
+        .staticmethod("baseTypeSmallest")
+       .def("dimensions", &Vec4<T>::dimensions,"dimensions() number of dimensions in the vector")
+        .staticmethod("dimensions")
+       .def("dot", &Vec4_dot<T>,"v1.dot(v2) inner product of the two vectors")
+       .def("dot", &Vec4_dot_Vec4Array<T>,"v1.dot(v2) array inner product")
+    
+       .def("equalWithAbsError", &Vec4<T>::equalWithAbsError,
+         "v1.equalWithAbsError(v2) true if the elements "
+         "of v1 and v2 are the same with an absolute error of no more than e, "
+         "i.e., abs(v1[i] - v2[i]) <= e")
+        .def("equalWithAbsError", &equalWithAbsErrorObj<T>)
+             
+       .def("equalWithRelError", &Vec4<T>::equalWithRelError,
+         "v1.equalWithAbsError(v2) true if the elements "
+         "of v1 and v2 are the same with an absolute error of no more than e, "
+         "i.e., abs(v1[i] - v2[i]) <= e * abs(v1[i])")
+        .def("equalWithRelError", &equalWithRelErrorObj<T>)
+         
+       .def("length2", &Vec4_length2<T>,"length2() square magnitude of the vector")
+       .def("__len__", Vec4_helper::len)
+       .def("__getitem__", Vec4_helper::getitem,return_value_policy<copy_non_const_reference>())
+       .def("__setitem__", Vec4_helper::setitem)
+        .def("negate", &Vec4_negate<T>, return_internal_reference<>())
+        .def("setValue", &setValue<T>)    
+        .def("__neg__", &Vec4_neg<T>)
+        .def("__mul__", &Vec4_mul<T, int>)
+        .def("__mul__", &Vec4_mul<T, float>)
+        .def("__mul__", &Vec4_mul<T, double>)
+        .def("__mul__", &Vec4_mulT<T>)
+        .def("__mul__", &Vec4_mulTArray<T>)
+        .def("__rmul__", &Vec4_rmulT<T>)
+        .def("__rmul__", &Vec4_rmulTArray<T>)
+        .def("__imul__", &Vec4_imulV<T, int>,return_internal_reference<>())
+        .def("__imul__", &Vec4_imulV<T, float>,return_internal_reference<>())
+        .def("__imul__", &Vec4_imulV<T, double>,return_internal_reference<>())
+        .def("__imul__", &Vec4_imulT<T>,return_internal_reference<>())
+        .def("__div__", &Vec4_Vec4_divT<T>)
+        .def("__truediv__", &Vec4_Vec4_divT<T>)
+        .def("__mul__", &Vec4_mulM44<T, float>)
+        .def("__mul__", &Vec4_mulM44<T, double>)
+        .def("__mul__", &Vec4_Vec4_mulT<T>)
+        .def("__div__", &Vec4_div<T,int>)
+        .def("__div__", &Vec4_div<T,float>)
+        .def("__div__", &Vec4_div<T,double>)
+        .def("__div__", &Vec4_divTuple<T,tuple>)
+        .def("__div__", &Vec4_divTuple<T,list>)
+        .def("__div__", &Vec4_divT<T>)
+        .def("__truediv__", &Vec4_div<T,int>)
+        .def("__truediv__", &Vec4_div<T,float>)
+        .def("__truediv__", &Vec4_div<T,double>)
+        .def("__truediv__", &Vec4_divTuple<T,tuple>)
+        .def("__truediv__", &Vec4_divTuple<T,list>)
+        .def("__truediv__", &Vec4_divT<T>)
+        .def("__rdiv__", &Vec4_rdivTuple<T,tuple>)
+        .def("__rdiv__", &Vec4_rdivTuple<T,list>)
+        .def("__rdiv__", &Vec4_rdivT<T>)
+        .def("__rtruediv__", &Vec4_rdivTuple<T,tuple>)
+        .def("__rtruediv__", &Vec4_rdivTuple<T,list>)
+        .def("__rtruediv__", &Vec4_rdivT<T>)
+        .def("__idiv__", &Vec4_idivObj<T>,return_internal_reference<>())
+        .def("__itruediv__", &Vec4_idivObj<T>,return_internal_reference<>())
+        .def("__xor__", &Vec4_dot<T>)
+        .def(self == self) // NOSONAR - suppress SonarCloud bug report.
+        .def(self != self) // NOSONAR - suppress SonarCloud bug report.
+        .def("__add__", &Vec4_add<T>)
+        .def("__add__", &Vec4_addV<T, int>)
+        .def("__add__", &Vec4_addV<T, float>)
+        .def("__add__", &Vec4_addV<T, double>)
+        .def("__add__", &Vec4_addT<T>)
+        .def("__add__", &Vec4_addTuple<T,tuple>)
+        .def("__add__", &Vec4_addTuple<T,list>)
+        .def("__radd__", &Vec4_addT<T>)
+        .def("__radd__", &Vec4_addTuple<T,tuple>)
+        .def("__radd__", &Vec4_addTuple<T,list>)
+        .def("__radd__", &Vec4_add<T>)
+        .def("__iadd__", &Vec4_iaddV<T, int>, return_internal_reference<>())
+        .def("__iadd__", &Vec4_iaddV<T, float>, return_internal_reference<>())
+        .def("__iadd__", &Vec4_iaddV<T, double>, return_internal_reference<>())
+        .def("__sub__", &Vec4_sub<T>)
+        .def("__sub__", &Vec4_subV<T, int>)
+        .def("__sub__", &Vec4_subV<T, float>)
+        .def("__sub__", &Vec4_subV<T, double>)
+        .def("__sub__", &Vec4_subT<T>)
+        .def("__sub__", &Vec4_subTuple<T,tuple>)
+        .def("__sub__", &Vec4_subTuple<T,list>)
+        .def("__rsub__", &Vec4_rsubT<T>)
+        .def("__rsub__", &Vec4_rsubTuple<T,tuple>)
+        .def("__rsub__", &Vec4_rsubTuple<T,list>)
+        .def("__isub__", &Vec4_isubV<T, int>, return_internal_reference<>())
+        .def("__isub__", &Vec4_isubV<T, float>, return_internal_reference<>())
+        .def("__isub__", &Vec4_isubV<T, double>, return_internal_reference<>())
+        .def("__mul__", &mult<T>)
+        .def("__rmul__", &mult<T>)
+        .def("__imul__", &Vec4_imulM44<T, float>, return_internal_reference<>())
+        .def("__imul__", &Vec4_imulM44<T, double>, return_internal_reference<>())
+        .def("__lt__", &lessThan<T>)
+        .def("__gt__", &greaterThan<T>)
+        .def("__le__", &lessThanEqual<T>)
+        .def("__ge__", &greaterThanEqual<T>)
+        .def("__eq__", &equal<T>)
+        .def("__ne__", &notequal<T>)
+       //.def(self_ns::str(self))
+       .def("__str__",&Vec4_str<T>)
+       .def("__repr__",&Vec4_repr<T>)
+        ;
+
+    register_Vec4_floatonly<T>(vec4_class);
+
+    decoratecopy(vec4_class);
+
+    //add_swizzle3_operators(v3f_class);
+    return vec4_class;
+}
+
+
+
+}  // namespace PyImath
+
+#endif    // _PyImathVec4Impl_h_
diff --git a/src/python/PyImath/PyImathVec4fd.cpp b/src/python/PyImath/PyImathVec4fd.cpp
new file mode 100644 (file)
index 0000000..17c1cd5
--- /dev/null
@@ -0,0 +1,46 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathVec4Impl.h"
+#include "PyImathVec4ArrayImpl.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+template <> const char *PyImath::V4fArray::name() { return "V4fArray"; }
+template <> const char *PyImath::V4dArray::name() { return "V4dArray"; }
+
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template<> const char *Vec4Name<float>::value() { return "V4f"; }
+template<> const char *Vec4Name<double>::value() { return "V4d"; }
+
+// Specialization for float to full precision
+template <>
+std::string Vec4_repr(const Vec4<float> &v)
+{
+    return (boost::format("%s(%.9g, %.9g, %.9g, %.9g)")
+                        % Vec4Name<float>::value() % v.x % v.y % v.z % v.w).str();
+}
+
+// Specialization for double to full precision
+template <>
+std::string Vec4_repr(const Vec4<double> &v)
+{
+    return (boost::format("%s(%.17g, %.17g, %.17g, %.17g)")
+                        % Vec4Name<double>::value() % v.x % v.y % v.z % v.w).str();
+}
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec4<float> > register_Vec4<float>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec4<double> > register_Vec4<double>();
+                
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec4<float> > > register_Vec4Array<float>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec4<double> > > register_Vec4Array<double>();
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec4<float> PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Vec4<float> >::value() { return IMATH_NAMESPACE::Vec4<float>(0,0,0,0); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec4<double> PyImath::FixedArrayDefaultValue<IMATH_NAMESPACE::Vec4<double> >::value() { return IMATH_NAMESPACE::Vec4<double>(0,0,0,0); }
+}
diff --git a/src/python/PyImath/PyImathVec4si.cpp b/src/python/PyImath/PyImathVec4si.cpp
new file mode 100644 (file)
index 0000000..5cfbe6a
--- /dev/null
@@ -0,0 +1,31 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathVec4Impl.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+template <> const char *PyImath::V4cArray::name()   { return "V4cArray"; }
+template <> const char *PyImath::V4sArray::name()   { return "V4sArray"; }
+template <> const char *PyImath::V4iArray::name()   { return "V4iArray"; }
+template <> const char *PyImath::V4i64Array::name() { return "V4i64Array"; }
+
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template<> const char *Vec4Name<unsigned char>::value() { return "V4c"; }
+template<> const char *Vec4Name<short>::value()         { return "V4s"; }
+template<> const char *Vec4Name<int>::value()           { return "V4i"; }
+template<> const char *Vec4Name<int64_t>::value()       { return "V4i64"; }
+
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec4<unsigned char> > register_Vec4<unsigned char>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec4<short> >         register_Vec4<short>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec4<int> >           register_Vec4<int>();
+template PYIMATH_EXPORT class_<IMATH_NAMESPACE::Vec4<int64_t> >       register_Vec4<int64_t>();
+
+}
+
diff --git a/src/python/PyImath/PyImathVec4siArray.cpp b/src/python/PyImath/PyImathVec4siArray.cpp
new file mode 100644 (file)
index 0000000..3b8692b
--- /dev/null
@@ -0,0 +1,24 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include "PyImathVec4ArrayImpl.h"
+#include "PyImathExport.h"
+
+namespace PyImath {
+using namespace boost::python;
+using namespace IMATH_NAMESPACE;
+
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec4<unsigned char> > > register_Vec4Array<unsigned char>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec4<short> > >         register_Vec4Array<short>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec4<int> > >           register_Vec4Array<int>();
+template PYIMATH_EXPORT class_<FixedArray<IMATH_NAMESPACE::Vec4<int64_t> > >       register_Vec4Array<int64_t>();
+
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec4<unsigned char> FixedArrayDefaultValue<IMATH_NAMESPACE::Vec4<unsigned char> >::value() { return IMATH_NAMESPACE::Vec4<unsigned char>(0,0,0,0); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec4<short>         FixedArrayDefaultValue<IMATH_NAMESPACE::Vec4<short> >::value()         { return IMATH_NAMESPACE::Vec4<short>(0,0,0,0); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec4<int>           FixedArrayDefaultValue<IMATH_NAMESPACE::Vec4<int> >::value()           { return IMATH_NAMESPACE::Vec4<int>(0,0,0,0); }
+template<> PYIMATH_EXPORT IMATH_NAMESPACE::Vec4<int64_t>       FixedArrayDefaultValue<IMATH_NAMESPACE::Vec4<int64_t> >::value()       { return IMATH_NAMESPACE::Vec4<int64_t>(0,0,0,0); }
+}
diff --git a/src/python/PyImath/PyImathVecOperators.h b/src/python/PyImath/PyImathVecOperators.h
new file mode 100644 (file)
index 0000000..4524d72
--- /dev/null
@@ -0,0 +1,65 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#ifndef _PyImathVecOperators_h_
+#define _PyImathVecOperators_h_
+
+namespace PyImath {
+
+template <class T>
+struct op_vecDot {
+    static inline typename T::BaseType apply(const T &a, const T &b) { return a.dot(b); }
+};
+
+template <class T,
+          IMATH_ENABLE_IF(!std::is_integral<typename T::BaseType>::value)>
+struct op_vecLength {
+    static inline typename T::BaseType apply(const T &v) { return v.length(); }
+};
+
+template <class T>
+struct op_vecLength2 {
+    static inline typename T::BaseType apply(const T &v) { return v.length2(); }
+};
+
+template <class T,
+          IMATH_ENABLE_IF(!std::is_integral<typename T::BaseType>::value)>
+struct op_vecNormalize {
+    static inline void apply(T &v) { v.normalize(); }
+};
+
+template <class T,
+          IMATH_ENABLE_IF(!std::is_integral<typename T::BaseType>::value)>
+struct op_vecNormalized {
+    static inline T apply(const T &v) { return v.normalized(); }
+};
+
+template <class T,
+          IMATH_ENABLE_IF(!std::is_integral<typename T::BaseType>::value)>
+struct op_vecNormalizeExc {
+    static inline void apply(T &v) { v.normalizeExc(); }
+};
+
+template <class T,
+          IMATH_ENABLE_IF(!std::is_integral<typename T::BaseType>::value)>
+struct op_vecNormalizedExc {
+    static inline T apply(const T &v) { return v.normalizedExc(); }
+};
+  
+template <class T>
+struct op_vec3Cross {
+    static inline IMATH_NAMESPACE::Vec3<T> apply(const IMATH_NAMESPACE::Vec3<T> &a, const IMATH_NAMESPACE::Vec3<T> &b) { return a.cross(b); }
+};
+
+template <class T>
+struct op_vec2Cross {
+    static inline T apply(const IMATH_NAMESPACE::Vec2<T> &a, const IMATH_NAMESPACE::Vec2<T> &b) { return a.cross(b); }
+};
+
+}  // namespace PyImath
+
+#endif // _PyImathVecOperators_h_
diff --git a/src/python/PyImath/imathmodule.cpp b/src/python/PyImath/imathmodule.cpp
new file mode 100644 (file)
index 0000000..bc68fbe
--- /dev/null
@@ -0,0 +1,650 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include <boost/python.hpp>
+#include <boost/python/make_constructor.hpp>
+#include <boost/format.hpp>
+#include <ImathVec.h>
+#include <ImathQuat.h>
+#include <ImathEuler.h>
+#include <ImathFun.h>
+#include <ImathMatrixAlgo.h>
+
+#include "PyImathFixedArray.h"
+#include "PyImath.h"
+#include "PyImathExport.h"
+#include "PyImathBasicTypes.h"
+#include "PyImathVec.h"
+#include "PyImathMatrix.h"
+#include "PyImathBox.h"
+#include "PyImathFun.h"
+#include "PyImathQuat.h"
+#include "PyImathEuler.h"
+#include "PyImathColor.h"
+#include "PyImathFrustum.h"
+#include "PyImathPlane.h"
+#include "PyImathLine.h"
+#include "PyImathRandom.h"
+#include "PyImathShear.h"
+#include "PyImathMathExc.h"
+#include "PyImathAutovectorize.h"
+#include "PyImathStringArrayRegister.h"
+#include "PyImathBufferProtocol.h"
+
+using namespace boost::python;
+using namespace PyImath;
+
+namespace {
+
+template <typename T>
+IMATH_NAMESPACE::Box<IMATH_NAMESPACE::Vec3<T> >
+computeBoundingBox(const FixedArray<IMATH_NAMESPACE::Vec3<T> >& position)
+{
+    IMATH_NAMESPACE::Box<IMATH_NAMESPACE::Vec3<T> > bounds;
+    int len = position.len();
+    for (int i = 0; i < len; ++i)
+        bounds.extendBy(position[i]);
+    return bounds;
+}
+
+IMATH_NAMESPACE::M44d
+procrustes1 (PyObject* from_input, 
+             PyObject* to_input,
+             PyObject* weights_input = 0,
+             bool doScale = false)
+{
+    // Verify the sequences:
+    if (!PySequence_Check (from_input))
+    {
+        PyErr_SetString (PyExc_TypeError, "Expected a sequence type for 'from'");
+        throw_error_already_set();
+    }
+        
+    if (!PySequence_Check (to_input))
+    {
+        PyErr_SetString (PyExc_TypeError, "Expected a sequence type for 'to'");
+        throw_error_already_set();
+    }
+
+    bool useWeights = PySequence_Check (weights_input);
+
+    // Now verify the lengths:
+    const Py_ssize_t n = PySequence_Length (from_input);
+    if (n != PySequence_Length (to_input) ||
+        (useWeights && n != PySequence_Length (weights_input)))
+    {
+        PyErr_SetString (PyExc_TypeError, "'from, 'to', and 'weights' should all have the same lengths.");
+        throw_error_already_set();
+    }
+
+    std::vector<IMATH_NAMESPACE::V3d> from;  from.reserve (n);
+    std::vector<IMATH_NAMESPACE::V3d> to;    to.reserve (n);
+    std::vector<double> weights;   weights.reserve (n);
+
+    for (Py_ssize_t i = 0; i < n; ++i)
+    {
+        PyObject* f = PySequence_GetItem (from_input, i);
+        PyObject* t = PySequence_GetItem (to_input, i);
+        PyObject* w = 0;
+        if (useWeights)
+            w = PySequence_GetItem (weights_input, i);
+
+        if (f == 0 || t == 0 || (useWeights && w == 0))
+        {
+            PyErr_SetString (PyExc_TypeError,
+                             "Missing element in array");
+            throw_error_already_set();
+        }
+
+        from.push_back (extract<IMATH_NAMESPACE::V3d> (f));
+        to.push_back (extract<IMATH_NAMESPACE::V3d> (t));
+        if (useWeights)
+            weights.push_back (extract<double> (w));
+    }
+
+    if (useWeights)
+        return IMATH_NAMESPACE::procrustesRotationAndTranslation (&from[0], &to[0], &weights[0], n, doScale);
+    else
+        return IMATH_NAMESPACE::procrustesRotationAndTranslation (&from[0], &to[0], n, doScale);
+}
+
+template <typename T>
+const T*
+flatten(const PyImath::FixedArray<T>& q, std::unique_ptr<T[]>& handle)
+{
+    if (q.isMaskedReference())
+    {
+        const size_t len = q.len();
+        handle.reset(new T[len]);
+        for (size_t i = 0; i < len; ++i)
+            handle[i] = q[i];
+
+        return handle.get();
+    }
+
+    return &q[0];
+}
+
+template <typename T>
+IMATH_NAMESPACE::M44d
+procrustesRotationAndTranslation(const FixedArray<IMATH_NAMESPACE::Vec3<T> >& from,
+                                 const FixedArray<IMATH_NAMESPACE::Vec3<T> >& to,
+                                 const FixedArray<T>* weights = 0,
+                                 bool doScale = false)
+{
+    const size_t len = from.match_dimension(to);
+    if (len == 0)
+        return IMATH_NAMESPACE::M44d();
+
+    std::unique_ptr<IMATH_NAMESPACE::Vec3<T>[]> fromHandle;
+    const Imath::Vec3<T>* fromPtr = flatten(from, fromHandle);
+
+    std::unique_ptr<IMATH_NAMESPACE::Vec3<T>[]> toHandle;
+    const Imath::Vec3<T>* toPtr = flatten(to, toHandle);
+
+    std::unique_ptr<T[]> weightsHandle;
+    const T* weightsPtr = nullptr;
+    if (weights)
+    {
+        weights->match_dimension(from);
+        flatten(*weights, weightsHandle);
+    }
+
+    if (weightsPtr)
+        return IMATH_NAMESPACE::procrustesRotationAndTranslation(fromPtr, toPtr, weightsPtr, len, doScale);
+    else
+        return IMATH_NAMESPACE::procrustesRotationAndTranslation(fromPtr, toPtr, len, doScale);
+}
+
+BOOST_PYTHON_FUNCTION_OVERLOADS(procrustesRotationAndTranslationf_overloads, procrustesRotationAndTranslation<float>, 2, 4);
+BOOST_PYTHON_FUNCTION_OVERLOADS(procrustesRotationAndTranslationd_overloads, procrustesRotationAndTranslation<double>, 2, 4);
+
+
+FixedArray2D<int> rangeX(int sizeX, int sizeY)
+{
+    FixedArray2D<int> f(sizeX, sizeY);
+    for (int j=0; j<sizeY; j++)
+        for (int i=0; i<sizeX; i++)
+            f(i,j) = i;
+    return f;
+}
+
+FixedArray2D<int> rangeY(int sizeX, int sizeY)
+{
+    FixedArray2D<int> f(sizeX, sizeY);
+    for (int j=0; j<sizeY; j++)
+        for (int i=0; i<sizeX; i++)
+            f(i,j) = j;
+    return f;
+}
+
+} // anonymous-namespace
+
+
+BOOST_PYTHON_MODULE(imath)
+{
+    scope().attr("__doc__") = "Imath module";
+    scope().attr("__version__") = IMATH_VERSION_STRING;
+
+    register_basicTypes();
+
+    class_<IntArray2D> iclass2D = IntArray2D::register_("IntArray2D","Fixed length array of ints");
+    add_arithmetic_math_functions(iclass2D);
+    add_mod_math_functions(iclass2D);
+    add_comparison_functions(iclass2D);
+    add_ordered_comparison_functions(iclass2D);
+    add_explicit_construction_from_type<float>(iclass2D);
+    add_explicit_construction_from_type<double>(iclass2D);
+
+    class_<IntMatrix> imclass = IntMatrix::register_("IntMatrix","Fixed size matrix of ints");
+    add_arithmetic_math_functions(imclass);
+
+    class_<FloatArray2D> fclass2D = FloatArray2D::register_("FloatArray2D","Fixed length 2D array of floats");
+    add_arithmetic_math_functions(fclass2D);
+    add_pow_math_functions(fclass2D);
+    add_comparison_functions(fclass2D);
+    add_ordered_comparison_functions(fclass2D);
+    add_explicit_construction_from_type<int>(fclass2D);
+    add_explicit_construction_from_type<double>(fclass2D);
+
+    class_<FloatMatrix> fmclass = FloatMatrix::register_("FloatMatrix","Fixed size matrix of floats");
+    add_arithmetic_math_functions(fmclass);
+    add_pow_math_functions(fmclass);
+
+    class_<DoubleArray2D> dclass2D = DoubleArray2D::register_("DoubleArray2D","Fixed length array of doubles");
+    add_arithmetic_math_functions(dclass2D);
+    add_pow_math_functions(dclass2D);
+    add_comparison_functions(dclass2D);
+    add_ordered_comparison_functions(dclass2D);
+    add_explicit_construction_from_type<int>(dclass2D);
+    add_explicit_construction_from_type<float>(dclass2D);
+
+    class_<DoubleMatrix> dmclass = DoubleMatrix::register_("DoubleMatrix","Fixed size matrix of doubles");
+    add_arithmetic_math_functions(dmclass);
+    add_pow_math_functions(dmclass);
+
+    def("rangeX", &rangeX);
+    def("rangeY", &rangeY);
+
+    def("IntArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<int> >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct an IntArray from a buffer object");
+
+    def("FloatArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<float> >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct a FloatArray from a buffer object");
+
+    def("DoubleArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<double> >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct a DoubleArray from a buffer object");
+
+    //
+    //  Vec2
+    //
+    register_Vec2<short>();
+    register_Vec2<int>();
+    register_Vec2<int64_t>();
+    register_Vec2<float>();
+    register_Vec2<double>();
+    class_<FixedArray<IMATH_NAMESPACE::V2s> >   v2s_class = register_Vec2Array<short>();
+    class_<FixedArray<IMATH_NAMESPACE::V2i> >   v2i_class = register_Vec2Array<int>();
+    class_<FixedArray<IMATH_NAMESPACE::V2i64> > v2i64_class = register_Vec2Array<int64_t>();
+    class_<FixedArray<IMATH_NAMESPACE::V2f> >   v2f_class = register_Vec2Array<float>();
+    class_<FixedArray<IMATH_NAMESPACE::V2d> >   v2d_class = register_Vec2Array<double>();
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2s>(v2i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2s>(v2i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2s>(v2f_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2s>(v2d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2i>(v2s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2i>(v2i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2i>(v2f_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2i>(v2d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2i64>(v2s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2i64>(v2i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2i64>(v2f_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2i64>(v2d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2f>(v2s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2f>(v2i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2f>(v2i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2f>(v2d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2d>(v2s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2d>(v2i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2d>(v2i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V2d>(v2f_class);
+
+    add_buffer_protocol<FixedArray<IMATH_NAMESPACE::V2s> > (v2s_class);
+    add_buffer_protocol<FixedArray<IMATH_NAMESPACE::V2i> > (v2i_class);
+    add_buffer_protocol<FixedArray<IMATH_NAMESPACE::V2i64> > (v2i64_class);
+    add_buffer_protocol<FixedArray<IMATH_NAMESPACE::V2f> > (v2f_class);
+    add_buffer_protocol<FixedArray<IMATH_NAMESPACE::V2d> > (v2d_class);
+
+    def("V2iArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<Imath::Vec2<int> > >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct a V2iArray from a buffer object");
+
+    def("V2fArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<Imath::Vec2<float> > >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct a V2fArray from a buffer object");
+
+    def("V2dArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<Imath::Vec2<double> > >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct a V2dArray from a buffer object");
+
+    //
+    //  Vec3
+    //
+    register_Vec3<unsigned char>();
+    register_Vec3<short>();
+    register_Vec3<int>();
+    register_Vec3<int64_t>();
+    register_Vec3<float>();
+    register_Vec3<double>();
+    class_<FixedArray<IMATH_NAMESPACE::V3s> >   v3s_class = register_Vec3Array<short>();
+    class_<FixedArray<IMATH_NAMESPACE::V3i> >   v3i_class = register_Vec3Array<int>();
+    class_<FixedArray<IMATH_NAMESPACE::V3i64> > v3i64_class = register_Vec3Array<int64_t>();
+    class_<FixedArray<IMATH_NAMESPACE::V3f> >   v3f_class = register_Vec3Array<float>();
+    class_<FixedArray<IMATH_NAMESPACE::V3d> >   v3d_class = register_Vec3Array<double>();
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3s>(v3i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3s>(v3i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3s>(v3f_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3s>(v3d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3i>(v3s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3i>(v3i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3i>(v3f_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3i>(v3d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3i64>(v3s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3i64>(v3i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3i64>(v3f_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3i64>(v3d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3f>(v3s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3f>(v3i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3f>(v3i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3f>(v3d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3d>(v3s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3d>(v3i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3d>(v3i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3d>(v3f_class);
+
+    add_buffer_protocol<FixedArray<IMATH_NAMESPACE::V3s> > (v3s_class);
+    add_buffer_protocol<FixedArray<IMATH_NAMESPACE::V3i> > (v3i_class);
+    add_buffer_protocol<FixedArray<IMATH_NAMESPACE::V3i64> > (v3i64_class);
+    add_buffer_protocol<FixedArray<IMATH_NAMESPACE::V3f> > (v3f_class);
+    add_buffer_protocol<FixedArray<IMATH_NAMESPACE::V3d> > (v3d_class);
+
+    def("V3iArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<Imath::Vec3<int> > >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct a V3iArray from a buffer object");
+
+    def("V3fArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<Imath::Vec3<float> > >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct a V3fArray from a buffer object");
+
+    def("V3dArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<Imath::Vec3<double> > >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct a V3dArray from a buffer object");
+
+    //
+    //  Vec4
+    //
+    register_Vec4<unsigned char>();
+    register_Vec4<short>();
+    register_Vec4<int>();
+    register_Vec4<int64_t>();
+    register_Vec4<float>();
+    register_Vec4<double>();
+    class_<FixedArray<IMATH_NAMESPACE::V4s> >   v4s_class = register_Vec4Array<short>();
+    class_<FixedArray<IMATH_NAMESPACE::V4i> >   v4i_class = register_Vec4Array<int>();
+    class_<FixedArray<IMATH_NAMESPACE::V4i64> > v4i64_class = register_Vec4Array<int64_t>();
+    class_<FixedArray<IMATH_NAMESPACE::V4f> >   v4f_class = register_Vec4Array<float>();
+    class_<FixedArray<IMATH_NAMESPACE::V4d> >   v4d_class = register_Vec4Array<double>();
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4s>(v4i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4s>(v4i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4s>(v4f_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4s>(v4d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4i>(v4s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4i>(v4i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4i>(v4f_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4i>(v4d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4i64>(v4s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4i64>(v4i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4i64>(v4f_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4i64>(v4d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4f>(v4s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4f>(v4i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4f>(v4i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4f>(v4d_class);
+
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4d>(v4s_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4d>(v4i_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4d>(v4i64_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V4d>(v4f_class);
+
+    def("V4iArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<Imath::Vec4<int> > >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct a V4iArray from a buffer object");
+
+    def("V4fArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<Imath::Vec4<float> > >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct a V4fArray from a buffer object");
+
+    def("V4dArrayFromBuffer", &fixedArrayFromBuffer<FixedArray<Imath::Vec4<double> > >,
+        return_value_policy<manage_new_object>(),
+        args("bufferObject"),
+        "Construct a V4dArray from a buffer object");
+
+    //
+    //  Quat
+    //
+    register_Quat<float>();
+    register_Quat<double>();
+    class_<FixedArray<IMATH_NAMESPACE::Quatf> > quatf_class = register_QuatArray<float>();
+    class_<FixedArray<IMATH_NAMESPACE::Quatd> > quatd_class = register_QuatArray<double>();
+    add_explicit_construction_from_type<IMATH_NAMESPACE::Quatd>(quatf_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::Quatf>(quatd_class);
+
+    //
+    // Euler
+    //
+    register_Euler<float>();
+    register_Euler<double>();
+    class_<FixedArray<IMATH_NAMESPACE::Eulerf> > eulerf_class = register_EulerArray<float>();
+    class_<FixedArray<IMATH_NAMESPACE::Eulerd> > eulerd_class = register_EulerArray<double>();
+    add_explicit_construction_from_type<IMATH_NAMESPACE::Eulerd>(eulerf_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::Eulerf>(eulerd_class);
+
+    //
+    // Box2
+    //
+    register_Box2<IMATH_NAMESPACE::V2s>();
+    register_Box2<IMATH_NAMESPACE::V2i>();
+    register_Box2<IMATH_NAMESPACE::V2i64>();
+    register_Box2<IMATH_NAMESPACE::V2f>();
+    register_Box2<IMATH_NAMESPACE::V2d>();
+    class_<FixedArray<IMATH_NAMESPACE::Box2s> >   b2s_class =   register_BoxArray<IMATH_NAMESPACE::V2s>();
+    class_<FixedArray<IMATH_NAMESPACE::Box2i> >   b2i_class =   register_BoxArray<IMATH_NAMESPACE::V2i>();
+    class_<FixedArray<IMATH_NAMESPACE::Box2i64> > b2i64_class = register_BoxArray<IMATH_NAMESPACE::V2i64>();
+    class_<FixedArray<IMATH_NAMESPACE::Box2f> >   b2f_class =   register_BoxArray<IMATH_NAMESPACE::V2f>();
+    class_<FixedArray<IMATH_NAMESPACE::Box2d> >   b2d_class =   register_BoxArray<IMATH_NAMESPACE::V2d>();
+
+    //
+    // Box3
+    //
+    register_Box3<IMATH_NAMESPACE::V3s>();
+    register_Box3<IMATH_NAMESPACE::V3i>();
+    register_Box3<IMATH_NAMESPACE::V3i64>();
+    register_Box3<IMATH_NAMESPACE::V3f>();
+    register_Box3<IMATH_NAMESPACE::V3d>();
+    class_<FixedArray<IMATH_NAMESPACE::Box3s> >   b3s_class =   register_BoxArray<IMATH_NAMESPACE::V3s>();
+    class_<FixedArray<IMATH_NAMESPACE::Box3i> >   b3i_class =   register_BoxArray<IMATH_NAMESPACE::V3i>();
+    class_<FixedArray<IMATH_NAMESPACE::Box3i64> > b3i64_class = register_BoxArray<IMATH_NAMESPACE::V3i64>();
+    class_<FixedArray<IMATH_NAMESPACE::Box3f> >   b3f_class =   register_BoxArray<IMATH_NAMESPACE::V3f>();
+    class_<FixedArray<IMATH_NAMESPACE::Box3d> >   b3d_class =   register_BoxArray<IMATH_NAMESPACE::V3d>();
+
+    //
+    // Matrix22/33/44
+    //
+    register_Matrix22<float>();
+    register_Matrix22<double>();
+    register_Matrix33<float>();
+    register_Matrix33<double>();
+    register_Matrix44<float>();
+    register_Matrix44<double>();
+
+    //
+    // M22/M33/44Array
+    //
+    class_<FixedArray<IMATH_NAMESPACE::M44d> > m44d_class = register_M44Array<double>();
+    class_<FixedArray<IMATH_NAMESPACE::M44f> > m44f_class = register_M44Array<float>();
+    add_explicit_construction_from_type< IMATH_NAMESPACE::Matrix44<double> >(m44d_class);
+    add_explicit_construction_from_type< IMATH_NAMESPACE::Matrix44<float> > (m44f_class);
+
+    class_<FixedArray<IMATH_NAMESPACE::M33d> > m33d_class = register_M33Array<double>();
+    class_<FixedArray<IMATH_NAMESPACE::M33f> > m33f_class = register_M33Array<float>();
+    add_explicit_construction_from_type< IMATH_NAMESPACE::Matrix33<double> >(m33d_class);
+    add_explicit_construction_from_type< IMATH_NAMESPACE::Matrix33<float> > (m33f_class);
+
+    class_<FixedArray<IMATH_NAMESPACE::M22d> > m22d_class = register_M22Array<double>();
+    class_<FixedArray<IMATH_NAMESPACE::M22f> > m22f_class = register_M22Array<float>();
+    add_explicit_construction_from_type< IMATH_NAMESPACE::Matrix22<double> >(m22d_class);
+    add_explicit_construction_from_type< IMATH_NAMESPACE::Matrix22<float> > (m22f_class);
+
+    //
+    // String Array
+    //
+    register_StringArrays();
+
+    //
+    // Color3/4
+    //
+    register_Color3<unsigned char>();
+    register_Color3<float>();
+    register_Color4<unsigned char>();
+    register_Color4<float>();
+
+    //
+    // C3/4Array
+    //
+    class_<FixedArray<IMATH_NAMESPACE::Color3f> > c3f_class = register_Color3Array<float>();
+    class_<FixedArray<IMATH_NAMESPACE::Color3c> > c3c_class = register_Color3Array<unsigned char>();
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3f>(c3f_class);
+    add_explicit_construction_from_type<IMATH_NAMESPACE::V3d>(c3f_class);
+
+    class_<FixedArray<IMATH_NAMESPACE::Color4f> > c4f_class = register_Color4Array<float>();
+    class_<FixedArray<IMATH_NAMESPACE::Color4c> > c4c_class = register_Color4Array<unsigned char>();
+
+    //
+    // Color4Array
+    //
+    register_Color4Array2D<float>();
+    register_Color4Array2D<unsigned char>();
+
+    //
+    // Frustum
+    //
+    register_Frustum<float>();
+    register_Frustum<double>();
+    register_FrustumTest<float>();
+    register_FrustumTest<double>();
+
+    //
+    // Plane
+    //
+    register_Plane<float>();
+    register_Plane<double>();
+
+    //
+    // Line
+    //
+    register_Line<float>();
+    register_Line<double>();
+
+    //
+    // Shear
+    //
+    register_Shear<float>();
+    register_Shear<double>();
+
+    //
+    // Utility Functions
+    //
+    register_functions();
+   
+
+    def("procrustesRotationAndTranslation", procrustes1, 
+        args("fromPts", "toPts", "weights", "doScale"),  // Can't use 'from' and 'to' because 'from' is a reserved keywork in Python
+        "Computes the orthogonal transform (consisting only of rotation and translation) mapping the "
+        "'fromPts' points as close as possible to the 'toPts' points in the least squares norm.  The 'fromPts' and "
+        "'toPts' lists must be the same length or the function will error out.  If weights "
+        "are provided, then the points are weighted (that is, some points are considered more important "
+        "than others while computing the transform).  If the 'doScale' parameter is True, then "
+        "the resulting matrix is also allowed to have a uniform scale.");
+
+    def("procrustesRotationAndTranslation", &procrustesRotationAndTranslation<float>, procrustesRotationAndTranslationf_overloads(
+        args("fromPts", "toPts", "weights", "doScale"),
+        "Computes the orthogonal transform (consisting only of rotation and translation) mapping the "
+        "'fromPts' points as close as possible to the 'toPts' points in the least squares norm.  The 'fromPts' and "
+        "'toPts' lists must be the same length or the function will error out.  If weights "
+        "are provided, then the points are weighted (that is, some points are considered more important "
+        "than others while computing the transform).  If the 'doScale' parameter is True, then "
+        "the resulting matrix is also allowed to have a uniform scale."));
+
+    def("procrustesRotationAndTranslation", &procrustesRotationAndTranslation<double>, procrustesRotationAndTranslationd_overloads(
+        args("fromPts", "toPts", "weights", "doScale"),
+        "Computes the orthogonal transform (consisting only of rotation and translation) mapping the "
+        "'fromPts' points as close as possible to the 'toPts' points in the least squares norm.  The 'fromPts' and "
+        "'toPts' lists must be the same length or the function will error out.  If weights "
+        "are provided, then the points are weighted (that is, some points are considered more important "
+        "than others while computing the transform).  If the 'doScale' parameter is True, then "
+        "the resulting matrix is also allowed to have a uniform scale."));
+
+    //
+    // Rand
+    //
+    register_Rand32();
+    register_Rand48();
+    
+    //
+    // Initialize constants
+    //
+
+    scope().attr("EULER_XYZ")    = IMATH_NAMESPACE::Eulerf::XYZ;
+    scope().attr("EULER_XZY")    = IMATH_NAMESPACE::Eulerf::XZY;
+    scope().attr("EULER_YZX")    = IMATH_NAMESPACE::Eulerf::YZX;
+    scope().attr("EULER_YXZ")    = IMATH_NAMESPACE::Eulerf::YXZ;
+    scope().attr("EULER_ZXY")    = IMATH_NAMESPACE::Eulerf::ZXY;
+    scope().attr("EULER_ZYX")    = IMATH_NAMESPACE::Eulerf::ZYX;
+    scope().attr("EULER_XZX")    = IMATH_NAMESPACE::Eulerf::XZX;
+    scope().attr("EULER_XYX")    = IMATH_NAMESPACE::Eulerf::XYX;
+    scope().attr("EULER_YXY")    = IMATH_NAMESPACE::Eulerf::YXY;
+    scope().attr("EULER_YZY")    = IMATH_NAMESPACE::Eulerf::YZY;
+    scope().attr("EULER_ZYZ")    = IMATH_NAMESPACE::Eulerf::ZYZ;
+    scope().attr("EULER_ZXZ")    = IMATH_NAMESPACE::Eulerf::ZXZ;
+    scope().attr("EULER_XYZr")   = IMATH_NAMESPACE::Eulerf::XYZr;
+    scope().attr("EULER_XZYr")   = IMATH_NAMESPACE::Eulerf::XZYr;
+    scope().attr("EULER_YZXr")   = IMATH_NAMESPACE::Eulerf::YZXr;
+    scope().attr("EULER_YXZr")   = IMATH_NAMESPACE::Eulerf::YXZr;
+    scope().attr("EULER_ZXYr")   = IMATH_NAMESPACE::Eulerf::ZXYr;
+    scope().attr("EULER_ZYXr")   = IMATH_NAMESPACE::Eulerf::ZYXr;
+    scope().attr("EULER_XZXr")   = IMATH_NAMESPACE::Eulerf::XZXr;
+    scope().attr("EULER_XYXr")   = IMATH_NAMESPACE::Eulerf::XYXr;
+    scope().attr("EULER_YXYr")   = IMATH_NAMESPACE::Eulerf::YXYr;
+    scope().attr("EULER_YZYr")   = IMATH_NAMESPACE::Eulerf::YZYr;
+    scope().attr("EULER_ZYZr")   = IMATH_NAMESPACE::Eulerf::ZYZr;
+    scope().attr("EULER_ZXZr")   = IMATH_NAMESPACE::Eulerf::ZXZr;
+    scope().attr("EULER_X_AXIS") = IMATH_NAMESPACE::Eulerf::X;
+    scope().attr("EULER_Y_AXIS") = IMATH_NAMESPACE::Eulerf::Y;
+    scope().attr("EULER_Z_AXIS") = IMATH_NAMESPACE::Eulerf::Z;
+    
+    scope().attr("INT_MIN")      = std::numeric_limits<int>::min();
+    scope().attr("INT_MAX")      = std::numeric_limits<int>::max();
+    scope().attr("INT_LOWEST")   = std::numeric_limits<int>::lowest();
+    scope().attr("INT_EPS")      = std::numeric_limits<int>::epsilon();
+
+    scope().attr("FLT_MIN")      = std::numeric_limits<float>::min();
+    scope().attr("FLT_MAX")      = std::numeric_limits<float>::max();
+    scope().attr("FLT_LOWEST")   = std::numeric_limits<float>::lowest();
+    scope().attr("FLT_EPS")      = std::numeric_limits<float>::epsilon();
+
+    scope().attr("DBL_MIN")      = std::numeric_limits<double>::min();
+    scope().attr("DBL_MAX")      = std::numeric_limits<double>::max();
+    scope().attr("DBL_LOWEST")   = std::numeric_limits<double>::lowest();
+    scope().attr("DBL_EPS")      = std::numeric_limits<double>::epsilon();
+
+    def("computeBoundingBox", &computeBoundingBox<float>,
+        "computeBoundingBox(position) -- computes the bounding box from the position array.");
+
+    def("computeBoundingBox", &computeBoundingBox<double>,
+        "computeBoundingBox(position) -- computes the bounding box from the position array.");
+}
+
diff --git a/src/python/PyImath/varraySemantics.txt b/src/python/PyImath/varraySemantics.txt
new file mode 100644 (file)
index 0000000..7d59886
--- /dev/null
@@ -0,0 +1,145 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+-----------
+Terminology
+-----------
+
+Items - Similar to 'list items'.  Can think of as the 'vertical'
+        dimension similar to the other FixedArray dimension.  Each item
+        contains an array of varying length.
+
+Elements - The 'variable-length' array members of each item.  In this
+           case, each 'element' is an int.  For a FloatVArray, the 
+           elements would be floats.
+
+
+------------
+Construction
+------------
+
+v = IntVArray()
+    : Do not support; FixedArrays generally don't have empty construction.
+
+v = IntVArray(10)
+    : Creates 10 items, each item has zero elements (i.e. empty).
+
+v = IntVArray(int initialValue , 10, 5)
+    : Creates 10 items, each item has 5 elements that are initialized
+      to the initialValue.
+
+v = IntVArray(IntArray initialValue, 10)
+    : Creates 10 items, each initialized with a copy of the elements of
+      the provided initialValue IntArray.
+
+v = IntVArray([1, 2, 3], 10)
+    : Creates 10 items, each initialized with the elements of the provided
+      list.  This would be similar to the previous constructor, but with
+      a different initialValue type.  We probably don't want to support
+      this right away, but possibly at some point in the future.
+
+v = IntVArray(int intialValue, IntArray() initialLengths)
+    : Creates initialLengths.len() items each with a number of elements
+      matching the values provided by the initialLengths array.  The
+      initial value for all elements is 'initalValue'.
+
+v = IntVArray(IntVArray clone)
+    : Created as a copy of 'clone'.
+
+
+Usage (Accessing)
+-----------------
+
+int = v.len()  (number of items)
+
+IntArray  = v[4]   (reference of v's data)
+IntArray  = v[-1]  (same as previous)
+IntVArray = v[3:9] (reference of v's data; stride provides indexing)
+IntVArray = v[:]   (same as previous, stride probably not needed)
+
+IntVArray = v[IntArray mask]
+    : Returns a reference of v's data; uses mask variable internally
+IntVArray = v[BoolArray mask]
+    : Not currently supported, but would provide the same as previous.
+      This 'BoolArray' mask should be implemented sometime soon (for
+      this and all other FixedArrays).
+
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+Question: Support v[5][2] semantics.  This might work out-of-the-box since
+          v[5] would return an IntArray, which supports [] also.  In this
+          case it would be fine and a single 'int' would be returned.
+          But for v[5][1:3], we would return another IntArray
+          instead of a regular int, so the levels of indirection 
+          for original internal IntVArray data might get too complicated.  Do
+          we support this semantic or not.  The problem is that if we don't
+          want to support it, we'll have to specifically disable it somehow
+          since we'll get it by default (v[5] returns IntArray, which would
+          automatically support [1:3]).
+
+Question: To avoid the previous issue, we'll probably want a special element
+          accessor method (probably called 'element').  That'll have to have
+          the ability to take in a 'slice' as an argument.  Would that all
+          work?
+
+In the continuing text, we'll assume we support an 'element' accessor
+method and not the [5][6] double-box notation.
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+int      = v[4].element(1)        (returns a single integer)
+int      = v[4].element(-1)       (same as previous)
+IntArray = v[4].element(2:7)      (return IntArray referencing original data)
+IntArray = v[4].element(:)        (same as previous; no 'stride' needed)
+int      = v[4].len()             (would not work; int doesn't support 'len')
+int      = v[4].element(:).len()  (the number of elements for item 4 ???)
+
+IntArray  = v[3:9].element(1)  (All of the element-1 members for items 3 - 9)
+IntArray  = v.element(1)       (All of the element-1 members for each item)
+IntArray  = v[3:9].element(-1) (same as previous, but returns last elements)
+IntVArray = v[3:9].element(2:7)  (subset of the original ?????)
+IntVArray = v[3:9].element(:)  (subset of the original v; only items 3 - 9)
+int 6     = v[3:9].len()
+
+IntArray  = v[:].element(1)   (List of all element-1s from all items ???)
+IntArray  = v[:].element(-1)  (List of all last elements ???)
+IntVArray = v[:].element(2:7) (subset of the original ????)
+IntVArray = v[:].element(:)   (basically a reference of the original)
+int       = v[:].len()        (number of items in v)
+
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+Question: We want to support easy indexing right into a 'X' V3fArray 
+          or something similar.  Lets say we want to add a V3f to all
+          coordinates of the entire system.  We'd want to be able to
+          write expressions like:
+
+              x[ v[:].element(:) ] += imath.V3f(1,2,3)
+              x[ v[:].element(0) ] += imath.V3f(1,2,3)  (the 'root' point)
+              x[ v[3].element(:) ] += ...
+              x[ v[1:10].element(:) ] += ...
+              x[ v[1:10].element(1:4) ] += ...
+
+          But in many cases, the expression returns another IntVArray.
+          Should/can we provide indexing into V3fArray from an IntVArray?
+          Do we currently support indexing into a V3fArray from IntArray?
+          What other ways can we make this convenient.
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+Question: What about cases where not all items support the same number
+          of elements.  What happens in these cases:
+
+              IntArray = v[:].element(7)
+
+          for cases where some or all of the items don't have an element-7.
+          Would the IntArray be a subset of v's items (i.e. if only 3 items
+          could return an element-7, the IntArray would be 3 long).  Or
+          would the IntArray contain invalid/None/undefined integers within
+          it.
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+Question: What other accessor/modification methods do we want to support.
+          append, remove, pop, push, etc?
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
diff --git a/src/python/PyImathNumpy/CMakeLists.txt b/src/python/PyImathNumpy/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7b4f6b2
--- /dev/null
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+if(TARGET Python2::Python AND
+   TARGET Boost::${PYIMATH_BOOST_PY_COMPONENT} AND
+   TARGET Python2::ImathNumPy)
+  set(moddeps_p2 PyImath)
+  list(TRANSFORM moddeps_p2 APPEND ${PYIMATH_LIB_PYTHONVER_ROOT}${Python2_VERSION_MAJOR}_${Python2_VERSION_MINOR})
+  Python2_add_library(imathnumpy_python2 MODULE
+    imathnumpymodule.cpp
+  )
+  target_link_libraries(imathnumpy_python2
+    PRIVATE
+      Imath
+      ${moddeps_p2}
+      Python2::Python
+      Boost::${PYIMATH_BOOST_PY_COMPONENT}
+      Python2::ImathNumPy
+    )
+  set_target_properties(imathnumpy_python2 PROPERTIES
+    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python${Python2_VERSION_MAJOR}_${Python2_VERSION_MINOR}/"
+    LIBRARY_OUTPUT_NAME "imathnumpy"
+    DEBUG_POSTFIX ""
+  )
+  install(TARGETS imathnumpy_python2 DESTINATION ${PyImath_Python2_SITEARCH_REL})
+endif()
+
+if(TARGET Python3::Python AND
+   TARGET Boost::${PYIMATH_BOOST_PY_COMPONENT} AND
+   TARGET Python3::ImathNumPy)
+
+  set(moddeps_p3 PyImath)
+  list(TRANSFORM moddeps_p3 APPEND ${PYIMATH_LIB_PYTHONVER_ROOT}${Python3_VERSION_MAJOR}_${Python3_VERSION_MINOR})
+
+  Python3_add_library(imathnumpy_python3 MODULE
+    imathnumpymodule.cpp
+  )
+  target_link_libraries(imathnumpy_python3
+    PRIVATE
+      Imath
+      ${moddeps_p3}
+      Python3::Python
+      Boost::${PYIMATH_BOOST_PY_COMPONENT}
+      Python3::ImathNumPy
+    )
+  set_target_properties(imathnumpy_python3 PROPERTIES
+    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python${Python3_VERSION_MAJOR}_${Python3_VERSION_MINOR}/"
+    LIBRARY_OUTPUT_NAME "imathnumpy"
+    DEBUG_POSTFIX ""
+  )
+  install(TARGETS imathnumpy_python3 DESTINATION ${PyImath_Python3_SITEARCH_REL})
+endif()
diff --git a/src/python/PyImathNumpy/imathnumpymodule.cpp b/src/python/PyImathNumpy/imathnumpymodule.cpp
new file mode 100644 (file)
index 0000000..7cca301
--- /dev/null
@@ -0,0 +1,252 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+// clang-format off
+
+#include <Python.h>
+#include <boost/python.hpp>
+#include <PyImath.h>
+#include <PyImathVec.h>
+#include <PyImathColor.h>
+#include <iostream>
+#include <boost/format.hpp>
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+#include <numpy/arrayobject.h>
+
+using namespace boost::python;
+using namespace PyImath;
+
+template <typename T>
+struct Holder
+{
+    Holder( T &a ) : m_val( a ) {}
+    static void Cleanup (PyObject *capsule)
+    {
+        Holder* h = static_cast<Holder*> (PyCapsule_GetPointer (capsule, NULL));
+        delete h;
+    }
+    T m_val;
+};
+
+template <typename T>
+static void
+setBaseObject (PyObject* nparr, T& arr)
+{
+    using holder         = Holder<T>;
+
+    holder* ph = new holder (arr);
+    PyObject* capsule = PyCapsule_New (ph, NULL, holder::Cleanup);
+    PyArray_SetBaseObject ((PyArrayObject*) nparr, capsule);
+}
+
+template <typename T> struct NumpyTypeFromType       { BOOST_STATIC_CONSTANT(int, typeEnum=NPY_NOTYPE); };
+template <> struct NumpyTypeFromType<signed char>    { BOOST_STATIC_CONSTANT(int, typeEnum=NPY_INT8);   };
+template <> struct NumpyTypeFromType<unsigned char>  { BOOST_STATIC_CONSTANT(int, typeEnum=NPY_UINT8);  };
+template <> struct NumpyTypeFromType<short>          { BOOST_STATIC_CONSTANT(int, typeEnum=NPY_INT16);  };
+template <> struct NumpyTypeFromType<unsigned short> { BOOST_STATIC_CONSTANT(int, typeEnum=NPY_UINT16); };
+template <> struct NumpyTypeFromType<int>            { BOOST_STATIC_CONSTANT(int, typeEnum=NPY_INT32);  };
+template <> struct NumpyTypeFromType<unsigned int>   { BOOST_STATIC_CONSTANT(int, typeEnum=NPY_UINT32); };
+template <> struct NumpyTypeFromType<float>          { BOOST_STATIC_CONSTANT(int, typeEnum=NPY_FLOAT);  };
+template <> struct NumpyTypeFromType<double>         { BOOST_STATIC_CONSTANT(int, typeEnum=NPY_DOUBLE); };
+
+template <typename T> struct BaseTypeFrom2DArray       { typedef void type; };
+template <> struct BaseTypeFrom2DArray<IntArray2D>     { typedef int type; };
+template <> struct BaseTypeFrom2DArray<FloatArray2D>   { typedef float type; };
+template <> struct BaseTypeFrom2DArray<DoubleArray2D>  { typedef double type; };
+template <> struct BaseTypeFrom2DArray<Color4cArray>   { typedef IMATH_NAMESPACE::Color4c type; };
+template <> struct BaseTypeFrom2DArray<Color4fArray>   { typedef IMATH_NAMESPACE::Color4f type; };
+
+template <typename T>
+object 
+arrayToNumpy_scalar(T &sa)
+{
+    typedef typename T::BaseType PodType;
+
+    if (sa.stride() != 1)
+        throw std::logic_error("Unable to make numpy wrapping of strided arrays");
+
+    int type = NumpyTypeFromType<PodType>::typeEnum;
+    npy_intp dims = sa.len();
+    PodType *data = &sa[0];
+    PyObject *a = PyArray_SimpleNewFromData(1, &dims, type, data);
+
+    if (!a)
+        throw_error_already_set();
+
+    setBaseObject (a, sa);
+
+    object retval = object(handle<>(a));
+    return retval;
+}
+
+template<typename T>
+object 
+arrayToNumpy_vector(T &va)
+{
+    typedef typename T::BaseType        BaseType;
+    typedef typename BaseType::BaseType PodType;
+
+    if (va.stride() != 1)
+        throw std::logic_error("Unable to make numpy wrapping of strided arrays");
+
+    int type = NumpyTypeFromType<PodType>::typeEnum;
+    npy_intp dims[2]{ va.len(), BaseType::dimensions()};
+    PodType *data = &va[0][0];
+    PyObject *a = PyArray_SimpleNewFromData(2, dims, type, data);
+
+    if (!a)
+        throw_error_already_set();
+
+    setBaseObject (a, va);
+
+    object retval = object (handle<> (a));
+    return retval;
+}
+
+template<typename T>
+object 
+arrayToNumpy_scalar2D(T &ca)
+{
+    typedef typename BaseTypeFrom2DArray<T>::type PodType;
+
+    // Numpy is matrix indexed based - the first index indicates the row and
+    // the second index indicates the column.
+    // Zeno data is image indexed based - the first index indicates the column
+    // and the second indicates the row.
+    // Swap the dimensions so Numpy handles data natively with matrix based
+    // indexing.
+    IMATH_NAMESPACE::Vec2<size_t> len = ca.len();
+    int type = NumpyTypeFromType<PodType>::typeEnum;
+    npy_intp dims[2]{ static_cast<npy_intp>(len.y),
+                      static_cast<npy_intp>(len.x) };
+    PodType *data = &ca(0, 0);
+    PyObject *a = PyArray_SimpleNewFromData(2, dims, type, data);
+
+    if (!a)
+        throw_error_already_set();
+
+    setBaseObject (a, ca);
+
+    object retval = object(handle<>(a));
+    return retval;
+}
+
+template<typename T>
+object 
+arrayToNumpy_vector2D(T &ca)
+{
+    typedef typename BaseTypeFrom2DArray<T>::type BaseType;
+    typedef typename BaseType::BaseType           PodType;
+
+    // Numpy is matrix indexed based - the first index indicates the row and
+    // the second index indicates the column.
+    // Zeno data is image indexed based - the first index indicates the column
+    // and the second indicates the row.
+    // Swap the dimensions so Numpy handles data natively with matrix based
+    // indexing.
+    IMATH_NAMESPACE::Vec2<size_t> len = ca.len();
+    int type = NumpyTypeFromType<PodType>::typeEnum;
+    npy_intp dims[3]{ static_cast<npy_intp>(len.y),
+                      static_cast<npy_intp>(len.x),
+                      BaseType::dimensions() };
+    PodType *data = &ca(0, 0)[0];
+    PyObject *a = PyArray_SimpleNewFromData(3, dims, type, data);
+
+    if (!a)
+        throw_error_already_set();
+
+    setBaseObject (a, ca);
+
+    object retval = object(handle<>(a));
+    return retval;
+}
+
+#if PY_MAJOR_VERSION > 2
+static void *apply_import()
+{
+    import_array();
+    return 0;
+}
+#endif
+
+// Convenience macro for wrapping scalar PyImath array types.
+#define WRAP_SCALAR_ARRAY(ARRAY_TYPE)                                            \
+    def("arrayToNumpy", &arrayToNumpy_scalar<ARRAY_TYPE>,                        \
+        "arrayToNumpy(array) - wrap the given " #ARRAY_TYPE " as a numpy array", \
+        (arg("array")));
+#define WRAP_SCALAR_ARRAY_2D(ARRAY_TYPE)                                         \
+    def("arrayToNumpy", &arrayToNumpy_scalar2D<ARRAY_TYPE>,                      \
+        "arrayToNumpy(array) - wrap the given " #ARRAY_TYPE " as a numpy array", \
+        (arg("array")));
+
+// Convenience macro for wrapping vector PyImath array types.
+#define WRAP_VECTOR_ARRAY(ARRAY_TYPE)                                            \
+    def("arrayToNumpy", &arrayToNumpy_vector<ARRAY_TYPE>,                        \
+        "arrayToNumpy(array) - wrap the given " #ARRAY_TYPE " as a numpy array", \
+        (arg("array")));
+#define WRAP_VECTOR_ARRAY_2D(ARRAY_TYPE)                                         \
+    def("arrayToNumpy", &arrayToNumpy_vector2D<ARRAY_TYPE>,                      \
+        "arrayToNumpy(array) - wrap the given " #ARRAY_TYPE " as a numpy array", \
+        (arg("array")));
+
+BOOST_PYTHON_MODULE(imathnumpy)
+{
+    scope().attr("__doc__") = "Imathnumpy module";
+    scope().attr("__version__") = IMATH_VERSION_STRING;
+
+    handle<> imath(PyImport_ImportModule("imath"));
+    if (PyErr_Occurred()) throw_error_already_set();
+    scope().attr("imath") = imath;
+
+    handle<> numpy(PyImport_ImportModule("numpy"));
+    if (PyErr_Occurred()) throw_error_already_set();
+    scope().attr("numpy") = numpy;
+
+#if PY_MAJOR_VERSION > 2
+    // seems like numpy expects this to be used in a scenario
+    // where there is a return value in python3...
+    (void)apply_import();
+#else
+    import_array();
+#endif
+
+    scope().attr("__doc__") = "Array wrapping module to overlay imath array data with numpy arrays";
+
+    WRAP_SCALAR_ARRAY(SignedCharArray)
+    WRAP_SCALAR_ARRAY(UnsignedCharArray)
+    WRAP_SCALAR_ARRAY(ShortArray)
+    WRAP_SCALAR_ARRAY(UnsignedShortArray)
+    WRAP_SCALAR_ARRAY(IntArray)
+    WRAP_SCALAR_ARRAY(UnsignedIntArray)
+    WRAP_SCALAR_ARRAY(FloatArray)
+    WRAP_SCALAR_ARRAY(DoubleArray)
+
+    WRAP_VECTOR_ARRAY(V2sArray)
+    WRAP_VECTOR_ARRAY(V2iArray)
+    WRAP_VECTOR_ARRAY(V2fArray)
+    WRAP_VECTOR_ARRAY(V2dArray)
+
+    WRAP_VECTOR_ARRAY(V3sArray)
+    WRAP_VECTOR_ARRAY(V3iArray)
+    WRAP_VECTOR_ARRAY(V3fArray)
+    WRAP_VECTOR_ARRAY(V3dArray)
+
+    WRAP_VECTOR_ARRAY(V4sArray)
+    WRAP_VECTOR_ARRAY(V4iArray)
+    WRAP_VECTOR_ARRAY(V4fArray)
+    WRAP_VECTOR_ARRAY(V4dArray)
+
+    WRAP_VECTOR_ARRAY(C3cArray)
+    WRAP_VECTOR_ARRAY(C3fArray)
+    WRAP_VECTOR_ARRAY(C4cArray)
+    WRAP_VECTOR_ARRAY(C4fArray)
+
+    WRAP_SCALAR_ARRAY_2D(IntArray2D)
+    WRAP_SCALAR_ARRAY_2D(FloatArray2D)
+    WRAP_SCALAR_ARRAY_2D(DoubleArray2D)
+
+    WRAP_VECTOR_ARRAY_2D(Color4cArray)
+    WRAP_VECTOR_ARRAY_2D(Color4fArray)
+}
diff --git a/src/python/PyImathNumpyTest/CMakeLists.txt b/src/python/PyImathNumpyTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..44f6525
--- /dev/null
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+if(TARGET Python2::Interpreter)
+  add_test(PyImath.PyImathNumpyTest_Python2
+    ${Python2_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/pyImathNumpyTest.in
+  )
+  set_tests_properties(PyImath.PyImathNumpyTest_Python2 PROPERTIES
+    ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python${Python2_VERSION_MAJOR}_${Python2_VERSION_MINOR}"
+  )
+endif()
+
+if(TARGET Python3::Interpreter)
+  add_test(PyImath.PyImathNumpyTest_Python3
+    ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/pyImathNumpyTest.in
+  )
+  set_tests_properties(PyImath.PyImathNumpyTest_Python3 PROPERTIES
+    ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python${Python3_VERSION_MAJOR}_${Python3_VERSION_MINOR}"
+  )
+endif()
diff --git a/src/python/PyImathNumpyTest/pyImathNumpyTest.in b/src/python/PyImathNumpyTest/pyImathNumpyTest.in
new file mode 100755 (executable)
index 0000000..c6099a9
--- /dev/null
@@ -0,0 +1,440 @@
+#!@PYTHON@
+
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+#
+
+from imath import *
+
+import imathnumpy
+import numpy as np
+
+testList = []
+
+def numpyType(ia):
+    podTypeDict = {
+        SignedCharArray :    np.int8,
+        UnsignedCharArray :  np.uint8,
+        ShortArray :         np.int16,
+        UnsignedShortArray : np.uint16,
+        IntArray :           np.int32,
+        UnsignedIntArray :   np.uint32,
+        FloatArray :         np.float32,
+        DoubleArray :        np.float64,
+        V2sArray :           np.int16,
+        V2iArray :           np.int32,
+        V2fArray :           np.float32,
+        V2dArray :           np.float64,
+        V3sArray :           np.int16,
+        V3iArray :           np.int32,
+        V3fArray :           np.float32,
+        V3dArray :           np.float64,
+        V4sArray :           np.int16,
+        V4iArray :           np.int32,
+        V4fArray :           np.float32,
+        V4dArray :           np.float64,
+        C3cArray :           np.uint8,
+        C3fArray :           np.float32,
+        C4cArray :           np.uint8,
+        C4fArray :           np.float32,
+        IntArray2D :         np.int32,
+        FloatArray2D :       np.float32,
+        DoubleArray2D :      np.float64,
+        Color4cArray2D :     np.uint8,
+        Color4fArray2D :     np.float32,
+    }
+
+    return podTypeDict[type(ia)]
+
+def baseTypeSize(ia):
+    baseTypeSizeDict = {
+        SignedCharArray :    1,
+        UnsignedCharArray :  1,
+        ShortArray :         1,
+        UnsignedShortArray : 1,
+        IntArray :           1,
+        UnsignedIntArray :   1,
+        FloatArray :         1,
+        DoubleArray :        1,
+        V2sArray :           2,
+        V2iArray :           2,
+        V2fArray :           2,
+        V2dArray :           2,
+        V3sArray :           3,
+        V3iArray :           3,
+        V3fArray :           3,
+        V3dArray :           3,
+        V4sArray :           4,
+        V4iArray :           4,
+        V4fArray :           4,
+        V4dArray :           4,
+        C3cArray :           3,
+        C3fArray :           3,
+        C4cArray :           4,
+        C4fArray :           4,
+        Color4cArray2D :     4,
+        Color4fArray2D :     4
+    }
+
+    return baseTypeSizeDict[type(ia)]
+
+
+###############################################################################
+
+def testScalarArrayToNumpy():
+    '''
+    Tests the wrapping of PyImath scalar array types to numpy arrays.
+    '''
+    aDim = 20
+
+    # Test all supported array types
+    arrayTestTypes = [
+        SignedCharArray,
+        UnsignedCharArray,
+        ShortArray,
+        UnsignedShortArray,
+        IntArray,
+        UnsignedIntArray,
+        FloatArray,
+        DoubleArray]
+
+    for arrayType in arrayTestTypes:
+        print("\nTesting: %s conversion to numpy" % arrayType.__name__)
+
+        ia = arrayType(aDim)
+        refType  = numpyType(ia)
+        refShape = (aDim,)
+        
+        for i in range(aDim):
+            ia[i] = i
+        na = imathnumpy.arrayToNumpy(ia)
+        
+        print("%s == %s" % (str(na.dtype), str(refType)))
+        assert(na.dtype == refType)
+
+        print("%s == %s" % (str(na.shape), str(refShape)))
+        assert(na.shape == refShape)
+
+        for i in range(aDim):
+            assert(na[i] == ia[i])
+        print(na)
+
+testList.append(testScalarArrayToNumpy)
+
+###############################################################################
+
+def testVectorArrayToNumpy():
+    '''
+    Tests the wrapping of PyImath vector array types to numpy arrays.
+    '''
+    aDim = 20
+
+    # Test all supported array types
+    arrayTestTypes = [
+        V2sArray,
+        V2iArray,
+        V2fArray,
+        V2dArray,
+        V3sArray,
+        V3iArray,
+        V3fArray,
+        V3dArray,
+        V4sArray,
+        V4iArray,
+        V4fArray,
+        V4dArray,
+        C3cArray,
+        C3fArray,
+        C4cArray,
+        C4fArray]
+
+    for arrayType in arrayTestTypes:
+        print("\nTesting: %s conversion to numpy" % arrayType.__name__)
+
+        ia = arrayType(aDim)
+        refType         = numpyType(ia)
+        refBaseTypeSize = baseTypeSize(ia)
+        refShape        = (aDim, refBaseTypeSize)
+
+        for i in range(aDim):
+            for j in range(refBaseTypeSize):
+                ia[i][j] = i + 2 ** j
+        na = imathnumpy.arrayToNumpy(ia)
+        
+        print("%s == %s" % (str(na.dtype), str(refType)))
+        assert(na.dtype == refType)
+
+        print("%s == %s" % (str(na.shape), str(refShape)))
+        assert(na.shape == refShape)
+
+        for i in range(aDim):
+            for j in range(refBaseTypeSize):
+                assert(na[i][j] == ia[i][j])
+        print(na)
+
+testList.append(testVectorArrayToNumpy)
+
+###############################################################################
+
+def testScalarArray2DToNumpy():
+    '''
+    Tests the wrapping of PyImath scalar2D array types to numpy arrays.
+    '''
+    aDim1 = 10
+    aDim2 = 5
+
+    # Test all supported array types
+    arrayTestTypes = [
+        IntArray2D,
+        FloatArray2D,
+        DoubleArray2D]
+
+    for arrayType in arrayTestTypes:
+        print("\nTesting: %s conversion to numpy" % arrayType.__name__)
+
+        ia = arrayType(aDim1, aDim2)
+        refType  = numpyType(ia)
+        refShape = (aDim2, aDim1)
+
+        for y in range(aDim2):
+            for x in range(aDim1):
+                ia[(x, y)] = x + 2 * y
+        na = imathnumpy.arrayToNumpy(ia)
+
+        print("%s == %s" % (str(na.dtype), str(refType)))
+        assert(na.dtype == refType)
+
+        print("%s == %s" % (str(na.shape), str(refShape)))
+        assert(na.shape == refShape)
+
+        for y in range(aDim2):
+            for x in range(aDim1):
+                assert(na[y][x] == ia.item(x, y))
+        print(na)
+
+testList.append(testScalarArray2DToNumpy)
+
+###############################################################################
+
+def testVectorArray2DToNumpy():
+    '''
+    Tests the wrapping of PyImath vector2D array types to numpy arrays.
+    '''
+    aDim1 = 10
+    aDim2 = 5
+
+    # Test all supported array types
+    arrayTestTypes = [
+        Color4cArray2D,
+        Color4fArray2D]
+
+    for arrayType in arrayTestTypes:
+        print("\nTesting: %s conversion to numpy" % arrayType.__name__)
+
+        ia = arrayType(aDim1, aDim2)
+        refType         = numpyType(ia)
+        refBaseTypeSize = baseTypeSize(ia)
+        refShape        = (aDim2, aDim1, refBaseTypeSize)
+
+        for y in range(aDim2):
+            for x in range(aDim1):
+                for k in range(refBaseTypeSize):
+                    ia.item(x, y)[k] = x + 2 * y + k
+        na = imathnumpy.arrayToNumpy(ia)
+
+        print("%s == %s" % (str(na.dtype), str(refType)))
+        assert(na.dtype == refType)
+
+        print("%s == %s" % (str(na.shape), str(refShape)))
+        assert(na.shape == refShape)
+
+        for y in range(aDim2):
+            for x in range(aDim1):
+                for k in range(refBaseTypeSize):
+                    assert(na[y][x][k] == ia.item(x, y)[k])
+        print(na)
+
+testList.append(testVectorArray2DToNumpy)
+
+###############################################################################
+
+def testBufferProtocol():
+    '''
+    Numpy arrays and FixedArrays both now support the Python buffer protocol.
+    This test will exercise the FixedArray implementation of the protocol
+    against numpy arrays since only very limited testing of the protocol is
+    possible in PyImathTest .
+    '''
+    def verify (x, X, factor=1., shared=True):
+
+        assert (len(x) == len(X))
+        for i in range(10):
+            #  Make sure each element is the proper factor of the index, this
+            # will help make sure all the indexing and striding is correct.
+            assert (X[i] == i*factor)
+            assert (X[i] == x[i])
+        
+        #  Buffers can be shared, so modifying the imath array should also
+        # be operating on the numpy array...
+        for i in range(10):
+            x[i] *= 10
+        for i in range(10):
+            assert ((shared and (X[i] == x[i])) or (not shared and (X[i]*10 == x[i])))
+
+
+    def verifyVector (v, V, cloned=False):
+
+        assert (len(v) == len(V))
+        for i in range(10):
+            assert (len(v[i]) == len(V[i]))
+            for j in range(len(v[i])): 
+                assert (V[i][j] == v[i][j])
+        
+        #  Buffers should be shared, so modifying the imath array should also
+        # be operating on the numpy array...
+        for i in range(10):
+            v[i] *= 10
+        for i in range(10):
+            for j in range(len(v[i])): 
+                assert ((not cloned and (V[i][j] == v[i][j])) or (cloned and (V[i][j]*10 == v[i][j])))
+
+        #  Verify that imath striding is properly mapped to numpy...
+        # Note that we modified the elements by a factor of 10 above, so when
+        # we check each element against the index we need to account for this.
+        Vx = np.asarray (v.x)
+        Vy = np.asarray (v.y)
+        if cloned:
+            # Factors will have already been applied...
+            factor = 1000.
+        else:
+            factor = 10.
+        verify (v.x, Vx, factor, shared=True)
+        verify (v.y, Vy, factor*10., shared=True)
+
+        if (len(v[0]) == 3):
+            Vz = np.asarray (v.z)
+            verify (v.z, Vz, factor*10.*10., shared=True)
+
+    # .........................................................................
+
+    a = UnsignedCharArray (10)
+    for i in range(10):
+        a[i] = i
+    aNP = np.asarray (a)
+    verify (a, aNP)
+
+    a = IntArray (10)
+    for i in range(10):
+        a[i] = i
+    aNP = np.asarray (a)
+    verify (a, aNP)
+
+    #  Use the BufferProtocol to construct a deepcopy of the numpy
+    # array as a FixedArray.
+    aNPclone = IntArrayFromBuffer (aNP)
+    verify (aNPclone, aNP, factor=10., shared=False)
+
+    a = FloatArray (10)
+    for i in range(10):
+        a[i] = float(i)
+    aNP = np.asarray (a)
+    verify (a, aNP)
+    
+    #  Use the BufferProtocol to construct a deepcopy of the numpy
+    # array as a FixedArray.
+    aNPclone = FloatArrayFromBuffer (aNP)
+    verify (aNPclone, aNP, factor=10., shared=False)
+
+    a = DoubleArray (10)
+    for i in range(10):
+        a[i] = float(i)
+    aNP = np.asarray (a)
+    verify (a, aNP)
+    
+    #  Use the BufferProtocol to construct a deepcopy of the numpy
+    # array as a FixedArray.
+    aNPclone = DoubleArrayFromBuffer (aNP)
+    verify (aNPclone, aNP, factor=10., shared=False)
+
+    v = V2iArray (10)
+    for i in range(10):
+        v[i] = V2i (i,i*10)
+    vNP = np.asarray (v)
+    verifyVector (v, vNP)
+
+    #  Use the BufferProtocol to construct a deepcopy of the numpy
+    # array as a FixedArray.
+    vNPclone = V2iArrayFromBuffer (vNP)
+    verifyVector (vNPclone, vNP, cloned=True)
+
+    v = V2fArray (10)
+    for i in range(10):
+        v[i] = V2f (i,i*10)
+    vNP = np.asarray (v)
+    verifyVector (v, vNP)
+
+    #  Use the BufferProtocol to construct a deepcopy of the numpy
+    # array as a FixedArray.
+    vNPclone = V2fArrayFromBuffer (vNP)
+    verifyVector (vNPclone, vNP, cloned=True)
+
+    v = V2dArray (10)
+    for i in range(10):
+        v[i] = V2d (i,i*10)
+    vNP = np.asarray (v)
+    verifyVector (v, vNP)
+
+    #  Use the BufferProtocol to construct a deepcopy of the numpy
+    # array as a FixedArray.
+    vNPclone = V2dArrayFromBuffer (vNP)
+    verifyVector (vNPclone, vNP, cloned=True)
+
+    v = V3iArray (10)
+    for i in range(10):
+        v[i] = V3i (i,i*10,i*100)
+    vNP = np.asarray (v)
+    verifyVector (v, vNP)
+
+    #  Use the BufferProtocol to construct a deepcopy of the numpy
+    # array as a FixedArray.
+    vNPclone = V3iArrayFromBuffer (vNP)
+    verifyVector (vNPclone, vNP, cloned=True)
+
+    v = V3fArray (10)
+    for i in range(10):
+        v[i] = V3f (i,i*10,i*100)
+    vNP = np.asarray (v)
+    verifyVector (v, vNP)
+
+    #  Use the BufferProtocol to construct a deepcopy of the numpy
+    # array as a FixedArray.
+    vNPclone = V3fArrayFromBuffer (vNP)
+    verifyVector (vNPclone, vNP, cloned=True)
+
+    v = V3dArray (10)
+    for i in range(10):
+        v[i] = V3d (i,i*10,i*100)
+    vNP = np.asarray (v)
+    verifyVector (v, vNP)
+
+    #  Use the BufferProtocol to construct a deepcopy of the numpy
+    # array as a FixedArray.
+    vNPclone = V3dArrayFromBuffer (vNP)
+    verifyVector (vNPclone, vNP, cloned=True)
+
+testList.append (testBufferProtocol)
+
+# -------------------------------------------------------------------------
+# Main loop
+
+for test in testList:
+    print("")
+    print("Running %s" % test.__name__)
+    test()
+
+print("done.")
+
+# Local Variables:
+# mode:python
+# End:
diff --git a/src/python/PyImathSpeedTest/CMakeLists.txt b/src/python/PyImathSpeedTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..546f9d8
--- /dev/null
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+# Speed tests are not performed in Python2 as getting acurate time is difficult.
+# set -DSPEED=ON when running cmake to perform these tests.
+if(TARGET Python3::Interpreter AND SPEED) 
+  add_test(PyImath.PyImathSpeedTest_Python3
+    ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/pyImathSpeedTest.in
+    )
+  set_tests_properties(PyImath.PyImathSpeedTest_Python3 PROPERTIES
+    ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python${Python3_VERSION_MAJOR}_${Python3_VERSION_MINOR}"
+    )
+endif()
diff --git a/src/python/PyImathSpeedTest/pyImathSpeedTest.in b/src/python/PyImathSpeedTest/pyImathSpeedTest.in
new file mode 100755 (executable)
index 0000000..2014f86
--- /dev/null
@@ -0,0 +1,247 @@
+#!@PYTHON@
+
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+import random
+import sys
+import time
+import numpy as np
+
+from imath import *
+
+X = 1000000
+f = open("time_trials.csv", "a")
+all_tests = {}
+
+def time_operation(func):
+    tested_inputs = all_tests[func]
+    for tested_input in tested_inputs:
+        arg_string = ""
+        for arg in tested_input:
+            arg_string += type(arg).__name__ + " "
+        f.write(func.__name__+": "+arg_string) # generates unique description
+        start_time = time.clock_gettime(4)
+        func(tested_input)
+        f.write(","+repr(time.clock_gettime(4) - start_time)+"\n")
+
+#MULTIPLICAITON TESTING
+
+def time_multVecMatrix(test_input):
+    mat = test_input[0]
+    vArray = test_input[1]
+    x = mat.multVecMatrix(vArray)
+
+def time_multDirMatrix(test_input):
+    mat = test_input[0]
+    vArray = test_input[1]
+    x = mat.multDirMatrix(vArray)
+
+m44f = M44f(5,6,6,8, 2,2,2,8, 6,6,2,8, 2,3,6,7)
+v3fa = V3fArray(X)
+v3fa[:] = V3f(1,1,1)
+
+m33f = M33f(5,6,6, 2,2,2, 6,6,2)
+v2fa = V2fArray(X)
+v2fa[:] = V2f(1,1)
+
+m44d = M44d(5,6,6,8, 2,2,2,8, 6,6,2,8, 2,3,6,7)
+v3da = V3dArray(X)
+v3da[:] = V3d(1,1,1)
+
+m33d = M33d(1,0,5, 2,1,6, 3,4,0)
+v2da = V2dArray(X)
+v2da[:] = V2d(1,1)
+
+tests_multMatrix = [[m44f, v3fa],
+                    [m33f, v2fa],
+                    [m44d, v3da],
+                    [m33d, v2da]]
+
+all_tests[time_multVecMatrix] = tests_multMatrix
+all_tests[time_multDirMatrix] = tests_multMatrix
+
+#INVERT TESTING
+   
+def time_inverse(test_input):
+    mata = test_input[0]
+    x = mata.inverse()
+    
+def time_invert(test_input):
+    mata = test_input[0]
+    mata.invert()
+
+def time_gjInverse(test_input):
+    mata = test_input[0]
+    x = mata.gjInverse()
+
+def time_gjInvert(test_input):
+    mata = test_input[0]
+    mata.gjInvert()
+
+
+m22f = M22f(4.0,7.0, 2.0,6.0)
+m22d = M22d(4.0,7.0, 2.0,6.0)
+
+m22fa = M22fArray(X)
+m22fa[:] = m22f
+m22da = M22dArray(X)
+m22da[:] = m22d
+m33fa = M33fArray(X)
+m33fa[:] = m33f
+m33da = M33dArray(X)
+m33da[:] = m33d
+m44fa = M44fArray(X)
+m44fa[:] = m44f
+m44da = M44dArray(X)
+m44da[:] = m44d
+
+tests_inver = [[m44fa],
+               [m33fa],
+               [m22fa],
+               [m44da],
+               [m33da],
+               [m22da]]
+
+tests_gjInver = [[m44fa],
+                 [m33fa],
+                 [m44da],
+                 [m33da]]
+
+all_tests[time_inverse] = tests_inver
+all_tests[time_invert] = tests_inver
+all_tests[time_gjInverse] = tests_gjInver
+all_tests[time_gjInvert] = tests_gjInver
+
+# NORMALIZE TEST
+
+def time_normalize(test_input):
+    vArray = test_input[0]
+    vArray.normalize()
+
+def time_normalizeExc(test_input):
+    vArray = test_input[0]
+    vArray.normalizeExc()
+
+def time_normalized(test_input):
+    vArray = test_input[0]
+    x = vArray.normalized()
+
+def time_normalizedExc(test_input):    
+    vArray = test_input[0]
+    x = vArray.normalizedExc()
+
+v4fa = V4fArray(X)
+v4fa[:] = V4f(1,1,1,1)
+
+v4da = V4dArray(X)
+v4da[:] = V4d(1,1,1,1)
+
+tests_normalize = [[v2fa],
+                   [v2da],
+                   [v3fa],
+                   [v3da],
+                   [v4fa],
+                   [v4da]]
+
+all_tests[time_normalize] = tests_normalize
+all_tests[time_normalizeExc] = tests_normalize
+all_tests[time_normalized] = tests_normalize
+all_tests[time_normalizedExc] = tests_normalize
+
+# SHEAR TEST
+
+def time_shear(test_input):
+    mat = test_input[0]
+    shear_in = test_input[1]
+    for i in range(0,X):
+        x = mat.shear(shear_in)
+    
+all_tests[time_shear] = [[m44f, (1,2,3)],
+                         [m44d, (1,2,3)],
+                         [m33f, (1,2)],
+                         [m33d, (1,2)],
+                         [m44f, V3f(1,2,3)],
+                         [m44d, V3d(1,2,3)],
+                         [m33f, V2f(1,2)],
+                         [m33d, V2d(1,2)]]
+#TODO: add Shear6<T>
+
+# SCALE TEST
+
+def time_scale(test_input):
+    mat = test_input[0]
+    scale_in = test_input[1]
+    for i in range(0,X):
+        x = mat.scale(scale_in)
+        #TODO: determine significance of Python bytcode impact on speed
+
+all_tests[time_scale] = [[m44f, 2.0],
+                         [m44d, 2.0],
+                         [m33f, 2.0],
+                         [m33d, 2.0],
+                         [m22f, 2.0],
+                         [m22d, 2.0]]
+
+# TRANSLATION TEST
+
+def time_translate(test_input):
+    mat = test_input[0]
+    trans_in = test_input[1]
+    for i in range(0,X):
+        x = mat.translate(trans_in)
+    
+all_tests[time_translate] = [[m44f, V3f(1,1,1)],
+                             [m44d, V3d(1,1,1)],
+                             [m33f, V2f(1,1)],
+                             [m33d, V2d(1,1)]]
+
+# FRUSTUM TEST
+
+def time_frustum_init(description, parameters):
+    f.write(description)
+    start_time = time.clock_gettime(4)
+    for i in range(0,X):
+        x = Frustum(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4])
+    f.write(","+repr(time.clock_gettime(4) - start_time)+"\n")
+#UNIMPLEMENTED 
+    
+for func in all_tests:
+    time_operation(func)
+
+"""
+def time_NOARRAYvec(test_input):
+    mat = test_input[0]
+    vec = test_input[1]
+    for i in range(0, X):
+        x = mat.multVecMatrix(vec)
+    
+def time_NOARRAYdir(test_input):
+    mat = test_input[0]
+    vec = test_input[1]
+    for i in range(0, X):
+        x = mat.multDirMatrix(vec)
+    
+m44f = M44f(5,6,6,8, 2,2,2,8, 6,6,2,8, 2,3,6,7)
+v3f = V3f(1,1,1)
+
+m33f = M33f(5,6,6, 2,2,2, 6,6,2)
+v2f = V2f(1,1)
+
+m44d = M44d(5,6,6,8, 2,2,2,8, 6,6,2,8, 2,3,6,7)
+v3d = V3d(1,1,1)
+
+m33d = M33d(1,0,5, 2,1,6, 3,4,0)
+v2d = V2d(1,1)
+
+tests_multMatrix = [[m44f, v3f],
+                    [m33f, v2f],
+                    [m44d, v3d],
+                    [m33d, v2d]]
+add_tests = {}
+add_tests[time_NOARRAYvec] = tests_multMatrix
+add_tests[time_NOARRAYdir] = tests_multMatrix
+
+for func in add_tests:
+    time_operation(func)
+"""
diff --git a/src/python/PyImathTest/CMakeLists.txt b/src/python/PyImathTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3758faf
--- /dev/null
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+if(TARGET Python2::Interpreter)
+  add_test(PyImath.PyImathTest_Python2
+    ${Python2_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/pyImathTest.in
+  )
+  set_tests_properties(PyImath.PyImathTest_Python2 PROPERTIES
+    ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python${Python2_VERSION_MAJOR}_${Python2_VERSION_MINOR}"
+  )
+endif()
+
+if(TARGET Python3::Interpreter)
+  add_test(PyImath.PyImathTest_Python3
+    ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/pyImathTest.in
+  )
+  set_tests_properties(PyImath.PyImathTest_Python3 PROPERTIES
+    ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python${Python3_VERSION_MAJOR}_${Python3_VERSION_MINOR}"
+  )
+
+  add_executable(PyImathTestC main.cpp testStringTable.cpp)
+
+  target_link_libraries(PyImathTestC 
+        Imath::Config
+        Imath::PyImath_Python${Python_VERSION_MAJOR}_${Python_VERSION_MINOR}
+        Python3::Python
+        Boost::${PYIMATH_BOOST_PY_COMPONENT})
+  set_target_properties(PyImathTestC PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+    )
+
+  add_test(NAME Imath.PyImathTestC COMMAND $<TARGET_FILE:PyImathTestC>)
+  set(PYTHONPATH ${CMAKE_BINARY_DIR}/python${Python_VERSION_MAJOR}_${Python_VERSION_MINOR})
+  set_tests_properties(Imath.PyImathTestC PROPERTIES ENVIRONMENT PYTHONPATH=${PYTHONPATH})
+  
+endif()
+  
diff --git a/src/python/PyImathTest/main.cpp b/src/python/PyImathTest/main.cpp
new file mode 100644 (file)
index 0000000..b2b133e
--- /dev/null
@@ -0,0 +1,2355 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <boost/python.hpp>
+#include <boost/python/handle.hpp>
+#include <boost/python/object.hpp>
+#include <ImathMath.h>
+#include <PyImathBox.h>
+#include <PyImathColor.h>
+#include <PyImathEuler.h>
+#include <PyImathFrustum.h>
+#include <PyImathLine.h>
+#include <PyImathMatrix.h>
+#include <PyImathPlane.h>
+#include <PyImathQuat.h>
+#include <PyImathRandom.h>
+#include <PyImathVec.h>
+#include <PyImathShear.h>
+
+#include <testStringTable.h>
+
+using namespace boost::python;
+
+#define TEST(x) if (argc < 2 || !strcmp (argv[1], #x)) x();
+
+PyObject *
+wrapTester (PyObject * /* self */, PyObject *args)
+{
+    try {
+        
+        char *type;
+        if (PyArg_ParseTuple (args, "s", &type))
+        {
+            std::string typeStr (type);
+
+            if (typeStr == "Box2i")
+                return PyImath::Box2i::wrap (Imath::Box2i (Imath::V2i (1, 2), 
+                                                           Imath::V2i (3, 4)));
+            else if (typeStr == "Box2f")
+                return PyImath::Box2f::wrap (Imath::Box2f (Imath::V2f (1.1f, 2.2f), 
+                                                           Imath::V2f (3.3f, 4.4f)));
+            else if (typeStr == "Box2d")
+                return PyImath::Box2d::wrap (Imath::Box2d (Imath::V2d (1.1, 2.2), 
+                                                           Imath::V2d (3.3, 4.4)));
+
+            if (typeStr == "Box3i")
+                return PyImath::Box3i::wrap (Imath::Box3i (Imath::V3i (1, 2, 3), 
+                                                           Imath::V3i (4, 5, 6)));
+            else if (typeStr == "Box3f")
+                return PyImath::Box3f::wrap (Imath::Box3f (Imath::V3f (1.1f, 2.2f, 3.3f), 
+                                                           Imath::V3f (4.4f, 5.5f, 6.6f)));
+            else if (typeStr == "Box3d")
+                return PyImath::Box3d::wrap (Imath::Box3d (Imath::V3d (1.1, 2.2, 3.3), 
+                                                           Imath::V3d (4.4, 5.5, 6.6)));
+
+            else if (typeStr == "Color3c")
+                return PyImath::Color3c::wrap (Imath::Color3c (1, 2, 3));
+            else if (typeStr == "Color3f")
+                return PyImath::Color3f::wrap (Imath::Color3f (1.1f, 2.2f, 3.3f));
+
+            else if (typeStr == "Color4c")
+                return PyImath::Color4c::wrap (Imath::Color4c (1, 2, 3, 4));
+            else if (typeStr == "Color4f")
+                return PyImath::Color4f::wrap (Imath::Color4f (1.1f, 2.2f, 3.3f, 4.4f));
+
+            else if (typeStr == "Eulerf")
+                return PyImath::Eulerf::wrap (Imath::Eulerf (Imath::V3f (1.1f, 2.2f, 3.3f), 
+                                                             Imath::Eulerf::XZY));
+            else if (typeStr == "Eulerd")
+                return PyImath::Eulerd::wrap (Imath::Eulerd (Imath::V3d (1.1f, 2.2f, 3.3f), 
+                                                             Imath::Eulerd::XZY));
+
+            else if (typeStr == "Frustumf")
+                return PyImath::Frustumf::wrap (Imath::Frustumf (1.1f, 2.2f, 3.3f,
+                                                                 4.4f, 5.5f, 6.6f));
+            else if (typeStr == "Frustumd")
+                return PyImath::Frustumd::wrap (Imath::Frustumd (1.1, 2.2, 3.3,
+                                                                 4.4, 5.5, 6.6));
+
+            else if (typeStr == "Line3f")
+                return PyImath::Line3f::wrap (Imath::Line3f (Imath::V3f (1.1f, 2.2f, 3.3f),
+                                                             Imath::V3f (4.4f, 5.5f, 6.6f)));
+            else if (typeStr == "Line3d")
+                return PyImath::Line3d::wrap (Imath::Line3d (Imath::V3d (1.1, 2.2, 3.3),
+                                                             Imath::V3d (4.4, 5.5, 6.6)));
+
+            else if (typeStr == "M33f")
+                return PyImath::M33f::wrap (Imath::M33f (1.1f, 2.2f, 3.3f,
+                                                         4.4f, 5.5f, 6.6f,
+                                                         7.7f, 8.8f, 9.9f));
+            else if (typeStr == "M33d")
+                return PyImath::M33d::wrap (Imath::M33d (1.1, 2.2, 3.3,
+                                                         4.4, 5.5, 6.6,
+                                                         7.7, 8.8, 9.9));
+
+            else if (typeStr == "M44f")
+                return PyImath::M44f::wrap (Imath::M44f (1.1f, 2.2f, 3.3f, 4.4f,
+                                                         5.5f, 6.6f, 7.7f, 8.8f, 
+                                                         9.9f, 10.10f, 11.11f, 12.12f,
+                                                         13.13f, 14.14f, 15.15f, 16.16f));
+            else if (typeStr == "M44d")
+                return PyImath::M44d::wrap (Imath::M44d (1.1, 2.2, 3.3, 4.4,
+                                                         5.5, 6.6, 7.7, 8.8, 
+                                                         9.9, 10.10, 11.11, 12.12,
+                                                         13.13, 14.14, 15.15, 16.16));
+
+            else if (typeStr == "Plane3f")
+                return PyImath::Plane3f::wrap (Imath::Plane3f (Imath::V3f (1.1f, 2.2f, 3.3f), 4.4f));
+            else if (typeStr == "Plane3d")
+                return PyImath::Plane3d::wrap (Imath::Plane3d (Imath::V3d (1.1, 2.2, 3.3), 4.4));
+
+            else if (typeStr == "Quatf")
+                return PyImath::Quatf::wrap (Imath::Quatf (1.1f, 2.2f, 3.3f, 4.4f));
+            else if (typeStr == "Quatd")
+                return PyImath::Quatd::wrap (Imath::Quatd (1.1, 2.2, 3.3, 4.4));
+
+            else if (typeStr == "Rand32")
+                return PyImath::Rand32::wrap (Imath::Rand32 ());
+            else if (typeStr == "Rand48")
+                return PyImath::Rand48::wrap (Imath::Rand48 ());
+
+            else if (typeStr == "Shear6f")
+                return PyImath::Shear6f::wrap (Imath::Shear6f (1.1f, 2.2f, 3.3f,
+                                                               4.4f, 5.5f, 6.6f));
+            else if (typeStr == "Shear6d")
+                return PyImath::Shear6d::wrap (Imath::Shear6d (1.1, 2.2, 3.3,
+                                                               4.4, 5.5, 6.6));
+
+            else if (typeStr == "V2i")
+                return PyImath::V2i::wrap (Imath::V2i (1, 2));
+            else if (typeStr == "V2f")
+                return PyImath::V2f::wrap (Imath::V2f (1.1f, 2.2f));
+            else if (typeStr == "V2d")
+                return PyImath::V2d::wrap (Imath::V2d (1.1, 2.2));
+
+            else if (typeStr == "V3i")
+                return PyImath::V3i::wrap (Imath::V3i (1, 2, 3));
+            else if (typeStr == "V3f")
+                return PyImath::V3f::wrap (Imath::V3f (1.1f, 2.2f, 3.3f));
+            else if (typeStr == "V3d")
+                return PyImath::V3d::wrap (Imath::V3d (1.1, 2.2, 3.3));
+        }
+        PyErr_Clear();
+
+        PyErr_SetString(PyExc_TypeError, "wrap testing failed");
+    }
+    catch (const boost::python::error_already_set& e)  \
+    {                                                  \
+       return 0;                                       \
+    }                                                  \
+    catch (...)                                                \
+    {                                                  \
+       boost::python::handle_exception();              \
+       return 0;                                       \
+    }
+
+    return 0;
+}
+
+PyMethodDef methods[] =
+{
+    {"wrap", (PyCFunction) wrapTester, METH_VARARGS, ""}, {0, 0}
+};
+
+void
+initWrapTester ()
+{
+#if PY_MAJOR_VERSION >= 3
+    static struct PyModuleDef moduleDef =
+        {
+            PyModuleDef_HEAD_INIT,
+            "wrap",
+            "wrap module",
+            -1,
+            methods
+        };
+
+    PyObject* module   = PyModule_Create(&moduleDef);
+    assert (module != 0);
+    // I (jyost) don't know if there's a better way to do the following,
+    // but this works.  (I did look at the docs and try various things to
+    // see if I could find a better way, and this is what I landed on.)
+    auto sysModule     = PyImport_AddModule("sys");
+    auto sysModuleDict = PyModule_GetDict(sysModule);
+    auto modulesDict   = PyDict_GetItemString(sysModuleDict, "modules");
+    PyDict_SetItemString(modulesDict, moduleDef.m_name, module);
+#else
+    PyObject *module = Py_InitModule ("wrap", methods);
+    assert (module != 0);
+#endif
+}
+
+
+void
+testBox2 ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing Box2*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "b2i = Box2i ((1, 2), (3, 4))\n"
+        "b2f = Box2f ((5.5, 6.6), (7.7, 8.8))\n"
+        "b2d = Box2d ((9.9, 10.10), (11.11, 12.12))\n"
+        "t2i = ((1, 2), (3, 4))\n"
+        "t2V2i = (V2i (1, 2), V2i (3, 4))\n"
+        "t2iMix = (V2i (1, 2), (3, 4))\n"
+        "t2f = ((5.5, 6.6), (7.7, 8.8))\n"
+        "t2V2f = (V2f (5.5, 6.6), V2f (7.7, 8.8))\n"
+        "t2fMix = (V2f (5.5, 6.6), (7.7, 8.8))\n"
+        "t2V2d = (V2d (9.9, 10.10), V2d (11.11, 12.12))\n"
+        "t2dMix = (V2d (9.9, 10.10), (11.11, 12.12))\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('Box2i')\n"
+        "assert w == Box2i ((1, 2), (3, 4))\n"
+        "w = wrap ('Box2f')\n"
+        "assert w.min().equalWithAbsError ((1.1, 2.2), 1e-7)\n"
+        "assert w.max().equalWithAbsError ((3.3, 4.4), 1e-7)\n"
+        "w = wrap ('Box2d')\n"
+        "assert w.min().equalWithAbsError ((1.1, 2.2), 1e-7)\n"
+        "assert w.max().equalWithAbsError ((3.3, 4.4), 1e-7)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+    //
+
+    extract <object> eb2i (mainNamespace ["b2i"]);
+    assert (eb2i.check());
+    
+    PyObject *b2iObj = eb2i().ptr();
+    assert (b2iObj != 0);
+
+    extract <object> eb2f (mainNamespace ["b2f"]);
+    assert (eb2f.check());
+    
+    PyObject *b2fObj = eb2f().ptr();
+    assert (b2fObj != 0);
+
+    extract <object> eb2d (mainNamespace ["b2d"]);
+    assert (eb2d.check());
+    
+    PyObject *b2dObj = eb2d().ptr();
+    assert (b2dObj != 0);
+
+    extract <object> et2i (mainNamespace["t2i"]);
+    assert (et2i.check());
+
+    PyObject *t2iObj = et2i().ptr();
+    assert (t2iObj != 0);
+
+    extract <object> et2V2i (mainNamespace["t2V2i"]);
+    assert (et2V2i.check());
+
+    PyObject *t2V2iObj = et2V2i().ptr();
+    assert (t2V2iObj != 0);
+
+    extract <object> et2iMix (mainNamespace["t2iMix"]);
+    assert (et2iMix.check());
+
+    PyObject *t2iMixObj = et2iMix().ptr();
+    assert (t2iMixObj != 0);
+
+    extract <object> et2f (mainNamespace["t2f"]);
+    assert (et2f.check());
+
+    PyObject *t2fObj = et2f().ptr();
+    assert (t2fObj != 0);
+
+    extract <object> et2V2f (mainNamespace["t2V2f"]);
+    assert (et2V2f.check());
+
+    PyObject *t2V2fObj = et2V2f().ptr();
+    assert (t2V2fObj != 0);
+
+    extract <object> et2fMix (mainNamespace["t2fMix"]);
+    assert (et2fMix.check());
+
+    PyObject *t2fMixObj = et2fMix().ptr();
+    assert (t2fMixObj != 0);
+
+    extract <object> et2V2d (mainNamespace["t2V2d"]);
+    assert (et2V2d.check());
+
+    PyObject *t2V2dObj = et2V2d().ptr();
+    assert (t2V2dObj != 0);
+
+    extract <object> et2dMix (mainNamespace["t2dMix"]);
+    assert (et2dMix.check());
+
+    PyObject *t2dMixObj = et2dMix().ptr();
+    assert (t2dMixObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+
+    std::cerr << "Testing Box2i:\n";
+
+    Imath::Box2i b2iAsB2i;
+    assert (PyImath::Box2i::convert (b2iObj, &b2iAsB2i) == 1);
+    assert (b2iAsB2i == Imath::Box2i (Imath::V2i (1, 2), 
+                                      Imath::V2i (3, 4)));
+
+    Imath::Box2i b2fAsB2i;
+    assert (PyImath::Box2i::convert (b2fObj, &b2fAsB2i) == 1);
+    assert (b2fAsB2i == Imath::Box2i (Imath::V2i (5, 6),
+                                      Imath::V2i (7, 8)));
+
+    Imath::Box2i b2dAsB2i;
+    assert (PyImath::Box2i::convert (b2dObj, &b2dAsB2i) == 1);
+    assert (b2dAsB2i == Imath::Box2i (Imath::V2i (9, 10),
+                                      Imath::V2i (11, 12)));
+
+    Imath::Box2i t2iAsB2i;
+    assert (PyImath::Box2i::convert (t2iObj, &t2iAsB2i) == 1);
+    assert (t2iAsB2i == Imath::Box2i (Imath::V2i (1, 2), 
+                                      Imath::V2i (3, 4)));
+
+    Imath::Box2i t2V2iAsB2i;
+    assert (PyImath::Box2i::convert (t2V2iObj, &t2V2iAsB2i) == 1);
+    assert (t2V2iAsB2i == Imath::Box2i (Imath::V2i (1, 2), 
+                                        Imath::V2i (3, 4)));
+
+    Imath::Box2i t2iMixAsB2i;
+    assert (PyImath::Box2i::convert (t2iMixObj, &t2iMixAsB2i) == 1);
+    assert (t2iMixAsB2i == Imath::Box2i (Imath::V2i (1, 2), 
+                                         Imath::V2i (3, 4)));
+
+    Imath::Box2i t2fAsB2i;
+    assert (PyImath::Box2i::convert (t2fObj, &t2fAsB2i) == 1);
+    assert (t2fAsB2i == Imath::Box2i (Imath::V2i (5, 6), 
+                                      Imath::V2i (7, 8)));
+
+    Imath::Box2i t2V2fAsB2i;
+    assert (PyImath::Box2i::convert (t2V2fObj, &t2V2fAsB2i) == 1);
+    assert (t2V2fAsB2i == Imath::Box2i (Imath::V2i (5, 6),
+                                        Imath::V2i (7, 8)));
+
+    Imath::Box2i t2fMixAsB2i;
+    assert (PyImath::Box2i::convert (t2fMixObj, &t2fMixAsB2i) == 1);
+    assert (t2fMixAsB2i == Imath::Box2i (Imath::V2i (5, 6), 
+                                         Imath::V2i (7, 8)));
+
+    Imath::Box2i t2V2dAsB2i;
+    assert (PyImath::Box2i::convert (t2V2dObj, &t2V2dAsB2i) == 1);
+    assert (t2V2dAsB2i == Imath::Box2i (Imath::V2i (9, 10),
+                                        Imath::V2i (11, 12)));
+
+    Imath::Box2i t2dMixAsB2i;
+    assert (PyImath::Box2i::convert (t2dMixObj, &t2dMixAsB2i) == 1);
+    assert (t2dMixAsB2i == Imath::Box2i (Imath::V2i (9, 10),
+                                         Imath::V2i (11, 12)));
+
+    Imath::Box2i iAsB2i;
+    assert (PyImath::Box2i::convert (iObj, &iAsB2i) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing Box2f:\n";
+
+    Imath::Box2f b2iAsB2f;
+    assert (PyImath::Box2f::convert (b2iObj, &b2iAsB2f) == 1);
+    assert (b2iAsB2f.min.equalWithAbsError (Imath::V2f (1.0f, 2.0f), 1e-7));
+    assert (b2iAsB2f.max.equalWithAbsError (Imath::V2f (3.0f, 4.0f), 1e-7));
+
+    Imath::Box2f b2fAsB2f;
+    assert (PyImath::Box2f::convert (b2fObj, &b2fAsB2f) == 1);
+    assert (b2fAsB2f.min.equalWithAbsError (Imath::V2f (5.5f, 6.6f), 1e-7));
+    assert (b2fAsB2f.max.equalWithAbsError (Imath::V2f (7.7f, 8.8f), 1e-7));
+
+    Imath::Box2f b2dAsB2f;
+    assert (PyImath::Box2f::convert (b2dObj, &b2dAsB2f) == 1);
+    assert (b2dAsB2f.min.equalWithAbsError (Imath::V2f (9.9f, 10.10f), 1e-7));
+    assert (b2dAsB2f.max.equalWithAbsError (Imath::V2f (11.11f, 12.12f), 1e-7));
+
+    Imath::Box2f t2iAsB2f;
+    assert (PyImath::Box2f::convert (t2iObj, &t2iAsB2f) == 1);
+    assert (t2iAsB2f.min.equalWithAbsError (Imath::V2f (1.0f, 2.0f), 1e-7)); 
+    assert (t2iAsB2f.max.equalWithAbsError (Imath::V2f (3.0f, 4.0f), 1e-7)); 
+
+    Imath::Box2f t2V2iAsB2f;
+    assert (PyImath::Box2f::convert (t2V2iObj, &t2V2iAsB2f) == 1);
+    assert (t2V2iAsB2f.min.equalWithAbsError (Imath::V2f (1.0f, 2.0f), 1e-7));
+    assert (t2V2iAsB2f.max.equalWithAbsError (Imath::V2f (3.0f, 4.0f), 1e-7));
+
+    Imath::Box2f t2iMixAsB2f;
+    assert (PyImath::Box2f::convert (t2iMixObj, &t2iMixAsB2f) == 1);
+    assert (t2iMixAsB2f.min.equalWithAbsError (Imath::V2f (1.0f, 2.0f), 1e-7));
+    assert (t2iMixAsB2f.max.equalWithAbsError (Imath::V2f (3.0, 4.0f), 1e-7));
+
+    Imath::Box2f t2fAsB2f;
+    assert (PyImath::Box2f::convert (t2fObj, &t2fAsB2f) == 1);
+    assert (t2fAsB2f.min.equalWithAbsError (Imath::V2f (5.5f, 6.6f), 1e-7));
+    assert (t2fAsB2f.max.equalWithAbsError (Imath::V2f (7.7f, 8.8f), 1e-7));
+
+    Imath::Box2f t2V2fAsB2f;
+    assert (PyImath::Box2f::convert (t2V2fObj, &t2V2fAsB2f) == 1);
+    assert (t2V2fAsB2f.min.equalWithAbsError (Imath::V2f (5.5f, 6.6f), 1e-7));
+    assert (t2V2fAsB2f.max.equalWithAbsError (Imath::V2f (7.7f, 8.8f), 1e-7));
+
+    Imath::Box2f t2fMixAsB2f;
+    assert (PyImath::Box2f::convert (t2fMixObj, &t2fMixAsB2f) == 1);
+    assert (t2fMixAsB2f.min.equalWithAbsError (Imath::V2f (5.5f, 6.6f), 1e-7));
+    assert (t2fMixAsB2f.max.equalWithAbsError (Imath::V2f (7.7f, 8.8f), 1e-7));
+
+    Imath::Box2f t2V2dAsB2f;
+    assert (PyImath::Box2f::convert (t2V2dObj, &t2V2dAsB2f) == 1);
+    assert (t2V2dAsB2f.min.equalWithAbsError (Imath::V2f (9.9f, 10.10f), 1e-7));
+    assert (t2V2dAsB2f.max.equalWithAbsError (Imath::V2f (11.11, 12.12f), 1e-7));
+
+    Imath::Box2f t2dMixAsB2f;
+    assert (PyImath::Box2f::convert (t2dMixObj, &t2dMixAsB2f) == 1);
+    assert (t2dMixAsB2f.min.equalWithAbsError (Imath::V2f (9.9f, 10.10f), 1e-7));
+    assert (t2dMixAsB2f.max.equalWithAbsError (Imath::V2f (11.11f, 12.12f), 1e-7));
+
+    Imath::Box2f iAsB2f;
+    assert (PyImath::Box2f::convert (iObj, &iAsB2f) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing Box2d:\n";
+
+    Imath::Box2d b2iAsB2d;
+    assert (PyImath::Box2d::convert (b2iObj, &b2iAsB2d) == 1);
+    assert (b2iAsB2d.min.equalWithAbsError (Imath::V2d (1.0, 2.0), 1e-7));
+    assert (b2iAsB2d.max.equalWithAbsError (Imath::V2d (3.0, 4.0), 1e-7));
+
+    Imath::Box2d b2fAsB2d;
+    assert (PyImath::Box2d::convert (b2fObj, &b2fAsB2d) == 1);
+    assert (b2fAsB2d.min.equalWithAbsError (Imath::V2d (5.5, 6.6), 1e-7));
+    assert (b2fAsB2d.max.equalWithAbsError (Imath::V2d (7.7, 8.8), 1e-6));
+
+    Imath::Box2d b2dAsB2d;
+    assert (PyImath::Box2d::convert (b2dObj, &b2dAsB2d) == 1);
+    assert (b2dAsB2d.min.equalWithAbsError (Imath::V2d (9.9, 10.10), 1e-6));
+    assert (b2dAsB2d.max.equalWithAbsError (Imath::V2d (11.11, 12.12), 1e-6));
+
+    Imath::Box2d t2iAsB2d;
+    assert (PyImath::Box2d::convert (t2iObj, &t2iAsB2d) == 1);
+    assert (t2iAsB2d.min.equalWithAbsError (Imath::V2d (1.0, 2.0), 1e-7)); 
+    assert (t2iAsB2d.max.equalWithAbsError (Imath::V2d (3.0, 4.0), 1e-7)); 
+
+    Imath::Box2d t2V2iAsB2d;
+    assert (PyImath::Box2d::convert (t2V2iObj, &t2V2iAsB2d) == 1);
+    assert (t2V2iAsB2d.min.equalWithAbsError (Imath::V2d (1.0, 2.0), 1e-7));
+    assert (t2V2iAsB2d.max.equalWithAbsError (Imath::V2d (3.0, 4.0), 1e-7));
+
+    Imath::Box2d t2iMixAsB2d;
+    assert (PyImath::Box2d::convert (t2iMixObj, &t2iMixAsB2d) == 1);
+    assert (t2iMixAsB2d.min.equalWithAbsError (Imath::V2d (1.0, 2.0), 1e-7));
+    assert (t2iMixAsB2d.max.equalWithAbsError (Imath::V2d (3.0, 4.0), 1e-7));
+
+    Imath::Box2d t2fAsB2d;
+    assert (PyImath::Box2d::convert (t2fObj, &t2fAsB2d) == 1);
+    assert (t2fAsB2d.min.equalWithAbsError (Imath::V2d (5.5, 6.6), 1e-7));
+    assert (t2fAsB2d.max.equalWithAbsError (Imath::V2d (7.7, 8.8), 1e-7));
+
+    Imath::Box2d t2V2fAsB2d;
+    assert (PyImath::Box2d::convert (t2V2fObj, &t2V2fAsB2d) == 1);
+    assert (t2V2fAsB2d.min.equalWithAbsError (Imath::V2d (5.5, 6.6), 1e-7));
+    assert (t2V2fAsB2d.max.equalWithAbsError (Imath::V2d (7.7, 8.8), 1e-6));
+
+    Imath::Box2d t2fMixAsB2d;
+    assert (PyImath::Box2d::convert (t2fMixObj, &t2fMixAsB2d) == 1);
+    assert (t2fMixAsB2d.min.equalWithAbsError (Imath::V2d (5.5, 6.6), 1e-7));
+    assert (t2fMixAsB2d.max.equalWithAbsError (Imath::V2d (7.7, 8.8), 1e-7));
+
+    Imath::Box2d t2V2dAsB2d;
+    assert (PyImath::Box2d::convert (t2V2dObj, &t2V2dAsB2d) == 1);
+    assert (t2V2dAsB2d.min.equalWithAbsError (Imath::V2d (9.9, 10.10), 1e-7));
+    assert (t2V2dAsB2d.max.equalWithAbsError (Imath::V2d (11.11, 12.12), 1e-7));
+
+    Imath::Box2d t2dMixAsB2d;
+    assert (PyImath::Box2d::convert (t2dMixObj, &t2dMixAsB2d) == 1);
+    assert (t2dMixAsB2d.min.equalWithAbsError (Imath::V2d (9.9, 10.10), 1e-7));
+    assert (t2dMixAsB2d.max.equalWithAbsError (Imath::V2d (11.11, 12.12), 1e-7));
+
+    Imath::Box2d iAsB2d;
+    assert (PyImath::Box2d::convert (iObj, &iAsB2d) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testBox3 ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing Box3*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "b3i = Box3i ((1, 2, 3), (4, 5, 6))\n"
+        "b3f = Box3f ((7.7, 8.8, 9.9), (10.10, 11.11, 12.12))\n"
+        "b3d = Box3d ((13.13, 14.14, 15.15), (16.16, 17.17, 18.18))\n"
+        "t2i = ((1, 2, 3), (4, 5, 6))\n"
+        "t2V3i = (V3i (1, 2, 3), V3i (4, 5, 6))\n"
+        "t2iMix = (V3i (1, 2, 3), (4, 5, 6))\n"
+        "t2f = ((7.7, 8.8, 9.9), (10.10, 11.11, 12.12))\n"
+        "t2V3f = (V3f (7.7, 8.8, 9.9), V3f (10.10, 11.11, 12.12))\n"
+        "t2fMix = (V3f (7.7, 8.8, 9.9), (10.10, 11.11, 12.12))\n"
+        "t2V3d = (V3d (13.13, 14.14, 15.15), V3d (16.16, 17.17, 18.18))\n"
+        "t2dMix = (V3d (13.13, 14.14, 15.15), (16.16, 17.17, 18.18))\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('Box3i')\n"
+        "assert w == Box3i ((1, 2, 3), (4, 5, 6))\n"
+        "w = wrap ('Box3f')\n"
+        "assert w.min().equalWithAbsError ((1.1, 2.2, 3.3), 1e-7)\n"
+        "assert w.max().equalWithAbsError ((4.4, 5.5, 6.6), 1e-7)\n"
+        "w = wrap ('Box3d')\n"
+        "assert w.min().equalWithAbsError ((1.1, 2.2, 3.3), 1e-7)\n"
+        "assert w.max().equalWithAbsError ((4.4, 5.5, 6.6), 1e-7)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> eb3i (mainNamespace ["b3i"]);
+    assert (eb3i.check());
+    
+    PyObject *b3iObj = eb3i().ptr();
+    assert (b3iObj != 0);
+
+    extract <object> eb3f (mainNamespace ["b3f"]);
+    assert (eb3f.check());
+    
+    PyObject *b3fObj = eb3f().ptr();
+    assert (b3fObj != 0);
+
+    extract <object> eb3d (mainNamespace ["b3d"]);
+    assert (eb3d.check());
+    
+    PyObject *b3dObj = eb3d().ptr();
+    assert (b3dObj != 0);
+
+    extract <object> et2i (mainNamespace["t2i"]);
+    assert (et2i.check());
+
+    PyObject *t2iObj = et2i().ptr();
+    assert (t2iObj != 0);
+
+    extract <object> et2V3i (mainNamespace["t2V3i"]);
+    assert (et2V3i.check());
+
+    PyObject *t2V3iObj = et2V3i().ptr();
+    assert (t2V3iObj != 0);
+
+    extract <object> et2iMix (mainNamespace["t2iMix"]);
+    assert (et2iMix.check());
+
+    PyObject *t2iMixObj = et2iMix().ptr();
+    assert (t2iMixObj != 0);
+
+    extract <object> et2f (mainNamespace["t2f"]);
+    assert (et2f.check());
+
+    PyObject *t2fObj = et2f().ptr();
+    assert (t2fObj != 0);
+
+    extract <object> et2V3f (mainNamespace["t2V3f"]);
+    assert (et2V3f.check());
+
+    PyObject *t2V3fObj = et2V3f().ptr();
+    assert (t2V3fObj != 0);
+
+    extract <object> et2fMix (mainNamespace["t2fMix"]);
+    assert (et2fMix.check());
+
+    PyObject *t2fMixObj = et2fMix().ptr();
+    assert (t2fMixObj != 0);
+
+    extract <object> et2V3d (mainNamespace["t2V3d"]);
+    assert (et2V3d.check());
+
+    PyObject *t2V3dObj = et2V3d().ptr();
+    assert (t2V3dObj != 0);
+
+    extract <object> et2dMix (mainNamespace["t2dMix"]);
+    assert (et2dMix.check());
+
+    PyObject *t2dMixObj = et2dMix().ptr();
+    assert (t2dMixObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+
+    std::cerr << "Testing Box3i:\n";
+
+    Imath::Box3i b3iAsB3i;
+    assert (PyImath::Box3i::convert (b3iObj, &b3iAsB3i) == 1);
+    assert (b3iAsB3i == Imath::Box3i (Imath::V3i (1, 2, 3), 
+                                      Imath::V3i (4, 5, 6)));
+
+    Imath::Box3i b3fAsB3i;
+    assert (PyImath::Box3i::convert (b3fObj, &b3fAsB3i) == 1);
+    assert (b3fAsB3i == Imath::Box3i (Imath::V3i (7, 8, 9),
+                                      Imath::V3i (10, 11, 12)));
+
+    Imath::Box3i b3dAsB3i;
+    assert (PyImath::Box3i::convert (b3dObj, &b3dAsB3i) == 1);
+    assert (b3dAsB3i == Imath::Box3i (Imath::V3i (13, 14, 15),
+                                      Imath::V3i (16, 17, 18)));
+
+    Imath::Box3i t2iAsB3i;
+    assert (PyImath::Box3i::convert (t2iObj, &t2iAsB3i) == 1);
+    assert (t2iAsB3i == Imath::Box3i (Imath::V3i (1, 2, 3), 
+                                      Imath::V3i (4, 5, 6)));
+
+    Imath::Box3i t2V3iAsB3i;
+    assert (PyImath::Box3i::convert (t2V3iObj, &t2V3iAsB3i) == 1);
+    assert (t2V3iAsB3i == Imath::Box3i (Imath::V3i (1, 2, 3), 
+                                        Imath::V3i (4, 5, 6)));
+
+    Imath::Box3i t2iMixAsB3i;
+    assert (PyImath::Box3i::convert (t2iMixObj, &t2iMixAsB3i) == 1);
+    assert (t2iMixAsB3i == Imath::Box3i (Imath::V3i (1, 2, 3), 
+                                         Imath::V3i (4, 5, 6)));
+
+    Imath::Box3i t2fAsB3i;
+    assert (PyImath::Box3i::convert (t2fObj, &t2fAsB3i) == 1);
+    assert (t2fAsB3i == Imath::Box3i (Imath::V3i (7, 8, 9), 
+                                      Imath::V3i (10, 11, 12)));
+
+    Imath::Box3i t2V3fAsB3i;
+    assert (PyImath::Box3i::convert (t2V3fObj, &t2V3fAsB3i) == 1);
+    assert (t2V3fAsB3i == Imath::Box3i (Imath::V3i (7, 8, 9),
+                                        Imath::V3i (10, 11, 12)));
+
+    Imath::Box3i t2fMixAsB3i;
+    assert (PyImath::Box3i::convert (t2fMixObj, &t2fMixAsB3i) == 1);
+    assert (t2fMixAsB3i == Imath::Box3i (Imath::V3i (7, 8, 9), 
+                                         Imath::V3i (10, 11, 12)));
+
+    Imath::Box3i t2V3dAsB3i;
+    assert (PyImath::Box3i::convert (t2V3dObj, &t2V3dAsB3i) == 1);
+    assert (t2V3dAsB3i == Imath::Box3i (Imath::V3i (13, 14, 15),
+                                        Imath::V3i (16, 17, 18)));
+
+    Imath::Box3i t2dMixAsB3i;
+    assert (PyImath::Box3i::convert (t2dMixObj, &t2dMixAsB3i) == 1);
+    assert (t2dMixAsB3i == Imath::Box3i (Imath::V3i (13, 14, 15),
+                                         Imath::V3i (16, 17, 18)));
+
+    Imath::Box3i iAsB3i;
+    assert (PyImath::Box3i::convert (iObj, &iAsB3i) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing Box3f:\n";
+
+    Imath::Box3f b3iAsB3f;
+    assert (PyImath::Box3f::convert (b3iObj, &b3iAsB3f) == 1);
+    assert (b3iAsB3f.min.equalWithAbsError (Imath::V3f (1.0f, 2.0f, 3.0f), 1e-7));
+    assert (b3iAsB3f.max.equalWithAbsError (Imath::V3f (4.0f, 5.0f, 6.0f), 1e-7));
+
+    Imath::Box3f b3fAsB3f;
+    assert (PyImath::Box3f::convert (b3fObj, &b3fAsB3f) == 1);
+    assert (b3fAsB3f.min.equalWithAbsError (Imath::V3f (7.7f, 8.8f, 9.9f), 1e-7));
+    assert (b3fAsB3f.max.equalWithAbsError (Imath::V3f (10.10f, 11.11f, 12.12f), 1e-7));
+
+    Imath::Box3f b3dAsB3f;
+    assert (PyImath::Box3f::convert (b3dObj, &b3dAsB3f) == 1);
+    assert (b3dAsB3f.min.equalWithAbsError (Imath::V3f (13.13f, 14.14f, 15.15f), 1e-7));
+    assert (b3dAsB3f.max.equalWithAbsError (Imath::V3f (16.16f, 17.17f, 18.18f), 1e-7));
+
+    Imath::Box3f t2iAsB3f;
+    assert (PyImath::Box3f::convert (t2iObj, &t2iAsB3f) == 1);
+    assert (t2iAsB3f.min.equalWithAbsError (Imath::V3f (1.0f, 2.0f, 3.0f), 1e-7)); 
+    assert (t2iAsB3f.max.equalWithAbsError (Imath::V3f (4.0f, 5.0f, 6.0f), 1e-7)); 
+
+    Imath::Box3f t2V3iAsB3f;
+    assert (PyImath::Box3f::convert (t2V3iObj, &t2V3iAsB3f) == 1);
+    assert (t2V3iAsB3f.min.equalWithAbsError (Imath::V3f (1.0f, 2.0f, 3.0f), 1e-7));
+    assert (t2V3iAsB3f.max.equalWithAbsError (Imath::V3f (4.0f, 5.0f, 6.0f), 1e-7));
+
+    Imath::Box3f t2iMixAsB3f;
+    assert (PyImath::Box3f::convert (t2iMixObj, &t2iMixAsB3f) == 1);
+    assert (t2iMixAsB3f.min.equalWithAbsError (Imath::V3f (1.0f, 2.0f, 3.0f), 1e-7));
+    assert (t2iMixAsB3f.max.equalWithAbsError (Imath::V3f (4.0f, 5.0f, 6.0f), 1e-7));
+
+    Imath::Box3f t2fAsB3f;
+    assert (PyImath::Box3f::convert (t2fObj, &t2fAsB3f) == 1);
+    assert (t2fAsB3f.min.equalWithAbsError (Imath::V3f (7.7f, 8.8f, 9.9f), 1e-7));
+    assert (t2fAsB3f.max.equalWithAbsError (Imath::V3f (10.10f, 11.11f, 12.12f), 1e-7));
+
+    Imath::Box3f t2V3fAsB3f;
+    assert (PyImath::Box3f::convert (t2V3fObj, &t2V3fAsB3f) == 1);
+    assert (t2V3fAsB3f.min.equalWithAbsError (Imath::V3f (7.7f, 8.8f, 9.9f), 1e-7));
+    assert (t2V3fAsB3f.max.equalWithAbsError (Imath::V3f (10.10f, 11.11f, 12.12f), 1e-7));
+
+    Imath::Box3f t2fMixAsB3f;
+    assert (PyImath::Box3f::convert (t2fMixObj, &t2fMixAsB3f) == 1);
+    assert (t2fMixAsB3f.min.equalWithAbsError (Imath::V3f (7.7f, 8.8f, 9.9f), 1e-7));
+    assert (t2fMixAsB3f.max.equalWithAbsError (Imath::V3f (10.10f, 11.11f, 12.12f), 1e-7));
+
+    Imath::Box3f t2V3dAsB3f;
+    assert (PyImath::Box3f::convert (t2V3dObj, &t2V3dAsB3f) == 1);
+    assert (t2V3dAsB3f.min.equalWithAbsError (Imath::V3f (13.13f, 14.14f, 15.15f), 1e-7));
+    assert (t2V3dAsB3f.max.equalWithAbsError (Imath::V3f (16.16f, 17.17f, 18.18f), 1e-7));
+
+    Imath::Box3f t2dMixAsB3f;
+    assert (PyImath::Box3f::convert (t2dMixObj, &t2dMixAsB3f) == 1);
+    assert (t2dMixAsB3f.min.equalWithAbsError (Imath::V3f (13.13f, 14.14f, 15.15f), 1e-7));
+    assert (t2dMixAsB3f.max.equalWithAbsError (Imath::V3f (16.16f, 17.17f, 18.18f), 1e-7));
+
+    Imath::Box3f iAsB3f;
+    assert (PyImath::Box3f::convert (iObj, &iAsB3f) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing Box3d:\n";
+
+    Imath::Box3d b3iAsB3d;
+    assert (PyImath::Box3d::convert (b3iObj, &b3iAsB3d) == 1);
+    assert (b3iAsB3d.min.equalWithAbsError (Imath::V3d (1.0, 2.0, 3.0), 1e-7));
+    assert (b3iAsB3d.max.equalWithAbsError (Imath::V3d (4.0, 5.0, 6.0), 1e-7));
+
+    Imath::Box3d b3fAsB3d;
+    assert (PyImath::Box3d::convert (b3fObj, &b3fAsB3d) == 1);
+    assert (b3fAsB3d.min.equalWithAbsError (Imath::V3d (7.7, 8.8, 9.9), 1e-6));
+    assert (b3fAsB3d.max.equalWithAbsError (Imath::V3d (10.10, 11.11, 12.12), 1e-6));
+
+    Imath::Box3d b3dAsB3d;
+    assert (PyImath::Box3d::convert (b3dObj, &b3dAsB3d) == 1);
+    assert (b3dAsB3d.min.equalWithAbsError (Imath::V3d (13.13, 14.14, 15.15), 1e-6));
+    assert (b3dAsB3d.max.equalWithAbsError (Imath::V3d (16.16, 17.17, 18.18), 1e-6));
+
+    Imath::Box3d t2iAsB3d;
+    assert (PyImath::Box3d::convert (t2iObj, &t2iAsB3d) == 1);
+    assert (t2iAsB3d.min.equalWithAbsError (Imath::V3d (1.0, 2.0, 3.0), 1e-7)); 
+    assert (t2iAsB3d.max.equalWithAbsError (Imath::V3d (4.0, 5.0, 6.0), 1e-7)); 
+
+    Imath::Box3d t2V3iAsB3d;
+    assert (PyImath::Box3d::convert (t2V3iObj, &t2V3iAsB3d) == 1);
+    assert (t2V3iAsB3d.min.equalWithAbsError (Imath::V3d (1.0, 2.0, 3.0), 1e-7));
+    assert (t2V3iAsB3d.max.equalWithAbsError (Imath::V3d (4.0, 5.0, 6.0), 1e-7));
+
+    Imath::Box3d t2iMixAsB3d;
+    assert (PyImath::Box3d::convert (t2iMixObj, &t2iMixAsB3d) == 1);
+    assert (t2iMixAsB3d.min.equalWithAbsError (Imath::V3d (1.0, 2.0, 3.0), 1e-7));
+    assert (t2iMixAsB3d.max.equalWithAbsError (Imath::V3d (4.0, 5.0, 6.0), 1e-7));
+
+    Imath::Box3d t2fAsB3d;
+    assert (PyImath::Box3d::convert (t2fObj, &t2fAsB3d) == 1);
+    assert (t2fAsB3d.min.equalWithAbsError (Imath::V3d (7.7, 8.8, 9.9), 1e-7));
+    assert (t2fAsB3d.max.equalWithAbsError (Imath::V3d (10.10, 11.11, 12.12), 1e-7));
+
+    Imath::Box3d t2V3fAsB3d;
+    assert (PyImath::Box3d::convert (t2V3fObj, &t2V3fAsB3d) == 1);
+    assert (t2V3fAsB3d.min.equalWithAbsError (Imath::V3d (7.7, 8.8, 9.9), 1e-6));
+    assert (t2V3fAsB3d.max.equalWithAbsError (Imath::V3d (10.10, 11.11, 12.12), 1e-6));
+
+    Imath::Box3d t2fMixAsB3d;
+    assert (PyImath::Box3d::convert (t2fMixObj, &t2fMixAsB3d) == 1);
+    assert (t2fMixAsB3d.min.equalWithAbsError (Imath::V3d (7.7, 8.8, 9.9), 1e-6));
+    assert (t2fMixAsB3d.max.equalWithAbsError (Imath::V3d (10.10, 11.11, 12.12), 1e-6));
+
+    Imath::Box3d t2V3dAsB3d;
+    assert (PyImath::Box3d::convert (t2V3dObj, &t2V3dAsB3d) == 1);
+    assert (t2V3dAsB3d.min.equalWithAbsError (Imath::V3d (13.13, 14.14, 15.15), 1e-7));
+    assert (t2V3dAsB3d.max.equalWithAbsError (Imath::V3d (16.16, 17.17, 18.18), 1e-7));
+
+    Imath::Box3d t2dMixAsB3d;
+    assert (PyImath::Box3d::convert (t2dMixObj, &t2dMixAsB3d) == 1);
+    assert (t2dMixAsB3d.min.equalWithAbsError (Imath::V3d (13.13, 14.14, 15.15), 1e-7));
+    assert (t2dMixAsB3d.max.equalWithAbsError (Imath::V3d (16.16, 17.17, 18.18), 1e-7));
+
+    Imath::Box3d iAsB3d;
+    assert (PyImath::Box3d::convert (iObj, &iAsB3d) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testC3 ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing C3*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "c3c = Color3c (1, 2, 3)\n"
+        "c3f = Color3f (1.1, 2.2, 3.3)\n"
+        "t3c = (4, 5, 6)\n"
+        "t3f = (4.4, 5.5, 6.6)\n"
+        "v3i = V3i (7, 8, 9)\n"
+        "v3f = V3f (10.10, 11.11, 12.12)\n"
+        "v3d = V3f (13.13, 14.14, 15.15)\n"
+        "l3c = [16, 17, 18]\n"
+        "l3f = [19.19, 20.20, 21.21]\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('Color3c')\n"
+        "assert w == Color3c (1, 2, 3)\n"
+        "w = wrap ('Color3f')\n"
+        "assert equal (w[0], 1.1, 1e-6)\n"
+        "assert equal (w[1], 2.2, 1e-6)\n"
+        "assert equal (w[2], 3.3, 1e-6)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> ec3c (mainNamespace ["c3c"]);
+    assert (ec3c.check());
+
+    PyObject *c3cObj = ec3c().ptr();
+    assert (c3cObj != 0);
+
+    extract <object> ec3f (mainNamespace ["c3f"]);
+    assert (ec3f.check());
+
+    PyObject *c3fObj = ec3f().ptr();
+    assert (c3fObj != 0);
+
+    extract <object> et3c (mainNamespace ["t3c"]);
+    assert (et3c.check());
+
+    PyObject *t3cObj = et3c().ptr();
+    assert (t3cObj != 0);
+
+    extract <object> et3f (mainNamespace ["t3f"]);
+    assert (et3f.check());
+
+    PyObject *t3fObj = et3f().ptr();
+    assert (t3fObj != 0);
+
+    extract <object> ev3i (mainNamespace ["v3i"]);
+    assert (ev3i.check());
+
+    PyObject *v3iObj = ev3i().ptr();
+    assert (v3iObj != 0);
+
+    extract <object> ev3f (mainNamespace ["v3f"]);
+    assert (ev3f.check());
+
+    PyObject *v3fObj = ev3f().ptr();
+    assert (v3fObj != 0);
+
+    extract <object> ev3d (mainNamespace ["v3d"]);
+    assert (ev3d.check());
+
+    PyObject *v3dObj = ev3d().ptr();
+    assert (v3dObj != 0);
+
+    extract <object> el3c (mainNamespace ["l3c"]);
+    assert (el3c.check());
+
+    PyObject *l3cObj = el3c().ptr();
+    assert (l3cObj != 0);
+
+    extract <object> el3f (mainNamespace ["l3f"]);
+    assert (el3f.check());
+
+    PyObject *l3fObj = el3f().ptr();
+    assert (l3fObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+
+    std::cerr << "Testing C3c:\n";
+
+    Imath::C3c c3cAsC3c;
+    assert (PyImath::C3c::convert (c3cObj, &c3cAsC3c) == 1);
+    assert (c3cAsC3c == Imath::C3c (1, 2, 3));
+
+    Imath::C3c c3fAsC3c;
+    assert (PyImath::C3c::convert (c3fObj, &c3fAsC3c) == 1);
+    assert (c3fAsC3c == Imath::C3c (1, 2, 3));
+
+    Imath::C3c t3cAsC3c;
+    assert (PyImath::C3c::convert (t3cObj, &t3cAsC3c) == 1);
+    assert (t3cAsC3c == Imath::C3c (4, 5, 6));
+
+    Imath::C3c t3fAsC3c;
+    assert (PyImath::C3c::convert (t3fObj, &t3fAsC3c) == 1);
+    assert (t3fAsC3c == Imath::C3c (4, 5, 6));
+
+    Imath::C3c v3iAsC3c;
+    assert (PyImath::C3c::convert (v3iObj, &v3iAsC3c) == 1);
+    assert (v3iAsC3c == Imath::C3c (7, 8, 9));
+
+    Imath::C3c v3fAsC3c;
+    assert (PyImath::C3c::convert (v3fObj, &v3fAsC3c) == 1);
+    assert (v3fAsC3c == Imath::C3c (10, 11, 12));
+
+    Imath::C3c v3dAsC3c;
+    assert (PyImath::C3c::convert (v3dObj, &v3dAsC3c) == 1);
+    assert (v3dAsC3c == Imath::C3c (13, 14, 15));
+
+    Imath::C3c l3cAsC3c;
+    assert (PyImath::C3c::convert (l3cObj, &l3cAsC3c) == 1);
+    assert (l3cAsC3c == Imath::C3c (16, 17, 18));
+
+    Imath::C3c l3fAsC3c;
+    assert (PyImath::C3c::convert (l3fObj, &l3fAsC3c) == 1);
+    assert (l3fAsC3c == Imath::C3c (19, 20, 21));
+
+    Imath::C3c iAsC3c;
+    assert (PyImath::C3c::convert (iObj, &iAsC3c) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing C3f:\n";
+
+    Imath::C3f c3cAsC3f;
+    assert (PyImath::C3f::convert (c3cObj, &c3cAsC3f) == 1);
+    assert (c3cAsC3f.equalWithAbsError (Imath::C3f (1.0f, 2.0f, 3.0f), 1e-7));
+
+    Imath::C3f c3fAsC3f;
+    assert (PyImath::C3f::convert (c3fObj, &c3fAsC3f) == 1);
+    assert (c3fAsC3f.equalWithAbsError (Imath::C3f (1.1f, 2.2f, 3.3f), 1e-7));
+
+    Imath::C3f t3cAsC3f;
+    assert (PyImath::C3f::convert (t3cObj, &t3cAsC3f) == 1);
+    assert (t3cAsC3f.equalWithAbsError (Imath::C3f (4.0f, 5.0f, 6.0f), 1e-7));
+
+    Imath::C3f t3fAsC3f;
+    assert (PyImath::C3f::convert (t3fObj, &t3fAsC3f) == 1);
+    assert (t3fAsC3f.equalWithAbsError (Imath::C3f (4.4f, 5.5f, 6.6f), 1e-7));
+
+    Imath::C3f v3iAsC3f;
+    assert (PyImath::C3f::convert (v3iObj, &v3iAsC3f) == 1);
+    assert (v3iAsC3f.equalWithAbsError (Imath::C3f (7.0f, 8.0f, 9.0f), 1e-7));
+
+    Imath::C3f v3fAsC3f;
+    assert (PyImath::C3f::convert (v3fObj, &v3fAsC3f) == 1);
+    assert (v3fAsC3f.equalWithAbsError (Imath::C3f (10.10f, 11.11f, 12.12f), 1e-7));
+
+    Imath::C3f v3dAsC3f;
+    assert (PyImath::C3f::convert (v3dObj, &v3dAsC3f) == 1);
+    assert (v3dAsC3f.equalWithAbsError (Imath::C3f (13.13f, 14.14f, 15.15f), 1e-7));
+
+    Imath::C3f l3cAsC3f;
+    assert (PyImath::C3f::convert (l3cObj, &l3cAsC3f) == 1);
+    assert (l3cAsC3f == Imath::C3f (16.0, 17.0, 18.0));
+
+    Imath::C3f l3fAsC3f;
+    assert (PyImath::C3f::convert (l3fObj, &l3fAsC3f) == 1);
+    assert (l3fAsC3f == Imath::C3f (19.19, 20.20, 21.21));
+
+    Imath::C3f iAsC3f;
+    assert (PyImath::C3f::convert (iObj, &iAsC3f) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testC4 ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing C4*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "c4c = Color4c (1, 2, 3, 4)\n"
+        "c4f = Color4f (1.1, 2.2, 3.3, 4.4)\n"
+        "t4c = (5, 6, 7, 8)\n"
+        "t4f = (5.5, 6.6, 7.7, 8.8)\n"
+        "l4c = [9, 10, 11, 12]\n"
+        "l4f = [13.13, 14.14, 15.15, 16.16]\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('Color4c')\n"
+        "assert w == Color4c (1, 2, 3, 4)\n"
+        "w = wrap ('Color4f')\n"
+        "assert equal (w[0], 1.1, 1e-7)\n"
+        "assert equal (w[1], 2.2, 1e-7)\n"
+        "assert equal (w[2], 3.3, 1e-7)\n"
+        "assert equal (w[3], 4.4, 1e-7)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> ec4c (mainNamespace ["c4c"]);
+    assert (ec4c.check());
+
+    PyObject *c4cObj = ec4c().ptr();
+    assert (c4cObj != 0);
+
+    extract <object> ec4f (mainNamespace ["c4f"]);
+    assert (ec4f.check());
+
+    PyObject *c4fObj = ec4f().ptr();
+    assert (c4fObj != 0);
+
+    extract <object> et4c (mainNamespace ["t4c"]);
+    assert (et4c.check());
+
+    PyObject *t4cObj = et4c().ptr();
+    assert (t4cObj != 0);
+
+    extract <object> et4f (mainNamespace ["t4f"]);
+    assert (et4f.check());
+
+    PyObject *t4fObj = et4f().ptr();
+    assert (t4fObj != 0);
+
+    extract <object> el4c (mainNamespace ["l4c"]);
+    assert (el4c.check());
+
+    PyObject *l4cObj = el4c().ptr();
+    assert (l4cObj != 0);
+
+    extract <object> el4f (mainNamespace ["l4f"]);
+    assert (el4f.check());
+
+    PyObject *l4fObj = el4f().ptr();
+    assert (l4fObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+
+    std::cerr << "Testing C4c:\n";
+
+    Imath::C4c c4cAsC4c;
+    assert (PyImath::C4c::convert (c4cObj, &c4cAsC4c) == 1);
+    assert (c4cAsC4c == Imath::C4c (1, 2, 3, 4));
+
+    Imath::C4c c4fAsC4c;
+    assert (PyImath::C4c::convert (c4fObj, &c4fAsC4c) == 1);
+    assert (c4fAsC4c == Imath::C4c (1, 2, 3, 4));
+
+    Imath::C4c t4cAsC4c;
+    assert (PyImath::C4c::convert (t4cObj, &t4cAsC4c) == 1);
+    assert (t4cAsC4c == Imath::C4c (5, 6, 7, 8));
+
+    Imath::C4c t4fAsC4c;
+    assert (PyImath::C4c::convert (t4fObj, &t4fAsC4c) == 1);
+    assert (t4fAsC4c == Imath::C4c (5, 6, 7, 8));
+
+    Imath::C4c l4cAsC4c;
+    assert (PyImath::C4c::convert (l4cObj, &l4cAsC4c) == 1);
+    assert (l4cAsC4c == Imath::C4c (9, 10, 11, 12));
+
+    Imath::C4c l4fAsC4c;
+    assert (PyImath::C4c::convert (l4fObj, &l4fAsC4c) == 1);
+    assert (l4fAsC4c == Imath::C4c (13, 14, 15, 16));
+
+    Imath::C4c iAsC4c;
+    assert (PyImath::C4c::convert (iObj, &iAsC4c) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing C4f:\n";
+
+    Imath::C4f c4cAsC4f;
+    assert (PyImath::C4f::convert (c4cObj, &c4cAsC4f) == 1);
+    assert (Imath::equalWithAbsError (c4cAsC4f[0], 1.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (c4cAsC4f[1], 2.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (c4cAsC4f[2], 3.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (c4cAsC4f[3], 4.0f, 1e-7f));
+
+    Imath::C4f c4fAsC4f;
+    assert (PyImath::C4f::convert (c4fObj, &c4fAsC4f) == 1);
+    assert (Imath::equalWithAbsError (c4fAsC4f[0], 1.1f, 1e-7f));
+    assert (Imath::equalWithAbsError (c4fAsC4f[1], 2.2f, 1e-7f));
+    assert (Imath::equalWithAbsError (c4fAsC4f[2], 3.3f, 1e-7f));
+    assert (Imath::equalWithAbsError (c4fAsC4f[3], 4.4f, 1e-7f));
+
+    Imath::C4f t4cAsC4f;
+    assert (PyImath::C4f::convert (t4cObj, &t4cAsC4f) == 1);
+    assert (Imath::equalWithAbsError (t4cAsC4f[0], 5.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (t4cAsC4f[1], 6.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (t4cAsC4f[2], 7.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (t4cAsC4f[3], 8.0f, 1e-7f));
+
+    Imath::C4f t4fAsC4f;
+    assert (PyImath::C4f::convert (t4fObj, &t4fAsC4f) == 1);
+    assert (Imath::equalWithAbsError (t4fAsC4f[0], 5.5f, 1e-7f));
+    assert (Imath::equalWithAbsError (t4fAsC4f[1], 6.6f, 1e-7f));
+    assert (Imath::equalWithAbsError (t4fAsC4f[2], 7.7f, 1e-7f));
+    assert (Imath::equalWithAbsError (t4fAsC4f[3], 8.8f, 1e-7f));
+
+    Imath::C4f l4cAsC4f;
+    assert (PyImath::C4f::convert (l4cObj, &l4cAsC4f) == 1);
+    assert (Imath::equalWithAbsError (l4cAsC4f[0], 9.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (l4cAsC4f[1], 10.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (l4cAsC4f[2], 11.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (l4cAsC4f[3], 12.0f, 1e-7f));
+
+    Imath::C4f l4fAsC4f;
+    assert (PyImath::C4f::convert (l4fObj, &l4fAsC4f) == 1);
+    assert (Imath::equalWithAbsError (l4fAsC4f[0], 13.13f, 1e-7f));
+    assert (Imath::equalWithAbsError (l4fAsC4f[1], 14.14f, 1e-7f));
+    assert (Imath::equalWithAbsError (l4fAsC4f[2], 15.15f, 1e-7f));
+    assert (Imath::equalWithAbsError (l4fAsC4f[3], 16.16f, 1e-7f));
+
+    Imath::C4f iAsC4f;
+    assert (PyImath::C4f::convert (iObj, &iAsC4f) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testEuler ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing Euler*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "ef = Eulerf (V3f(1.1, 2.2, 3.3), EULER_XZY)\n"
+        "ed = Eulerd (V3d(4.4, 5.5, 6.6), EULER_ZYX)\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('Eulerf')\n"
+        "assert equal (w.x, 1.1, 1e-6)\n"
+        "assert equal (w.y, 2.2, 1e-6)\n"
+        "assert equal (w.z, 3.3, 1e-6)\n"
+        "assert w.order() == EULER_XZY\n"
+        "w = wrap ('Eulerd')\n"
+        "assert equal (w.x, 1.1, 1e-6)\n"
+        "assert equal (w.y, 2.2, 1e-6)\n"
+        "assert equal (w.z, 3.3, 1e-6)\n"
+        "assert w.order() == EULER_XZY\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> eef (mainNamespace["ef"]);
+    assert (eef.check());
+
+    PyObject *efObj = eef().ptr();
+    assert (efObj != 0);
+
+    extract <object> eed (mainNamespace["ed"]);
+    assert (eed.check());
+
+    PyObject *edObj = eed().ptr();
+    assert (edObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+    
+    std::cerr << "Testing Eulerf:\n";
+
+    Imath::Eulerf efAsEf;
+    assert (PyImath::Eulerf::convert (efObj, &efAsEf) == 1);
+    Imath::Eulerf eff (Imath::V3f (1.1f, 2.2f, 3.3f), Imath::Eulerf::XZY);
+    assert (efAsEf.order() == eff.order());
+    assert (efAsEf.toMatrix44().equalWithAbsError (eff.toMatrix44(), 1e-7));
+
+    Imath::Eulerf edAsEf;
+    assert (PyImath::Eulerf::convert (edObj, &edAsEf) == 1);
+    Imath::Eulerf edf (Imath::V3f (4.4f, 5.5f, 6.6f), Imath::Eulerf::ZYX);
+    assert (edAsEf.order() == edf.order());
+    assert (edAsEf.toMatrix44().equalWithAbsError (edf.toMatrix44(), 1e-6));
+
+    Imath::Eulerf iAsEf;
+    assert (PyImath::Eulerf::convert (iObj, &iAsEf) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing Eulerd:\n";
+
+    Imath::Eulerd efAsEd;
+    assert (PyImath::Eulerd::convert (efObj, &efAsEd) == 1);
+    Imath::Eulerd efd (Imath::V3d (1.1, 2.2, 3.3), Imath::Eulerd::XZY);
+    assert (efAsEd.order() == efd.order());
+    assert (efAsEd.toMatrix44().equalWithAbsError (efd.toMatrix44(), 1e-7));
+
+    Imath::Eulerd edAsEd;
+    assert (PyImath::Eulerd::convert (edObj, &edAsEd) == 1);
+    Imath::Eulerd edd (Imath::V3d (4.4, 5.5, 6.6), Imath::Eulerd::ZYX);
+    assert (edAsEd.order() == edd.order());
+    assert (edAsEd.toMatrix44().equalWithAbsError (edd.toMatrix44(), 1e-6));
+
+    Imath::Eulerd iAsEd;
+    assert (PyImath::Eulerd::convert (iObj, &iAsEd) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testFrustum ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing Frustum*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "ff = Frustumf (-1.0, -100.0, -2.0, 2.0, 3.0, -3.0, 0)\n"
+        "fd = Frustumf (-2.0, -50.0, -3.0, 3.0, 2.0, -2.0, 1)\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('Frustumf')\n"
+        "assert equal (w.nearPlane(), 1.1, 1e-7)\n"
+        "assert equal (w.farPlane(), 2.2, 1e-7)\n"
+        "assert equal (w.left(), 3.3, 1e-7)\n"
+        "assert equal (w.right(), 4.4, 1e-7)\n"
+        "assert equal (w.top(), 5.5, 1e-7)\n"
+        "assert equal (w.bottom(), 6.6, 1e-7)\n"
+        "assert w.orthographic() == 0\n"
+        "w = wrap ('Frustumd')\n"
+        "assert equal (w.nearPlane(), 1.1, 1e-6)\n"
+        "assert equal (w.farPlane(), 2.2, 1e-7)\n"
+        "assert equal (w.left(), 3.3, 1e-7)\n"
+        "assert equal (w.right(), 4.4, 1e-7)\n"
+        "assert equal (w.top(), 5.5, 1e-7)\n"
+        "assert equal (w.bottom(), 6.6, 1e-7)\n"
+        "assert w.orthographic() == 0\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> eff (mainNamespace["ff"]);
+    assert (eff.check());
+
+    PyObject *ffObj = eff().ptr();
+    assert (ffObj != 0);
+
+    extract <object> efd (mainNamespace["fd"]);
+    assert (efd.check());
+
+    PyObject *fdObj = efd().ptr();
+    assert (fdObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+    
+    std::cerr << "Testing Frustumf:\n";
+
+    Imath::Frustumf ffAsFf;
+    assert (PyImath::Frustumf::convert (ffObj, &ffAsFf) == 1);
+    assert (Imath::equalWithAbsError (ffAsFf.nearPlane(), -1.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (ffAsFf.farPlane(), -100.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (ffAsFf.left(), -2.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (ffAsFf.right(), 2.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (ffAsFf.top(), 3.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (ffAsFf.bottom(), -3.0f, 1e-7f));
+    assert (ffAsFf.orthographic() == false);
+
+    Imath::Frustumf fdAsFf;
+    assert (PyImath::Frustumf::convert (fdObj, &fdAsFf) == 1);
+    assert (Imath::equalWithAbsError (fdAsFf.nearPlane(), -2.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (fdAsFf.farPlane(), -50.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (fdAsFf.left(), -3.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (fdAsFf.right(), 3.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (fdAsFf.top(), 2.0f, 1e-7f));
+    assert (Imath::equalWithAbsError (fdAsFf.bottom(), -2.0f, 1e-7f));
+    assert (fdAsFf.orthographic() == true);
+
+    Imath::Frustumf iAsFf;
+    assert (PyImath::Frustumf::convert (iObj, &iAsFf) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing Frustumd:\n";
+
+    Imath::Frustumd ffAsFd;
+    assert (PyImath::Frustumd::convert (ffObj, &ffAsFd) == 1);
+    assert (Imath::equalWithAbsError (ffAsFd.nearPlane(), -1.0, 1e-7));
+    assert (Imath::equalWithAbsError (ffAsFd.farPlane(), -100.0, 1e-7));
+    assert (Imath::equalWithAbsError (ffAsFd.left(), -2.0, 1e-7));
+    assert (Imath::equalWithAbsError (ffAsFd.right(), 2.0, 1e-7));
+    assert (Imath::equalWithAbsError (ffAsFd.top(), 3.0, 1e-7));
+    assert (Imath::equalWithAbsError (ffAsFd.bottom(), -3.0, 1e-7));
+    assert (ffAsFd.orthographic() == false);
+
+    Imath::Frustumd fdAsFd;
+    assert (PyImath::Frustumd::convert (fdObj, &fdAsFd) == 1);
+    assert (Imath::equalWithAbsError (fdAsFd.nearPlane(), -2.0, 1e-7));
+    assert (Imath::equalWithAbsError (fdAsFd.farPlane(), -50.0, 1e-7));
+    assert (Imath::equalWithAbsError (fdAsFd.left(), -3.0, 1e-7));
+    assert (Imath::equalWithAbsError (fdAsFd.right(), 3.0, 1e-7));
+    assert (Imath::equalWithAbsError (fdAsFd.top(), 2.0, 1e-7));
+    assert (Imath::equalWithAbsError (fdAsFd.bottom(), -2.0, 1e-7));
+    assert (fdAsFd.orthographic() == true);
+
+    Imath::Frustumf iAsFd;
+    assert (PyImath::Frustumf::convert (iObj, &iAsFd) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testLine ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing Line*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "l3f = Line3f (V3f (1.1, 2.2, 3.3), V3f (4.4, 5.5, 6.6))\n"
+        "l3d = Line3d (V3d (7.7, 8.8, 9.9), V3d (10.10, 11.11, 12.12))\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('Line3f')\n"
+        "p1 = V3f (1.1, 2.2, 3.3)\n"
+        "p2 = V3f (4.4, 5.5, 6.6)\n"
+        "d = (p2 - p1).normalize()\n"
+        "assert w.pos().equalWithAbsError (p1, 1e-6)\n"
+        "assert w.dir().equalWithAbsError (d, 1e-6)\n"
+        "w = wrap ('Line3d')\n"
+        "p1 = V3d (1.1, 2.2, 3.3)\n"
+        "p2 = V3d (4.4, 5.5, 6.6)\n"
+        "d = (p2 - p1).normalize()\n"
+        "assert w.pos().equalWithAbsError (p1, 1e-6)\n"
+        "assert w.dir().equalWithAbsError (d, 1e-6)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> el3f (mainNamespace["l3f"]);
+    assert (el3f.check());
+
+    PyObject *l3fObj = el3f().ptr();
+    assert (l3fObj != 0);
+
+    extract <object> el3d (mainNamespace["l3d"]);
+    assert (el3d.check());
+
+    PyObject *l3dObj = el3d().ptr();
+    assert (l3dObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+    
+    std::cerr << "Testing Line3f:\n";
+
+    Imath::Line3f l3fAsL3f;
+    assert (PyImath::Line3f::convert (l3fObj, &l3fAsL3f) == 1);
+    Imath::V3f l3fP1f (1.1f, 2.2f, 3.3f);
+    Imath::V3f l3fP2f (4.4f, 5.5f, 6.6f);
+    Imath::V3f l3fPosf = l3fP1f;
+    Imath::V3f l3fDirf = (l3fP2f - l3fP1f).normalize();
+    assert (l3fAsL3f.pos.equalWithAbsError (l3fPosf, 1e-7));
+    assert (l3fAsL3f.dir.equalWithAbsError (l3fDirf, 1e-7));
+
+    Imath::Line3f l3dAsL3f;
+    assert (PyImath::Line3f::convert (l3dObj, &l3dAsL3f) == 1);
+    Imath::V3f l3dP1f (7.7f, 8.8f, 9.9f);
+    Imath::V3f l3dP2f (10.10f, 11.11f, 12.12f);
+    Imath::V3f l3dPosf = l3dP1f;
+    Imath::V3f l3dDirf = (l3dP2f - l3dP1f).normalize();
+    assert (l3dAsL3f.pos.equalWithAbsError (l3dPosf, 1e-7));
+    assert (l3dAsL3f.dir.equalWithAbsError (l3dDirf, 1e-6));
+
+    Imath::Line3f iAsL3f;
+    assert (PyImath::Line3f::convert (iObj, &iAsL3f) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing Line3d:\n";
+
+    Imath::Line3d l3fAsL3d;
+    assert (PyImath::Line3d::convert (l3fObj, &l3fAsL3d) == 1);
+    Imath::V3d l3fP1d (1.1, 2.2, 3.3);
+    Imath::V3d l3fP2d (4.4, 5.5, 6.6);
+    Imath::V3d l3fPosd = l3fP1d;
+    Imath::V3d l3fDird = (l3fP2d - l3fP1d).normalize();
+    assert (l3fAsL3d.pos.equalWithAbsError (l3fPosd, 1e-7));
+    assert (l3fAsL3d.dir.equalWithAbsError (l3fDird, 1e-7));
+
+    Imath::Line3d l3dAsL3d;
+    assert (PyImath::Line3d::convert (l3dObj, &l3dAsL3d) == 1);
+    Imath::V3d l3dP1d (7.7, 8.8, 9.9);
+    Imath::V3d l3dP2d (10.10, 11.11, 12.12);
+    Imath::V3d l3dPosd = l3dP1d;
+    Imath::V3d l3dDird = (l3dP2d - l3dP1d).normalize();
+    assert (l3dAsL3d.pos.equalWithAbsError (l3dPosd, 1e-7));
+    assert (l3dAsL3d.dir.equalWithAbsError (l3dDird, 1e-7));
+
+    Imath::Line3d iAsL3d;
+    assert (PyImath::Line3d::convert (iObj, &iAsL3d) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testM33 ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing M33*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "m33f = M33f ((1.1, 2.2, 3.3),\n"
+        "             (4.4, 5.5, 6.6),\n"
+        "             (7.7, 8.8, 9.9))\n"
+        "m33d = M33d ((10.10, 11.11, 12.12),\n"
+        "             (13.13, 14.14, 15.15),\n"
+        "             (16.16, 17.17, 18.18))\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('M33f')\n"
+        "assert w.equalWithAbsError (m33f, 1e-6)\n"
+        "w = wrap ('M33d')\n"
+        "m33d2 = M33d (m33f)\n"
+        "assert w.equalWithAbsError (m33d2, 1e-6)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> em33f (mainNamespace["m33f"]);
+    assert (em33f.check());
+
+    PyObject *m33fObj = em33f().ptr();
+    assert (m33fObj != 0);
+
+    extract <object> em33d (mainNamespace["m33d"]);
+    assert (em33d.check());
+
+    PyObject *m33dObj = em33d().ptr();
+    assert (m33dObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+    
+    std::cerr << "Testing M33f:\n";
+
+    Imath::M33f m33fAsM33f;
+    assert (PyImath::M33f::convert (m33fObj, &m33fAsM33f) == 1);
+    Imath::M33f m33ff (1.1f, 2.2f, 3.3f, 
+                       4.4f, 5.5f, 6.6f, 
+                       7.7f, 8.8f, 9.9f);
+    assert (m33fAsM33f.equalWithAbsError (m33ff, 1e-7));
+
+    Imath::M33f m33dAsM33f;
+    assert (PyImath::M33f::convert (m33dObj, &m33dAsM33f) == 1);
+    Imath::M33f m33df (10.10f, 11.11f, 12.12f, 
+                       13.13f, 14.14f, 15.15f, 
+                       16.16f, 17.17f, 18.18f);
+    assert (m33dAsM33f.equalWithAbsError (m33df, 1e-7));
+
+    Imath::M33f iAsM33f;
+    assert (PyImath::M33f::convert (iObj, &iAsM33f) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing M33d:\n";
+
+    Imath::M33d m33fAsM33d;
+    assert (PyImath::M33d::convert (m33fObj, &m33fAsM33d) == 1);
+    Imath::M33d m33fd (1.1, 2.2, 3.3, 
+                       4.4, 5.5, 6.6, 
+                       7.7, 8.8, 9.9);
+    assert (m33fAsM33d.equalWithAbsError (m33fd, 1e-6));
+
+    Imath::M33d m33dAsM33d;
+    assert (PyImath::M33d::convert (m33dObj, &m33dAsM33d) == 1);
+    Imath::M33d m33dd (10.10, 11.11, 12.12, 
+                       13.13, 14.14, 15.15, 
+                       16.16, 17.17, 18.18);
+    assert (m33dAsM33d.equalWithAbsError (m33dd, 1e-7));
+
+    Imath::M33d iAsM33d;
+    assert (PyImath::M33d::convert (iObj, &iAsM33d) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testM44 ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing M44*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "m44f = M44f ((1.1, 2.2, 3.3, 4.4),\n"
+        "             (5.5, 6.6, 7.7, 8.8),\n"
+        "             (9.9, 10.10, 11.11, 12.12),\n"
+        "             (13.13, 14.14, 15.15, 16.16))\n"
+        "m44d = M44d ((17.17, 18.18, 19.19, 20.20),\n"
+        "             (21.21, 22.22, 23.23, 24.24),\n"
+        "             (25.25, 26.26, 27.27, 28.28),\n"
+        "             (29.29, 30.30, 31.31, 32.32))\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('M44f')\n"
+        "assert w.equalWithAbsError (m44f, 1e-6)\n"
+        "w = wrap ('M44d')\n"
+        "m44d2 = M44d (m44f)\n"
+        "assert w.equalWithAbsError (m44d2, 1e-6)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> em44f (mainNamespace["m44f"]);
+    assert (em44f.check());
+
+    PyObject *m44fObj = em44f().ptr();
+    assert (m44fObj != 0);
+
+    extract <object> em44d (mainNamespace["m44d"]);
+    assert (em44d.check());
+
+    PyObject *m44dObj = em44d().ptr();
+    assert (m44dObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+    
+    std::cerr << "Testing M44f:\n";
+
+    Imath::M44f m44fAsM44f;
+    assert (PyImath::M44f::convert (m44fObj, &m44fAsM44f) == 1);
+    Imath::M44f m44ff (1.1f, 2.2f, 3.3f, 4.4f,
+                       5.5f, 6.6f, 7.7f, 8.8f,
+                       9.9f, 10.10f, 11.11f, 12.12f,
+                       13.13f, 14.14f, 15.15f, 16.16f);
+    assert (m44fAsM44f.equalWithAbsError (m44ff, 1e-7f));
+
+    Imath::M44f m44dAsM44f;
+    assert (PyImath::M44f::convert (m44dObj, &m44dAsM44f) == 1);
+    Imath::M44f m44df (17.17f, 18.18f, 19.19f, 20.20f,
+                       21.21f, 22.22f, 23.23f, 24.24f,
+                       25.25f, 26.26f, 27.27f, 28.28f,
+                       29.29f, 30.30f, 31.31f, 32.32f);
+    assert (m44dAsM44f.equalWithAbsError (m44df, 1e-7f));
+
+    Imath::M44f iAsM44f;
+    assert (PyImath::M44f::convert (iObj, &iAsM44f) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing M44d:\n";
+
+    Imath::M44d m44fAsM44d;
+    assert (PyImath::M44d::convert (m44fObj, &m44fAsM44d) == 1);
+    Imath::M44d m44fd (1.1, 2.2, 3.3, 4.4,
+                       5.5, 6.6, 7.7, 8.8,
+                       9.9, 10.10, 11.11, 12.12,
+                       13.13, 14.14, 15.15, 16.16);
+    assert (m44fAsM44d.equalWithAbsError (m44fd, 1e-6));
+
+    Imath::M44d m44dAsM44d;
+    assert (PyImath::M44d::convert (m44dObj, &m44dAsM44d) == 1);
+    Imath::M44d m44dd (17.17, 18.18, 19.19, 20.20,
+                       21.21, 22.22, 23.23, 24.24,
+                       25.25, 26.26, 27.27, 28.28,
+                       29.29, 30.30, 31.31, 32.32);
+    assert (m44dAsM44d.equalWithAbsError (m44dd, 1e-7));
+
+    Imath::M44d iAsM44d;
+    assert (PyImath::M44d::convert (iObj, &iAsM44d) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testPlane ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing Plane*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "p3f = Plane3f (V3f (1.1, 2.2, 3.3), 4.4)\n"
+        "p3d = Plane3d (V3d (5.5, 6.6, 7.7), 8.8)\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('Plane3f')\n"
+        "n = V3f (1.1, 2.2, 3.3).normalize()\n"
+        "assert w.normal().equalWithAbsError (n, 1e-7)\n"
+        "assert equal (w.distance(), 4.4, 1e-7)\n"
+        "w = wrap ('Plane3d')\n"
+        "n = V3d (1.1, 2.2, 3.3).normalize()\n"
+        "assert w.normal().equalWithAbsError (n, 1e-7)\n"
+        "assert equal (w.distance(), 4.4, 1e-7)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> ep3f (mainNamespace["p3f"]);
+    assert (ep3f.check());
+
+    PyObject *p3fObj = ep3f().ptr();
+    assert (p3fObj != 0);
+
+    extract <object> ep3d (mainNamespace["p3d"]);
+    assert (ep3d.check());
+
+    PyObject *p3dObj = ep3d().ptr();
+    assert (p3dObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+    
+    std::cerr << "Testing Plane3f:\n";
+
+    Imath::Plane3f p3fAsP3f;
+    assert (PyImath::Plane3f::convert (p3fObj, &p3fAsP3f) == 1);
+    Imath::V3f p3fnf (1.1f, 2.2f, 3.3f);
+    p3fnf.normalize();
+    assert (p3fAsP3f.normal.equalWithAbsError (p3fnf, 1e-6f));
+    assert (Imath::equalWithAbsError (p3fAsP3f.distance, 4.4f, 1e-7f));
+
+    Imath::Plane3f p3dAsP3f;
+    assert (PyImath::Plane3f::convert (p3dObj, &p3dAsP3f) == 1);
+    Imath::V3f p3dnf (5.5f, 6.6f, 7.7f);
+    p3dnf.normalize();
+    assert (p3dAsP3f.normal.equalWithAbsError (p3dnf, 1e-7f));
+    assert (Imath::equalWithAbsError (p3dAsP3f.distance, 8.8f, 1e-7f));
+
+    Imath::Plane3f iAsP3f;
+    assert (PyImath::Plane3f::convert (iObj, &iAsP3f) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing Plane3d:\n";
+
+    Imath::Plane3d p3fAsP3d;
+    assert (PyImath::Plane3d::convert (p3fObj, &p3fAsP3d) == 1);
+    Imath::V3d p3fnd (1.1, 2.2, 3.3);
+    p3fnd.normalize();
+    assert (p3fAsP3d.normal.equalWithAbsError (p3fnd, 1e-7));
+    assert (Imath::equalWithAbsError (p3fAsP3d.distance, 4.4, 1e-7));
+
+    Imath::Plane3d p3dAsP3d;
+    assert (PyImath::Plane3d::convert (p3dObj, &p3dAsP3d) == 1);
+    Imath::V3d p3dnd (5.5, 6.6, 7.7);
+    p3dnd.normalize();
+    assert (p3dAsP3d.normal.equalWithAbsError (p3dnd, 1e-7));
+    assert (Imath::equalWithAbsError (p3dAsP3d.distance, 8.8, 1e-7));
+
+    Imath::Plane3d iAsP3d;
+    assert (PyImath::Plane3d::convert (iObj, &iAsP3d) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testQuat ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing Quat*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "qf = Quatf (1.1, 2.2, 3.3, 4.4)\n"
+        "qd = Quatd (5.5, V3d (6.6, 7.7, 8.8))\n"
+        "t = (9.9, 10.10, 11.11, 12.12)\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('Quatf')\n"
+        "assert equal (w.r(), 1.1, 1e-7)\n"
+        "assert w.v().equalWithAbsError (V3f (2.2, 3.3, 4.4), 1e-7)\n"
+        "w = wrap ('Quatd')\n"
+        "assert equal (w.r(), 1.1, 1e-7)\n"
+        "assert w.v().equalWithAbsError (V3d (2.2, 3.3, 4.4), 1e-7)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> eqf (mainNamespace["qf"]);
+    assert (eqf.check());
+
+    PyObject *qfObj = eqf().ptr();
+    assert (qfObj != 0);
+
+    extract <object> eqd (mainNamespace["qd"]);
+    assert (eqd.check());
+
+    PyObject *qdObj = eqd().ptr();
+    assert (qdObj != 0);
+
+    extract <object> et (mainNamespace["t"]);
+    assert (et.check());
+
+    PyObject *tObj = et().ptr();
+    assert (tObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+    
+    std::cerr << "Testing Quatf:\n";
+
+    Imath::Quatf qfAsQf;
+    assert (PyImath::Quatf::convert (qfObj, &qfAsQf) == 1);
+    assert (Imath::equalWithAbsError (qfAsQf.r, 1.1f, 1e-7f));
+    assert (qfAsQf.v.equalWithAbsError (Imath::V3f (2.2f, 3.3f, 4.4f), 1e-7f));
+
+    Imath::Quatf qdAsQf;
+    assert (PyImath::Quatf::convert (qdObj, &qdAsQf) == 1);
+    assert (Imath::equalWithAbsError (qdAsQf.r, 5.5f, 1e-7f));
+    assert (qdAsQf.v.equalWithAbsError (Imath::V3f (6.6f, 7.7f, 8.8f), 1e-7f));
+
+    Imath::Quatf tAsQf;
+    assert (PyImath::Quatf::convert (tObj, &tAsQf) == 1);
+    assert (Imath::equalWithAbsError (tAsQf.r, 9.9f, 1e-7f));
+    assert (tAsQf.v.equalWithAbsError (Imath::V3f (10.10f, 11.11f, 12.12f), 1e-7f));
+
+    Imath::Quatf iAsQf;
+    assert (PyImath::Quatf::convert (iObj, &iAsQf) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+    
+    std::cerr << "Testing Quatd:\n";
+
+    Imath::Quatd qfAsQd;
+    assert (PyImath::Quatd::convert (qfObj, &qfAsQd) == 1);
+    assert (Imath::equalWithAbsError (qfAsQd.r, 1.1, 1e-7));
+    assert (qfAsQd.v.equalWithAbsError (Imath::V3d (2.2, 3.3, 4.4), 1e-7));
+
+    Imath::Quatd qdAsQd;
+    assert (PyImath::Quatd::convert (qdObj, &qdAsQd) == 1);
+    assert (Imath::equalWithAbsError (qdAsQd.r, 5.5, 1e-7));
+    assert (qdAsQd.v.equalWithAbsError (Imath::V3d (6.6, 7.7, 8.8), 1e-7));
+
+    Imath::Quatd tAsQd;
+    assert (PyImath::Quatd::convert (tObj, &tAsQd) == 1);
+    assert (Imath::equalWithAbsError (tAsQd.r, 9.9, 1e-7));
+    assert (tAsQd.v.equalWithAbsError (Imath::V3d (10.10, 11.11, 12.12), 1e-7));
+
+    Imath::Quatd iAsQd;
+    assert (PyImath::Quatd::convert (iObj, &iAsQd) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testRandom ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing Random*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "from wrap import *\n"
+        "w = wrap ('Rand32')\n"
+        "r1 = w.nextf()\n"
+        "r2 = w.nextf()\n"
+        "assert r1 != r2\n"
+        "w = wrap ('Rand48')\n"
+        "r1 = w.nextf()\n"
+        "r2 = w.nextf()\n"
+        "assert r1 != r2\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+    
+    std::cerr << "Testing Rand32:\n";
+
+    std::cerr << "ok\n";
+
+    //
+    
+    std::cerr << "Testing Rand48:\n";
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testShear ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing Shear6*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "s6f = Shear6f (1.1, 2.2, 3.3, 4.4, 5.5, 6.6)\n"
+        "s6d = Shear6d (7.7, 8.8, 9.9, 10.10, 11.11, 12.12)\n"
+        "t3 = (13.13, 14.14, 15.15)\n"
+        "t6 = (16.16, 17.17, 18.18, 19.19, 20.20, 21.21)\n"
+        "v3i = V3i (22, 23, 24)\n"
+        "v3f = V3f (25.25, 26.26, 27.27)\n"
+        "v3d = V3d (28.28, 29.29, 30.30)\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('Shear6f')\n"
+        "assert w.equalWithAbsError (s6f, 1e-6)\n"
+        "w = wrap ('Shear6d')\n"
+        "s6d2 = Shear6d (s6f)\n"
+        "assert w.equalWithAbsError (s6d2, 1e-6)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> es6f (mainNamespace["s6f"]);
+    assert (es6f.check());
+    PyObject *s6fObj = es6f().ptr();
+    assert (s6fObj != 0);
+
+    extract <object> es6d (mainNamespace["s6d"]);
+    assert (es6d.check());
+
+    PyObject *s6dObj = es6d().ptr();
+    assert (s6dObj != 0);
+
+    extract <object> et3 (mainNamespace["t3"]);
+    assert (et3.check());
+
+    PyObject *t3Obj = et3().ptr();
+    assert (t3Obj != 0);
+
+    extract <object> et6 (mainNamespace["t6"]);
+    assert (et6.check());
+
+    PyObject *t6Obj = et6().ptr();
+    assert (t6Obj != 0);
+
+    extract <object> ev3i (mainNamespace ["v3i"]);
+    assert (ev3i.check());
+
+    PyObject *v3iObj = ev3i().ptr();
+    assert (v3iObj != 0);
+
+    extract <object> ev3f (mainNamespace ["v3f"]);
+    assert (ev3f.check());
+    
+    PyObject *v3fObj = ev3f().ptr();
+    assert (v3fObj != 0);
+
+    extract <object> ev3d (mainNamespace ["v3d"]);
+    assert (ev3d.check());
+    
+    PyObject *v3dObj = ev3d().ptr();
+    assert (v3dObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+    
+    std::cerr << "Testing Shear6f:\n";
+
+    Imath::Shear6f s6fAsS6f;
+    assert (PyImath::Shear6f::convert (s6fObj, &s6fAsS6f) == 1);
+    Imath::Shear6f s6ff (1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f);
+    assert (s6fAsS6f.equalWithAbsError (s6ff, 1e-7f));
+
+    Imath::Shear6f s6dAsS6f;
+    assert (PyImath::Shear6f::convert (s6dObj, &s6dAsS6f) == 1);
+    Imath::Shear6f s6df (7.7f, 8.8f, 9.9f, 10.10f, 11.11f, 12.12f);
+    assert (s6dAsS6f.equalWithAbsError (s6df, 1e-7f));
+
+    Imath::Shear6f t3AsS6f;
+    assert (PyImath::Shear6f::convert (t3Obj, &t3AsS6f) == 1);
+    Imath::Shear6f t3f (13.13f, 14.14f, 15.15f, 0, 0, 0);
+    assert (t3AsS6f.equalWithAbsError (t3f, 1e-7f));
+
+    Imath::Shear6f t6AsS6f;
+    assert (PyImath::Shear6f::convert (t6Obj, &t6AsS6f) == 1);
+    Imath::Shear6f t6f (16.16f, 17.17f, 18.18f, 19.19f, 20.20f, 21.21f);
+    assert (t6AsS6f.equalWithAbsError (t6f, 1e-7f));
+
+    Imath::Shear6f v3iAsS6f;
+    assert (PyImath::Shear6f::convert (v3iObj, &v3iAsS6f) == 1);
+    Imath::Shear6f v3if (22.0f, 23.0f, 24.0f, 0, 0, 0);
+    assert (v3iAsS6f.equalWithAbsError (v3if, 1e-7f));
+
+    Imath::Shear6f v3fAsS6f;
+    assert (PyImath::Shear6f::convert (v3fObj, &v3fAsS6f) == 1);
+    Imath::Shear6f v3ff (25.25f, 26.26f, 27.27f, 0, 0, 0);
+    assert (v3fAsS6f.equalWithAbsError (v3ff, 1e-7f));
+
+    Imath::Shear6f v3dAsS6f;
+    assert (PyImath::Shear6f::convert (v3dObj, &v3dAsS6f) == 1);
+    Imath::Shear6f v3df (28.28f, 29.29f, 30.30f, 0, 0, 0);
+    assert (v3dAsS6f.equalWithAbsError (v3df, 1e-7f));
+
+    Imath::Shear6f iAsS6f;
+    assert (PyImath::Shear6f::convert (iObj, &iAsS6f) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing Shear6d:\n";
+
+    Imath::Shear6d s6fAsS6d;
+    assert (PyImath::Shear6d::convert (s6fObj, &s6fAsS6d) == 1);
+    Imath::Shear6d s6fd (1.1, 2.2, 3.3, 4.4, 5.5, 6.6);
+    assert (s6fAsS6d.equalWithAbsError (s6fd, 1e-7));
+
+    Imath::Shear6d s6dAsS6d;
+    assert (PyImath::Shear6d::convert (s6dObj, &s6dAsS6d) == 1);
+    Imath::Shear6d s6dd (7.7, 8.8, 9.9, 10.10, 11.11, 12.12);
+    assert (s6dAsS6d.equalWithAbsError (s6dd, 1e-7));
+
+    Imath::Shear6d t3AsS6d;
+    assert (PyImath::Shear6d::convert (t3Obj, &t3AsS6d) == 1);
+    Imath::Shear6d t3d (13.13, 14.14, 15.15, 0, 0, 0);
+    assert (t3AsS6d.equalWithAbsError (t3d, 1e-7));
+
+    Imath::Shear6d t6AsS6d;
+    assert (PyImath::Shear6d::convert (t6Obj, &t6AsS6d) == 1);
+    Imath::Shear6d t6d (16.16, 17.17, 18.18, 19.19, 20.20, 21.21);
+    assert (t6AsS6d.equalWithAbsError (t6d, 1e-7));
+
+    Imath::Shear6d v3iAsS6d;
+    assert (PyImath::Shear6d::convert (v3iObj, &v3iAsS6d) == 1);
+    Imath::Shear6d v3id (22.0, 23.0, 24.0, 0, 0, 0);
+    assert (v3iAsS6d.equalWithAbsError (v3id, 1e-7));
+
+    Imath::Shear6d v3fAsS6d;
+    assert (PyImath::Shear6d::convert (v3fObj, &v3fAsS6d) == 1);
+    Imath::Shear6d v3fd (25.25, 26.26, 27.27, 0, 0, 0);
+    assert (v3fAsS6d.equalWithAbsError (v3fd, 1e-6));
+
+    Imath::Shear6d v3dAsS6d;
+    assert (PyImath::Shear6d::convert (v3dObj, &v3dAsS6d) == 1);
+    Imath::Shear6d v3dd (28.28, 29.29, 30.30, 0, 0, 0);
+    assert (v3dAsS6d.equalWithAbsError (v3dd, 1e-7));
+
+    Imath::Shear6d iAsS6d;
+    assert (PyImath::Shear6d::convert (iObj, &iAsS6d) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testV2 ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing V2*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "v2i = V2i (1, 2)\n"
+        "v2f = V2f (3.3, 4.4)\n"
+        "v2d = V2d (5.5, 6.6)\n"
+        "t = (7, 8)\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('V2i')\n"
+        "assert w == V2i (1, 2)\n"
+        "w = wrap ('V2f')\n"
+        "assert w.equalWithAbsError (V2f (1.1, 2.2), 1e-7)\n"
+        "w = wrap ('V2d')\n"
+        "assert w.equalWithAbsError (V2d (1.1, 2.2), 1e-7)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> ev2i (mainNamespace ["v2i"]);
+    assert (ev2i.check());
+    
+    PyObject *v2iObj = ev2i().ptr();
+    assert (v2iObj != 0);
+
+    extract <object> ev2f (mainNamespace ["v2f"]);
+    assert (ev2f.check());
+    
+    PyObject *v2fObj = ev2f().ptr();
+    assert (v2fObj != 0);
+
+    extract <object> ev2d (mainNamespace ["v2d"]);
+    assert (ev2d.check());
+    
+    PyObject *v2dObj = ev2d().ptr();
+    assert (v2dObj != 0);
+
+    extract <object> et (mainNamespace["t"]);
+    assert (et.check());
+
+    PyObject *tObj = et().ptr();
+    assert (tObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+
+    std::cerr << "Testing V2i:\n";
+
+    Imath::V2i v2iAsV2i;
+    assert (PyImath::V2i::convert (v2iObj, &v2iAsV2i) == 1);
+    assert (v2iAsV2i == Imath::V2i (1, 2));
+
+    Imath::V2i v2fAsV2i;
+    assert (PyImath::V2i::convert (v2fObj, &v2fAsV2i) == 1);
+    assert (v2fAsV2i == Imath::V2i (3, 4));
+
+    Imath::V2i v2dAsV2i;
+    assert (PyImath::V2i::convert (v2dObj, &v2dAsV2i) == 1);
+    assert (v2dAsV2i == Imath::V2i (5, 6));
+
+    Imath::V2i tAsV2i;
+    assert (PyImath::V2i::convert (tObj, &tAsV2i) == 1);
+    assert (tAsV2i == Imath::V2i (7, 8));
+
+    Imath::V2i iAsV2i;
+    assert (PyImath::V2i::convert (iObj, &iAsV2i) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing V2f:\n";
+
+    Imath::V2f v2iAsV2f;
+    assert (PyImath::V2f::convert (v2iObj, &v2iAsV2f) == 1);
+    assert (v2iAsV2f.equalWithAbsError (Imath::V2f (1.0f, 2.0f), 1e-7));
+
+    Imath::V2f v2fAsV2f;
+    assert (PyImath::V2f::convert (v2fObj, &v2fAsV2f) == 1);
+    assert (v2fAsV2f.equalWithAbsError (Imath::V2f (3.3f, 4.4f), 1e-7));
+
+    Imath::V2f v2dAsV2f;
+    assert (PyImath::V2f::convert (v2dObj, &v2dAsV2f) == 1);
+    assert (v2dAsV2f.equalWithAbsError (Imath::V2f (5.5f, 6.6f), 1e-7));
+
+    Imath::V2f tAsV2f;
+    assert (PyImath::V2f::convert (tObj, &tAsV2f) == 1);
+    assert (tAsV2f.equalWithAbsError (Imath::V2f (7.0f, 8.0f), 1e-7));
+
+    Imath::V2f iAsV2f;
+    assert (PyImath::V2f::convert (iObj, &iAsV2f) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing V2d:\n";
+
+    Imath::V2d v2iAsV2d;
+    assert (PyImath::V2d::convert (v2iObj, &v2iAsV2d) == 1);
+    assert (v2iAsV2d.equalWithAbsError (Imath::V2d (1.0, 2.0), 1e-7));
+
+    Imath::V2d v2fAsV2d;
+    assert (PyImath::V2d::convert (v2fObj, &v2fAsV2d) == 1);
+    assert (v2fAsV2d.equalWithAbsError (Imath::V2f (3.3, 4.4), 1e-7));
+
+    Imath::V2d v2dAsV2d;
+    assert (PyImath::V2d::convert (v2dObj, &v2dAsV2d) == 1);
+    assert (v2dAsV2d.equalWithAbsError (Imath::V2f (5.5, 6.6), 1e-7));
+
+    Imath::V2d tAsV2d;
+    assert (PyImath::V2d::convert (tObj, &tAsV2d) == 1);
+    assert (tAsV2d.equalWithAbsError (Imath::V2d (7.0, 8.0), 1e-7));
+
+    Imath::V2d iAsV2d;
+    assert (PyImath::V2d::convert (iObj, &iAsV2d) == 0);
+
+    std::cerr << "ok\n";
+}
+
+
+void
+testV3 ()
+{
+    object mainModule ((handle<> (borrowed (PyImport_AddModule ("__main__")))));
+    object mainNamespace = mainModule.attr ("__dict__");
+
+    std::cerr << "Testing V3*:\n";
+
+    std::string code = 
+        "from imath import *\n"
+        "v3i = V3i (1, 2, 3)\n"
+        "v3f = V3f (4.4, 5.5, 6.6)\n"
+        "v3d = V3d (7.7, 8.8, 9.9)\n"
+        "t = (10, 11, 12)\n"
+        "i = 1\n"
+        "from wrap import *\n"
+        "w = wrap ('V3i')\n"
+        "assert w == V3i (1, 2, 3)\n"
+        "w = wrap ('V3f')\n"
+        "assert w.equalWithAbsError (V3f (1.1, 2.2, 3.3), 1e-7)\n"
+        "w = wrap ('V3d')\n"
+        "assert w.equalWithAbsError (V3d (1.1, 2.2, 3.3), 1e-7)\n";
+
+    handle<> ignored (PyRun_String (code.c_str(), Py_file_input, 
+                                    mainNamespace.ptr(), mainNamespace.ptr()));
+
+    //
+
+    extract <object> ev3i (mainNamespace ["v3i"]);
+    assert (ev3i.check());
+
+    PyObject *v3iObj = ev3i().ptr();
+    assert (v3iObj != 0);
+
+    extract <object> ev3f (mainNamespace ["v3f"]);
+    assert (ev3f.check());
+    
+    PyObject *v3fObj = ev3f().ptr();
+    assert (v3fObj != 0);
+
+    extract <object> ev3d (mainNamespace ["v3d"]);
+    assert (ev3d.check());
+    
+    PyObject *v3dObj = ev3d().ptr();
+    assert (v3dObj != 0);
+
+    extract <object> et (mainNamespace["t"]);
+    assert (et.check());
+
+    PyObject *tObj = et().ptr();
+    assert (tObj != 0);
+
+    extract <object> ei (mainNamespace["i"]);
+    assert (ei.check());
+
+    PyObject *iObj = ei().ptr();
+    assert (iObj != 0);
+
+    //
+    
+    std::cerr << "Testing V3i:\n";
+
+    Imath::V3i v3iAsV3i;
+    assert (PyImath::V3i::convert (v3iObj, &v3iAsV3i) == 1);
+    assert (v3iAsV3i == Imath::V3i (1, 2, 3));
+
+    Imath::V3i v3fAsV3i;
+    assert (PyImath::V3i::convert (v3fObj, &v3fAsV3i) == 1);
+    assert (v3fAsV3i == Imath::V3i (4, 5, 6));
+
+    Imath::V3d v3iAsV3d;
+    assert (PyImath::V3d::convert (v3iObj, &v3iAsV3d) == 1);
+    assert (v3iAsV3d.equalWithAbsError (Imath::V3d (1.0, 2.0, 3.0), 1e-7));
+
+    Imath::V3i tAsV3i;
+    assert (PyImath::V3i::convert (tObj, &tAsV3i) == 1);
+    assert (tAsV3i == Imath::V3i (10, 11, 12));
+
+    Imath::V3i iAsV3i;
+    assert (PyImath::V3i::convert (iObj, &iAsV3i) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing V3f:\n";
+
+    Imath::V3f v3iAsV3f;
+    assert (PyImath::V3f::convert (v3iObj, &v3iAsV3f) == 1);
+    assert (v3iAsV3f.equalWithAbsError (Imath::V3f (1.0f, 2.0f, 3.0f), 1e-7));
+
+    Imath::V3f v3fAsV3f;
+    assert (PyImath::V3f::convert (v3fObj, &v3fAsV3f) == 1);
+    assert (v3fAsV3f.equalWithAbsError (Imath::V3f (4.4f, 5.5f, 6.6f), 1e-7));
+
+    Imath::V3f v3dAsV3f;
+    assert (PyImath::V3f::convert (v3dObj, &v3dAsV3f) == 1);
+    assert (v3dAsV3f.equalWithAbsError (Imath::V3f (7.7f, 8.8f, 9.9f), 1e-7));
+
+    Imath::V3f tAsV3f;
+    assert (PyImath::V3f::convert (tObj, &tAsV3f) == 1);
+    assert (tAsV3f.equalWithAbsError (Imath::V3f (10.0f, 11.0f, 12.0f), 1e-7));
+
+    Imath::V3f iAsV3f;
+    assert (PyImath::V3f::convert (iObj, &iAsV3f) == 0);
+
+    std::cerr << "ok\n";
+
+    //
+
+    std::cerr << "Testing V3d:\n";
+
+    Imath::V3i v3dAsV3i;
+    assert (PyImath::V3i::convert (v3dObj, &v3dAsV3i) == 1);
+    assert (v3dAsV3i == Imath::V3i (7, 8, 9));
+
+    Imath::V3d v3fAsV3d;
+    assert (PyImath::V3d::convert (v3fObj, &v3fAsV3d) == 1);
+    assert (v3fAsV3d.equalWithAbsError (Imath::V3f (4.4, 5.5, 6.6), 1e-7));
+
+    Imath::V3d v3dAsV3d;
+    assert (PyImath::V3d::convert (v3dObj, &v3dAsV3d) == 1);
+    assert (v3dAsV3d.equalWithAbsError (Imath::V3f (7.7, 8.8, 9.9), 1e-6));
+
+    Imath::V3d tAsV3d;
+    assert (PyImath::V3d::convert (tObj, &tAsV3d) == 1);
+    assert (tAsV3d.equalWithAbsError (Imath::V3d (10.0, 11.0, 12.0), 1e-7));
+
+    Imath::V3d iAsV3d;
+    assert (PyImath::V3d::convert (iObj, &iAsV3d) == 0);
+
+    std::cerr << "ok\n";
+}
+
+int
+main (int argc, char *argv[])
+{
+    Py_Initialize();
+    if (Py_IsInitialized())
+    {
+        initWrapTester();
+
+        TEST (testBox2);
+        TEST (testBox3);
+        TEST (testC3);
+        TEST (testC4);
+        TEST (testEuler);
+        TEST (testFrustum);
+        TEST (testLine);
+        TEST (testM33);
+        TEST (testM44);
+        TEST (testPlane);
+        TEST (testQuat);
+        TEST (testRandom);
+        TEST (testShear);
+        TEST (testV2);
+        TEST (testV3);
+    
+        Py_Finalize();
+    }
+
+    TEST (testStringTable);
+
+    return 0;
+}
diff --git a/src/python/PyImathTest/pyImathTest.in b/src/python/PyImathTest/pyImathTest.in
new file mode 100644 (file)
index 0000000..dc9be34
--- /dev/null
@@ -0,0 +1,10320 @@
+#!@PYTHON@
+
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+#
+
+from imath import *
+from math import sqrt, pi, sin, cos
+import math
+import string, traceback, sys
+import random
+
+testList = []
+
+# -----------------------------------------------------------------
+# Test helper functions
+# -----------------------------------------------------------------
+
+ArrayBaseType = {}
+ArrayBaseType[V2sArray] = V2s
+ArrayBaseType[V2iArray] = V2i
+ArrayBaseType[V2fArray] = V2f
+ArrayBaseType[V2dArray] = V2d
+ArrayBaseType[V3sArray] = V3s
+ArrayBaseType[V3iArray] = V3i
+ArrayBaseType[V3fArray] = V3f
+ArrayBaseType[V3dArray] = V3d
+
+VecBaseType = {}
+VecBaseType[V2s] = int
+VecBaseType[V2i] = int
+VecBaseType[V2f] = float
+VecBaseType[V2d] = float
+VecBaseType[V3s] = int
+VecBaseType[V3i] = int
+VecBaseType[V3f] = float
+VecBaseType[V3d] = float
+
+eps = 10*FLT_EPS
+
+def dimensions(baseType):
+    if hasattr(baseType, 'dimensions'):
+        return baseType.dimensions()
+    else:
+        return 1
+
+def numNonZeroMaskEntries(mask):
+    count = 0
+    for i in range(0, len(mask)):
+        if mask[i]:
+            count += 1
+    return count
+
+def equalWithAbsErrorScalar(x1, x2, e):
+    return abs(x1 - x2) < e
+
+def make_range(start, end):
+    num = end-start
+    increment = 1
+    if num < 0:
+        num = -num;
+        increment = -1
+
+    retval = IntArray(num)
+    val = start
+    for i in range(0, num):
+        retval[i] = val
+        val += increment
+
+    return retval
+
+# We want to be able to use the test helper
+# functions generically with different array types
+# so we use hasattr to check if the arguments support
+# [] operator.  This is sufficient to distinguish
+# between vector and scalar types for our purposes here
+
+def equalWithAbsError(x1, x2, e):
+    if hasattr(x1, '__len__') and hasattr(x1, '__getitem__') and hasattr(x2, '__len__') and hasattr(x2, '__getitem__'):
+        assert(len(x1) == len(x2))
+        for i in range(0, len(x1)):
+            if not equalWithAbsErrorScalar(x1[i], x2[i], e):
+                return False
+        return True
+    else:
+        return equalWithAbsErrorScalar(x1, x2, e)
+
+def equalWithRelErrorScalar(x1, x2, e):
+    return abs(x1 - x2) <= e * abs(x1)
+
+def equalWithRelError(x1, x2, e):
+    if hasattr(x1, '__len__') and hasattr(x1, '__getitem__') and hasattr(x2, '__len__') and hasattr(x2, '__getitem__'):
+        assert(len(x1) == len(x2))
+        for i in range(0, len(x1)):
+            if not equalWithRelErrorScalar(x1[i], x2[i], e):
+                return False
+        return True
+    else:
+        return equalWithRelErrorScalar(x1, x2, e)
+
+def testVectorVectorArithmeticOps(f1, f2):
+    f = f1 + f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] + f2[i])
+
+    f = f1 - f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] - f2[i])
+
+    f = f1 * f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] * f2[i])
+
+    f = f1 / f2
+    assert(len(f) == len(f1))
+
+    if isinstance(f,IntArray) or isinstance(f,ShortArray):
+        op = lambda a,b : a // b
+    else:
+        op = lambda a,b : a / b
+    for i in range(0, len(f)):
+        assert(equalWithAbsError(f[i], op(f1[i],f2[i]), eps))
+
+    f = -f1
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == -f1[i])
+
+def testVectorScalarArithmeticOps(f1, v):
+    f = f1 + v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] + v)
+
+    f = v + f1
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == v + f1[i])
+
+    f = f1 - v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] - v)
+
+    f = v - f1
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if f[i] != v - f1[i]:
+            assert(f[i] == v - f1[i])
+
+    f = f1 * v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] * v)
+
+    f = v * f1
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == v * f1[i])
+
+    f = f1 / v
+    assert(len(f) == len(f1))
+    if isinstance(f,IntArray) or isinstance(f,ShortArray):
+        op = lambda a,b : a // b
+    else:
+        op = lambda a,b : a / b
+    for i in range(0, len(f)):
+        assert(equalWithAbsError(f[i], op(f1[i],v), eps))
+
+
+def testVectorVectorInPlaceArithmeticOps(f1, f2):
+    f = f1[:]
+    f += f2
+
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] + f2[i])
+
+    f = f1[:]
+    f -= f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] - f2[i])
+
+    f = f1[:]
+    f *= f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] * f2[i])
+
+    f = f1[:]
+    f /= f2
+    assert(len(f) == len(f1))
+    if isinstance(f,IntArray) or isinstance(f,ShortArray):
+        op = lambda a,b : a // b
+    else:
+        op = lambda a,b : a / b
+    for i in range(0, len(f)):
+        assert(equalWithAbsError(f[i], op(f1[i],f2[i]), eps))
+
+    f = f1[:]
+    f = -f;
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == -f1[i])
+
+def testVectorScalarInPlaceArithmeticOps(f1, v):
+    f = f1[:]
+    f += v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] + v)
+
+    f = f1[:]
+    f -= v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] - v)
+
+    f = f1[:]
+    f *= v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] * v)
+
+    f = f1[:]
+    f /= v
+    assert(len(f) == len(f1))
+    if isinstance(f,IntArray) or isinstance(f,ShortArray):
+        op = lambda a,b : a // b
+    else:
+        op = lambda a,b : a / b
+    for i in range(0, len(f)):
+        assert(equalWithAbsError(f[i], op(f1[i],v), eps))
+
+def testPowFunctions(f1, f2):
+    # vector-vector pow
+    assert(len(f1) == len(f2))
+    f = pow(f1, f2)
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(equalWithRelError(f[i], pow(f1[i], f2[i]), eps))
+
+    f  = f1 ** f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(equalWithRelError(f[i], f1[i] ** f2[i], eps))
+
+    # vector-scalar pow
+    v = f2[0]
+    f = pow(f1, v)
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(equalWithRelError(f[i], pow(f1[i], v), eps))
+
+    # in-place vector-vector pow
+    f = f1[:]
+    f **= f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(equalWithRelError(f[i], pow(f1[i], f2[i]), eps))
+
+    # in-place vector-scalar pow
+    f = f1[:]
+    v = f2[0]
+    f **= v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(equalWithRelError(f[i], f1[i] ** v, eps))
+
+def testModOps(f1, f2):
+    f = f1 % f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] % f2[i])
+
+    v = f2[0]
+    f = f1 % v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] %v)
+
+    f = f1[:]
+    f %= f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] % f2[i])
+
+
+def testVectorVectorComparisonOps(f1, f2):
+    f = f1 == f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (f1[i] == f2[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = f1 != f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (f1[i] != f2[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+def testVectorVectorInequalityOps(f1, f2):
+    f = f1 < f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (f1[i] < f2[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = f1 > f2
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (f1[i] > f2[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = f1 <= f2
+    for i in range(0, len(f)):
+        if (f1[i] <= f2[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = f1 >= f2
+    for i in range(0, len(f)):
+        if (f1[i] >= f2[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+def testVectorScalarComparisonOps(f1, v):
+    f = f1 == v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (f1[i] == v):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = v == f1
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (v == f1[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = f1 != v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (f1[i] != v):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = v != f1
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (v != f1[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+def testVectorScalarInequalityOps(f1, v):
+    f = f1 < v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (f1[i] < v):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = v < f1
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (v < f1[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = f1 > v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (f1[i] > v):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = v > f1
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        if (v > f1[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = f1 <= v
+    for i in range(0, len(f)):
+        if (f1[i] <= v):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = v <= f1
+    for i in range(0, len(f)):
+        if (v <= f1[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = f1 >= v
+    for i in range(0, len(f)):
+        if (f1[i] >= v):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+    f = v >= f1
+    for i in range(0, len(f)):
+        if (v >= f1[i]):
+            assert(f[i] == 1)
+        else:
+            assert(f[i] == 0)
+
+
+# f1 and f2 are assumed to be unmasked arrays of the same length
+def testVectorVectorMaskedInPlaceArithmeticOps(f1, f2, m):
+    assert(len(f1) == len(f2))
+
+    f = f1[:]
+    f[m] += f2
+    for i in range(0, len(m)):
+        if m[i]: assert(f[i] == f1[i] + f2[i])
+
+    f = f1[:]
+    f[m] -= f2
+    for i in range(0, len(m)):
+        if m[i]: assert(f[i] == f1[i] - f2[i])
+
+    f = f1[:]
+    f[m] *= f2
+    for i in range(0, len(m)):
+        if m[i]: assert(f[i] == f1[i] * f2[i])
+
+    f = f1[:]
+    f[m] /= f2
+    if isinstance(f,IntArray) or isinstance(f,ShortArray):
+        op = lambda a,b : a // b
+    else:
+        op = lambda a,b : a / b
+    for i in range(0, len(m)):
+        if m[i]: assert(equalWithAbsError(f[i], op(f1[i],f2[i]), eps))
+
+    f = f1[:]
+    f[m] = -f
+    for i in range(0, len(m)):
+        if m[i]: assert(f[i] == -f1[i])
+
+# f1 is assumed to be an unmasked array and f2 is a masked
+# or unmasked array such that len(f2) == len(f1[m])
+def testVectorVectorMaskedInPlaceArithmeticOps2(f1, f2, m):
+    assert(len(f1[m]) == len(f2))
+    f = f1[:]
+    f1m = f1[m]
+    f[m] += f2
+    fm = f[m]
+
+    for i in range(0, len(fm)):
+        assert(fm[i] == f1m[i] + f2[i])
+
+    for i in range(0, len(m)):
+        if m[i] == 0:
+            assert(f[i] == f1[i])
+
+    f = f1[:]
+    f[m] -= f2
+    fm = f[m]
+
+    for i in range(0, len(fm)):
+        assert(fm[i] == f1m[i] - f2[i])
+    
+    for i in range(0, len(m)):
+        if m[i] == 0:
+            assert(f[i] == f1[i])
+
+    f = f1[:]
+    f[m] *= f2
+    fm = f[m]
+
+    for i in range(0, len(fm)):
+        assert(fm[i] == f1m[i] * f2[i])
+    
+    for i in range(0, len(m)):
+        if m[i] == 0:
+            assert(f[i] == f1[i])
+
+    f = f1[:]
+    f[m] /= f2
+    fm = f[m]
+
+    if isinstance(f,IntArray) or isinstance(f,ShortArray):
+        op = lambda a,b : a // b
+    else:
+        op = lambda a,b : a / b
+    for i in range(0, len(fm)):
+        assert(equalWithAbsError(fm[i], op(f1m[i],f2[i]), eps))
+    
+    for i in range(0, len(m)):
+        if m[i] == 0:
+            assert(f[i] == f1[i])
+
+def testVectorVectorMaskedArithmeticOps(f1, f2, f3, m):
+    f = f3[:]
+    f[m] = f1[m] + f2[m]
+    for i in range(0, len(m)):
+        if m[i]: assert(f[i] == f1[i] + f2[i])
+        else:    assert(f[i] == f3[i])
+
+    f = f3[:]
+    f[m] = f1[m] - f2[m]
+    for i in range(0, len(m)):
+        if m[i]: assert(f[i] == f1[i] - f2[i])
+        else:    assert(f[i] == f3[i])
+
+    f = f3[:]
+    f[m] = f1[m] * f2[m]
+    for i in range(0, len(m)):
+        if m[i]: assert(f[i] == f1[i] * f2[i])
+        else:    assert(f[i] == f3[i])
+
+    f = f3[:]
+    f[m] = f1[m] / f2[m]
+    if isinstance(f,IntArray) or isinstance(f,ShortArray):
+        op = lambda a,b : a // b
+    else:
+        op = lambda a,b : a / b
+    for i in range(0, len(m)):
+        if m[i]: assert(equalWithRelError(f[i], op(f1[i],f2[i]), eps))
+        else:    assert(f[i] == f3[i])
+
+
+def testUnaryVecMethods(f):
+    g = f.length2()
+    assert(len(g) == len(f))
+    for i in range(0, len(f)):
+        assert(g[i] == f[i].length2())
+
+    # Normalization and length only makes sense for these types
+    if type(f) in [V2fArray, V2dArray, V3fArray, V3dArray]:
+        g = f.length()
+        assert(len(g) == len(f))
+        for i in range(0, len(f)):
+            assert(equalWithRelError(g[i], f[i].length(), eps))
+
+        g = f[:]
+        g.normalize()
+        assert(len(g) == len(f))
+        for i in range(0, len(f)):
+            assert(g[i] == f[i].normalized())
+
+        g = f.normalized()
+        assert(len(g) == len(f))
+        for i in range(0, len(f)):
+            assert(g[i] == f[i].normalized())
+
+
+def testBinaryVecMethods(f1, f2):
+    f = f1.dot(f2)
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i].dot(f2[i]))
+
+    assert(f1.dot(f2) == f2.dot(f1))
+
+    f = f1.cross(f2)
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(equalWithAbsError(f[i], f1[i].cross(f2[i]), eps))
+
+    assert(f1.cross(f2) == -f2.cross(f1))
+
+    v = f2[0]
+    f = f1.dot(v)
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i].dot(v))
+
+    assert(f1.dot(v) == v.dot(f1))
+
+    f = f1.cross(v)
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(equalWithAbsError(f[i], f1[i].cross(v), eps))
+
+    assert(f1.cross(v) == -v.cross(f1))
+
+
+def assertVectorVectorArithmeticOpFailures(f1, f2):
+    try:
+        f = f1 + f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f = f1 - f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f = f1 * f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f = f1 / f2
+    except:
+        pass
+    else:
+        assert(False)
+
+def assertVectorVectorInPlaceArithmeticOpFailures(f1, f2):
+    try:
+        f1 += f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f1 -= f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f1 *= f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f1 /= f2
+    except:
+        pass
+    else:
+        assert(False)
+
+def assertVectorVectorComparisonOpFailures(f1, f2):
+    try:
+        f1 == f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f1 != f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f1 < f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f1 > f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f1 <= f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f1 >= f2
+    except:
+        pass
+    else:
+        assert(False)
+
+def assertPowFunctionFailures(f1, f2):
+    try:
+        f1 ** f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f1 **= f2
+    except:
+        pass
+    else:
+        assert(False)
+
+def assertModOpFailures(f1, f2):
+    try:
+        f1 % f2
+    except:
+        pass
+    else:
+        assert(False)
+
+    try:
+        f1 %= f2
+    except:
+        pass
+    else:
+        assert(False)
+
+def testArrayArrayEquality(a1,a2):
+    assert len(a1) == len(a2)
+    for i in range(0, len(a1)):
+        assert a1[i] == a2[i]
+
+# -----------------------------------------------------------------
+# Begin main test definitions
+# -----------------------------------------------------------------
+
+def testSlicesOnArrayImpl(Array, BaseTypeConstructor):
+    
+    # Test the slicing operators on array types.
+    # We use a python list as a reference here.
+
+    size = 4
+
+    a = Array(size)
+    l = []
+
+    for i in range(0,size):
+        n = BaseTypeConstructor(i)
+        a[i] = n
+        l.append(n)
+
+    # Test extraction using slices
+
+    a1 = a[::2]
+    l1 = l[::2]
+    testArrayArrayEquality(a1, l1)
+
+    a2 = a[::-1]
+    l2 = l[::-1]
+    testArrayArrayEquality(a2, l2)
+
+    a3 = a[1:size]
+    l3 = l[1:size]
+    testArrayArrayEquality(a3, l3)
+
+    a4 = a[:size]
+    l4 = l[:size]
+    testArrayArrayEquality(a4, l4)
+
+    a5 = a[:-1]
+    l5 = l[:-1]
+    testArrayArrayEquality(a5, l5)
+
+    a6 = a[1:]
+    l6 = l[1:]
+    testArrayArrayEquality(a6, l6)
+
+    testArrayArrayEquality(a,a[:])
+
+    # Test assignment using slices
+
+    a8 = a
+    l8 = l
+    a8[::2] = a8[::-2]
+    l8[::2] = a8[::-2]
+
+    testArrayArrayEquality(a8,l8)
+
+    try:
+        a9 = a
+        a9[::1] = a9[::2]
+    except:
+        pass
+    else:
+        assert(False)
+
+    # Test that a sliced array does not share
+    # the same internal data
+    a10 = a[:]
+    a10[0] = BaseTypeConstructor(size)
+
+    assert a10[0] != a[0]
+
+def testSlicesOnArray():
+
+    # All fixed arrays except StringArray shares
+    # the same implementation. We just choose
+    # a few samples for testing.
+    testSlicesOnArrayImpl(IntArray, int)
+    testSlicesOnArrayImpl(V3fArray, V3f)
+    testSlicesOnArrayImpl(FloatArray, float)
+    testSlicesOnArrayImpl(StringArray, str)
+    
+    print ("ok")
+    
+testList.append (('testSlicesOnArray',testSlicesOnArray))
+
+def testNonMaskedFloatTypeArray(FloatTypeArray):
+    f1 = FloatTypeArray(5)
+    assert (len(f1) == 5)
+
+    # Check for correct initialization
+    for i in range(0, len(f1)):
+        assert(f1[i] == 0)
+
+    f1 = FloatTypeArray(1.25, 10)
+    assert(len(f1) == 10)
+    for i in range(0, len(f1)):
+        assert(f1[i] == 1.25)
+
+    # Ensure that an exception is thrown when
+    # we exceed the bounds of the array
+    try:
+        print (f1[10])
+    except:
+        pass
+    else:
+        assert(False)
+
+    # Check element assignment
+    f1[0] = 1.5
+    f1[1] = 2.0
+
+    assert(f1[0] == 1.5)
+    assert(f1[1] == 2.0)
+
+    # Test copy construction
+    f2 = FloatTypeArray(f1)
+    assert(len(f2) == len(f1))
+    for i in range(0, len(f1)):
+        assert f1[i] == f2[i]
+
+    # The same internal data is referenced by both arrays
+    f2[3] = 4.5
+    assert(f2[3] == 4.5)
+    assert(f1[3] == 4.5)
+    f1[4] = 5.5
+    assert(f1[4] == 5.5)
+    assert(f2[4] == 5.5)
+
+    # Test negative indices
+    assert(f2[-1] == f2[len(f2)-1])
+    assert(f2[-2] == f2[len(f2)-2])
+
+    # Test slice operations
+
+    # Copy contents of f1
+    f3 = f1[:]
+    assert(len(f3) == len(f1))
+
+    for i in range(0, len(f1)):
+        assert(f3[i] == f1[i])
+
+    f3[0] = 0.25
+    assert(f3[0] != f1[0])
+
+    f3 = f1[2:4]
+    assert(len(f3) == 2)
+    assert(f3[0] == f1[2] and f3[1] == f1[3])
+
+    # Test array-array operations
+    f1 = FloatTypeArray(5)
+    f2 = FloatTypeArray(5)
+
+    # These values were chosen to allow division operations
+    # to return exact values that can be compared with '=='
+
+    f1[0] = 1.25
+    f1[1] = 2.0
+    f1[2] = 3.0
+    f1[3] = 1.0
+    f1[4] = 3.75
+
+    f2[0] = 5.0
+    f2[1] = 2.0
+    f2[2] = 1.5
+    f2[3] = 2.0
+    f2[4] = 10.0
+
+    testVectorVectorArithmeticOps(f1, f2)
+    testVectorVectorInPlaceArithmeticOps(f1, f2)
+
+    # Test operations for arrays with scalars
+    testVectorScalarArithmeticOps(f1, 1.75)
+    testVectorScalarInPlaceArithmeticOps(f1, 0.25)
+    testVectorScalarComparisonOps(f1, 3.5)
+    testVectorScalarInequalityOps(f1, 3.5)
+
+    # Make sure that operations fail when performed on arrays
+    # of differing lengths
+    f3 = FloatTypeArray(6)
+
+    assertVectorVectorArithmeticOpFailures(f1, f3)
+    assertVectorVectorInPlaceArithmeticOpFailures(f1, f3)
+    assertVectorVectorComparisonOpFailures(f1, f3)
+    assertPowFunctionFailures(f1, f3)
+
+    testPowFunctions(f1, f2)
+
+    print ("ok")
+
+testList.append(('testNonMaskedFloatArray', lambda : testNonMaskedFloatTypeArray(FloatArray)))
+testList.append(('testNonMaskedDoubleArray', lambda : testNonMaskedFloatTypeArray(DoubleArray)))
+
+def testNonMaskedIntTypeArray(IntTypeArray):
+    f1 = IntTypeArray(5)
+    assert (len(f1) == 5)
+
+    # Check for correct initialization
+    for i in range(0, len(f1)):
+        assert(f1[i] == 0)
+
+    f1 = IntTypeArray(3, 10)
+    assert(len(f1) == 10)
+    for i in range(0, len(f1)):
+        assert(f1[i] == 3)
+
+    # Ensure that an exception is thrown when
+    # we exceed the bounds of the array
+    try:
+        print (f1[10])
+    except:
+        pass
+    else:
+        assert(false)
+
+    # Check element assignment
+    f1[0] = 1
+    f1[1] = 2
+
+    assert(f1[0] == 1)
+    assert(f1[1] == 2)
+
+    # Test copy construction
+    f2 = IntTypeArray(f1)
+    assert(len(f2) == len(f1))
+    for i in range(0, len(f1)):
+        assert f1[i] == f2[i]
+
+    # The same internal data is referenced by both arrays
+    f2[3] = 4
+    assert(f2[3] == 4)
+    assert(f1[3] == 4)
+    f1[4] = 5
+    assert(f1[4] == 5)
+    assert(f2[4] == 5)
+
+    # Test negative indices
+    assert(f2[-1] == f2[len(f2)-1])
+    assert(f2[-2] == f2[len(f2)-2])
+
+    # Test slice operations
+
+    # Copy contents of f1
+    f3 = f1[:]
+    assert(len(f3) == len(f1))
+
+    for i in range(0, len(f1)):
+        assert(f3[i] == f1[i])
+
+    f3[0] = 4
+    assert(f3[0] != f1[0])
+
+    f3 = f1[2:4]
+    assert(len(f3) == 2)
+    assert(f3[0] == f1[2] and f3[1] == f1[3])
+
+    # Test array-array operations
+    f1 = IntTypeArray(5)
+    f2 = IntTypeArray(5)
+
+    # These values were chosen to allow division operations
+    # to return exact values that can be compared with '=='
+
+    f1[0] = 1
+    f1[1] = 2
+    f1[2] = 3
+    f1[3] = 1
+    f1[4] = 7
+
+    f2[0] = 5
+    f2[1] = 2
+    f2[2] = 1
+    f2[3] = 2
+    f2[4] = 10
+
+    testVectorVectorArithmeticOps(f1, f2)
+    testVectorVectorInPlaceArithmeticOps(f1, f2)
+    testVectorVectorComparisonOps(f1, f2)
+    testVectorVectorInequalityOps(f1, f2)
+
+    # Test operations for arrays with scalars
+    testVectorScalarArithmeticOps(f1, 2)
+    testVectorScalarInPlaceArithmeticOps(f1, 4)
+    testVectorScalarComparisonOps(f1, 7)
+    testVectorScalarInequalityOps(f1, 7)
+
+    testModOps(f1, f2)
+
+    # Make sure that operations fail when performed on arrays
+    # of differing lengths
+    f3 = IntTypeArray(6)
+
+    assertVectorVectorArithmeticOpFailures(f1, f3)
+    assertVectorVectorInPlaceArithmeticOpFailures(f1, f3)
+    assertVectorVectorComparisonOpFailures(f1, f3)
+    assertModOpFailures(f1, f3)
+
+    print ("ok")
+
+testList.append(('testNonMaskedIntArray', lambda : testNonMaskedIntTypeArray(IntArray)))
+testList.append(('testNonMaskedShortArray', lambda : testNonMaskedIntTypeArray(ShortArray)))
+#testList.append(('testNonMaskedUnsignedCharArray', lambda : testNonMaskedIntTypeArray(UnsignedCharArray))) # arithmetic tests will fail this
+
+def testMaskedFloatTypeArray(FloatTypeArray):
+    f = FloatTypeArray(10)
+
+    f[0] = 1.25
+    f[1] = 2.5
+    f[2] = 1.0
+    f[3] = 1.75
+    f[4] = 5.25
+    f[5] = 7.0
+    f[6] = 4.25
+    f[7] = 1.0
+    f[8] = 0.5
+    f[9] = 3.5
+
+    # Ensure we can't create a masked array if the indices don't match
+    m1 = IntArray(9)
+    try:
+        mf = f[m1]
+    except:
+        pass
+    else:
+        assert(false)
+
+    m1 = IntArray(len(f))
+    m1[0] = 1
+    m1[1] = 0
+    m1[2] = 0
+    m1[3] = 1
+    m1[4] = 1
+    m1[5] = 0
+    m1[6] = 0
+    m1[7] = 1
+    m1[8] = 0
+    m1[9] = 1
+
+    # Ensure the masked array reports the correct reduced length
+    mf = f[m1]
+    assert(len(mf) == numNonZeroMaskEntries(m1))
+
+    # Ensure the masked array holds the correct values
+    assert(mf[0] == 1.25)
+    assert(mf[1] == 1.75)
+    assert(mf[2] == 5.25)
+    assert(mf[3] == 1.0)
+    assert(mf[4] == 3.5)
+
+    # Masked arrays reference the same internal data
+    f[9] = 1.75
+    assert(mf[4] == 1.75)
+    mf[3] = 10.5
+    assert(f[7] == 10.5)
+
+    # Test copy construction of masked references
+    g = FloatTypeArray(mf)
+
+    # Check slices of masks
+    s = mf[1:3]
+    assert(len(s) == 2)
+    assert(s[0] == mf[1])
+    assert(s[1] == mf[2])
+
+    assert(mf[-1] == mf[len(mf)-1])
+    assert(mf[-2] == mf[len(mf)-2])
+
+    # Check that slices copy (not reference) array data
+    s = mf[:]
+    assert(len(s) == len(mf))
+    for i in range(0, len(mf)):
+        assert(s[i] == mf[i])
+
+    s[0] = 0
+    assert(s[0] != mf[0])
+
+    # Test operations with masked arrays
+    # Masked arrays should behave exactly as ordinary arrays
+
+    m2 = IntArray(len(f))
+    m2[0] = 1
+    m2[1] = 0
+    m2[2] = 1
+    m2[3] = 0
+    m2[4] = 1
+    m2[5] = 1
+    m2[6] = 0
+    m2[7] = 0
+    m2[8] = 1
+    m2[9] = 1
+
+    # m1 and m2 differ in the number of non-zero entries.
+    # Ensure that arithmetic operations with masked arrays
+    # cannot proceed if they have differing lengths
+
+    mf1 = f[m1]
+    mf2 = f[m2]
+
+    assertVectorVectorInPlaceArithmeticOpFailures(mf1, mf2)
+
+    # Test that the operations still fail when the number
+    # of non-zero mask entries is the same
+
+    m2[9] = 0
+
+    assert(numNonZeroMaskEntries(m1) == numNonZeroMaskEntries(m2))
+
+    mf2 = f[m2]
+  
+    # Aritmetic operations and comparison ops are supported
+    testVectorVectorArithmeticOps(mf1, mf2)
+    testVectorVectorComparisonOps(mf1, mf2)
+    testVectorVectorInequalityOps(mf1, mf2)
+
+    # Test operations between masked arrays and non-masked arrays
+    assert(len(mf1) == 5);
+    g = FloatTypeArray(5)
+    g[0] = 0.25
+    g[1] = 1.75
+    g[2] = 3.0
+    g[3] = 4.25
+    g[4] = 5.75
+
+    testVectorVectorArithmeticOps(g, mf1)
+    testVectorVectorComparisonOps(g, mf1)
+    testVectorVectorInequalityOps(g, mf1)
+
+    assert(len(f) == 10)
+    g = FloatTypeArray(10)
+    g[0] = 0.75
+    g[1] = 1.25
+    g[2] = 6.0
+    g[3] = 4.25
+    g[4] = 1.5
+    g[5] = 8.0
+    g[6] = 3.5
+    g[7] = 2.0
+    g[8] = 1.75
+    g[9] = 6.5
+
+    testVectorVectorMaskedInPlaceArithmeticOps(f, g, m1)
+    testVectorVectorMaskedInPlaceArithmeticOps2(f, g[m1], m1)
+    testVectorVectorMaskedInPlaceArithmeticOps2(f, g[m2][:], m1)
+    testVectorVectorMaskedArithmeticOps(f, g, f / 2.0, m1)
+
+    print ("ok")
+
+testList.append(('testMaskedFloatArray', lambda : testMaskedFloatTypeArray(FloatArray)))
+testList.append(('testMaskedDoubleArray', lambda : testMaskedFloatTypeArray(DoubleArray)))
+
+
+def testMaskedIntTypeArray(IntTypeArray):
+    f = IntTypeArray(10)
+
+    f[0] = 1
+    f[1] = 2
+    f[2] = 9
+    f[3] = 1
+    f[4] = 5
+    f[5] = 7
+    f[6] = 4
+    f[7] = 1
+    f[8] = 6
+    f[9] = 3
+
+    # Ensure we can't create a masked array if the indices don't match
+    m1 = IntArray(9)
+    try:
+        mf = f[m1]
+    except:
+        pass
+    else:
+        assert(false)
+
+    m1 = IntArray(len(f))
+    m1[0] = 1
+    m1[1] = 0
+    m1[2] = 0
+    m1[3] = 1
+    m1[4] = 1
+    m1[5] = 0
+    m1[6] = 0
+    m1[7] = 1
+    m1[8] = 0
+    m1[9] = 1
+
+    # Ensure the masked array reports the correct reduced length
+    mf = f[m1]
+    assert(len(mf) == numNonZeroMaskEntries(m1))
+
+    # Ensure the masked array holds the correct values
+    assert(mf[0] == 1)
+    assert(mf[1] == 1)
+    assert(mf[2] == 5)
+    assert(mf[3] == 1)
+    assert(mf[4] == 3)
+
+    # Masked arrays reference the same internal data
+    f[9] = 4
+    assert(mf[4] == 4)
+    mf[3] = 5
+    assert(f[7] == 5)
+
+    # Test copy construction of masked references
+    g = IntTypeArray(mf)
+
+    # Check slices of masks
+    s = mf[1:3]
+    assert(len(s) == 2)
+    assert(s[0] == mf[1])
+    assert(s[1] == mf[2])
+
+    assert(mf[-1] == mf[len(mf)-1])
+    assert(mf[-2] == mf[len(mf)-2])
+
+    # Check that slices copy (not reference) array data
+    s = mf[:]
+    assert(len(s) == len(mf))
+    for i in range(0, len(mf)):
+        assert(s[i] == mf[i])
+
+    s[0] = 0
+    assert(s[0] != mf[0])
+
+    # Test operations with masked arrays
+    # Masked arrays should behave exactly as ordinary arrays
+
+    m2 = IntArray(len(f))
+    m2[0] = 1
+    m2[1] = 0
+    m2[2] = 1
+    m2[3] = 0
+    m2[4] = 1
+    m2[5] = 1
+    m2[6] = 0
+    m2[7] = 0
+    m2[8] = 1
+    m2[9] = 1
+
+    # m1 and m2 differ in the number of non-zero entries.
+    # Ensure that arithmetic operations with masked arrays
+    # cannot proceed if they have differing lengths
+
+    mf1 = f[m1]
+    mf2 = f[m2]
+
+    assertVectorVectorInPlaceArithmeticOpFailures(mf1, mf2)
+
+    # Test that the operations still fail when the number
+    # of non-zero mask entries is the same
+
+    m2[9] = 0
+
+    assert(numNonZeroMaskEntries(m1) == numNonZeroMaskEntries(m2))
+
+    mf2 = f[m2]
+  
+    #assertVectorVectorInPlaceArithmeticOpFailures(mf1, mf2)
+
+    # Aritmetic operations and comparison ops are supported
+    testVectorVectorArithmeticOps(mf1, mf2)
+    testVectorVectorComparisonOps(mf1, mf2)
+    testVectorVectorInequalityOps(mf1, mf2)
+
+    # Test operations between masked arrays and non-masked arrays
+    assert(len(mf1) == 5);
+    g = IntTypeArray(5)
+    g[0] = 2
+    g[1] = 1
+    g[2] = 5
+    g[3] = 4
+    g[4] = 8
+
+    testVectorVectorArithmeticOps(g, mf1)
+    testVectorVectorComparisonOps(g, mf1)
+    testVectorVectorInequalityOps(g, mf1)
+
+    assert(len(f) == 10)
+    g = IntTypeArray(10)
+    g[0] = 5
+    g[1] = 11
+    g[2] = 3
+    g[3] = 4
+    g[4] = 1
+    g[5] = 8
+    g[6] = 6
+    g[7] = 2
+    g[8] = 1
+    g[9] = 7
+
+    testVectorVectorMaskedInPlaceArithmeticOps(f, g, m1)
+    testVectorVectorMaskedInPlaceArithmeticOps2(f, g[m1], m1)
+    testVectorVectorMaskedInPlaceArithmeticOps2(f, g[m2][:], m1)
+    testVectorVectorMaskedArithmeticOps(f, g, f / 2, m1)
+
+    print ("ok")
+
+testList.append(('testMaskedIntArray', lambda : testMaskedIntTypeArray(IntArray)))
+testList.append(('testMaskedShortArray', lambda : testMaskedIntTypeArray(ShortArray)))
+
+def testNonMaskedVecTypeArray(VecTypeArray):
+    base_type = ArrayBaseType[VecTypeArray]
+    vec_base_type = VecBaseType[base_type]
+
+    f1 = VecTypeArray(5)
+    assert (len(f1) == 5)
+
+    # Check for correct initialization
+    for i in range(0, len(f1)):
+        assert(f1[i] == base_type(0))
+
+    v = None
+    if dimensions(base_type) == 2:
+        v = base_type(1.25, 3.75)
+    elif base_type.dimensions() == 3:
+        v = base_type(1.25, 3.75, 2.0)
+    else:
+        assert(False)
+
+    f1 = VecTypeArray(v, 10)
+    assert(len(f1) == 10)
+    for i in range(0, len(f1)):
+        assert(f1[i] == v)
+
+    # Ensure that an exception is thrown when
+    # we exceed the bounds of the array
+    try:
+        print (f1[10])
+    except:
+        pass
+    else:
+        assert(False)
+
+    # Check element assignment
+
+    v1 = None
+    v2 = None
+
+    if dimensions(base_type) == 2:
+        v1 = base_type(1.5, 0.75)
+        v2 = base_type(4.25, 7.5)
+    elif dimensions(base_type) == 3:
+        v1 = base_type(1.5, 0.75, 5.0)
+        v2 = base_type(4.25, 7.5, 2.25)
+    else:
+        assert(False)
+
+    f1[0] = v1
+    f1[1] = v2
+
+    assert(f1[0] == v1)
+    assert(f1[1] == v2)
+
+    # Test copy construction
+    f2 = VecTypeArray(f1)
+    assert(len(f2) == len(f1))
+    for i in range(0, len(f1)):
+        assert f1[i] == f2[i]
+
+    # The same internal data is referenced by both arrays
+    v = None
+    if dimensions(base_type) == 2:
+        v = base_type(4.5, 1.75)
+    elif base_type.dimensions() == 3:
+        v = base_type(4.5, 1.75, 6.0)
+    else:
+        assert(False)
+
+    f2[3] = v
+    assert(f2[3] == v)
+    assert(f1[3] == v)
+
+    f1[4] = 2*v
+    assert(f1[4] == 2*v)
+    assert(f2[4] == 2*v)
+
+    # Test negative indices
+    assert(f2[-1] == f2[len(f2)-1])
+    assert(f2[-2] == f2[len(f2)-2])
+
+    # Test slice operations
+
+    # Copy contents of f1
+    f3 = f1[:]
+    assert(len(f3) == len(f1))
+
+    for i in range(0, len(f1)):
+        assert(f3[i] == f1[i])
+
+    v = None
+    if dimensions(base_type) == 2:
+        v = base_type(0.25, 5.25)
+    elif base_type.dimensions() == 3:
+        v = base_type(0.25, 5.25, 1.0)
+
+    assert(v is not None)
+
+    f3[0] = v
+    assert(f3[0] != f1[0])
+
+    f3 = f1[2:4]
+    assert(len(f3) == 2)
+    assert(f3[0] == f1[2] and f3[1] == f1[3])
+
+    # Test array-array operations
+    f1 = VecTypeArray(5)
+    f2 = VecTypeArray(5)
+
+    # These values were chosen to allow division operations
+    # to return exact values that can be compared with '=='
+
+    if dimensions(base_type) == 2:
+        f1[0] = base_type(1.25, 2.5)
+        f1[1] = base_type(2.0, 7.25)
+        f1[2] = base_type(3.0, 9.0)
+        f1[3] = base_type(1.0, 8.5)
+        f1[4] = base_type(3.75, 3.25)
+
+        f2[0] = base_type(5.0, 4.25)
+        f2[1] = base_type(2.0, 3.5)
+        f2[2] = base_type(1.5, 6.0)
+        f2[3] = base_type(2.0, 7.25)
+        f2[4] = base_type(10.0, 11.0)
+
+    elif dimensions(base_type) == 3:
+        f1[0] = base_type(1.25, 2.5, 11.75)
+        f1[1] = base_type(2.0, 7.25, 4.0)
+        f1[2] = base_type(3.0, 9.0, 12.25)
+        f1[3] = base_type(1.0, 8.5, 6.5)
+        f1[4] = base_type(3.75, 0.25, 5.25)
+
+        f2[0] = base_type(5.0, 4.25, 5.75)
+        f2[1] = base_type(2.0, 3.5, 8.0)
+        f2[2] = base_type(1.5, 6.0, 12.5)
+        f2[3] = base_type(2.0, 7.25, 15.0)
+        f2[4] = base_type(10.0, 11.0, 1.25)
+
+    testVectorVectorArithmeticOps(f1, f2)
+    testVectorVectorInPlaceArithmeticOps(f1, f2)
+    testUnaryVecMethods(f1)
+    testBinaryVecMethods(f1, f2)
+
+    if dimensions(base_type) == 2:
+        v = base_type(1.25, 5.25)
+    elif dimensions(base_type) == 3:
+        v = base_type(1.25, 5.25, 1.0)
+    else:
+        assert(False)
+
+    assert(v is not None)
+
+    # Test operations for arrays with scalars
+    testVectorScalarArithmeticOps(f1, v)
+    testVectorScalarInPlaceArithmeticOps(f1, v)
+    testVectorScalarComparisonOps(f1, v)
+
+    # Test multiplication and division by vector base types
+    v = vec_base_type(4.25)
+    
+    f = f1 * v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == f1[i] * v)
+
+    f = v * f1
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(f[i] == v * f1[i])
+
+    f = f1 / v
+    assert(len(f) == len(f1))
+    for i in range(0, len(f)):
+        assert(equalWithAbsError(f[i], f1[i] / v, eps))
+
+
+    # Make sure that operations fail when performed on arrays
+    # of differing lengths
+    f3 = VecTypeArray(6)
+
+    assertVectorVectorArithmeticOpFailures(f1, f3)
+    assertVectorVectorInPlaceArithmeticOpFailures(f1, f3)
+
+    print ("ok")
+
+testList.append(('testNonMaskedV2sArray', lambda : testNonMaskedVecTypeArray(V2sArray)))
+testList.append(('testNonMaskedV2iArray', lambda : testNonMaskedVecTypeArray(V2iArray)))
+testList.append(('testNonMaskedV2fArray', lambda : testNonMaskedVecTypeArray(V2fArray)))
+testList.append(('testNonMaskedV2dArray', lambda : testNonMaskedVecTypeArray(V2dArray)))
+testList.append(('testNonMaskedV3sArray', lambda : testNonMaskedVecTypeArray(V3sArray)))
+testList.append(('testNonMaskedV3iArray', lambda : testNonMaskedVecTypeArray(V3iArray)))
+testList.append(('testNonMaskedV3fArray', lambda : testNonMaskedVecTypeArray(V3fArray)))
+testList.append(('testNonMaskedV3dArray', lambda : testNonMaskedVecTypeArray(V3dArray)))
+
+
+def testMaskedVecTypeArray(VecTypeArray):
+    base_type = ArrayBaseType[VecTypeArray]
+    vec_base_type = VecBaseType[base_type]
+
+    f = VecTypeArray(10)
+
+    if dimensions(base_type) == 2:
+        f[0] = base_type(1.25, 5.25)
+        f[1] = base_type(2.5, 6.0)
+        f[2] = base_type(1.0, 3.75)
+        f[3] = base_type(1.75, 11.25)
+        f[4] = base_type(5.25, 12.0)
+        f[5] = base_type(7.0, 4.5)
+        f[6] = base_type(4.25, 6.5)
+        f[7] = base_type(1.0, 2.25)
+        f[8] = base_type(1.5, 1.75)
+        f[9] = base_type(3.5, 4.0)
+    elif dimensions(base_type) == 3:
+        f[0] = base_type(1.25, 5.25, 8.5)
+        f[1] = base_type(2.5, 6.0, 7.25)
+        f[2] = base_type(1.0, 3.75, 15.5)
+        f[3] = base_type(1.75, 11.25, 10.0)
+        f[4] = base_type(5.25, 12.0, 16.5)
+        f[5] = base_type(7.0, 4.5, 1.25)
+        f[6] = base_type(4.25, 6.5, 9.25)
+        f[7] = base_type(1.0, 2.25, 5.0)
+        f[8] = base_type(1.5, 1.75, 7.5)
+        f[9] = base_type(3.5, 4.0, 5.75)
+
+    # Ensure we can't create a masked array if the indices don't match
+    m1 = IntArray(9)
+    try:
+        mf = f[m1]
+    except:
+        pass
+    else:
+        assert(false)
+
+    m1 = IntArray(len(f))
+    m1[0] = 1
+    m1[1] = 0
+    m1[2] = 0
+    m1[3] = 1
+    m1[4] = 1
+    m1[5] = 0
+    m1[6] = 0
+    m1[7] = 1
+    m1[8] = 0
+    m1[9] = 1
+
+    # Ensure the masked array reports the correct reduced length
+    mf = f[m1]
+    assert(len(mf) == numNonZeroMaskEntries(m1))
+
+    # Ensure the masked array holds the correct values
+    assert(mf[0] == f[0])
+    assert(mf[1] == f[3])
+    assert(mf[2] == f[4])
+    assert(mf[3] == f[7])
+    assert(mf[4] == f[9])
+
+    # Masked arrays reference the same internal data
+    v = None
+    if dimensions(base_type) == 2:
+        v = base_type(1.75, 2.5)
+    elif dimensions(base_type) == 3:
+        v = base_type(1.75, 2.5, 9.25)
+    else:
+        assert(False)
+
+    f[9] = v
+    assert(mf[4] == v)
+
+    mf[3] = 2*v
+    assert(f[7] == 2*v)
+
+    # Test copy construction of masked references
+    g = VecTypeArray(mf)
+
+    # Check slices of masks
+    s = mf[1:3]
+    assert(len(s) == 2)
+    assert(s[0] == mf[1])
+    assert(s[1] == mf[2])
+
+    assert(mf[-1] == mf[len(mf)-1])
+    assert(mf[-2] == mf[len(mf)-2])
+
+    # Check that slices copy (not reference) array data
+    s = mf[:]
+    assert(len(s) == len(mf))
+    for i in range(0, len(mf)):
+        assert(s[i] == mf[i])
+
+    s[0] = base_type(0)
+    assert(s[0] != mf[0])
+
+    # Test operations with masked arrays
+    # Masked arrays should behave exactly as ordinary arrays
+
+    m2 = IntArray(len(f))
+    m2[0] = 1
+    m2[1] = 0
+    m2[2] = 1
+    m2[3] = 0
+    m2[4] = 1
+    m2[5] = 1
+    m2[6] = 0
+    m2[7] = 0
+    m2[8] = 1
+    m2[9] = 1
+
+    # m1 and m2 differ in the number of non-zero entries.
+    # Ensure that arithmetic operations with masked arrays
+    # cannot proceed if they have differing lengths
+
+    mf1 = f[m1]
+    mf2 = f[m2]
+
+    assertVectorVectorInPlaceArithmeticOpFailures(mf1, mf2)
+
+    # Test that the operations still fail when the number
+    # of non-zero mask entries is the same
+
+    m2[9] = 0
+
+    assert(numNonZeroMaskEntries(m1) == numNonZeroMaskEntries(m2))
+
+    mf2 = f[m2]
+  
+    # Aritmetic operations and comparison ops are supported
+    testVectorVectorArithmeticOps(mf1, mf2)
+    testVectorVectorComparisonOps(mf1, mf2)
+
+    # Test operations between masked arrays and non-masked arrays
+    assert(len(mf1) == 5);
+    g = VecTypeArray(5)
+
+    if dimensions(base_type) == 2:
+        g[0] = base_type(5.25, 2.75)
+        g[1] = base_type(1.75, 11.5)
+        g[2] = base_type(3.0, 8.25)
+        g[3] = base_type(4.25, 6.75)
+        g[4] = base_type(5.75, 12.0)
+    elif dimensions(base_type) == 3:
+        g[0] = base_type(5.25, 2.75, 1.0)
+        g[1] = base_type(1.75, 11.5, 15.25)
+        g[2] = base_type(3.0, 8.25, 9.0)
+        g[3] = base_type(4.25, 6.75, 1.25)
+        g[4] = base_type(5.75, 12.0, 7.5)
+    else:
+        assert(False)
+
+    testVectorVectorArithmeticOps(g, mf1)
+    testVectorVectorComparisonOps(g, mf1)
+
+    testUnaryVecMethods(g)
+    testBinaryVecMethods(g, mf1)
+    testBinaryVecMethods(mf1, mf2)
+
+    assert(len(f) == 10)
+    g = VecTypeArray(10)
+
+    if dimensions(base_type) == 2:
+        g[0] = base_type(5.25, 2.75)
+        g[1] = base_type(1.75, 11.5)
+        g[2] = base_type(3.0, 8.25)
+        g[3] = base_type(4.25, 6.75)
+        g[4] = base_type(5.75, 12.0)
+        g[5] = base_type(8.0, 5.25)
+        g[6] = base_type(3.5, 4.0)
+        g[7] = base_type(2.0, 12.5)
+        g[8] = base_type(1.75, 6.75)
+        g[9] = base_type(6.5, 8.0)
+    elif dimensions(base_type) == 3:
+        g[0] = base_type(5.25, 2.75, 1.0)
+        g[1] = base_type(1.75, 11.5, 15.25)
+        g[2] = base_type(3.0, 8.25, 9.0)
+        g[3] = base_type(4.25, 6.75, 1.25)
+        g[4] = base_type(5.75, 12.0, 7.5)
+        g[5] = base_type(8.0, 5.25, 12.25)
+        g[6] = base_type(3.5, 4.0, 6.0)
+        g[7] = base_type(2.0, 12.5, 16.5)
+        g[8] = base_type(1.75, 6.75, 4.25)
+        g[9] = base_type(6.5, 8.0, 7.75)
+    else:
+        assert(False)
+
+    testVectorVectorMaskedInPlaceArithmeticOps(f, g, m1)
+    testVectorVectorMaskedInPlaceArithmeticOps2(f, g[m1], m1)
+    testVectorVectorMaskedInPlaceArithmeticOps2(f, g[m2][:], m1)
+
+    v = None
+    if dimensions(base_type) == 2:
+        v = base_type(1.25, 3.75)
+    elif base_type.dimensions() == 3:
+        v = base_type(1.25, 3.75, 2.0)
+    else:
+        assert(False)
+
+    assert(v is not None)
+
+    # Test operations for arrays with scalars
+    testVectorScalarArithmeticOps(g, v)
+    testVectorScalarInPlaceArithmeticOps(g, v)
+    testVectorScalarComparisonOps(g, v)
+
+    testVectorVectorMaskedArithmeticOps(f, f, f, m1)
+
+    # Test multiplication and division by vector base types
+    v = vec_base_type(4.25)
+    
+    f = g * v
+    assert(len(f) == len(g))
+    for i in range(0, len(f)):
+        assert(f[i] == g[i] * v)
+
+    f = v * g
+    assert(len(f) == len(g))
+    for i in range(0, len(f)):
+        assert(f[i] == v * g[i])
+
+    f = g / v
+    assert(len(f) == len(g))
+    for i in range(0, len(f)):
+        assert(equalWithAbsError(f[i], g[i] / v, eps))
+
+    testVectorVectorMaskedArithmeticOps
+
+    print ("ok")
+
+testList.append(('testMaskedV2sArray', lambda : testMaskedVecTypeArray(V2sArray)))
+testList.append(('testMaskedV2iArray', lambda : testMaskedVecTypeArray(V2iArray)))
+testList.append(('testMaskedV2fArray', lambda : testMaskedVecTypeArray(V2fArray)))
+testList.append(('testMaskedV2dArray', lambda : testMaskedVecTypeArray(V2dArray)))
+testList.append(('testMaskedV3fArray', lambda : testMaskedVecTypeArray(V3fArray)))
+testList.append(('testMaskedV3dArray', lambda : testMaskedVecTypeArray(V3dArray)))
+
+
+# -------------------------------------------------------------------------
+# Tests for functions
+
+def testFun ():
+
+    assert sign(5)    ==  1    
+    assert sign(5.0)  ==  1    
+    assert sign(-5)   == -1    
+    assert sign(-5.0) == -1    
+
+    assert log(math.e) ==  1    
+    assert log(1)      ==  0    
+
+    assert log10(10)   ==  1    
+    assert log10(1)    ==  0    
+
+    assert lerp(1, 2, 0.5)     == 1.5
+    assert lerp(1.0, 2.0, 0.5) == 1.5
+    assert lerp(2, 1, 0.5)     == 1.5
+    assert lerp(2.0, 1.0, 0.5) == 1.5
+
+    assert lerpfactor(1.5, 1, 2)     == 0.5
+    assert lerpfactor(1.5, 1.0, 2.0) == 0.5
+
+    assert clamp(0, 1, 2)       == 1
+    assert clamp(3, 1, 2)       == 2
+    assert clamp(0.0, 1.0, 2.0) == 1
+    assert clamp(3.0, 1.0, 2.0) == 2
+
+    assert cmp(1, 2)     == -1
+    assert cmp(2, 2)     ==  0
+    assert cmp(3, 2)     ==  1
+    assert cmp(1.0, 2.0) == -1
+    assert cmp(2.0, 2.0) ==  0
+    assert cmp(3.0, 2.0) ==  1
+
+    assert cmpt(1.0, 1.5, 0.1) == -1
+    assert cmpt(1.5, 1.5, 0.1) ==  0
+    assert cmpt(2.0, 1.5, 0.1) ==  1
+    assert cmpt(1.0, 1.5, 0.6) ==  0
+    assert cmpt(1.5, 1.5, 0.6) ==  0
+    assert cmpt(2.0, 1.5, 0.6) ==  0
+
+    assert iszero(0, 0)        == 1
+    assert iszero(0, 0.1)      == 1
+    assert iszero(0.01, 0.1)   == 1
+    assert iszero(0.01, 0.001) == 0
+
+    assert equal(5, 5, 0)        == 1
+    assert equal(5, 6, 0)        == 0
+    assert equal(5, 5.01, 0.1)   == 1
+    assert equal(5, 5.01, 0.001) == 0
+
+    assert trunc(1.1)  ==  1
+    assert trunc(-1.1) == -1
+    assert trunc(1)    ==  1
+
+    assert divs( 4,  2) ==  2
+    assert divs(-4,  2) == -2
+    assert divs( 4, -2) == -2
+    assert divs(-4, -2) ==  2
+    assert mods( 3,  2) ==  1
+    assert mods(-3,  2) == -1
+    assert mods( 3, -2) ==  1
+    assert mods(-3, -2) == -1
+
+    assert divp( 4,  2) ==  2
+    assert divp(-4,  2) == -2
+    assert divp( 4, -2) == -2
+    assert divp(-4, -2) ==  2
+    assert modp( 3,  2) ==  1
+    assert modp(-3,  2) ==  1
+    assert modp( 3, -2) ==  1
+    assert modp(-3, -2) ==  1
+
+    print ("ok")
+
+    return
+
+testList.append (('testFun',testFun))
+
+
+# -------------------------------------------------------------------------
+# Tests for V2x
+
+def testV2x (Vec):
+    
+    # Constructors (and element access).
+
+    v = Vec()
+    assert v[0] == 0 and v[1] == 0
+
+    v = Vec(1)
+    assert v[0] == 1 and v[1] == 1
+
+    v = Vec(0, 1)
+    assert v[0] == 0 and v[1] == 1
+
+    v = Vec((0, 1))
+    assert v[0] == 0 and v[1] == 1
+
+    v = Vec([0, 1])
+    assert v[0] == 0 and v[1] == 1
+
+    v = Vec()
+    v.setValue(0, 1)
+    assert v[0] == 0 and v[1] == 1
+
+    # Repr.
+
+    v = Vec(1/9., 2/9.)
+    assert v == eval(repr(v))
+
+    # Sequence length.
+
+    v = Vec()
+    assert len(v) == 2
+
+    # Element setting.
+
+    v = Vec()
+    v[0] = 10
+    v[1] = 11
+    assert v[0] == 10 and v[1] == 11
+
+    try:
+        v[-3] = 0  # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0   # We shouldn't get here.   
+
+    try:
+        v[3] = 0   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0   # We shouldn't get here.
+
+    try:
+        v[1] = "a" # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0   # We shouldn't get here.
+
+    # Assignment.
+
+    v1 = Vec(1)
+    
+    v2 = v1
+    assert v2[0] == 1 and v2[1] == 1
+    v1[0] = 2
+    assert v2[0] == 2 and v2[1] == 1
+    
+    # Comparison operators.
+
+    v1 = Vec(20, 20)
+    v2 = Vec(20, 20)
+    v3 = Vec(20, 21)
+
+    assert v1 == v2
+    assert v1 != v3
+    assert not (v1 < v2)
+    assert v1 < v3
+    assert v1 <= v2
+    assert v1 <= v3
+    assert not (v3 <= v1)
+    assert not (v2 > v1)
+    assert v3 > v1
+    assert v2 >= v1
+    assert v3 >= v1
+    assert not (v1 >= v3)
+    
+    # Epsilon equality.
+
+    e = 0.005
+    v1 = Vec(1)
+    v2 = Vec(1 + e)
+
+    assert v1.equalWithAbsError(v2, e)
+    assert v2.equalWithAbsError(v1, e)
+
+    e = 0.003
+    v1 = Vec(10)
+    v2 = Vec(10 + 10 * e)
+
+    assert v1.equalWithRelError(v2, e)
+    assert v2.equalWithRelError(v1, e)
+
+    # Dot products.
+
+    v1 = Vec(0, 1)
+    v2 = Vec(1, 0)
+    v3 = Vec(1, 1)
+
+    assert v1.dot(v2) == 0
+    assert v1.dot(v3) == 1
+    assert v1 ^ v2 == v1.dot(v2)
+    assert v1 ^ v3 == v1.dot(v3)
+
+    # Cross products.
+
+    v1 = Vec(1, 0)
+    v2 = Vec(0, 1)
+
+    assert v1.cross(v2) == 1
+    assert v2.cross(v1) == -1
+    assert v1 % v2 == v1.cross(v2)
+    assert v2 % v1 == v2.cross(v1)
+
+    # Addition.
+
+    v1 = Vec(10, 20)
+    v2 = Vec(30, 40)
+
+    assert v1 + v2 == Vec(40, 60)
+    assert v2 + v1 == v1 + v2
+    assert v1 + 1 == Vec(11, 21)
+    assert 1 + v1 == v1 + 1
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 + (1, 2) == Vec(11, 22)
+    assert (1, 2) + v1 == v1 + (1, 2)
+
+    # Subtraction and negation.
+
+    v1 = Vec(10, 20)
+    v2 = Vec(30, 40)
+
+    assert v2 - v1 == Vec(20, 20)
+    assert v1 - 1 == Vec(9, 19)
+    assert 1 - v1 == - (v1 - 1)
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 - (1, 2) == Vec(9, 18)
+    assert (1, 2) - v1 == - (v1 - (1, 2))
+
+    assert v1.negate() == Vec(-10, -20)
+
+    # Multiplication.
+
+    v1 = Vec(1, 2)
+    v2 = Vec(3, 4)
+    
+    assert v1 * v2 == Vec(3, 8)
+    assert v2 * v1 == v1 * v2
+    assert 2 * v1 == Vec(2, 4)
+    assert v1 * 2 == 2 * v1
+
+    assert v1 * V2i(3, 4) == Vec(3, 8)
+    assert v1 * V2f(3, 4) == Vec(3, 8)
+    assert v1 * V2d(3, 4) == Vec(3, 8)
+
+    v1 *= 2
+    assert v1 == Vec(2, 4)
+    v1 = Vec(1, 2)
+    
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 * (1, 2) == Vec(1, 4)
+    assert (1, 2) * v1 == v1 * (1, 2)
+
+    # Division.
+
+    v1 = Vec(10, 20)
+    v2 = Vec(2, 4)
+    
+    assert v1 / v2 == Vec(10/2, 20/4)
+    assert v1 / 2 == Vec(10/2, 20/2)
+    assert Vec(40) / v1 == Vec(40/10, 40/20)
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 / (1, 2) == Vec(10/1, 20/2)
+    assert Vec(30, 40) / v1 == Vec(30/10, 40/20)
+
+    assert v1 / V2i (2, 4) == Vec(10/2, 20/4)
+    assert v1 / V2f (2, 4) == Vec(10/2, 20/4)
+    assert v1 / V2d (2, 4) == Vec(10/2, 20/4)
+    assert v1 / (2, 4) == Vec(10/2, 20/4)
+    assert v1 / [2, 4] == Vec(10/2, 20/4)
+
+    v1 = Vec(10, 20)
+    v1 /= 2
+    assert v1 == Vec(10/2, 20/2)
+    
+    v1 = Vec(10, 20)
+    v1 /= V2i (2, 4)
+    assert v1 == Vec(10/2, 20/4)
+    
+    v1 = Vec(10, 20)
+    v1 /= V2f (2, 4)
+    assert v1 == Vec(10/2, 20/4)
+
+    v1 = Vec(10, 20)
+    v1 /= V2d (2, 4)
+    assert v1 == Vec(10/2, 20/4)
+
+    v1 = Vec(10, 20)
+    v1 /= (2, 4)
+    assert v1 == Vec(10/2, 20/4)
+
+    v1 = Vec(10, 20)
+    v1 /= [2, 4]
+    assert v1 == Vec(10/2, 20/4)
+
+    # Length.
+
+    if (Vec != V2i):
+       v = Vec(1, 2)
+       assert equal(v.length(), sqrt(1*1 + 2*2), v.baseTypeEpsilon())
+
+    v = Vec(1, 2)
+    assert v.length2() == 1*1 + 2*2
+
+    # Normalizing.
+
+    if (Vec != V2i):
+       v = Vec(1, 2)
+       v.normalize()
+       assert equal(v.length(), 1, v.baseTypeEpsilon())
+
+       v = Vec(1, 2)
+       v.normalizeExc()
+       assert equal(v.length(), 1, v.baseTypeEpsilon())
+       v = Vec(0)
+       try:
+           v.normalizeExc()        # This should raise an exception.
+       except:
+           pass
+       else:
+           assert 0                # We shouldn't get here.
+       
+       v = Vec(1, 2)
+       v.normalizeNonNull()
+       assert equal(v.length(), 1, v.baseTypeEpsilon())
+
+       v = Vec(1, 2)
+       assert equal(v.normalized().length(), 1, v.baseTypeEpsilon())
+
+       v = Vec(1, 2)
+       assert equal(v.normalizedExc().length(), 1, v.baseTypeEpsilon())
+       v = Vec(0)
+       try:
+           v.normalizedExc()        # This should raise an exception.
+       except:
+           pass
+       else:
+           assert 0                # We shouldn't get here.
+       
+       v = Vec(1, 2)
+       assert equal(v.normalizedNonNull().length(), 1, v.baseTypeEpsilon())
+
+
+    # Projection.
+
+    if (Vec != V2i):
+        s = Vec(2, 0)
+        t = Vec(1, 1)
+        assert t.project(s) == Vec(1, 0)
+
+    # Orthogonal.
+
+    if (Vec != V2i):
+        s = Vec(2, 0)
+        t = Vec(1, 1)
+        o = s.orthogonal(t)
+        assert iszero(o ^ s, s.baseTypeEpsilon())
+
+    # Reflect.
+
+    if (Vec != V2i):
+        s = Vec(1, 1)
+        t = Vec(2, 0)
+        r = s.reflect(t)
+        assert equal(abs(s ^ t), abs(r ^ t), s.baseTypeEpsilon())
+
+    # Closest vertex.
+
+    v0 = Vec(0, 0)
+    v1 = Vec(5, 0)
+    v2 = Vec(0, 5)
+    
+    p = Vec(1, 1)
+    assert p.closestVertex(v0, v1, v2) == v0
+
+    p = Vec(4, 1)
+    assert p.closestVertex(v0, v1, v2) == v1
+
+    p = Vec(1, 4)
+    assert p.closestVertex(v0, v1, v2) == v2
+
+
+    print ("ok")
+
+    return
+
+def testV2 ():
+
+    print ("V2i")
+    testV2x (V2i)
+    print ("V2f")
+    testV2x (V2f)
+    print ("V2d")
+    testV2x (V2d)
+
+testList.append (('testV2',testV2))
+
+
+# -------------------------------------------------------------------------
+# Tests for V2xArray
+
+def testV2xArray (Array, Vec, Arrayx):
+    
+    # Constructors (and element access).
+
+    a = Array (3)
+
+    a[0] = Vec(0)
+    a[1] = Vec(1)
+    a[2] = Vec(2)
+
+    assert a[0] == Vec(0)
+    assert a[1] == Vec(1)
+    assert a[2] == Vec(2)
+
+    a[0].setValue(10,10)
+    a[1].setValue(11,11)
+    a[2].setValue(12,12)
+
+    assert a[0] == Vec(10)
+    assert a[1] == Vec(11)
+    assert a[2] == Vec(12)
+
+    # Element setting.
+
+    a = Array(2)
+
+    try:
+        a[-3] = Vec(0)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a[3] = Vec(0)   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        a[1] = "a"         # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    a = Array(2)
+    a[0] = Vec(0)
+    a[1] = Vec(1)
+    
+    b = Array(2)
+    b[0] = Vec(0)
+    b[1] = Vec(1)
+    
+    c = Array(2)
+    c[0] = Vec(10)
+    c[1] = Vec(11)
+
+    # TODO: make equality work correctly.
+    #assert a == b
+    assert a != c
+    
+    # Dot products.
+
+    a = Array(2)
+    a[0] = Vec(1, 2)
+    a[1] = Vec(3, 4)
+
+    b = Array(2)
+    b[0] = Vec(5, 6)
+    b[1] = Vec(7, 8)
+
+    r = a.dot(b)
+    assert r[0] == 1*5 + 2*6
+    assert r[1] == 3*7 + 4*8
+
+    c = Vec(5, 6)
+    r = a.dot(c)
+    assert r[0] == 1*5 + 2*6
+    assert r[1] == 3*5 + 4*6
+
+    d = Array(3)
+    try:
+        a.dot(d)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+    
+    
+    # Cross products.
+
+    a = Array(2)
+    a[0] = Vec(1, 2)
+    a[1] = Vec(3, 4)
+
+    b = Array(2)
+    b[0] = Vec(5, 6)
+    b[1] = Vec(7, 8)
+
+    r = a.cross(b)
+    assert r[0] == 1*6 - 2*5
+    assert r[1] == 3*8 - 4*7
+
+    c = Vec(5, 6)
+    r = a.cross(c)
+    assert r[0] == 1*6 - 2*5
+    assert r[1] == 3*6 - 4*5
+
+    d = Array(3)
+    try:
+        a.cross(d)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Addition.
+
+    a = Array(2)
+    a[0] = Vec(1, 2)
+    a[1] = Vec(3, 4)
+
+    b = Array(2)
+    b[0] = Vec(5, 6)
+    b[1] = Vec(7, 8)
+
+    r = a + b
+    assert r[0] == Vec(1+5, 2+6)
+    assert r[1] == Vec(3+7, 4+8)
+
+    r = a + Vec(10)
+    assert r[0] == Vec(1+10, 2+10)
+    assert r[1] == Vec(3+10, 4+10)
+
+    v = Vec(11)
+    r = v + a 
+    assert r[0] == Vec(11+1, 11+2)
+    assert r[1] == Vec(11+3, 11+4)
+
+    a += b
+    assert a[0] == Vec(1+5, 2+6)
+    assert a[1] == Vec(3+7, 4+8)
+
+    a[0] = Vec(1, 2)
+    a[1] = Vec(3, 4)
+
+    a += Vec(10)
+    assert a[0] == Vec(1+10, 2+10)
+    assert a[1] == Vec(3+10, 4+10)
+
+    c = Array(3)
+
+    try:
+        a + c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a += c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Subtraction.
+
+    a = Array(2)
+    a[0] = Vec(1, 2)
+    a[1] = Vec(3, 4)
+
+    b = Array(2)
+    b[0] = Vec(5, 6)
+    b[1] = Vec(7, 8)
+
+    r = a - b
+    assert r[0] == Vec(1-5, 2-6)
+    assert r[1] == Vec(3-7, 4-8)
+
+    r = a - Vec(10)
+    assert r[0] == Vec(1-10, 2-10)
+    assert r[1] == Vec(3-10, 4-10)
+
+    r = Vec(10) - a
+    assert r[0] == Vec(10-1, 10-2)
+    assert r[1] == Vec(10-3, 10-4)
+
+    v = Vec(11)
+    r = v - a 
+    assert r[0] == Vec(11-1, 11-2)
+    assert r[1] == Vec(11-3, 11-4)
+
+    a -= b
+    assert a[0] == Vec(1-5, 2-6)
+    assert a[1] == Vec(3-7, 4-8)
+
+    a[0] = Vec(1, 2)
+    a[1] = Vec(3, 4)
+
+    a -= Vec(10)
+    assert a[0] == Vec(1-10, 2-10)
+    assert a[1] == Vec(3-10, 4-10)
+
+    c = Array(3)
+
+    try:
+        a - c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a -= c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Negation.
+
+    a = Array(2)
+    a[0] = Vec(1, 2)
+    a[1] = Vec(3, 4)
+
+    r = -a
+    assert r[0] == Vec(-1, -2)
+    assert r[1] == Vec(-3, -4)
+
+    # Multiplication.
+
+    a = Array(2)
+    a[0] = Vec(1, 2)
+    a[1] = Vec(3, 4)
+
+    r = a * 10
+    assert r[0] == Vec(1, 2) * 10
+    assert r[1] == Vec(3, 4) * 10
+
+    b = Arrayx(2)
+    b[0] = 10
+    b[1] = 11
+
+    r = a * b
+    assert r[0] == Vec(1, 2) * 10
+    assert r[1] == Vec(3, 4) * 11
+    
+    a *= 10
+    assert a[0] == Vec(1, 2) * 10
+    assert a[1] == Vec(3, 4) * 10
+
+    a[0] = Vec(1, 2)
+    a[1] = Vec(3, 4)
+
+    a *= b
+    assert a[0] == Vec(1, 2) * 10
+    assert a[1] == Vec(3, 4) * 11
+
+    a[0] = Vec(1, 2)
+    a[1] = Vec(3, 4)
+
+    b = Array(2)
+    b[0] = Vec(5, 6)
+    b[1] = Vec(7, 8)
+
+    r = a * b
+    assert r[0] == Vec(1*5, 2*6)
+    assert r[1] == Vec(3*7, 4*8)
+
+    v = Vec(9, 10)
+
+    r = a * v
+    assert r[0] == Vec(1*9, 2*10)
+    assert r[1] == Vec(3*9, 4*10)
+
+    r = v * a
+    assert r[0] == Vec(1*9, 2*10)
+    assert r[1] == Vec(3*9, 4*10)
+
+    a *= b
+    assert a[0] == Vec(1*5, 2*6)
+    assert a[1] == Vec(3*7, 4*8)
+
+    a[0] = Vec(1, 2)
+    a[1] = Vec(3, 4)
+
+    a *= v
+    assert a[0] == Vec(1*9, 2*10)
+    assert a[1] == Vec(3*9, 4*10)
+
+    d = Array(3)
+    try:
+        a * d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a *= d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Division.
+
+    a = Array(2)
+    a[0] = Vec(1.0, 2.0)
+    a[1] = Vec(3.0, 4.0)
+
+    r = a / 10
+    assert r[0] == Vec(1.0, 2.0) / 10
+    assert r[1] == Vec(3.0, 4.0) / 10
+
+    b = Arrayx(2)
+    b[0] = 10
+    b[1] = 11
+
+    r = a / b
+    assert r[0] == Vec(1.0, 2.0) / 10
+    assert r[1] == Vec(3.0, 4.0) / 11
+    
+    a /= 10
+    assert a[0] == Vec(1.0, 2.0) / 10
+    assert a[1] == Vec(3.0, 4.0) / 10
+
+    a[0] = Vec(1.0, 2.0)
+    a[1] = Vec(3.0, 4.0)
+
+    a /= b
+    assert a[0] == Vec(1.0, 2.0) / 10
+    assert a[1] == Vec(3.0, 4.0) / 11
+
+    a[0] = Vec(1.0, 2.0)
+    a[1] = Vec(3.0, 4.0)
+
+    b = Array(2)
+    b[0] = Vec(5, 6)
+    b[1] = Vec(7, 8)
+
+    r = a / b
+    assert r[0] == Vec(1.0/5, 2.0/6)
+    assert r[1] == Vec(3.0/7, 4.0/8)
+
+    v = Vec(9, 10)
+
+    r = a / v
+    assert r[0] == Vec(1.0/9, 2.0/10)
+    assert r[1] == Vec(3.0/9, 4.0/10)
+
+    # TODO: Figure out why "v / a" is illegal, even though the
+    # add_arithmetic_math_functions() routine in PyImathFixedArray.h
+    # should make it possible.
+    #r = v / a
+    #assert r[0] == Vec(1.0/9, 2.0/10)
+    #assert r[1] == Vec(3.0/9, 4.0/10)
+
+    a /= b
+    assert a[0] == Vec(1.0/5, 2.0/6)
+    assert a[1] == Vec(3.0/7, 4.0/8)
+
+    a[0] = Vec(1.0, 2.0)
+    a[1] = Vec(3.0, 4.0)
+
+    a /= v
+    assert a[0] == Vec(1.0/9, 2.0/10)
+    assert a[1] == Vec(3.0/9, 4.0/10)
+
+    d = Array(3)
+    try:
+        a / d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a /= d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Length.
+
+    if (Vec != V2i):
+        v0 = Vec(1, 2)
+        v1 = Vec(3, 4)
+
+        a = Array(2)
+        a[0] = v0
+        a[1] = v1
+
+        l = a.length()
+        assert (l[0] == v0.length())
+        assert (l[1] == v1.length())
+
+        l = a.length2()
+        assert (l[0] == v0.length2())
+        assert (l[1] == v1.length2())
+
+    # Normalizing.
+
+    if (Vec != V2i):
+
+        a[0] = Vec(1, 2)
+        a[1] = Vec(3, 4)
+
+        r = a.normalized();
+        assert r[0] == Vec(1, 2).normalized()
+        assert r[1] == Vec(3, 4).normalized()
+
+        a.normalize();
+        assert a[0] == Vec(1, 2).normalized()
+        assert a[1] == Vec(3, 4).normalized()
+
+    print ("ok")
+
+    return
+
+def testV2Array ():
+
+    print ("V2iArray")
+    testV2xArray (V2iArray, V2i, IntArray)
+    print ("V2fArray")
+    testV2xArray (V2fArray, V2f, FloatArray)
+    print ("V2dArray")
+    testV2xArray (V2dArray, V2d, DoubleArray)
+
+testList.append (('testV2Array',testV2Array))
+
+
+# -------------------------------------------------------------------------
+# Tests for V3x
+
+def testV3x (Vec):
+    
+    # Constructors (and element access).
+
+    v = Vec()
+    assert v[0] == 0 and v[1] == 0 and v[2] == 0
+
+    v = Vec(1)
+    assert v[0] == 1 and v[1] == 1 and v[2] == 1
+
+    v = Vec(0, 1, 2)
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2
+
+    v = Vec((0, 1, 2))
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2
+
+    v = Vec([0, 1, 2])
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2
+
+    v = Vec()
+    v.setValue(0, 1, 2)
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2
+
+    # Repr.
+
+    v = Vec(1/9., 2/9., 3/9.)
+    assert v == eval(repr(v))
+
+    # Sequence length.
+
+    v = Vec()
+    assert len(v) == 3
+
+    # Element setting.
+
+    v = Vec()
+    v[0] = 10
+    v[1] = 11
+    v[2] = 12
+    assert v[0] == 10 and v[1] == 11 and v[2] == 12
+
+    try:
+        v[-4] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[3] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[1] = "a"           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    v1 = Vec(1)
+    
+    v2 = v1
+    assert v2[0] == 1 and v2[1] == 1 and v2[2] == 1
+    v1[0] = 2
+    assert v2[0] == 2 and v2[1] == 1 and v2[2] == 1
+    
+    # Comparison operators.
+
+    v1 = Vec(20, 20, 0)
+    v2 = Vec(20, 20, 0)
+    v3 = Vec(20, 21, 0)
+
+    assert v1 == v2
+    assert v1 != v3
+    assert not (v1 < v2)
+    assert v1 < v3
+    assert v1 <= v2
+    assert v1 <= v3
+    assert not (v3 <= v1)
+    assert not (v2 > v1)
+    assert v3 > v1
+    assert v2 >= v1
+    assert v3 >= v1
+    assert not (v1 >= v3)
+    
+    # Epsilon equality.
+
+    e = 0.005
+    v1 = Vec(1)
+    v2 = Vec(1 + e)
+
+    assert v1.equalWithAbsError(v2, e)
+    assert v2.equalWithAbsError(v1, e)
+
+    e = 0.003
+    v1 = Vec(10)
+    v2 = Vec(10 + 10 * e)
+
+    assert v1.equalWithRelError(v2, e)
+    assert v2.equalWithRelError(v1, e)
+
+    # Dot products.
+
+    v1 = Vec(0, 1, 0)
+    v2 = Vec(1, 0, 0)
+    v3 = Vec(1, 1, 0)
+
+    assert v1.dot(v2) == 0
+    assert v1.dot(v3) == 1
+    assert v1 ^ v2 == v1.dot(v2)
+    assert v1 ^ v3 == v1.dot(v3)
+
+    # Cross products.
+
+    v1 = Vec(1, 0, 0)
+    v2 = Vec(0, 1, 0)
+
+    assert v1.cross(v2) == Vec(0, 0, 1)
+    assert v2.cross(v1) == Vec(0, 0, -1)
+    assert v1 % v2 == v1.cross(v2)
+    assert v2 % v1 == v2.cross(v1)
+
+    # Addition.
+
+    v1 = Vec(10, 20, 30)
+    v2 = Vec(30, 40, 50)
+
+    assert v1 + v2 == Vec(40, 60, 80)
+    assert v2 + v1 == v1 + v2
+    assert v1 + 1 == Vec(11, 21, 31)
+    assert 1 + v1 == v1 + 1
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 + (1, 2, 3) == Vec(11, 22, 33)
+    assert (1, 2, 3) + v1 == v1 + (1, 2, 3)
+
+    # Subtraction and negation.
+
+    v1 = Vec(10, 20, 30)
+    v2 = Vec(30, 40, 50)
+
+    assert v2 - v1 == Vec(20, 20, 20)
+    assert v1 - 1 == Vec(9, 19, 29)
+    assert 1 - v1 == - (v1 - 1)
+    
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 - (1, 2, 3) == Vec(9, 18, 27)
+    assert (1, 2, 3) - v1 == - (v1 - (1, 2, 3))
+
+    assert v1.negate() == Vec(-10, -20, -30)
+
+    # Multiplication.
+
+    v1 = Vec(1, 2, 3)
+    v2 = Vec(3, 4, 5)
+    
+    assert v1 * v2 == Vec(3, 8, 15)
+    assert v2 * v1 == v1 * v2
+    assert 2 * v1 == Vec(2, 4, 6)
+    assert v1 * 2 == 2 * v1
+
+    assert v1 * V3i(3, 4, 5) == Vec(3, 8, 15)
+    assert v1 * V3f(3, 4, 5) == Vec(3, 8, 15)
+    assert v1 * V3d(3, 4, 5) == Vec(3, 8, 15)
+
+    v1 *= 2
+    assert v1 == Vec(2, 4, 6)
+    v1 = Vec(1, 2, 3)
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 * (1, 2, 3) == Vec(1, 4, 9)
+    assert (1, 2, 3) * v1 == v1 * (1, 2, 3)
+
+    # Division.
+
+    v1 = Vec(10, 20, 40)
+    v2 = Vec(2, 4, 8)
+    
+    assert v1 / v2 == Vec(10/2, 20/4, 40/8)
+    assert v1 / 2 == Vec(10/2, 20/2, 40/2)
+    assert Vec(40) / v1 == Vec(40/10, 40/20, 40/40)
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 / (1, 2, 4) == Vec(10, 10, 10)
+    assert Vec(50, 40, 80) / v1 == Vec(5, 2, 2)
+
+    assert v1 / V3i (2, 4, 8) == Vec(10/2, 20/4, 40/8)
+    assert v1 / V3f (2, 4, 8) == Vec(10/2, 20/4, 40/8)
+    assert v1 / V3d (2, 4, 8) == Vec(10/2, 20/4, 40/8)
+    assert v1 / (2, 4, 8) == Vec(10/2, 20/4, 40/8)
+    assert v1 / [2, 4, 8] == Vec(10/2, 20/4, 40/8)
+
+    v1 = Vec(10, 20, 40)
+    v1 /= 2
+    assert v1 == Vec(10/2, 20/2, 40/2)
+    
+    v1 = Vec(10, 20, 40)
+    v1 /= V3i (2, 4, 8)
+    assert v1 == Vec(10/2, 20/4, 40/8)
+    
+    v1 = Vec(10, 20, 40)
+    v1 /= V3f (2, 4, 8)
+    assert v1 == Vec(10/2, 20/4, 40/8)
+
+    v1 = Vec(10, 20, 40)
+    v1 /= V3d (2, 4, 8)
+    assert v1 == Vec(10/2, 20/4, 40/8)
+
+    v1 = Vec(10, 20, 40)
+    v1 /= (2, 4, 8)
+    assert v1 == Vec(10/2, 20/4, 40/8)
+
+    v1 = Vec(10, 20, 40)
+    v1 /= [2, 4, 8]
+    assert v1 == Vec(10/2, 20/4, 40/8)
+
+    # Length.
+
+    if (Vec != V3i):
+       v = Vec(1, 2, 3)
+       assert equal(v.length(), sqrt(1*1 + 2*2 + 3*3), v.baseTypeEpsilon())
+
+    v = Vec(1, 2, 3)
+    assert v.length2() == 1*1 + 2*2 + 3*3
+
+    # Normalizing.
+
+    if (Vec != V3i):
+       v = Vec(1, 2, 3)
+       v.normalize()
+       assert equal(v.length(), 1, v.baseTypeEpsilon())
+
+       v = Vec(1, 2, 3)
+       v.normalizeExc()
+       assert equal(v.length(), 1, v.baseTypeEpsilon())
+       v = Vec(0)
+       try:
+           v.normalizeExc()        # This should raise an exception.
+       except:
+           pass
+       else:
+           assert 0                # We shouldn't get here.
+       
+       v = Vec(1, 2, 3)
+       v.normalizeNonNull()
+       assert equal(v.length(), 1, v.baseTypeEpsilon())
+
+       v = Vec(1, 2, 3)
+       assert equal(v.normalized().length(), 1, v.baseTypeEpsilon())
+
+       v = Vec(1, 2, 3)
+       assert equal(v.normalizedExc().length(), 1, v.baseTypeEpsilon())
+       v = Vec(0)
+       try:
+           v.normalizedExc()  # This should raise an exception.
+       except:
+           pass
+       else:
+           assert 0              # We shouldn't get here.
+       
+       v = Vec(1, 2, 3)
+       assert equal(v.normalizedNonNull().length(), 1, v.baseTypeEpsilon())
+
+    # Projection.
+
+    if (Vec != V3i):
+        s = Vec(2, 0, 0)
+        t = Vec(1, 1, 0)
+        assert t.project(s) == Vec(1, 0, 0)
+
+    # Orthogonal.
+
+    if (Vec != V3i):
+        s = Vec(2, 0, 0)
+        t = Vec(1, 1, 0)
+        o = s.orthogonal(t)
+        assert iszero(o ^ s, s.baseTypeEpsilon())
+
+    # Reflect.
+
+    if (Vec != V3i):
+        s = Vec(1, 1, 0)
+        t = Vec(2, 0, 0)
+        r = s.reflect(t)
+        assert equal(abs(s ^ t), abs(r ^ t), s.baseTypeEpsilon())
+
+    # Closest vertex.
+
+    v0 = Vec(0, 0, 0)
+    v1 = Vec(5, 0, 0)
+    v2 = Vec(0, 5, 0)
+    
+    p = Vec(1, 1, 0)
+    assert p.closestVertex(v0, v1, v2) == v0
+
+    p = Vec(4, 1, 0)
+    assert p.closestVertex(v0, v1, v2) == v1
+
+    p = Vec(1, 4, 0)
+    assert p.closestVertex(v0, v1, v2) == v2
+
+
+    print ("ok")
+
+    return
+
+def testV3 ():
+
+    print ("V3i")
+    testV3x (V3i)
+    print ("V3f")
+    testV3x (V3f)
+    print ("V3d")
+    testV3x (V3d)
+
+testList.append (('testV3',testV3))
+
+
+# -------------------------------------------------------------------------
+# Tests for V3xArray
+
+def testV3xArray (Array, Vec, Arrayx):
+    
+    # Constructors (and element access).
+
+    a = Array (3)
+
+    a[0] = Vec(0)
+    a[1] = Vec(1)
+    a[2] = Vec(2)
+
+    assert a[0] == Vec(0)
+    assert a[1] == Vec(1)
+    assert a[2] == Vec(2)
+
+    a[0].setValue(10,10,10)
+    a[1].setValue(11,11,11)
+    a[2].setValue(12,12,12)
+
+    assert a[0] == Vec(10)
+    assert a[1] == Vec(11)
+    assert a[2] == Vec(12)
+
+    # explicit constructors across types
+    af = V3fArray(a)
+    assert a[0] == Vec(af[0])
+    assert a[1] == Vec(af[1])
+    assert a[2] == Vec(af[2])
+    ad = V3dArray(a)
+    assert a[0] == Vec(ad[0])
+    assert a[1] == Vec(ad[1])
+    assert a[2] == Vec(ad[2])
+    ai = V3iArray(a)
+    assert a[0] == Vec(ai[0])
+    assert a[1] == Vec(ai[1])
+    assert a[2] == Vec(ai[2])
+
+
+    # Element setting.
+
+    a = Array(2)
+
+    try:
+        a[-3] = Vec(0)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a[3] = Vec(0)   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        a[1] = "a"         # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    a = Array(2)
+    a[0] = Vec(0)
+    a[1] = Vec(1)
+    
+    b = Array(2)
+    b[0] = Vec(0)
+    b[1] = Vec(1)
+    
+    c = Array(2)
+    c[0] = Vec(10)
+    c[1] = Vec(11)
+
+    # TODO: make equality work correctly.
+    #assert a == b
+    assert a != c
+    
+    # Dot products.
+
+    a = Array(2)
+    a[0] = Vec(1, 2, 3)
+    a[1] = Vec(4, 5, 6)
+
+    b = Array(2)
+    b[0] = Vec(7, 8, 9)
+    b[1] = Vec(10, 11, 12)
+
+    r = a.dot(b)
+    assert r[0] == 1*7 + 2*8 + 3*9
+    assert r[1] == 4*10 + 5*11 + 6*12
+
+    c = Vec(13, 14, 15)
+    r = a.dot(c)
+    assert r[0] == 1*13 + 2*14 + 3*15
+    assert r[1] == 4*13 + 5*14 + 6*15
+
+    d = Array(3)
+    try:
+        a.dot(d)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+    
+    
+    # Cross products.
+
+    a = Array(2)
+    a[0] = Vec(1, 2, 3)
+    a[1] = Vec(4, 5, 6)
+
+    b = Array(2)
+    b[0] = Vec(7, 8, 9)
+    b[1] = Vec(10, 11, 12)
+
+    r = a.cross(b)
+    assert r[0] == Vec(1, 2, 3) % Vec(7, 8, 9)
+    assert r[1] == Vec(4, 5, 6) % Vec(10, 11, 12)
+
+    c = Vec(13, 14, 15)
+    r = a.cross(c)
+    assert r[0] == Vec(1, 2, 3) % Vec(13, 14, 15)
+    assert r[1] == Vec(4, 5, 6) % Vec(13, 14, 15)
+
+    d = Array(3)
+    try:
+        a.cross(d)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Addition.
+
+    a = Array(2)
+    a[0] = Vec(1, 2, 3)
+    a[1] = Vec(4, 5, 6)
+
+    b = Array(2)
+    b[0] = Vec(7, 8, 9)
+    b[1] = Vec(10, 11, 12)
+
+    r = a + b
+    assert r[0] == Vec(1+7, 2+8, 3+9)
+    assert r[1] == Vec(4+10, 5+11, 6+12)
+
+    r = a + Vec(10)
+    assert r[0] == Vec(1+10, 2+10, 3+10)
+    assert r[1] == Vec(4+10, 5+10, 6+10)
+
+    v = Vec(11)
+    r = v + a 
+    assert r[0] == Vec(11+1, 11+2, 11+3)
+    assert r[1] == Vec(11+4, 11+5, 11+6)
+
+    a += b
+    assert a[0] == Vec(1+7, 2+8, 3+9)
+    assert a[1] == Vec(4+10, 5+11, 6+12)
+
+    a[0] = Vec(1, 2, 3)
+    a[1] = Vec(4, 5, 6)
+
+    a += Vec(10)
+    assert a[0] == Vec(1+10, 2+10, 3+10)
+    assert a[1] == Vec(4+10, 5+10, 6+10)
+
+    c = Array(3)
+
+    try:
+        a + c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a += c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Subtraction.
+
+    a = Array(2)
+    a[0] = Vec(1, 2, 3)
+    a[1] = Vec(4, 5, 6)
+
+    b = Array(2)
+    b[0] = Vec(7, 8, 9)
+    b[1] = Vec(10, 11, 12)
+
+    r = a - b
+    assert r[0] == Vec(1-7, 2-8, 3-9)
+    assert r[1] == Vec(4-10, 5-11, 6-12)
+
+    r = a - Vec(10)
+    assert r[0] == Vec(1-10, 2-10, 3-10)
+    assert r[1] == Vec(4-10, 5-10, 6-10)
+
+    v = Vec(11)
+    r = v - a 
+    assert r[0] == Vec(11-1, 11-2, 11-3)
+    assert r[1] == Vec(11-4, 11-5, 11-6)
+
+    a -= b
+    assert a[0] == Vec(1-7, 2-8, 3-9)
+    assert a[1] == Vec(4-10, 5-11, 6-12)
+
+    a[0] = Vec(1, 2, 3)
+    a[1] = Vec(4, 5, 6)
+
+    a -= Vec(10)
+    assert a[0] == Vec(1-10, 2-10, 3-10)
+    assert a[1] == Vec(4-10, 5-10, 6-10)
+
+    c = Array(3)
+
+    try:
+        a - c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a -= c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Negation.
+
+    a = Array(2)
+    a[0] = Vec(1, 2, 3)
+    a[1] = Vec(4, 5, 6)
+
+    r = -a
+    assert r[0] == Vec(-1, -2, -3)
+    assert r[1] == Vec(-4, -5, -6)
+
+    # Multiplication.
+
+    a = Array(2)
+    a[0] = Vec(1, 2, 3)
+    a[1] = Vec(4, 5, 6)
+
+    r = a * 10
+    assert r[0] == Vec(1, 2, 3) * 10
+    assert r[1] == Vec(4, 5, 6) * 10
+
+    b = Arrayx(2)
+    b[0] = 10
+    b[1] = 11
+
+    r = a * b
+    assert r[0] == Vec(1, 2, 3) * 10
+    assert r[1] == Vec(4, 5, 6) * 11
+    
+    a *= 10
+    assert a[0] == Vec(1, 2, 3) * 10
+    assert a[1] == Vec(4, 5, 6) * 10
+
+    a[0] = Vec(1, 2, 3)
+    a[1] = Vec(4, 5, 6)
+
+    a *= b
+    assert a[0] == Vec(1, 2, 3) * 10
+    assert a[1] == Vec(4, 5, 6) * 11
+
+    a[0] = Vec(1, 2, 3)
+    a[1] = Vec(4, 5, 6)
+
+    b = Array(2)
+    b[0] = Vec(7, 8, 9)
+    b[1] = Vec(10, 11, 12)
+
+    r = a * b
+    assert r[0] == Vec(1*7, 2*8, 3*9)
+    assert r[1] == Vec(4*10, 5*11, 6*12)
+
+    v = Vec(13, 14, 15)
+
+    r = a * v
+    assert r[0] == Vec(1*13, 2*14, 3*15)
+    assert r[1] == Vec(4*13, 5*14, 6*15)
+
+    r = v * a
+    assert r[0] == Vec(1*13, 2*14, 3*15)
+    assert r[1] == Vec(4*13, 5*14, 6*15)
+
+    a *= b
+    assert a[0] == Vec(1*7, 2*8, 3*9)
+    assert a[1] == Vec(4*10, 5*11, 6*12)
+
+    a[0] = Vec(1, 2, 3)
+    a[1] = Vec(4, 5, 6)
+
+    a *= v
+    assert a[0] == Vec(1*13, 2*14, 3*15)
+    assert a[1] == Vec(4*13, 5*14, 6*15)
+
+    d = Array(3)
+    try:
+        a * d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a *= d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Division.
+
+    a = Array(2)
+    a[0] = Vec(1.0, 2.0, 3.0)
+    a[1] = Vec(4.0, 5.0, 6.0)
+
+    r = a / 10
+    assert r[0] == Vec(1.0, 2.0, 3.0) / 10
+    assert r[1] == Vec(4.0, 5.0, 6.0) / 10
+
+    b = Arrayx(2)
+    b[0] = 10
+    b[1] = 11
+
+    r = a / b
+    assert r[0] == Vec(1.0, 2.0, 3.0) / 10
+    assert r[1] == Vec(4.0, 5.0, 6.0) / 11
+    
+    a /= 10
+    assert a[0] == Vec(1.0, 2.0, 3.0) / 10
+    assert a[1] == Vec(4.0, 5.0, 6.0) / 10
+
+    a[0] = Vec(1.0, 2.0, 3.0)
+    a[1] = Vec(4.0, 5.0, 6.0)
+
+    a /= b
+    assert a[0] == Vec(1.0, 2.0, 3.0) / 10
+    assert a[1] == Vec(4.0, 5.0, 6.0) / 11
+
+    a[0] = Vec(1.0, 2.0, 3.0)
+    a[1] = Vec(4.0, 5.0, 6.0)
+
+    b = Array(2)
+    b[0] = Vec(7.0, 8.0, 9.0)
+    b[1] = Vec(10.0, 11.0, 12.0)
+
+    r = a / b
+    assert r[0] == Vec(1.0/7, 2.0/8, 3.0/9)
+    assert r[1] == Vec(4.0/10, 5.0/11, 6.0/12)
+
+    v = Vec(13.0, 14.0, 15.0)
+
+    r = a / v
+    assert r[0] == Vec(1.0/13, 2.0/14, 3.0/15)
+    assert r[1] == Vec(4.0/13, 5.0/14, 6.0/15)
+
+    # TODO: Figure out why "v / a" is illegal, even though the
+    # add_arithmetic_math_functions() routine in PyImathFixedArray.h
+    # should make it possible.
+    #r = v / a
+    #assert r[0] == Vec(1.0/13, 2.0/14, 3.0/15)
+    #assert r[1] == Vec(4.0/13, 5.0/14, 6.0/15)
+
+    a /= b
+    assert a[0] == Vec(1.0/7, 2.0/8, 3.0/9)
+    assert a[1] == Vec(4.0/10, 5.0/11, 6.0/12)
+
+    a[0] = Vec(1.0, 2.0, 3.0)
+    a[1] = Vec(4.0, 5.0, 6.0)
+
+    a /= v
+    assert a[0] == Vec(1.0/13, 2.0/14, 3.0/15)
+    assert a[1] == Vec(4.0/13, 5.0/14, 6.0/15)
+
+    d = Array(3)
+    try:
+        a / d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a /= d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Length.
+
+    v0 = Vec(1, 2, 3)
+    v1 = Vec(4, 5, 6)
+
+    a = Array(2)
+    a[0] = v0
+    a[1] = v1
+
+    if (Vec != V3i):
+        l = a.length()
+        assert (l[0] == v0.length())
+        assert (l[1] == v1.length())
+
+    l = a.length2()
+    assert (l[0] == v0.length2())
+    assert (l[1] == v1.length2())
+    
+    # Normalizing.
+
+    if (Vec != V3i):
+
+        a[0] = Vec(1, 2, 3)
+        a[1] = Vec(4, 5, 6)
+
+        r = a.normalized();
+        assert r[0] == Vec(1, 2, 3).normalized()
+        assert r[1] == Vec(4, 5, 6).normalized()
+
+        a.normalize();
+        assert a[0] == Vec(1, 2, 3).normalized()
+        assert a[1] == Vec(4, 5, 6).normalized()
+
+    print ("ok")
+
+    return
+
+def testV3Array ():
+
+    print ("V3iArray")
+    testV3xArray (V3iArray, V3i, IntArray)
+    print ("V3fArray")
+    testV3xArray (V3fArray, V3f, FloatArray)
+    print ("V3dArray")
+    testV3xArray (V3dArray, V3d, DoubleArray)
+
+testList.append (('testV3Array',testV3Array))
+
+
+# -------------------------------------------------------------------------
+# Tests for Vec --> Vec conversions
+
+def testV2xConversions (Vec):
+
+    # Assignment
+    
+    v1 = Vec(0, 1)
+
+    v2 = V2i (v1)
+    assert v2[0] == 0 and v2[1] == 1
+
+    v2 = V2f (v1)
+    assert v2[0] == 0 and v2[1] == 1
+
+    v2 = V2d (v1)
+    assert v2[0] == 0 and v2[1] == 1
+
+    # The += operator
+    
+    v2 = Vec (1, 2)
+    v2 += V2i (v1)
+    assert v2[0] == 1 and v2[1] == 3
+
+    v2 = Vec (1, 2)
+    v2 += V2f (v1)
+    assert v2[0] == 1 and v2[1] == 3
+
+    v2 = Vec (1, 2)
+    v2 += V2d (v1)
+    assert v2[0] == 1 and v2[1] == 3
+
+    # The -= operator
+    
+    v2 = Vec (1, 2)
+    v2 -= V2i (v1)
+    assert v2[0] == 1 and v2[1] == 1
+
+    v2 = Vec (1, 2)
+    v2 -= V2f (v1)
+    assert v2[0] == 1 and v2[1] == 1
+
+    v2 = Vec (1, 2)
+    v2 -= V2d (v1)
+    assert v2[0] == 1 and v2[1] == 1
+
+    # The *= operator
+    
+    v2 = Vec (1, 2)
+    v2 *= V2i (v1)
+    assert v2[0] == 0 and v2[1] == 2
+
+    v2 = Vec (1, 2)
+    v2 *= V2f (v1)
+    assert v2[0] == 0 and v2[1] == 2
+
+    v2 = Vec (1, 2)
+    v2 *= V2d (v1)
+    assert v2[0] == 0 and v2[1] == 2
+
+    print ("ok")
+    return
+
+
+def testV3xConversions (Vec):
+
+    # Assignment
+    
+    v1 = Vec(0, 1, 2)
+
+    v2 = V3i (v1)
+    assert v2[0] == 0 and v2[1] == 1 and v2[2] == 2
+
+    v2 = V3f (v1)
+    assert v2[0] == 0 and v2[1] == 1 and v2[2] == 2
+
+    v2 = V3d (v1)
+    assert v2[0] == 0 and v2[1] == 1 and v2[2] == 2
+
+    # The += operator
+
+    v2 = Vec (1, 2, 3)
+    v2 += V3i (v1)
+    assert v2[0] == 1 and v2[1] == 3 and v2[2] == 5
+    
+    v2 = Vec (1, 2, 3)
+    v2 += V3f (v1)
+    assert v2[0] == 1 and v2[1] == 3 and v2[2] == 5
+    
+    v2 = Vec (1, 2, 3)
+    v2 += V3d (v1)
+    assert v2[0] == 1 and v2[1] == 3 and v2[2] == 5
+
+    # The -= operator
+
+    v2 = Vec (1, 2, 3)
+    v2 -= V3i (v1)
+    assert v2[0] == 1 and v2[1] == 1 and v2[2] == 1
+    
+    v2 = Vec (1, 2, 3)
+    v2 -= V3f (v1)
+    assert v2[0] == 1 and v2[1] == 1 and v2[2] == 1
+    
+    v2 = Vec (1, 2, 3)
+    v2 -= V3d (v1)
+    assert v2[0] == 1 and v2[1] == 1 and v2[2] == 1
+
+    # The *= operator
+    
+    v2 = Vec (1, 2, 3)
+    v2 *= V3i (v1)
+    assert v2[0] == 0 and v2[1] == 2 and v2[2] == 6
+    
+    v2 = Vec (1, 2, 3)
+    v2 *= V3f (v1)
+    assert v2[0] == 0 and v2[1] == 2 and v2[2] == 6
+    
+    v2 = Vec (1, 2, 3)
+    v2 *= V3d (v1)
+    assert v2[0] == 0 and v2[1] == 2 and v2[2] == 6
+    
+    print ("ok")
+    return
+
+# -------------------------------------------------------------------------
+# Tests for V4x
+
+def testV4x (Vec):
+    
+    # Constructors (and element access).
+
+    v = Vec()
+    assert v[0] == 0 and v[1] == 0 and v[2] == 0 and v[3] == 0
+
+    v = Vec(1)
+    assert v[0] == 1 and v[1] == 1 and v[2] == 1 and v[3] == 1
+
+    v = Vec(0, 1, 2, 3)
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2 and v[3] == 3
+
+    v = Vec((0, 1, 2, 3))
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2 and v[3] == 3
+
+    v = Vec([0, 1, 2, 3])
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2 and v[3] == 3
+
+    v = Vec()
+    v.setValue(0, 1, 2, 3)
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2 and v[3] == 3
+
+    # Repr.
+
+    v = Vec(1/9., 2/9., 3/9., 4./9.)
+    assert v == eval(repr(v))
+
+    # Sequence length.
+
+    v = Vec()
+    assert len(v) == 4
+
+    # Element setting.
+
+    v = Vec()
+    v[0] = 10
+    v[1] = 11
+    v[2] = 12
+    v[3] = 13
+    assert v[0] == 10 and v[1] == 11 and v[2] == 12 and v[3] == 13
+
+    try:
+        # TODO why does this have to be -5 and not -4?
+        v[-5] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[4] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[1] = "a"           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    v1 = Vec(1)
+    
+    v2 = v1
+    assert v2[0] == 1 and v2[1] == 1 and v2[2] == 1 and v2[3] == 1
+    v1[0] = 2
+    assert v2[0] == 2 and v2[1] == 1 and v2[2] == 1 and v2[3] == 1
+    
+    # Comparison operators.
+
+    v1 = Vec(20, 20, 20, 20)
+    v2 = Vec(20, 20, 20, 20)
+    v3 = Vec(20, 20, 20, 21)
+
+    assert v1 == v2
+    assert v1 != v3
+    assert not (v1 < v2)
+    assert v1 < v3
+    assert v1 <= v2
+    assert v1 <= v3
+    assert not (v3 <= v1)
+    assert not (v2 > v1)
+    assert v3 > v1
+    assert v2 >= v1
+    assert v3 >= v1
+    assert not (v1 >= v3)
+    
+    # Epsilon equality.
+
+    e = 0.005
+    v1 = Vec(1)
+    v2 = Vec(1 + e)
+
+    assert v1.equalWithAbsError(v2, e)
+    assert v2.equalWithAbsError(v1, e)
+
+    e = 0.003
+    v1 = Vec(10)
+    v2 = Vec(10 + 10 * e)
+
+    assert v1.equalWithRelError(v2, e)
+    assert v2.equalWithRelError(v1, e)
+
+    # Dot products.
+
+    v1 = Vec(0, 1, 0, 1)
+    v2 = Vec(1, 0, 0, 0)
+    v3 = Vec(1, 1, 1, 1)
+
+    assert v1.dot(v2) == 0
+    assert v1.dot(v3) == 2
+    assert v1 ^ v2 == v1.dot(v2)
+    assert v1 ^ v3 == v1.dot(v3)
+
+    # Addition.
+
+    v1 = Vec(10, 20, 30, 40)
+    v2 = Vec(30, 40, 50, 60)
+
+    assert v1 + v2 == Vec(40, 60, 80, 100)
+    assert v2 + v1 == v1 + v2
+    assert v1 + 1 == Vec(11, 21, 31, 41)
+    assert 1 + v1 == v1 + 1
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 + (1, 2, 3, 4) == Vec(11, 22, 33, 44)
+    assert (1, 2, 3, 4) + v1 == v1 + (1, 2, 3, 4)
+
+    # Subtraction and negation.
+
+    v1 = Vec(10, 20, 30, 40)
+    v2 = Vec(30, 40, 50, 60)
+
+    assert v2 - v1 == Vec(20, 20, 20, 20)
+    assert v1 - 1 == Vec(9, 19, 29, 39)
+    assert 1 - v1 == - (v1 - 1)
+    
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 - (1, 2, 3, 4) == Vec(9, 18, 27, 36)
+    assert (1, 2, 3, 4) - v1 == - (v1 - (1, 2, 3, 4))
+
+    assert v1.negate() == Vec(-10, -20, -30, -40)
+
+    # Multiplication.
+
+    v1 = Vec(1, 2, 3, 4)
+    v2 = Vec(3, 4, 5, 6)
+    
+    assert v1 * v2 == Vec(3, 8, 15, 24)
+    assert v2 * v1 == v1 * v2
+    assert 2 * v1 == Vec(2, 4, 6, 8)
+    assert v1 * 2 == 2 * v1
+
+    assert v1 * V4i(3, 4, 5, 6) == Vec(3, 8, 15, 24)
+    assert v1 * V4f(3, 4, 5, 6) == Vec(3, 8, 15, 24)
+    assert v1 * V4d(3, 4, 5, 6) == Vec(3, 8, 15, 24)
+
+    v1 *= 2
+    assert v1 == Vec(2, 4, 6, 8)
+    v1 = Vec(1, 2, 3, 4)
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 * (1, 2, 3, 4) == Vec(1, 4, 9, 16)
+    assert (1, 2, 3, 4) * v1 == v1 * (1, 2, 3, 4)
+
+    # Division.
+
+    v1 = Vec(10, 20, 40, 80)
+    v2 = Vec(2, 4, 8, 10)
+    
+    assert v1 / v2 == Vec(10/2, 20/4, 40/8, 80/10)
+    assert v1 / 2 == Vec(10/2, 20/2, 40/2, 80/2)
+    assert Vec(80) / v1 == Vec(80/10, 80/20, 80/40, 80/80)
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert v1 / (1, 2, 4, 8) == Vec(10, 10, 10, 10)
+    assert Vec(50, 40, 80, 160) / v1 == Vec(5, 2, 2, 2)
+
+    assert v1 / V4i (2, 4, 8, 10) == Vec(10/2, 20/4, 40/8, 80/10)
+    assert v1 / V4f (2, 4, 8, 10) == Vec(10/2, 20/4, 40/8, 80/10)
+    assert v1 / V4d (2, 4, 8, 10) == Vec(10/2, 20/4, 40/8, 80/10)
+    assert v1 / (2, 4, 8, 10) == Vec(10/2, 20/4, 40/8, 80/10)
+    assert v1 / [2, 4, 8, 10] == Vec(10/2, 20/4, 40/8, 80/10)
+
+    v1 = Vec(10, 20, 40, 80)
+    v1 /= 2
+    assert v1 == Vec(10/2, 20/2, 40/2, 80/2)
+    
+    v1 = Vec(10, 20, 40, 80)
+    v1 /= V4i (2, 4, 8, 10)
+    assert v1 == Vec(10/2, 20/4, 40/8, 80/10)
+    
+    v1 = Vec(10, 20, 40, 80)
+    v1 /= V4f (2, 4, 8, 10)
+    assert v1 == Vec(10/2, 20/4, 40/8, 80/10)
+
+    v1 = Vec(10, 20, 40, 80)
+    v1 /= V4d (2, 4, 8, 10)
+    assert v1 == Vec(10/2, 20/4, 40/8, 80/10)
+
+    v1 = Vec(10, 20, 40, 80)
+    v1 /= (2, 4, 8, 10)
+    assert v1 == Vec(10/2, 20/4, 40/8, 80/10)
+
+    v1 = Vec(10, 20, 40, 80)
+    v1 /= [2, 4, 8, 10]
+    assert v1 == Vec(10/2, 20/4, 40/8, 80/10)
+
+    # Length.
+
+    if (Vec != V4i):
+       v = Vec(1, 2, 3, 4)
+       assert equal(v.length(), sqrt(1*1 + 2*2 + 3*3 + 4*4), 10.0*v.baseTypeEpsilon())
+
+    v = Vec(1, 2, 3, 4)
+    assert v.length2() == 1*1 + 2*2 + 3*3 + 4*4
+
+    # Normalizing.
+
+    if (Vec != V4i):
+       v = Vec(1, 2, 3, 4)
+       v.normalize()
+       assert equal(v.length(), 1, v.baseTypeEpsilon())
+
+       v = Vec(1, 2, 3, 4)
+       v.normalizeExc()
+       assert equal(v.length(), 1, v.baseTypeEpsilon())
+       v = Vec(0)
+       try:
+           v.normalizeExc()        # This should raise an exception.
+       except:
+           pass
+       else:
+           assert 0                # We shouldn't get here.
+       
+       v = Vec(1, 2, 3, 4)
+       v.normalizeNonNull()
+       assert equal(v.length(), 1, v.baseTypeEpsilon())
+
+       v = Vec(1, 2, 3, 4)
+       assert equal(v.normalized().length(), 1, v.baseTypeEpsilon())
+
+       v = Vec(1, 2, 3, 4)
+       assert equal(v.normalizedExc().length(), 1, v.baseTypeEpsilon())
+       v = Vec(0)
+       try:
+           v.normalizedExc()  # This should raise an exception.
+       except:
+           pass
+       else:
+           assert 0              # We shouldn't get here.
+       
+       v = Vec(1, 2, 3, 4)
+       assert equal(v.normalizedNonNull().length(), 1, v.baseTypeEpsilon())
+
+    # Projection.
+
+    if (Vec != V4i):
+        s = Vec(0, 0, 0, 2)
+        t = Vec(1, 1, 1, 1)
+        assert t.project(s) == Vec(0, 0, 0, 1)
+
+    # Orthogonal.
+
+    if (Vec != V4i):
+        s = Vec(0, 0, 0, 2)
+        t = Vec(1, 1, 1, 1)
+        o = s.orthogonal(t)
+        assert iszero(o ^ s, s.baseTypeEpsilon())
+
+    # Reflect.
+
+    if (Vec != V4i):
+        s = Vec(1, 1, 1, 1)
+        t = Vec(0, 0, 0, 2)
+        r = s.reflect(t)
+        assert equal(abs(s ^ t), abs(r ^ t), s.baseTypeEpsilon())
+
+    print ("ok")
+
+    return
+
+def testV4 ():
+
+    print ("V4i")
+    testV4x (V4i)
+    print ("V4f")
+    testV4x (V4f)
+    print ("V4d")
+    testV4x (V4d)
+
+testList.append (('testV4',testV4))
+
+
+# -------------------------------------------------------------------------
+# Tests for V4xArray
+
+def testV4xArray (Array, Vec, Arrayx):
+    
+    # Constructors (and element access).
+
+    a = Array (4)
+
+    a[0] = Vec(0)
+    a[1] = Vec(1)
+    a[2] = Vec(2)
+    a[3] = Vec(3)
+
+    assert a[0] == Vec(0)
+    assert a[1] == Vec(1)
+    assert a[2] == Vec(2)
+    assert a[3] == Vec(3)
+
+    a[0].setValue(10,10,10,10)
+    a[1].setValue(11,11,11,11)
+    a[2].setValue(12,12,12,12)
+    a[3].setValue(13,13,13,13)
+
+    assert a[0] == Vec(10)
+    assert a[1] == Vec(11)
+    assert a[2] == Vec(12)
+    assert a[3] == Vec(13)
+
+    # Element setting.
+
+    a = Array(2)
+
+    try:
+        a[-3] = Vec(0)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a[4] = Vec(0)   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        a[1] = "a"         # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    a = Array(2)
+    a[0] = Vec(0)
+    a[1] = Vec(1)
+    
+    b = Array(2)
+    b[0] = Vec(0)
+    b[1] = Vec(1)
+    
+    c = Array(2)
+    c[0] = Vec(10)
+    c[1] = Vec(11)
+
+    # TODO: make equality work correctly.
+    #assert a == b
+    assert a != c
+    
+    # Dot products.
+
+    a = Array(2)
+    a[0] = Vec(1, 2, 3, 4)
+    a[1] = Vec(4, 5, 6, 7)
+
+    b = Array(2)
+    b[0] = Vec(7, 8, 9, 10)
+    b[1] = Vec(10, 11, 12, 13)
+
+    r = a.dot(b)
+    assert r[0] == 1*7 + 2*8 + 3*9 + 4*10
+    assert r[1] == 4*10 + 5*11 + 6*12 + 7*13
+
+    c = Vec(13, 14, 15, 16)
+    r = a.dot(c)
+    assert r[0] == 1*13 + 2*14 + 3*15 + 4*16
+    assert r[1] == 4*13 + 5*14 + 6*15 + 7*16
+
+    d = Array(3)
+    try:
+        a.dot(d)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+    
+    # Addition.
+
+    a = Array(2)
+    a[0] = Vec(1, 2, 3, 4)
+    a[1] = Vec(4, 5, 6, 7)
+
+    b = Array(2)
+    b[0] = Vec(7, 8, 9, 10)
+    b[1] = Vec(10, 11, 12, 13)
+
+    r = a + b
+    assert r[0] == Vec(1+7, 2+8, 3+9, 4+10)
+    assert r[1] == Vec(4+10, 5+11, 6+12, 7+13)
+
+    r = a + Vec(10)
+    assert r[0] == Vec(1+10, 2+10, 3+10, 4+10)
+    assert r[1] == Vec(4+10, 5+10, 6+10, 7+10)
+
+    v = Vec(11)
+    r = v + a 
+    assert r[0] == Vec(11+1, 11+2, 11+3, 11+4)
+    assert r[1] == Vec(11+4, 11+5, 11+6, 11+7)
+
+    a += b
+    assert a[0] == Vec(1+7, 2+8, 3+9, 4+10)
+    assert a[1] == Vec(4+10, 5+11, 6+12, 7+13)
+
+    a[0] = Vec(1, 2, 3, 4)
+    a[1] = Vec(4, 5, 6, 7)
+
+    a += Vec(10)
+    assert a[0] == Vec(1+10, 2+10, 3+10, 4+10)
+    assert a[1] == Vec(4+10, 5+10, 6+10, 7+10)
+
+    c = Array(3)
+
+    try:
+        a + c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a += c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Subtraction.
+
+    a = Array(2)
+    a[0] = Vec(1, 2, 3, 4)
+    a[1] = Vec(4, 5, 6, 7)
+
+    b = Array(2)
+    b[0] = Vec(7, 8, 9, 10)
+    b[1] = Vec(10, 11, 12, 13)
+
+    r = a - b
+    assert r[0] == Vec(1-7, 2-8, 3-9, 4-10)
+    assert r[1] == Vec(4-10, 5-11, 6-12, 7-13)
+
+    r = a - Vec(10)
+    assert r[0] == Vec(1-10, 2-10, 3-10, 4-10)
+    assert r[1] == Vec(4-10, 5-10, 6-10, 7-10)
+
+    v = Vec(11)
+    r = v - a 
+    assert r[0] == Vec(11-1, 11-2, 11-3, 11-4)
+    assert r[1] == Vec(11-4, 11-5, 11-6, 11-7)
+
+    a -= b
+    assert a[0] == Vec(1-7, 2-8, 3-9, 4-10)
+    assert a[1] == Vec(4-10, 5-11, 6-12, 7-13)
+
+    a[0] = Vec(1, 2, 3, 4)
+    a[1] = Vec(4, 5, 6, 7)
+
+    a -= Vec(10)
+    assert a[0] == Vec(1-10, 2-10, 3-10, 4-10)
+    assert a[1] == Vec(4-10, 5-10, 6-10, 7-10)
+
+    c = Array(3)
+
+    try:
+        a - c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a -= c                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Negation.
+
+    a = Array(2)
+    a[0] = Vec(1, 2, 3, 4)
+    a[1] = Vec(4, 5, 6, 7)
+
+    r = -a
+    assert r[0] == Vec(-1, -2, -3, -4)
+    assert r[1] == Vec(-4, -5, -6, -7)
+
+    # Multiplication.
+
+    a = Array(2)
+    a[0] = Vec(1, 2, 3, 4)
+    a[1] = Vec(4, 5, 6, 7)
+
+    r = a * 10
+    assert r[0] == Vec(1, 2, 3, 4) * 10
+    assert r[1] == Vec(4, 5, 6, 7) * 10
+
+    b = Arrayx(2)
+    b[0] = 10
+    b[1] = 11
+
+    r = a * b
+    assert r[0] == Vec(1, 2, 3, 4) * 10
+    assert r[1] == Vec(4, 5, 6, 7) * 11
+    
+    a *= 10
+    assert a[0] == Vec(1, 2, 3, 4) * 10
+    assert a[1] == Vec(4, 5, 6, 7) * 10
+
+    a[0] = Vec(1, 2, 3, 4)
+    a[1] = Vec(4, 5, 6, 7)
+
+    a *= b
+    assert a[0] == Vec(1, 2, 3, 4) * 10
+    assert a[1] == Vec(4, 5, 6, 7) * 11
+
+    a[0] = Vec(1, 2, 3, 4)
+    a[1] = Vec(4, 5, 6, 7)
+
+    b = Array(2)
+    b[0] = Vec(7, 8, 9, 10)
+    b[1] = Vec(10, 11, 12, 13)
+
+    r = a * b
+    assert r[0] == Vec(1*7, 2*8, 3*9, 4*10)
+    assert r[1] == Vec(4*10, 5*11, 6*12, 7*13)
+
+    v = Vec(13, 14, 15, 16)
+
+    r = a * v
+    assert r[0] == Vec(1*13, 2*14, 3*15, 4*16)
+    assert r[1] == Vec(4*13, 5*14, 6*15, 7*16)
+
+    r = v * a
+    assert r[0] == Vec(1*13, 2*14, 3*15, 4*16)
+    assert r[1] == Vec(4*13, 5*14, 6*15, 7*16)
+
+    a *= b
+    assert a[0] == Vec(1*7, 2*8, 3*9, 4*10)
+    assert a[1] == Vec(4*10, 5*11, 6*12, 7*13)
+
+    a[0] = Vec(1, 2, 3, 4)
+    a[1] = Vec(4, 5, 6, 7)
+
+    a *= v
+    assert a[0] == Vec(1*13, 2*14, 3*15, 4*16)
+    assert a[1] == Vec(4*13, 5*14, 6*15, 7*16)
+
+    d = Array(3)
+    try:
+        a * d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a *= d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Division.
+
+    a = Array(2)
+    a[0] = Vec(1.0, 2.0, 3.0, 4.0)
+    a[1] = Vec(4.0, 5.0, 6.0, 7.0)
+
+    r = a / 10
+    assert r[0] == Vec(1.0, 2.0, 3.0, 4.0) / 10
+    assert r[1] == Vec(4.0, 5.0, 6.0, 7.0) / 10
+
+    b = Arrayx(2)
+    b[0] = 10
+    b[1] = 11
+
+    r = a / b
+    assert r[0] == Vec(1.0, 2.0, 3.0, 4.0) / 10
+    assert r[1] == Vec(4.0, 5.0, 6.0, 7.0) / 11
+    
+    a /= 10
+    assert a[0] == Vec(1.0, 2.0, 3.0, 4.0) / 10
+    assert a[1] == Vec(4.0, 5.0, 6.0, 7.0) / 10
+
+    a[0] = Vec(1.0, 2.0, 3.0, 4.0)
+    a[1] = Vec(4.0, 5.0, 6.0, 7.0)
+
+    a /= b
+    assert a[0] == Vec(1.0, 2.0, 3.0, 4.0) / 10
+    assert a[1] == Vec(4.0, 5.0, 6.0, 7.0) / 11
+
+    a[0] = Vec(1.0, 2.0, 3.0, 4.0)
+    a[1] = Vec(4.0, 5.0, 6.0, 7.0)
+
+    b = Array(2)
+    b[0] = Vec(7.0, 8.0, 9.0, 10.0)
+    b[1] = Vec(10.0, 11.0, 12.0, 13.0)
+
+    r = a / b
+    assert r[0] == Vec(1.0/7, 2.0/8, 3.0/9, 4.0/10)
+    assert r[1] == Vec(4.0/10, 5.0/11, 6.0/12, 7.0/13)
+
+    v = Vec(13.0, 14.0, 15.0, 16)
+
+    r = a / v
+    assert r[0] == Vec(1.0/13, 2.0/14, 3.0/15, 4.0/16)
+    assert r[1] == Vec(4.0/13, 5.0/14, 6.0/15, 7.0/16)
+
+    # TODO: Figure out why "v / a" is illegal, even though the
+    # add_arithmetic_math_functions() routine in PyImathFixedArray.h
+    # should make it possible.
+    #r = v / a
+    #assert r[0] == Vec(1.0/13, 2.0/14, 3.0/15)
+    #assert r[1] == Vec(4.0/13, 5.0/14, 6.0/15)
+
+    a /= b
+    assert a[0] == Vec(1.0/7, 2.0/8, 3.0/9, 4.0/10)
+    assert a[1] == Vec(4.0/10, 5.0/11, 6.0/12, 7.0/13)
+
+    a[0] = Vec(1.0, 2.0, 3.0, 4.0)
+    a[1] = Vec(4.0, 5.0, 6.0, 7.0)
+
+    a /= v
+    assert a[0] == Vec(1.0/13, 2.0/14, 3.0/15, 4.0/16)
+    assert a[1] == Vec(4.0/13, 5.0/14, 6.0/15, 7.0/16)
+
+    d = Array(3)
+    try:
+        a / d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    try:
+        a /= d                # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.   
+
+    # Length.
+
+    v0 = Vec(1, 2, 3, 4)
+    v1 = Vec(4, 5, 6, 7)
+
+    a = Array(2)
+    a[0] = v0
+    a[1] = v1
+
+    if (Vec != V4i):
+        l = a.length()
+        assert (l[0] == v0.length())
+        assert (l[1] == v1.length())
+
+    l = a.length2()
+    assert (l[0] == v0.length2())
+    assert (l[1] == v1.length2())
+    
+    # Normalizing.
+
+    if (Vec != V4i):
+
+        a[0] = Vec(1, 2, 3, 4)
+        a[1] = Vec(4, 5, 6, 7)
+
+        r = a.normalized();
+        assert r[0] == Vec(1, 2, 3, 4).normalized()
+        assert r[1] == Vec(4, 5, 6, 7).normalized()
+
+        a.normalize();
+        assert a[0] == Vec(1, 2, 3, 4).normalized()
+        assert a[1] == Vec(4, 5, 6, 7).normalized()
+
+    print ("ok")
+
+    return
+
+def testV4Array ():
+
+    print ("V4iArray")
+    testV4xArray (V4iArray, V4i, IntArray)
+    print ("V4fArray")
+    testV4xArray (V4fArray, V4f, FloatArray)
+    print ("V4dArray")
+    testV4xArray (V4dArray, V4d, DoubleArray)
+
+testList.append (('testV4Array',testV4Array))
+
+def testV4xConversions (Vec):
+
+    # Assignment
+    
+    v1 = Vec(0, 1, 2, 3)
+
+    v2 = V4i (v1)
+    assert v2[0] == 0 and v2[1] == 1 and v2[2] == 2 and v2[3] == 3
+
+    v2 = V4f (v1)
+    assert v2[0] == 0 and v2[1] == 1 and v2[2] == 2 and v2[3] == 3
+
+    v2 = V4d (v1)
+    assert v2[0] == 0 and v2[1] == 1 and v2[2] == 2 and v2[3] == 3
+
+    # The += operator
+
+    v2 = Vec (1, 2, 3, 4)
+    v2 += V4i (v1)
+    assert v2[0] == 1 and v2[1] == 3 and v2[2] == 5 and v2[3] == 7
+    
+    v2 = Vec (1, 2, 3, 4)
+    v2 += V4f (v1)
+    assert v2[0] == 1 and v2[1] == 3 and v2[2] == 5  and v2[3] == 7
+    
+    v2 = Vec (1, 2, 3, 4)
+    v2 += V4d (v1)
+    assert v2[0] == 1 and v2[1] == 3 and v2[2] == 5  and v2[3] == 7
+
+    # The -= operator
+
+    v2 = Vec (1, 2, 3, 4)
+    v2 -= V4i (v1)
+    assert v2[0] == 1 and v2[1] == 1 and v2[2] == 1 and v2[3] == 1
+    
+    v2 = Vec (1, 2, 3, 4)
+    v2 -= V4f (v1)
+    assert v2[0] == 1 and v2[1] == 1 and v2[2] == 1 and v2[3] == 1
+    
+    v2 = Vec (1, 2, 3, 4)
+    v2 -= V4d (v1)
+    assert v2[0] == 1 and v2[1] == 1 and v2[2] == 1 and v2[3] == 1
+
+    # The *= operator
+    
+    v2 = Vec (1, 2, 3, 4)
+    v2 *= V4i (v1)
+    assert v2[0] == 0 and v2[1] == 2 and v2[2] == 6 and v2[3] == 12
+    
+    v2 = Vec (1, 2, 3, 4)
+    v2 *= V4f (v1)
+    assert v2[0] == 0 and v2[1] == 2 and v2[2] == 6 and v2[3] == 12
+    
+    v2 = Vec (1, 2, 3, 4)
+    v2 *= V4d (v1)
+    assert v2[0] == 0 and v2[1] == 2 and v2[2] == 6 and v2[3] == 12
+    
+    print ("ok")
+    return
+
+
+def testV2xV3xConversion (VecA, VecB):
+
+    try:
+        v = VecA();
+        v1 = VecB (v);           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+
+def testVecConversions ():
+
+    print ("V2i")
+    testV2xConversions (V2i)
+    print ("V2f")
+    testV2xConversions (V2f)
+    print ("V2d")
+    testV2xConversions (V2d)
+
+    print ("V3i")
+    testV3xConversions (V3i)
+    print ("V3f")
+    testV3xConversions (V3f)
+    print ("V3d")
+    testV3xConversions (V3d)
+
+    print ("V4i")
+    testV4xConversions (V4i)
+    print ("V4f")
+    testV4xConversions (V4f)
+    print ("V4d")
+    testV4xConversions (V4d)
+
+
+    print ("invalid conversions")
+    # Deliberatly not exhaustive, just representative.
+    testV2xV3xConversion (V2i, V3f)
+    testV2xV3xConversion (V3f, V2d)
+
+    print ("ok")
+    return
+
+
+testList.append (('testVecConversions',testVecConversions))
+
+
+
+# -------------------------------------------------------------------------
+# Tests for Shear6x
+
+def testShear6x (Shear):
+    
+    # Constructors (and element access).
+
+    h = Shear()
+    assert h[0] == 0 and h[1] == 0 and h[2] == 0 and \
+           h[3] == 0 and h[4] == 0 and h[5] == 0
+
+    h = Shear(1)
+    assert h[0] == 1 and h[1] == 1 and h[2] == 1 and \
+           h[3] == 1 and h[4] == 1 and h[5] == 1
+
+    h = Shear(0, 1, 2)
+    assert h[0] == 0 and h[1] == 1 and h[2] == 2 and \
+           h[3] == 0 and h[4] == 0 and h[5] == 0
+
+    h = Shear((0, 1, 2))
+    assert h[0] == 0 and h[1] == 1 and h[2] == 2 and \
+           h[3] == 0 and h[4] == 0 and h[5] == 0
+
+    h = Shear(0, 1, 2, 3, 4, 5)
+    assert h[0] == 0 and h[1] == 1 and h[2] == 2 and \
+           h[3] == 3 and h[4] == 4 and h[5] == 5
+
+    h = Shear((0, 1, 2, 3, 4, 5))
+    assert h[0] == 0 and h[1] == 1 and h[2] == 2 and \
+           h[3] == 3 and h[4] == 4 and h[5] == 5
+
+    h = Shear()
+    h.setValue(0, 1, 2, 3, 4, 5) 
+    assert h[0] == 0 and h[1] == 1 and h[2] == 2 and \
+           h[3] == 3 and h[4] == 4 and h[5] == 5
+
+    # Repr.
+
+    h = Shear(1/9., 2/9., 3/9., 4/9., 5/9., 6/9.)
+    assert h == eval(repr(h))
+
+    # Sequence length.
+
+    h = Shear()
+    assert len(h) == 6
+
+    # Element setting.
+
+    h = Shear()
+    h[0] = 10
+    h[1] = 11
+    h[2] = 12
+    h[3] = 13
+    h[4] = 14
+    h[5] = 15
+    assert h[0] == 10 and h[1] == 11 and h[2] == 12 and \
+           h[3] == 13 and h[4] == 14 and h[5] == 15
+
+    try:
+        h[-7] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        h[6] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        h[1] = "a"           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    h1 = Shear(1)
+    
+    h2 = h1
+    assert h2[0] == 1 and h2[1] == 1 and h2[2] == 1 and \
+           h2[3] == 1 and h2[4] == 1 and h2[5] == 1
+    h1[0] = 2
+    assert h2[0] == 2 and h2[1] == 1 and h2[2] == 1 and \
+           h2[3] == 1 and h2[4] == 1 and h2[5] == 1
+    
+    # Comparison operators.
+
+    h1 = Shear(20, 20, 20, 20, 20, 0)
+    h2 = Shear(20, 20, 20, 20, 20, 0)
+    h3 = Shear(20, 20, 20, 20, 21, 0)
+
+    assert h1 == h2
+    assert h1 != h3
+    assert not (h1 < h2)
+    assert h1 < h3
+    assert h1 <= h2
+    assert h1 <= h3
+    assert not (h3 <= h1)
+    assert not (h2 > h1)
+    assert h3 > h1
+    assert h2 >= h1
+    assert h3 >= h1
+    assert not (h1 >= h3)
+    
+    # Epsilon equality.
+
+    e = 0.005
+    h1 = Shear(1)
+    h2 = Shear(1 + e)
+
+    assert h1.equalWithAbsError(h2, e)
+    assert h2.equalWithAbsError(h1, e)
+
+    e = 0.003
+    h1 = Shear(10)
+    h2 = Shear(10 + 10 * e)
+
+    assert h1.equalWithRelError(h2, e)
+    assert h2.equalWithRelError(h1, e)
+
+    # Addition.
+
+    h1 = Shear(10, 20, 30, -10, -20, -30)
+    h2 = Shear(30, 40, 50, -30, -40, -50)
+
+    assert h1 + h2 == Shear(40, 60, 80, -40, -60, -80)
+    assert h2 + h1 == h1 + h2
+    assert h1 + 1 == Shear(11, 21, 31, -9, -19, -29)
+    assert 1 + h1 == h1 + 1
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert h1 + (1, 2, 3, 4, 5, 6) == Shear(11, 22, 33, -6, -15, -24)
+    assert (1, 2, 3, 4, 5, 6) + h1 == h1 + (1, 2, 3, 4, 5, 6)
+
+    # Subtraction and negation.
+
+    h1 = Shear(10, 20, 30, -10, -20, -30)
+    h2 = Shear(30, 40, 50, -30, -40, -50)
+
+    assert h2 - h1 == Shear(20, 20, 20, -20, -20, -20)
+    assert h1 - 1 == Shear(9, 19, 29, -11, -21, -31)
+    assert 1 - h1 == - (h1 - 1)
+    
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert h1 - (1, 2, 3, 4, 5, 6) == Shear(9, 18, 27, -14, -25, -36)
+    assert (1, 2, 3, 4, 5, 6) - h1 == - (h1 - (1, 2, 3, 4, 5, 6))
+
+    assert h1.negate() == Shear(-10, -20, -30, 10, 20, 30)
+
+    # Multiplication.
+
+    h1 = Shear(1, 2, 3, -1, -2, -3)
+    h2 = Shear(3, 4, 5, -3, -4, -5)
+    
+    assert h1 * h2 == Shear(3, 8, 15, 3, 8, 15)
+    assert h2 * h1 == h1 * h2
+    assert 2 * h1 == Shear(2, 4, 6, -2, -4, -6)
+    assert h1 * 2 == 2 * h1
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert h1 * (1, 2, 3, 4, 5, 6) == Shear(1, 4, 9, -4, -10, -18)
+    assert (1, 2, 3, 4, 5, 6) * h1 == h1 * (1, 2, 3, 4, 5, 6)
+
+    # Division.
+
+    h1 = Shear(10, 20, 40, -10, -20, -40)
+    h2 = Shear(2, 4, 8, -2, -4, -8)
+    
+    assert h1 / h2 == Shear(10/2, 20/4, 40/8, -10/-2, -20/-4, -40/-8)
+    assert h1 / 2 == Shear(10/2, 20/2, 40/2, -10/2, -20/2, -40/2)
+    assert Shear(40) / h1 == Shear(40/10, 40/20, 40/40, 40/-10, 40/-20, 40/-40)
+
+    # (with the switch to python2, we now allow ops between vectors and tuples)
+    assert h1 / (1, 2, 4, -1, -2, -4) == Shear(10, 10, 10, 10, 10, 10)
+    assert Shear(50, 40, 80, -50, -40, -80) / h1 == Shear(5, 2, 2, 5, 2, 2)
+
+    print ("ok")
+
+    return
+
+def testShear6 ():
+
+    print ("Shear6f")
+    testShear6x (Shear6f)
+    print ("Shear6d")
+    testShear6x (Shear6d)
+
+testList.append (('testShear6',testShear6))
+
+
+# -------------------------------------------------------------------------
+# Tests for Shear --> Shear conversions
+
+def testShearV3xConversions (Vec):
+
+    v = Vec (0, 1, 2)
+
+    h = Shear6f (v)
+    assert h[0] == 0 and h[1] == 1 and h[2] == 2 and \
+           h[3] == 0 and h[4] == 0 and h[5] == 0
+
+    h = Shear6d (v)
+    assert h[0] == 0 and h[1] == 1 and h[2] == 2 and \
+           h[3] == 0 and h[4] == 0 and h[5] == 0
+
+    print ("ok")
+    return
+
+
+def testShear6xConversions (Shear):
+
+    h1 = Shear(0, 1, 2, 3, 4, 5)
+
+    h2 = Shear6f (h1)
+    assert h2[0] == 0 and h2[1] == 1 and h2[2] == 2 and \
+           h2[3] == 3 and h2[4] == 4 and h2[5] == 5
+
+    h2 = Shear6d (h1)
+    assert h2[0] == 0 and h2[1] == 1 and h2[2] == 2 and \
+           h2[3] == 3 and h2[4] == 4 and h2[5] == 5
+
+    print ("ok")
+    return
+
+
+def testShearConversions ():
+
+    print ("V3f")
+    testShearV3xConversions (V3f)
+    print ("V3d")
+    testShearV3xConversions (V3d)
+
+    print ("Shear6f")
+    testShear6xConversions (Shear6f)
+    print ("Shear6d")
+    testShear6xConversions (Shear6d)
+
+    print ("ok")
+    return
+
+
+testList.append (('testShearConversions',testShearConversions))
+
+
+# -------------------------------------------------------------------------
+# Tests for M22x
+
+def testM22x (Mat, Vec):
+    
+    # Constructors (and element access).
+
+    m = Mat()
+    assert m[0][0] == 1 and m[0][1] == 0 and \
+           m[1][0] == 0 and m[1][1] == 1
+
+    m = Mat(1)
+    assert m[0][0] == 1 and m[0][1] == 1 and \
+           m[1][0] == 1 and m[1][1] == 1
+
+    m = Mat((0, 1), (2, 3))
+    assert m[0][0] == 0 and m[0][1] == 1 and \
+           m[1][0] == 2 and m[1][1] == 3
+
+
+    m = Mat(0, 1, 2, 3)
+    assert m[0][0] == 0 and m[0][1] == 1 and \
+           m[1][0] == 2 and m[1][1] == 3
+
+    # Repr.
+
+    m = Mat(0/9., 1/9., 2/9., 3/9.)
+    assert m == eval(repr(m))
+
+    # Sequence length.
+
+    m = Mat()
+    assert len(m) == 2
+
+    # Element setting.
+
+    m = Mat()
+    m[0][0] = 10
+    m[1][1] = 11
+    assert m[0][0] == 10 and m[1][1] == 11
+
+    try:
+        m[-4][0] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[3][0] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        m[0][-4] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[0][3] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[1] = (1,2,3)           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    m1 = Mat(1)
+    
+    m2 = m1
+    assert m2[0][0] == 1 and m2[0][1] == 1 and \
+           m2[1][0] == 1 and m2[1][1] == 1
+
+    m1[0][0] = 2
+    assert m2[0][0] == 2 and m2[0][1] == 1 and \
+           m2[1][0] == 1 and m2[1][1] == 1
+
+    # Identity.
+
+    m = Mat(2)
+
+    m.makeIdentity()
+    assert m[0][0] == 1 and m[0][1] == 0 and \
+           m[1][0] == 0 and m[1][1] == 1
+           
+    # Comparison operators.
+
+    m1 = Mat()
+    m1[1][1] = 2
+    m2 = Mat()
+    m2[1][1] = 2
+    m3 = Mat()
+    m3[1][1] = 3
+
+    assert m1 == m2
+    assert m1 != m3
+    assert not (m1 < m2)
+    assert m1 < m3
+    assert m1 <= m2
+    assert m1 <= m3
+    assert not (m3 <= m1)
+    assert not (m2 > m1)
+    assert m3 > m1
+    assert m2 >= m1
+    assert m3 >= m1
+    assert not (m1 >= m3)
+
+    # Epsilon equality.
+
+    e = 0.005
+    m1 = Mat(1)
+    m2 = Mat(1 + e)
+
+    assert m1.equalWithAbsError(m2, e)
+    assert m2.equalWithAbsError(m1, e)
+
+    e = 0.003
+    m1 = Mat(10)
+    m2 = Mat(10 + 10 * e)
+
+    assert m1.equalWithRelError(m2, e)
+    assert m2.equalWithRelError(m1, e)
+
+    # Addition.
+
+    m1 = Mat(1)
+    m2 = Mat(2)
+
+    assert m1 + m2 == Mat(3)
+    assert m2 + m1 == m1 + m2
+    assert m1 + 1 == Mat(2)
+    assert 1 + m1 == m1 + 1
+
+    # Subtraction and negation.
+
+    m1 = Mat(2)
+    m2 = Mat(3)
+
+    assert m2 - m1 == Mat(1)
+    assert m1 - 1 == Mat(1)
+    assert 1 - m1 == - (m1 - 1)
+    assert m1.negate() == Mat(-2)
+
+    # Multiplication.
+
+    m1 = Mat(1)
+    # (Scales by (3, 4).)
+    m2 = Mat()
+    m2[0][0] = 3
+    m2[1][1] = 4
+    v = Vec(1, 2)
+
+    assert m1 * 2 == Mat(2)
+    assert m1 * 2 == 2 * m1
+    assert m1 * m2 == Mat((3,4),(3,4))
+    assert v * m2 == Vec(3, 8)
+    try:
+        m1 * v                   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    m2f = M22f()
+    m2f[0][0] = 1
+    m2f[1][1] = 2
+    v = Vec(1, 2)
+    v *= m2f
+    assert v == Vec(1, 4)
+
+    m2d = M22d()
+    m2d[0][0] = 1
+    m2d[1][1] = 2
+    v = Vec(1, 2)
+    v *= m2d
+    assert v == Vec(1, 4)
+
+    # (Rotates by 45 degrees.)
+    m3 = Mat()
+    m3[0][0] = 0
+    m3[0][1] = 1
+    m3[1][0] = -1
+    m3[1][1] = 0    
+    m4 = m3 * Mat()
+    v1 = Vec(1, 0)
+    v2 = Vec()
+
+    m4.multDirMatrix(v1,v2)
+    assert v2.equalWithAbsError((0, 1), v2.baseTypeEpsilon())
+    v2 = m4.multDirMatrix(v1)
+    assert v2.equalWithAbsError((0, 1), v2.baseTypeEpsilon())
+    v1a = V2fArray(1)
+    v1a[:] = V2f(v1)
+    v2a = m4.multDirMatrix(v1a)
+    assert v2a[0].equalWithAbsError((0, 1), v2a[0].baseTypeEpsilon())
+    v1a = V2dArray(1)
+    v1a[:] = V2d(v1)
+    v2a = m4.multDirMatrix(v1a)
+    assert v2a[0].equalWithAbsError((0, 1), v2a[0].baseTypeEpsilon())
+    
+    # Division.
+
+    m = Mat(4)
+
+    assert m / 2 == Mat(2)
+    try:
+        4 / m                   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Transpose.
+
+    m = Mat(1, 2, 3, 4)
+
+    assert m.transpose() == Mat(1, 3, 2, 4)
+    m.transposed()
+    assert m == Mat(1, 3, 2, 4)
+    
+    # Invert.
+
+    m1 = Mat()
+    m1[0][0] = 1
+    m1[1][1] = 2
+    
+    m1I = m1.inverse()
+    assert m1 * m1I == Mat()
+
+    m2 = Mat(m1)
+    m2.invert()
+    assert m1 * m2 == Mat()
+
+    # Rotation (in radians).
+
+    v1 = Vec(1, 0)
+
+    m = Mat()
+    m.setRotation(-pi / 2)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((0, -1), v2.baseTypeEpsilon())
+
+    m.rotate(-pi / 2)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((-1, 0), v2.baseTypeEpsilon())
+
+    # Scaling.
+
+    v1 = Vec(1, 2)
+
+    m = Mat()
+    m.setScale(2)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((2, 4), v2.baseTypeEpsilon())
+
+    m.scale(3)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((6, 12), v2.baseTypeEpsilon())
+
+    m = Mat()
+    m.setScale((1, 2))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((1, 4), v2.baseTypeEpsilon())
+
+    m.scale((2, 3))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((2, 12), v2.baseTypeEpsilon())
+
+    # It is not essential for correctness that the following exceptions
+    # occur.  Instead, these tests merely document the way the Python
+    # wrappings currently work.
+    try:
+        m.setScale(1, 2)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0                   # We shouldn't get here.
+
+    m = Mat()
+    a = pi/4
+    # (Rotation by -a around Z axis.)
+    m[0][0] = cos(a)
+    m[0][1] = -sin(a)
+    m[1][0] = sin(a)
+    m[1][1] = cos(a)
+    v = Vec()
+
+    m.extractEuler(v)
+    assert v.equalWithAbsError((-a, 0), v.baseTypeEpsilon())
+
+    # Determinants (by building a random singular value decomposition)
+
+    u = Mat()
+    v = Mat()
+    s = Mat()
+
+    u.setRotation( random.random() )
+    v.setRotation( random.random() )
+    s[0][0] = random.random()
+    s[1][1] = random.random()
+
+    c = u * s * v.transpose()
+    assert abs(c.determinant() - s[0][0]*s[1][1]) <= u.baseTypeEpsilon()
+
+
+    print ("ok")
+    return
+
+def testM22 ():
+
+    print ("M22f")
+    testM22x (M22f, V2f)
+    print ("M22d")
+    testM22x (M22d, V2d)
+
+testList.append (('testM22',testM22))
+
+
+# -------------------------------------------------------------------------
+# Tests for M33x
+
+def testM33x (Mat, Vec, Vec3):
+    
+    # Constructors (and element access).
+
+    m = Mat()
+    assert m[0][0] == 1 and m[0][1] == 0 and m[0][2] == 0 and \
+           m[1][0] == 0 and m[1][1] == 1 and m[1][2] == 0 and \
+           m[2][0] == 0 and m[2][1] == 0 and m[2][2] == 1
+
+    m = Mat(1)
+    assert m[0][0] == 1 and m[0][1] == 1 and m[0][2] == 1 and \
+           m[1][0] == 1 and m[1][1] == 1 and m[1][2] == 1 and \
+           m[2][0] == 1 and m[2][1] == 1 and m[2][2] == 1
+
+    m = Mat((0, 1, 2), (3, 4, 5), (6, 7, 8))
+    assert m[0][0] == 0 and m[0][1] == 1 and m[0][2] == 2 and \
+           m[1][0] == 3 and m[1][1] == 4 and m[1][2] == 5 and \
+           m[2][0] == 6 and m[2][1] == 7 and m[2][2] == 8
+
+
+    m = Mat(0, 1, 2, 3, 4, 5, 6, 7, 8)
+    assert m[0][0] == 0 and m[0][1] == 1 and m[0][2] == 2 and \
+           m[1][0] == 3 and m[1][1] == 4 and m[1][2] == 5 and \
+           m[2][0] == 6 and m[2][1] == 7 and m[2][2] == 8
+
+    # Repr.
+
+    m = Mat(0/9., 1/9., 2/9., 3/9., 4/9., 5/9., 6/9., 7/9., 8/9.)
+    assert m == eval(repr(m))
+
+    # Sequence length.
+
+    m = Mat()
+    assert len(m) == 3
+
+    # Element setting.
+
+    m = Mat()
+    m[0][0] = 10
+    m[1][2] = 11
+    assert m[0][0] == 10 and m[1][2] == 11
+
+    try:
+        m[-4][0] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[3][0] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        m[0][-4] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[0][3] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[1] = (1,2,3)           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    m1 = Mat(1)
+    
+    m2 = m1
+    assert m2[0][0] == 1 and m2[0][1] == 1 and m2[0][2] == 1 and \
+           m2[1][0] == 1 and m2[1][1] == 1 and m2[1][2] == 1 and \
+           m2[2][0] == 1 and m2[2][1] == 1 and m2[2][2] == 1
+    m1[0][0] = 2
+    assert m2[0][0] == 2 and m2[0][1] == 1 and m2[0][2] == 1 and \
+           m2[1][0] == 1 and m2[1][1] == 1 and m2[1][2] == 1 and \
+           m2[2][0] == 1 and m2[2][1] == 1 and m2[2][2] == 1
+    
+    # Identity.
+
+    m = Mat(2)
+
+    m.makeIdentity()
+    assert m[0][0] == 1 and m[0][1] == 0 and m[0][2] == 0 and \
+           m[1][0] == 0 and m[1][1] == 1 and m[1][2] == 0 and \
+           m[2][0] == 0 and m[2][1] == 0 and m[2][2] == 1
+
+    # Comparison operators.
+
+    m1 = Mat()
+    m1[1][1] = 2
+    m2 = Mat()
+    m2[1][1] = 2
+    m3 = Mat()
+    m3[1][1] = 3
+
+    assert m1 == m2
+    assert m1 != m3
+    assert not (m1 < m2)
+    assert m1 < m3
+    assert m1 <= m2
+    assert m1 <= m3
+    assert not (m3 <= m1)
+    assert not (m2 > m1)
+    assert m3 > m1
+    assert m2 >= m1
+    assert m3 >= m1
+    assert not (m1 >= m3)
+
+    # Epsilon equality.
+
+    e = 0.005
+    m1 = Mat(1)
+    m2 = Mat(1 + e)
+
+    assert m1.equalWithAbsError(m2, e)
+    assert m2.equalWithAbsError(m1, e)
+
+    e = 0.003
+    m1 = Mat(10)
+    m2 = Mat(10 + 10 * e)
+
+    assert m1.equalWithRelError(m2, e)
+    assert m2.equalWithRelError(m1, e)
+
+    # Addition.
+
+    m1 = Mat(1)
+    m2 = Mat(2)
+
+    assert m1 + m2 == Mat(3)
+    assert m2 + m1 == m1 + m2
+    assert m1 + 1 == Mat(2)
+    assert 1 + m1 == m1 + 1
+
+    # Subtraction and negation.
+
+    m1 = Mat(2)
+    m2 = Mat(3)
+
+    assert m2 - m1 == Mat(1)
+    assert m1 - 1 == Mat(1)
+    assert 1 - m1 == - (m1 - 1)
+    assert m1.negate() == Mat(-2)
+
+    # Multiplication.
+
+    m1 = Mat(1)
+    # (Translates by (1,2).)
+    m2 = Mat()
+    m2[2][0] = 1
+    m2[2][1] = 2
+    # (Scales by (3, 4).)
+    m3 = Mat()
+    m3[0][0] = 3
+    m3[1][1] = 4
+    v = Vec(1, 2)
+
+    assert m1 * 2 == Mat(2)
+    assert m1 * 2 == 2 * m1
+    assert m2 * m3 == Mat((3,0,0),(0,4,0),(3,8,1))
+    assert m3 * m2 == Mat((3,0,0),(0,4,0),(1,2,1))
+    assert v * m2 == Vec(2, 4)
+    try:
+        m1 * v                   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    m2f = M33f()
+    m2f[2][0] = 1
+    m2f[2][1] = 2
+    v = Vec(1, 2)
+    v *= m2f
+    assert v == Vec(2, 4)
+
+    m2d = M33d()
+    m2d[2][0] = 1
+    m2d[2][1] = 2
+    v = Vec(1, 2)
+    v *= m2d
+    assert v == Vec(2, 4)
+
+    # (Rotates by 45 degrees, then translates by (1,2).)
+    m3 = Mat()
+    m3[0][0] = 0
+    m3[0][1] = 1
+    m3[1][0] = -1
+    m3[1][1] = 0    
+    m4 = m3 * m2
+    v1 = Vec(1, 0)
+    v2 = Vec()
+    
+    m4.multVecMatrix(v1,v2)
+    assert v2.equalWithAbsError((1, 3), v2.baseTypeEpsilon())
+    v2 = m4.multVecMatrix(v1)
+    assert v2.equalWithAbsError((1, 3), v2.baseTypeEpsilon())
+    v1a = V2fArray(1)
+    v1a[:] = V2f(v1)
+    v2a = m4.multVecMatrix(v1a)
+    assert v2a[0].equalWithAbsError((1, 3), v2a[0].baseTypeEpsilon())
+    v1a = V2dArray(1)
+    v1a[:] = V2d(v1)
+    v2a = m4.multVecMatrix(v1a)
+    assert v2a[0].equalWithAbsError((1, 3), v2a[0].baseTypeEpsilon())
+    
+
+    m4.multDirMatrix(v1,v2)
+    assert v2.equalWithAbsError((0, 1), v2.baseTypeEpsilon())
+    v2 = m4.multDirMatrix(v1)
+    assert v2.equalWithAbsError((0, 1), v2.baseTypeEpsilon())
+    v1a = V2fArray(1)
+    v1a[:] = V2f(v1)
+    v2a = m4.multDirMatrix(v1a)
+    assert v2a[0].equalWithAbsError((0, 1), v2a[0].baseTypeEpsilon())
+    v1a = V2dArray(1)
+    v1a[:] = V2d(v1)
+    v2a = m4.multDirMatrix(v1a)
+    assert v2a[0].equalWithAbsError((0, 1), v2a[0].baseTypeEpsilon())
+    
+    # Division.
+
+    m = Mat(4)
+
+    assert m / 2 == Mat(2)
+    try:
+        4 / m                   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Transpose.
+
+    m = Mat(1, 2, 3, 4, 5, 6, 7, 8, 9)
+
+    assert m.transpose() == Mat(1, 4, 7, 2, 5, 8, 3, 6, 9)
+    m.transposed()
+    assert m == Mat(1, 4, 7, 2, 5, 8, 3, 6, 9)
+    
+    # Invert.
+
+    # (Translates by (1,2).)
+    m1 = Mat()
+    m1[2][0] = 1
+    m1[2][1] = 2
+    
+    m1I = m1.inverse()
+    assert m1 * m1I == Mat()
+    m1I = m1.gjInverse()
+    assert m1 * m1I == Mat()
+
+    m2 = Mat(m1)
+    m2.invert()
+    assert m1 * m2 == Mat()
+    m2 = Mat(m1)
+    m2.gjInvert()
+    assert m1 * m2 == Mat()
+
+    # Rotation (in radians).
+
+    v1 = Vec(1, 0)
+
+    m = Mat()
+    m.setRotation(-pi / 2)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((0, -1), v2.baseTypeEpsilon())
+
+    m.rotate(-pi / 2)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((-1, 0), v2.baseTypeEpsilon())
+
+    # Scaling.
+
+    v1 = Vec(1, 2)
+
+    m = Mat()
+    m.setScale(2)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((2, 4), v2.baseTypeEpsilon())
+
+    m.scale(3)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((6, 12), v2.baseTypeEpsilon())
+
+    m = Mat()
+    m.setScale((1, 2))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((1, 4), v2.baseTypeEpsilon())
+
+    m.scale((2, 3))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((2, 12), v2.baseTypeEpsilon())
+
+    # It is not essential for correctness that the following exceptions
+    # occur.  Instead, these tests merely document the way the Python
+    # wrappings currently work.
+    try:
+        m.setScale(1, 2)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0                   # We shouldn't get here.
+
+    # Shearing.
+
+    v1 = Vec(1, 2)
+
+    m = Mat()
+    m.setShear(2)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((5, 2), v2.baseTypeEpsilon())
+
+    m.shear(3)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((11, 2), v2.baseTypeEpsilon())
+
+    m = Mat()
+    m.setShear((2, 1))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((5, 3), v2.baseTypeEpsilon())
+
+    m.shear((3, 2))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((15, 11), v2.baseTypeEpsilon())
+
+    m = Mat()
+    m.setShear((1, 2))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((3, 4), v2.baseTypeEpsilon())
+
+    m.shear((2, 3))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((10, 15), v2.baseTypeEpsilon())
+
+    # It is not essential for correctness that the following exceptions
+    # occur.  Instead, these tests merely document the way the Python
+    # wrappings currently work.
+    try:
+        m.setShear(1, 2)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0                   # We shouldn't get here.
+
+    # Translation.
+
+    v1 = Vec(1, 0)
+
+    m = Mat()
+    m.setTranslation((3, 2))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((4, 2), v2.baseTypeEpsilon())
+
+    m.translate((1, 2))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((5, 4), v2.baseTypeEpsilon())
+
+    v3 = m.translation()
+    assert v3.equalWithAbsError((4, 4), v2.baseTypeEpsilon())
+
+    # Extract scaling.
+
+    m = Mat()
+    s = Vec(4, 5)
+    m.translate((1, 2))
+    m.shear(7)
+    m.scale(s)
+
+    sM = Vec()
+    m.extractScaling(sM)
+    assert sM.equalWithAbsError(s, s.baseTypeEpsilon())
+
+    # Sans scaling / Remove scaling.
+
+    m1 = Mat()
+    m1.translate((1, 2))
+    m1.shear(7)
+    m1.scale((4, 5))
+
+    m2 = m1.sansScaling()
+    assert m2[0][0] == 1 and m2[1][1] == 1 and \
+           abs (m2[1][0] - 7) <= 4 * m2.baseTypeEpsilon () and \
+           abs (m2[0][1])     <= 4 * m2.baseTypeEpsilon () and \
+           m2[2][0] == 1 and m2[2][1] == 2 
+
+    m1 = Mat()
+    m1.translate((1, 2))
+    m1.shear(7)
+    m1.scale((0, 0))
+
+    try:
+        m2 = m1.sansScaling()  # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0               # We shouldn't get here.   
+
+    m1 = Mat()
+    m1.translate((1, 2))
+    m1.shear(7)
+    m2 = Mat(m1)
+    m1.scale((4, 5))
+
+    r = m1.removeScaling()
+    assert r == 1 and m1.equalWithAbsError(m2, 4 * m1.baseTypeEpsilon())
+
+    m = Mat()
+    m.translate((1, 2))
+    m.shear(7)
+    m.scale((0, 0))
+
+    try:
+        r = m.removeScaling()  # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0               # We shouldn't get here.   
+
+    m = Mat()
+    m.translate((1, 2))
+    m.shear(7)
+    m.scale((0, 0))
+
+    r = m.removeScaling(0)
+    assert r == 0
+
+    # Sans scaling and shear / Remove scaling and shear.
+
+    m1 = Mat()
+    m1.translate((1, 2))
+    m1.shear(7)
+    m1.scale((4, 5))
+
+    m2 = m1.sansScalingAndShear()
+    assert m2[0][0] == 1 and m2[1][1] == 1 and \
+           m2[1][0] == 0 and m2[0][1] == 0 and \
+           m2[2][0] == 1 and m2[2][1] == 2 
+
+    m1 = Mat()
+    m1.translate((1, 2))
+    m1.shear(7)
+    m1.scale((0, 0))
+
+    try:
+        m2 = m1.sansScalingAndShear()  # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0               # We shouldn't get here.   
+
+    m1 = Mat()
+    m1.translate((1, 2))
+    m2 = Mat(m1)
+    m1.shear(7)
+    m1.scale((4, 5))
+
+    r = m1.removeScalingAndShear()
+    assert r == 1 and m1.equalWithAbsError(m2, m1.baseTypeEpsilon())
+
+    m = Mat()
+    m.translate((1, 2))
+    m.scale((0, 0))
+
+    try:
+        r = m.removeScalingAndShear()  # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0               # We shouldn't get here.   
+
+    m = Mat()
+    m.translate((1, 2))
+    m.shear(7)
+    m.scale((0, 0))
+
+    r = m.removeScalingAndShear(0)
+    assert r == 0
+
+    # Extract and remove scaling and shear.
+
+    m = Mat()
+    s = Vec(4, 5)
+    h = Vec(7, 0)
+    m.translate((1, 2))
+    m2 = Mat(m)
+    m.shear(h)
+    m.scale(s)
+
+    sM = Vec()
+    hM = Vec()
+    m.extractScalingAndShear(sM, hM)
+    assert sM.equalWithAbsError(s, s.baseTypeEpsilon())
+    assert hM.equalWithAbsError(h, 4 * h.baseTypeEpsilon())
+
+    sM = Vec()
+    hM = Vec()
+    m.extractAndRemoveScalingAndShear(sM, hM)
+    assert sM.equalWithAbsError(s, s.baseTypeEpsilon())
+    assert hM.equalWithAbsError(h, 4 * h.baseTypeEpsilon())
+    assert m2.equalWithAbsError(m, m.baseTypeEpsilon())
+
+    # Extract Euler.
+
+    m = Mat()
+    a = pi/4
+    # (Rotation by -a around Z axis.)
+    m[0][0] = cos(a)
+    m[0][1] = -sin(a)
+    m[1][0] = sin(a)
+    m[1][1] = cos(a)
+    v = Vec()
+
+    m.extractEuler(v)
+    assert v.equalWithAbsError((-a, 0), v.baseTypeEpsilon())
+
+    # Extract scale, shear, rotation, translation.
+
+    s = Vec(1, 2)
+    h = Vec(0.5, 0)
+    a = pi/4
+    t = Vec(4, 5)
+
+    mS = Mat()
+    mS.scale(s)
+    mH = Mat()
+    # (Shear by XY, XZ, YZ shear factors.)
+    mH.shear(h)
+    mR = Mat()
+    # (Rotation by -a around Z axis.)
+    mR[0][0] = cos(a)
+    mR[0][1] = -sin(a)
+    mR[1][0] = sin(a)
+    mR[1][1] = cos(a)
+    mT = Mat()
+    mT.translate(t)
+    m = mS * mH * mR * mT
+
+    sInq = Vec()
+    hInq = Vec()
+    rInq = Vec()
+    tInq = Vec()
+
+    b = m.extractSHRT(sInq, hInq, rInq, tInq)
+
+    assert sInq.equalWithAbsError(s, 2 * sInq.baseTypeEpsilon())
+    assert hInq.equalWithAbsError(h, hInq.baseTypeEpsilon())
+    assert rInq.equalWithAbsError((-a, 0), 2 * rInq.baseTypeEpsilon())
+    assert tInq.equalWithAbsError(t, tInq.baseTypeEpsilon())
+
+    # Matrix minors
+
+    a = Mat(1,2,3,4,5,6,7,8,9)
+    assert a.minorOf(0,0) == a.fastMinor(1,2,1,2)
+    assert a.minorOf(0,1) == a.fastMinor(1,2,0,2)
+    assert a.minorOf(0,2) == a.fastMinor(1,2,0,1)
+    assert a.minorOf(1,0) == a.fastMinor(0,2,1,2)
+    assert a.minorOf(1,1) == a.fastMinor(0,2,0,2)
+    assert a.minorOf(1,2) == a.fastMinor(0,2,0,1)
+    assert a.minorOf(2,0) == a.fastMinor(0,1,1,2)
+    assert a.minorOf(2,1) == a.fastMinor(0,1,0,2)
+    assert a.minorOf(2,2) == a.fastMinor(0,1,0,1)
+
+    # Determinants (by building a random singular value decomposition)
+
+    u = Mat()
+    v = Mat()
+    s = Mat()
+
+    u.setRotation( random.random() )
+    v.setRotation( random.random() )
+    s[0][0] = random.random()
+    s[1][1] = random.random()
+    s[2][2] = random.random()
+
+    c = u * s * v.transpose()
+    assert abs(c.determinant() - s[0][0]*s[1][1]*s[2][2]) <= u.baseTypeEpsilon()
+
+    # Outer product of two 3D vectors
+
+    a = Vec3(1,2,3)
+    b = Vec3(4,5,6)
+    p = Mat()
+
+    p.outerProduct(a,b)
+    for i in range(3):
+        for j in range(3):
+            assert p[i][j] == a[i]*b[j]
+
+    print ("ok")
+    return
+
+def testM33 ():
+
+    print ("M33f")
+    testM33x (M33f, V2f, V3f)
+    print ("M33d")
+    testM33x (M33d, V2d, V3d)
+
+testList.append (('testM33',testM33))
+
+
+# -------------------------------------------------------------------------
+# Tests for M44x
+
+def testM44x (Mat, Vec):
+    
+    # Constructors (and element access).
+
+    m = Mat()
+    assert \
+      m[0][0] == 1 and m[0][1] == 0 and m[0][2] == 0 and m[0][3] == 0 and \
+      m[1][0] == 0 and m[1][1] == 1 and m[1][2] == 0 and m[1][3] == 0 and \
+      m[2][0] == 0 and m[2][1] == 0 and m[2][2] == 1 and m[2][3] == 0 and \
+      m[3][0] == 0 and m[3][1] == 0 and m[3][2] == 0 and m[3][3] == 1
+
+    m = Mat(1)
+    assert \
+      m[0][0] == 1 and m[0][1] == 1 and m[0][2] == 1 and m[0][3] == 1 and \
+      m[1][0] == 1 and m[1][1] == 1 and m[1][2] == 1 and m[1][3] == 1 and \
+      m[2][0] == 1 and m[2][1] == 1 and m[2][2] == 1 and m[2][3] == 1 and \
+      m[3][0] == 1 and m[3][1] == 1 and m[3][2] == 1 and m[3][3] == 1
+
+    m = Mat((0,1,2,3), (4,5,6,7), (8,9,10,11), (12,13,14,15))
+    assert \
+      m[0][0] == 0 and m[0][1] == 1 and m[0][2] == 2 and m[0][3] == 3 and \
+      m[1][0] == 4 and m[1][1] == 5 and m[1][2] == 6 and m[1][3] == 7 and \
+      m[2][0] == 8 and m[2][1] == 9 and m[2][2] ==10 and m[2][3] ==11 and \
+      m[3][0] ==12 and m[3][1] ==13 and m[3][2] ==14 and m[3][3] ==15
+
+    # Repr.
+
+    m = Mat((0/9.,1/9.,2/9.,3/9.),
+            (4/9.,5/9.,6/9.,7/9.),
+            (8/9.,9/9.,10/9.,11/9.),
+            (12/9.,13/9.,14/9.,15/9.))
+    assert m == eval(repr(m))
+
+    # Sequence length.
+
+    m = Mat()
+    assert len(m) == 4
+
+    # Element setting.
+
+    m = Mat()
+    m[0][0] = 10
+    m[1][2] = 11
+    assert m[0][0] == 10 and m[1][2] == 11
+
+    try:
+        m[-5][0] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        m[4][0] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        m[0][-5] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        m[0][4] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        m[1] = (1,2,3,4)   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    m1 = Mat(1)
+    
+    m2 = m1
+    assert \
+      m2[0][0] ==1 and m2[0][1] ==1 and m2[0][2] ==1 and m2[0][3] ==1 and \
+      m2[1][0] ==1 and m2[1][1] ==1 and m2[1][2] ==1 and m2[1][3] ==1 and \
+      m2[2][0] ==1 and m2[2][1] ==1 and m2[2][2] ==1 and m2[2][3] ==1 and \
+      m2[3][0] ==1 and m2[3][1] ==1 and m2[3][2] ==1 and m2[3][3] ==1
+
+    m1[0][0] = 2
+    assert \
+      m2[0][0] ==2 and m2[0][1] ==1 and m2[0][2] ==1 and m2[0][3] ==1 and \
+      m2[1][0] ==1 and m2[1][1] ==1 and m2[1][2] ==1 and m2[1][3] ==1 and \
+      m2[2][0] ==1 and m2[2][1] ==1 and m2[2][2] ==1 and m2[2][3] ==1 and \
+      m2[3][0] ==1 and m2[3][1] ==1 and m2[3][2] ==1 and m2[3][3] ==1
+    
+    # Identity.
+
+    m = Mat(2)
+
+    m.makeIdentity()
+    assert \
+      m[0][0] == 1 and m[0][1] == 0 and m[0][2] == 0 and m[0][3] == 0 and \
+      m[1][0] == 0 and m[1][1] == 1 and m[1][2] == 0 and m[1][3] == 0 and \
+      m[2][0] == 0 and m[2][1] == 0 and m[2][2] == 1 and m[2][3] == 0 and \
+      m[3][0] == 0 and m[3][1] == 0 and m[3][2] == 0 and m[3][3] == 1
+
+    # Comparison operators.
+
+    m1 = Mat()
+    m1[1][1] = 2
+    m2 = Mat()
+    m2[1][1] = 2
+    m3 = Mat()
+    m3[1][1] = 3
+
+    assert m1 == m2
+    assert m1 != m3
+    assert not (m1 < m2)
+    assert m1 < m3
+    assert m1 <= m2
+    assert m1 <= m3
+    assert not (m3 <= m1)
+    assert not (m2 > m1)
+    assert m3 > m1
+    assert m2 >= m1
+    assert m3 >= m1
+    assert not (m1 >= m3)
+
+    # Epsilon equality.
+
+    e = 0.005
+    m1 = Mat(1)
+    m2 = Mat(1 + e)
+
+    assert m1.equalWithAbsError(m2, e)
+    assert m2.equalWithAbsError(m1, e)
+
+    e = 0.003
+    m1 = Mat(10)
+    m2 = Mat(10 + 10 * e)
+
+    assert m1.equalWithRelError(m2, e)
+    assert m2.equalWithRelError(m1, e)
+
+    # Addition.
+
+    m1 = Mat(1)
+    m2 = Mat(2)
+
+    assert m1 + m2 == Mat(3)
+    assert m2 + m1 == m1 + m2
+    assert m1 + 1 == Mat(2)
+    assert 1 + m1 == m1 + 1
+
+    # Subtraction and negation.
+
+    m1 = Mat(2)
+    m2 = Mat(3)
+
+    assert m2 - m1 == Mat(1)
+    assert m1 - 1 == Mat(1)
+    assert 1 - m1 == - (m1 - 1)
+    assert m1.negate() == Mat(-2)
+
+    # Multiplication.
+
+    m1 = Mat(1)
+    # (Translates by (1, 2, 0).)
+    m2 = Mat()
+    m2[3][0] = 1
+    m2[3][1] = 2
+    # (Scales by (3, 4, 1).)
+    m3 = Mat()
+    m3[0][0] = 3
+    m3[1][1] = 4
+    v = Vec(1, 2, 0)
+
+    assert m1 * 2 == Mat(2)
+    assert m1 * 2 == 2 * m1
+    assert m2 * m3 == Mat((3,0,0,0),(0,4,0,0),(0,0,1,0),(3,8,0,1))
+    assert m3 * m2 == Mat((3,0,0,0),(0,4,0,0),(0,0,1,0),(1,2,0,1))
+    assert v * m2 == Vec(2, 4, 0)
+    try:
+        m1 * v                   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    m2f = M44f()
+    m2f[3][0] = 1
+    m2f[3][1] = 2
+    v = Vec(1, 2, 0)
+    v *= m2f
+    assert v == Vec(2, 4, 0)
+
+    m2d = M44d()
+    m2d[3][0] = 1
+    m2d[3][1] = 2
+    v = Vec(1, 2, 0)
+    v *= m2d
+    assert v == Vec(2, 4, 0)
+
+    # (Rotates by 45 degrees around Z, then translates by (1, 2, 0).)
+    m3 = Mat()
+    m3[0][0] = 0
+    m3[0][1] = 1
+    m3[1][0] = -1
+    m3[1][1] = 0    
+    m4 = m3 * m2
+    v1 = Vec(1, 0, 0)
+    v2 = Vec()
+    
+    m4.multVecMatrix(v1,v2)
+    assert v2.equalWithAbsError((1, 3, 0), v2.baseTypeEpsilon())
+    v2 = m4.multVecMatrix(v1)
+    assert v2.equalWithAbsError((1, 3, 0), v2.baseTypeEpsilon())
+    v1a = V3fArray(1)
+    v1a[:] = V3f(v1)
+    v2a = m4.multVecMatrix(v1a)
+    assert v2a[0].equalWithAbsError((1, 3, 0), v2a[0].baseTypeEpsilon())
+    v1a = V3dArray(1)
+    v1a[:] = V3d(v1)
+    v2a = m4.multVecMatrix(v1a)
+    assert v2a[0].equalWithAbsError((1, 3, 0), v2a[0].baseTypeEpsilon())
+    
+    m4.multDirMatrix(v1,v2)
+    assert v2.equalWithAbsError((0, 1, 0), v2.baseTypeEpsilon())
+    v2 = m4.multDirMatrix(v1)
+    assert v2.equalWithAbsError((0, 1, 0), v2.baseTypeEpsilon())
+    v1a = V3fArray(1)
+    v1a[:] = V3f(v1)
+    v2a = m4.multDirMatrix(v1a)
+    assert v2a[0].equalWithAbsError((0, 1, 0), v2a[0].baseTypeEpsilon())
+    v1a = V3dArray(1)
+    v1a[:] = V3d(v1)
+    v2a = m4.multDirMatrix(v1a)
+    assert v2a[0].equalWithAbsError((0, 1, 0), v2a[0].baseTypeEpsilon())
+    
+    # Division.
+
+    m = Mat(4)
+
+    assert m / 2 == Mat(2)
+    try:
+        4 / m                   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Transpose.
+
+    m = Mat((0,1,2,3), (4,5,6,7), (8,9,10,11), (12,13,14,15))
+
+    assert m.transpose() == Mat((0,4,8,12), (1,5,9,13), (2,6,10,14), (3,7,11,15))
+    m.transposed()
+    assert m == Mat((0,4,8,12), (1,5,9,13), (2,6,10,14), (3,7,11,15))
+    
+    # Invert.
+
+    # (Translates by (1,2).)
+    m1 = Mat()
+    m1[3][0] = 1
+    m1[3][1] = 2
+    
+    m1I = m1.inverse()
+    assert m1 * m1I == Mat()
+    m1I = m1.gjInverse()
+    assert m1 * m1I == Mat()
+
+    m2 = Mat(m1)
+    m2.invert()
+    assert m1 * m2 == Mat()
+    m2 = Mat(m1)
+    m2.gjInvert()
+    assert m1 * m2 == Mat()
+
+    # Scaling.
+
+    v1 = Vec(1, 2, 0)
+
+    m = Mat()
+    m.setScale(2)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((2, 4, 0), v2.baseTypeEpsilon())
+
+    m.scale(3)
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((6, 12, 0), v2.baseTypeEpsilon())
+
+    m = Mat()
+    m.setScale((1, 2, 1))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((1, 4, 0), v2.baseTypeEpsilon())
+
+    m.scale((2, 3, 1))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((2, 12, 0), v2.baseTypeEpsilon())
+
+    # It is not essential for correctness that the following exceptions
+    # occur.  Instead, these tests merely document the way the Python
+    # wrappings currently work.
+    try:
+        m.setScale(1, 2)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0                   # We shouldn't get here.
+
+    # Shearing.
+
+    v1 = Vec((1, 2, 3))
+
+    m = Mat()
+    m.setShear((2, 3, 4))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((14, 14, 3), v2.baseTypeEpsilon())
+
+    m.shear((1, 2, 3))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((40, 23, 3), v2.baseTypeEpsilon())
+
+    m = Mat()
+    m.setShear((4, 3, 2, -4, -3, -2))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((18, 4, -4), v2.baseTypeEpsilon())
+
+    m.shear((3, 2, 1, -3, -2, -1))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((18, -52, -44), v2.baseTypeEpsilon())
+
+    # It is not essential for correctness that the following exceptions
+    # occur.  Instead, these tests merely document the way the Python
+    # wrappings currently work.
+    try:
+        m.setShear(1, 2, 3)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0                   # We shouldn't get here.
+
+    # It is not essential for correctness that the following exceptions
+    # occur.  Instead, these tests merely document the way the Python
+    # wrappings currently work.
+    try:
+        m.shear(1, 2, 3, 4, 5, 6)        # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0                   # We shouldn't get here.
+
+    # Translation.
+
+    v1 = Vec(1, 0, 0)
+
+    m = Mat()
+    m.setTranslation((3, 2, 0))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((4, 2, 0), v2.baseTypeEpsilon())
+
+    m.translate((1, 2, 0))
+
+    v2 = v1 * m
+    assert v2.equalWithAbsError((5, 4, 0), v2.baseTypeEpsilon())
+
+    v3 = m.translation()
+    assert v3.equalWithAbsError((4, 4, 0), v3.baseTypeEpsilon())
+
+    # Extract scaling.
+
+    m = Mat()
+    s = Vec(4, 5, 6)
+    m.translate((1, 2, 3))
+    m.shear((7, 8, 9))
+    m.scale(s)
+
+    sM = Vec()
+    m.extractScaling(sM)
+    assert sM.equalWithAbsError(s, s.baseTypeEpsilon())
+
+    # Sans scaling / Remove scaling.
+
+    m1 = Mat()
+    m1.translate((1, 2, 3))
+    m1.shear((7, 8, 9))
+    m1.scale((4, 5, 6))
+
+    m2 = m1.sansScaling()
+    assert m2[0][0] == 1 and m2[1][1] == 1 and m2[2][2] == 1 and \
+           m2[1][0] == 7 and m2[2][0] == 8 and m2[2][1] == 9 and \
+           m2[0][1] == 0 and m2[0][2] == 0 and m2[1][2] == 0 and \
+           m2[3][0] == 1 and m2[3][1] == 2 and m2[3][2] == 3
+
+    m1 = Mat()
+    m1.translate((1, 2, 3))
+    m1.shear((7, 8, 9))
+    m1.scale((0, 0, 0))
+
+    try:
+        m2 = m1.sansScaling()  # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0               # We shouldn't get here.   
+
+    m1 = Mat()
+    m1.translate((1, 2, 3))
+    m1.shear((7, 8, 9))
+    m2 = Mat(m1)
+    m1.scale((4, 5, 6))
+
+    r = m1.removeScaling()
+    assert r == 1 and m1.equalWithAbsError(m2, m1.baseTypeEpsilon())
+
+    m = Mat()
+    m.translate((1, 2, 3))
+    m.shear((7, 8, 9))
+    m.scale((0, 0, 0))
+
+    try:
+        r = m.removeScaling()  # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0               # We shouldn't get here.   
+
+    m = Mat()
+    m.translate((1, 2, 3))
+    m.shear((7, 8, 9))
+    m.scale((0, 0, 0))
+
+    r = m.removeScaling(0)
+    assert r == 0
+
+    # Sans scaling and shear / Remove scaling and shear.
+
+    m1 = Mat()
+    m1.translate((1, 2, 3))
+    m1.shear((7, 8, 9))
+    m1.scale((4, 5, 6))
+
+    m2 = m1.sansScalingAndShear()
+    assert m2[0][0] == 1 and m2[1][1] == 1 and m2[2][2] == 1 and \
+           m2[1][0] == 0 and m2[2][0] == 0 and m2[2][1] == 0 and \
+           m2[0][1] == 0 and m2[0][2] == 0 and m2[1][2] == 0 and \
+           m2[3][0] == 1 and m2[3][1] == 2 and m2[3][2] == 3
+
+    m1 = Mat()
+    m1.translate((1, 2, 3))
+    m1.shear((7, 8, 9))
+    m1.scale((0, 0, 0))
+
+    try:
+        m2 = m1.sansScalingAndShear()  # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0               # We shouldn't get here.   
+
+    m1 = Mat()
+    m1.translate((1, 2, 3))
+    m2 = Mat(m1)
+    m1.shear((7, 8, 9))
+    m1.scale((4, 5, 6))
+
+    r = m1.removeScalingAndShear()
+    assert r == 1 and m1.equalWithAbsError(m2, m1.baseTypeEpsilon())
+
+    m = Mat()
+    m.translate((1, 2, 3))
+    m.scale((0, 0, 0))
+
+    try:
+        r = m.removeScalingAndShear()  # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0               # We shouldn't get here.   
+
+    m = Mat()
+    m.translate((1, 2, 3))
+    m.shear((7, 8, 9))
+    m.scale((0, 0, 0))
+
+    r = m.removeScalingAndShear(0)
+    assert r == 0
+
+    # Extract and remove scaling and shear.
+
+    m = Mat()
+    s = Vec(4, 5, 6)
+    h = Vec(7, 8, 9)
+    m.translate((1, 2, 3))
+    m2 = Mat(m)
+    m.shear(h)
+    m.scale(s)
+
+    sM = Vec()
+    hM = Vec()
+    m.extractScalingAndShear(sM, hM)
+    assert sM.equalWithAbsError(s, s.baseTypeEpsilon())
+    assert hM.equalWithAbsError(h, h.baseTypeEpsilon())
+
+    sM = Vec()
+    hM = Vec()
+    m.extractAndRemoveScalingAndShear(sM, hM)
+    assert sM.equalWithAbsError(s, s.baseTypeEpsilon())
+    assert hM.equalWithAbsError(h, h.baseTypeEpsilon())
+    assert m2.equalWithAbsError(m, m.baseTypeEpsilon())
+
+    # Extract Euler.
+
+    m = Mat()
+    a = pi/4
+    # (Rotation by -a around Z axis.)
+    m[0][0] = cos(a)
+    m[0][1] = -sin(a)
+    m[1][0] = sin(a)
+    m[1][1] = cos(a)
+    v = Vec()
+
+    m.extractEulerZYX(v)
+    assert v.equalWithAbsError((-a, 0, 0), v.baseTypeEpsilon())
+
+    m.extractEulerXYZ(v)
+    assert v.equalWithAbsError((0, 0, -a), v.baseTypeEpsilon())
+
+
+    # Extract scale, shear, rotation, translation.
+
+    s = Vec(1, 2, 3)
+    h = Vec(0.5, 1, 0.75)
+    a = pi/4
+    t = Vec(4, 5, 6)
+
+    mS = Mat()
+    mS.scale(s)
+    mH = Mat()
+    # (Shear by XY, XZ, YZ shear factors.)
+    mH.shear(h)
+    mR = Mat()
+    # (Rotation by -a around Z axis.)
+    mR[0][0] = cos(a)
+    mR[0][1] = -sin(a)
+    mR[1][0] = sin(a)
+    mR[1][1] = cos(a)
+    mT = Mat()
+    mT.translate(t)
+    m = mS * mH * mR * mT
+
+    sInq = Vec()
+    hInq = Vec()
+    rInq = Vec()
+    tInq = Vec()
+
+    b = m.extractSHRT(sInq, hInq, rInq, tInq)
+
+    assert sInq.equalWithAbsError(s, sInq.baseTypeEpsilon())
+    assert hInq.equalWithAbsError(h, hInq.baseTypeEpsilon())
+    assert rInq.equalWithAbsError((0, 0, -a), 2 * rInq.baseTypeEpsilon())
+    assert tInq.equalWithAbsError(t, tInq.baseTypeEpsilon())
+
+    # From-to rotation matrix.
+
+    fromDir = Vec(1, 1, 0)
+    fromDir.normalize()
+    toDir = Vec(0, 1, 1)
+    toDir.normalize()
+    m = Mat()
+    m.rotationMatrix(fromDir, toDir)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, 2 * v.baseTypeEpsilon())
+
+    fromDirTup = (fromDir[0], fromDir[1], fromDir[2])
+    toDirTup = (toDir[0], toDir[1], toDir[2])
+
+    m = Mat()
+    m.rotationMatrix(fromDirTup, toDirTup)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, 2 * v.baseTypeEpsilon())
+
+    m = Mat()
+    m.rotationMatrix(fromDir, toDirTup)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, 2 * v.baseTypeEpsilon())
+
+    m = Mat()
+    m.rotationMatrix(fromDirTup, toDir)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, 2 * v.baseTypeEpsilon())
+
+    fromDir = V3f(1, 1, 0)
+    fromDir.normalize()
+    toDir = V3f(0, 1, 1)
+    toDir.normalize()
+    m = Mat()
+    m.rotationMatrix(fromDir, toDir)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, 2 * V3f.baseTypeEpsilon())
+
+    fromDir = V3d(1, 1, 0)
+    fromDir.normalize()
+    toDir = V3d(0, 1, 1)
+    toDir.normalize()
+    m = Mat()
+    m.rotationMatrix(fromDir, toDir)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, 2 * V3f.baseTypeEpsilon())
+
+    # From-to rotation matrix with up dir.
+
+    upDir = Vec(1, 0, 1)
+    upDir.normalize()
+    fromDir = Vec(1, 1, 0)
+    fromDir.normalize()
+    toDir = Vec(0, 1, 1)
+    toDir.normalize()
+    m = Mat()
+    m.rotationMatrixWithUpDir(fromDir, toDir, upDir)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, v.baseTypeEpsilon())
+
+    fromDirTup = (fromDir[0], fromDir[1], fromDir[2])
+    toDirTup = (toDir[0], toDir[1], toDir[2])
+    upDirTup = (upDir[0], upDir[1], upDir[2])
+
+    m = Mat()
+    m.rotationMatrixWithUpDir(fromDirTup, toDirTup, upDirTup)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, 2 * v.baseTypeEpsilon())
+
+    m = Mat()
+    m.rotationMatrixWithUpDir(fromDir, toDirTup, upDirTup)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, 2 * v.baseTypeEpsilon())
+
+    m = Mat()
+    m.rotationMatrixWithUpDir(fromDirTup, toDir, upDirTup)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, 2 * v.baseTypeEpsilon())
+
+    m = Mat()
+    m.rotationMatrixWithUpDir(fromDirTup, toDirTup, upDir)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, 2 * v.baseTypeEpsilon())
+
+    upDir = V3f(1, 0, 1)
+    upDir.normalize()
+    fromDir = V3f(1, 1, 0)
+    fromDir.normalize()
+    toDir = V3f(0, 1, 1)
+    toDir.normalize()
+    m = Mat()
+    m.rotationMatrixWithUpDir(fromDir, toDir, upDir)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, V3f.baseTypeEpsilon())
+
+    upDir = V3d(1, 0, 1)
+    upDir.normalize()
+    fromDir = V3d(1, 1, 0)
+    fromDir.normalize()
+    toDir = V3d(0, 1, 1)
+    toDir.normalize()
+    m = Mat()
+    m.rotationMatrixWithUpDir(fromDir, toDir, upDir)
+
+    v = fromDir * m
+    assert v.equalWithAbsError(toDir, V3f.baseTypeEpsilon())
+
+    # Determinants (by building a random singular value decomposition)
+
+    u = Mat()
+    v = Mat()
+    s = Mat()
+
+    u.rotationMatrix( V3f(random.random(),random.random(),random.random()).normalize(),
+                      V3f(random.random(),random.random(),random.random()).normalize() )
+    v.rotationMatrix( V3f(random.random(),random.random(),random.random()).normalize(),
+                      V3f(random.random(),random.random(),random.random()).normalize() )
+    s[0][0] = random.random()
+    s[1][1] = random.random()
+    s[2][2] = random.random()
+    s[3][3] = random.random()
+
+    c = u * s * v.transpose()
+    assert abs(c.determinant() - s[0][0]*s[1][1]*s[2][2]*s[3][3]) <= u.baseTypeEpsilon()
+
+    # Matrix minors
+
+    a = Mat(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
+    assert a.minorOf(0,0) == a.fastMinor(1,2,3,1,2,3)
+    assert a.minorOf(0,1) == a.fastMinor(1,2,3,0,2,3)
+    assert a.minorOf(0,2) == a.fastMinor(1,2,3,0,1,3)
+    assert a.minorOf(0,3) == a.fastMinor(1,2,3,0,1,2)
+    assert a.minorOf(1,0) == a.fastMinor(0,2,3,1,2,3)
+    assert a.minorOf(1,1) == a.fastMinor(0,2,3,0,2,3)
+    assert a.minorOf(1,2) == a.fastMinor(0,2,3,0,1,3)
+    assert a.minorOf(1,3) == a.fastMinor(0,2,3,0,1,2)
+    assert a.minorOf(2,0) == a.fastMinor(0,1,3,1,2,3)
+    assert a.minorOf(2,1) == a.fastMinor(0,1,3,0,2,3)
+    assert a.minorOf(2,2) == a.fastMinor(0,1,3,0,1,3)
+    assert a.minorOf(2,3) == a.fastMinor(0,1,3,0,1,2)
+    assert a.minorOf(3,0) == a.fastMinor(0,1,2,1,2,3)
+    assert a.minorOf(3,1) == a.fastMinor(0,1,2,0,2,3)
+    assert a.minorOf(3,2) == a.fastMinor(0,1,2,0,1,3)
+    assert a.minorOf(3,3) == a.fastMinor(0,1,2,0,1,2)
+
+    print ("ok")
+    return
+
+def testM44 ():
+
+    print ("M44f")
+    testM44x (M44f, V3f)
+    print ("M44d")
+    testM44x (M44d, V3d)
+
+testList.append (('testM44',testM44))
+
+
+# -------------------------------------------------------------------------
+# Tests for Mat --> Mat conversions
+
+def testM22xConversions (Mat):
+
+    # Assignment
+    
+    m1 = Mat(0,1, 2,3)
+
+    m2 = M22f (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 1
+
+    m2 = M22d (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 1
+
+    m2 = M22f(42)
+    assert m2[0][0] == 42 and m2[0][1] == 42
+    
+    m2 = M22d(42)
+    assert m2[0][0] == 42 and m2[0][1] == 42
+    
+    # The += operator
+
+    m2 = Mat(0,1, 2,3)
+    m2 += M22f (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 2
+    
+    m2 = Mat(0,1, 2,3)
+    m2 += M22d (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 2
+    
+    m2 += 1
+    assert m2[0][0] == 1 and m2[0][1] == 3
+    
+    # The -= operator
+
+    m2 = Mat(0,1, 2,3)
+    m2 -= M22f (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 0
+    
+    m2 = Mat(0,1, 2,3)
+    m2 -= M22d (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 0
+
+    m2 -= 1
+    assert m2[0][0] == -1 and m2[0][1] == -1
+
+    # The *= operator
+
+    m2 = Mat(0,1, 2,3)
+    m2 *= M22f (m1)
+    assert m2[0][0] == 0*0 + 1*2
+    assert m2[0][1] == 0*1 + 1*3
+        
+    m2 = Mat(0,1, 2,3)
+    m2 *= M22d (m1)
+    assert m2[0][0] == 0*0 + 1*2
+    assert m2[0][1] == 0*1 + 1*3
+        
+    m2 *= 10
+    assert m2[0][0] == 20 and m2[0][1] == 30
+    
+    # The /= operator
+
+    m2.makeIdentity()
+    m2 /= 10
+    assert equalWithRelErrorScalar(m2[0][0], 1/10.0, 0.0001)
+        
+    print ("ok")
+    return
+
+
+def testM33xConversions (Mat):
+
+    # Assignment
+    
+    m1 = Mat(0,1,2, 3,4,5, 6,7,8)
+
+    m2 = M33f (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 1
+
+    m2 = M33d (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 1
+
+    m2 = M33f(42)
+    assert m2[0][0] == 42 and m2[0][1] == 42
+    
+    m2 = M33d(42)
+    assert m2[0][0] == 42 and m2[0][1] == 42
+    
+    # The += operator
+
+    m2 = Mat(0,1,2, 3,4,5, 6,7,8)
+    m2 += M33f (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 2
+    
+    m2 = Mat(0,1,2, 3,4,5, 6,7,8)
+    m2 += M33d (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 2
+    
+    m2 += 1
+    assert m2[0][0] == 1 and m2[0][1] == 3
+    
+    # The -= operator
+
+    m2 = Mat(0,1,2, 3,4,5, 6,7,8)
+    m2 -= M33f (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 0
+    
+    m2 = Mat(0,1,2, 3,4,5, 6,7,8)
+    m2 -= M33d (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 0
+
+    m2 -= 1
+    assert m2[0][0] == -1 and m2[0][1] == -1
+
+    # The *= operator
+
+    m2 = Mat(0,1,2, 3,4,5, 6,7,8)
+    m2 *= M33f (m1)
+    assert m2[0][0] == 0*0 + 1*3 + 2*6
+    assert m2[0][1] == 0*1 + 1*4 + 2*7
+        
+    m2 = Mat(0,1,2, 3,4,5, 6,7,8)
+    m2 *= M33d (m1)
+    assert m2[0][0] == 0*0 + 1*3 + 2*6
+    assert m2[0][1] == 0*1 + 1*4 + 2*7
+        
+    m2 *= 10
+    assert m2[0][0] == (0*0 + 1*3 + 2*6)*10 and m2[0][1] == (0*1 + 1*4 + 2*7)*10
+    
+    # The /= operator
+
+    m2.makeIdentity()
+    m2 /= 10
+    assert equalWithRelErrorScalar(m2[0][0], 1/10.0, 0.0001)
+        
+    print ("ok")
+    return
+
+
+def testM44xConversions (Mat):
+
+    # Assignment
+    
+    m1 = Mat((0,1,2,3), (4,5,6,7), (8,9,10,11), (12,13,14,15))
+
+    m2 = M44f (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 1 and m2[0][2] == 2
+
+    m2 = M44d (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 1 and m2[0][2] == 2
+
+    m2 = M44f(42)
+    assert m2[0][0] == 42 and m2[0][1] == 42
+    
+    m2 = M44d(42)
+    assert m2[0][0] == 42 and m2[0][1] == 42
+    
+    # The += operator
+
+    m2 = Mat((0,1,2,3), (4,5,6,7), (8,9,10,11), (12,13,14,15))
+    m2 += M44f (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 2
+    
+    m2 = Mat((0,1,2,3), (4,5,6,7), (8,9,10,11), (12,13,14,15))
+    m2 += M44d (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 2
+    
+    m2 += 1
+    assert m2[0][0] == 1 and m2[0][1] == 3
+
+    # The -= operator
+
+    m2 = Mat((0,1,2,3), (4,5,6,7), (8,9,10,11), (12,13,14,15))
+    m2 -= M44f (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 0
+    
+    m2 = Mat((0,1,2,3), (4,5,6,7), (8,9,10,11), (12,13,14,15))
+    m2 -= M44d (m1)
+    assert m2[0][0] == 0 and m2[0][1] == 0
+    
+    m2 -= 1
+    assert m2[0][0] == -1 and m2[0][1] == -1
+
+    # The *= operator
+
+    m2 = Mat((0,1,2,3), (4,5,6,7), (8,9,10,11), (12,13,14,15))
+    m2 *= M44f (m1)
+    assert m2[0][0] == 0*0 + 1*4 + 2*8 + 3*12
+    assert m2[0][1] == 0*1 + 1*5 + 2*9 + 3*13
+        
+    m2 = Mat((0,1,2,3), (4,5,6,7), (8,9,10,11), (12,13,14,15))
+    m2 *= M44d (m1)
+    assert m2[0][0] == 0*0 + 1*4 + 2*8 + 3*12
+    assert m2[0][1] == 0*1 + 1*5 + 2*9 + 3*13
+                
+    m2 *= 10
+    assert m2[0][0] == (0*0 + 1*4 + 2*8 + 3*12)*10 and m2[0][1] == (0*1 + 1*5 + 2*9 + 3*13)*10
+    
+    # The /= operator
+
+    m2.makeIdentity()
+    m2 /= 10
+    assert equalWithRelErrorScalar(m2[0][0], 1/10.0, 0.0001)
+        
+    print ("ok")
+    return
+
+
+def testInvalidConversion (MatA, MatB):
+    try:
+        m = MatA();
+        m1 = MatB (m);           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+
+def testM33xM44xConversion (MatA, MatB):
+    testInvalidConversion (MatA, MatB)
+
+
+def testM22xM33xConversion (MatA, MatB):
+    testInvalidConversion (MatA, MatB)
+
+
+def testM22xM44xConversion (MatA, MatB):
+    testInvalidConversion (MatA, MatB)
+
+
+def testMatConversions ():
+
+    print ("M22f")
+    testM22xConversions (M22f)
+    print ("M22d")
+    testM22xConversions (M22d)
+
+    print ("M33f")
+    testM33xConversions (M33f)
+    print ("M33d")
+    testM33xConversions (M33d)
+
+    print ("M44f")
+    testM44xConversions (M44f)
+    print ("M44d")
+    testM44xConversions (M44d)
+
+    print ("invalid conversions")
+    # Deliberatly not exhaustive, just representative.
+
+    testM22xM33xConversion (M22f, M33d)
+    testM22xM33xConversion (M33f, M22d)
+
+    testM22xM44xConversion (M22f, M44d)
+    testM22xM44xConversion (M44f, M22d)
+
+    testM33xM44xConversion (M33f, M44d)
+    testM33xM44xConversion (M44f, M33d)
+
+    print ("ok")
+    return
+
+
+testList.append (('testMatConversions',testMatConversions))
+
+
+# -------------------------------------------------------------------------
+# Tests for Box2x
+
+def testBox2x (Box, Vec):
+
+    # constructors
+
+    b = Box()
+    assert b.isEmpty() and (not b.hasVolume())
+
+    b = Box (Vec (1, 2))
+    assert (not b.isEmpty()) and (not b.hasVolume())
+    assert b.min() == Vec (1, 2) and b.max() == Vec (1, 2)
+
+    b = Box (Vec (4, 5), Vec (7, 8))
+    assert (not b.isEmpty()) and b.hasVolume()
+    assert b.min() == Vec (4, 5) and b.max() == Vec (7, 8)
+
+    b1 = Box (b)
+    assert b1.min() == Vec (4, 5) and b1.max() == Vec (7, 8)
+
+    b = Box (((1, 2), (4, 5)))
+    assert b.min() == Vec (1, 2) and b.max() == Vec (4, 5)
+
+    # setMin(), setMax()
+
+    b = Box()
+    b.setMin (Vec (1, 2))
+    b.setMax (Vec (3, 6))
+    assert b.min() == Vec (1, 2) and b.max() == Vec (3, 6)
+    assert b.size() == Vec (2, 4)
+    assert b.center() == Vec (2, 4)
+
+    # makeEmpty()
+
+    b.makeEmpty()
+    assert b.isEmpty()
+
+    # extendBy()
+
+    b.extendBy (Vec (1, 2))
+    assert b.min() == Vec (1, 2) and b.max() == Vec (1, 2)
+
+    b.extendBy (Vec (0, 2))
+    assert b.min() == Vec (0, 2) and b.max() == Vec (1, 2)
+
+    b.extendBy (Box (Vec (0, 0), Vec (4, 4)))
+    assert b.min() == Vec (0, 0) and b.max() == Vec (4, 4)
+
+    # intersects()
+
+    b = Box (Vec (0, 0), Vec (4, 4))
+    assert b.intersects (Vec (1, 2))
+    assert not b.intersects (Vec (6, 7))
+    assert b.intersects (Box (Vec (-2, -2), Vec (1, 1)))
+    assert not b.intersects (Box (Vec (-2, -2), Vec (-1, -1)))
+
+    # majorAxis()
+
+    assert 0 == Box(Vec (0, 0), Vec (2, 1)).majorAxis()
+    assert 1 == Box(Vec (0, 0), Vec (1, 2)).majorAxis()
+
+    # repr
+
+    b = Box (Vec (1/9., 2/9.), Vec (4/9., 5/9.))
+    assert b == eval (repr (b))
+
+    print ("ok")
+    return
+
+
+def testBox2():
+
+    print ("Box2i")
+    testBox2x (Box2i, V2i)
+    print ("Box2i64")
+    testBox2x (Box2i64, V2i64)
+    print ("Box2f")
+    testBox2x (Box2f, V2f)
+    print ("Box2d")
+    testBox2x (Box2d, V2d)
+
+
+testList.append (('testBox2',testBox2))
+
+
+# -------------------------------------------------------------------------
+# Tests for Box3x
+
+def testBox3x (Box, Vec):
+
+    # constructors
+
+    b = Box()
+    assert b.isEmpty() and (not b.hasVolume())
+
+    b = Box (Vec (1, 2, 3))
+    assert (not b.isEmpty()) and (not b.hasVolume())
+    assert b.min() == Vec (1, 2, 3) and b.max() == Vec (1, 2, 3)
+
+    b = Box (Vec (4, 5, 6), Vec (7, 8, 9))
+    assert (not b.isEmpty()) and b.hasVolume()
+    assert b.min() == Vec (4, 5, 6) and b.max() == Vec (7, 8, 9)
+
+    b1 = Box (b)
+    assert b1.min() == Vec (4, 5, 6) and b1.max() == Vec (7, 8, 9)
+
+    b = Box (((1, 2, 3), (4, 5, 6)))
+    assert b.min() == Vec (1, 2, 3) and b.max() == Vec (4, 5, 6)
+
+    # setMin(), setMax()
+
+    b = Box()
+    b.setMin (Vec (1, 2, 3))
+    b.setMax (Vec (3, 6, 11))
+    assert b.min() == Vec (1, 2, 3) and b.max() == Vec (3, 6, 11)
+    assert b.size() == Vec (2, 4, 8)
+    assert b.center() == Vec (2, 4, 7)
+
+    # makeEmpty()
+
+    b.makeEmpty()
+    assert b.isEmpty()
+
+    # extendBy()
+
+    b.extendBy (Vec (1, 2, 3))
+    assert b.min() == Vec (1, 2, 3) and b.max() == Vec (1, 2, 3)
+
+    b.extendBy (Vec (0, 2, 4))
+    assert b.min() == Vec (0, 2, 3) and b.max() == Vec (1, 2, 4)
+
+    b.extendBy (Box (Vec (0, 0, 0), Vec (4, 4, 4)))
+    assert b.min() == Vec (0, 0, 0) and b.max() == Vec (4, 4, 4)
+
+    # intersects()
+
+    b = Box (Vec (0, 0, 0), Vec (4, 4, 4))
+    assert b.intersects (Vec (1, 2, 3))
+    assert not b.intersects (Vec (6, 7, 8))
+    assert b.intersects (Box (Vec (-2, -2, -2), Vec (1, 1, 1)))
+    assert not b.intersects (Box (Vec (-2, -2, -2), Vec (-1, -1, -1)))
+
+    # majorAxis()
+
+    assert 0 == Box(Vec (0, 0, 0), Vec (2, 1, 1)).majorAxis()
+    assert 1 == Box(Vec (0, 0, 0), Vec (1, 2, 1)).majorAxis()
+    assert 2 == Box(Vec (0, 0, 0), Vec (1, 1, 2)).majorAxis()
+
+    # repr
+
+    b = Box (Vec (1/9., 2/9., 3/9.), Vec (4/9., 5/9., 6/9.))
+    assert b == eval (repr (b))
+
+    # tranform
+
+    b = Box (Vec (1, 1, 1), Vec (2, 2, 2))
+
+    mf = M44f ()
+    mf.setTranslation (Vec (10, 11, 12))
+
+    b2 = b * mf
+    assert b2.min() == Vec (11, 12, 13)
+    assert b2.max() == Vec (12, 13, 14)
+    
+    b *= mf
+    assert b.min() == Vec (11, 12, 13)
+    assert b.max() == Vec (12, 13, 14)
+    
+    b = Box (Vec (1, 1, 1), Vec (2, 2, 2))
+
+    md = M44d ()
+    md.setTranslation (Vec (10, 11, 12))
+
+    b2 = b * md
+    assert b2.min() == Vec (11, 12, 13)
+    assert b2.max() == Vec (12, 13, 14)
+    
+    b *= md
+    assert b.min() == Vec (11, 12, 13)
+    assert b.max() == Vec (12, 13, 14)
+    
+    print ("ok")
+    return
+
+
+def testBox3():
+
+    print ("Box3i")
+    testBox3x (Box3i, V3i)
+    print ("Box3i64")
+    testBox3x (Box3i64, V3i64)
+    print ("Box3f")
+    testBox3x (Box3f, V3f)
+    print ("Box3d")
+    testBox3x (Box3d, V3d)
+
+
+testList.append (('testBox3',testBox3))
+
+
+# -------------------------------------------------------------------------
+# Tests for Box --> Box conversions
+
+def testBox2Conversions (Box, Vec):
+
+    b1 = Box (Vec (1, 2), Vec (4, 5))
+
+    b2 = Box2i (b1)
+    assert b2.min() == V2i (1, 2) and b2.max() == V2i (4, 5)
+
+    b2 = Box2f (b1)
+    assert b2.min() == V2f (1, 2) and b2.max() == V2f (4, 5)
+
+    b2 = Box2d (b1)
+    assert b2.min() == V2d (1, 2) and b2.max() == V2d (4, 5)
+
+    print ("ok")
+    return
+
+
+def testBox3Conversions (Box, Vec):
+
+    b1 = Box (Vec (1, 2, 3), Vec (4, 5, 6))
+
+    b2 = Box3i (b1)
+    assert b2.min() == V3i (1, 2, 3) and b2.max() == V3i (4, 5, 6)
+
+    b2 = Box3f (b1)
+    assert b2.min() == V3f (1, 2, 3) and b2.max() == V3f (4, 5, 6)
+
+    b2 = Box3d (b1)
+    assert b2.min() == V3d (1, 2, 3) and b2.max() == V3d (4, 5, 6)
+
+    print ("ok")
+    return
+
+
+def testBox2Box3Conversion (Box1, Box2):
+
+    try:
+        b = Box1();
+        b1 = Box2 (b);           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+
+def testBoxConversions ():
+
+    print ("Box2i")
+    testBox2Conversions (Box2i, V2i)
+    print ("Box2i64")
+    testBox2Conversions (Box2i64, V2i64)
+    print ("Box2f")
+    testBox2Conversions (Box2f, V2f)
+    print ("Box2d")
+    testBox2Conversions (Box2d, V2d)
+
+    print ("Box3i")
+    testBox3Conversions (Box3i, V3i)
+    print ("Box3i64")
+    testBox3Conversions (Box3i64, V3i64)
+    print ("Box3f")
+    testBox3Conversions (Box3f, V3f)
+    print ("Box3d")
+    testBox3Conversions (Box3d, V3d)
+
+    print ("invalid conversions")
+    testBox2Box3Conversion (Box2i, Box3i)
+    testBox2Box3Conversion (Box2i, Box3f)
+    testBox2Box3Conversion (Box3d, Box2i)
+    testBox2Box3Conversion (Box3f, Box2f)
+
+    print ("ok")
+    return
+
+
+testList.append (('testBoxConversions',testBoxConversions))
+
+
+# -------------------------------------------------------------------------
+# Tests for Quatx
+
+def testQuatx (Quat, Vec, M33, M44):
+
+    # constructors, r(), v()
+    e = 4 * Vec.baseTypeEpsilon()
+
+    q = Quat()
+    assert q.r() == 1 and q.v() == Vec (0, 0, 0)
+
+    q = Quat (2, 3, 4, 5)
+    assert q.r() == 2 and q.v() == Vec (3, 4, 5)
+
+    q = Quat (6, Vec (7, 8, 9))
+    assert q.r() == 6 and q.v() == Vec (7, 8, 9)
+
+    q1 = Quat (q)
+    assert q1.r() == 6 and q1.v() == Vec (7, 8, 9)
+
+    # setR(), setV()
+
+    q.setR (1)
+    q.setV (Vec (2, 3, 4))
+    assert q.r() == 1 and q.v() == Vec (2, 3, 4)
+
+    # invert(), inverse()
+
+    q = Quat (1, 0, 0, 1)
+    assert q.inverse() == Quat (0.5, 0, 0, -0.5)
+    q.invert()
+    assert q == Quat (0.5, 0, 0, -0.5)
+
+    # normalize(), normalized()
+
+    q = Quat (2, Vec (0, 0, 0))
+    assert q.normalized() == Quat (1, 0, 0, 0)
+    q.normalize()
+    assert q == Quat (1, 0, 0, 0)
+
+    q = Quat (0, Vec (0, 2, 0))
+    assert q.normalized() == Quat (0, 0, 1, 0)
+    q.normalize()
+    assert q == Quat (0, 0, 1, 0)
+
+    # length()
+
+    q = Quat (3, 0, 4, 0)
+    assert q.length() == 5
+
+    # setAxisAngle(), angle(), axis()
+
+    q.setAxisAngle (Vec (0, 0, 1), pi/2)
+    v = q.axis()
+    a = q.angle()
+    assert v.equalWithAbsError (Vec (0, 0, 1), e)
+    assert equal(a, pi/2, e)
+
+    # setRotation()
+
+    q.setRotation (Vec (1, 0, 0), Vec (0, 1, 0))
+    v = q.axis()
+    a = q.angle()
+    assert v.equalWithAbsError (Vec (0, 0, 1), e)
+    assert equal(a, pi/2, e)
+
+    # slerp()
+
+    q = Quat()
+    q.setAxisAngle (Vec (0, 0, 1), pi/2)
+    p = Quat()
+    p.setAxisAngle (Vec (1, 0, 0), pi/2)
+    
+    r = q.slerp (p, 0)
+
+    assert equal (r.r(), sqrt(2) / 2, e)
+
+    assert r.v().equalWithAbsError (Vec (0, 0, sqrt(2) / 2), e)
+    r = q.slerp (p, 1)
+
+    assert equal (r.r(), sqrt(2) / 2, e)
+
+    assert r.v().equalWithAbsError (Vec (sqrt(2) / 2, 0, 0), e)
+
+    # toMatrix33(), toMatrix44()
+
+    q.setRotation (Vec (1, 0, 0), Vec (0, 1, 0))
+
+    m = q.toMatrix33()
+
+    assert m.equalWithAbsError (M33 (0, 1, 0,
+                                    -1, 0, 0,
+                                     0, 0, 1),
+                                m.baseTypeEpsilon())
+    m = q.toMatrix44()
+
+    assert m.equalWithAbsError (M44 (( 0, 1, 0, 0),
+                                     (-1, 0, 0, 0),
+                                     ( 0, 0, 1, 0),
+                                     ( 0, 0, 0, 1)),
+                                m.baseTypeEpsilon())
+
+    # +, - (unary and binary), ~ *, /, ^
+
+    assert Quat (1, 2, 3, 4) + Quat (5, 6, 7, 8) == Quat (6, 8, 10, 12)
+
+    assert Quat (-1, -2, -3, -4) - Quat (5, 6, 7, 8) == Quat (-6, -8, -10, -12)
+    assert -Quat (1, 2, 3, 4) == Quat (-1, -2, -3, -4)
+    
+    assert ~Quat (1, 2, 3, 4) == Quat (1, -2, -3, -4)
+
+    assert 2 * Quat (1, 2, 3, 4) == Quat (2, 4, 6, 8)
+    assert Quat (1, 2, 3, 4) * 2 == Quat (2, 4, 6, 8)
+    assert Quat (1, 0, 0, 1) * Quat (1, 1, 0, 0) == Quat (1, 1, 1, 1)
+    assert Quat (1, 1, 0, 0) * Quat (1, 0, 0, 1) == Quat (1, 1, -1, 1)
+    
+    assert Quat (1, 0, 0, 1) / Quat (0.5, -0.5, 0, 0) == Quat (1, 1, 1, 1)
+    assert Quat (2, 4, 6, 8) / 2 == Quat (1, 2, 3, 4)
+
+    assert Quat (1, 2, 3, 4) ^ Quat (2, 2, 2, 2) == 20
+
+    # repr
+
+    q = Quat (1/9., 2/9., 3/9., 4/9.)
+    assert q == eval (repr (q))
+
+    # extract()
+
+    m1 = M44 ()
+    vFrom = Vec (1, 0, 0)
+    vTo = Vec (0, 1, 1)
+    m1.rotationMatrix(vFrom, vTo)
+    q = Quat ()
+    q.extract(m1)
+    m2 = q.toMatrix44()
+    assert m2.equalWithAbsError(m1, 2*m1.baseTypeEpsilon())
+
+    print ("ok")
+    return
+
+
+def testQuatConversions ():
+
+    q = Quatf (1, V3f (2, 3, 4))
+    q1 = Quatd (q)
+    assert q1.r() == 1 and q1.v() == V3d (2, 3, 4)
+
+    q = Quatd (1, V3d (2, 3, 4))
+    q1 = Quatf (q)
+    assert q1.r() == 1 and q1.v() == V3f (2, 3, 4)
+
+    print ("ok")
+    return
+
+
+def testQuat():
+
+    print ("Quatf")
+    testQuatx (Quatf, V3f, M33f, M44f)
+    print ("Quatd")
+    testQuatx (Quatd, V3d, M33d, M44d)
+    print ("conversions")
+    testQuatConversions()
+
+
+testList.append (('testQuat',testQuat))
+
+
+# -------------------------------------------------------------------------
+# Tests for Eulerx
+
+def testEulerx (Euler, Vec, M33, M44):
+
+    # constructors, toXYZVector(), order()
+
+    e = Euler()
+    assert e.toXYZVector() == Vec (0, 0, 0) and e.order() == EULER_XYZ
+
+    e = Euler (Vec (1, 2, 3))
+    assert e.toXYZVector() == Vec (1, 2, 3) and e.order() == EULER_XYZ
+
+    e = Euler (Vec (1, 2, 3), EULER_ZYX)
+    assert e.toXYZVector() == Vec (3, 2, 1) and e.order() == EULER_ZYX
+
+    e1 = Euler (e)
+    assert e1.toXYZVector() == Vec (3, 2, 1) and e1.order() == EULER_ZYX
+
+    e = Euler (4, 5, 6)
+    assert e.toXYZVector() == Vec (4, 5, 6) and e.order() == EULER_XYZ
+
+    e = Euler (4, 5, 6, EULER_ZXY)
+    assert e.toXYZVector() == Vec (5, 6, 4) and e.order() == EULER_ZXY
+
+    e = Euler (M33())
+    assert e.toXYZVector() == Vec (0, 0, 0) and e.order() == EULER_XYZ
+
+    e = Euler (M33(), EULER_ZYX)
+    assert e.toXYZVector() == Vec (0, 0, 0) and e.order() == EULER_ZYX
+
+    e = Euler (M44())
+    assert e.toXYZVector() == Vec (0, 0, 0) and e.order() == EULER_XYZ
+
+    e = Euler (M44(), EULER_ZYX)
+    assert e.toXYZVector() == Vec (0, 0, 0) and e.order() == EULER_ZYX
+
+    # comparison
+
+    e = Euler (1, 2, 3, EULER_XYZ)
+
+    e1 = e
+    assert e1 == e
+
+    e1 = Euler (1, 2, 3, EULER_XZY)
+    assert e1 != e
+
+    e1 = Euler (1, 1, 3, EULER_XYZ)
+    assert e1 != e
+
+    # setXYZVector(), setOrder()
+
+    e.setXYZVector (Vec (7, 8, 9))
+
+    e.setOrder (EULER_ZYX)
+    assert e.order() == EULER_ZYX and e.toXYZVector() == Vec (9, 8, 7)
+
+    e.setOrder (EULER_XYZ)
+    assert e.order() == EULER_XYZ and e.toXYZVector() == Vec (7, 8, 9)
+
+    # set(), frameStatic(), initialRepeated(), parityEven(), initialAxis()
+
+    e.set (EULER_X_AXIS, 0, 0, 1)
+    assert e.order() == EULER_XZX
+    assert e.frameStatic() == 1
+    assert e.initialRepeated() == 1
+    assert e.parityEven() == 0
+    assert e.initialAxis() == EULER_X_AXIS
+
+    e.set (EULER_Y_AXIS, 1, 0, 1)
+    assert e.order() == EULER_YZYr
+    assert e.frameStatic() == 0
+    assert e.initialRepeated() == 1
+    assert e.parityEven() == 0
+    assert e.initialAxis() == EULER_Y_AXIS
+
+    e.set (EULER_Z_AXIS, 1, 1, 1)
+    assert e.order() == EULER_XZXr
+    assert e.frameStatic() == 0
+    assert e.initialRepeated() == 1
+    assert e.parityEven() == 1
+    assert e.initialAxis() == EULER_Z_AXIS
+
+    # extract()
+
+    e = Euler (EULER_XYZ);
+
+    m = M33 (( 0, 2, 0),        # 90-degree rotation around Z,
+             (-2, 0, 0),        # scale by factor 2
+             ( 0, 0, 2))
+
+    e.extract (m);
+    v = e.toXYZVector();
+
+    assert v.equalWithAbsError (Vec (0, 0, pi/2), v.baseTypeEpsilon())
+
+    m = M44 (( 0, 2, 0, 0),        # 90-degree rotation around Z
+             (-2, 0, 0, 0),        # scale by factor 2
+             ( 0, 0, 2, 0),
+             ( 0, 0, 0, 1))
+
+    e.extract (m);
+    v = e.toXYZVector();
+
+    assert v.equalWithAbsError (Vec (0, 0, pi/2), v.baseTypeEpsilon())
+
+    # toMatrix33(), toMatrix44()
+
+    m = e.toMatrix33();
+
+    assert m.equalWithAbsError (M33 (0, 1, 0,
+                                    -1, 0, 0,
+                                     0, 0, 1),
+                                m.baseTypeEpsilon())
+    m = e.toMatrix44();
+
+    assert m.equalWithAbsError (M44 (( 0, 1, 0, 0),
+                                     (-1, 0, 0, 0),
+                                     ( 0, 0, 1, 0),
+                                     ( 0, 0, 0, 1)),
+                                m.baseTypeEpsilon())
+    # toQuat()
+
+    q = e.toQuat();
+
+    assert equal (q.r(), sqrt(2) / 2, Vec().baseTypeEpsilon())
+
+    assert q.v().equalWithAbsError (Vec (0, 0, sqrt(2) / 2),
+                                    Vec().baseTypeEpsilon())
+
+    # angleOrder()
+
+    e = Euler (EULER_XYZ)
+    assert e.angleOrder() == (0, 1, 2)
+
+    e = Euler (EULER_XZY)
+    assert e.angleOrder() == (0, 2, 1)
+
+    e = Euler (EULER_ZYX)
+    assert e.angleOrder() == (2, 1, 0)
+
+    # makeNear()
+
+    e = Euler (0, 0, 0.1 + 2 * pi)
+    e1 = Euler (0, 0, 0.1)
+
+    e.makeNear (e1)
+    v = e.toXYZVector()
+    assert v.equalWithAbsError (Vec (0, 0, 0.1), v.baseTypeEpsilon())
+
+    # repr
+
+    e = Euler (1/9., 2/9., 3/9., EULER_XYZ)
+    assert e == eval (repr (e))
+
+    e = Euler (1/9., 2/9., 3/9., EULER_YXZ)
+    assert e == eval (repr (e))
+
+    e = Euler (1/9., 2/9., 3/9., EULER_XZXr)
+    assert e == eval (repr (e))
+
+    print ("ok")
+    return
+
+
+def testEulerConversions ():
+
+    e = Eulerf (V3f (1, 2, 3), EULER_XYZ)
+    e1 = Eulerd (e)
+    assert e1.toXYZVector() == V3d (1, 2, 3) and e1.order() == EULER_XYZ
+
+    e = Eulerd (V3d (1, 2, 3), EULER_XYZ)
+    e1 = Eulerf (e)
+    assert e1.toXYZVector() == V3f (1, 2, 3) and e1.order() == EULER_XYZ
+
+    print ("ok")
+    return
+
+
+def testEuler():
+
+    print ("Eulerf")
+    testEulerx (Eulerf, V3f, M33f, M44f)
+    print ("Eulerd")
+    testEulerx (Eulerd, V3d, M33d, M44d)
+    print ("conversions")
+    testEulerConversions()
+
+
+testList.append (('testEuler',testEuler))
+
+
+# -------------------------------------------------------------------------
+# Tests for Line3x
+
+def testLine3x (Line, Vec, Mat):
+
+    # constructors, pos(), dir()
+
+    l = Line()
+    assert l.pos() == Vec (0, 0, 0) and l.dir() == Vec (1, 0, 0)
+
+    l = Line (Vec (1, 2, 3), Vec (1, 6, 3))
+    assert l.pos() == Vec (1, 2, 3) and l.dir() == Vec (0, 1, 0)
+
+    l1 = Line (l)
+    assert l1.pos() == Vec (1, 2, 3) and l1.dir() == Vec (0, 1, 0)
+
+    # comparison
+
+    l = Line (Vec (1, 1, 1), Vec (2, 2, 2))
+    l1 = Line (l)
+    assert l == l1
+
+    l = Line (Vec (1, 1, 1), Vec (2, 2, 3))
+    assert l != l1
+
+    l = Line (Vec (1, 1, 2), Vec (2, 2, 2))
+    assert l != l1
+
+    # setPos(), setDir(), set()
+
+    l.setPos (Vec (4, 5, 6))
+    l.setDir (Vec (0, 0, 4))
+    assert l.pos() == Vec (4, 5, 6) and l.dir() == Vec (0, 0, 1)
+
+    l.set (Vec (1, 2, 3), Vec (1, 6, 3))
+    assert l.pos() == Vec (1, 2, 3) and l.dir() == Vec (0, 1, 0)
+
+    # pointAt()
+
+    l = Line (Vec (1, 2, 3), Vec (2, 2, 3))
+    assert l.pointAt (2) == Vec (3, 2, 3)
+
+    # distanceTo()
+
+    l = Line (Vec (0, 0, 0), Vec (1, 0, 0))
+    assert l.distanceTo (Vec (2, 3, 0)) == 3
+    assert l.distanceTo (Line (Vec (0, 2, -1), Vec (0, 2, 1))) == 2
+
+    # closestPointTo(), closestPoints()
+
+    l = Line (Vec (1, 0, 0), Vec (2, 0, 0))
+    assert l.closestPointTo (Vec (0, 1, 0)) == Vec (0, 0, 0)
+
+    l1 = Line (Vec (0, 1, 1), Vec (0, 1, 2))
+    assert l.closestPointTo (l1) == Vec (0, 0, 0)
+
+    p = l.closestPoints (l1)
+    assert p[0] == Vec (0, 0, 0) and p[1] == Vec (0, 1, 0)
+
+    # closestTriangleVertex()
+
+    l = Line (Vec (0, 0, 0), Vec (1, 0, 0))
+    v = l.closestTriangleVertex (Vec (1, 1, 1), Vec (2, 0, 2), Vec (1, 2, 3))
+    assert v == Vec (1, 1, 1)
+
+    # intersectWithTriangle()
+
+    l = Line (Vec (0, 0, 0), Vec (1, 0, 0))
+
+    i = l.intersectWithTriangle (Vec (1, 1, 0), Vec (1, 2, 0), Vec (2, 2, 0))
+
+    assert i == None
+
+    i = l.intersectWithTriangle (Vec (4,-1,-1), Vec (4,-1, 2), Vec (4, 2,-1))
+
+    assert i[0] == Vec (4, 0, 0)
+    assert i[1].equalWithAbsError (Vec (1) / 3, i[1].baseTypeEpsilon())
+    assert i[2] == 0
+
+    # rotatePoint()
+
+    l = Line (Vec (0, 0, 0), Vec (1, 0, 0))
+    p = l.rotatePoint (Vec (2, 2, 0), pi/2)
+
+    assert p.equalWithAbsError (Vec (2, 0, -2), p.baseTypeEpsilon())
+
+    # line*matrix multiplication
+
+    l = Line (Vec (0, 0, 0), Vec (1, 0, 0))
+
+    m = Mat (( 0, 1, 0, 0),
+             (-1, 0, 0, 0),
+             ( 0, 0, 1, 0),
+             ( 0, 0, 0, 1))
+
+    l = l * m
+    assert l.pos() == Vec (0, 0, 0) and l.dir() == Vec (0, 1, 0)
+
+    try:
+        l = m * l        # should raise TypeError
+    except TypeError:
+        pass
+    else:
+        assert 0
+
+    # repr
+
+    e = Line (V3f (1/9., 2/9., 3/9.), V3f (1/9., 3/9., 3/9.))
+    assert e == eval (repr (e))
+
+    print ("ok")
+    return
+
+
+def testLine3Conversions ():
+
+    l = Line3f (V3f (1, 2, 3), V3f (1, 3, 3))
+    l1 = Line3d (l)
+    assert l1.pos() == V3d (1, 2, 3) and l1.dir() == V3d (0, 1, 0)
+
+    l = Line3d (V3d (1, 2, 3), V3d (1, 3, 3))
+    l1 = Line3f (l)
+    assert l1.pos() == V3f (1, 2, 3) and l1.dir() == V3f (0, 1, 0)
+
+    print ("ok")
+    return
+
+
+def testLine3():
+
+    print ("Line3f")
+    testLine3x (Line3f, V3f, M44f)
+    print ("Line3d")
+    testLine3x (Line3d, V3d, M44d)
+    print ("conversions")
+    testLine3Conversions()
+
+
+testList.append (('testLine3',testLine3))
+
+
+# -------------------------------------------------------------------------
+# Tests for Plane3x
+
+def testPlane3x (Plane, Vec, Mat, Line):
+
+    # constructors, normal(), distance()
+
+    p = Plane()
+    assert p.normal() == Vec (1, 0, 0) and p.distance() == 0
+
+    p = Plane (Vec (0, 4, 0), 3) # normal, distance
+    assert p.normal() == Vec (0, 1, 0) and p.distance() == 3
+
+    p = Plane (Vec (0, 4, 0), Vec (0, 1, 0)) # point, normal
+    assert p.normal() == Vec (0, 1, 0) and p.distance() == 4
+
+    p = Plane (Vec (0, 0, 1), Vec (2, 0, 1), Vec (0, 2, 1)) # three points
+    assert p.normal() == Vec (0, 0, 1) and p.distance() == 1
+
+    p1 = Plane (p)
+    assert p1.normal() == Vec (0, 0, 1) and p1.distance() == 1
+
+    # comparison
+
+    p = Plane (Vec (1, 1, 1), 2)
+    p1 = Plane (p)
+    assert p == p1
+
+    p = Plane (Vec (1, 1, 2), 2)
+    assert p != p1
+
+    p = Plane (Vec (1, 1, 1), 1)
+    assert p != p1
+
+    # setNormal(), setDistance()
+
+    p = Plane(Vec (1, 1, 1), 3)
+    p.setNormal (Vec (0, 0, 4))
+    p.setDistance (5)
+    assert p.normal() == Vec (0, 0, 1) and p.distance() == 5
+
+    # set()
+
+    p.set (Vec (0, 1, 0), 2) # normal, distance
+    assert p.normal() == Vec (0, 1, 0) and p.distance() == 2
+
+    p.set (Vec (0, 2, 0), Vec (0, 0, 1)) # point, normal
+    assert p.normal() == Vec (0, 0, 1) and p.distance() == 0
+
+    p.set (Vec (1, 0, 2), Vec (1, 2, 0), Vec (1, 0, 0)) # three points
+    assert p.normal() == Vec (-1, 0, 0) and p.distance() == -1
+
+    # intersect(), intersectT(), distanceTo(), reflectPoint(), reflectVector()
+
+    p = Plane (Vec (2, 0, 2), Vec (2, 2, 0), Vec (2, 0, 0)) # three points
+
+    l = Line (Vec (0, 0, 0), Vec (1, 0, 0))
+    assert p.intersect(l) == Vec (2, 0, 0)
+    assert p.intersectT(l) == 2
+
+    assert p.distanceTo (Vec (1, 2, 3)) ==  1
+    assert p.distanceTo (Vec (3, 2, 3)) == -1
+
+    assert p.reflectPoint (Vec (1, 2, 3)) == Vec (3, 2, 3)
+    assert p.reflectVector (Vec (1, 2, 3)) == Vec (1, -2, -3)
+
+    # plane*matrix multiplication
+
+    p = Plane (Vec (1, 0, 0), 4)
+
+    m = Mat (( 0, 1, 0, 0),
+             (-1, 0, 0, 0),
+             ( 0, 0, 1, 0),
+             ( 0, 0, 0, 1))
+
+    p = p * m
+    assert p.normal().equalWithAbsError (Vec (0, 1, 0), Vec().baseTypeEpsilon())
+    assert equal (p.distance(), 4, Vec().baseTypeEpsilon())
+
+    try:
+        p = m * p        # should raise TypeError
+    except TypeError:
+        pass
+    else:
+        assert 0
+
+    # unary minus operator
+
+    assert -Plane (Vec (0, 1, 0), 4) == Plane (Vec (0, -1, 0), -4)
+
+    # repr
+
+    e = Plane (Vec (0/9., 1/9., 0/9.), 3/9.)
+    assert e == eval (repr (e))
+
+    print ("ok")
+    return
+
+
+def testPlane3Conversions ():
+
+    p = Plane3f (V3f (1, 0, 0), 3)
+    p1 = Plane3d (p)
+    assert p1.normal() == V3d (1, 0, 0) and p1.distance() == 3
+
+    p = Plane3d (V3d (1, 0, 0), 3)
+    p1 = Plane3f (p)
+    assert p1.normal() == V3f (1, 0, 0) and p1.distance() == 3
+
+    print ("ok")
+    return
+
+
+def testPlane3():
+
+    print ("Plane3f")
+    testPlane3x (Plane3f, V3f, M44f, Line3f)
+    print ("Plane3d with Line3f")
+    testPlane3x (Plane3d, V3d, M44d, Line3f)
+    print ("Plane3d with Line3d")
+    testPlane3x (Plane3d, V3d, M44d, Line3d)
+    print ("conversions")
+    testPlane3Conversions()
+
+
+testList.append (('testPlane3',testPlane3))
+
+
+# -------------------------------------------------------------------------
+# Tests for Color3x
+
+def testColor3x (Color, maxComp):
+    
+    # Constructors (and element access).
+
+    v = Color()
+    assert v[0] == 0 and v[1] == 0 and v[2] == 0
+
+    v = Color(1)
+    assert v[0] == 1 and v[1] == 1 and v[2] == 1
+
+    v = Color(0, 1, 2)
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2
+
+    v = Color((0, 1, 2))
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2
+
+    v = Color([0, 1, 2])
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2
+
+    v = Color()
+    v.setValue(0, 1, 2)
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2
+
+    # Repr.
+
+    v = Color(1/9., 2/9., 3/9.)
+    assert v == eval(repr(v))
+
+    # Sequence length.
+
+    v = Color()
+    assert len(v) == 3
+
+    # Element setting.
+
+    v = Color()
+    v[0] = 10
+    v[1] = 11
+    v[2] = 12
+    assert v[0] == 10 and v[1] == 11 and v[2] == 12
+
+    try:
+        v[-4] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[3] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[1] = "a"           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    v1 = Color(1)
+    
+    v2 = v1
+    assert v2[0] == 1 and v2[1] == 1 and v2[2] == 1
+    v1[0] = 2
+    assert v2[0] == 2 and v2[1] == 1 and v2[2] == 1
+    
+    # Comparison operators.
+
+    v1 = Color(20, 20, 0)
+    v2 = Color(20, 20, 0)
+    v3 = Color(20, 21, 0)
+
+    assert v1 == v2
+    assert v1 != v3
+    assert not (v1 < v2)
+    assert v1 < v3
+    assert v1 <= v2
+    assert v1 <= v3
+    assert not (v3 <= v1)
+    assert not (v2 > v1)
+    assert v3 > v1
+    assert v2 >= v1
+    assert v3 >= v1
+    assert not (v1 >= v3)
+    
+    # Addition.
+
+    v1 = Color(10, 20, 30)
+    v2 = Color(30, 40, 50)
+
+    assert v1 + v2 == Color(40, 60, 80)
+    assert v2 + v1 == v1 + v2
+    assert v1 + 1 == Color(11, 21, 31)
+    assert 1 + v1 == v1 + 1
+
+    # (with the switch to python2, we now allow ops between colors and tuples)
+    assert v1 + (1, 2, 3) == Color(11, 22, 33)
+    assert (1, 2, 3) + v1 == v1 + (1, 2, 3)
+
+    # Subtraction and negation.
+
+    v1 = Color(10, 20, 30)
+    v2 = Color(30, 40, 50)
+
+    assert v2 - v1 == Color(20, 20, 20)
+    assert v1 - 1 == Color(9, 19, 29)
+    assert 1 - v1 == - (v1 - 1)
+
+    # (with the switch to python2, we now allow ops between colors and tuples)
+    assert v1 - (1, 2, 3) == Color(9, 18, 27)
+    assert (1, 2, 3) - v1 == - (v1 - (1, 2, 3))
+
+    assert v1.negate() == Color(-10, -20, -30)
+
+    # Multiplication.
+
+    v1 = Color(1, 2, 3)
+    v2 = Color(3, 4, 5)
+    
+    assert v1 * v2 == Color(3, 8, 15)
+    assert v2 * v1 == v1 * v2
+    assert 2 * v1 == Color(2, 4, 6)
+    assert v1 * 2 == 2 * v1
+
+    # (with the switch to python2, we now allow ops between colors and tuples)
+    assert v1 * (1, 2, 3) == Color(1, 4, 9)
+    assert (1, 2, 3) * v1 == v1 * (1, 2, 3)
+
+    # Division.
+
+    v1 = Color(10, 20, 40)
+    v2 = Color(2, 4, 8)
+    
+    assert v1 / v2 == Color(10/2, 20/4, 40/8)
+    assert v1 / 2 == Color(10/2, 20/2, 40/2)
+    assert Color(40) / v1 == Color(40/10, 40/20, 40/40)
+
+    # (with the switch to python2, we now allow ops between colors and tuples)
+    assert v1 / (1, 4, 20) == Color(10/1, 20/4, 40/20)
+    assert Color(20, 60, 160) / v1 == Color(20/10, 60/20, 160/40)
+    
+    # Color space conversion.
+
+    c1 = Color(maxComp, 0, 0)
+
+    c2 = c1.rgb2hsv()
+    assert c2[0] == 0 and c2[1] == maxComp and c2[2] == maxComp
+
+    c3 = c2.hsv2rgb()
+    assert c3[0] == maxComp and c3[1] == 0 and c3[2] == 0    
+
+    print ("ok")
+
+    return
+
+def testColor3 ():
+
+    print ("Color3f")
+    testColor3x (Color3f, 1.0)
+    print ("Color3c")
+    testColor3x (Color3c, 255)
+
+testList.append (('testColor3',testColor3))
+
+
+# -------------------------------------------------------------------------
+# Tests for Color4x
+
+def testColor4x (Color, maxComp):
+    
+    # Constructors (and element access).
+
+    v = Color()
+    assert v[0] == 0 and v[1] == 0 and v[2] == 0 and v[3] == 0
+
+    v = Color(1)
+    assert v[0] == 1 and v[1] == 1 and v[2] == 1 and v[3] == 1
+
+    v = Color(0, 1, 2, 3)
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2 and v[3] == 3
+
+    v = Color((0, 1, 2, 3))
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2 and v[3] == 3
+
+    v = Color([0, 1, 2, 3])
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2 and v[3] == 3
+
+    v = Color()
+    v.setValue(0, 1, 2, 3)
+    assert v[0] == 0 and v[1] == 1 and v[2] == 2 and v[3] == 3
+
+    # Repr.
+
+    v = Color(1/9., 2/9., 3/9., 4/9.)
+    assert v == eval(repr(v))
+
+    # Sequence length.
+
+    v = Color()
+    assert len(v) == 4
+
+    # Element setting.
+
+    v = Color()
+    v[0] = 10
+    v[1] = 11
+    v[2] = 12
+    v[3] = 13
+    assert v[0] == 10 and v[1] == 11 and v[2] == 12 and v[3] == 13
+
+    try:
+        v[-5] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[4] = 0           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        v[1] = "a"           # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    v1 = Color(1)
+    
+    v2 = v1
+    assert v2[0] == 1 and v2[1] == 1 and v2[2] == 1 and v2[3] == 1
+    v1[0] = 2
+    assert v2[0] == 2 and v2[1] == 1 and v2[2] == 1 and v2[3] == 1
+    
+    # Comparison operators.
+
+    v1 = Color(20, 20, 0, 0)
+    v2 = Color(20, 20, 0, 0)
+    v3 = Color(20, 21, 0, 0)
+
+    assert v1 == v2
+    assert v1 != v3
+    assert not (v1 < v2)
+    assert v1 < v3
+    assert v1 <= v2
+    assert v1 <= v3
+    assert not (v3 <= v1)
+    assert not (v2 > v1)
+    assert v3 > v1
+    assert v2 >= v1
+    assert v3 >= v1
+    assert not (v1 >= v3)
+    
+    # Addition.
+
+    v1 = Color(10, 20, 30, 0)
+    v2 = Color(30, 40, 50, 0)
+
+    assert v1 + v2 == Color(40, 60, 80, 0)
+    assert v2 + v1 == v1 + v2
+    assert v1 + 1 == Color(11, 21, 31, 1)
+    assert 1 + v1 == v1 + 1
+
+    # (with the switch to python2, we now allow ops between colors and tuples)
+    assert v1 + (1, 2, 3, 4) == Color(11, 22, 33, 4)
+    assert (1, 2, 3, 4) + v1 == v1 + (1, 2, 3, 4)
+
+    # Subtraction and negation.
+
+    v1 = Color(10, 20, 30, 0)
+    v2 = Color(30, 40, 50, 0)
+
+    assert v2 - v1 == Color(20, 20, 20, 0)
+    assert v1 - 1 == Color(9, 19, 29, -1)
+    assert 1 - v1 == - (v1 - 1)
+
+    # (with the switch to python2, we now allow ops between colors and tuples)
+    assert v1 - (1, 2, 3, 4) == Color(9, 18, 27, -4)
+    assert (1, 2, 3, 4) - v1 == - (v1 - (1, 2, 3, 4))
+
+    assert v1.negate() == Color(-10, -20, -30, 0)
+
+    # Multiplication.
+
+    v1 = Color(1, 2, 3, 0)
+    v2 = Color(3, 4, 5, 0)
+    
+    assert v1 * v2 == Color(3, 8, 15, 0)
+    assert v2 * v1 == v1 * v2
+    assert 2 * v1 == Color(2, 4, 6, 0)
+    assert v1 * 2 == 2 * v1
+
+    # (with the switch to python2, we now allow ops between colors and tuples)
+    assert v1 * (1, 2, 3, 4) == Color(1, 4, 9, 0)
+    assert (1, 2, 3, 4) * v1 == v1 * (1, 2, 3, 4)
+
+    # Division.
+
+    v1 = Color(10, 20, 40, 40)
+    v2 = Color(2, 4, 8, 8)
+    
+    assert v1 / v2 == Color(10/2, 20/4, 40/8, 40/8)
+    assert v1 / 2 == Color(10/2, 20/2, 40/2, 40/2)
+    assert Color(40) / v1 == Color(40/10, 40/20, 40/40, 40/40)
+
+    # (with the switch to python2, we now allow ops between colors and tuples)
+    assert v1 / (1, 4, 8, 20) == Color(10/1, 20/4, 40/8, 40/20)
+    assert Color(20, 60, 160, 40) / v1 == Color(20/10, 60/20, 160/40, 40/40)
+
+    # Color space conversion.
+
+    c1 = Color(maxComp, 0, 0, 0)
+
+    c2 = c1.rgb2hsv()
+    assert c2[0] == 0 and c2[1] == maxComp and c2[2] == maxComp and c2[3] == 0
+
+    c3 = c2.hsv2rgb()
+    assert c3[0] == maxComp and c3[1] == 0 and c3[2] == 0 and c3[3] == 0
+
+    print ("ok")
+
+    return
+
+def testColor4 ():
+
+    print ("Color4f")
+    testColor4x (Color4f, 1.0)
+    print ("Color4c")
+    testColor4x (Color4c, 255)
+
+testList.append (('testColor4',testColor4))
+
+
+# -------------------------------------------------------------------------
+# Tests for Color --> Color conversions
+
+def testColor3xConversions (Color):
+
+    v1 = Color(0, 1, 2)
+
+    v2 = Color3c (v1)
+    assert v2[0] == 0 and v2[1] == 1 and v2[2] == 2
+
+    v2 = Color3f (v1)
+    assert v2[0] == 0 and v2[1] == 1 and v2[2] == 2
+
+    print ("ok")
+    return
+
+
+def testColor4xConversions (Color):
+
+    v1 = Color(0, 1, 2, 3)
+
+    v2 = Color4c (v1)
+    assert v2[0] == 0 and v2[1] == 1 and v2[2] == 2 and v2[3] == 3
+
+    v2 = Color4f (v1)
+    assert v2[0] == 0 and v2[1] == 1 and v2[2] == 2 and v2[3] == 3
+
+    print ("ok")
+    return
+
+
+def testColor3xColor4xConversion (ColorA, ColorB):
+
+    try:
+        v = ColorA ();
+        v1 = ColorB (v);   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+
+def testColorConversions ():
+
+    print ("Color3c")
+    testColor3xConversions (Color3c)
+    print ("Color3f")
+    testColor3xConversions (Color3f)
+    print ("V3i")
+    testColor3xConversions (V3i)
+    print ("V3f")
+    testColor3xConversions (V3f)
+    print ("V3d")
+    testColor3xConversions (V3d)
+
+    print ("Color4c")
+    testColor4xConversions (Color4c)
+    print ("Color4f")
+    testColor4xConversions (Color4f)
+
+    print ("invalid conversions")
+    # Deliberatly not exhaustive, just representative.
+    testColor3xColor4xConversion (Color3c, Color4f)
+    testColor3xColor4xConversion (Color4c, Color3f)
+
+    print ("ok")
+    return
+
+
+testList.append (('testColorConversions',testColorConversions))
+
+
+# -------------------------------------------------------------------------
+# Tests for Frustumx
+
+def testFrustumx (Frustum, Vec3, Mat):
+    
+    # Constructors (and accessors).
+
+    f = Frustum()
+
+    nearPlane = 1
+    farPlane = 1000
+    left = -2
+    right = 2
+    top = 2
+    bottom = -2
+    ortho = 1
+
+    f = Frustum(nearPlane, farPlane, left, right, top, bottom, ortho)
+    assert f.nearPlane() == nearPlane and f.farPlane() == farPlane and \
+           f.left() == left and f.right() == right and \
+           f.bottom() == bottom and f.top() == top and \
+           f.orthographic() == ortho
+
+    # Repr.
+
+    f = Frustum(nearPlane, farPlane, left, right, top, bottom, ortho)
+    assert f.nearPlane() == nearPlane and f.farPlane() == farPlane and \
+           f.left() == left and f.right() == right and \
+           f.bottom() == bottom and f.top() == top and \
+           f.orthographic() == ortho
+    assert f.near() == nearPlane and f.far() == farPlane
+
+    # Assignment.
+
+    f1 = Frustum(nearPlane, farPlane, left, right, top, bottom, ortho)
+    
+    f2 = f1
+    assert f2.nearPlane() == f1.nearPlane() and f2.farPlane() == f1.farPlane() and \
+           f2.left() == f1.left() and f2.right() == f2.right() and \
+           f2.bottom() == f1.bottom() and f2.top() == f1.top() and \
+           f2.orthographic() == f1.orthographic()
+    assert f2.near() == f1.nearPlane() and f2.far() == f1.farPlane()
+
+    # Planes.
+
+    nearPlane = 1
+    farPlane = 2
+    left = -1
+    right = 1
+    top = 1
+    bottom = -1
+    ortho = 0
+    f = Frustum(nearPlane, farPlane, left, right, top, bottom, ortho)
+
+    p1 = f.planes();
+    
+    topN    = Vec3( 0, 1, 1).normalized()
+    rightN  = Vec3( 1, 0, 1).normalized()
+    bottomN = Vec3( 0,-1, 1).normalized()
+    leftN   = Vec3(-1, 0, 1).normalized()
+    nearPlaneN   = Vec3( 0, 0, 1)
+    farPlaneN    = Vec3( 0, 0,-1)
+    assert p1[0].normal() == topN and p1[0].distance() == 0
+    assert p1[1].normal() == rightN and p1[1].distance() == 0
+    assert p1[2].normal() == bottomN and p1[2].distance() == 0
+    assert p1[3].normal() == leftN and p1[3].distance() == 0
+    assert p1[4].normal() == nearPlaneN and p1[4].distance() == -nearPlane
+    assert p1[5].normal() == farPlaneN and p1[5].distance() == farPlane
+
+    m = Mat()
+    m.rotationMatrix(Vec3(0, 0,-1), (-1, 0, 0))
+    p2 = f.planes(m)
+
+    topN    = Vec3( 1, 1, 0).normalized()
+    rightN  = Vec3( 1, 0,-1).normalized()
+    bottomN = Vec3( 1,-1, 0).normalized()
+    leftN   = Vec3( 1, 0, 1).normalized()
+    nearPlaneN   = Vec3( 1, 0, 0)
+    farPlaneN    = Vec3(-1, 0, 0)
+    assert p2[0].normal().equalWithAbsError(topN, topN.baseTypeEpsilon())
+    assert p2[0].distance() == 0
+    assert p2[1].normal().equalWithAbsError(rightN, rightN.baseTypeEpsilon())
+    assert p2[1].distance() == 0
+    assert p2[2].normal().equalWithAbsError(bottomN, bottomN.baseTypeEpsilon())
+    assert p2[2].distance() == 0
+    assert p2[3].normal().equalWithAbsError(leftN, leftN.baseTypeEpsilon())
+    assert p2[3].distance() == 0
+    assert p2[4].normal().equalWithAbsError(nearPlaneN, nearPlaneN.baseTypeEpsilon())
+    assert equal(p2[4].distance(), -nearPlane, 2 * nearPlaneN.baseTypeEpsilon())
+    assert p2[5].normal().equalWithAbsError(farPlaneN, farPlaneN.baseTypeEpsilon())
+    assert equal(p2[5].distance(), farPlane, 2 * farPlaneN.baseTypeEpsilon())
+
+    m_near = f.nearPlane() - 0.1
+    m_far = f.farPlane() + 100
+    f.modifyNearAndFar(m_near, m_far)
+    assert equal(f.nearPlane(), m_near, 2 * farPlaneN.baseTypeEpsilon())
+    assert equal(f.farPlane(), m_far, 2 * farPlaneN.baseTypeEpsilon())
+
+    # Fovy, aspect, projection matrix.
+
+    nearPlane = 1
+    farPlane = 2
+    left = -1
+    right = 1
+    top = 1
+    bottom = -1
+    ortho = 0
+    f = Frustum(nearPlane, farPlane, left, right, top, bottom, ortho)
+
+    assert equal(f.fovx(), pi / 2.0, Vec3().baseTypeEpsilon())
+    assert equal(f.aspect(), 1, Vec3().baseTypeEpsilon())
+
+    m = f.projectionMatrix()
+    C = -(farPlane + nearPlane) / (farPlane - nearPlane)
+    D = (-2 * farPlane * nearPlane) / (farPlane - nearPlane)
+    E = 2 * nearPlane / (right - left)
+    F = 2 * nearPlane / (top - bottom)
+    assert m[0][0] == E
+    assert m[1][1] == F
+    assert m[2][2] == C
+    assert m[3][2] == D
+    # constructor w/ fov and aspect
+    g = Frustum(nearPlane, farPlane, f.fovx(), f.fovy(), f.aspect())
+    assert (g == f)
+
+    # Window.
+
+    nearPlane = 2
+    farPlane = 4
+    left = -2
+    right = 2
+    top = 2
+    bottom = -2
+    ortho = 0
+    f1 = Frustum(nearPlane, farPlane, left, right, top, bottom, ortho)
+
+    left2 = -0.5
+    right2 = 0.5
+    top2 = 0.25
+    bottom2 = -0.25
+    f2 = f1.window(left2, right2, top2, bottom2)
+    assert f2.left() == -1 and f2.right() == 1
+    assert f2.top() == 0.5 and f2.bottom() == -0.5
+
+    # Project screen to ray, point to screen.
+
+    nearPlane = 1
+    farPlane = 2
+    left = -1
+    right = 1
+    top = 1
+    bottom = -1
+    ortho = 0
+    f = Frustum(nearPlane, farPlane, left, right, top, bottom, ortho)
+
+    s = 0.5
+    t = 0.5
+    l = f.projectScreenToRay((s, t))
+    
+    p3d = Vec3(left + (right - left) * (1 + s) / 2.0,
+             bottom + (top - bottom) * (1 + t) / 2.0, -nearPlane)
+    assert iszero(l.distanceTo(p3d), 2 * p3d.baseTypeEpsilon())
+
+    p2d = f.projectPointToScreen(p3d)
+    assert p2d.equalWithAbsError((s, t), p2d.baseTypeEpsilon())
+
+    p3df = V3f (p3d)
+    p2d = f.projectPointToScreen(p3df)
+    assert p2d.equalWithAbsError((s, t), p2d.baseTypeEpsilon())
+
+    p3dd = V3d (p3d)
+    p2d = f.projectPointToScreen(p3dd)
+    assert p2d.equalWithAbsError((s, t), p2d.baseTypeEpsilon())
+    ortho = 1
+    f = Frustum(nearPlane, farPlane, left, right, top, bottom, ortho)
+    s = 0.5
+    t = 0.5
+    l = f.projectScreenToRay((s, t))
+    assert equalWithRelError (l.pos(), V3f(0.5, 0.5, 0), 0.001)
+    assert equalWithRelError (l.dir(), V3f(0.0, 0.0, -1), 0.001)    
+
+    p2d = f.projectPointToScreen(p3d)
+    assert equalWithRelError (p2d, V2f(0.5, 0.5), 0.001)
+    
+    # Conversion between depth and Z.
+
+    f = Frustum()
+    zMin = 1
+    zMax = 100
+    
+    assert round(f.ZToDepth(zMin, zMin, zMax)) == round(-f.nearPlane())
+    assert round(f.ZToDepth(zMax, zMin, zMax)) == round(-f.farPlane())
+    assert (f.near() == f.nearPlane())
+    assert (f.far() == f.farPlane())
+
+    assert round(f.normalizedZToDepth(-1)) == round(-f.nearPlane())
+    assert round(f.normalizedZToDepth(1)) == round(-f.farPlane())
+
+    assert f.DepthToZ(-f.nearPlane(), zMin, zMax) == zMin
+    assert f.DepthToZ(-f.farPlane(), zMin, zMax) == zMax
+    f.setOrthographic(True)
+    assert equalWithRelErrorScalar (f.normalizedZToDepth(-1), 999.8, 0.01)
+    assert equalWithRelErrorScalar (f.DepthToZ(-f.nearPlane(), zMin, zMax), 1.0, 0.001)
+    assert equalWithRelErrorScalar (f.DepthToZ(-f.farPlane(), zMin, zMax), 100.0, 0.001)
+    
+    # Screen and world radius conversion.
+
+    nearPlane = 1
+    farPlane = 10
+    left = -1
+    right = 1
+    top = 1
+    bottom = -1
+    ortho = 0
+    f = Frustum(nearPlane, farPlane, left, right, top, bottom, ortho)
+
+    d = 4
+    s = 0.75
+    r1 = f.screenRadius((0, 0, -d), d * s)
+    assert equal(r1, s, Vec3().baseTypeEpsilon())
+
+    r2 = f.worldRadius((0, 0, -d), r1)
+    assert equal(r2, d * s, Vec3().baseTypeEpsilon())
+
+    print ("ok")
+
+    return
+
+def testFrustum ():
+
+    print ("Frustumf")
+    testFrustumx (Frustumf, V3f, M44f)
+
+testList.append (('testFrustum',testFrustum))
+
+
+# -------------------------------------------------------------------------
+# Tests for random number generators
+
+def testRandomCompare (r1a, r1b, r1c, r2):
+    n = 10
+    nMatch1a1b = 0
+    nMatch1a1c = 0
+    nMatch1a2 = 0
+    for i in range(n):
+        a = r1a()
+        b = r1b()
+        c = r1c()
+        d = r2()
+        if (a == b): nMatch1a1b = nMatch1a1b + 1
+        if (a == c): nMatch1a1c = nMatch1a1c + 1
+        if (a == d): nMatch1a2 = nMatch1a2 + 1
+    assert nMatch1a1b == n
+    assert nMatch1a1c == n
+    assert nMatch1a2 < n
+    
+def testRandomCompareSphere (r1a, r1b, r1c, r2, type):
+    n = 10
+    nMatch1a1b = 0
+    nMatch1a1c = 0
+    nMatch1a2 = 0
+    for i in range(n):
+        a = r1a(type)
+        b = r1b(type)
+        c = r1c(type)
+        d = r2(type)
+        if (a == b): nMatch1a1b = nMatch1a1b + 1
+        if (a == c): nMatch1a1c = nMatch1a1c + 1
+        if (a == d): nMatch1a2 = nMatch1a2 + 1
+    assert nMatch1a1b == n
+    assert nMatch1a1c == n
+    assert nMatch1a2 < n
+    
+def testRandomx (Rand):
+
+    # Same/different seeds produces same/different sequences.
+
+    r1a = Rand(1)
+    r1b = Rand(1)
+    r1c = Rand(r1a)
+    r2 = Rand(2)
+    
+    testRandomCompare(r1a.nextb, r1b.nextb, r1c.nextb, r2.nextb)
+    testRandomCompare(r1a.nexti, r1b.nexti, r1c.nexti, r2.nexti)
+    testRandomCompare(r1a.nextf, r1b.nextf, r1c.nextf, r2.nextf)
+    testRandomCompareSphere(r1a.nextSolidSphere, r1b.nextSolidSphere, \
+                            r1c.nextSolidSphere, r2.nextSolidSphere, V2f())
+    testRandomCompareSphere(r1a.nextSolidSphere, r1b.nextSolidSphere, \
+                            r1c.nextSolidSphere, r2.nextSolidSphere, V2d())
+    testRandomCompareSphere(r1a.nextSolidSphere, r1b.nextSolidSphere, \
+                            r1c.nextSolidSphere, r2.nextSolidSphere, V3f())
+    testRandomCompareSphere(r1a.nextSolidSphere, r1b.nextSolidSphere, \
+                            r1c.nextSolidSphere, r2.nextSolidSphere, V3f())
+    testRandomCompareSphere(r1a.nextHollowSphere, r1b.nextHollowSphere, \
+                            r1c.nextHollowSphere, r2.nextHollowSphere, V2f())
+    testRandomCompareSphere(r1a.nextHollowSphere, r1b.nextHollowSphere, \
+                            r1c.nextHollowSphere, r2.nextHollowSphere, V2d())
+    testRandomCompareSphere(r1a.nextHollowSphere, r1b.nextHollowSphere, \
+                            r1c.nextHollowSphere, r2.nextHollowSphere, V3f())
+    testRandomCompareSphere(r1a.nextHollowSphere, r1b.nextHollowSphere, \
+                            r1c.nextHollowSphere, r2.nextHollowSphere, V3f())
+    testRandomCompare(r1a.nextGauss, r1b.nextGauss, r1c.nextGauss, \
+                      r2.nextGauss)
+    testRandomCompareSphere(r1a.nextGaussSphere, r1b.nextGaussSphere, \
+                            r1c.nextGaussSphere, r2.nextGaussSphere, V2f())
+    testRandomCompareSphere(r1a.nextGaussSphere, r1b.nextGaussSphere, \
+                            r1c.nextGaussSphere, r2.nextGaussSphere, V2d())
+    testRandomCompareSphere(r1a.nextGaussSphere, r1b.nextGaussSphere, \
+                            r1c.nextGaussSphere, r2.nextGaussSphere, V3f())
+    testRandomCompareSphere(r1a.nextGaussSphere, r1b.nextGaussSphere, \
+                            r1c.nextGaussSphere, r2.nextGaussSphere, V3f())
+
+    # Init (if it works for one type, it should work for all).
+
+    r = Rand(10)
+    seq = []
+    n = 10
+    for i in range(n):
+        seq.append(r.nextb())
+    r.init(10)
+    for i in range(n):
+        assert r.nextb() == seq[i]
+
+    print ("ok")
+
+    return
+
+def testRandom ():
+
+    print ("Rand32")
+    testRandomx (Rand32)
+    print ("Rand48")
+    testRandomx (Rand48)
+    
+testList.append (('testRandom',testRandom))
+
+# -------------------------------------------------------------------------
+# Tests C4xArrays
+def testC4xArray(Array, Color, Arrayx):
+    a = Array (3)
+
+    a[0] = Color(0)
+    a[1] = Color(1)
+    a[2] = Color(2)
+
+    assert a[0] == Color(0)
+    assert a[1] == Color(1)
+    assert a[2] == Color(2)
+
+    # Element setting.
+
+    a = Array(2)
+
+    try:
+        a[-3] = Color(0) # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0            # We shouldn't get here.   
+
+    try:
+        a[3] = Color(0)   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        a[1] = "a"         # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    a = Array(2)
+    a[0] = Color(0)
+    a[1] = Color(1)
+
+    # Array Component access
+    
+    ar = Arrayx(2)
+    ag = Arrayx(2)
+    ab = Arrayx(2)
+    aa = Arrayx(2)
+    ar[:] = a.r
+    ag[:] = a.g
+    ab[:] = a.b
+    aa[:] = a.a
+
+    assert ar == a.r
+    assert ag == a.g
+    assert ab == a.b
+    assert aa == a.a
+
+    a.r[0] = 1
+    assert ar != a.r
+
+
+def testC4Array ():
+    print ("C4fArray")
+    testC4xArray (C4fArray, Color4f, FloatArray)
+    print ("C4cArray")
+    testC4xArray (C4cArray, Color4c, UnsignedCharArray)
+
+testList.append (('testC4Array',testC4Array))
+
+# -------------------------------------------------------------------------
+# Tests C3xArrays
+def testC3xArray(Array, Color, Arrayx):
+    a = Array (3)
+
+    a[0] = Color(0)
+    a[1] = Color(1)
+    a[2] = Color(2)
+
+    assert a[0] == Color(0)
+    assert a[1] == Color(1)
+    assert a[2] == Color(2)
+
+    # Element setting.
+
+    a = Array(2)
+
+    try:
+        a[-3] = Color(0) # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0         # We shouldn't get here.   
+
+    try:
+        a[3] = Color(0)   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0        # We shouldn't get here.
+
+    try:
+        a[1] = "a"      # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0        # We shouldn't get here.
+
+    # Assignment.
+
+    a = Array(2)
+    a[0] = Color(0)
+    a[1] = Color(1)
+
+    # Array Component access
+    
+    ar = Arrayx(2)
+    ag = Arrayx(2)
+    ab = Arrayx(2)
+    ar[:] = a.r
+    ag[:] = a.g
+    ab[:] = a.b
+
+    assert ar == a.r
+    assert ag == a.g
+    assert ab == a.b
+
+    a.r[0] = 1
+    assert ar != a.r
+
+
+def testC3xExplicitConversion(Array):
+
+     # explicit constructors from Vec3 types
+    af = V3fArray(3)
+    af[0] = V3f(0)
+    af[1] = V3f(1)
+    af[2] = V3f(2)
+    a = Array(af);
+    assert af[0] == V3f(a[0])
+    assert af[1] == V3f(a[1])
+    assert af[2] == V3f(a[2])
+
+    ad = V3dArray(3)
+    ad[0] = V3d(0)
+    ad[1] = V3d(1)
+    ad[2] = V3d(2)
+    a = Array(ad);
+    assert ad[0] == V3d(a[0])
+    assert ad[1] == V3d(a[1])
+    assert ad[2] == V3d(a[2])
+
+def testC3Array ():
+    print ("C3fArray")
+    testC3xArray (C3fArray, Color3f, FloatArray)
+    testC3xExplicitConversion(C3fArray)
+    print ("C3cArray")
+    testC3xArray (C3cArray, Color3c, UnsignedCharArray)
+
+testList.append (('testC3Array',testC3Array))
+
+# -------------------------------------------------------------------------
+# Verify that floating-point exceptions, both in Imath and in Python,
+# raise Python exceptions rather than causing crashes.
+
+def testFpExceptions():
+
+    try:
+        f = sqrt (-1)
+        print (f)
+    except ValueError:
+        pass
+    except OverflowError:
+        pass
+    else:
+        assert 0
+
+    try:
+        f = sqrt (-1)
+        print (f)
+    except ValueError:
+        pass
+    except OverflowError:
+        pass
+    else:
+        assert 0
+
+    try:
+        f = 1 / 0
+        print (f)
+    except ZeroDivisionError:
+        pass
+    else:
+        assert 0
+
+    print ("ok")
+    return
+
+testList.append (('testFpExceptions',testFpExceptions))
+
+def testProcrustes():
+    m = M44d()
+    m.translate (V3d(10, 5, 0))
+
+    r = Eulerd (pi, pi/4.0, 0)
+    m = m * r.toMatrix44()
+
+    n = 8
+    f = []
+    t = []
+    w = []
+    for i in range (n):
+        theta = 2.0 * pi * float(i)/float(n)
+        fromVec = V3d(cos(theta), sin(theta), 0)
+        w.append (1)
+        f.append (fromVec)
+        t.append (fromVec * m)
+
+    result = procrustesRotationAndTranslation (f, t, None, False)
+    for i in range(n):
+        res = f[i] * result
+        assert ((res - t[i]).length2() < 1e-5)
+
+    # Test it with arrays:
+    r = Rand48(145)
+    f1 = V3dArray (n)
+    t1 = V3dArray (n)
+    for i in range(n):
+        fromVec = V3d (r.nextf(), r.nextf(), r.nextf())
+        f1[i] = fromVec
+        t1[i] = fromVec * m
+    result = procrustesRotationAndTranslation (f1, t1, None, False)
+    for i in range(n):
+        res = f1[i] * result
+        assert ((res - t1[i]).length2() < 1e-5)
+
+    # Verify weights:
+    f.append (V3d(0,0,0))
+    t.append (V3d(10000,10000,100))
+    w.append (0.0)
+    result = procrustesRotationAndTranslation (f, t, w, False)
+    for i in range(n):
+        res = f[i] * result
+        assert ((res - t[i]).length2() < 1e-5)
+   
+testList.append (('testProcrustes',testProcrustes))
+
+def testSVD():
+    # We'll just test the Python wrapper here; for comprehensive SVD tests,
+    # please see ImathToolboxTest.
+    # 4x4
+    m = M44d()
+    [U, S, V] = m.singularValueDecomposition(False)
+
+    eps = 1e-4
+    def sameMatrix44 (m1, m2):
+        for i in range(4):
+            for j in range(4):
+                if (abs(m1[i][j] - m2[i][j]) > eps):
+                    return False
+        return True
+
+    def sameVector4 (v1, v2):
+        for i in range(4):
+            if (abs(v1[i] - v2[i]) > eps):
+                return False
+        return True
+
+    assert (sameMatrix44(U, M44d()));
+    assert (sameMatrix44(V, M44d()));
+    assert (sameVector4(S, V4d(1,1,1,1)))
+
+    def checkSVD44(m):
+        [U, S, V] = m.singularValueDecomposition(True)
+        assert (sameMatrix44(U*U.transposed(), M44d()))
+        assert (sameMatrix44(V*V.transposed(), M44d()))
+        for i in range(3):
+            assert S[i] >= 0
+
+        assert (U.determinant() > 0)
+        assert (V.determinant() > 0)
+
+        sDiag = M44d()
+        for i in range(4):
+            sDiag[i][i] = S[i]
+        assert (sameMatrix44(U*sDiag*V.transposed(), m))
+
+        [U2, S2, V2] = m.singularValueDecomposition(False)
+        for i in range(4):
+            assert (S2[i] >= 0)
+        for i in range(3):
+            assert (abs(S[i] - S2[i]) < eps)
+        assert (abs(abs(S[3]) - S2[3]) < eps)
+
+    scaleMatrix = M44d()
+    scaleMatrix.setScale (V3d(1, 2, 3))
+    m = m * scaleMatrix
+    checkSVD44(m)
+
+    e = Eulerd (20, 30, 40)
+    m = m * e.toMatrix44()
+    checkSVD44(m)
+
+    scaleMatrix.setScale (V3d(-3, 2, 3))
+    m = m * e.toMatrix44()
+    checkSVD44(m)
+    
+    # 3x3
+    m = M33d()
+    [U, S, V] = m.singularValueDecomposition(False)
+
+    eps = 1e-4
+    def sameMatrix33 (m1, m2):
+        for i in range(3):
+            for j in range(3):
+                if (abs(m1[i][j] - m2[i][j]) > eps):
+                    return False
+        return True
+
+    def sameVector3 (v1, v2):
+        for i in range(3):
+            if (abs(v1[i] - v2[i]) > eps):
+                return False
+        return True
+
+    assert (sameMatrix33(U, M33d()));
+    assert (sameMatrix33(V, M33d()));
+    assert (sameVector3(S, V3d(1,1,1)))
+
+    def checkSVD33(m):
+        [U, S, V] = m.singularValueDecomposition(True)
+        assert (sameMatrix33(U*U.transposed(), M33d()))
+        assert (sameMatrix33(V*V.transposed(), M33d()))
+        for i in range(3):
+            assert S[i] >= 0
+
+        assert (U.determinant() > 0)
+        assert (V.determinant() > 0)
+
+        sDiag = M33d()
+        for i in range(3):
+            sDiag[i][i] = S[i]
+        assert (sameMatrix33(U*sDiag*V.transposed(), m))
+
+        [U2, S2, V2] = m.singularValueDecomposition(False)
+        for i in range(2):
+            assert (S2[i] >= 0)
+        for i in range(2):
+            assert (abs(S[i] - S2[i]) < eps)
+        assert (abs(abs(S[2]) - S2[2]) < eps)
+
+    scaleMatrix = M33d (1, 0, 0, 0, 2, 0, 0, 0, 3)
+    m = m * scaleMatrix
+    checkSVD33(m)
+
+    e = Eulerd (20, 30, 40)
+    m = m * e.toMatrix33()
+    checkSVD33(m)
+
+    scaleMatrix = M33d (-3, 0, 0, 0, 2, 0, 0, 0, 3)
+    m = m * e.toMatrix33()
+    checkSVD33(m)
+
+testList.append (('testSVD',testSVD))
+
+def testSymmetricEigensolve():
+    # We'll just test the Python wrapper here; for comprehensive eigensolver tests,
+    # please see ImathToolboxTest.
+    # 4x4
+
+    eps = 1e-4
+    def sameMatrix44 (m1, m2):
+        for i in range(4):
+            for j in range(4):
+                if (abs(m1[i][j] - m2[i][j]) > eps):
+                    return False
+        return True
+
+    def sameVector4 (v1, v2):
+        for i in range(4):
+            if (abs(v1[i] - v2[i]) > eps):
+                return False
+        return True
+    
+    m = M44d()
+    [Q, S] = m.symmetricEigensolve()
+    assert (sameMatrix44 (Q, M44d()))
+    assert (sameVector4 (S, V4d(1,1,1,1)))
+
+    m = M44d(2, 4, 3,  6,
+             4, 1, 9,  7,
+             3, 9, 10, 13,
+             6, 7, 13, 27);
+    [Q, S] = m.symmetricEigensolve()
+    assert (sameMatrix44(Q*Q.transposed(), M44d()))
+
+    sDiag = M44d()
+    for i in range(4):
+        sDiag[i][i] = S[i]
+    assert (sameMatrix44 (Q * sDiag * Q.transposed(), m))
+
+    # Verify that it checks for symmetry:
+    m[2][3] = 1000
+    try:
+        m.symmetricEigensolve()
+    except ValueError:
+        pass
+    else:
+        assert 0
+
+    def sameMatrix33 (m1, m2):
+        for i in range(3):
+            for j in range(3):
+                if (abs(m1[i][j] - m2[i][j]) > eps):
+                    return False
+        return True
+
+    def sameVector3 (v1, v2):
+        for i in range(3):
+            if (abs(v1[i] - v2[i]) > eps):
+                return False
+        return True
+    
+    m = M33d()
+    [Q, S] = m.symmetricEigensolve()
+    assert (sameMatrix33 (Q, M33d()))
+    assert (sameVector3 (S, V3d(1,1,1)))
+
+    m = M33d(2, 4, 3,
+             4, 1, 9, 
+             3, 9, 10)
+    [Q, S] = m.symmetricEigensolve()
+    assert (sameMatrix33(Q*Q.transposed(), M33d()))
+
+    sDiag = M33d()
+    for i in range(3):
+        sDiag[i][i] = S[i]
+    assert (sameMatrix33 (Q * sDiag * Q.transposed(), m))
+
+    # Verify that it checks for symmetry:
+    m[1][2] = 1000
+    try:
+        m.symmetricEigensolve()
+    except ValueError:
+        pass
+    else:
+        assert 0
+
+
+
+testList.append (('testSymmetricEigensolve',testSymmetricEigensolve))
+
+# -------------------------------------------------------------------------
+# Tests MxArrays
+def testMxArray(Array, Matrix):
+    a = Array (3)
+
+    a[0] = Matrix(0)
+    a[1] = Matrix(1)
+    a[2] = Matrix(2)
+
+    assert a[0] == Matrix(0)
+    assert a[1] == Matrix(1)
+    assert a[2] == Matrix(2)
+
+    # Element setting.
+
+    a = Array(2)
+
+    try:
+        a[-3] = Matrix(0) # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0            # We shouldn't get here.   
+
+    try:
+        a[3] = Matrix(0)   # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    try:
+        a[1] = "a"         # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0           # We shouldn't get here.
+
+    # Assignment.
+
+    a = Array(2)
+    a[0] = Matrix(0)
+    a[1] = Matrix(1)
+
+    # Comparison.
+
+    m = Matrix(2)
+    a1 = Array(m, 3)
+    a2 = Array(m, 3)
+
+    testVectorVectorComparisonOps(a1, a2)
+    testVectorScalarComparisonOps(a1, m)
+
+def testM4Array(Array, Matrix, Vec, VecArray):
+
+    a = Array(3)
+    m0 = Matrix()
+    m0.setTranslation (Vec(1,2,3))
+    m1 = Matrix()
+    m1.setScale (Vec(.3,.2,.1))
+    m2 = Matrix()
+    m2.rotate (Vec(.3,.1,.2))
+
+    a[0] = m0
+    a[1] = m1
+    a[2] = m2
+
+    n = a.inverse()
+    assert n[0] == m0.inverse()
+    assert n[1] == m1.inverse()
+    assert n[2] == m2.inverse()
+
+    a.invert()
+    testVectorVectorComparisonOps(a, n)
+    
+    n0 = a[0]
+    n1 = a[2]
+    n2 = a[2]
+    a.transpose()
+    assert n[0].transposed() == a[0]
+    assert n[1].transposed() == a[1]
+    assert n[2].transposed() == a[2]
+
+    v = VecArray(3)
+    v[0] = Vec(11,17,3).normalized()
+    v[1] = Vec(7,19,31).normalized()
+    v[2] = Vec(23,5,13).normalized()
+   
+    V = a.multDirMatrix(v)
+    assert a[0].multDirMatrix(v[0]) == V[0]
+    assert a[1].multDirMatrix(v[1]) == V[1]
+    assert a[2].multDirMatrix(v[2]) == V[2]
+
+    V = a.multVecMatrix(v)
+    assert a[0].multVecMatrix(v[0]) == V[0]
+    assert a[1].multVecMatrix(v[1]) == V[1]
+    assert a[2].multVecMatrix(v[2]) == V[2]
+
+def testMatrixArray ():
+    print ("M44fArray")
+    testMxArray (M44fArray, M44f)
+    testM4Array (M44fArray, M44f, V3f, V3fArray)
+    print ("M44dArray")
+    testMxArray (M44dArray, M44d)
+    testM4Array (M44dArray, M44d, V3d, V3dArray)
+    print ("M33fArray")
+    testMxArray (M33fArray, M33f)
+    print ("M33dArray")
+    testMxArray (M33dArray, M33d)
+    print ("M22fArray")
+    testMxArray (M22fArray, M22f)
+    print ("M22dArray")
+    testMxArray (M22dArray, M22d)
+
+testList.append(("testMatrixArray",testMatrixArray))
+
+# -------------------------------------------------------------------------
+# Tests BoxxArrays
+def testBoxxArray(Array, Box, Vec):
+
+    b0 = Box(Vec(1), Vec(2))
+    b1 = Box(Vec(2), Vec(3))
+    b2 = Box(Vec(3), Vec(4))
+
+    a = Array (3)
+
+    a[0] = b0
+    a[1] = b1
+    a[2] = b2
+
+    assert a[0] == b0
+    assert a[1] == b1
+    assert a[2] == b2
+
+    # Element setting.
+
+    a = Array(2)
+
+    try:
+        a[-3] = b0      # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0        # We shouldn't get here.
+
+    try:
+        a[3] = b0       # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0        # We shouldn't get here.
+
+    try:
+        a[1] = "a"      # This should raise an exception.
+    except:
+        pass
+    else:
+        assert 0        # We shouldn't get here.
+
+    # Assignment.
+
+    a = Array(2)
+    a[0] = b0
+    a[1] = b1
+
+    # Comparison.
+
+    a1 = Array(b2, 3)
+    a2 = Array(b2, 3)
+
+    testVectorVectorComparisonOps(a1, a2)
+    testVectorScalarComparisonOps(a1, b2)
+
+def testBoxArray ():
+    print ("Box2iArray")
+    testBoxxArray (Box2iArray, Box2i, V2i)
+    print ("Box2sArray")
+    testBoxxArray (Box2sArray, Box2s, V2s)
+    print ("Box2fArray")
+    testBoxxArray (Box2fArray, Box2f, V2f)
+    print ("Box2dArray")
+    testBoxxArray (Box2dArray, Box2d, V2d)
+    print ("Box3iArray")
+    testBoxxArray (Box3iArray, Box3i, V3i)
+    print ("Box3sArray")
+    testBoxxArray (Box3sArray, Box3s, V3s)
+    print ("Box3fArray")
+    testBoxxArray (Box3fArray, Box3f, V3f)
+    print ("Box3dArray")
+    testBoxxArray (Box3dArray, Box3d, V3d)
+
+testList.append(("testBoxArray",testBoxArray))
+
+def testStringArray():
+
+    num = 10
+
+    s = StringArray(num)
+    s2 = StringArray(num)
+
+    assert((s != '').reduce() == 0)
+    assert((s == '').reduce() == num)
+
+    assert(('' != s).reduce() == 0)
+    assert(('' == s).reduce() == num)
+
+    assert((s != s2).reduce() == 0)
+    assert((s == s2).reduce() == num)
+  
+    id = IntArray(num)
+    id[:] = make_range(0,num)
+
+    s = StringArray('foo', num)
+    s2 = StringArray('a', num)
+    s2[:] = 'foo'
+
+    assert((s != 'foo').reduce() == 0)
+    assert((s == 'foo').reduce() == num)
+
+    assert(('foo' != s).reduce() == 0)
+    assert(('foo' == s).reduce() == num)
+    assert((s != s2).reduce() == 0)
+    assert((s == s2).reduce() == num)
+
+    s[id < num//2] = 'bar'
+    
+    assert((s != 'foo').reduce() == num//2)
+    assert((s == 'foo').reduce() == num//2)
+
+    assert(('foo' != s).reduce() == num//2)
+    assert(('foo' == s).reduce() == num//2)
+
+    assert((s != 'bar').reduce() == num//2)
+    assert((s == 'bar').reduce() == num//2)
+
+    assert(('bar' != s).reduce() == num//2)
+    assert(('bar' == s).reduce() == num//2)
+
+    assert((s != s2).reduce() == num//2)
+    assert((s == s2).reduce() == num//2)
+    
+    for i in range(0,num):
+        s2[i] = str(i)
+
+    for i in range(0,num):
+        assert(int(s2[i]) == i)
+
+    print ("should see {0} 'bar' and {1} 'foo'".format (num//2,num//2))
+    for m in s:
+        print (m)
+    print ("should see '0' through '{}'".format(num-1))
+    for m in s2:
+        print (m)
+
+    print ("ok")
+
+testList.append(("testStringArray",testStringArray))
+
+
+def testWstringArray():
+
+    num = 10
+
+    s = WstringArray(num)
+    s2 = WstringArray(num)
+
+    assert((s != '').reduce() == 0)
+    assert((s == '').reduce() == num)
+
+    assert(('' != s).reduce() == 0)
+    assert(('' == s).reduce() == num)
+
+    assert((s != s2).reduce() == 0)
+    assert((s == s2).reduce() == num)
+  
+    id = IntArray(num)
+    id[:] = make_range(0,num)
+
+    s = WstringArray(u'foo', num)
+    s2 = WstringArray(u'a', num)
+    s2[:] = u'foo'
+
+    assert((s != u'foo').reduce() == 0)
+    assert((s == u'foo').reduce() == num)
+
+    assert((u'foo' != s).reduce() == 0)
+    assert((u'foo' == s).reduce() == num)
+    assert((s != s2).reduce() == 0)
+    assert((s == s2).reduce() == num)
+
+    s[id < num//2] = u'bar'
+    
+    assert((s != u'foo').reduce() == num//2)
+    assert((s == u'foo').reduce() == num//2)
+
+    assert((u'foo' != s).reduce() == num//2)
+    assert((u'foo' == s).reduce() == num//2)
+
+    assert((s != u'bar').reduce() == num//2)
+    assert((s == u'bar').reduce() == num//2)
+
+    assert((u'bar' != s).reduce() == num//2)
+    assert((u'bar' == s).reduce() == num//2)
+
+    assert((s != s2).reduce() == num//2)
+    assert((s == s2).reduce() == num//2)
+    
+    for i in range(0,num):
+        s2[i] = str(i)
+
+    for i in range(0,num):
+        assert(int(s2[i]) == i)
+
+    print ("should see {0} 'bar' and {1} 'foo'".format(num//2,num//2))
+    for m in s:
+        print (m)
+    print ("should see '0' through '{}'".format(num-1))
+    for m in s2:
+        print (m)
+
+    print ("ok")
+
+testList.append(("testWstringArray",testWstringArray))
+
+
+def testVArrays():
+    '''
+    Test variable-length arrays.  Currently we only support an
+    VIntArray with very limited Python functionality.  This test
+    should be expanded when support for variable-length arrays
+    becomes more complete.
+    '''
+
+    num = 1000
+    a1 = VIntArray(num)
+    a2 = VIntArray(1, num)
+    a3 = VIntArray(a2)
+    assert(len(a1) == num)
+    assert(len(a2) == num)
+    assert(len(a3) == num)
+
+    # test constructor failure cases
+    failed = False
+    try:
+        VIntArray(-1)
+    except:
+        failed = True
+    assert(failed)
+
+    failed = False
+    try:
+        VIntArray(10,-1)
+    except:
+        failed = True
+    assert(failed)
+
+    assert(a2[0][0] == 1)
+    assert(a2[1][0] == 1)
+    assert(a2[2][0] == 1)
+    assert(a2[3][0] == 1)
+
+    # index out of bounds
+    failed = False
+    try:
+        a2[num]
+    except:
+        failed = True
+    assert(failed)
+
+
+    values = IntArray(1)
+    values[0] = 5
+
+    # test getitem and setitem
+    assert(len(a1[0]) == 0)
+    assert(len(a2[0]) == 1)
+    assert(len(a3[0]) == 1)
+    a2[0] = values
+    assert(a2[0][0] == 5)
+
+    # test getitem, negative indices
+    assert(len(a1[-1]) == 0)
+    assert(len(a2[-1]) == 1)
+    assert(len(a3[-1]) == 1)
+    a2[-1] = values
+    assert(a2[-1][0] == 5)
+
+    mask = IntArray(num)
+    mask[2] = 1
+    mask[3] = 1
+   
+    # test getitem and setitem with mask
+    assert(len(a2[mask]) == 2) # two elements from the original array
+    a2[mask] = values
+    assert(a2[0][0] == 5)
+    assert(a2[1][0] == 1)
+    assert(a2[2][0] == 5)
+    assert(a2[3][0] == 5)
+
+    a2[3][0] = 6
+    assert(a2[3][0] == 6)
+    a2m = a2[mask] # masked to [2,3]
+    a2ms = a2m[1:2:1] # sliced to [2]
+    a2msa = a2ms[0] # indexed to the elemnt 3 array
+    assert(a2msa[0] == 6) # test slice on mask
+
+    # test slice assignment in masked array
+    tmpValues = IntArray(9,1)
+    a2m[1:2:1] = tmpValues
+    assert(a2[3][0] == 9)
+
+    tmpValues = IntArray(9,2)
+    tmpValuesMask = IntArray(2)
+    tmpValuesMask[1] = 1
+    tmpValues[1] = 15
+    a2m[1:2:1] = tmpValues[tmpValuesMask]
+    assert(a2[3][0] == 15)
+
+    # mismatched length on RHG
+    failed = False
+    try:
+        a2m[1:2:1] = tmpValues
+    except:
+        failed = True
+    assert(failed)
+
+    tmpValues[1] = 17
+    a2[3:4:1] = tmpValues[tmpValuesMask]
+    assert(a2[3][0] == 17)
+
+    # mismatched length on RHG
+    failed = False
+    try:
+        a2[3:4:1] = tmpValues
+    except:
+        failed = True
+    assert(failed)
+
+    a2[mask] = tmpValues[tmpValuesMask]
+
+    # test getitem and setitem with slice
+    values[:] = 7
+    assert(len(a2[1:4:2]) == 2) # two elements from the original array
+    a2[1:4:2] = values
+    assert(a2[0][0] == 5)
+    assert(a2[1][0] == 7)
+    assert(a2[2][0] == 17)
+    assert(a2[3][0] == 7)
+
+    # test size property setitem and getitem
+    a1.size[0] = 10
+    assert(len(a1[0]) == 10)
+    assert(a1.size[0] == 10)
+
+    # test internal reference handling
+    a10 = a1[0]
+    a10[9] = 15
+    del a10
+    a10 = a1[0]
+    assert(a10[9] == 15)
+
+    #  Some tests for Variable V2is
+
+    print ("Testing VV2i...")
+    failed = False
+    try:
+        VV2iArray(-1)
+    except:
+        failed = True
+    assert(failed)
+
+    failed = False
+    try:
+        VV2iArray(10,-1)
+    except:
+        failed = True
+    assert(failed)
+
+    defaults2i = V2iArray(1)
+    defaults2i[0] = V2i(17,31)
+
+    a = VV2iArray (defaults2i[0], 5)
+    count = 0
+    for elem in a:
+        assert (elem == V2i(17,31))
+        count += 1
+    assert (count == 5)
+
+    failed = False
+    try:
+        print ("If you see a value here it's bogus: {}".format(a[-6]))
+    except:
+        failed = True
+    assert (failed)
+    print ("")
+
+    #  Some tests for Variable floats
+
+    print ("Testing VFloat...")
+    failed = False
+    try:
+        VFloatArray(-1)
+    except:
+        failed = True
+    assert(failed)
+
+    failed = False
+    try:
+        VFloatArray(10.,-1)
+    except:
+        failed = True
+    assert(failed)
+
+    value0 = 42.23
+    value1 = 2.
+    defaultsFloats = VFloatArray(1,2)
+    defaultsFloats[0] = FloatArray(value0, 1)
+    defaultsFloats[1] = FloatArray(value1, 1)
+
+    a = VFloatArray (defaultsFloats[1][0], 7)
+    count = 0
+    for elem in a:
+        assert (len(elem) == 1)
+        assert (elem[0]  == value1)
+        assert (elem[-1] == value1)
+        count += 1
+    assert (count == 7 and len(a) == count)
+
+    failed = False
+    try:
+        print ("If you see a value here it's bogus: {}".format(a[8]))
+    except:
+        failed = True
+    assert (failed)
+    print ("")
+
+    # See the 'PyImath/varraySemantics.txt' document for more information.
+
+testList.append(("testVArrays", testVArrays))
+
+
+def testReadOnlyBasic(AType, val):
+    '''
+    Tests the basic operation, features, and expectations of a read-only
+    fixed array.  Makes sure the writeable state is accurate and errors
+    are thrown if we try to modify a read-only array.  Also makes sures
+    that values returned from arrays are as expected, depending on the 
+    writable state of the array (i.e. copies of array values or direct
+    references to those array values).
+    '''
+
+    a = AType(13)
+    assert (len(a) == 13)
+    assert (a.writable() == True)
+
+    for i in range(5):
+        a[i] = val
+    for i in range(5):
+        assert (equalWithAbsError(a[i], val, eps) == True)
+    for i in range(5,13):
+        assert (equalWithAbsError(a[i], val, eps) == False)
+
+    # Test '__getitem__' subtleties for array items.
+    if hasattr(a[0], 'setValue'):
+        l = len(a[0])
+        # Vector-type arrays.
+        if l == 2:
+            for i in range(13):
+                a[i].setValue(101, 102)
+            for i in range(13):
+                assert (equalWithAbsError(a[i].x, 101, eps) == True)
+                assert (equalWithAbsError(a[i].y, 102, eps) == True)
+            for i in range(5):
+                v = a[i]
+                v.setValue(val.x, val.y)
+        elif l == 3:
+            for i in range(13):
+                a[i].setValue(101, 102, 103)
+            for i in range(13):
+                assert (equalWithAbsError(a[i].x, 101, eps) == True)
+                assert (equalWithAbsError(a[i].y, 102, eps) == True)
+                assert (equalWithAbsError(a[i].z, 103, eps) == True)
+            for i in range(5):
+                v = a[i]
+                v.setValue(val.x, val.y, val.z)
+
+        for i in range(5):
+            assert (equalWithAbsError(a[i], val, eps) == True)
+        for i in range(5,13):
+            assert (equalWithAbsError(a[i], val, eps) == False)
+
+    b = a
+    c = AType (a)
+    assert (len(b) == 13)
+    assert (len(c) == 13)
+    assert (b.writable() == True)
+    assert (c.writable() == True)
+
+    for i in range(5):
+        assert (equalWithAbsError(b[i], val, eps) == True)
+        assert (equalWithAbsError(c[i], val, eps) == True)
+    for i in range(5,13):
+        assert (equalWithAbsError(b[i], val, eps) == False)
+        assert (equalWithAbsError(c[i], val, eps) == False)
+
+    # Make the array 'read only'.
+
+    a.makeReadOnly()
+    assert (len(a) == 13)
+    assert (a.writable() == False)
+
+    b = a
+    c = AType (a)
+    assert (len(b) == 13)
+    assert (len(c) == 13)
+    assert (b.writable() == False)
+    assert (c.writable() == False)
+
+    for i in range(5):
+        assert (equalWithAbsError(a[i], val, eps) == True)
+        assert (equalWithAbsError(b[i], val, eps) == True)
+        assert (equalWithAbsError(c[i], val, eps) == True)
+    for i in range(5,13):
+        assert (equalWithAbsError(a[i], val, eps) == False)
+        assert (equalWithAbsError(b[i], val, eps) == False)
+        assert (equalWithAbsError(c[i], val, eps) == False)
+
+    # These should all fail because the array is read-only.
+    try:
+        a[3] = val
+    except:
+        pass
+    else:
+        assert(False)
+    try:
+        a[5] = val
+    except:
+        pass
+    else:
+        assert(False)
+    try:
+        a[8:10] = val
+    except:
+        pass
+    else:
+        assert(False)
+
+    # Continue to test '__getitem__' subtleties for array items.
+    if hasattr(a[0], 'setValue'):
+        l = len(a[0])
+        # Vector-type arrays.
+        if l == 2:
+            for i in range(13):
+                a[i].setValue(201, 202)
+            # For read-only arrays, the setValue should be operating
+            # on copies of the vaslues.  Because of that, the values
+            # should not have actually changed.
+            for i in range(13):
+                assert (equalWithAbsError(a[i].x, 201, eps) == False)
+                assert (equalWithAbsError(a[i].y, 202, eps) == False)
+        elif l == 3:
+            for i in range(13):
+                a[i].setValue(201, 202, 203)
+            # For read-only arrays, the setValue should be operating
+            # on copies of the vaslues.  Because of that, the values
+            # should not have actually changed.
+            for i in range(13):
+                assert (equalWithAbsError(a[i].x, 201, eps) == False)
+                assert (equalWithAbsError(a[i].y, 202, eps) == False)
+                assert (equalWithAbsError(a[i].z, 203, eps) == False)
+
+        for i in range(5):
+            assert (equalWithAbsError(a[i], val, eps) == True)
+        for i in range(5,13):
+            assert (equalWithAbsError(a[i], val, eps) == False)
+
+    print ("ok")
+
+testList.append(("testReadOnlyBasicInt",
+                 lambda : testReadOnlyBasic(IntArray, 7)))
+testList.append(("testReadOnlyBasicFloat",
+                 lambda : testReadOnlyBasic(FloatArray, 1.234)))
+testList.append(("testReadOnlyBasicV3f",
+                 lambda : testReadOnlyBasic(V3fArray, V3f(1.2, 3.4, 5.6))))
+testList.append(("testReadOnlyBasicV2i",
+                 lambda : testReadOnlyBasic(V2iArray, V2i(8, 9))))
+
+
+def testVectorVectorInPlaceArithmeticOpsReadOnly(f1, f2,
+                                                 shouldFail = True):
+    assert(len(f1) == len(f2))
+
+    try:    f1 += f2
+    except: pass
+    else:   assert(not shouldFail)
+
+    try:    f1 -= f2
+    except: pass
+    else:   assert(not shouldFail)
+
+    try:    f1 *= f2
+    except: pass
+    else:   assert(not shouldFail)
+
+    try:    f1 /= f2
+    except: pass
+    else:   assert(not shouldFail)
+
+def testVectorScalarInPlaceArithmeticOpsReadOnly(f1, v):
+    try:    f1 += v
+    except: pass
+    else:   assert(False)
+
+    try:    f1 -= v
+    except: pass
+    else:   assert(False)
+
+    try:    f1 *= v
+    except: pass
+    else:   assert(False)
+
+    try:    f1 /= v
+    except: pass
+    else:   assert(False)
+
+def testVectorVectorMaskedInPlaceArithmeticOpsReadOnly(f1, f2, m,
+                                                       shouldFail = True):
+    assert(len(f1) == len(f2))
+    assert(len(f1) == len(m ));
+
+    try:    f1[m] += f2
+    except: pass
+    else:   assert(not shouldFail)
+
+    try:    f1[m] -= f2
+    except: pass
+    else:   assert(not shouldFail)
+
+    try:    f1[m] *= f2
+    except: pass
+    else:   assert(not shouldFail)
+
+    try:    f1[m] /= f2
+    except: pass
+    else:   assert(not shouldFail)
+
+def testVectorVectorMaskedInPlaceArithmeticOps2ReadOnly(f1, f2, m,
+                                                        shouldFail = True):
+    assert(len(f1) == len(m))
+    assert(len(f1[m]) == len(f2))
+
+    try:    f1[m] += f2
+    except: pass
+    else:   assert(not shouldFail)
+
+    try:    f1[m] -= f2
+    except: pass
+    else:   assert(not shouldFail)
+
+    try:    f1[m] *= f2
+    except: pass
+    else:   assert(not shouldFail)
+
+    try:    f1[m] /= f2
+    except: pass
+    else:   assert(not shouldFail)
+
+def testUnaryVecMethodsReadOnly(f):
+    g = f.length()
+    assert(len(g) == len(f))
+    for i in range(0, len(f)):
+        assert(equalWithRelError(g[i], f[i].length(), eps))
+
+    g = f.length2()
+    assert(len(g) == len(f))
+    for i in range(0, len(f)):
+        assert(g[i] == f[i].length2())
+
+    # Normalization only makes sense for these types
+    try:    f.normalize()
+    except: pass
+    else:   assert(False)
+
+    g = f.normalized()
+    assert(len(g) == len(f))
+    for i in range(0, len(f)):
+        assert(g[i] == f[i].normalized())
+
+def testReadOnlyAutoVect(ArrayType, val1, val2):
+    '''
+    Tests the auto-vectorized functions operating on read-only arrays.
+    Generally it is ok if a read-only array is used in a vectorized function
+    if its values are just read (used), but errors should be thrown if the
+    auto-vectorized function tries to modify a read-only array.
+    '''
+
+    aLen = 1234
+    f1  = ArrayType(val1, aLen)
+    f1w = ArrayType(val1, aLen)
+    f2 = ArrayType(val2, aLen)
+
+    m = IntArray(aLen)
+    m[    : 100] = 1
+    m[ 100: 200] = 0
+    m[ 200: 300] = 1
+    m[ 300: 400] = 0
+    m[ 400: 500] = 1
+    m[ 500: 600] = 0
+    m[ 600: 700] = 1
+    m[ 700: 800] = 0
+    m[ 800: 900] = 1
+    m[ 900:1000] = 0
+    m[1000:1100] = 1
+    m[1100:1200] = 0
+    m[1200:    ] = 1
+
+    m.makeReadOnly()
+
+    maskedLen = len(f1[m])
+    f3 = ArrayType(val2, len(f1[m]))
+
+    assert (f1.writable() == True)
+    assert (f2.writable() == True)
+    assert (f3.writable() == True)
+
+    testVectorVectorArithmeticOps(f1, f2)
+
+    testVectorScalarArithmeticOps(f1, val2)
+
+    testVectorVectorInPlaceArithmeticOps(f1, f2)
+
+    testVectorScalarInPlaceArithmeticOps(f1, val2)
+
+    testVectorVectorComparisonOps(f1, f2)
+
+    testVectorScalarComparisonOps(f1, val2)
+
+    testVectorVectorMaskedInPlaceArithmeticOps(f1, f2, m)
+
+    testVectorVectorMaskedInPlaceArithmeticOps2(f1, f3, m)
+
+    if ArrayType in [V2fArray, V2dArray, V3fArray, V3dArray]:
+        testUnaryVecMethods(f1)
+
+        testBinaryVecMethods(f1, f2)
+
+    # Now do the test again with both arrays read-only.
+    # Most tests will still pass, but some will fail.
+
+    f1.makeReadOnly()
+    f2.makeReadOnly()
+    f3.makeReadOnly()
+    assert (f1.writable() == False)
+    assert (f2.writable() == False)
+    assert (f3.writable() == False)
+
+    f1w = ArrayType(val1, aLen)
+    assert (f1w.writable() == True)
+
+    testVectorVectorArithmeticOps(f1, f2)
+
+    testVectorScalarArithmeticOps(f1, val2)
+
+    testVectorVectorInPlaceArithmeticOpsReadOnly(f1 , f2)
+    testVectorVectorInPlaceArithmeticOpsReadOnly(f1w, f2, False)
+
+    testVectorScalarInPlaceArithmeticOpsReadOnly(f1, val2)
+
+    testVectorVectorComparisonOps(f1, f2)
+
+    testVectorScalarComparisonOps(f1, val2)
+
+    testVectorVectorMaskedInPlaceArithmeticOpsReadOnly(f1 , f2, m)
+    testVectorVectorMaskedInPlaceArithmeticOpsReadOnly(f1w, f2, m, False)
+
+    testVectorVectorMaskedInPlaceArithmeticOps2ReadOnly(f1 , f3, m)
+    testVectorVectorMaskedInPlaceArithmeticOps2ReadOnly(f1w, f3, m, False)
+
+    if ArrayType in [V2fArray, V2dArray, V3fArray, V3dArray]:
+        testUnaryVecMethodsReadOnly(f1)
+    
+        testBinaryVecMethods(f1, f2)
+
+    print ("ok")
+
+testList.append(("testReadOnlyAutoVectFloat",
+                  lambda : testReadOnlyAutoVect(FloatArray, 1.25, 5.0)))
+testList.append(("testReadOnlyAutoVectDouble",
+                  lambda : testReadOnlyAutoVect(DoubleArray, 3.456, 4.567)))
+testList.append(("testReadOnlyAutoVectV3f",
+                  lambda : testReadOnlyAutoVect(V3fArray, V3f(1.234, 2.345, 3.456),
+                                                          V3f(4.234, 6.345, 5.456))))
+testList.append(("testReadOnlyAutoVectV2d",
+                  lambda : testReadOnlyAutoVect(V2dArray, V2d(3.456, 0.456),
+                                                           V2d(4.567, 0.581))))
+
+
+def testReadOnlySpecialAccess():
+    '''
+    Tests that some of the special array-access operators (for example,
+    a 'V3fArray' x, y, or z operators) maintain the proper writable 
+    state and behave as expected.
+    '''
+
+    aLen = 123
+
+    b2 = Box2dArray(aLen)
+    b3 = Box3fArray(aLen)
+
+    assert (b2.writable() == True)
+    assert (b3.writable() == True)
+
+    assert (b2.min.writable() == True)
+    assert (b2.max.writable() == True)
+    assert (b3.min.writable() == True)
+    assert (b3.max.writable() == True)
+
+    b2.min[10] = V2d( 1, 2)
+    b2.max[10] = V2d( 2, 3)
+    b3.min[10] = V3f(-1,-1,-1)
+    b3.max[10] = V3f( 1, 1, 1)
+
+    b2.makeReadOnly()
+    b3.makeReadOnly()
+
+    assert (b2.writable() == False)
+    assert (b3.writable() == False)
+
+    assert (b2.min.writable() == False)
+    assert (b2.max.writable() == False)
+    assert (b3.min.writable() == False)
+    assert (b3.max.writable() == False)
+
+    assert (equalWithAbsError(b2.min[10], V2d(1,2), eps) == True)
+    assert (equalWithAbsError(b2.max[10], V2d(2,3), eps) == True)
+    assert (equalWithAbsError(b3.min[10], V3f(-1,-1,-1), eps) == True)
+    assert (equalWithAbsError(b3.max[10], V3f( 1, 1, 1), eps) == True)
+
+    try:    b2.min[20] = V2d( 1, 2)
+    except: pass
+    else:   assert(False)
+    try:    b2.max[20] = V2d( 2, 3)
+    except: pass
+    else:   assert(False)
+    try:    b3.min[20] = V3f(-1,-1,-1)
+    except: pass
+    else:   assert(False)
+    try:    b3.max[20] = V3f( 1, 1, 1)
+    except: pass
+    else:   assert(False)
+
+    ##
+
+    c3 = C3fArray(aLen)
+    c4 = C4fArray(aLen)
+
+    assert (c3.writable() == True)
+    assert (c4.writable() == True)
+
+    assert (c3.r.writable() == True)
+    assert (c3.g.writable() == True)
+    assert (c3.b.writable() == True)
+
+    assert (c4.r.writable() == True)
+    assert (c4.g.writable() == True)
+    assert (c4.b.writable() == True)
+    assert (c4.a.writable() == True)
+
+    c3.r[10] = 0.1
+    c3.g[10] = 0.2
+    c3.b[10] = 0.3
+
+    c4.r[10] = 0.1
+    c4.g[10] = 0.2
+    c4.b[10] = 0.3
+    c4.a[10] = 0.4
+
+    c3.makeReadOnly()
+    c4.makeReadOnly()
+
+    assert (c3.writable() == False)
+    assert (c4.writable() == False)
+
+    assert (c3.r.writable() == False)
+    assert (c3.g.writable() == False)
+    assert (c3.b.writable() == False)
+
+    assert (c4.r.writable() == False)
+    assert (c4.g.writable() == False)
+    assert (c4.b.writable() == False)
+    assert (c4.a.writable() == False)
+
+    assert (equalWithAbsError(c3.r[10], 0.1, eps) == True)
+    assert (equalWithAbsError(c3.g[10], 0.2, eps) == True)
+    assert (equalWithAbsError(c3.b[10], 0.3, eps) == True)
+
+    assert (equalWithAbsError(c4.r[10], 0.1, eps) == True)
+    assert (equalWithAbsError(c4.g[10], 0.2, eps) == True)
+    assert (equalWithAbsError(c4.b[10], 0.3, eps) == True)
+    assert (equalWithAbsError(c4.a[10], 0.4, eps) == True)
+
+    try:    c3.r[10] = 0.2
+    except: pass
+    else:   assert(False)
+    try:    c3.g[10] = 0.3
+    except: pass
+    else:   assert(False)
+    try:    c3.b[10] = 0.4
+    except: pass
+    else:   assert(False)
+
+    try:    c4.r[10] = 0.2
+    except: pass
+    else:   assert(False)
+    try:    c4.g[10] = 0.3
+    except: pass
+    else:   assert(False)
+    try:    c4.b[10] = 0.4
+    except: pass
+    else:   assert(False)
+    try:    c4.a[10] = 0.5
+    except: pass
+    else:   assert(False)
+
+    ##
+
+    qd = QuatdArray(aLen)
+    qf = QuatfArray(aLen)
+
+    assert (qd.writable() == True)
+    assert (qf.writable() == True)
+
+    assert (qd.r.writable() == True)
+    assert (qd.x.writable() == True)
+    assert (qd.y.writable() == True)
+    assert (qd.z.writable() == True)
+    assert (qf.r.writable() == True)
+    assert (qf.x.writable() == True)
+    assert (qf.y.writable() == True)
+    assert (qf.z.writable() == True)
+
+    qd.setRotation( V3dArray(V3d(1,2,3), aLen),
+                    V3dArray(V3d(2,3,4), aLen) )
+    qf.orientToVectors( V3fArray(V3f(2,3,4), aLen),
+                        V3fArray(V3f(3,4,5), aLen), False )
+    qd.setAxisAngle( V3dArray(V3d(4,5,6), aLen), DoubleArray(23.45, aLen) )
+    qf.setEulerXYZ( V3fArray(V3f(30,-10,20), aLen) )
+
+    qd.makeReadOnly()
+    qf.makeReadOnly()
+
+    assert (qd.writable() == False)
+    assert (qf.writable() == False)
+
+    assert (qd.r.writable() == False)
+    assert (qd.x.writable() == False)
+    assert (qd.y.writable() == False)
+    assert (qd.z.writable() == False)
+    assert (qf.r.writable() == False)
+    assert (qf.x.writable() == False)
+    assert (qf.y.writable() == False)
+    assert (qf.z.writable() == False)
+
+    try:
+        qd.setRotation( V3dArray(V3d(-1,-2,-3), aLen),
+                        V3dArray(V3d(-2,-3,-4), aLen) )
+    except:
+        pass
+    else:
+        assert(False)
+    try:
+        qf.orientToVectors( V3fArray(V3f(-2,-3,-4), aLen),
+                            V3fArray(V3f(-3,-4,-5), aLen), True )
+    except:
+        pass
+    else:
+        assert(False)
+    try:
+        qd.setAxisAngle( V3dArray(V3d(-4,-5,-6), aLen), DoubleArray(-23.45, aLen) )
+    except:
+        pass
+    else:
+        assert(False)
+    try:
+        qf.setEulerXYZ( V3fArray(V3f(-30,10,-20), aLen) )
+    except:
+        pass
+    else:
+        assert(False)
+
+    ##
+
+    v2 = V2fArray(aLen)
+    v3 = V3dArray(aLen)
+    v4 = V4fArray(aLen)
+
+    assert (v2.writable() == True)
+    assert (v3.writable() == True)
+    assert (v4.writable() == True)
+
+    assert (v2.x.writable() == True)
+    assert (v2.y.writable() == True)
+    assert (v3.x.writable() == True)
+    assert (v3.y.writable() == True)
+    assert (v3.z.writable() == True)
+    assert (v4.x.writable() == True)
+    assert (v4.y.writable() == True)
+    assert (v4.z.writable() == True)
+    assert (v4.w.writable() == True)
+
+    v2.x[10] = 0.1
+    v2.y[10] = 0.2
+    v3.x[10] = 0.1
+    v3.y[10] = 0.2
+    v3.z[10] = 0.3
+    v4.x[10] = 0.1
+    v4.y[10] = 0.2
+    v4.z[10] = 0.3
+    v4.w[10] = 0.4
+
+    v2.makeReadOnly()
+    v3.makeReadOnly()
+    v4.makeReadOnly()
+
+    assert (v2.writable() == False)
+    assert (v3.writable() == False)
+    assert (v4.writable() == False)
+
+    assert (v2.x.writable() == False)
+    assert (v2.y.writable() == False)
+    assert (v3.x.writable() == False)
+    assert (v3.y.writable() == False)
+    assert (v3.z.writable() == False)
+    assert (v4.x.writable() == False)
+    assert (v4.y.writable() == False)
+    assert (v4.z.writable() == False)
+    assert (v4.w.writable() == False)
+
+    assert (equalWithAbsError(v2.x[10], 0.1, eps) == True)
+    assert (equalWithAbsError(v2.y[10], 0.2, eps) == True)
+    assert (equalWithAbsError(v3.x[10], 0.1, eps) == True)
+    assert (equalWithAbsError(v3.y[10], 0.2, eps) == True)
+    assert (equalWithAbsError(v3.z[10], 0.3, eps) == True)
+    assert (equalWithAbsError(v4.x[10], 0.1, eps) == True)
+    assert (equalWithAbsError(v4.y[10], 0.2, eps) == True)
+    assert (equalWithAbsError(v4.z[10], 0.3, eps) == True)
+    assert (equalWithAbsError(v4.w[10], 0.4, eps) == True)
+
+    try:    v2.x[20] = 0.2
+    except: pass
+    else:   assert(False)
+    try:    v2.y[20] = 0.3
+    except: pass
+    else:   assert(False)
+    try:    v3.x[20] = 0.2
+    except: pass
+    else:   assert(False)
+    try:    v3.y[20] = 0.3
+    except: pass
+    else:   assert(False)
+    try:    v3.z[20] = 0.4
+    except: pass
+    else:   assert(False)
+    try:    v4.x[20] = 0.2
+    except: pass
+    else:   assert(False)
+    try:    v4.y[20] = 0.3
+    except: pass
+    else:   assert(False)
+    try:    v4.z[20] = 0.4
+    except: pass
+    else:   assert(False)
+    try:    v4.w[20] = 0.5
+    except: pass
+    else:   assert(False)
+
+    print ("ok")
+
+testList.append(("testReadOnlySpecialAccess", testReadOnlySpecialAccess))
+
+
+def testReadOnlyIndexedArrays(ArrayType, val):
+    '''
+    Tests that indexed read-only arrays behave as expected.
+    '''
+
+    aLen = 123
+
+    a = ArrayType(aLen)
+    assert (a.writable() == True)
+
+    m = IntArray(aLen)
+    m[:]     = 0
+    m[10:80] = 1
+    assert (m.writable() == True)
+    m.makeReadOnly()
+    assert (m.writable() == False)
+
+    a1 = a[30:100]  # getitem (new array; writable)
+    assert (len(a1) == 70)
+    assert (a1.writable() == True)
+    a1[:] = val
+
+    a2 = a[m]   # getitem (copied; writable state preserved)
+    assert (len(a2) == 70)
+    assert (a2.writable() == True)
+    a2[:] = val
+
+    assert (equalWithAbsError(a[ 5], val, eps) == False)
+    assert (equalWithAbsError(a[20], val, eps) == True )
+    assert (equalWithAbsError(a[90], val, eps) == False)
+
+    a2[:] = ArrayType(2 * val, 70)
+    assert (equalWithAbsError(a[ 5], 2*val, eps) == False)
+    assert (equalWithAbsError(a[20], 2*val, eps) == True )
+    assert (equalWithAbsError(a[90], 2*val, eps) == False)
+
+    a.makeReadOnly()
+    assert (a.writable() == False)
+
+    a1 = a[30:100]  # getitem (new array; writable by default)
+    assert (len(a1) == 70)
+    assert (a1.writable() == True)
+    a1[:] = val
+
+    a2 = a[m]   # getitem (copied; writable state preserved)
+    assert (len(a2) == 70)
+    assert (a2.writable() == False)
+    try:    a2[:] = val
+    except: pass
+    else:   assert(False)
+
+    a1[:] = ArrayType(val, 70)
+    try:    a2[:] = ArrayType(val, 70)
+    except: pass
+    else:   assert(False)
+
+    #
+
+    a = ArrayType(aLen)
+    assert (a.writable() == True)
+
+    a[m]       =   val  # setitem_scalar
+    a[100:110] = 2*val  # setitem_scalar
+    assert (equalWithAbsError(a[  5],   val, eps) == False)
+    assert (equalWithAbsError(a[ 30],   val, eps) == True )
+    assert (equalWithAbsError(a[105], 2*val, eps) == True )
+    assert (equalWithAbsError(a[115], 2*val, eps) == False)
+
+    a[m]       = ArrayType(3*val, 70)  # setitem_vector
+    a[100:110] = ArrayType(4*val, 10)  # setitem_vector
+    assert (equalWithAbsError(a[  5], 3*val, eps) == False)
+    assert (equalWithAbsError(a[ 30], 3*val, eps) == True )
+    assert (equalWithAbsError(a[105], 4*val, eps) == True )
+    assert (equalWithAbsError(a[115], 4*val, eps) == False)
+
+    a.makeReadOnly()
+    assert (a.writable() == False)
+
+    try:    a[m]      = 5*val;  # setitem_scalar
+    except: pass
+    else:   assert(False)
+    try:    a[100:110] = 6*val;  # setitem_scalar
+    except: pass
+    else:   assert(False)
+
+    try:    a[m]       = ArrayType(7*val, 70)  # setitem_vector
+    except: pass
+    else:   assert(False)
+    try:    a[100:110] = ArrayType(8*val, 10)  # setitem_vector
+    except: pass
+    else:   assert(False)
+
+    print ("ok")
+
+testList.append(("testReadOnlyIndexedArraysFloat",
+                 lambda : testReadOnlyIndexedArrays(FloatArray, 1.25)))
+testList.append(("testReadOnlyIndexedArraysV3f",
+                 lambda : testReadOnlyIndexedArrays(V3fArray, V3f(1.25, 2, 3))))
+
+
+def testReadOnlyVIntArrays():
+    '''
+    Tests the basic operations of read-only Variable-Int arrays and makes
+    sure they behave as expected and throw access errors when they should.
+    '''
+
+    aLen = 123
+
+    a = VIntArray(aLen)
+    assert (len(a) == aLen)
+    assert (a.writable() == True)
+
+    a.size[:] = 10  # 10 cvs each.
+
+    for i in range(aLen):
+        assert (len(a[i]) == 10)
+        for j in range(10):
+            a[i][j] = j + i
+
+    for i in range(aLen):
+        for j in range(len(a[i])):
+            assert (a[i][j] == (i+j))
+
+    a.makeReadOnly()
+    assert (a.writable() == False)
+
+    av = a[70]  # getitem
+    assert(len(av) == 10)
+    assert(av.writable() == False)
+
+    try:    a[80][5] = 7
+    except: pass
+    else:   assert(False)
+
+    assert (a.size[12] == 10)
+    try:    a.size[13] = 12
+    except: pass
+    else:   assert(False)
+
+    av = a[10:14]
+    assert (len(av) == 4)
+    assert (av.writable() == True)  # A new array is returned for slices
+    for i in range(len(av)):
+        assert (len(av[i]) == 10)
+        av[i][3] = 3
+        av[i][8] = 8
+
+    m = IntArray(aLen)
+    m[:] = 0
+    m[50:70] = 1
+    m.makeReadOnly()
+
+    av = a[m]
+    assert (len(av) == 20)
+    assert (av.writable() == False)  # An copied indexed array is returned for masks.
+
+    print ("ok")
+
+testList.append(("testReadOnlyVIntArrays", testReadOnlyVIntArrays))
+
+
+def testReadOnlyStringArrays():
+    '''
+    Tests the basic operations of read-only string arrays and makes sure
+    they behave as expected and throw access errors when they should.
+    '''
+
+    aLen = 20
+
+    a = StringArray(aLen)
+    assert (len(a) == aLen)
+    assert (a.writable() == True)
+
+    a[:]  = "Hello"
+    a[10] = "Hello Joe"
+
+    for i in range(20):
+        if i == 10:
+            assert (a[i] == "Hello Joe")
+        else:
+            assert (a[i] == "Hello")
+
+    a.makeReadOnly()
+    assert (len(a) == aLen)
+    assert (a.writable() == False)
+
+    for i in range(20):
+        if i == 10:
+            assert (a[i] == "Hello Joe")
+        else:
+            assert (a[i] == "Hello")
+
+    try:    a[3:12] = "Goodbye"
+    except: pass
+    else:   assert(False)
+    try:    a[10] = "Goodbye Joe"
+    except: pass
+    else:   assert(False)
+
+    print ("ok")
+
+testList.append(("testReadOnlyStringArrays", testReadOnlyStringArrays))
+
+
+def testQuatArrays():
+
+    x  = math.sqrt(2.) / 2.
+    q1 = QuatfArray(5)
+
+    q1[0].setAxisAngle (V3f ( 1., 0., 0.), math.pi)
+    q1[1].setAxisAngle (V3f ( 1., 1., 0.), math.pi)
+    q1[2].setAxisAngle (V3f ( 0., 1., 0.), math.pi)
+    q1[3].setAxisAngle (V3f (-1., 1., 0.), math.pi)
+    q1[4].setAxisAngle (V3f (-1., 0., 0.), math.pi)
+
+    qA = Quatf()
+    qA.setAxisAngle (V3f (0., 0., 1.), math.pi / 2.)
+
+    assert (abs (q1.x[1] - x) <= 1.e-6)
+    assert (abs (q1.y[1] - x) <= 1.e-6)
+    assert (abs (q1.x[3] + x) <= 1.e-6)
+    assert (abs (q1.y[3] - x) <= 1.e-6)
+
+    q2 = -q1
+    for i in range(5):
+        assert (q2[i] == -q1[i])
+
+    s  = q1 ^ q2
+    for i in range(5):
+        assert (s[i] == q1[i] ^ q2[i])
+
+    q3 = q1 * qA
+    for i in range(5):
+        assert (q3[i] == q1[i] * qA)
+    q3 *= 10.
+
+    tmp = QuatfArray (5)
+    tmp[:] = q3
+    q3.normalize()
+    for i in range(5):
+        assert (q3[i] != tmp[i])
+        assert (q3[i] == tmp[i].normalized())
+
+    q4 = q1.slerp (q3, 0.5)
+    for i in range(5):
+        assert (q4[i] == q1[i].slerpShortestArc (q3[i], 0.5))
+
+    tmp[:] = q4
+    q4 *= q3.inverse()
+    for i in range(5):
+        assert (q4[i] == tmp[i] * q3[i].inverse())
+
+    q5 = QuatfArray (5)
+    tmp[:] = q4
+    q5[:] = q4.normalized()
+    for i in range(5):
+        assert (q4[i] == tmp[i])
+        assert (q5[i] == q4[i].normalize())
+
+    print ("ok")
+
+testList.append(("testQuatArrays", testQuatArrays))
+
+
+def testBufferProtocol():
+    '''
+    The buffer protocol can be used to exchange array data between python modules.
+    For example, numpy and Pixar Vt arrays both support the buffer protocol.
+    There's a limited amount of testing that can be done with native python, so
+    the majority of this functionality is tested in the PyImathNumpyTest project.
+    '''
+    def verifyScalar (a):
+
+        m = memoryview (a)
+        assert (        m.ndim == 1)
+        assert (len(m.strides) == m.ndim)
+        assert (  len(m.shape) == m.ndim)
+        assert (    m.shape[0] == len(a))
+        assert (  m.strides[0] == struct.calcsize (m.format))
+
+
+    def verifyVector (a):
+
+        m = memoryview (a)
+        assert (        m.ndim == 2)
+        assert (len(m.strides) == m.ndim)
+        assert (  len(m.shape) == m.ndim)
+        assert (    m.shape[0] == len(a))
+        assert (    m.shape[1] == len(a[0]))
+        assert (  m.strides[0] == struct.calcsize (m.format) * len(a[0]))
+        assert (  m.strides[1] == struct.calcsize (m.format))
+
+# .............................................................................
+
+    import struct
+
+    a = UnsignedCharArray (10)
+    verifyScalar (a)
+
+    a = IntArray (10)
+    verifyScalar (a)
+
+    a = FloatArray (10)
+    verifyScalar (a)
+
+    a = DoubleArray (10)
+    verifyScalar (a)
+
+    a = V2iArray (10)
+    verifyVector (a)
+
+    a = V2fArray (10)
+    verifyVector (a)
+
+    a = V2dArray (10)
+    verifyVector (a)
+
+    a = V3iArray (10)
+    verifyVector (a)
+
+    a = V3fArray (10)
+    verifyVector (a)
+
+    a = V3dArray (10)
+    verifyVector (a)
+
+    print ("ok")
+
+testList.append(("Buffer protocol test", testBufferProtocol))
+
+def testFloatArray2D():
+
+    a = FloatArray2D(2,3)
+    a[(0,0)] = 1.0
+    a[(0,1)] = 2.0
+    a[(0,2)] = 3.0
+    a[(1,0)] = 4.0
+    a[(1,1)] = 5.0
+    a[(1,2)] = 6.0
+
+    a += 1.0
+    a -= 0.5
+    a *= 4.0
+    a /= 2.0
+    b = 3 * a - a + (a * a / 2) / a
+
+    assert equalWithAbsError (b.item(0,0), 7.5, 0.001)
+    assert equalWithAbsError (b.item(0,1), 12.5, 0.001)
+    assert equalWithAbsError (b.item(0,2), 17.5, 0.001)
+    assert equalWithAbsError (b.item(1,0), 22.5, 0.001)
+    assert equalWithAbsError (b.item(1,1), 27.5, 0.001)
+    assert equalWithAbsError (b.item(1,2), 32.5, 0.001)
+
+    choice = IntArray2D(2,3)
+    choice[(0,0)] = 1
+    choice[(0,1)] = 0
+    choice[(0,2)] = 0
+    choice[(1,0)] = 0
+    choice[(1,1)] = 1
+    choice[(1,2)] = 0
+
+    d = b.ifelse(choice,a)
+
+    assert d.item(0,0) == b.item(0,0)
+    assert d.item(0,1) == a.item(0,1)
+    assert d.item(0,2) == a.item(0,2)
+    assert d.item(1,0) == a.item(1,0)
+    assert d.item(1,1) == b.item(1,1)
+    assert d.item(1,2) == a.item(1,2)
+
+    print ("ok")
+
+testList.append(("FloatArray2D test", testFloatArray2D))
+
+def testColor4Array2D():
+
+    a = Color4fArray2D(2,3)
+    a[(0,0)] = Color4f(1,0,0,0)
+    a[(0,1)] = Color4f(0,1,0,0)
+    a[(0,2)] = Color4f(0,0,1,0)
+    a[(1,0)] = Color4f(1,0,0,1)
+    a[(1,1)] = Color4f(0,1,0,1)
+    a[(1,2)] = Color4f(0,0,1,1)
+
+    a += Color4f(1.0, 1.0, 1.0, 1.0)
+    a -= Color4f(0.5, 0.5, 0.5, 0.5)
+    a *= 4.0
+    a /= 2.0
+    b = 3 * a - a + (a * a / 2) / a
+
+    assert equalWithAbsError (b.item(0,0), Color4f(7.5, 2.5, 2.5, 2.5), 0.001)
+    assert equalWithAbsError (b.item(0,1), Color4f(2.5, 7.5, 2.5, 2.5), 0.001)
+    assert equalWithAbsError (b.item(0,2), Color4f(2.5, 2.5, 7.5, 2.5), 0.001)
+    assert equalWithAbsError (b.item(1,0), Color4f(7.5, 2.5, 2.5, 7.5), 0.001)
+    assert equalWithAbsError (b.item(1,1), Color4f(2.5, 7.5, 2.5, 7.5), 0.001)
+    assert equalWithAbsError (b.item(1,2), Color4f(2.5, 2.5, 7.5, 7.5), 0.001)
+
+    choice = IntArray2D(2,3)
+    choice[(0,0)] = 1
+    choice[(0,1)] = 0
+    choice[(0,2)] = 0
+    choice[(1,0)] = 0
+    choice[(1,1)] = 1
+    choice[(1,2)] = 0
+
+    d = b.ifelse(choice,a)
+
+    assert d.item(0,0) == b.item(0,0)
+    assert d.item(0,1) == a.item(0,1)
+    assert d.item(0,2) == a.item(0,2)
+    assert d.item(1,0) == a.item(1,0)
+    assert d.item(1,1) == b.item(1,1)
+    assert d.item(1,2) == a.item(1,2)
+
+    print ("ok")
+
+testList.append(("Color4fArray2D test", testColor4Array2D))
+
+# -------------------------------------------------------------------------
+# Main loop
+
+random.seed (1567)
+
+import imath
+print (imath.__file__)
+
+for test in testList:
+    funcName = test[0]
+    print ("")
+    print ("Running {}".format (funcName))
+    test[1]()
+
+print ("")
+
+# Local Variables:
+# mode:python
+# End:
diff --git a/src/python/PyImathTest/testStringTable.cpp b/src/python/PyImathTest/testStringTable.cpp
new file mode 100644 (file)
index 0000000..765d5c5
--- /dev/null
@@ -0,0 +1,125 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+#ifdef NDEBUG
+#    undef NDEBUG
+#endif
+
+#include <PyImathStringTable.h>
+#include <iostream>
+#include <assert.h>
+
+using namespace std;
+using namespace PyImath;
+
+namespace {
+
+void
+testString()
+{
+    StringTable st;
+
+    size_t size = st.size();
+    assert(size == 0);
+    assert(!st.hasString("foo"));
+
+    StringTableIndex index = st.intern("foo");
+    assert(index == st.lookup("foo"));
+    assert(st.lookup(index) == "foo");
+    assert(st.hasString("foo"));
+
+    size = st.size();
+    assert(size == 1);
+
+    bool thrown = false;
+    try {
+        index = st.lookup("bar");
+    } catch (std::exception &e) {
+        thrown = true;
+    }
+    assert (thrown);
+
+    thrown = false;
+    try {
+        std::string s = st.lookup(StringTableIndex(1));
+    } catch (std::exception &e) {
+        thrown = true;
+    }
+    assert (thrown);
+    
+    assert(!st.hasString("bar"));
+
+    index = st.intern("bar");
+    assert(index == st.lookup("bar"));
+    assert(st.lookup(index) == "bar");
+    assert(0 == st.lookup("foo").index());
+    assert(st.lookup(StringTableIndex(0)) == "foo");
+    assert(st.hasString("bar"));
+}
+
+void
+testWString()
+{
+    WStringTable st;
+
+    size_t size = st.size();
+    assert(size == 0);
+    assert(!st.hasString(L"foo"));
+
+    StringTableIndex index = st.intern(L"foo");
+    assert(index == st.lookup(L"foo"));
+    assert(st.lookup(index) == L"foo");
+    assert(st.hasString(L"foo"));
+
+    size = st.size();
+    assert(size == 1);
+
+    bool thrown = false;
+    try {
+        index = st.lookup(L"bar");
+    } catch (std::exception &e) {
+        thrown = true;
+    }
+    assert (thrown);
+
+    thrown = false;
+    try {
+        std::wstring s = st.lookup(StringTableIndex(1));
+    } catch (std::exception &e) {
+        thrown = true;
+    }
+    assert (thrown);
+    
+    assert(!st.hasString(L"bar"));
+
+    index = st.intern(L"bar");
+    assert(index == st.lookup(L"bar"));
+    assert(st.lookup(index) == L"bar");
+    assert(0 == st.lookup(L"foo").index());
+    assert(st.lookup(StringTableIndex(0)) == L"foo");
+    assert(st.hasString(L"bar"));
+}
+
+} // namespace
+
+
+void
+testStringTable()
+{
+    cout << "Testing string table:" << endl;
+    
+    try
+    {
+       testString();
+        testWString();
+    }
+    catch (const exception &e)
+    {
+       cerr << "Unexpected exception: " << e.what() << endl;
+       assert(false);
+    }
+
+    cout << "ok\n" << endl;
+}
diff --git a/src/python/PyImathTest/testStringTable.h b/src/python/PyImathTest/testStringTable.h
new file mode 100644 (file)
index 0000000..1ef13a5
--- /dev/null
@@ -0,0 +1,2 @@
+void testStringTable();
+
diff --git a/src/python/config/CMakeLists.txt b/src/python/config/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b09905c
--- /dev/null
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+### The autoconf setup for this folder generates a PyImathConfig.h file
+### but no source actually uses that, so let's elide that for now
+
+add_library(PyImathConfig INTERFACE)
+target_include_directories(PyImathConfig INTERFACE
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
+install(TARGETS PyImathConfig EXPORT ${PROJECT_NAME})
+add_library(PyImath::Config ALIAS PyImathConfig)
+
+if(IMATH_INSTALL_PKG_CONFIG)
+  # use a helper function to avoid variable pollution, but pretty simple
+  function(pyimath_pkg_config_help pcinfile)
+    set(prefix ${CMAKE_INSTALL_PREFIX})
+    set(exec_prefix "\${prefix}")
+    set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
+    set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
+    string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
+    set(LIB_SUFFIX_DASH ${IMATH_LIB_SUFFIX}${CMAKE_${uppercase_CMAKE_BUILD_TYPE}_POSTFIX})
+    string(REPLACE ".in" "" pcout ${pcinfile})
+    configure_file(${pcinfile} ${CMAKE_CURRENT_BINARY_DIR}/${pcout} @ONLY)
+    install(
+        FILES ${CMAKE_CURRENT_BINARY_DIR}/${pcout}
+        DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
+    )
+  endfunction()
+  pyimath_pkg_config_help(../PyImath.pc.in)
+else()
+  message(STATUS "pkg-config generation disabled")
+endif()
diff --git a/src/python/config/ModuleDefine.cmake b/src/python/config/ModuleDefine.cmake
new file mode 100644 (file)
index 0000000..7e30614
--- /dev/null
@@ -0,0 +1,160 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+function(PYIMATH_ADD_LIBRARY_PRIV libname)
+  set(options)
+  set(oneValueArgs PRIV_EXPORT CURDIR CURBINDIR OUTROOT)
+  set(multiValueArgs SOURCE HEADERS DEPENDENCIES PRIVATE_DEPS)
+  cmake_parse_arguments(PYIMATH_CURLIB "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+
+  # Currently, the python bindings REQUIRE a shared library for
+  # the Iex stuff to be initialized correctly. As such, force that
+  # here
+  # TODO Change this back when these bindings are refactored
+  add_library(${libname} SHARED ${PYIMATH_CURLIB_SOURCE})
+  #if(BUILD_SHARED_LIBS)
+  set_target_properties(${libname} PROPERTIES
+  SOVERSION ${IMATH_LIB_SOVERSION}
+  VERSION ${IMATH_LIB_VERSION}
+  )
+  #endif()
+  set_target_properties(${libname} PROPERTIES
+    OUTPUT_NAME "${PYIMATH_CURLIB_OUTROOT}${libname}${PYIMATH_LIB_SUFFIX}"
+  )
+  target_compile_features(${libname} PUBLIC cxx_std_${IMATH_CXX_STANDARD})
+  # we are always building shared, so don't check for that
+  if(PYIMATH_CURLIB_PRIV_EXPORT)
+    target_compile_definitions(${libname} PRIVATE ${PYIMATH_CURLIB_PRIV_EXPORT})
+  endif()
+  if(WIN32)
+    target_compile_definitions(${libname} PUBLIC IMATH_DLL)
+  endif()
+  if(PYIMATH_CURLIB_CURDIR)
+    target_include_directories(${libname} PUBLIC $<BUILD_INTERFACE:${PYIMATH_CURLIB_CURDIR}>)
+  endif()
+  if(PYIMATH_CURLIB_CURBINDIR)
+    target_include_directories(${libname} PRIVATE $<BUILD_INTERFACE:${PYIMATH_CURLIB_CURBINDIR}>)
+  endif()
+  if(Boost_INCLUDE_DIR)
+    target_include_directories(${libname} PUBLIC ${Boost_INCLUDE_DIR})
+  endif()
+  target_link_libraries(${libname} PUBLIC ${PYIMATH_CURLIB_DEPENDENCIES})
+  if(PYIMATH_CURLIB_PRIVATE_DEPS)
+    target_link_libraries(${libname} PRIVATE ${PYIMATH_CURLIB_PRIVATE_DEPS})
+  endif()
+  set_target_properties(${libname} PROPERTIES
+    CXX_STANDARD_REQUIRED ON
+    CXX_EXTENSIONS OFF
+    POSITION_INDEPENDENT_CODE ON
+  )
+
+  add_library(${PROJECT_NAME}::${libname} ALIAS ${libname})
+
+  install(TARGETS ${libname}
+    EXPORT ${PROJECT_NAME}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endfunction()
+
+# NB: This function has a number if specific names / variables
+# not to mention behavior, so be careful copying...
+function(PYIMATH_DEFINE_MODULE modname)
+  set(options NEEDED_BY_OTHER_MODULES)
+  set(oneValueArgs PRIV_EXPORT CURDIR CURBINDIR LIBNAME)
+  set(multiValueArgs LIBSOURCE MODSOURCE HEADERS DEPENDENCIES PRIVATE_DEPS MODULE_DEPS)
+  cmake_parse_arguments(PYIMATH_CURMOD "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+  if(PYIMATH_CURMOD_HEADERS)
+    install(
+      FILES
+        ${PYIMATH_CURMOD_HEADERS}
+      DESTINATION
+        ${CMAKE_INSTALL_INCLUDEDIR}/${IMATH_OUTPUT_SUBDIR}
+    )
+  endif()
+
+  if(NOT PYIMATH_CURMOD_LIBNAME)
+    message(FATAL_ERROR "NYI usage of pyimath_define_module")
+    return()
+  endif()
+
+  set(libarglist SOURCE ${PYIMATH_CURMOD_LIBSOURCE})
+  if(PYIMATH_CURMOD_PRIV_EXPORT)
+    list(APPEND libarglist PRIV_EXPORT ${PYIMATH_CURMOD_PRIV_EXPORT})
+  endif()
+  if(PYIMATH_CURMOD_HEADERS)
+    list(APPEND libarglist HEADERS ${PYIMATH_CURMOD_HEADERS})
+  endif()
+  if(PYIMATH_CURMOD_CURDIR)
+    list(APPEND libarglist CURDIR ${PYIMATH_CURMOD_CURDIR})
+  endif()
+  if(PYIMATH_CURMOD_CURBINDIR)
+    list(APPEND libarglist CURBINDIR ${PYIMATH_CURMOD_CURBINDIR})
+  endif()
+  if(PYIMATH_CURMOD_DEPENDENCIES)
+    list(APPEND libarglist DEPENDENCIES ${PYIMATH_CURMOD_DEPENDENCIES})
+  endif()
+  # NB: make this one last so we can cheat and add the python and boost
+  # libs as private deps at the end regardless of whether it was provided
+  list(APPEND libarglist PRIVATE_DEPS ${PYIMATH_CURMOD_PRIVATE_DEPS})
+  if(USE_PYTHON2)
+    if(TARGET Python2::Python AND TARGET Boost::${PYIMATH_BOOST_PY_COMPONENT})
+      set(libname "${PYIMATH_CURMOD_LIBNAME}${PYIMATH_LIB_PYTHONVER_ROOT}${Python2_VERSION_MAJOR}_${Python2_VERSION_MINOR}")
+      set(extraDeps ${PYIMATH_CURMOD_MODULE_DEPS})
+      list(TRANSFORM extraDeps APPEND ${PYIMATH_LIB_PYTHONVER_ROOT}${Python2_VERSION_MAJOR}_${Python2_VERSION_MINOR})
+
+      pyimath_add_library_priv(${libname}
+        ${libarglist}
+        ${extraDeps}
+        Python2::Python
+        Boost::${PYIMATH_BOOST_PY_COMPONENT}
+      )
+
+      Python2_add_library(${modname}_python2 MODULE ${PYIMATH_CURMOD_MODSOURCE})
+      target_link_libraries(${modname}_python2
+        PRIVATE
+          ${libname}
+          ${extraDeps}
+          ${PYIMATH_CURMOD_DEPENDENCIES}
+          ${PYIMATH_CURMOD_PRIVATE_DEPS}
+          Boost::${PYIMATH_BOOST_PY_COMPONENT}
+        )
+      set_target_properties(${modname}_python2 PROPERTIES
+        LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python${Python2_VERSION_MAJOR}_${Python2_VERSION_MINOR}/"
+        LIBRARY_OUTPUT_NAME "${modname}"
+        DEBUG_POSTFIX ""
+      )
+      install(TARGETS ${modname}_python2 DESTINATION ${PyImath_Python2_SITEARCH_REL})
+    endif()
+  else()
+    if(TARGET Python3::Python AND TARGET Boost::${PYIMATH_BOOST_PY_COMPONENT})
+      set(libname "${PYIMATH_CURMOD_LIBNAME}${PYIMATH_LIB_PYTHONVER_ROOT}${Python3_VERSION_MAJOR}_${Python3_VERSION_MINOR}")
+      set(extraDeps ${PYIMATH_CURMOD_MODULE_DEPS})
+      list(TRANSFORM extraDeps APPEND ${PYIMATH_LIB_PYTHONVER_ROOT}${Python3_VERSION_MAJOR}_${Python3_VERSION_MINOR})
+
+      pyimath_add_library_priv(${libname}
+        ${libarglist}
+        ${extraDeps}
+        Python3::Python
+        Boost::${PYIMATH_BOOST_PY_COMPONENT}
+      )
+      Python3_add_library(${modname}_python3 MODULE ${PYIMATH_CURMOD_MODSOURCE})
+      target_link_libraries(${modname}_python3
+        PRIVATE
+          ${libname} ${extraDeps}
+          ${PYIMATH_CURMOD_DEPENDENCIES}
+          ${PYIMATH_CURMOD_PRIVATE_DEPS}
+          Boost::${PYIMATH_BOOST_PY_COMPONENT}
+        )
+      set_target_properties(${modname}_python3 PROPERTIES
+        LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python${Python3_VERSION_MAJOR}_${Python3_VERSION_MINOR}/"
+        LIBRARY_OUTPUT_NAME "${modname}"
+        DEBUG_POSTFIX ""
+      )
+      install(TARGETS ${modname}_python3 DESTINATION ${PyImath_Python3_SITEARCH_REL})
+    endif()
+  endif()
+endfunction()
diff --git a/src/python/config/NumPyLocate.cmake b/src/python/config/NumPyLocate.cmake
new file mode 100644 (file)
index 0000000..77cf8cf
--- /dev/null
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+if(TARGET Python2::Interpreter)
+  execute_process(
+    COMMAND ${Python2_EXECUTABLE} -c
+    "from __future__ import print_function\ntry: import numpy; print(numpy.get_include(), end='')\nexcept: import sys; sys.exit(1)\n"
+    RESULT_VARIABLE _NUMPY2_RESULT
+    OUTPUT_VARIABLE py_imath_numpy2_path
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  if(NOT _NUMPY2_RESULT MATCHES 0)
+    set(NumPy_Py2_FOUND FALSE CACHE INTERNAL "Python2 numpy libraries not found")
+    message(WARNING "Unable to import numpy using python ${Python2_VERSION}")
+  else()
+    execute_process(
+      COMMAND ${Python2_EXECUTABLE} -c
+      "from __future__ import print_function\ntry: import numpy; print(numpy.__version__, end='')\nexcept: import sys; sys.exit(1)\n"
+      RESULT_VARIABLE _NUMPY2_RESULT
+      OUTPUT_VARIABLE py_imath_numpy2_version
+      OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+    if(NOT _NUMPY2_RESULT MATCHES 0)
+      set(NumPy_Py2_FOUND FALSE CACHE INTERNAL "Python2 numpy libraries not found")
+      message(WARNING "Found numpy module in python ${Python2_VERSION}, but no version information")
+    else()
+      find_path(NumPy_Py2_INCLUDE_DIRS numpy/arrayobject.h
+        HINTS "${py_imath_numpy2_path}" "${Python2_INCLUDE_DIRS}"
+        NO_DEFAULT_PATH
+      )
+      if(NumPy_Py2_INCLUDE_DIRS)
+        set(NumPy_Py2_FOUND TRUE CACHE INTERNAL "Python2 numpy found")
+        set(NumPy_Py2_VERSION ${py_imath_numpy2_version})
+        add_library(NumPy_Py2 INTERFACE IMPORTED GLOBAL)
+        target_include_directories(NumPy_Py2 INTERFACE ${NumPy_Py2_INCLUDE_DIRS})
+        add_library(Python2::ImathNumPy ALIAS NumPy_Py2)
+        message(STATUS "Found NumPy ${NumPy_Py2_VERSION} for Python ${Python2_VERSION}: ${NumPy_Py2_INCLUDE_DIRS}")
+      else()
+        set(NumPy_Py2_FOUND FALSE CACHE INTERNAL "Python2 numpy libraries not found")
+        message(WARNING "Found numpy version ${py_imath_numpy2_version} in python ${Python2_VERSION}, but unable to locate header files")
+      endif()
+    endif()
+  endif()
+endif()
+
+if(TARGET Python3::Interpreter)
+  execute_process(
+    COMMAND ${Python3_EXECUTABLE} -c
+    "from __future__ import print_function\ntry: import numpy; print(numpy.get_include(), end='')\nexcept: import sys; sys.exit(1)\n"
+    RESULT_VARIABLE _NUMPY3_RESULT
+    OUTPUT_VARIABLE py_imath_numpy3_path
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  if(NOT _NUMPY3_RESULT MATCHES 0)
+    set(NumPy_Py3_FOUND FALSE CACHE INTERNAL "Python3 numpy libraries not found")
+    message(WARNING "Unable to import numpy using python ${Python3_VERSION}")
+  else()
+    execute_process(
+      COMMAND ${Python3_EXECUTABLE} -c
+      "from __future__ import print_function\ntry: import numpy; print(numpy.__version__, end='')\nexcept: import sys; sys.exit(1)\n"
+      RESULT_VARIABLE _NUMPY3_RESULT
+      OUTPUT_VARIABLE py_imath_numpy3_version
+      OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+    if(NOT _NUMPY3_RESULT MATCHES 0)
+      set(NumPy_Py3_FOUND FALSE CACHE INTERNAL "Python3 numpy libraries not found")
+      message(WARNING "Found numpy module in python ${Python3_VERSION}, but no version information")
+    else()
+      find_path(NumPy_Py3_INCLUDE_DIRS numpy/arrayobject.h
+        HINTS "${py_imath_numpy3_path}" "${Python3_INCLUDE_DIRS}"
+        NO_DEFAULT_PATH
+      )
+      if(NumPy_Py3_INCLUDE_DIRS)
+        set(NumPy_Py3_FOUND TRUE CACHE INTERNAL "Python3 numpy found")
+        set(NumPy_Py3_VERSION ${py_imath_numpy3_version})
+        add_library(NumPy_Py3 INTERFACE IMPORTED GLOBAL)
+        target_include_directories(NumPy_Py3 INTERFACE ${NumPy_Py3_INCLUDE_DIRS})
+        add_library(Python3::ImathNumPy ALIAS NumPy_Py3)
+        message(STATUS "Found NumPy ${NumPy_Py3_VERSION} for Python ${Python3_VERSION}: ${NumPy_Py3_INCLUDE_DIRS}")
+      else()
+        set(NumPy_Py3_FOUND FALSE CACHE INTERNAL "Python3 numpy libraries not found")
+        message(WARNING "Found numpy version ${py_imath_numpy3_version} in python ${Python3_VERSION}, but unable to locate header files")
+      endif()
+    endif()
+  endif()
+endif()
diff --git a/src/python/config/PyImathConfig.h.in b/src/python/config/PyImathConfig.h.in
new file mode 100644 (file)
index 0000000..6e7cd79
--- /dev/null
@@ -0,0 +1,36 @@
+//
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright Contributors to the OpenEXR Project.
+//
+
+//
+// Define and set to 1 if the target system supports a proc filesystem
+// compatible with the Linux kernel's proc filesystem.  Note that this
+// is only used by a program in the IlmImfTest test suite, it's not
+// used by any OpenEXR library or application code.
+//
+
+#undef HAVE_LINUX_PROCFS
+
+//
+// Define and set to 1 if the target system is a Darwin-based system
+// (e.g., OS X).
+//
+
+#undef HAVE_DARWIN
+
+//
+// Define and set to 1 if the target system has a complete <iomanip>
+// implementation, specifically if it supports the std::right
+// formatter.
+//
+
+#undef HAVE_COMPLETE_IOMANIP
+
+//
+// Define and set to 1 if the target system has support for large
+// stack sizes.
+//
+
+#undef HAVE_LARGE_STACK
+
diff --git a/src/python/config/PyImathSetup.cmake b/src/python/config/PyImathSetup.cmake
new file mode 100644 (file)
index 0000000..01a2154
--- /dev/null
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright Contributors to the OpenEXR Project.
+
+include(GNUInstallDirs)
+
+########################
+## Target configuration
+
+set(PYIMATH_OVERRIDE_PYTHON_INSTALL_DIR "" CACHE STRING "Override the install location for imath.so and imathnumpy.so modules")
+
+########################
+## Build related options
+
+# Suffix to append to root name, this helps with version management
+# but can be turned off if you don't care, or otherwise customized
+#
+set(PYIMATH_LIB_SUFFIX "-${IMATH_VERSION_API}" CACHE STRING "String added to the end of all the libraries")
+# This provides a root for the unique name of the library based on
+# the version of python being compiled for
+set(PYIMATH_LIB_PYTHONVER_ROOT "_Python" CACHE STRING "String added as a root to the identifier of the python version in the libraries")